1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-18 10:35:55 +00:00
freebsd/sys/dev/aic7xxx/aicasm.c
Justin T. Gibbs c5cb388883 Makefile gram.y scan.l sequencer.h symbol.c symbol.h aic7xxx_asm.c:
New sequencer assembler for the aic7xxx adapters.  This assembler
	performs some amount of register type checking, allows bit
	manipulation of symbolic constants, and generates "patch tables"
	for conditionalized downloading of portions of the program.
	This makes it easier to take full advantage of the different
	features of the aic7xxx cards without imposing run time penalies
	or being bound to the small memory footprints of the low end
	cards for features like target mode.

aic7xxx.reg:
	New, assembler parsed, register definitions fo the aic7xxx cards.
	This was done primarily in anticipation of 7810 support which
	will have a different register layout, but should be able to use
	the same assembler.  The kernel aic7xxx driver consumes a generated
	file in the compile directory to get the definitions of the register
	locations.

aic7xxx.seq:
	Convert to the slighly different syntax of the new assembler.

	Conditionalize SCB_PAGING, ultra, and twin features which shaves
	quite a bit of space once the program is downloaded.

	Add code to leave the selection hardware enabled during reconnects
	that win bus arbitration.  This ensures that we will rearbitrate
	as soon as the bus goes free instead of delaying for a bit.

	When we expect the bus to go free, perform all of the cleanup
	associated with that event "up front" and enter a loop awaiting
	bus free.  If we see a REQ first, complain, but attempt to
	continue.  This will hopefully address, or at least help diagnose,
	the "target didn't send identify" messages that have been reported.

Spelling corrections obtained from NetBSD.
1997-03-16 07:08:19 +00:00

408 lines
9.7 KiB
C

