NetBSD/sys/dev/microcode/siop/ncr53cxxx.c
bouyer 5ee6872b46 - Add support for NOP instruction
- fix dsp value for second operand of memory move, so that patch list will be
  correct.
2000-04-25 16:01:16 +00:00

1385 lines
30 KiB
C

/* $NetBSD: ncr53cxxx.c,v 1.2 2000/04/25 16:01:16 bouyer Exp $ */
/*
* Copyright (c) 1995,1999 Michael L. Hitch
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Michael L. Hitch.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* ncr53cxxx.c - SCSI SCRIPTS Assembler */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#ifndef AMIGA
#define strcmpi strcasecmp
#endif
#define MAXTOKENS 16
#define MAXINST 1024
#define MAXSYMBOLS 128
struct {
int type;
char *name;
} tokens[MAXTOKENS];
int ntokens;
int tokenix;
void f_proc (void);
void f_pass (void);
void f_list (void); /* ENTRY, EXTERNAL label list */
void f_define (void); /* ABSOLUTE, RELATIVE label list */
void f_move (void);
void f_jump (void);
void f_call (void);
void f_return (void);
void f_int (void);
void f_select (void);
void f_reselect (void);
void f_wait (void);
void f_disconnect (void);
void f_set (void);
void f_clear (void);
void f_load (void);
void f_store (void);
void f_nop (void);
void f_arch (void);
struct {
char *name;
void (*func)(void);
} directives[] = {
{"PROC", f_proc},
{"PASS", f_pass},
{"ENTRY", f_list},
{"ABSOLUTE", f_define},
{"EXTERN", f_list},
{"EXTERNAL", f_list},
{"RELATIVE", f_define},
{"MOVE", f_move},
{"JUMP", f_jump},
{"CALL", f_call},
{"RETURN", f_return},
{"INT", f_int},
{"SELECT", f_select},
{"RESELECT", f_reselect},
{"WAIT", f_wait},
{"DISCONNECT", f_disconnect},
{"SET", f_set},
{"CLEAR", f_clear},
{"LOAD", f_load},
{"STORE", f_store},
{"NOP", f_nop},
{"ARCH", f_arch},
{NULL, NULL}};
u_int32_t script[MAXINST];
int dsps;
char *script_name = "SCRIPT";
u_int32_t inst0, inst1, inst2;
unsigned int ninsts;
unsigned int npatches;
struct patchlist {
struct patchlist *next;
unsigned offset;
};
#define S_LABEL 0x0000
#define S_ABSOLUTE 0x0001
#define S_RELATIVE 0x0002
#define S_EXTERNAL 0x0003
#define F_DEFINED 0x0001
#define F_ENTRY 0x0002
struct {
short type;
short flags;
u_int32_t value;
struct patchlist *patchlist;
char *name;
} symbols[MAXSYMBOLS];
int nsymbols;
char *stypes[] = {"Label", "Absolute", "Relative", "External"};
char *phases[] = {
"data_out", "data_in", "cmd", "status",
"res4", "res5", "msg_out", "msg_in"
};
struct ncrregs {
char *name;
int addr[4];
};
#define ARCH710 1
#define ARCH720 2
#define ARCH810 3
#define ARCH825 4
struct ncrregs regs[] = {
{"scntl0", {0x00, 0x00, 0x00, 0x00}},
{"scntl1", {0x01, 0x01, 0x01, 0x01}},
{"scntl2", {-1, 0x02, 0x02, 0x02}},
{"scntl3", {-1, 0x03, 0x03, 0x03}},
{"scid", {-1, 0x04, 0x04, 0x04}},
{"sdid", {0x02, -1, -1, -1}},
{"sien", {0x03, -1, -1, -1}},
{"scid", {0x04, -1, -1, -1}},
{"sxfer", {0x05, 0x05, 0x05, 0x05}},
{"sdid", {-1, 0x06, 0x06, 0x06}},
{"gpreg", {-1, 0x07, 0x07, 0x07}},
{"sodl", {0x06, -1, -1, -1}},
{"socl", {0x07, -1, -1, -1}},
{"sfbr", {0x08, 0x08, 0x08, 0x08}},
{"socl", {-1, 0x09, 0x09, 0x09}},
{"ssid", {-1, 0x0a, 0x0a, 0x0a}},
{"sidl", {0x09, -1, -1, -1}},
{"sbdl", {0x0a, -1, -1, -1}},
{"sbcl", {0x0b, 0x0b, 0x0b, 0x0b}},
{"dstat", {0x0c, 0x0c, 0x0c, 0x0c}},
{"sstat0", {0x0d, 0x0d, 0x0d, 0x0d}},
{"sstat1", {0x0e, 0x0e, 0x0e, 0x0e}},
{"sstat2", {0x0f, 0x0f, 0x0f, 0x0f}},
{"dsa0", {0x10, 0x10, 0x10, 0x10}},
{"dsa1", {0x11, 0x11, 0x11, 0x11}},
{"dsa2", {0x12, 0x12, 0x12, 0x12}},
{"dsa3", {0x13, 0x13, 0x13, 0x13}},
{"istat", {-1, 0x14, 0x14, 0x14}},
{"ctest0", {0x14, 0x18, 0x18, 0x18}},
{"ctest1", {0x15, 0x19, 0x19, 0x19}},
{"ctest2", {0x16, 0x1a, 0x1a, 0x1a}},
{"ctest3", {0x17, 0x1b, 0x1b, 0x1b}},
{"temp0", {-1, 0x1c, 0x1c, 0x1c}},
{"temp1", {-1, 0x1d, 0x1d, 0x1d}},
{"temp2", {-1, 0x1e, 0x1e, 0x1e}},
{"temp3", {-1, 0x1f, 0x1f, 0x1f}},
{"dfifo", {-1, 0x20, 0x20, 0x20}},
{"ctest4", {0x18, 0x21, 0x21, 0x21}},
{"ctest5", {0x19, 0x22, 0x22, 0x22}},
{"ctest6", {0x20, 0x23, 0x23, 0x23}},
{"ctest7", {0x21, -1, -1, -1}},
{"temp0", {0x22, -1, -1, -1}},
{"temp1", {0x23, -1, -1, -1}},
{"temp2", {0x24, -1, -1, -1}},
{"temp3", {0x25, -1, -1, -1}},
{"dfifo", {0x26, -1, -1, -1}},
{"istat", {0x27, -1, -1, -1}},
{"ctest8", {0x28, -1, -1, -1}},
{"lcrc", {0x29, -1, -1, -1}},
{"dbc0", {0x2a, 0x24, 0x24, 0x24}},
{"dbc1", {0x2b, 0x25, 0x25, 0x25}},
{"dbc2", {0x2c, 0x26, 0x26, 0x26}},
{"dcmd", {0x2d, 0x27, 0x27, 0x27}},
{"dnad0", {0x2e, 0x28, 0x28, 0x28}},
{"dnad1", {0x2f, 0x29, 0x29, 0x29}},
{"dnad2", {0x30, 0x2a, 0x2a, 0x2a}},
{"dnad3", {0x31, 0x2b, 0x2b, 0x2b}},
{"dsp0", {0x32, 0x2c, 0x2c, 0x2c}},
{"dsp1", {0x33, 0x2d, 0x2d, 0x2d}},
{"dsp2", {0x34, 0x2e, 0x2e, 0x2e}},
{"dsp3", {0x35, 0x2f, 0x2f, 0x2f}},
{"dsps0", {0x36, 0x30, 0x30, 0x30}},
{"dsps1", {0x37, 0x31, 0x31, 0x31}},
{"dsps2", {0x38, 0x32, 0x32, 0x32}},
{"dsps3", {0x39, 0x33, 0x33, 0x33}},
{"scratch0", {0x40, -1, -1, -1}},
{"scratch1", {0x41, -1, -1, -1}},
{"scratch2", {0x42, -1, -1, -1}},
{"scratch3", {0x43, -1, -1, -1}},
{"scratcha0", { -1, 0x34, 0x34, 0x34}},
{"scratcha1", { -1, 0x35, 0x35, 0x35}},
{"scratcha2", { -1, 0x36, 0x36, 0x36}},
{"scratcha3", { -1, 0x37, 0x37, 0x37}},
{"dmode", {0x44, 0x38, 0x38, 0x38}},
{"dien", {0x45, 0x39, 0x39, 0x39}},
{"dwt", {0x46, 0x3a, -1, -1}},
{"sbr", { -1, -1, 0x3a, 0x3a}},
{"dcntl", {0x47, 0x3b, 0x3b, 0x3b}},
{"addr0", {0x48, 0x3c, 0x3c, 0x3c}},
{"addr1", {0x49, 0x3d, 0x3d, 0x3d}},
{"addr2", {0x4A, 0x3e, 0x3e, 0x3e}},
{"addr3", {0x4B, 0x3f, 0x3f, 0x3f}},
{"sien0", { -1, 0x40, 0x40, 0x40}},
{"sien1", { -1, 0x41, 0x41, 0x41}},
{"sist0", { -1, 0x42, 0x42, 0x42}},
{"sist1", { -1, 0x43, 0x43, 0x43}},
{"slpar", { -1, 0x44, 0x44, 0x44}},
{"swide", { -1, 0x45, -1, 0x45}},
{"macntl", { -1, 0x46, 0x46, 0x46}},
{"gpcntl", { -1, 0x47, 0x47, 0x47}},
{"stime0", { -1, 0x48, 0x48, 0x48}},
{"stime1", { -1, 0x49, 0x49, 0x49}},
{"respid0", { -1, 0x4a, 0x4a, 0x4a}},
{"respid1", { -1, 0x4b, -1, 0x4b}},
{"stest0", { -1, 0x4c, 0x4c, 0x4c}},
{"stest1", { -1, 0x4d, 0x4d, 0x4d}},
{"stest2", { -1, 0x4e, 0x4e, 0x4e}},
{"stest3", { -1, 0x4f, 0x4f, 0x4f}},
{"sidl0", { -1, 0x50, 0x50, 0x50}},
{"sidl1", { -1, 0x51, -1, 0x51}},
{"sodl0", { -1, 0x54, 0x54, 0x54}},
{"sodl1", { -1, 0x55, -1, 0x55}},
{"sbdl0", { -1, 0x58, 0x58, 0x58}},
{"sbdl1", { -1, 0x59, -1, 0x59}},
{"scratchb0", { -1, 0x5c, 0x5c, 0x5c}},
{"scratchb1", { -1, 0x5d, 0x5d, 0x5d}},
{"scratchb2", { -1, 0x5e, 0x5e, 0x5e}},
{"scratchb3", { -1, 0x5f, 0x5f, 0x5f}},
{"scratchc0", { -1, -1, -1, 0x60}},
{"scratchc1", { -1, -1, -1, 0x61}},
{"scratchc2", { -1, -1, -1, 0x62}},
{"scratchc3", { -1, -1, -1, 0x63}},
{"scratchd0", { -1, -1, -1, 0x64}},
{"scratchd1", { -1, -1, -1, 0x65}},
{"scratchd2", { -1, -1, -1, 0x5e}},
{"scratchd3", { -1, -1, -1, 0x67}},
{"scratche0", { -1, -1, -1, 0x68}},
{"scratche1", { -1, -1, -1, 0x69}},
{"scratche2", { -1, -1, -1, 0x6a}},
{"scratche3", { -1, -1, -1, 0x6b}},
{"scratchf0", { -1, -1, -1, 0x6c}},
{"scratchf1", { -1, -1, -1, 0x6d}},
{"scratchf2", { -1, -1, -1, 0x6e}},
{"scratchf3", { -1, -1, -1, 0x6f}},
{"scratchg0", { -1, -1, -1, 0x70}},
{"scratchg1", { -1, -1, -1, 0x71}},
{"scratchg2", { -1, -1, -1, 0x72}},
{"scratchg3", { -1, -1, -1, 0x73}},
{"scratchh0", { -1, -1, -1, 0x74}},
{"scratchh1", { -1, -1, -1, 0x75}},
{"scratchh2", { -1, -1, -1, 0x7e}},
{"scratchh3", { -1, -1, -1, 0x77}},
{"scratchi0", { -1, -1, -1, 0x78}},
{"scratchi1", { -1, -1, -1, 0x79}},
{"scratchi2", { -1, -1, -1, 0x7a}},
{"scratchi3", { -1, -1, -1, 0x7b}},
{"scratchj0", { -1, -1, -1, 0x7c}},
{"scratchj1", { -1, -1, -1, 0x7d}},
{"scratchj2", { -1, -1, -1, 0x7e}},
{"scratchj3", { -1, -1, -1, 0x7f}},
};
int lineno;
int err_listed;
int arch;
int partial_flag;
char inbuf[128];
char *sourcefile;
char *outputfile;
char *listfile;
char *errorfile;
FILE *infp;
FILE *outfp;
FILE *listfp;
FILE *errfp;
void setarch(char *);
void parse (void);
void process (void);
void emit_symbols (void);
void list_symbols (void);
void errout (char *);
void define_symbol (char *, u_int32_t, short, short);
void close_script (void);
void new_script (char *);
void store_inst (void);
int expression (int *);
int evaluate (int);
int number (char *);
int lookup (char *);
int reserved (char *, int);
int CheckPhase (int);
int CheckRegister (int);
void transfer (int, int);
void select_reselect (int);
void set_clear (u_int32_t);
void block_move (void);
void register_write (void);
void memory_to_memory (void);
void loadstore (int);
void error_line(void);
char *makefn(char *, char *);
void usage(void);
int
main (int argc, char *argv[])
{
int i;
if (argc < 2 || argv[1][0] == '-')
usage();
sourcefile = argv[1];
infp = fopen (sourcefile, "r");
if (infp == NULL) {
perror ("open source");
fprintf (stderr, "scc: error opening source file %s\n", argv[1]);
exit (1);
}
/*
* process options
* -l [listfile]
* -o [outputfile]
* -p [outputfile]
* -z [debugfile]
* -e [errorfile]
* -a arch
* -v
* -u
*/
for (i = 2; i < argc; ++i) {
if (argv[i][0] != '-')
usage();
switch (argv[i][1]) {
case 'o':
case 'p':
partial_flag = argv[i][1] == 'p';
if (i + 1 >= argc || argv[i + 1][0] == '-')
outputfile = makefn (sourcefile, "out");
else {
outputfile = argv[i + 1];
++i;
}
break;
case 'l':
if (i + 1 >= argc || argv[i + 1][0] == '-')
listfile = makefn (sourcefile, "lis");
else {
listfile = argv[i + 1];
++i;
}
break;
case 'e':
if (i + 1 >= argc || argv[i + 1][0] == '-')
errorfile = makefn (sourcefile, "err");
else {
errorfile = argv[i + 1];
++i;
}
break;
case 'a':
if (i + 1 == argc)
usage();
setarch(argv[i +1]);
if (arch == 0) {
fprintf(stderr,"%s: bad arch '%s'\n",
argv[0], argv[i +1]);
exit(1);
}
++i;
break;
default:
fprintf (stderr, "scc: unrecognized option '%c'\n",
argv[i][1]);
usage();
}
}
if (outputfile)
outfp = fopen (outputfile, "w");
if (listfile)
listfp = fopen (listfile, "w");
if (errorfile)
errfp = fopen (errorfile, "w");
else
errfp = stderr;
if (outfp) {
time_t cur_time;
fprintf(outfp, "/*\t$NetBSD: ncr53cxxx.c,v 1.2 2000/04/25 16:01:16 bouyer Exp $\t*/\n");
fprintf(outfp, "/*\n");
fprintf(outfp, " *\tDO NOT EDIT - this file is automatically generated.\n");
time(&cur_time);
fprintf(outfp, " *\tcreated from %s on %s", sourcefile, ctime(&cur_time));
fprintf(outfp, " */\n");
}
while (fgets (inbuf, sizeof (inbuf), infp)) {
++lineno;
if (listfp)
fprintf (listfp, "%3d: %s", lineno, inbuf);
err_listed = 0;
parse ();
if (ntokens) {
#ifdef DUMP_TOKENS
int i;
fprintf (listfp, " %d tokens\n", ntokens);
for (i = 0; i < ntokens; ++i) {
fprintf (listfp, " %d: ", i);
if (tokens[i].type)
fprintf (listfp,"'%c'\n", tokens[i].type);
else
fprintf (listfp, "%s\n", tokens[i].name);
}
#endif
if (ntokens >= 2 && tokens[0].type == 0 &&
tokens[1].type == ':') {
define_symbol (tokens[0].name, dsps, S_LABEL, F_DEFINED);
tokenix += 2;
}
if (tokenix < ntokens)
process ();
}
}
close_script ();
emit_symbols ();
if (outfp && !partial_flag) {
fprintf (outfp, "\nu_int32_t INSTRUCTIONS = 0x%08x;\n", ninsts);
fprintf (outfp, "u_int32_t PATCHES = 0x%08x;\n", npatches);
}
list_symbols ();
exit(0);
}
void setarch(char *val)
{
switch (atoi(val)) {
case 710:
arch = ARCH710;
break;
case 720:
arch = ARCH720;
break;
case 810:
arch = ARCH810;
break;
case 825:
arch = ARCH825;
break;
default:
arch = 0;
}
}
void emit_symbols ()
{
int i;
struct patchlist *p;
if (nsymbols == 0 || outfp == NULL)
return;
for (i = 0; i < nsymbols; ++i) {
char *code;
if (symbols[i].type == S_ABSOLUTE)
code = "A_";
else if (symbols[i].type == S_RELATIVE)
code = "R_";
else if (symbols[i].type == S_EXTERNAL)
code = "E_";
else if (symbols[i].flags & F_ENTRY)
code = "Ent_";
else
continue;
fprintf (outfp, "#define\t%s%s\t0x%08x\n", code, symbols[i].name,
symbols[i].value);
if (symbols[i].flags & F_ENTRY || symbols[i].patchlist == NULL)
continue;
fprintf (outfp, "u_int32_t %s%s_Used[] = {\n", code, symbols[i].name);
#if 1
p = symbols[i].patchlist;
while (p) {
fprintf (outfp, "\t0x%08x,\n", p->offset / 4);
p = p->next;
}
#endif
fprintf (outfp, "};\n\n");
}
/* patches ? */
}
void list_symbols ()
{
int i;
if (nsymbols == 0 || listfp == NULL)
return;
fprintf (listfp, "\n\nValue Type Symbol\n");
for (i = 0; i < nsymbols; ++i) {
fprintf (listfp, "%08x: %-8s %s\n", symbols[i].value,
stypes[symbols[i].type], symbols[i].name);
}
}
void errout (char *text)
{
error_line();
fprintf (errfp, "*** %s ***\n", text);
}
void parse ()
{
char *p = inbuf;
char c;
char string[64];
char *s;
ntokens = tokenix = 0;
while (1) {
while ((c = *p++) && c != '\n' && (c <= ' ' || c == '\t'))
;
if (c == '\n' || c == 0 || c == ';')
break;
if (ntokens >= MAXTOKENS) {
errout ("Token table full");
break;
}
if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z') || c == '$' || c == '_') {
s = string;
*s++ = c;
while (((c = *p) >= '0' && c <= '9') ||
(c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
c == '_' || c == '$') {
*s++ = *p++;
}
*s = 0;
tokens[ntokens].name = malloc (strlen (string) + 1);
strcpy (tokens[ntokens].name, string);
tokens[ntokens].type = 0;
}
else {
tokens[ntokens].type = c;
}
++ntokens;
}
return;
}
void process ()
{
int i;
if (tokens[tokenix].type) {
error_line();
fprintf (errfp, "Error: expected directive, found '%c'\n",
tokens[tokenix].type);
return;
}
for (i = 0; directives[i].name; ++i) {
if (strcmpi (directives[i].name, tokens[tokenix].name) == 0)
break;
}
if (directives[i].name == NULL) {
error_line();
fprintf (errfp, "Error: expected directive, found \"%s\"\n",
tokens[tokenix].name);
return;
}
if (directives[i].func == NULL) {
error_line();
fprintf (errfp, "No function for directive \"%s\"\n", tokens[tokenix].name);
} else {
#if 0
fprintf (listfp, "Processing directive \"%s\"\n", directives[i].name);
#endif
++tokenix;
(*directives[i].func) ();
}
}
void define_symbol (char *name, u_int32_t value, short type, short flags)
{
int i;
struct patchlist *p;
for (i = 0; i < nsymbols; ++i) {
if (symbols[i].type == type && strcmp (symbols[i].name, name) == 0) {
if (symbols[i].flags & F_DEFINED) {
error_line();
fprintf (errfp, "*** Symbol \"%s\" multiply defined\n",
name);
} else {
symbols[i].flags |= flags;
symbols[i].value = value;
p = symbols[i].patchlist;
while (p) {
if (p->offset > dsps)
errout ("Whoops\007");
else
script[p->offset / 4] = dsps - p->offset - 4;
p = p->next;
}
}
return;
}
}
if (nsymbols >= MAXSYMBOLS) {
errout ("Symbol table full");
return;
}
symbols[nsymbols].type = type;
symbols[nsymbols].flags = flags;
symbols[nsymbols].value = value;
symbols[nsymbols].patchlist = NULL;
symbols[nsymbols].name = malloc (strlen (name) + 1);
strcpy (symbols[nsymbols].name, name);
++nsymbols;
}
void close_script ()
{
int i;
if (dsps == 0)
return;
if (outfp) {
fprintf (outfp, "const u_int32_t %s[] = {\n", script_name);
for (i = 0; i < dsps / 4; i += 2) {
fprintf (outfp, "\t0x%08x, 0x%08x", script[i],
script[i + 1]);
/* check for memory move instruction */
if ((script[i] & 0xe0000000) == 0xc0000000)
fprintf (outfp, ", 0x%08x,", script[i + 2]);
else
if ((i + 2) <= dsps / 4) fprintf (outfp, ",\t\t");
fprintf (outfp, "\t/* %03x - %3d */\n", i * 4, i * 4);
if ((script[i] & 0xe0000000) == 0xc0000000)
++i;
}
fprintf (outfp, "};\n\n");
}
dsps = 0;
}
void new_script (char *name)
{
close_script ();
script_name = malloc (strlen (name) + 1);
strcpy (script_name, name);
}
int reserved (char *string, int t)
{
if (tokens[t].type == 0 && strcmpi (tokens[t].name, string) == 0)
return (1);
return (0);
}
int CheckPhase (int t)
{
int i;
for (i = 0; i < 8; ++i) {
if (reserved (phases[i], t)) {
inst0 |= i << 24;
return (1);
}
}
return (0);
}
int CheckRegister (int t)
{
int i;
if (arch <= 0) {
errout("'ARCH' statement missing");
return -1;
}
for (i = 0; i < (sizeof(regs) / sizeof(regs[0])); i++) {
if (regs[i].addr[arch - 1] >= 0 && reserved(regs[i].name, t))
return regs[i].addr[arch-1];
}
return (-1);
}
int expression (int *t)
{
int value;
int i = *t;
value = evaluate (i++);
while (i < ntokens) {
if (tokens[i].type == '+')
value += evaluate (i + 1);
else if (tokens[i].type == '-')
value -= evaluate (i + 1);
else
errout ("Unknown identifier");
i += 2;
}
*t = i;
return (value);
}
int evaluate (t)
{
int value;
char *name;
if (tokens[t].type) {
errout ("Expected an identifier");
return (0);
}
name = tokens[t].name;
if (*name >= '0' && *name <= '9')
value = number (name);
else
value = lookup (name);
return (value);
}
int number (char *s)
{
int value;
int n;
int radix;
radix = 10;
if (*s == '0') {
++s;
radix = 8;
switch (*s) {
case 'x':
case 'X':
radix = 16;
break;
case 'b':
case 'B':
radix = 2;
}
if (radix != 8)
++s;
}
value = 0;
while (*s) {
n = *s++;
if (n >= '0' && n <= '9')
n -= '0';
else if (n >= 'a' && n <= 'f')
n -= 'a' - 10;
else if (n >= 'A' && n <= 'F')
n -= 'A' - 10;
else {
error_line();
fprintf (errfp, "*** Expected digit\n");
n = 0;
}
if (n >= radix)
errout ("Expected digit");
else
value = value * radix + n;
}
return (value);
}
int lookup (char *name)
{
int i;
struct patchlist *p;
for (i = 0; i < nsymbols; ++i) {
if (strcmp (name, symbols[i].name) == 0) {
if ((symbols[i].flags & F_DEFINED) == 0) {
p = (struct patchlist *) &symbols[i].patchlist;
while (p->next)
p = p->next;
p->next = (struct patchlist *) malloc (sizeof (struct patchlist));
p = p->next;
p->next = NULL;
p->offset = dsps + 4;
}
return ((int) symbols[i].value);
}
}
if (nsymbols >= MAXSYMBOLS) {
errout ("Symbol table full");
return (0);
}
symbols[nsymbols].type = S_LABEL; /* assume forward reference */
symbols[nsymbols].flags = 0;
symbols[nsymbols].value = 0;
p = (struct patchlist *) malloc (sizeof (struct patchlist));
symbols[nsymbols].patchlist = p;
p->next = NULL;
p->offset = dsps + 4;
symbols[nsymbols].name = malloc (strlen (name) + 1);
strcpy (symbols[nsymbols].name, name);
++nsymbols;
return (0);
}
void f_arch (void)
{
int i, archsave;
i = tokenix;
archsave = arch;
setarch(tokens[i].name);
if( arch == 0) {
errout("Unrecognized ARCH");
arch = archsave;
}
}
void f_proc (void)
{
if (tokens[tokenix].type != 0 || tokens[tokenix + 1].type != ':')
errout ("Invalid PROC statement");
else
new_script (tokens[tokenix].name);
}
void f_pass (void)
{
errout ("PASS option not implemented");
}
/*
* f_list: process list of symbols for the ENTRY and EXTERNAL directive
*/
void f_list (void)
{
int i;
short type;
short flags;
type = strcmpi (tokens[tokenix-1].name, "ENTRY") ? S_EXTERNAL : S_LABEL;
flags = type == S_LABEL ? F_ENTRY : 0;
for (i = tokenix; i < ntokens; ++i) {
if (tokens[i].type != 0) {
errout ("Expected an identifier");
return;
}
define_symbol (tokens[i].name, 0, type, flags);
if (i + 1 < ntokens) {
if (tokens[++i].type == ',')
continue;
errout ("Expected a separator");
return;
}
}
}
/*
* f_define: process list of definitions for ABSOLUTE and RELATIVE directive
*/
void f_define (void)
{
int i;
char *name;
u_int32_t value;
int type;
type = strcmpi (tokens[tokenix-1].name, "ABSOLUTE") ? S_RELATIVE : S_ABSOLUTE;
i = tokenix;
while (i < ntokens) {
if (tokens[i].type) {
errout ("Expected an identifier");
return;
}
if (tokens[i + 1].type != '=') {
errout ("Expected a separator");
return;
}
name = tokens[i].name;
i += 2;
value = expression (&i);
define_symbol (name, value, type, F_DEFINED);
}
}
void store_inst ()
{
int i = dsps / 4;
int l = 8;
if ((inst0 & 0xe0000000) == 0xc0000000)
l = 12; /* Memory to memory move is 12 bytes */
if ((dsps + l) / 4 > MAXINST) {
errout ("Instruction table overflow");
return;
}
script[i++] = inst0;
script[i++] = inst1;
if (l == 12)
script[i++] = inst2;
if (listfp) {
fprintf (listfp, "\t%04x: %08x %08x", dsps, inst0, inst1);
if (l == 12)
fprintf (listfp, " %08x", inst2);
fprintf (listfp, "\n");
}
dsps += l;
inst0 = inst1 = inst2 = 0;
++ninsts;
}
void f_move (void)
{
if (reserved ("memory", tokenix))
memory_to_memory ();
else if (reserved ("from", tokenix) || tokens[tokenix+1].type == ',')
block_move ();
else
register_write ();
store_inst ();
}
void f_jump (void)
{
transfer (0x80000000, 0);
}
void f_call (void)
{
transfer (0x88000000, 0);
}
void f_return (void)
{
transfer (0x90000000, 1);
}
void f_int (void)
{
transfer (0x98000000, 2);
}
void f_select (void)
{
int t = tokenix;
if (reserved ("atn", t)) {
inst0 = 0x01000000;
++t;
}
select_reselect (t);
}
void f_reselect (void)
{
select_reselect (tokenix);
}
void f_wait (void)
{
int i = tokenix;
inst1 = 0;
if (reserved ("disconnect", i)) {
inst0 = 0x48000000;
}
else {
if (reserved ("reselect", i))
inst0 = 0x50000000;
else if (reserved ("select", i))
inst0 = 0x50000000;
else
errout ("Expected SELECT or RESELECT");
++i;
if (reserved ("rel", i)) {
i += 2;
inst1 = evaluate (i) - dsps - 8;
inst0 |= 0x04000000;
}
else
inst1 = evaluate (i);
}
store_inst ();
}
void f_disconnect (void)
{
inst0 = 0x48000000;
store_inst ();
}
void f_set (void)
{
set_clear (0x58000000);
}
void f_clear (void)
{
set_clear (0x60000000);
}
void f_load (void)
{
inst0 = 0xe1000000;
if (arch < ARCH810) {
errout ("Wrong arch for load/store");
return;
}
loadstore(tokenix);
}
void f_store (void)
{
int i;
inst0 = 0xe0000000;
if (arch < ARCH810) {
errout ("Wrong arch for load/store");
return;
}
i = tokenix;
if (reserved("noflush", i)) {
inst0 |= 0x2000000;
i++;
}
loadstore(i);
}
void f_nop (void)
{
inst0 = 0x10000000;
inst1 = 0x00000000;
store_inst ();
}
void loadstore(int i)
{
int reg, size;
reg = CheckRegister(i);
if (reg < 0)
errout ("Expected register");
else
inst0 |= reg << 16;
if (reg == 8)
errout ("Register can't be SFBR");
i++;
if (tokens[i].type == ',')
i++;
else
errout ("expected ','");
size = evaluate(i);
if (i < 1 || i > 4)
errout("wrong size");
if ((reg & 0x3) + size > 4)
errout("size too big for register");
inst0 |= size;
i++;
if (tokens[i].type == ',')
i++;
else
errout ("expected ','");
if (reserved("from", i) || reserved("dsarel", i)) {
i++;
inst0 |= 0x10000000;
}
inst1 = evaluate(i);
store_inst ();
}
void transfer (int word0, int type)
{
int i;
i = tokenix;
inst0 = word0;
if (type == 0 && reserved ("rel", i)) {
inst1 = evaluate (i + 2) - dsps - 8;
i += 3;
inst0 |= 0x00800000;
}
else if (type != 1) {
inst1 = evaluate (i);
}
++i;
if (i >= ntokens) {
inst0 |= 0x00080000;
store_inst ();
return;
}
if (tokens[i].type != ',')
errout ("Expected a separator, ',' assumed");
else
++i;
if (reserved("when", i))
inst0 |= 0x00010000;
else if (reserved ("if", i) == 0) {
errout ("Expected a reserved word");
store_inst ();
return;
}
if (reserved ("not", ++i))
++i;
else
inst0 |= 0x00080000;
if (reserved ("atn", i)) {
inst0 |= 0x00020000;
++i;
} else if (CheckPhase (i)) {
inst0 |= 0x00020000;
++i;
}
if (i < ntokens && tokens[i].type != ',') {
if (inst0 & 0x00020000) {
if (inst0 & 0x00080000 && reserved ("and", i)) {
++i;
}
else if ((inst0 & 0x00080000) == 0 && reserved ("or", i)) {
++i;
}
else
errout ("Expected a reserved word");
}
inst0 |= 0x00040000 + (evaluate (i++) & 0xff);
}
if (i < ntokens) {
if (tokens[i].type == ',')
++i;
else
errout ("Expected a separator, ',' assumed");
if (reserved ("and", i) && reserved ("mask", i + 1))
inst0 |= ((evaluate (i + 2) & 0xff) << 8);
else
errout ("Expected , AND MASK");
}
store_inst ();
}
void select_reselect (int t)
{
inst0 |= 0x40000000; /* ATN may be set from SELECT */
if (reserved ("from", t)) {
++t;
inst0 |= 0x02000000 | evaluate (t++);
}
else
inst0 |= (evaluate (t++) & 0xff) << 16;
if (tokens[t++].type == ',') {
if (reserved ("rel", t)) {
inst0 |= 0x04000000;
inst1 = evaluate (t + 2) - dsps - 8;
}
else
inst1 = evaluate (t);
}
else
errout ("Expected separator");
store_inst ();
}
void set_clear (u_int32_t code)
{
int i = tokenix;
short need_and = 0;
inst0 = code;
while (i < ntokens) {
if (need_and) {
if (reserved ("and", i))
++i;
else
errout ("Expected AND");
}
if (reserved ("atn", i)) {
inst0 |= 0x0008;
++i;
}
else if (reserved ("ack", i)) {
inst0 |= 0x0040;
++i;
}
else if (reserved ("target", i)) {
inst0 |= 0x0200;
++i;
}
else
errout ("Expected ATN, ACK, or TARGET");
need_and = 1;
}
store_inst ();
}
void block_move ()
{
if (reserved ("from", tokenix)) {
inst1 = evaluate (tokenix+1);
inst0 |= 0x10000000 | inst1; /*** ??? to match Zeus script */
tokenix += 2;
}
else {
inst0 |= evaluate (tokenix++); /* count */
tokenix++; /* skip ',' */
if (reserved ("ptr", tokenix)) {
++ tokenix;
inst0 |= 0x20000000;
}
inst1 = evaluate (tokenix++); /* address */
}
if (tokens[tokenix].type != ',')
errout ("Expected separator");
if (reserved ("when", tokenix + 1)) {
inst0 |= 0x08000000;
CheckPhase (tokenix + 2);
}
else if (reserved ("with", tokenix + 1)) {
CheckPhase (tokenix + 2);
}
else
errout ("Expected WITH or WHEN");
}
void register_write ()
{
/*
* MOVE reg/data8 TO reg register write
* MOVE reg <op> data8 TO reg register write
* MOVE reg + data8 TO reg WITH CARRY register write
*/
int op;
int reg;
int data;
if (reserved ("to", tokenix+1))
op = 0;
else if (tokens[tokenix+1].type == '|')
op = 2;
else if (tokens[tokenix+1].type == '&')
op = 4;
else if (tokens[tokenix+1].type == '+')
op = 6;
else if (tokens[tokenix+1].type == '-')
op = 8;
else
errout ("Unknown register operator");
if (op && reserved ("to", tokenix+3) == 0)
errout ("Register command expected TO");
reg = CheckRegister (tokenix);
if (reg < 0) { /* Not register, must be data */
data = evaluate (tokenix);
if (op)
errout ("Register operator not move");
reg = CheckRegister (tokenix+2);
if (reg < 0)
errout ("Expected register");
inst0 = 0x78000000 | (data << 8) | reg << 16;
#if 0
fprintf (listfp, "Move data to register: %02x %d\n", data, reg);
#endif
}
else if (op) { /* A register read/write operator */
data = evaluate (tokenix+2);
if (tokenix+5 < ntokens) {
if (!reserved("with", tokenix+5) ||
!reserved("carry", tokenix+6)) {
errout("Expected 'WITH CARRY'");
} else if (op != 6) {
errout("'WITH CARRY' only valide with '+'");
}
op = 7;
}
if (op == 8) {
data = -data;
op = 6;
}
inst0 = (data & 0xff) << 8;
data = CheckRegister (tokenix+4);
if (data < 0)
errout ("Expected register");
if (reg != data && reg != 8 && data != 8)
errout ("One register MUST be SBFR");
if (reg == data) { /* A register read/modify/write */
#if 0
fprintf (listfp, "Read/modify register: %02x %d %d\n", inst0 >> 8, op, reg);
#endif
inst0 |= 0x78000000 | (op << 24) | (reg << 16);
}
else { /* A move to/from SFBR */
if (reg == 8) { /* MOVE SFBR <> TO reg */
#if 0
fprintf (listfp, "Move SFBR to register: %02x %d %d\n", inst0 >> 8, op, data);
#endif
inst0 |= 0x68000000 | (op << 24) | (data << 16);
}
else {
#if 0
fprintf (listfp, "Move register to SFBR: %02x %d %d\n", inst0 >> 8, op, reg);
#endif
inst0 |= 0x70000000 | (op << 24) | (reg << 16);
}
}
}
else { /* register to register */
data = CheckRegister (tokenix+2);
if (reg == 8) /* move SFBR to reg */
inst0 = 0x6a000000 | (data << 16);
else if (data == 8) /* move reg to SFBR */
inst0 = 0x72000000 | (reg << 16);
else
errout ("One register must be SFBR");
}
}
void memory_to_memory ()
{
inst0 = 0xc0000000 + evaluate (tokenix+1);
inst1 = evaluate (tokenix+3);
/*
* need to hack dsps, otherwise patch offset will be wrong for
* second pointer
*/
dsps += 4;
inst2 = evaluate (tokenix+5);
dsps -= 4;
}
void error_line()
{
if (errfp != listfp && errfp && err_listed == 0) {
fprintf (errfp, "%3d: %s", lineno, inbuf);
err_listed = 1;
}
}
char * makefn (base, sub)
char *base;
char *sub;
{
char *fn;
fn = malloc (strlen (base) + strlen (sub) + 2);
strcpy (fn, base);
base = strrchr(fn, '.');
if (base)
*base = 0;
strcat (fn, ".");
strcat (fn, sub);
return (fn);
}
void usage()
{
fprintf (stderr, "usage: scc sourcfile [options]\n");
exit(1);
}