1
0
Files
irix-657m-src/stand/arcs/IP19prom/pod_parse.c
2022-09-29 17:59:04 +03:00

703 lines
16 KiB
C

#include <sys/types.h>
#include <sys/sbd.h>
#include "biendian.h"
#include "pod.h"
#include "ip19prom.h"
#include "pod_failure.h"
extern void loprintf(char *, ...);
extern void loputs(void (*putc)(char), char *, int);
extern void loputchar(char);
#ifdef BRINGUP
extern sload(int, struct flag_struct);
extern int pon_sload(int, struct flag_struct*);
#else
extern sload(int, int *, struct flag_struct);
extern int pon_sload(int, int*, struct flag_struct*);
#endif
int *pod_parse(int *, struct reg_struct *, int, int, struct flag_struct *);
int lo_strcmp(int *, char *);
uint lo_atoh(int *);
int lo_ishex(int);
extern memory(int, int, uint, uint, uint, int);
extern _register(int, int *, int, struct reg_struct *);
extern info();
extern jump_addr(uint, uint, uint, struct flag_struct *);
extern prom_slave();
extern pon_flush_scache();
extern pon_flush_dcache();
extern pon_invalidate_icache();
extern void pod_loop(char *, int);
extern int set_unit_enable(uint, uint, uint, uint);
extern epcerrc();
const struct cmd_table {
int token;
int args;
char *name;
char *help;
} commands[] = {
{WRITE_BYTE, 2, "wb", "Write byte: wb ADDRESS NUMBER"},
{WRITE_HALF, 2, "wh", "Write halfword: wh ADDRESS NUMBER"},
{WRITE_WORD, 2, "ww", "Write word: ww ADDRESS NUMBER"},
{WRITE_DOUBLE, 2, "wd", "Write double: wd ADDRESS NUMBER"},
{DISP_BYTE, 1, "db", "Display byte: db ADDRESS"},
{DISP_HALF, 1, "dh", "Display halfword: dh ADDRESS"},
{DISP_WORD, 1, "dw", "Display word: dw ADDRESS"},
{DISP_DOUBLE, 1, "dd", "Display double: dd ADDRESS"},
{SERIAL_LOAD, 0, "sload", "Serial download: sload"},
{SERIAL_RUN, 0, "srun", "Download and run: srun"},
#if 0
{LOAD_IOPROM, 1, "pload", "IO prom download: pload [baudrate]"},
#endif
{DISP_REG, 1, "dr", "Display register: dr <sr || sp || all>"},
{WRITE_REG, 2, "wr", "Write register: wr < sr >"},
{SCOPE_LOOP, 1, "sloop", "'scope loop: sloop (COMMAND)"},
{FINITE_LOOP, 2, "loop", "Finite loop: loop TIMES (COMMAND)"},
{DISP_INFO, 0, "info", "Slot contents: info"},
{TEST_MEM, 2, "mem", "Mem diagnostic: mem LOADDR HIADDR"},
{JUMP_ADDR, 1, "j", "Jump to address: j ADDRESS"},
{JUMP_ADDR1, 2, "j1", "Jump to address: j1 ADDRESS PARAM1"},
{JUMP_ADDR2, 3, "j2", "Jump to address: j2 ADDRESS PARAM1 PARAM2"},
{LEFT_PAREN, 0, "(", ""},
{DISP_CONF, 2, "dc", "Disp. config reg: dc SLOT REGNUM"},
{WRITE_CONF, 3, "wc", "Write config reg: wc SLOT REGNUM VALUE"},
{TEST_SCACHE, 1, "scache", "Test 2ary cache: scache COUNT"},
{DISP_MC3, 1, "dmc", "Disp mem bd regs: dmc SLOT"},
{DISP_IO4, 1, "dio", "Disp io brd regs: dio SLOT"},
{DECODE_ECC, 0, "ecc", "Display ecc info: ecc"},
{RESET_SYSTEM, 0, "reset", "Reset the system: reset"},
{PRM_CRD, 0, "credits", ""},
{BIG_ENDIAN, 1, "big", ""},
{DISP_HELP, 0, "?", ""},
{DISP_HELP, 0, "help", ""},
{NIBLET, 1, "niblet", "Run Niblet: niblet <0 - 9>"},
{POD_RESUME, 0, "resume", ""},
{SEND_INT, 3, "si", "Send interrupt: si SLOT CPU LEVEL"},
{FLUSHI, 0, "flushi", ""},
{FLUSHD, 0, "flushd", ""},
{FLUSHS, 0, "flushs", ""},
{FLUSHT, 0, "flusht", "Clear TLB: flusht"},
{TLB_DUMP, 1, "td", "Dump TLB: td <index | l | h | all>"},
{CLEAR_STATE, 0, "clear", "Clear State: clear"},
{DECODE_ADDR, 1, "decode", "Decode Address: decode PHYSADDR"},
{SET_DE, 1, "de", "Set test DE bit: de <0|1> (0 = cache errors enabled for tests)"},
{WALK_MEM, 3, "walk", "Walk a bit: walk <loaddr> <hiaddr> <cont on fails>"},
{ITAG_DUMP, 1, "itag", "Dump icache tag: itag <line_addr>"},
{DTAG_DUMP, 1, "dtag", "Dump dcache tag: dtag <line_addr>"},
{STAG_DUMP, 1, "stag", "Dump scache tag: stag <line_addr>"},
{SLAVE_MODE, 0, "slave", "Goto slave mode: slave"},
{WRITE_EXTENDED,3, "wx", "Write Extended: wx BLOC OFF VALUE"},
{DISP_EXTENDED, 2, "dx", "Display Extended: dx BLOC OFF"},
{DOWNLOAD_IO4, 0, "io", "Download IO PROM: io"},
{WHY, 0, "why", "Why are we here?: why"},
{RECONF_MEM, 0, "reconf", ""},
{GOTO_MEM, 0, "gm", ""},
{GOTO_CACHE, 0, "gc", ""},
{DO_BIST, 0, "bist", ""},
{DISABLE_UNIT, 2, "disable", "Disable unit: disable SLOT UNIT"},
{ENABLE_UNIT, 2, "enable", "Enable unit: enable SLOT UNIT"},
{FDISABLE_UNIT, 2, "fdisable", "Force disable: fdisable SLOT UNIT"},
{FENABLE_UNIT, 2, "fenable", "Force enable: fenable SLOT UNIT"},
{DISP_EVCONFIG, 1, "devc", "Display config: devc SLOT | all"},
{POD_SELECT, 1, "select", ""},
{ZAP_INVENTORY, 0, "zap", "Reinit inventory: zap"},
{DISP_MPCONF, 1, "dmpc", "Display MPCONF: dmpc VPID"},
{FIX_CHECKSUM, 0, "fixcksum", "Fix EAROM cksum: fix"},
{DISP_CHECKSUM, 0, "cksum", "Show EAROM cksum: cksum"},
{NULL, 0, "", ""},
};
/*
* pod_parse is the commands driver for Power on menu.
* Basic utilities for bring up, available functions are:
* - loprintf: can handle string, %s and %x.
* - pon_sload: down loading program from RS232 into cache/mem and run it.
*/
int find_token(int *cmd, int *cmd_token, int *num_args) {
int i = 0;
for (i = 0; (commands[i].token != NULL) &&
(lo_strcmp(cmd, commands[i].name)); i++);
if (*cmd == 0) {
*cmd_token = NO_COMMAND;
*num_args = 0;
} else {
*cmd_token = commands[i].token;
*num_args = commands[i].args;
}
if (*cmd_token)
return 1;
else
return 0;
}
void skipwhite(src)
int **src;
{
while (**src == ' ' || **src == '\t')
(*src)++;
}
void parse_error() {
loprintf("*** POD syntax error.\n");
}
void copystr(target, src)
int **target, **src;
{
while (**src != ' ' && **src != '\t' && **src != 0 && **src != ';'
&& **src != ')')
*((*target)++) = *((*src)++);
}
int get_arg(int *string, uint *value, int **bufp) {
int *ip;
skipwhite(bufp);
if (!(**bufp)) {
loprintf("*** Insufficient arguments\n");;
return 0;
}
/* get argv1 */
ip = string;
if (**bufp == '(') {
*ip++ = **bufp;
(*bufp)++;
*ip = 0;
} else {
copystr(&ip, bufp);
*ip = 0;
*value = lo_atoh(string);
}
return 1;
}
int check_eol(int **bufp) {
if (*bufp == (int *)NULL) {
return 1;
}
if (**bufp == ')') {
#ifdef PDEBUG
loprintf("end of line: Right paren.\n");
#endif
(*bufp)++;
return 1;
}
if (!(**bufp)) {
#ifdef PDEBUG
loprintf("end of line: NULL\n");
#endif
return 1;
}
if (**bufp == ';') {
#ifdef PDEBUG
loprintf("Semicolon.\n");
#endif
(*bufp)++;
}
#ifdef PDEBUG
loprintf("Interior of line\n");
#endif
return 0;
}
int *pod_parse(int *buf, struct reg_struct *gprs, int parse_level, int sloop,
struct flag_struct *flags)
{
int *bufp = buf;
int cmd[32];
int argv1[32];
int argv2[32];
int argv3[32];
int *ip;
uint arg1_val;
uint arg2_val;
uint arg3_val;
int line_end;
int cmd_token;
int num_args;
int i;
int x;
extern prom_start();
#ifdef PDEBUG
loprintf("Sloop = %d\n", sloop);
#endif /* PDEBUG */
if (parse_level >= MAX_NEST) {
loprintf("*** Too many levels of loops/parentheses.\n");
return (int *)NULL;
}
#ifdef PDEBUG
loprintf("Parser level %d\n", parse_level);
#endif
line_end = 0;
/* command format: cmd [argv1] [argv2] */
/* get command */
while (!line_end) {
skipwhite(&bufp);
ip = cmd;
if (*bufp == '(') {
*ip++ = *bufp++;
} else {
copystr(&ip, &bufp);
}
*ip = 0;
if (!find_token(cmd, &cmd_token, &num_args)) {
loprintf("*** Invalid POD command: '%p'\n", cmd);
return (int *)NULL;
}
#ifdef PDEBUG
loprintf("Command == %p, token == %d, args = %d\n", cmd, cmd_token, num_args);
#endif
if (num_args > 0) {
if (!get_arg(argv1, &arg1_val, &bufp))
return (int *)NULL;
#ifdef PDEBUG
loprintf("Argv1 = %p\n", argv1);
#endif
}
if (num_args > 1) {
if (!get_arg(argv2, &arg2_val, &bufp))
return (int *)NULL;
#ifdef PDEBUG
loprintf("Argv2 = %p\n", argv2);
#endif
}
if (num_args > 2) {
if (!get_arg(argv3, &arg3_val, &bufp))
return (int *)NULL;
#ifdef PDEBUG
loprintf("Argv2 = %p\n", argv3);
#endif
}
line_end = check_eol(&bufp);
if ((flags->selected != 0xff) &&
(flags->slice != flags->selected) &&
(cmd_token != POD_SELECT)) {
loprintf("*** Not selected\n");
return;
}
do {
switch (cmd_token) {
case POD_SELECT:
flags->selected = arg1_val;
loprintf("Selected slice %b\n", arg1_val);
break;
case SERIAL_LOAD:
case SERIAL_RUN:
if (!flags->mem) {
loprintf(
"Your stack must be in memory to download. Use the 'gm' command.\n");
} else {
pon_sload(cmd_token, flags);
}
break;
case WRITE_BYTE:
memory(WRITE, BYTE, arg1_val, 0, arg2_val,
parse_level);
break;
case WRITE_HALF:
memory(WRITE, HALF, arg1_val, 0, arg2_val,
parse_level);
break;
case WRITE_WORD:
memory(WRITE, WORD, arg1_val, 0, arg2_val,
parse_level);
break;
case WRITE_DOUBLE:
memory(WRITE, DOUBLE, arg1_val, 0, arg2_val,
parse_level);
break;
case WRITE_EXTENDED:
u64sw(arg1_val, arg2_val, arg3_val);
break;
case DISP_BYTE:
memory(READ, BYTE, arg1_val, 0, 0,
parse_level);
break;
case DISP_HALF:
memory(READ, HALF, arg1_val, 0, 0,
parse_level);
break;
case DISP_WORD:
memory(READ, WORD, arg1_val, 0, 0,
parse_level);
break;
case DISP_DOUBLE:
memory(READ, DOUBLE, arg1_val, 0, 0,
parse_level);
break;
case DISP_EXTENDED:
loprintf("Bloc %x Offset %x: %x\n",
arg1_val, arg2_val,
u64lw(arg1_val, arg2_val));
break;
case TEST_SCACHE:
pod_check_scache0(arg1_val, flags->de);
break;
#ifndef NO_NIBLET
case NIBLET:
if (!flags->mem) {
loprintf(
"Your stack must be in memory to run Niblet. Use the 'gm' command.\n");
} else {
if (lo_strcmp(argv1, "all")) {
do_niblet(arg1_val);
} else {
for (i = 0; i < 10; i++) {
loprintf(" -- Test #%d --\n",
i);
x = do_niblet(i);
if (x)
break;
}
if (!x)
loprintf("All tests passed.\n");
else
loprintf("*** Test %d FAILED\n",
i);
}
}
break;
#endif /* ! NO_NIBLET */
case GOTO_MEM:
run_cached(pod_loop);
/* Never returns */
break;
case GOTO_CACHE:
pod_handler("Putting stack in dcache\r\n",
EVDIAG_DEBUG);
/* Never returns */
break;
case SET_DE:
if (arg1_val != 1 && arg1_val != 0) {
loprintf("*** DE must be 0 or 1.");
break;
}
flags->de = arg1_val;
break;
case BIG_ENDIAN:
set_endian(arg1_val);
break;
case RESET_SYSTEM:
reset_system();
break;
case DISP_REG:
_register(READ, argv1, 0, gprs);
break;
case DISP_CONF:
conf_register(READ, arg1_val, arg2_val, 0, 0,
parse_level);
break;
case WRITE_CONF:
conf_register(WRITE, arg1_val, arg2_val, 0,
arg3_val, parse_level);
break;
case DISP_MC3:
dump_mc3(arg1_val);
break;
case DISP_IO4:
dump_io4(arg1_val);
break;
case DISP_EVCONFIG:
dump_evcfg(argv1, arg1_val);
break;
case DISP_MPCONF:
dump_mpconf(argv1, arg1_val);
break;
case POD_RESUME:
pod_resume();
break;
case TLB_DUMP:
tlb_dump(argv1, arg1_val);
break;
case CLEAR_STATE:
clear_ip19_state();
loprintf("Cleared CPU error state.\n");
clear_mc3_state();
loprintf("Cleared memory error state.\n");
clear_io4_state();
loprintf("Cleared IO error state.\n");
break;
case SEND_INT:
send_int(arg1_val, arg2_val, arg3_val);
break;
case WRITE_REG:
_register(WRITE,argv1,arg2_val,gprs);
break;
case WALK_MEM:
pod_walk(arg1_val, arg2_val, arg3_val, 1);
break;
case WHY:
flags->scroll_msg = 1;
loprintf("Reason for entering POD mode: %s\n",
flags->diag_string);
break;
case SCOPE_LOOP:
if (*argv1 != '(') {
parse_error();
return (int *)NULL;
}
#ifdef PDEBUG
loprintf(" In sloop: Parser level %d\n", parse_level);
#endif
ip = pod_parse(bufp, gprs, parse_level+1, 1,
flags);
if (ip == (int *)NULL)
return ip;
bufp = ip;
line_end = check_eol(&bufp);
/* Recheck the end of line because we made
recursive parser calls in the switch */
break;
case ZAP_INVENTORY:
zap_inventory();
break;
case FIX_CHECKSUM:
fix_cksum();
break;
case DISP_CHECKSUM:
disp_cksum();
break;
case FINITE_LOOP:
if (*argv2 != '(') {
parse_error();
return (int *)NULL;
}
if (!arg1_val) {
loprintf("*** Loop count must be > 0.\n");
return (int *)NULL;
}
for (i = 0; i < arg1_val; i++) {
ip = pod_parse(bufp, gprs,
parse_level+1, 0, flags);
#ifdef PDEBUG
loprintf(" In loop: Parser level %d\n", parse_level);
#endif
if (ip == (int *)NULL)
return ip;
}
bufp = ip;
line_end = check_eol(&bufp);
/* Recheck the end of line because we made
recursive parser calls in the switch */
break;
case LEFT_PAREN:
#ifdef PDEBUG
loprintf("Left paren.\n");
#endif
bufp = pod_parse(bufp, gprs, parse_level+1, 0,
flags);
#ifdef PDEBUG
loprintf(" Parser level %d\n", parse_level);
#endif
line_end = check_eol(&bufp);
/* Recheck the end of line because we made
recursive parser calls in the switch */
break;
case DISP_INFO:
info();
break;
case DECODE_ADDR:
decode_address(arg1_val);
break;
case PRM_CRD:
prm_crd(flags);
break;
case FLUSHT:
flush_tlb();
break;
case FLUSHD:
call_asm(pon_flush_dcache, 0);
break;
case FLUSHS:
call_asm(pon_flush_scache, 0);
break;
case FLUSHI:
call_asm(pon_invalidate_icache, 0);
break;
case DTAG_DUMP:
case STAG_DUMP:
case ITAG_DUMP:
dump_tag(cmd_token, arg1_val);
break;
case DECODE_ECC:
pod_ecc();
break;
case TEST_MEM:
mem_test(arg1_val, arg2_val, flags);
break;
case SLAVE_MODE:
jump_addr((uint)prom_slave, 0, 0, flags);
break;
case JUMP_ADDR:
arg2_val = 0;
/* Fall through */
case JUMP_ADDR1:
arg3_val = 0;
/* Fall through */
case JUMP_ADDR2:
loprintf("Returned %x\n",
jump_addr(arg1_val,
arg2_val, arg3_val, flags));
break;
case DOWNLOAD_IO4:
load_io4prom();
break;
case DISABLE_UNIT:
(void)set_unit_enable(arg1_val, arg2_val, 0, 0);
break;
case FDISABLE_UNIT:
(void)set_unit_enable(arg1_val, arg2_val, 0, 1);
break;
case ENABLE_UNIT:
(void)set_unit_enable(arg1_val, arg2_val, 1, 0);
break;
case FENABLE_UNIT:
(void)set_unit_enable(arg1_val, arg2_val, 1, 1);
break;
case DO_BIST:
if (flags->mem) {
loprintf(
"Your stack must be in cache to reconfigure memory. Use the 'gc' command.\n");
} else {
pod_bist();
}
break;
case RECONF_MEM:
if (flags->mem) {
loprintf(
"Your stack must be in cache to reconfigure memory. Use the 'gc' command.\n");
} else {
pod_reconf_mem();
}
break;
case DISP_HELP:
loprintf("\
All numerical inputs should be in hex with or without 0x preceding them.\n");
loprintf("\
Commands may be separated by semicolons, and loops may be nested.\n");
x = 2;
for (i = 0; (commands[i].token != NULL); i++) {
if (get_char(commands[i].help)) {
loprintf(" %s\n",
commands[i].help);
x++;
}
if (!(x % 23) && !parse_level) {
loprintf("--MORE--");
pod_getc();
loprintf("\r \r");
}
}
break;
case NO_COMMAND:
break;
default:
loprintf("*** Unimplemented POD command: '%p'\n", cmd);
break;
} /* Switch */
if (sloop)
if (pod_poll()) {
pod_getc();
sloop = 0;
}
} while (sloop);
} /* While line end */
return bufp;
}
int lo_strcmp(int *ip, char *cp) /* biendian */
{
FLIPINIT(dosw, cp);
while (*ip == ' ' && *ip != 0)
ip++;
while ((EVCFLIP(dosw, cp) != 0) || (*ip != 0)) {
if (*ip++ == EVCFLIP(dosw,cp++))
continue;
else
return(-1);
}
return(0);
}
void lo_strcpy(char *dest, char *src) /* biendian */
{
FLIPINIT(dosw, src);
while (EVCFLIP(dosw, src) != 0)
*dest++ = EVCFLIP(dosw, src++);
}
uint lo_atoh(int *cp)
{
register unsigned i;
/* Ignore leading 0x or 0X */
if (*cp == '0' && (*(cp+1) == 'x' || *(cp+1) == 'X'))
cp += 2;
for (i = 0 ; lo_ishex(*cp) ;)
if (*cp <= '9')
i = i*16 + *cp++ - '0';
else {
if (*cp >= 'a')
i = i * 16 + *cp++ - 'a' + 10;
else
i = i * 16 + *cp++ - 'A' + 10;
}
return i;
}
uint lo_atoi(int *cp)
{
register unsigned i;
for (i = 0 ; isdigit(*cp) ;)
i = i*10 + *cp++ - '0';
return i;
}
int lo_ishex(int c)
{
if ((c >= '0' && c <= '9') ||
(c >= 'A' && c <= 'F') ||
(c >= 'a' && c <= 'f')) {
return 1;
}
else
return 0;
}