/*
* Aic7xxx SCSI host adapter firmware asssembler
*
* Copyright (c) 1997 Justin T. Gibbs.
* 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 immediately at the beginning of the file, without modification,
* 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. 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
*
* $Id$
*/
#include <sys/types.h>
#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>
#include <unistd.h>
#include "aic7xxx_asm.h"
#include "symbol.h"
#include "sequencer.h"
static void usage __P((void));
static void back_patch __P((void));
static void output_code __P((FILE *ofile));
static void output_listing __P((FILE *listfile, char *ifilename));
struct path_list search_path;
int includes_search_curdir;
char *appname;
FILE *ofile;
char *ofilename;
static STAILQ_HEAD(,instruction) seq_program;
static STAILQ_HEAD(, patch) patch_list;
symlist_t patch_options;
#if DEBUG
extern int yy_flex_debug;
extern int yydebug;
#endif
extern FILE *yyin;
extern int yyparse __P((void));
int
main(argc, argv)
int argc;
char *argv[];
{
extern char *optarg;
extern int optind;
int ch;
int retval;
char *inputfilename;
char *regfilename;
FILE *regfile;
char *listfilename;
FILE *listfile;
SLIST_INIT(&search_path);
STAILQ_INIT(&seq_program);
STAILQ_INIT(&patch_list);
SLIST_INIT(&patch_options);
includes_search_curdir = 1;
appname = *argv;
regfile = NULL;
listfile = NULL;
#if DEBUG
yy_flex_debug = 0;
#endif
while ((ch = getopt(argc, argv, "d:l:n:o:r:I:")) != EOF) {
switch(ch) {
case 'd':
#if DEBUG
if (strcmp(optarg, "s") == 0)
yy_flex_debug = 1;
else if (strcmp(optarg, "p") == 0)
yydebug = 1;
#else
stop("-d: Assembler not built with debugging "
"information", EX_SOFTWARE);
#endif
break;
case 'l':
/* Create a program listing */
if ((listfile = fopen(optarg, "w")) == NULL) {
perror(optarg);
stop(NULL, EX_CANTCREAT);
}
listfilename = optarg;
break;
case 'n':
/* Don't complain about the -nostdinc directrive */
if (strcmp(optarg, "ostdinc")) {
fprintf(stderr, "%s: Unknown option -%c%s\n",
appname, ch, optarg);
usage();
/* NOTREACHED */
}
break;
case 'o':
if ((ofile = fopen(optarg, "w")) == NULL) {
perror(optarg);
stop(NULL, EX_CANTCREAT);
}
ofilename = optarg;
break;
case 'r':
if ((regfile = fopen(optarg, "w")) == NULL) {
perror(optarg);
stop(NULL, EX_CANTCREAT);
}
regfilename = optarg;
break;
case 'I':
{
path_entry_t include_dir;
if (strcmp(optarg, "-") == 0) {
if (includes_search_curdir == 0) {
fprintf(stderr, "%s: Warning - '-I-' "
"specified multiple "
"times\n", appname);
}
includes_search_curdir = 0;
for (include_dir = search_path.slh_first;
include_dir != NULL;
include_dir = include_dir->links.sle_next)
/*
* All entries before a '-I-' only
* apply to includes specified with
* quotes instead of "<>".
*/
include_dir->quoted_includes_only = 1;
} else {
include_dir =
(path_entry_t)malloc(sizeof(*include_dir));
if (include_dir == NULL) {
perror(optarg);
stop(NULL, EX_OSERR);
}
include_dir->directory = strdup(optarg);
if (include_dir->directory == NULL) {
perror(optarg);
stop(NULL, EX_OSERR);
}
include_dir->quoted_includes_only = 0;
SLIST_INSERT_HEAD(&search_path, include_dir,
links);
}
break;
}
case '?':
default:
usage();
/* NOTREACHED */
}
}
argc -= optind;
argv += optind;
if (argc != 1) {
fprintf(stderr, "%s: No input file specifiled\n", appname);
usage();
/* NOTREACHED */
}
symtable_open();
inputfilename = *argv;
include_file(*argv, SOURCE_FILE);
retval = yyparse();
if (retval == 0) {
back_patch();
if (ofile != NULL)
output_code(ofile);
if (regfile != NULL)
symtable_dump(regfile);
if (listfile != NULL)
output_listing(listfile, inputfilename);
}
stop(NULL, 0);
/* NOTREACHED */
return (0);
}
static void
usage()
{
(void)fprintf(stderr, "usage: %s [-I directory] [-o output_file] "
"input_file\n", appname);
exit(EX_USAGE);
}
static void
back_patch()
{
struct instruction *cur_instr;
for(cur_instr = seq_program.stqh_first;
cur_instr != NULL;
cur_instr = cur_instr->links.stqe_next) {
if (cur_instr->patch_label != NULL) {
struct ins_format3 *f3_instr;
u_int address;
if (cur_instr->patch_label->type != LABEL) {
char buf[255];
snprintf(buf, sizeof(buf),
"Undefined label %s",
cur_instr->patch_label->name);
stop(buf, EX_DATAERR);
/* NOTREACHED */
}
f3_instr = &cur_instr->format.format3;
address = ((f3_instr->opcode_addr & ADDR_HIGH_BIT) << 8)
| f3_instr->address;
address += cur_instr->patch_label->info.linfo->address;
f3_instr->opcode_addr &= ~ADDR_HIGH_BIT;
f3_instr->opcode_addr |= (address >> 8) & ADDR_HIGH_BIT;
f3_instr->address = address & 0xFF;
}
}
}
static void
output_code(ofile)
FILE *ofile;
{
struct instruction *cur_instr;
patch_t *cur_patch;
symbol_node_t *cur_node;
int instrcount;
instrcount = 0;
fprintf(ofile,
"/*
* DO NOT EDIT - This file is automatically generated.
*/\n");
fprintf(ofile, "static u_int8_t seqprog[] = {\n");
for(cur_instr = seq_program.stqh_first;
cur_instr != NULL;
cur_instr = cur_instr->links.stqe_next) {
fprintf(ofile, "\t0x%02x, 0x%02x, 0x%02x, 0x%02x,\n",
cur_instr->format.bytes[0],
cur_instr->format.bytes[1],
cur_instr->format.bytes[2],
cur_instr->format.bytes[3]);
instrcount++;
}
fprintf(ofile, "};\n");
/*
* Output the patch list, option definitions first.
*/
for(cur_node = patch_options.slh_first;
cur_node != NULL;
cur_node = cur_node->links.sle_next) {
fprintf(ofile, "#define\t%-16s\t0x%x\n", cur_node->symbol->name,
cur_node->symbol->info.condinfo->value);
}
symlist_free(&patch_options);
fprintf(ofile,
"struct patch {
int options;
int negative;
int begin;
int end;
} patches[] = {\n");
for(cur_patch = patch_list.stqh_first;
cur_patch != NULL;
cur_patch = cur_patch->links.stqe_next)
fprintf(ofile, "\t{ 0x%08x, %d, 0x%03x, 0x%03x },\n",
cur_patch->options, cur_patch->negative, cur_patch->begin,
cur_patch->end);
fprintf(ofile, "\t{ 0x%08x, %d, 0x%03x, 0x%03x }\n};\n",
0, 0, 0, 0);
fprintf(stderr, "%s: %d instructions used\n", appname, instrcount);
}
void
output_listing(listfile, ifilename)
FILE *listfile;
char *ifilename;
{
FILE *ifile;
int line;
struct instruction *cur_instr;
int instrcount;
char buf[1024];
instrcount = 0;
line = 1;
if ((ifile = fopen(ifilename, "r")) == NULL) {
perror(ifilename);
stop(NULL, EX_DATAERR);
}
for(cur_instr = seq_program.stqh_first;
cur_instr != NULL;
cur_instr = cur_instr->links.stqe_next) {
while (line < cur_instr->srcline) {
fgets(buf, sizeof(buf), ifile);
fprintf(listfile, "\t\t%s", buf);
line++;
}
fprintf(listfile, "%03x %02x%02x%02x%02x", instrcount,
cur_instr->format.bytes[0],
cur_instr->format.bytes[1],
cur_instr->format.bytes[2],
cur_instr->format.bytes[3]);
fgets(buf, sizeof(buf), ifile);
fprintf(listfile, "%s", buf);
line++;
instrcount++;
}
fclose(ifile);
}
/*
* Print out error information if appropriate, and clean up before
* terminating the program.
*/
void
stop(string, err_code)
const char *string;
int err_code;
{
if (string != NULL) {
fprintf(stderr, "%s: ", appname);
if (yyfilename != NULL) {
fprintf(stderr, "Stopped at file %s, line %d - ",
yyfilename, yylineno);
}
fprintf(stderr, "%s\n", string);
}
if (ofile != NULL) {
fclose(ofile);
if (err_code != 0) {
fprintf(stderr, "%s: Removing %s due to error\n",
appname, ofilename);
unlink(ofilename);
}
}
symtable_close();
exit(err_code);
}
struct instruction *
seq_alloc()
{
struct instruction *new_instr;
new_instr = (struct instruction *)malloc(sizeof(struct instruction));
if (new_instr == NULL)
stop("Unable to malloc instruction object", EX_SOFTWARE);
memset(new_instr, 0, sizeof(*new_instr));
STAILQ_INSERT_TAIL(&seq_program, new_instr, links);
new_instr->srcline = yylineno;
return new_instr;
}
patch_t *
patch_alloc()
{
patch_t *new_patch;
new_patch = (patch_t *)malloc(sizeof(patch_t));
if (new_patch == NULL)
stop("Unable to malloc patch object", EX_SOFTWARE);
memset(new_patch, 0, sizeof(*new_patch));
STAILQ_INSERT_TAIL(&patch_list, new_patch, links);
return new_patch;
}