1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-17 10:26:15 +00:00

Massive overhaul of the aic7xxx driver:

- Convert to CAM
 - Use a new DMA based queuing and paging scheme
 - Add preliminary target mode support
 - Add support for the aic789X chips
 - Take advantage of external SRAM on more controllers.
 - Numerous bug fixes and performance improvements.
This commit is contained in:
Justin T. Gibbs 1998-09-15 07:24:17 +00:00
parent 44de612bd0
commit 3bafc9d432
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=39220
21 changed files with 8453 additions and 1138 deletions

174
sys/dev/aic7xxx/93cx6.c Normal file
View File

@ -0,0 +1,174 @@
/*
* Interface for the 93C66/56/46/26/06 serial eeprom parts.
*
* Copyright (c) 1995, 1996 Daniel M. Eischen
* 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. Absolutely no warranty of function or purpose is made by the author
* Daniel M. Eischen.
* 4. Modifications may be freely made to this file if the above conditions
* are met.
*
* $Id: 93cx6.c,v 1.10 1997/02/22 09:38:36 peter Exp $
*/
/*
* The instruction set of the 93C66/56/46/26/06 chips are as follows:
*
* Start OP *
* Function Bit Code Address** Data Description
* -------------------------------------------------------------------
* READ 1 10 A5 - A0 Reads data stored in memory,
* starting at specified address
* EWEN 1 00 11XXXX Write enable must preceed
* all programming modes
* ERASE 1 11 A5 - A0 Erase register A5A4A3A2A1A0
* WRITE 1 01 A5 - A0 D15 - D0 Writes register
* ERAL 1 00 10XXXX Erase all registers
* WRAL 1 00 01XXXX D15 - D0 Writes to all registers
* EWDS 1 00 00XXXX Disables all programming
* instructions
* *Note: A value of X for address is a don't care condition.
* **Note: There are 8 address bits for the 93C56/66 chips unlike
* the 93C46/26/06 chips which have 6 address bits.
*
* The 93C46 has a four wire interface: clock, chip select, data in, and
* data out. In order to perform one of the above functions, you need
* to enable the chip select for a clock period (typically a minimum of
* 1 usec, with the clock high and low a minimum of 750 and 250 nsec
* respectively). While the chip select remains high, you can clock in
* the instructions (above) starting with the start bit, followed by the
* OP code, Address, and Data (if needed). For the READ instruction, the
* requested 16-bit register contents is read from the data out line but
* is preceded by an initial zero (leading 0, followed by 16-bits, MSB
* first). The clock cycling from low to high initiates the next data
* bit to be sent from the chip.
*
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <machine/bus_memio.h>
#include <machine/bus_pio.h>
#include <machine/bus.h>
#include <dev/aic7xxx/93cx6.h>
/*
* Right now, we only have to read the SEEPROM. But we make it easier to
* add other 93Cx6 functions.
*/
static struct seeprom_cmd {
unsigned char len;
unsigned char bits[3];
} seeprom_read = {3, {1, 1, 0}};
/*
* Wait for the SEERDY to go high; about 800 ns.
*/
#define CLOCK_PULSE(sd, rdy) \
while ((SEEPROM_STATUS_INB(sd) & rdy) == 0) { \
; /* Do nothing */ \
} \
(void)SEEPROM_INB(sd); /* Clear clock */
/*
* Read the serial EEPROM and returns 1 if successful and 0 if
* not successful.
*/
int
read_seeprom(sd, buf, start_addr, count)
struct seeprom_descriptor *sd;
u_int16_t *buf;
bus_size_t start_addr;
bus_size_t count;
{
int i = 0;
u_int k = 0;
u_int16_t v;
u_int8_t temp;
/*
* Read the requested registers of the seeprom. The loop
* will range from 0 to count-1.
*/
for (k = start_addr; k < count + start_addr; k++) {
/* Send chip select for one clock cycle. */
temp = sd->sd_MS ^ sd->sd_CS;
SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
CLOCK_PULSE(sd, sd->sd_RDY);
/*
* Now we're ready to send the read command followed by the
* address of the 16-bit register we want to read.
*/
for (i = 0; i < seeprom_read.len; i++) {
if (seeprom_read.bits[i] != 0)
temp ^= sd->sd_DO;
SEEPROM_OUTB(sd, temp);
CLOCK_PULSE(sd, sd->sd_RDY);
SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
CLOCK_PULSE(sd, sd->sd_RDY);
if (seeprom_read.bits[i] != 0)
temp ^= sd->sd_DO;
}
/* Send the 6 or 8 bit address (MSB first, LSB last). */
for (i = (sd->sd_chip - 1); i >= 0; i--) {
if ((k & (1 << i)) != 0)
temp ^= sd->sd_DO;
SEEPROM_OUTB(sd, temp);
CLOCK_PULSE(sd, sd->sd_RDY);
SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
CLOCK_PULSE(sd, sd->sd_RDY);
if ((k & (1 << i)) != 0)
temp ^= sd->sd_DO;
}
/*
* Now read the 16 bit register. An initial 0 precedes the
* register contents which begins with bit 15 (MSB) and ends
* with bit 0 (LSB). The initial 0 will be shifted off the
* top of our word as we let the loop run from 0 to 16.
*/
v = 0;
for (i = 16; i >= 0; i--) {
SEEPROM_OUTB(sd, temp);
CLOCK_PULSE(sd, sd->sd_RDY);
v <<= 1;
if (SEEPROM_DATA_INB(sd) & sd->sd_DI)
v |= 1;
SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
CLOCK_PULSE(sd, sd->sd_RDY);
}
buf[k - start_addr] = v;
/* Reset the chip select for the next command cycle. */
temp = sd->sd_MS;
SEEPROM_OUTB(sd, temp);
CLOCK_PULSE(sd, sd->sd_RDY);
SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
CLOCK_PULSE(sd, sd->sd_RDY);
SEEPROM_OUTB(sd, temp);
CLOCK_PULSE(sd, sd->sd_RDY);
}
#ifdef 93CX6_DUMP_EEPROM
printf("\nSerial EEPROM:");
for (k = 0; k < count; k = k + 1) {
if (((k % 8) == 0) && (k != 0)) {
printf ("\n ");
}
printf (" 0x%x", buf[k]);
}
printf ("\n");
#endif
return (1);
}

95
sys/dev/aic7xxx/93cx6.h Normal file
View File

@ -0,0 +1,95 @@
/*
* Interface to the 93C46 serial EEPROM that is used to store BIOS
* settings for the aic7xxx based adaptec SCSI controllers. It can
* also be used for 93C26 and 93C06 serial EEPROMS.
*
* Copyright (c) 1994, 1995 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, this list of conditions, and the following disclaimer,
* without modification, immediately at the beginning of the file.
* 2. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* Where this Software is combined with software released under the terms of
* the GNU Public License ("GPL") and the terms of the GPL would require the
* combined work to also be released under the terms of the GPL, the terms
* and conditions of this License will apply in addition to those of the
* GPL with the exception of any terms or conditions of this License that
* conflict with, or are expressly prohibited by, the GPL.
*
* 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/param.h>
#if !defined(__NetBSD__)
#include <sys/systm.h>
#endif
#ifdef KERNEL
typedef enum {
C46 = 6,
C56_66 = 8
} seeprom_chip_t;
struct seeprom_descriptor {
bus_space_tag_t sd_tag;
bus_space_handle_t sd_bsh;
bus_size_t sd_control_offset;
bus_size_t sd_status_offset;
bus_size_t sd_dataout_offset;
seeprom_chip_t sd_chip;
u_int16_t sd_MS;
u_int16_t sd_RDY;
u_int16_t sd_CS;
u_int16_t sd_CK;
u_int16_t sd_DO;
u_int16_t sd_DI;
};
/*
* This function will read count 16-bit words from the serial EEPROM and
* return their value in buf. The port address of the aic7xxx serial EEPROM
* control register is passed in as offset. The following parameters are
* also passed in:
*
* CS - Chip select
* CK - Clock
* DO - Data out
* DI - Data in
* RDY - SEEPROM ready
* MS - Memory port mode select
*
* A failed read attempt returns 0, and a successful read returns 1.
*/
#define SEEPROM_INB(sd) \
bus_space_read_1(sd->sd_tag, sd->sd_bsh, sd->sd_control_offset)
#define SEEPROM_OUTB(sd, value) \
bus_space_write_1(sd->sd_tag, sd->sd_bsh, sd->sd_control_offset, value)
#define SEEPROM_STATUS_INB(sd) \
bus_space_read_1(sd->sd_tag, sd->sd_bsh, sd->sd_status_offset)
#define SEEPROM_DATA_INB(sd) \
bus_space_read_1(sd->sd_tag, sd->sd_bsh, sd->sd_dataout_offset)
int read_seeprom(struct seeprom_descriptor *sd, u_int16_t *buf,
bus_size_t start_addr, bus_size_t count);
#endif /* KERNEL */

4823
sys/dev/aic7xxx/aic7xxx.c Normal file

File diff suppressed because it is too large Load Diff

524
sys/dev/aic7xxx/aic7xxx.h Normal file
View File

@ -0,0 +1,524 @@
/*
* Interface to the generic driver for the aic7xxx based adaptec
* SCSI controllers. This is used to implement product specific
* probe and attach routines.
*
* Copyright (c) 1994, 1995, 1996, 1997, 1998 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, this list of conditions, and the following disclaimer,
* without modification, immediately at the beginning of the file.
* 2. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* Where this Software is combined with software released under the terms of
* the GNU Public License ("GPL") and the terms of the GPL would require the
* combined work to also be released under the terms of the GPL, the terms
* and conditions of this License will apply in addition to those of the
* GPL with the exception of any terms or conditions of this License that
* conflict with, or are expressly prohibited by, the GPL.
*
* 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: aic7xxx.h,v 1.40 1997/02/25 03:05:35 gibbs Exp $
*/
#ifndef _AIC7XXX_H_
#define _AIC7XXX_H_
#include "ahc.h" /* for NAHC from config */
#include "opt_aic7xxx.h" /* for config options */
#include <pci/pcivar.h> /* for pcici_t */
#define AHC_MAXTRANSFER_SIZE 0x00ffffff /* limited by 24bit counter */
#define AHC_NSEG 32 /* The number of dma segments supported.
* AHC_NSEG can be maxed out at 256 entries,
* but the kernel will never need to transfer
* such a large (1MB) request. To reduce the
* driver's memory consumption, we reduce the
* max to 32. 16 would work if all transfers
* are paged alined since the kernel will only
* generate at most a 64k transfer, but to
* handle non-page aligned transfers, you need
* 17, so we round to the next power of two
* to make allocating SG space easy and
* efficient.
*/
#define AHC_SCB_MAX 255 /*
* Up to 255 SCBs on some types of aic7xxx
* based boards. The aic7870 have 16 internal
* SCBs, but external SRAM bumps this to 255.
* The aic7770 family have only 4, and the
* aic7850 has only 3.
*/
#if defined(__FreeBSD__)
extern u_long ahc_unit;
#endif
struct ahc_dma_seg {
u_int32_t addr;
u_int32_t len;
};
typedef enum {
AHC_NONE = 0x0000,
AHC_CHIPID_MASK = 0x00FF,
AHC_AIC7770 = 0x0001,
AHC_AIC7850 = 0x0002,
AHC_AIC7860 = 0x0003,
AHC_AIC7870 = 0x0004,
AHC_AIC7880 = 0x0005,
AHC_AIC7890 = 0x0006,
AHC_AIC7895 = 0x0007,
AHC_AIC7896 = 0x0008,
AHC_VL = 0x0100, /* Bus type VL */
AHC_EISA = 0x0200, /* Bus type EISA */
AHC_PCI = 0x0400, /* Bus type PCI */
} ahc_chip;
typedef enum {
AHC_FENONE = 0x0000,
AHC_ULTRA = 0x0001, /* Supports 20MHz Transfers */
AHC_ULTRA2 = 0x0002, /* Supports 40MHz Transfers */
AHC_WIDE = 0x0004, /* Wide Channel */
AHC_TWIN = 0x0008, /* Twin Channel */
AHC_MORE_SRAM = 0x0010, /* 80 bytes instead of 64 */
AHC_CMD_CHAN = 0x0020, /* Has a Command DMA Channel */
AHC_QUEUE_REGS = 0x0040, /* Has Queue management registers */
AHC_SG_PRELOAD = 0x0080, /* Can perform auto-SG preload */
AHC_SPIOCAP = 0x0100, /* Has a Serial Port I/O Cap Register */
AHC_MULTI_TID = 0x0200, /* Has bitmask of TIDs for select-in */
AHC_AIC7770_FE = AHC_FENONE,
AHC_AIC7850_FE = AHC_FENONE|AHC_SPIOCAP,
AHC_AIC7860_FE = AHC_ULTRA|AHC_SPIOCAP,
AHC_AIC7870_FE = AHC_FENONE,
AHC_AIC7880_FE = AHC_ULTRA,
AHC_AIC7890_FE = AHC_MORE_SRAM|AHC_CMD_CHAN|AHC_ULTRA2|AHC_QUEUE_REGS|AHC_SG_PRELOAD|AHC_MULTI_TID,
AHC_AIC7895_FE = AHC_MORE_SRAM|AHC_CMD_CHAN|AHC_ULTRA,
AHC_AIC7896_FE = AHC_MORE_SRAM|AHC_CMD_CHAN|AHC_ULTRA2|AHC_QUEUE_REGS|AHC_SG_PRELOAD|AHC_MULTI_TID,
} ahc_feature;
typedef enum {
AHC_FNONE = 0x000,
AHC_PAGESCBS = 0x001,/* Enable SCB paging */
AHC_CHANNEL_B_PRIMARY = 0x002,/*
* On twin channel adapters, probe
* channel B first since it is the
* primary bus.
*/
AHC_USEDEFAULTS = 0x004,/*
* For cards without an seeprom
* or a BIOS to initialize the chip's
* SRAM, we use the default target
* settings.
*/
AHC_INDIRECT_PAGING = 0x008,
AHC_SHARED_SRAM = 0x010,
AHC_LARGE_SEEPROM = 0x020,/* Uses C56_66 not C46 */
AHC_EXTENDED_TRANS_A = 0x100,
AHC_EXTENDED_TRANS_B = 0x200,
AHC_TERM_ENB_A = 0x400,
AHC_TERM_ENB_B = 0x800,
AHC_HANDLING_REQINITS = 0x1000,
AHC_TARGETMODE = 0x2000,/*
* Allow target operations on this
* controller.
*/
AHC_NEWEEPROM_FMT = 0x4000,
AHC_RESOURCE_SHORTAGE = 0x8000
} ahc_flag;
typedef enum {
SCB_FREE = 0x0000,
SCB_OTHERTCL_TIMEOUT = 0x0002,/*
* Another device was active
* during the first timeout for
* this SCB so we gave ourselves
* an additional timeout period
* in case it was hogging the
* bus.
*/
SCB_DEVICE_RESET = 0x0004,
SCB_SENSE = 0x0008,
SCB_RECOVERY_SCB = 0x0040,
SCB_MSGOUT_SENT = 0x0200,
SCB_MSGOUT_SDTR = 0x0400,
SCB_MSGOUT_WDTR = 0x0800,
SCB_MSGOUT_BITS = (SCB_MSGOUT_SDTR|SCB_MSGOUT_WDTR
|SCB_MSGOUT_SENT),
SCB_ABORT = 0x1000,
SCB_QUEUED_MSG = 0x2000,
SCB_ACTIVE = 0x4000,
SCB_TARGET_IMMEDIATE = 0x8000
} scb_flag;
/*
* The driver keeps up to MAX_SCB scb structures per card in memory. The SCB
* consists of a "hardware SCB" mirroring the fields availible on the card
* and additional information the kernel stores for each transaction.
*/
struct hardware_scb {
/*0*/ u_int8_t control;
/*1*/ u_int8_t tcl; /* 4/1/3 bits */
/*2*/ u_int8_t status;
/*3*/ u_int8_t SG_count;
/*4*/ u_int32_t SG_pointer;
/*8*/ u_int8_t residual_SG_count;
/*9*/ u_int8_t residual_data_count[3];
/*12*/ u_int32_t data;
/*16*/ u_int32_t datalen; /* Really only three bytes, but its
* faster to treat it as a long on
* a quad boundary.
*/
/*20*/ u_int32_t cmdpointer;
/*24*/ u_int8_t cmdlen;
/*25*/ u_int8_t tag; /* Index into our kernel SCB array.
* Also used as the tag for tagged I/O
*/
/*26*/ u_int8_t next; /* Used for threading SCBs in the
* "Waiting for Selection" and
* "Disconnected SCB" lists down
* in the sequencer.
*/
/*27*/ u_int8_t scsirate; /* Value for SCSIRATE register */
/*28*/ u_int8_t scsioffset; /* Value for SCSIOFFSET register */
/*29*/ u_int8_t spare[3]; /*
* Spare space available on
* all controller types.
*/
/*32*/ u_int8_t cmdstore[16]; /*
* CDB storage for controllers
* supporting 64 byte SCBs.
*/
/*48*/ u_int32_t cmdstore_busaddr; /*
* Address of command store for
* 32byte SCB adapters
*/
/*48*/ u_int8_t spare_64[12]; /*
* Pad to 64 bytes.
*/
};
struct scb {
struct hardware_scb *hscb;
STAILQ_ENTRY(scb) links; /* for chaining */
union ccb *ccb; /* the ccb for this cmd */
scb_flag flags;
bus_dmamap_t dmamap;
struct ahc_dma_seg *ahc_dma;/* Pointer to SG segments */
u_int32_t ahc_dmaphys;/* Phsical address of SG list */
u_int sg_count;/* How full ahc_dma_seg is */
};
struct scb_data {
struct hardware_scb *hscbs; /* Array of hardware SCBs */
struct scb *scbarray[AHC_SCB_MAX]; /* Array of kernel SCBs */
STAILQ_HEAD(, scb) free_scbs; /*
* Pool of SCBs ready to be assigned
* commands to execute.
*/
u_int8_t numscbs;
u_int8_t maxhscbs; /* Number of SCBs on the card */
u_int8_t maxscbs; /*
* Max SCBs we allocate total including
* any that will force us to page SCBs
*/
};
/*
* Connection desciptor for select-in requests in target mode.
* The first byte is the connecting target, followed by identify
* message and optional tag information, terminated by 0xFF. The
* remainder is the command to execute.
*/
struct target_cmd {
u_int8_t icl; /* Really only holds Initiator ID */
u_int8_t targ_id; /* Target ID we were selected at */
u_int8_t identify; /* Identify message */
u_int8_t bytes[29];
};
/*
* Per lun target mode state including accept TIO CCB
* and immediate notify CCB pools.
*/
struct tmode_lstate {
SLIST_HEAD(, ccb_hdr) accept_tios;
SLIST_HEAD(, ccb_hdr) immed_notifies;
};
/*
* Per target mode enabled target state. Esentially just an array of
* pointers to lun target state.
*/
struct tmode_tstate {
struct tmode_lstate* enabled_luns[8];
};
/*
* Define the format of the aic7XX0 SEEPROM registers (16 bits).
*/
struct seeprom_config {
/*
* SCSI ID Configuration Flags
*/
u_int16_t device_flags[16]; /* words 0-15 */
#define CFXFER 0x0007 /* synchronous transfer rate */
#define CFSYNCH 0x0008 /* enable synchronous transfer */
#define CFDISC 0x0010 /* enable disconnection */
#define CFWIDEB 0x0020 /* wide bus device */
#define CFSYNCHISULTRA 0x0040 /* CFSYNCH is an ultra offset (2940AU)*/
/* UNUSED 0x0080 */
#define CFSTART 0x0100 /* send start unit SCSI command */
#define CFINCBIOS 0x0200 /* include in BIOS scan */
#define CFRNFOUND 0x0400 /* report even if not found */
#define CFMULTILUN 0x0800 /* Probe multiple luns in BIOS scan */
/* UNUSED 0xf000 */
/*
* BIOS Control Bits
*/
u_int16_t bios_control; /* word 16 */
#define CFSUPREM 0x0001 /* support all removeable drives */
#define CFSUPREMB 0x0002 /* support removeable drives for boot only */
#define CFBIOSEN 0x0004 /* BIOS enabled */
/* UNUSED 0x0008 */
#define CFSM2DRV 0x0010 /* support more than two drives */
#define CF284XEXTEND 0x0020 /* extended translation (284x cards) */
/* UNUSED 0x0060 */
#define CFEXTEND 0x0080 /* extended translation enabled */
/* UNUSED 0xff00 */
/*
* Host Adapter Control Bits
*/
u_int16_t adapter_control; /* word 17 */
#define CFAUTOTERM 0x0001 /* Perform Auto termination */
#define CFULTRAEN 0x0002 /* Ultra SCSI speed enable */
#define CF284XSELTO 0x0003 /* Selection timeout (284x cards) */
#define CF284XFIFO 0x000C /* FIFO Threshold (284x cards) */
#define CFSTERM 0x0004 /* SCSI low byte termination */
#define CFWSTERM 0x0008 /* SCSI high byte termination */
#define CFSPARITY 0x0010 /* SCSI parity */
#define CF284XSTERM 0x0020 /* SCSI low byte term (284x cards) */
#define CFRESETB 0x0040 /* reset SCSI bus at boot */
#define CFCHNLBPRIMARY 0x0100 /* aic7895 probe B channel first */
#define CFSEAUTOTERM 0x0400 /* aic7890 Perform SE Auto Termination*/
#define CFLVDSTERM 0x0800 /* aic7890 LVD Termination */
/* UNUSED 0xf080 */
/*
* Bus Release, Host Adapter ID
*/
u_int16_t brtime_id; /* word 18 */
#define CFSCSIID 0x000f /* host adapter SCSI ID */
/* UNUSED 0x00f0 */
#define CFBRTIME 0xff00 /* bus release time */
/*
* Maximum targets
*/
u_int16_t max_targets; /* word 19 */
#define CFMAXTARG 0x00ff /* maximum targets */
/* UNUSED 0xff00 */
u_int16_t res_1[11]; /* words 20-30 */
u_int16_t checksum; /* word 31 */
};
#define AHC_TRANS_CUR 0x01 /* Modify current neogtiation status */
#define AHC_TRANS_ACTIVE 0x03 /* Assume this is the active target */
#define AHC_TRANS_GOAL 0x04 /* Modify negotiation goal */
#define AHC_TRANS_USER 0x08 /* Modify user negotiation settings */
struct ahc_transinfo {
u_int8_t width;
u_int8_t period;
u_int8_t offset;
};
struct ahc_target_tinfo {
u_int8_t scsirate;
struct ahc_transinfo current;
struct ahc_transinfo goal;
struct ahc_transinfo user;
};
struct ahc_syncrate {
int sxfr_ultra2;
int sxfr;
/* Rates in Ultra mode have bit 8 of sxfr set */
#define ULTRA_SXFR 0x100
u_int8_t period; /* Period to send to SCSI target */
char *rate;
};
typedef enum {
MSG_TYPE_NONE = 0x00,
MSG_TYPE_INITIATOR_MSGOUT = 0x01,
MSG_TYPE_INITIATOR_MSGIN = 0x02
} ahc_msg_type;
struct ahc_softc {
bus_space_tag_t tag;
bus_space_handle_t bsh;
bus_dma_tag_t dmat;
struct scb_data *scb_data;
/*
* CCBs that have been send to the controller
*/
LIST_HEAD(, ccb_hdr) pending_ccbs;
/*
* Target mode related state kept on a per enabled lun basis.
* Targets that are not enabled will have null entries.
*/
struct tmode_tstate* enabled_targets[16];
/*
* Device instance currently on the bus awaiting a continue TIO
* for a command that was not given the disconnect priveledge.
*/
struct tmode_lstate* pending_device;
/*
* Card characteristics
*/
ahc_chip chip;
ahc_feature features;
ahc_flag flags;
/* Values to store in the SEQCTL register for pause and unpause */
u_int8_t unpause;
u_int8_t pause;
/* Command Queues */
u_int8_t qoutfifonext;
u_int8_t qinfifonext;
u_int8_t qoutfifo[256];
u_int8_t qinfifo[256];
/*
* 256 byte array storing the SCBID of outstanding
* untagged SCBs indexed by TCL.
*/
u_int8_t untagged_scbs[256];
/*
* User/Current/Active Negotiation settings
*/
struct ahc_target_tinfo transinfo[16];
/*
* Per target state bitmasks.
*/
u_int16_t ultraenb; /* Using ultra sync rate */
u_int16_t sdtrpending; /* Pending SDTR request */
u_int16_t wdtrpending; /* Pending WDTR request */
u_int16_t discenable; /* Disconnection allowed */
u_int16_t tagenable; /* Tagged Queuing allowed */
/*
* Hooks into the XPT.
*/
struct cam_sim *sim;
struct cam_sim *sim_b;
struct cam_path *path;
struct cam_path *path_b;
int unit;
/* Channel Names ('A', 'B', etc.) */
char channel;
char channel_b;
/* Initiator Bus ID */
u_int8_t our_id;
u_int8_t our_id_b;
/*
* PCI error detection and data for running the
* PCI error interrupt handler.
*/
int unsolicited_ints;
pcici_t pci_config_id;
/* Hmmm. */
struct target_cmd *targetcmds;
int next_targetcmd;
int num_targetcmds;
/*
* Incoming and outgoing message handling.
*/
ahc_msg_type msg_type;
u_int8_t msg_buf[8]; /* Message we are sending */
u_int msg_len; /* Length of message to send */
u_int msg_index; /* Current index in message */
/*
* "Bus" addresses of our data structures.
*/
u_int32_t hscb_busaddr;
};
struct full_ahc_softc {
struct ahc_softc softc;
struct scb_data scb_data_storage;
};
/* #define AHC_DEBUG */
#ifdef AHC_DEBUG
/* Different debugging levels used when AHC_DEBUG is defined */
#define AHC_SHOWMISC 0x0001
#define AHC_SHOWCMDS 0x0002
#define AHC_SHOWSCBS 0x0004
#define AHC_SHOWABORTS 0x0008
#define AHC_SHOWSENSE 0x0010
#define AHC_SHOWSCBCNT 0x0020
extern int ahc_debug; /* Initialized in i386/scsi/aic7xxx.c */
#endif
char *ahc_name(struct ahc_softc *ahc);
struct ahc_softc *ahc_alloc(int unit, u_int32_t io_base,
vm_offset_t maddr, ahc_chip chip,
ahc_feature features, ahc_flag flags,
struct scb_data *scb_data);
int ahc_reset(struct ahc_softc *ahc);
void ahc_free(struct ahc_softc *);
int ahc_probe_scbs(struct ahc_softc *);
int ahc_init(struct ahc_softc *);
int ahc_attach(struct ahc_softc *);
void ahc_intr(void *arg);
#define ahc_inb(ahc, port) \
bus_space_read_1((ahc)->tag, (ahc)->bsh, port)
#define ahc_outb(ahc, port, value) \
bus_space_write_1((ahc)->tag, (ahc)->bsh, port, value)
#define ahc_outsb(ahc, port, valp, count) \
bus_space_write_multi_1((ahc)->tag, (ahc)->bsh, port, valp, count)
#endif /* _AIC7XXX_H_ */

View File

@ -1,7 +1,7 @@
/*
* Aic7xxx register and scratch ram definitions.
*
* Copyright (c) 1994-1997 Justin Gibbs.
* Copyright (c) 1994-1998 Justin Gibbs.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -10,10 +10,7 @@
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer,
* without modification, immediately at the beginning of the file.
* 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
* 2. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* Where this Software is combined with software released under the terms of
@ -35,7 +32,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: aic7xxx.reg,v 1.5 1997/08/13 17:02:24 gibbs Exp $
* $Id: aic7xxx.reg,v 1.4 1997/06/27 19:38:39 gibbs Exp $
*/
/*
@ -164,6 +161,7 @@ register SCSIRATE {
access_mode RW
bit WIDEXFER 0x80 /* Wide transfer control */
mask SXFR 0x70 /* Sync transfer rate */
mask SXFR_ULTRA2 0x7f /* Sync transfer rate */
mask SOFS 0x0f /* Sync offset */
}
@ -177,6 +175,13 @@ register SCSIID {
access_mode RW
mask TID 0xf0 /* Target ID mask */
mask OID 0x0f /* Our ID mask */
/*
* SCSI Maximum Offset (p. 4-61 aic7890/91 Data Book)
* The aic7890/91 allow an offset of up to 127 transfers in both wide
* and narrow mode.
*/
alias SCSIOFFSET
mask SOFS_ULTRA2 0x7f /* Sync offset U2 chips */
}
/*
@ -230,14 +235,15 @@ register CLRSINT0 {
register SSTAT0 {
address 0x00b
access_mode RO
bit TARGET 0x80 /* Board acting as target */
bit SELDO 0x40 /* Selection Done */
bit SELDI 0x20 /* Board has been selected */
bit SELINGO 0x10 /* Selection In Progress */
bit SWRAP 0x08 /* 24bit counter wrap */
bit SDONE 0x04 /* STCNT = 0x000000 */
bit SPIORDY 0x02 /* SCSI PIO Ready */
bit DMADONE 0x01 /* DMA transfer completed */
bit TARGET 0x80 /* Board acting as target */
bit SELDO 0x40 /* Selection Done */
bit SELDI 0x20 /* Board has been selected */
bit SELINGO 0x10 /* Selection In Progress */
bit SWRAP 0x08 /* 24bit counter wrap */
bit IOERR 0x08 /* LVD Tranceiver mode changed */
bit SDONE 0x04 /* STCNT = 0x000000 */
bit SPIORDY 0x02 /* SCSI PIO Ready */
bit DMADONE 0x01 /* DMA transfer completed */
}
/*
@ -279,6 +285,7 @@ register SSTAT2 {
address 0x00d
access_mode RO
bit OVERRUN 0x80
bit EXP_ACTIVE 0x10 /* SCSI Expander Active */
mask SFCNT 0x1f
}
@ -293,14 +300,13 @@ register SSTAT3 {
}
/*
* SCSI Test Control (p. 3-27)
* SCSI ID for the aic7890/91 chips
*/
register SCSITEST {
register SCSIID_ULTRA2 {
address 0x00f
access_mode RW
bit RQAKCNT 0x04
bit CNTRTEST 0x02
bit CMODE 0x01
mask TID 0xf0 /* Target ID mask */
mask OID 0x0f /* Our ID mask */
}
/*
@ -315,6 +321,7 @@ register SIMODE0 {
bit ENSELDI 0x20
bit ENSELINGO 0x10
bit ENSWRAP 0x08
bit ENIOERR 0x08 /* LVD Tranceiver mode changes */
bit ENSDONE 0x04
bit ENSPIORDY 0x02
bit ENDMADONE 0x01
@ -378,6 +385,7 @@ register SELTIMER {
bit STAGE3 0x04
bit STAGE2 0x02
bit STAGE1 0x01
alias TARGIDIN
}
/*
@ -392,6 +400,36 @@ register SELID {
bit ONEBIT 0x08
}
/*
* Target Mode Selecting in ID bitmask (aic7890/91/96/97)
*/
register TARGID {
address 0x01b
size 2
access_mode RW
}
/*
* Serial Port I/O Cabability register (p. 4-95 aic7860 Data Book)
* Indicates if external logic has been attached to the chip to
* perform the tasks of accessing a serial eeprom, testing termination
* strength, and performing cable detection. On the aic7860, most of
* these features are handled on chip, but on the aic7855 an attached
* aic3800 does the grunt work.
*/
register SPIOCAP {
address 0x01b
access_mode RW
bit SOFT1 0x80
bit SOFT0 0x40
bit SOFTCMDEN 0x20
bit HAS_BRDCTL 0x10 /* External Board control */
bit SEEPROM 0x08 /* External serial eeprom logic */
bit EEPROM 0x04 /* Writable external BIOS ROM */
bit ROM 0x02 /* Logic for accessing external ROM */
bit SSPIOCPS 0x01 /* Termination and cable detection */
}
/*
* SCSI Block Control (p. 3-32)
* Controls Bus type and channel selection. In a twin channel configuration
@ -406,7 +444,10 @@ register SBLKCTL {
bit DIAGLEDON 0x40 /* Aic78X0 only */
bit AUTOFLUSHDIS 0x20
bit SELBUSB 0x08
bit ENAB40 0x08 /* LVD transceiver active */
bit ENAB20 0x04 /* SE/HVD transceiver active */
bit SELWIDE 0x02
bit XCVR 0x01 /* External transceiver active */
}
/*
@ -529,6 +570,19 @@ register BCTL {
bit ENABLE 0x01
}
register DSCOMMAND0 {
address 0x084
access_mode RW
bit CACHETHEN 0x80
bit DPARCKEN 0x40
bit MPARCKEN 0x20
bit EXTREQLCK 0x10
bit INTSCBRAMSEL 0x08
bit RAMPS 0x04
bit USCBSIZE32 0x02
bit CIOPARCKEN 0x01
}
/*
* On the aic78X0 chips, Board Control is replaced by the DSCommand
* register (p. 4-64)
@ -622,32 +676,26 @@ register INTSTAT {
mask NO_IDENT 0x20|SEQINT /* no IDENTIFY after reconnect*/
mask NO_MATCH 0x30|SEQINT /* no cmd match for reconnect */
mask EXTENDED_MSG 0x40|SEQINT /* Extended message received */
mask NO_MATCH_BUSY 0x50|SEQINT /* Couldn't find BUSY SCB */
mask ABORT_REQUESTED 0x50|SEQINT /* Reconect of aborted SCB */
mask REJECT_MSG 0x60|SEQINT /* Reject message received */
mask BAD_STATUS 0x70|SEQINT /* Bad status from target */
mask RESIDUAL 0x80|SEQINT /* Residual byte count != 0 */
mask ABORT_CMDCMPLT 0x91 /*
* Command tagged for abort
* completed successfully.
*/
mask AWAITING_MSG 0xa0|SEQINT /*
* Kernel requested to specify
* a message to this target
* (command was null), so tell
* it that it can fill the
* message buffer.
*/
mask MSG_BUFFER_BUSY 0xc0|SEQINT /*
* Sequencer wants to use the
* message buffer, but it
* already contains a message
* a message to this target
* (command was null), so tell
* it that it can fill the
* message buffer.
*/
mask MSGIN_PHASEMIS 0xd0|SEQINT /*
mask TARGET_MSG_HELP 0xb0|SEQINT
mask TARGET_SYNC_CMD 0xc0|SEQINT
mask TRACEPOINT 0xd0|SEQINT
mask MSGIN_PHASEMIS 0xe0|SEQINT /*
* Target changed phase on us
* when we were expecting
* another msgin byte.
*/
mask DATA_OVERRUN 0xe0|SEQINT /*
mask DATA_OVERRUN 0xf0|SEQINT /*
* Target attempted to write
* beyond the bounds of its
* command.
@ -665,7 +713,11 @@ register INTSTAT {
register ERROR {
address 0x092
access_mode RO
bit PARERR 0x08
bit CIOPARERR 0x80 /* Ultra2 only */
bit PCIERRSTAT 0x40 /* PCI only */
bit MPARERR 0x20 /* PCI only */
bit DPARERR 0x10 /* PCI only */
bit SQPARERR 0x08
bit ILLOPCODE 0x04
bit ILLSADDR 0x02
bit ILLHADDR 0x01
@ -677,6 +729,7 @@ register ERROR {
register CLRINT {
address 0x092
access_mode WO
bit CLRPARERR 0x10 /* PCI only */
bit CLRBRKADRINT 0x08
bit CLRSCSIINT 0x04
bit CLRCMDINT 0x02
@ -686,6 +739,7 @@ register CLRINT {
register DFCNTRL {
address 0x093
access_mode RW
bit PRELOADEN 0x80 /* aic7890 only */
bit WIDEODD 0x40
bit SCSIEN 0x20
bit SDMAEN 0x10
@ -700,6 +754,7 @@ register DFCNTRL {
register DFSTATUS {
address 0x094
access_mode RO
bit PRELOAD_AVAIL 0x80
bit DWORDEMP 0x20
bit MREQPEND 0x10
bit HDONE 0x08
@ -761,6 +816,14 @@ register QOUTCNT {
access_mode RO
}
/*
* Special Function
*/
register SFUNCT {
address 0x09f
access_mode RW
}
/*
* SCB Definition (p. 5-4)
*/
@ -768,11 +831,11 @@ scb {
address 0x0a0
SCB_CONTROL {
size 1
bit MK_MESSAGE 0x80
bit TARGET_SCB 0x80
bit DISCENB 0x40
bit TAG_ENB 0x20
bit MUST_DMAUP_SCB 0x10
bit ABORT_SCB 0x08
bit MK_MESSAGE 0x10
bit ULTRAENB 0x08
bit DISCONNECTED 0x04
mask SCB_TAG_TYPE 0x03
}
@ -801,15 +864,20 @@ scb {
size 4
}
SCB_DATACNT {
size 3
}
SCB_LINKED_NEXT {
size 1
/*
* Really only 3 bytes, but padded to make
* the kernel's job easier.
*/
size 4
}
SCB_CMDPTR {
alias SCB_TARGET_PHASES
alias SCB_TARGET_ID /* Byte 2 */
bit TARGET_DATA_IN 0x1 /* In the second byte */
size 4
}
SCB_CMDLEN {
alias SCB_INITIATOR_TAG
size 1
}
SCB_TAG {
@ -818,14 +886,29 @@ scb {
SCB_NEXT {
size 1
}
SCB_PREV {
SCB_SCSIRATE {
size 1
}
SCB_BUSYTARGETS {
SCB_SCSIOFFSET {
size 1
}
SCB_SPARE {
size 3
}
SCB_CMDSTORE {
size 16
}
SCB_CMDSTORE_BUSADDR {
size 4
}
SCB_64BYTE_SPARE {
size 12
}
}
const SCB_32BYTE_SIZE 28
const SCB_64BYTE_SIZE 48
const SG_SIZEOF 0x08 /* sizeof(struct ahc_dma) */
/* --------------------- AHA-2840-only definitions -------------------- */
@ -851,6 +934,117 @@ register STATUS_2840 {
register DSPCISTATUS {
address 0x086
mask DFTHRSH_100 0xc0
}
register CCHADDR {
address 0x0E0
size 8
}
register CCHCNT {
address 0x0E8
}
register CCSGRAM {
address 0x0E9
}
register CCSGADDR {
address 0x0EA
}
register CCSGCTL {
address 0x0EB
bit CCSGDONE 0x80
bit CCSGEN 0x08
bit FLAG 0x02
bit CCSGRESET 0x01
}
register CCSCBCNT {
address 0xEF
}
register CCSCBCTL {
address 0x0EE
bit CCSCBDONE 0x80
bit ARRDONE 0x40 /* SCB Array prefetch done */
bit CCARREN 0x10
bit CCSCBEN 0x08
bit CCSCBDIR 0x04
bit CCSCBRESET 0x01
}
register CCSCBADDR {
address 0x0ED
}
register CCSCBRAM {
address 0xEC
}
/*
* SCB bank address (7895/7896/97 only)
*/
register SCBBADDR {
address 0x0F0
access_mode RW
}
register CCSCBPTR {
address 0x0F1
}
register HNSCB_QOFF {
address 0x0F4
}
register SNSCB_QOFF {
address 0x0F6
}
register SDSCB_QOFF {
address 0x0F8
}
register QOFF_CTLSTA {
address 0x0FA
bit SCB_AVAIL 0x40
bit SNSCB_ROLLOVER 0x20
bit SDSCB_ROLLOVER 0x10
mask SCB_QSIZE 0x07
mask SCB_QSIZE_256 0x06
}
register DFF_THRSH {
address 0x0FB
mask WR_DFTHRSH 0x70
mask RD_DFTHRSH 0x07
mask RD_DFTHRSH_MIN 0x00
mask RD_DFTHRSH_25 0x01
mask RD_DFTHRSH_50 0x02
mask RD_DFTHRSH_63 0x03
mask RD_DFTHRSH_75 0x04
mask RD_DFTHRSH_85 0x05
mask RD_DFTHRSH_90 0x06
mask RD_DFTHRSH_MAX 0x07
mask WR_DFTHRSH_MIN 0x00
mask WR_DFTHRSH_25 0x10
mask WR_DFTHRSH_50 0x20
mask WR_DFTHRSH_63 0x30
mask WR_DFTHRSH_75 0x40
mask WR_DFTHRSH_85 0x50
mask WR_DFTHRSH_90 0x60
mask WR_DFTHRSH_MAX 0x70
}
register SG_CACHEPTR {
access_mode RW
address 0x0fc
mask SG_USER_DATA 0xfc
bit LAST_SEG 0x02
bit LAST_SEG_DONE 0x01
}
register BRDCTL {
@ -863,6 +1057,12 @@ register BRDCTL {
bit BRDRW 0x04
bit BRDCTL1 0x02
bit BRDCTL0 0x01
/* 7890 Definitions */
bit BRDDAT4 0x10
bit BRDDAT3 0x08
bit BRDDAT2 0x04
bit BRDRW_ULTRA2 0x02
bit BRDSTB_ULTRA2 0x01
}
/*
@ -921,9 +1121,13 @@ scratch_ram {
/*
* 1 byte per target starting at this address for configuration values
*/
TARG_SCRATCH {
TARG_SCSIRATE {
alias CMDSIZE_TABLE
size 16
}
/*
* Bit vector of targets that have ULTRA enabled.
*/
ULTRA_ENB {
size 2
}
@ -934,18 +1138,16 @@ scratch_ram {
size 2
}
/*
* Length of pending message
* Single byte buffer used to designate the type or message
* to send to a target.
*/
MSG_LEN {
size 1
}
/* We reserve 8bytes to store outgoing messages */
MSG_OUT {
size 8
size 1
}
/* Parameters for DMA Logic */
DMAPARAMS {
size 1
bit PRELOADEN 0x80
bit WIDEODD 0x40
bit SCSIEN 0x20
bit SDMAEN 0x10
@ -958,13 +1160,15 @@ scratch_ram {
}
SEQ_FLAGS {
size 1
bit RESELECTED 0x80
bit IDENTIFY_SEEN 0x40
bit TAGGED_SCB 0x20
bit DPHASE 0x10
bit PAGESCBS 0x04
bit WIDE_BUS 0x02
bit TWIN_BUS 0x01
bit IDENTIFY_SEEN 0x80
bit SCBPTR_VALID 0x40
bit DPHASE 0x20
/* Target flags */
bit TARG_CMD_PENDING 0x10
bit CMDPHASE_PENDING 0x08
bit DPHASE_PENDING 0x04
bit SPHASE_PENDING 0x02
bit NO_DISCONNECT 0x01
}
/*
* Temporary storage for the
@ -974,26 +1178,14 @@ scratch_ram {
SAVED_TCL {
size 1
}
/* Working value of the number of SG segments left */
SG_COUNT {
size 1
}
/* working value of SG pointer */
/* Working value of SG pointer */
SG_NEXT {
size 4
}
/*
* head of list of SCBs awaiting
* selection
*/
WAITING_SCBH {
size 1
}
SAVED_LINKPTR {
size 1
}
SAVED_SCBPTR {
size 1
}
/*
* The last bus phase as seen by the sequencer.
*/
@ -1011,23 +1203,12 @@ scratch_ram {
mask P_MESGIN CDI|IOI|MSGI
mask P_BUSFREE 0x01
}
MSGIN_EXT_LEN {
size 1
}
MSGIN_EXT_OPCODE {
size 1
}
/*
* location 3, stores the last
* byte of an extended message if
* it passes the two bytes of space
* we allow now. This byte isn't
* used for anything, it just makes
* the code shorter for tossing
* extra bytes.
* head of list of SCBs awaiting
* selection
*/
MSGIN_EXT_BYTES {
size 3
WAITING_SCBH {
size 1
}
/*
* head of list of SCBs that are
@ -1044,18 +1225,40 @@ scratch_ram {
FREE_SCBH {
size 1
}
/*
* Address of the hardware scb array in the host.
*/
HSCB_ADDR {
size 4
}
CUR_SCBID {
/*
* Address of the 256 byte array storing the SCBID of outstanding
* untagged SCBs indexed by TCL.
*/
SCBID_ADDR {
size 4
}
/*
* Address of the array of command descriptors used to store
* information about incoming selections.
*/
TMODE_CMDADDR {
size 4
}
KERNEL_QINPOS {
size 1
}
QINPOS {
size 1
}
QOUTPOS {
size 1
}
/*
* Running count of commands placed in
* the QOUTFIFO. This is cleared by the
* kernel driver every FIFODEPTH commands.
* Offset into the command descriptor array for the next
* available desciptor to use.
*/
CMDOUTCNT {
TMODE_CMDADDR_NEXT {
size 1
}
ARG_1 {
@ -1063,8 +1266,30 @@ scratch_ram {
mask SEND_MSG 0x80
mask SEND_SENSE 0x40
mask SEND_REJ 0x20
mask MSGOUT_PHASEMIS 0x10
alias RETURN_1
}
ARG_2 {
size 1
alias RETURN_2
}
/*
* Snapshot of MSG_OUT taken after each message is sent.
*/
LAST_MSG {
size 1
}
/*
* Number of times we have filled the CCSGRAM with prefetched
* SG elements.
*/
PREFETCH_CNT {
size 1
}
/*
* These are reserved registers in the card's scratch ram. Some of
* the values are specified in the AHA2742 technical reference manual
@ -1073,7 +1298,10 @@ scratch_ram {
SCSICONF {
address 0x05a
size 1
bit TERM_ENB 0x80
bit RESET_SCSI 0x40
mask HSCSIID 0x07 /* our SCSI ID */
mask HWSCSIID 0x0f /* our SCSI ID if Wide Bus */
}
HOSTCONF {
address 0x05d
@ -1086,29 +1314,51 @@ scratch_ram {
mask BIOSDISABLED 0x30
bit CHANNEL_B_PRIMARY 0x08
}
/*
* Per target SCSI offset values for Ultra2 controllers.
*/
TARG_OFFSET {
address 0x070
size 16
}
}
const SCB_LIST_NULL 0xff
const TARGET_CMD_CMPLT 0xfe
const CCSGADDR_MAX 0x80
const CCSGRAM_MAXSEGS 16
/* Offsets into the SCBID array where different data is stored */
const QOUTFIFO_OFFSET 0
const QINFIFO_OFFSET 1
const UNTAGGEDSCB_OFFSET 2
/* WDTR Message values */
const BUS_8_BIT 0x00
const BUS_8_BIT 0x00
const BUS_16_BIT 0x01
const BUS_32_BIT 0x02
/* Offset maximums */
const MAX_OFFSET_8BIT 0x0f
const MAX_OFFSET_16BIT 0x08
const MAX_OFFSET_16BIT 0x08
const MAX_OFFSET_ULTRA2 0x7f
const HOST_MSG 0xff
/* Target mode command processing constants */
const CMD_GROUP_CODE_SHIFT 0x05
const CMD_GROUP0_BYTE_DELTA -4
const CMD_GROUP2_BYTE_DELTA 9
const CMD_GROUP3_BYTE_DELTA -15
const CMD_GROUP4_BYTE_DELTA 4
const CMD_GROUP5_BYTE_DELTA 11
/*
* Downloaded (kernel inserted) constants
*/
const SCBCOUNT download /* The number of SCBs on this card */
const COMP_SCBCOUNT download /* Two's complement of max SCBID */
/*
* The maximum number of entries allowed in the QIN/OUTFIFO.
* Number of command descriptors in the command descriptor array.
*/
const FIFODEPTH download /* Two's complement of SCBCOUNT */
/*
* Mask of bits to test against when looking at the Queue Count
* registers. Works around a bug on aic7850 chips.
*/
const QCNTMASK download
const TMODE_NUMCMDS download

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,174 @@
/*
* Interface for the 93C66/56/46/26/06 serial eeprom parts.
*
* Copyright (c) 1995, 1996 Daniel M. Eischen
* 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. Absolutely no warranty of function or purpose is made by the author
* Daniel M. Eischen.
* 4. Modifications may be freely made to this file if the above conditions
* are met.
*
* $Id: 93cx6.c,v 1.10 1997/02/22 09:38:36 peter Exp $
*/
/*
* The instruction set of the 93C66/56/46/26/06 chips are as follows:
*
* Start OP *
* Function Bit Code Address** Data Description
* -------------------------------------------------------------------
* READ 1 10 A5 - A0 Reads data stored in memory,
* starting at specified address
* EWEN 1 00 11XXXX Write enable must preceed
* all programming modes
* ERASE 1 11 A5 - A0 Erase register A5A4A3A2A1A0
* WRITE 1 01 A5 - A0 D15 - D0 Writes register
* ERAL 1 00 10XXXX Erase all registers
* WRAL 1 00 01XXXX D15 - D0 Writes to all registers
* EWDS 1 00 00XXXX Disables all programming
* instructions
* *Note: A value of X for address is a don't care condition.
* **Note: There are 8 address bits for the 93C56/66 chips unlike
* the 93C46/26/06 chips which have 6 address bits.
*
* The 93C46 has a four wire interface: clock, chip select, data in, and
* data out. In order to perform one of the above functions, you need
* to enable the chip select for a clock period (typically a minimum of
* 1 usec, with the clock high and low a minimum of 750 and 250 nsec
* respectively). While the chip select remains high, you can clock in
* the instructions (above) starting with the start bit, followed by the
* OP code, Address, and Data (if needed). For the READ instruction, the
* requested 16-bit register contents is read from the data out line but
* is preceded by an initial zero (leading 0, followed by 16-bits, MSB
* first). The clock cycling from low to high initiates the next data
* bit to be sent from the chip.
*
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <machine/bus_memio.h>
#include <machine/bus_pio.h>
#include <machine/bus.h>
#include <dev/aic7xxx/93cx6.h>
/*
* Right now, we only have to read the SEEPROM. But we make it easier to
* add other 93Cx6 functions.
*/
static struct seeprom_cmd {
unsigned char len;
unsigned char bits[3];
} seeprom_read = {3, {1, 1, 0}};
/*
* Wait for the SEERDY to go high; about 800 ns.
*/
#define CLOCK_PULSE(sd, rdy) \
while ((SEEPROM_STATUS_INB(sd) & rdy) == 0) { \
; /* Do nothing */ \
} \
(void)SEEPROM_INB(sd); /* Clear clock */
/*
* Read the serial EEPROM and returns 1 if successful and 0 if
* not successful.
*/
int
read_seeprom(sd, buf, start_addr, count)
struct seeprom_descriptor *sd;
u_int16_t *buf;
bus_size_t start_addr;
bus_size_t count;
{
int i = 0;
u_int k = 0;
u_int16_t v;
u_int8_t temp;
/*
* Read the requested registers of the seeprom. The loop
* will range from 0 to count-1.
*/
for (k = start_addr; k < count + start_addr; k++) {
/* Send chip select for one clock cycle. */
temp = sd->sd_MS ^ sd->sd_CS;
SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
CLOCK_PULSE(sd, sd->sd_RDY);
/*
* Now we're ready to send the read command followed by the
* address of the 16-bit register we want to read.
*/
for (i = 0; i < seeprom_read.len; i++) {
if (seeprom_read.bits[i] != 0)
temp ^= sd->sd_DO;
SEEPROM_OUTB(sd, temp);
CLOCK_PULSE(sd, sd->sd_RDY);
SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
CLOCK_PULSE(sd, sd->sd_RDY);
if (seeprom_read.bits[i] != 0)
temp ^= sd->sd_DO;
}
/* Send the 6 or 8 bit address (MSB first, LSB last). */
for (i = (sd->sd_chip - 1); i >= 0; i--) {
if ((k & (1 << i)) != 0)
temp ^= sd->sd_DO;
SEEPROM_OUTB(sd, temp);
CLOCK_PULSE(sd, sd->sd_RDY);
SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
CLOCK_PULSE(sd, sd->sd_RDY);
if ((k & (1 << i)) != 0)
temp ^= sd->sd_DO;
}
/*
* Now read the 16 bit register. An initial 0 precedes the
* register contents which begins with bit 15 (MSB) and ends
* with bit 0 (LSB). The initial 0 will be shifted off the
* top of our word as we let the loop run from 0 to 16.
*/
v = 0;
for (i = 16; i >= 0; i--) {
SEEPROM_OUTB(sd, temp);
CLOCK_PULSE(sd, sd->sd_RDY);
v <<= 1;
if (SEEPROM_DATA_INB(sd) & sd->sd_DI)
v |= 1;
SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
CLOCK_PULSE(sd, sd->sd_RDY);
}
buf[k - start_addr] = v;
/* Reset the chip select for the next command cycle. */
temp = sd->sd_MS;
SEEPROM_OUTB(sd, temp);
CLOCK_PULSE(sd, sd->sd_RDY);
SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
CLOCK_PULSE(sd, sd->sd_RDY);
SEEPROM_OUTB(sd, temp);
CLOCK_PULSE(sd, sd->sd_RDY);
}
#ifdef 93CX6_DUMP_EEPROM
printf("\nSerial EEPROM:");
for (k = 0; k < count; k = k + 1) {
if (((k % 8) == 0) && (k != 0)) {
printf ("\n ");
}
printf (" 0x%x", buf[k]);
}
printf ("\n");
#endif
return (1);
}

View File

@ -0,0 +1,95 @@
/*
* Interface to the 93C46 serial EEPROM that is used to store BIOS
* settings for the aic7xxx based adaptec SCSI controllers. It can
* also be used for 93C26 and 93C06 serial EEPROMS.
*
* Copyright (c) 1994, 1995 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, this list of conditions, and the following disclaimer,
* without modification, immediately at the beginning of the file.
* 2. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* Where this Software is combined with software released under the terms of
* the GNU Public License ("GPL") and the terms of the GPL would require the
* combined work to also be released under the terms of the GPL, the terms
* and conditions of this License will apply in addition to those of the
* GPL with the exception of any terms or conditions of this License that
* conflict with, or are expressly prohibited by, the GPL.
*
* 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/param.h>
#if !defined(__NetBSD__)
#include <sys/systm.h>
#endif
#ifdef KERNEL
typedef enum {
C46 = 6,
C56_66 = 8
} seeprom_chip_t;
struct seeprom_descriptor {
bus_space_tag_t sd_tag;
bus_space_handle_t sd_bsh;
bus_size_t sd_control_offset;
bus_size_t sd_status_offset;
bus_size_t sd_dataout_offset;
seeprom_chip_t sd_chip;
u_int16_t sd_MS;
u_int16_t sd_RDY;
u_int16_t sd_CS;
u_int16_t sd_CK;
u_int16_t sd_DO;
u_int16_t sd_DI;
};
/*
* This function will read count 16-bit words from the serial EEPROM and
* return their value in buf. The port address of the aic7xxx serial EEPROM
* control register is passed in as offset. The following parameters are
* also passed in:
*
* CS - Chip select
* CK - Clock
* DO - Data out
* DI - Data in
* RDY - SEEPROM ready
* MS - Memory port mode select
*
* A failed read attempt returns 0, and a successful read returns 1.
*/
#define SEEPROM_INB(sd) \
bus_space_read_1(sd->sd_tag, sd->sd_bsh, sd->sd_control_offset)
#define SEEPROM_OUTB(sd, value) \
bus_space_write_1(sd->sd_tag, sd->sd_bsh, sd->sd_control_offset, value)
#define SEEPROM_STATUS_INB(sd) \
bus_space_read_1(sd->sd_tag, sd->sd_bsh, sd->sd_status_offset)
#define SEEPROM_DATA_INB(sd) \
bus_space_read_1(sd->sd_tag, sd->sd_bsh, sd->sd_dataout_offset)
int read_seeprom(struct seeprom_descriptor *sd, u_int16_t *buf,
bus_size_t start_addr, bus_size_t count);
#endif /* KERNEL */

View File

@ -1,7 +1,7 @@
/*
* Aic7xxx SCSI host adapter firmware asssembler
*
* Copyright (c) 1997 Justin T. Gibbs.
* Copyright (c) 1997, 1998 Justin T. Gibbs.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -10,10 +10,7 @@
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer,
* without modification, immediately at the beginning of the file.
* 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
* 2. 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
@ -28,7 +25,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: aicasm.c,v 1.18 1997/06/27 19:38:45 gibbs Exp $
* $Id: aicasm.c,v 1.19 1997/09/03 03:44:38 gibbs Exp $
*/
#include <sys/types.h>
#include <sys/mman.h>
@ -43,13 +40,24 @@
#include "aicasm_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,
char *options));
static struct patch *next_patch __P((struct patch *cur_patch, int options,
int instrptr));
typedef struct patch {
STAILQ_ENTRY(patch) links;
int patch_func;
u_int begin;
u_int skip_instr;
u_int skip_patch;
} patch_t;
STAILQ_HEAD(patch_list, patch) patches;
static void usage(void);
static void back_patch(void);
static void output_code(FILE *ofile);
static void output_listing(FILE *listfile, char *ifilename);
static int dump_scope(scope_t *scope);
static void emit_patch(scope_t *scope, int patch);
static int check_patch(patch_t **start_patch, int start_instr,
int *skip_addr, int *func_vals);
struct path_list search_path;
int includes_search_curdir;
@ -62,8 +70,8 @@ char *listfilename;
FILE *listfile;
static STAILQ_HEAD(,instruction) seq_program;
static STAILQ_HEAD(, patch) patch_list;
symlist_t patch_options;
struct scope_list scope_stack;
symlist_t patch_functions;
#if DEBUG
extern int yy_flex_debug;
@ -82,19 +90,24 @@ main(argc, argv)
int ch;
int retval;
char *inputfilename;
char *options;
scope_t *sentinal;
STAILQ_INIT(&patches);
SLIST_INIT(&search_path);
STAILQ_INIT(&seq_program);
STAILQ_INIT(&patch_list);
SLIST_INIT(&patch_options);
SLIST_INIT(&scope_stack);
/* Set Sentinal scope node */
sentinal = scope_alloc();
sentinal->type = SCOPE_ROOT;
includes_search_curdir = 1;
appname = *argv;
regfile = NULL;
listfile = NULL;
options = NULL;
#if DEBUG
yy_flex_debug = 0;
yydebug = 0;
#endif
while ((ch = getopt(argc, argv, "d:l:n:o:r:I:O:")) != -1) {
switch(ch) {
@ -138,10 +151,6 @@ main(argc, argv)
}
ofilename = optarg;
break;
case 'O':
/* Patches to include in the listing */
options = optarg;
break;
case 'r':
if ((regfile = fopen(optarg, "w")) == NULL) {
perror(optarg);
@ -207,13 +216,33 @@ main(argc, argv)
include_file(*argv, SOURCE_FILE);
retval = yyparse();
if (retval == 0) {
if (SLIST_FIRST(&scope_stack) == NULL
|| SLIST_FIRST(&scope_stack)->type != SCOPE_ROOT) {
stop("Unterminated conditional expression",
EX_DATAERR);
/* NOTREACHED */
}
/* Process outmost scope */
process_scope(SLIST_FIRST(&scope_stack));
/*
* Decend the tree of scopes and insert/emit
* patches as appropriate. We perform a depth first
* tranversal, recursively handling each scope.
*/
/* start at the root scope */
dump_scope(SLIST_FIRST(&scope_stack));
/* Patch up forward jump addresses */
back_patch();
if (ofile != NULL)
output_code(ofile);
if (regfile != NULL)
if (regfile != NULL) {
symtable_dump(regfile);
}
if (listfile != NULL)
output_listing(listfile, inputfilename, options);
output_listing(listfile, inputfilename);
}
stop(NULL, 0);
@ -228,7 +257,7 @@ usage()
(void)fprintf(stderr,
"usage: %-16s [-nostdinc] [-I-] [-I directory] [-o output_file]
[-r register_output_file] [-l program_list_file]
[-O option_name[|options_name2]] input_file\n",
input_file\n",
appname);
exit(EX_USAGE);
}
@ -255,12 +284,9 @@ back_patch()
/* NOTREACHED */
}
f3_instr = &cur_instr->format.format3;
address = ((f3_instr->opcode_addr & ADDR_HIGH_BIT) << 8)
| f3_instr->address;
address = 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;
f3_instr->address = address;
}
}
}
@ -284,6 +310,7 @@ output_code(ofile)
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],
@ -291,60 +318,128 @@ output_code(ofile)
cur_instr->format.bytes[3]);
instrcount++;
}
fprintf(ofile, "};\n");
fprintf(ofile, "};\n\n");
/*
* Output the patch list, option definitions first.
* Output patch information. Patch functions first.
*/
for(cur_node = patch_options.slh_first;
for(cur_node = SLIST_FIRST(&patch_functions);
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);
cur_node = SLIST_NEXT(cur_node,links)) {
fprintf(ofile,
"static int ahc_patch%d_func(struct ahc_softc *ahc);
static int
ahc_patch%d_func(struct ahc_softc *ahc)
{
return (%s);
}\n\n",
cur_node->symbol->info.condinfo->func_num,
cur_node->symbol->info.condinfo->func_num,
cur_node->symbol->name);
}
fprintf(ofile,
"struct patch {
int options;
int negative;
int begin;
int end;
"typedef int patch_func_t __P((struct ahc_softc *));
struct patch {
patch_func_t *patch_func;
u_int32_t begin :10,
skip_instr :10,
skip_patch :12;
} patches[] = {\n");
for(cur_patch = patch_list.stqh_first;
for(cur_patch = STAILQ_FIRST(&patches);
cur_patch != NULL;
cur_patch = cur_patch->links.stqe_next)
cur_patch = STAILQ_NEXT(cur_patch,links)) {
fprintf(ofile, "\t{ ahc_patch%d_func, %d, %d, %d },\n",
cur_patch->patch_func, cur_patch->begin,
cur_patch->skip_instr, cur_patch->skip_patch);
}
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, "\n};\n");
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, patches)
FILE *listfile;
char *ifilename;
char *patches;
static int
dump_scope(scope_t *scope)
{
scope_t *cur_scope;
int patches_emitted = 0;
/*
* Emit the first patch for this scope
*/
emit_patch(scope, 0);
/*
* Dump each scope within this one.
*/
cur_scope = TAILQ_FIRST(&scope->inner_scope);
while (cur_scope != NULL) {
dump_scope(cur_scope);
cur_scope = TAILQ_NEXT(cur_scope, scope_links);
}
/*
* Emit the second, closing, patch for this scope
*/
emit_patch(scope, 1);
}
void
emit_patch(scope_t *scope, int patch)
{
patch_info_t *pinfo;
patch_t *new_patch;
pinfo = &scope->patches[patch];
if (pinfo->skip_instr == 0)
/* No-Op patch */
return;
new_patch = (patch_t *)malloc(sizeof(*new_patch));
if (new_patch == NULL)
stop("Could not malloc patch structure", EX_OSERR);
memset(new_patch, 0, sizeof(*new_patch));
if (patch == 0) {
new_patch->patch_func = scope->func_num;
new_patch->begin = scope->begin_addr;
} else {
new_patch->patch_func = 0;
new_patch->begin = scope->end_addr;
}
new_patch->skip_instr = pinfo->skip_instr;
new_patch->skip_patch = pinfo->skip_patch;
STAILQ_INSERT_TAIL(&patches, new_patch, links);
}
void
output_listing(FILE *listfile, char *ifilename)
{
char buf[1024];
FILE *ifile;
int line;
struct instruction *cur_instr;
patch_t *cur_patch;
symbol_node_t *cur_func;
int *func_values;
int instrcount;
int instrptr;
char buf[1024];
patch_t *cur_patch;
char *option_spec;
int options;
int line;
int func_count;
int skip_addr;
instrcount = 0;
instrptr = 0;
line = 1;
options = 1; /* All code outside of patch blocks */
skip_addr = 0;
if ((ifile = fopen(ifilename, "r")) == NULL) {
perror(ifilename);
stop(NULL, EX_DATAERR);
@ -353,31 +448,66 @@ output_listing(listfile, ifilename, patches)
/*
* Determine which options to apply to this listing.
*/
while ((option_spec = strsep(&patches, "|")) != NULL) {
symbol_t *symbol;
for (func_count = 0, cur_func = SLIST_FIRST(&patch_functions);
cur_func != NULL;
cur_func = SLIST_NEXT(cur_func, links))
func_count++;
symbol = symtable_get(option_spec);
if (symbol->type != CONDITIONAL) {
stop("Invalid option specified in patch list for "
"program listing", EX_USAGE);
/* NOTREACHED */
if (func_count != 0) {
func_values = (int *)malloc(func_count * sizeof(int));
if (func_values == NULL)
stop("Could not malloc", EX_OSERR);
func_values[0] = 0; /* FALSE func */
func_count--;
/*
* Ask the user to fill in the return values for
* the rest of the functions.
*/
for (cur_func = SLIST_FIRST(&patch_functions);
cur_func != NULL && SLIST_NEXT(cur_func, links) != NULL;
cur_func = SLIST_NEXT(cur_func, links), func_count--) {
int input;
fprintf(stdout, "\n(%s)\n", cur_func->symbol->name);
fprintf(stdout,
"Enter the return value for "
"this expression[T/F]:");
while (1) {
input = getchar();
input = toupper(input);
if (input == 'T') {
func_values[func_count] = 1;
break;
} else if (input == 'F') {
func_values[func_count] = 0;
break;
}
}
}
options |= symbol->info.condinfo->value;
fprintf(stdout, "\nThanks!\n");
}
cur_patch = patch_list.stqh_first;
for(cur_instr = seq_program.stqh_first;
/* Now output the listing */
cur_patch = STAILQ_FIRST(&patches);
for(cur_instr = STAILQ_FIRST(&seq_program);
cur_instr != NULL;
cur_instr = cur_instr->links.stqe_next,instrcount++) {
cur_instr = STAILQ_NEXT(cur_instr, links), instrcount++) {
cur_patch = next_patch(cur_patch, options, instrcount);
if (cur_patch
&& cur_patch->begin <= instrcount
&& cur_patch->end > instrcount)
if (check_patch(&cur_patch, instrcount,
&skip_addr, func_values) == 0) {
/* Don't count this instruction as it is in a patch
* that was removed.
*/
continue;
}
while (line < cur_instr->srcline) {
fgets(buf, sizeof(buf), ifile);
@ -401,29 +531,39 @@ output_listing(listfile, ifilename, patches)
fclose(ifile);
}
static struct patch *
next_patch(cur_patch, options, instrptr)
struct patch *cur_patch;
int options;
int instrptr;
static int
check_patch(patch_t **start_patch, int start_instr,
int *skip_addr, int *func_vals)
{
while(cur_patch != NULL) {
if (((cur_patch->options & options) != 0
&& cur_patch->negative == FALSE)
|| ((cur_patch->options & options) == 0
&& cur_patch->negative == TRUE)
|| (instrptr >= cur_patch->end)) {
/*
* Either we want to keep this section of code,
* or we have consumed this patch. Skip to the
* next patch.
patch_t *cur_patch;
cur_patch = *start_patch;
while (cur_patch != NULL && start_instr == cur_patch->begin) {
if (func_vals[cur_patch->patch_func] == 0) {
int skip;
/* Start rejecting code */
*skip_addr = start_instr + cur_patch->skip_instr;
for (skip = cur_patch->skip_patch;
skip > 0 && cur_patch != NULL;
skip--)
cur_patch = STAILQ_NEXT(cur_patch, links);
} else {
/* Accepted this patch. Advance to the next
* one and wait for our intruction pointer to
* hit this point.
*/
cur_patch = cur_patch->links.stqe_next;
} else
/* Found an okay patch */
break;
cur_patch = STAILQ_NEXT(cur_patch, links);
}
}
return (cur_patch);
*start_patch = cur_patch;
if (start_instr < *skip_addr)
/* Still skipping */
return (0);
return (1);
}
/*
@ -471,7 +611,7 @@ stop(string, err_code)
}
}
symlist_free(&patch_options);
symlist_free(&patch_functions);
symtable_close();
exit(err_code);
@ -491,15 +631,85 @@ seq_alloc()
return new_instr;
}
patch_t *
patch_alloc()
scope_t *
scope_alloc()
{
patch_t *new_patch;
scope_t *new_scope;
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;
new_scope = (scope_t *)malloc(sizeof(scope_t));
if (new_scope == NULL)
stop("Unable to malloc scope object", EX_SOFTWARE);
memset(new_scope, 0, sizeof(*new_scope));
TAILQ_INIT(&new_scope->inner_scope);
if (SLIST_FIRST(&scope_stack) != NULL) {
TAILQ_INSERT_TAIL(&SLIST_FIRST(&scope_stack)->inner_scope,
new_scope, scope_links);
}
/* This patch is now the current scope */
SLIST_INSERT_HEAD(&scope_stack, new_scope, scope_stack_links);
return new_scope;
}
void
process_scope(scope_t *scope)
{
/*
* We are "leaving" this scope. We should now have
* enough information to process the lists of scopes
* we encapsulate.
*/
scope_t *cur_scope;
u_int skip_patch_count;
u_int skip_instr_count;
cur_scope = TAILQ_LAST(&scope->inner_scope, scope_tailq);
skip_patch_count = 0;
skip_instr_count = 0;
while (cur_scope != NULL) {
u_int patch0_patch_skip;
patch0_patch_skip = 0;
switch (cur_scope->type) {
case SCOPE_IF:
case SCOPE_ELSE_IF:
if (skip_instr_count != 0) {
/* Create a tail patch */
patch0_patch_skip++;
cur_scope->patches[1].skip_patch =
skip_patch_count + 1;
cur_scope->patches[1].skip_instr =
skip_instr_count;
}
/* Count Head patch */
patch0_patch_skip++;
/* Count any patches contained in our inner scope */
patch0_patch_skip += cur_scope->inner_scope_patches;
cur_scope->patches[0].skip_patch = patch0_patch_skip;
cur_scope->patches[0].skip_instr =
cur_scope->end_addr - cur_scope->begin_addr;
skip_instr_count += cur_scope->patches[0].skip_instr;
skip_patch_count += patch0_patch_skip;
if (cur_scope->type == SCOPE_IF) {
scope->inner_scope_patches += skip_patch_count;
skip_patch_count = 0;
skip_instr_count = 0;
}
break;
case SCOPE_ELSE:
/* Count any patches contained in our innter scope */
skip_patch_count += cur_scope->inner_scope_patches;
skip_instr_count += cur_scope->end_addr
- cur_scope->begin_addr;
break;
}
cur_scope = TAILQ_PREV(cur_scope, scope_tailq, scope_links);
}
}

View File

@ -10,10 +10,7 @@
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer,
* without modification, immediately at the beginning of the file.
* 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
* 2. 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
@ -28,7 +25,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: aic7xxx_asm.h,v 1.2 1997/03/16 07:28:30 gibbs Exp $
* $Id: aicasm.h,v 1.3 1997/06/27 19:38:47 gibbs Exp $
*/
#include <sys/queue.h>
@ -56,13 +53,15 @@ typedef enum {
SLIST_HEAD(path_list, path_entry);
extern struct path_list search_path;
extern struct symlist patch_options;
extern struct scope_list scope_stack;
extern struct symlist patch_functions;
extern int includes_search_curdir; /* False if we've seen -I- */
extern char *appname;
extern int yylineno;
extern char *yyfilename;
void stop __P((const char *errstring, int err_code));
void include_file __P((char *file_name, include_type type));
struct instruction *seq_alloc __P((void));
struct patch *patch_alloc __P((void));
void stop(const char *errstring, int err_code);
void include_file(char *file_name, include_type type);
struct instruction *seq_alloc(void);
struct scope *scope_alloc(void);
void process_scope(struct scope *);

View File

@ -1,7 +1,7 @@
/*
* Aic7xxx SCSI host adapter firmware asssembler
*
* Copyright (c) 1997 Justin T. Gibbs.
* Copyright (c) 1997, 1998 Justin T. Gibbs.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -10,10 +10,7 @@
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer,
* without modification, immediately at the beginning of the file.
* 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
* 2. 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
@ -28,7 +25,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: aicasm.c,v 1.18 1997/06/27 19:38:45 gibbs Exp $
* $Id: aicasm.c,v 1.19 1997/09/03 03:44:38 gibbs Exp $
*/
#include <sys/types.h>
#include <sys/mman.h>
@ -43,13 +40,24 @@
#include "aicasm_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,
char *options));
static struct patch *next_patch __P((struct patch *cur_patch, int options,
int instrptr));
typedef struct patch {
STAILQ_ENTRY(patch) links;
int patch_func;
u_int begin;
u_int skip_instr;
u_int skip_patch;
} patch_t;
STAILQ_HEAD(patch_list, patch) patches;
static void usage(void);
static void back_patch(void);
static void output_code(FILE *ofile);
static void output_listing(FILE *listfile, char *ifilename);
static int dump_scope(scope_t *scope);
static void emit_patch(scope_t *scope, int patch);
static int check_patch(patch_t **start_patch, int start_instr,
int *skip_addr, int *func_vals);
struct path_list search_path;
int includes_search_curdir;
@ -62,8 +70,8 @@ char *listfilename;
FILE *listfile;
static STAILQ_HEAD(,instruction) seq_program;
static STAILQ_HEAD(, patch) patch_list;
symlist_t patch_options;
struct scope_list scope_stack;
symlist_t patch_functions;
#if DEBUG
extern int yy_flex_debug;
@ -82,19 +90,24 @@ main(argc, argv)
int ch;
int retval;
char *inputfilename;
char *options;
scope_t *sentinal;
STAILQ_INIT(&patches);
SLIST_INIT(&search_path);
STAILQ_INIT(&seq_program);
STAILQ_INIT(&patch_list);
SLIST_INIT(&patch_options);
SLIST_INIT(&scope_stack);
/* Set Sentinal scope node */
sentinal = scope_alloc();
sentinal->type = SCOPE_ROOT;
includes_search_curdir = 1;
appname = *argv;
regfile = NULL;
listfile = NULL;
options = NULL;
#if DEBUG
yy_flex_debug = 0;
yydebug = 0;
#endif
while ((ch = getopt(argc, argv, "d:l:n:o:r:I:O:")) != -1) {
switch(ch) {
@ -138,10 +151,6 @@ main(argc, argv)
}
ofilename = optarg;
break;
case 'O':
/* Patches to include in the listing */
options = optarg;
break;
case 'r':
if ((regfile = fopen(optarg, "w")) == NULL) {
perror(optarg);
@ -207,13 +216,33 @@ main(argc, argv)
include_file(*argv, SOURCE_FILE);
retval = yyparse();
if (retval == 0) {
if (SLIST_FIRST(&scope_stack) == NULL
|| SLIST_FIRST(&scope_stack)->type != SCOPE_ROOT) {
stop("Unterminated conditional expression",
EX_DATAERR);
/* NOTREACHED */
}
/* Process outmost scope */
process_scope(SLIST_FIRST(&scope_stack));
/*
* Decend the tree of scopes and insert/emit
* patches as appropriate. We perform a depth first
* tranversal, recursively handling each scope.
*/
/* start at the root scope */
dump_scope(SLIST_FIRST(&scope_stack));
/* Patch up forward jump addresses */
back_patch();
if (ofile != NULL)
output_code(ofile);
if (regfile != NULL)
if (regfile != NULL) {
symtable_dump(regfile);
}
if (listfile != NULL)
output_listing(listfile, inputfilename, options);
output_listing(listfile, inputfilename);
}
stop(NULL, 0);
@ -228,7 +257,7 @@ usage()
(void)fprintf(stderr,
"usage: %-16s [-nostdinc] [-I-] [-I directory] [-o output_file]
[-r register_output_file] [-l program_list_file]
[-O option_name[|options_name2]] input_file\n",
input_file\n",
appname);
exit(EX_USAGE);
}
@ -255,12 +284,9 @@ back_patch()
/* NOTREACHED */
}
f3_instr = &cur_instr->format.format3;
address = ((f3_instr->opcode_addr & ADDR_HIGH_BIT) << 8)
| f3_instr->address;
address = 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;
f3_instr->address = address;
}
}
}
@ -284,6 +310,7 @@ output_code(ofile)
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],
@ -291,60 +318,128 @@ output_code(ofile)
cur_instr->format.bytes[3]);
instrcount++;
}
fprintf(ofile, "};\n");
fprintf(ofile, "};\n\n");
/*
* Output the patch list, option definitions first.
* Output patch information. Patch functions first.
*/
for(cur_node = patch_options.slh_first;
for(cur_node = SLIST_FIRST(&patch_functions);
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);
cur_node = SLIST_NEXT(cur_node,links)) {
fprintf(ofile,
"static int ahc_patch%d_func(struct ahc_softc *ahc);
static int
ahc_patch%d_func(struct ahc_softc *ahc)
{
return (%s);
}\n\n",
cur_node->symbol->info.condinfo->func_num,
cur_node->symbol->info.condinfo->func_num,
cur_node->symbol->name);
}
fprintf(ofile,
"struct patch {
int options;
int negative;
int begin;
int end;
"typedef int patch_func_t __P((struct ahc_softc *));
struct patch {
patch_func_t *patch_func;
u_int32_t begin :10,
skip_instr :10,
skip_patch :12;
} patches[] = {\n");
for(cur_patch = patch_list.stqh_first;
for(cur_patch = STAILQ_FIRST(&patches);
cur_patch != NULL;
cur_patch = cur_patch->links.stqe_next)
cur_patch = STAILQ_NEXT(cur_patch,links)) {
fprintf(ofile, "\t{ ahc_patch%d_func, %d, %d, %d },\n",
cur_patch->patch_func, cur_patch->begin,
cur_patch->skip_instr, cur_patch->skip_patch);
}
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, "\n};\n");
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, patches)
FILE *listfile;
char *ifilename;
char *patches;
static int
dump_scope(scope_t *scope)
{
scope_t *cur_scope;
int patches_emitted = 0;
/*
* Emit the first patch for this scope
*/
emit_patch(scope, 0);
/*
* Dump each scope within this one.
*/
cur_scope = TAILQ_FIRST(&scope->inner_scope);
while (cur_scope != NULL) {
dump_scope(cur_scope);
cur_scope = TAILQ_NEXT(cur_scope, scope_links);
}
/*
* Emit the second, closing, patch for this scope
*/
emit_patch(scope, 1);
}
void
emit_patch(scope_t *scope, int patch)
{
patch_info_t *pinfo;
patch_t *new_patch;
pinfo = &scope->patches[patch];
if (pinfo->skip_instr == 0)
/* No-Op patch */
return;
new_patch = (patch_t *)malloc(sizeof(*new_patch));
if (new_patch == NULL)
stop("Could not malloc patch structure", EX_OSERR);
memset(new_patch, 0, sizeof(*new_patch));
if (patch == 0) {
new_patch->patch_func = scope->func_num;
new_patch->begin = scope->begin_addr;
} else {
new_patch->patch_func = 0;
new_patch->begin = scope->end_addr;
}
new_patch->skip_instr = pinfo->skip_instr;
new_patch->skip_patch = pinfo->skip_patch;
STAILQ_INSERT_TAIL(&patches, new_patch, links);
}
void
output_listing(FILE *listfile, char *ifilename)
{
char buf[1024];
FILE *ifile;
int line;
struct instruction *cur_instr;
patch_t *cur_patch;
symbol_node_t *cur_func;
int *func_values;
int instrcount;
int instrptr;
char buf[1024];
patch_t *cur_patch;
char *option_spec;
int options;
int line;
int func_count;
int skip_addr;
instrcount = 0;
instrptr = 0;
line = 1;
options = 1; /* All code outside of patch blocks */
skip_addr = 0;
if ((ifile = fopen(ifilename, "r")) == NULL) {
perror(ifilename);
stop(NULL, EX_DATAERR);
@ -353,31 +448,66 @@ output_listing(listfile, ifilename, patches)
/*
* Determine which options to apply to this listing.
*/
while ((option_spec = strsep(&patches, "|")) != NULL) {
symbol_t *symbol;
for (func_count = 0, cur_func = SLIST_FIRST(&patch_functions);
cur_func != NULL;
cur_func = SLIST_NEXT(cur_func, links))
func_count++;
symbol = symtable_get(option_spec);
if (symbol->type != CONDITIONAL) {
stop("Invalid option specified in patch list for "
"program listing", EX_USAGE);
/* NOTREACHED */
if (func_count != 0) {
func_values = (int *)malloc(func_count * sizeof(int));
if (func_values == NULL)
stop("Could not malloc", EX_OSERR);
func_values[0] = 0; /* FALSE func */
func_count--;
/*
* Ask the user to fill in the return values for
* the rest of the functions.
*/
for (cur_func = SLIST_FIRST(&patch_functions);
cur_func != NULL && SLIST_NEXT(cur_func, links) != NULL;
cur_func = SLIST_NEXT(cur_func, links), func_count--) {
int input;
fprintf(stdout, "\n(%s)\n", cur_func->symbol->name);
fprintf(stdout,
"Enter the return value for "
"this expression[T/F]:");
while (1) {
input = getchar();
input = toupper(input);
if (input == 'T') {
func_values[func_count] = 1;
break;
} else if (input == 'F') {
func_values[func_count] = 0;
break;
}
}
}
options |= symbol->info.condinfo->value;
fprintf(stdout, "\nThanks!\n");
}
cur_patch = patch_list.stqh_first;
for(cur_instr = seq_program.stqh_first;
/* Now output the listing */
cur_patch = STAILQ_FIRST(&patches);
for(cur_instr = STAILQ_FIRST(&seq_program);
cur_instr != NULL;
cur_instr = cur_instr->links.stqe_next,instrcount++) {
cur_instr = STAILQ_NEXT(cur_instr, links), instrcount++) {
cur_patch = next_patch(cur_patch, options, instrcount);
if (cur_patch
&& cur_patch->begin <= instrcount
&& cur_patch->end > instrcount)
if (check_patch(&cur_patch, instrcount,
&skip_addr, func_values) == 0) {
/* Don't count this instruction as it is in a patch
* that was removed.
*/
continue;
}
while (line < cur_instr->srcline) {
fgets(buf, sizeof(buf), ifile);
@ -401,29 +531,39 @@ output_listing(listfile, ifilename, patches)
fclose(ifile);
}
static struct patch *
next_patch(cur_patch, options, instrptr)
struct patch *cur_patch;
int options;
int instrptr;
static int
check_patch(patch_t **start_patch, int start_instr,
int *skip_addr, int *func_vals)
{
while(cur_patch != NULL) {
if (((cur_patch->options & options) != 0
&& cur_patch->negative == FALSE)
|| ((cur_patch->options & options) == 0
&& cur_patch->negative == TRUE)
|| (instrptr >= cur_patch->end)) {
/*
* Either we want to keep this section of code,
* or we have consumed this patch. Skip to the
* next patch.
patch_t *cur_patch;
cur_patch = *start_patch;
while (cur_patch != NULL && start_instr == cur_patch->begin) {
if (func_vals[cur_patch->patch_func] == 0) {
int skip;
/* Start rejecting code */
*skip_addr = start_instr + cur_patch->skip_instr;
for (skip = cur_patch->skip_patch;
skip > 0 && cur_patch != NULL;
skip--)
cur_patch = STAILQ_NEXT(cur_patch, links);
} else {
/* Accepted this patch. Advance to the next
* one and wait for our intruction pointer to
* hit this point.
*/
cur_patch = cur_patch->links.stqe_next;
} else
/* Found an okay patch */
break;
cur_patch = STAILQ_NEXT(cur_patch, links);
}
}
return (cur_patch);
*start_patch = cur_patch;
if (start_instr < *skip_addr)
/* Still skipping */
return (0);
return (1);
}
/*
@ -471,7 +611,7 @@ stop(string, err_code)
}
}
symlist_free(&patch_options);
symlist_free(&patch_functions);
symtable_close();
exit(err_code);
@ -491,15 +631,85 @@ seq_alloc()
return new_instr;
}
patch_t *
patch_alloc()
scope_t *
scope_alloc()
{
patch_t *new_patch;
scope_t *new_scope;
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;
new_scope = (scope_t *)malloc(sizeof(scope_t));
if (new_scope == NULL)
stop("Unable to malloc scope object", EX_SOFTWARE);
memset(new_scope, 0, sizeof(*new_scope));
TAILQ_INIT(&new_scope->inner_scope);
if (SLIST_FIRST(&scope_stack) != NULL) {
TAILQ_INSERT_TAIL(&SLIST_FIRST(&scope_stack)->inner_scope,
new_scope, scope_links);
}
/* This patch is now the current scope */
SLIST_INSERT_HEAD(&scope_stack, new_scope, scope_stack_links);
return new_scope;
}
void
process_scope(scope_t *scope)
{
/*
* We are "leaving" this scope. We should now have
* enough information to process the lists of scopes
* we encapsulate.
*/
scope_t *cur_scope;
u_int skip_patch_count;
u_int skip_instr_count;
cur_scope = TAILQ_LAST(&scope->inner_scope, scope_tailq);
skip_patch_count = 0;
skip_instr_count = 0;
while (cur_scope != NULL) {
u_int patch0_patch_skip;
patch0_patch_skip = 0;
switch (cur_scope->type) {
case SCOPE_IF:
case SCOPE_ELSE_IF:
if (skip_instr_count != 0) {
/* Create a tail patch */
patch0_patch_skip++;
cur_scope->patches[1].skip_patch =
skip_patch_count + 1;
cur_scope->patches[1].skip_instr =
skip_instr_count;
}
/* Count Head patch */
patch0_patch_skip++;
/* Count any patches contained in our inner scope */
patch0_patch_skip += cur_scope->inner_scope_patches;
cur_scope->patches[0].skip_patch = patch0_patch_skip;
cur_scope->patches[0].skip_instr =
cur_scope->end_addr - cur_scope->begin_addr;
skip_instr_count += cur_scope->patches[0].skip_instr;
skip_patch_count += patch0_patch_skip;
if (cur_scope->type == SCOPE_IF) {
scope->inner_scope_patches += skip_patch_count;
skip_patch_count = 0;
skip_instr_count = 0;
}
break;
case SCOPE_ELSE:
/* Count any patches contained in our innter scope */
skip_patch_count += cur_scope->inner_scope_patches;
skip_instr_count += cur_scope->end_addr
- cur_scope->begin_addr;
break;
}
cur_scope = TAILQ_PREV(cur_scope, scope_tailq, scope_links);
}
}

View File

@ -10,10 +10,7 @@
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer,
* without modification, immediately at the beginning of the file.
* 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
* 2. 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
@ -28,7 +25,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: aic7xxx_asm.h,v 1.2 1997/03/16 07:28:30 gibbs Exp $
* $Id: aicasm.h,v 1.3 1997/06/27 19:38:47 gibbs Exp $
*/
#include <sys/queue.h>
@ -56,13 +53,15 @@ typedef enum {
SLIST_HEAD(path_list, path_entry);
extern struct path_list search_path;
extern struct symlist patch_options;
extern struct scope_list scope_stack;
extern struct symlist patch_functions;
extern int includes_search_curdir; /* False if we've seen -I- */
extern char *appname;
extern int yylineno;
extern char *yyfilename;
void stop __P((const char *errstring, int err_code));
void include_file __P((char *file_name, include_type type));
struct instruction *seq_alloc __P((void));
struct patch *patch_alloc __P((void));
void stop(const char *errstring, int err_code);
void include_file(char *file_name, include_type type);
struct instruction *seq_alloc(void);
struct scope *scope_alloc(void);
void process_scope(struct scope *);

View File

@ -2,7 +2,7 @@
/*
* Parser for the Aic7xxx SCSI Host adapter sequencer assembler.
*
* Copyright (c) 1997 Justin T. Gibbs.
* Copyright (c) 1997-1998 Justin T. Gibbs.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -11,10 +11,7 @@
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer,
* without modification, immediately at the beginning of the file.
* 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
* 2. 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
@ -29,7 +26,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: aicasm_gram.y,v 1.3 1997/09/03 03:44:40 gibbs Exp $
* $Id: aicasm_gram.y,v 1.4 1997/09/27 19:37:28 gibbs Exp $
*/
#include <stdio.h>
@ -56,7 +53,6 @@ static symbol_ref_t sindex;
static int instruction_ptr;
static int sram_or_scb_offset;
static int download_constant_count;
static patch_t *cur_patch;
static void process_bitmask __P((int mask_type, symbol_t *sym, int mask));
static void initialize_symbol __P((symbol_t *symbol));
@ -118,11 +114,13 @@ static int is_download_const __P((expression_t *immed));
%token <str> T_PATH
%token <sym> T_CEXPR
%token T_EOF T_INCLUDE
%token <value> T_SHR T_SHL T_ROR T_ROL
%token <value> T_MVI T_MOV T_CLR
%token <value> T_MVI T_MOV T_CLR T_BMOV
%token <value> T_JMP T_JC T_JNC T_JE T_JNE T_JNZ T_JZ T_CALL
@ -150,7 +148,7 @@ static int is_download_const __P((expression_t *immed));
%token T_NL
%token T_IF T_ELSE T_ENDIF
%token T_IF T_ELSE T_ELSE_IF T_ENDIF
%type <sym_ref> reg_symbol address destination source opt_source
@ -670,64 +668,89 @@ address:
;
conditional:
T_IF
T_IF T_CEXPR '{'
{
if (cur_patch != NULL) {
stop("Nested .if directive", EX_DATAERR);
scope_t *new_scope;
add_conditional($2);
new_scope = scope_alloc();
new_scope->type = SCOPE_IF;
new_scope->begin_addr = instruction_ptr;
new_scope->func_num = $2->info.condinfo->func_num;
}
| T_ELSE T_IF T_CEXPR '{'
{
scope_t *new_scope;
scope_t *scope_context;
scope_t *last_scope;
/*
* Ensure that the previous scope is either an
* if or and else if.
*/
scope_context = SLIST_FIRST(&scope_stack);
last_scope = TAILQ_LAST(&scope_context->inner_scope,
scope_tailq);
if (last_scope == NULL
|| last_scope->type == T_ELSE) {
stop("'else if' without leading 'if'", EX_DATAERR);
/* NOTREACHED */
}
cur_patch = patch_alloc();
cur_patch->begin = instruction_ptr;
}
option_list
;
conditional:
T_ELSE
{
patch_t *next_patch;
if (cur_patch == NULL) {
stop(".else outsize of .if", EX_DATAERR);
/* NOTREACHED */
}
cur_patch->end = instruction_ptr;
next_patch = patch_alloc();
next_patch->options = cur_patch->options;
next_patch->negative = cur_patch->negative ? FALSE : TRUE;
cur_patch = next_patch;
cur_patch->begin = instruction_ptr;
}
;
conditional:
T_ENDIF
{
if (cur_patch == NULL) {
stop(".endif outsize of .if", EX_DATAERR);
/* NOTREACHED */
}
cur_patch->end = instruction_ptr;
cur_patch = NULL;
}
;
option_list:
'(' option_symbol_list ')'
| '!' option_list
{
cur_patch->negative = cur_patch->negative ? FALSE : TRUE;
}
;
option_symbol_list:
T_SYMBOL
{
add_conditional($1);
}
| option_list '|' T_SYMBOL
{
add_conditional($3);
new_scope = scope_alloc();
new_scope->type = SCOPE_ELSE_IF;
new_scope->begin_addr = instruction_ptr;
new_scope->func_num = $3->info.condinfo->func_num;
}
| T_ELSE '{'
{
scope_t *new_scope;
scope_t *scope_context;
scope_t *last_scope;
/*
* Ensure that the previous scope is either an
* if or and else if.
*/
scope_context = SLIST_FIRST(&scope_stack);
last_scope = TAILQ_LAST(&scope_context->inner_scope,
scope_tailq);
if (last_scope == NULL
|| last_scope->type == SCOPE_ELSE) {
stop("'else' without leading 'if'", EX_DATAERR);
/* NOTREACHED */
}
new_scope = scope_alloc();
new_scope->type = SCOPE_ELSE;
new_scope->begin_addr = instruction_ptr;
}
;
conditional:
'}'
{
scope_t *scope_context;
scope_t *last_scope;
scope_context = SLIST_FIRST(&scope_stack);
if (scope_context->type == SCOPE_ROOT) {
stop("Unexpected '}' encountered", EX_DATAERR);
/* NOTREACHED */
}
scope_context->end_addr = instruction_ptr;
/* Pop the scope */
SLIST_REMOVE_HEAD(&scope_stack, scope_stack_links);
process_scope(scope_context);
if (SLIST_FIRST(&scope_stack) == NULL) {
stop("Unexpected '}' encountered", EX_DATAERR);
/* NOTREACHED */
}
}
;
@ -803,6 +826,13 @@ code:
}
;
code:
T_BMOV destination ',' source ',' immediate ret ';'
{
format_1_instr(AIC_OP_BMOV, &$2, &$6, &$4, $7);
}
;
code:
T_MOV destination ',' source ret ';'
{
@ -1118,7 +1148,8 @@ format_1_instr(opcode, dest, immed, src, ret)
/* Allocate sequencer space for the instruction and fill it out */
instr = seq_alloc();
f1_instr = &instr->format.format1;
f1_instr->opcode_ret = (opcode << 1) | (ret ? RETURN_BIT : 0);
f1_instr->ret = ret ? 1 : 0;
f1_instr->opcode = opcode;
f1_instr->destination = dest->symbol->info.rinfo->address
+ dest->offset;
f1_instr->source = src->symbol->info.rinfo->address
@ -1126,7 +1157,7 @@ format_1_instr(opcode, dest, immed, src, ret)
f1_instr->immediate = immed->value;
if (is_download_const(immed))
f1_instr->opcode_ret |= DOWNLOAD_CONST_IMMEDIATE;
f1_instr->parity = 1;
symlist_free(&immed->referenced_syms);
instruction_ptr++;
@ -1154,7 +1185,8 @@ format_2_instr(opcode, dest, places, src, ret)
/* Allocate sequencer space for the instruction and fill it out */
instr = seq_alloc();
f2_instr = &instr->format.format2;
f2_instr->opcode_ret = (AIC_OP_ROL << 1) | (ret ? RETURN_BIT : 0);
f2_instr->ret = ret ? 1 : 0;
f2_instr->opcode = AIC_OP_ROL;
f2_instr->destination = dest->symbol->info.rinfo->address
+ dest->offset;
f2_instr->source = src->symbol->info.rinfo->address
@ -1225,15 +1257,14 @@ format_3_instr(opcode, src, immed, address)
instr->patch_label = address->symbol;
} else
addr = address->symbol->info.linfo->address + address->offset;
f3_instr->opcode_addr = (opcode << 1)
| ((addr >> 8) & 0x01);
f3_instr->address = addr & 0xff;
f3_instr->opcode = opcode;
f3_instr->address = addr;
f3_instr->source = src->symbol->info.rinfo->address
+ src->offset;
f3_instr->immediate = immed->value;
if (is_download_const(immed))
f3_instr->opcode_addr |= DOWNLOAD_CONST_IMMEDIATE;
f3_instr->parity = 1;
symlist_free(&immed->referenced_syms);
instruction_ptr++;
@ -1326,19 +1357,38 @@ static void
add_conditional(symbol)
symbol_t *symbol;
{
static int numoptions = 1;
static int numfuncs;
if (symbol->type == UNINITIALIZED) {
symbol->type = CONDITIONAL;
initialize_symbol(symbol);
symbol->info.condinfo->value = 0x01 << numoptions++;
symlist_add(&patch_options, symbol, SYMLIST_INSERT_HEAD);
} else if (symbol->type != CONDITIONAL) {
stop("Conditional symbol mirrors other symbol",
if (numfuncs == 0) {
/* add a special conditional, "0" */
symbol_t *false_func;
false_func = symtable_get("0");
if (false_func->type != UNINITIALIZED) {
stop("Conditional expression '0' "
"conflicts with a symbol", EX_DATAERR);
/* NOTREACHED */
}
false_func->type = CONDITIONAL;
initialize_symbol(false_func);
false_func->info.condinfo->func_num = numfuncs++;
symlist_add(&patch_functions, false_func, SYMLIST_INSERT_HEAD);
}
/* This condition has occurred before */
if (symbol->type == CONDITIONAL)
return;
if (symbol->type != UNINITIALIZED) {
stop("Conditional expression conflicts with a symbol",
EX_DATAERR);
/* NOTREACHED */
}
cur_patch->options |= symbol->info.condinfo->value;
symbol->type = CONDITIONAL;
initialize_symbol(symbol);
symbol->info.condinfo->func_num = numfuncs++;
symlist_add(&patch_functions, symbol, SYMLIST_INSERT_HEAD);
}
void

View File

@ -2,7 +2,7 @@
/*
* Lexical Analyzer for the Aic7xxx SCSI Host adapter sequencer assembler.
*
* Copyright (c) 1997 Justin T. Gibbs.
* Copyright (c) 1997-1998 Justin T. Gibbs.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -11,10 +11,7 @@
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer,
* without modification, immediately at the beginning of the file.
* 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
* 2. 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
@ -29,7 +26,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: aicasm_scan.l,v 1.4 1997/09/03 03:44:42 gibbs Exp $
* $Id: aicasm_scan.l,v 1.5 1997/09/27 19:37:29 gibbs Exp $
*/
#include <sys/types.h>
@ -43,6 +40,11 @@
#include "aicasm.h"
#include "aicasm_symbol.h"
#include "y.tab.h"
#define MAX_STR_CONST 256
char string_buf[MAX_STR_CONST];
char *string_buf_ptr;
int parren_count;
%}
PATH [-/A-Za-z0-9_.]*[./][-/A-Za-z0-9_.]*
@ -50,6 +52,8 @@ WORD [A-Za-z_][-A-Za-z_0-9]*
SPACE [ \t]+
%x COMMENT
%x CEXPR
%x INCLUDE
%%
\n { ++yylineno; }
@ -60,6 +64,32 @@ SPACE [ \t]+
<COMMENT>"*"+[^*/\n]* ;
<COMMENT>"/"+[^*/\n]* ;
<COMMENT>"*"+"/" { BEGIN INITIAL; }
if[ \t]*\( {
string_buf_ptr = string_buf;
parren_count = 1;
BEGIN CEXPR;
return T_IF;
}
<CEXPR>\( { *string_buf_ptr++ = '('; parren_count++; }
<CEXPR>\) {
parren_count--;
if (parren_count == 0) {
/* All done */
BEGIN INITIAL;
*string_buf_ptr = '\0';
yylval.sym = symtable_get(string_buf);
return T_CEXPR;
} else {
*string_buf_ptr++ = ')';
}
}
<CEXPR>\n { ++yylineno; }
<CEXPR>[^()\n]+ {
char *yptr = yytext;
while (*yptr != '\0')
*string_buf_ptr++ = *yptr++;
}
{SPACE} ;
@ -109,6 +139,7 @@ jnz { return T_JNZ; }
call { return T_CALL; }
add { return T_ADD; }
adc { return T_ADC; }
bmov { return T_BMOV; }
inc { return T_INC; }
dec { return T_DEC; }
stc { return T_STC; }
@ -120,12 +151,10 @@ and { return T_AND; }
or { return T_OR; }
ret { return T_RET; }
nop { return T_NOP; }
.if { return T_IF; }
.else { return T_ELSE; }
.endif { return T_ENDIF; }
else { return T_ELSE; }
/* Allowed Symbols */
[-+,:()~|&."{};<>[\]!] { return yytext[0]; }
[-+,:()~|&."{};<>[\]!] { return yytext[0]; }
/* Number processing */
0[0-7]* {
@ -144,7 +173,11 @@ nop { return T_NOP; }
}
/* Include Files */
#include { return T_INCLUDE; }
#include { return T_INCLUDE; BEGIN INCLUDE;}
<INCLUDE>[<>\"] { return yytext[0]; }
<INCLUDE>{PATH} { yylval.str = strdup(yytext); return T_PATH; }
<INCLUDE>; { BEGIN INITIAL; return yytext[0]; }
<INCLUDE>. { stop("Invalid include line", EX_DATAERR); }
/* For parsing C include files with #define foo */
#define { yylval.value = TRUE; return T_CONST; }

View File

@ -10,10 +10,7 @@
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer,
* without modification, immediately at the beginning of the file.
* 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
* 2. 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
@ -28,7 +25,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: aicasm_symbol.c,v 1.3 1997/09/03 03:44:44 gibbs Exp $
* $Id: aicasm_symbol.c,v 1.4 1997/09/27 19:37:30 gibbs Exp $
*/

View File

@ -10,10 +10,7 @@
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer,
* without modification, immediately at the beginning of the file.
* 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
* 2. 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
@ -28,7 +25,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: aicasm_symbol.h,v 1.2 1997/06/27 19:38:56 gibbs Exp $
* $Id: aicasm_symbol.h,v 1.3 1997/09/27 19:37:30 gibbs Exp $
*/
#include <sys/queue.h>
@ -82,7 +79,7 @@ struct label_info {
};
struct cond_info {
int value;
int func_num;
};
typedef struct expression_info {
@ -113,13 +110,32 @@ typedef struct symbol_node {
symbol_t *symbol;
}symbol_node_t;
typedef struct patch {
STAILQ_ENTRY(patch) links;
int negative;
int begin;
int end;
int options;
} patch_t;
typedef enum {
SCOPE_ROOT,
SCOPE_IF,
SCOPE_ELSE_IF,
SCOPE_ELSE
} scope_type;
typedef struct patch_info {
int skip_patch;
int skip_instr;
} patch_info_t;
typedef struct scope {
SLIST_ENTRY(scope) scope_stack_links;
TAILQ_ENTRY(scope) scope_links;
TAILQ_HEAD(, scope) inner_scope;
scope_type type;
int inner_scope_patches;
int begin_addr;
int end_addr;
patch_info_t patches[2];
int func_num;
} scope_t;
SLIST_HEAD(scope_list, scope);
TAILQ_HEAD(scope_tailq, scope);
void symbol_delete __P((symbol_t *symbol));

View File

@ -2,7 +2,7 @@
/*
* Parser for the Aic7xxx SCSI Host adapter sequencer assembler.
*
* Copyright (c) 1997 Justin T. Gibbs.
* Copyright (c) 1997-1998 Justin T. Gibbs.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -11,10 +11,7 @@
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer,
* without modification, immediately at the beginning of the file.
* 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
* 2. 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
@ -29,7 +26,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: aicasm_gram.y,v 1.3 1997/09/03 03:44:40 gibbs Exp $
* $Id: aicasm_gram.y,v 1.4 1997/09/27 19:37:28 gibbs Exp $
*/
#include <stdio.h>
@ -56,7 +53,6 @@ static symbol_ref_t sindex;
static int instruction_ptr;
static int sram_or_scb_offset;
static int download_constant_count;
static patch_t *cur_patch;
static void process_bitmask __P((int mask_type, symbol_t *sym, int mask));
static void initialize_symbol __P((symbol_t *symbol));
@ -118,11 +114,13 @@ static int is_download_const __P((expression_t *immed));
%token <str> T_PATH
%token <sym> T_CEXPR
%token T_EOF T_INCLUDE
%token <value> T_SHR T_SHL T_ROR T_ROL
%token <value> T_MVI T_MOV T_CLR
%token <value> T_MVI T_MOV T_CLR T_BMOV
%token <value> T_JMP T_JC T_JNC T_JE T_JNE T_JNZ T_JZ T_CALL
@ -150,7 +148,7 @@ static int is_download_const __P((expression_t *immed));
%token T_NL
%token T_IF T_ELSE T_ENDIF
%token T_IF T_ELSE T_ELSE_IF T_ENDIF
%type <sym_ref> reg_symbol address destination source opt_source
@ -670,64 +668,89 @@ address:
;
conditional:
T_IF
T_IF T_CEXPR '{'
{
if (cur_patch != NULL) {
stop("Nested .if directive", EX_DATAERR);
scope_t *new_scope;
add_conditional($2);
new_scope = scope_alloc();
new_scope->type = SCOPE_IF;
new_scope->begin_addr = instruction_ptr;
new_scope->func_num = $2->info.condinfo->func_num;
}
| T_ELSE T_IF T_CEXPR '{'
{
scope_t *new_scope;
scope_t *scope_context;
scope_t *last_scope;
/*
* Ensure that the previous scope is either an
* if or and else if.
*/
scope_context = SLIST_FIRST(&scope_stack);
last_scope = TAILQ_LAST(&scope_context->inner_scope,
scope_tailq);
if (last_scope == NULL
|| last_scope->type == T_ELSE) {
stop("'else if' without leading 'if'", EX_DATAERR);
/* NOTREACHED */
}
cur_patch = patch_alloc();
cur_patch->begin = instruction_ptr;
}
option_list
;
conditional:
T_ELSE
{
patch_t *next_patch;
if (cur_patch == NULL) {
stop(".else outsize of .if", EX_DATAERR);
/* NOTREACHED */
}
cur_patch->end = instruction_ptr;
next_patch = patch_alloc();
next_patch->options = cur_patch->options;
next_patch->negative = cur_patch->negative ? FALSE : TRUE;
cur_patch = next_patch;
cur_patch->begin = instruction_ptr;
}
;
conditional:
T_ENDIF
{
if (cur_patch == NULL) {
stop(".endif outsize of .if", EX_DATAERR);
/* NOTREACHED */
}
cur_patch->end = instruction_ptr;
cur_patch = NULL;
}
;
option_list:
'(' option_symbol_list ')'
| '!' option_list
{
cur_patch->negative = cur_patch->negative ? FALSE : TRUE;
}
;
option_symbol_list:
T_SYMBOL
{
add_conditional($1);
}
| option_list '|' T_SYMBOL
{
add_conditional($3);
new_scope = scope_alloc();
new_scope->type = SCOPE_ELSE_IF;
new_scope->begin_addr = instruction_ptr;
new_scope->func_num = $3->info.condinfo->func_num;
}
| T_ELSE '{'
{
scope_t *new_scope;
scope_t *scope_context;
scope_t *last_scope;
/*
* Ensure that the previous scope is either an
* if or and else if.
*/
scope_context = SLIST_FIRST(&scope_stack);
last_scope = TAILQ_LAST(&scope_context->inner_scope,
scope_tailq);
if (last_scope == NULL
|| last_scope->type == SCOPE_ELSE) {
stop("'else' without leading 'if'", EX_DATAERR);
/* NOTREACHED */
}
new_scope = scope_alloc();
new_scope->type = SCOPE_ELSE;
new_scope->begin_addr = instruction_ptr;
}
;
conditional:
'}'
{
scope_t *scope_context;
scope_t *last_scope;
scope_context = SLIST_FIRST(&scope_stack);
if (scope_context->type == SCOPE_ROOT) {
stop("Unexpected '}' encountered", EX_DATAERR);
/* NOTREACHED */
}
scope_context->end_addr = instruction_ptr;
/* Pop the scope */
SLIST_REMOVE_HEAD(&scope_stack, scope_stack_links);
process_scope(scope_context);
if (SLIST_FIRST(&scope_stack) == NULL) {
stop("Unexpected '}' encountered", EX_DATAERR);
/* NOTREACHED */
}
}
;
@ -803,6 +826,13 @@ code:
}
;
code:
T_BMOV destination ',' source ',' immediate ret ';'
{
format_1_instr(AIC_OP_BMOV, &$2, &$6, &$4, $7);
}
;
code:
T_MOV destination ',' source ret ';'
{
@ -1118,7 +1148,8 @@ format_1_instr(opcode, dest, immed, src, ret)
/* Allocate sequencer space for the instruction and fill it out */
instr = seq_alloc();
f1_instr = &instr->format.format1;
f1_instr->opcode_ret = (opcode << 1) | (ret ? RETURN_BIT : 0);
f1_instr->ret = ret ? 1 : 0;
f1_instr->opcode = opcode;
f1_instr->destination = dest->symbol->info.rinfo->address
+ dest->offset;
f1_instr->source = src->symbol->info.rinfo->address
@ -1126,7 +1157,7 @@ format_1_instr(opcode, dest, immed, src, ret)
f1_instr->immediate = immed->value;
if (is_download_const(immed))
f1_instr->opcode_ret |= DOWNLOAD_CONST_IMMEDIATE;
f1_instr->parity = 1;
symlist_free(&immed->referenced_syms);
instruction_ptr++;
@ -1154,7 +1185,8 @@ format_2_instr(opcode, dest, places, src, ret)
/* Allocate sequencer space for the instruction and fill it out */
instr = seq_alloc();
f2_instr = &instr->format.format2;
f2_instr->opcode_ret = (AIC_OP_ROL << 1) | (ret ? RETURN_BIT : 0);
f2_instr->ret = ret ? 1 : 0;
f2_instr->opcode = AIC_OP_ROL;
f2_instr->destination = dest->symbol->info.rinfo->address
+ dest->offset;
f2_instr->source = src->symbol->info.rinfo->address
@ -1225,15 +1257,14 @@ format_3_instr(opcode, src, immed, address)
instr->patch_label = address->symbol;
} else
addr = address->symbol->info.linfo->address + address->offset;
f3_instr->opcode_addr = (opcode << 1)
| ((addr >> 8) & 0x01);
f3_instr->address = addr & 0xff;
f3_instr->opcode = opcode;
f3_instr->address = addr;
f3_instr->source = src->symbol->info.rinfo->address
+ src->offset;
f3_instr->immediate = immed->value;
if (is_download_const(immed))
f3_instr->opcode_addr |= DOWNLOAD_CONST_IMMEDIATE;
f3_instr->parity = 1;
symlist_free(&immed->referenced_syms);
instruction_ptr++;
@ -1326,19 +1357,38 @@ static void
add_conditional(symbol)
symbol_t *symbol;
{
static int numoptions = 1;
static int numfuncs;
if (symbol->type == UNINITIALIZED) {
symbol->type = CONDITIONAL;
initialize_symbol(symbol);
symbol->info.condinfo->value = 0x01 << numoptions++;
symlist_add(&patch_options, symbol, SYMLIST_INSERT_HEAD);
} else if (symbol->type != CONDITIONAL) {
stop("Conditional symbol mirrors other symbol",
if (numfuncs == 0) {
/* add a special conditional, "0" */
symbol_t *false_func;
false_func = symtable_get("0");
if (false_func->type != UNINITIALIZED) {
stop("Conditional expression '0' "
"conflicts with a symbol", EX_DATAERR);
/* NOTREACHED */
}
false_func->type = CONDITIONAL;
initialize_symbol(false_func);
false_func->info.condinfo->func_num = numfuncs++;
symlist_add(&patch_functions, false_func, SYMLIST_INSERT_HEAD);
}
/* This condition has occurred before */
if (symbol->type == CONDITIONAL)
return;
if (symbol->type != UNINITIALIZED) {
stop("Conditional expression conflicts with a symbol",
EX_DATAERR);
/* NOTREACHED */
}
cur_patch->options |= symbol->info.condinfo->value;
symbol->type = CONDITIONAL;
initialize_symbol(symbol);
symbol->info.condinfo->func_num = numfuncs++;
symlist_add(&patch_functions, symbol, SYMLIST_INSERT_HEAD);
}
void

View File

@ -2,7 +2,7 @@
/*
* Lexical Analyzer for the Aic7xxx SCSI Host adapter sequencer assembler.
*
* Copyright (c) 1997 Justin T. Gibbs.
* Copyright (c) 1997-1998 Justin T. Gibbs.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -11,10 +11,7 @@
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer,
* without modification, immediately at the beginning of the file.
* 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
* 2. 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
@ -29,7 +26,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: aicasm_scan.l,v 1.4 1997/09/03 03:44:42 gibbs Exp $
* $Id: aicasm_scan.l,v 1.5 1997/09/27 19:37:29 gibbs Exp $
*/
#include <sys/types.h>
@ -43,6 +40,11 @@
#include "aicasm.h"
#include "aicasm_symbol.h"
#include "y.tab.h"
#define MAX_STR_CONST 256
char string_buf[MAX_STR_CONST];
char *string_buf_ptr;
int parren_count;
%}
PATH [-/A-Za-z0-9_.]*[./][-/A-Za-z0-9_.]*
@ -50,6 +52,8 @@ WORD [A-Za-z_][-A-Za-z_0-9]*
SPACE [ \t]+
%x COMMENT
%x CEXPR
%x INCLUDE
%%
\n { ++yylineno; }
@ -60,6 +64,32 @@ SPACE [ \t]+
<COMMENT>"*"+[^*/\n]* ;
<COMMENT>"/"+[^*/\n]* ;
<COMMENT>"*"+"/" { BEGIN INITIAL; }
if[ \t]*\( {
string_buf_ptr = string_buf;
parren_count = 1;
BEGIN CEXPR;
return T_IF;
}
<CEXPR>\( { *string_buf_ptr++ = '('; parren_count++; }
<CEXPR>\) {
parren_count--;
if (parren_count == 0) {
/* All done */
BEGIN INITIAL;
*string_buf_ptr = '\0';
yylval.sym = symtable_get(string_buf);
return T_CEXPR;
} else {
*string_buf_ptr++ = ')';
}
}
<CEXPR>\n { ++yylineno; }
<CEXPR>[^()\n]+ {
char *yptr = yytext;
while (*yptr != '\0')
*string_buf_ptr++ = *yptr++;
}
{SPACE} ;
@ -109,6 +139,7 @@ jnz { return T_JNZ; }
call { return T_CALL; }
add { return T_ADD; }
adc { return T_ADC; }
bmov { return T_BMOV; }
inc { return T_INC; }
dec { return T_DEC; }
stc { return T_STC; }
@ -120,12 +151,10 @@ and { return T_AND; }
or { return T_OR; }
ret { return T_RET; }
nop { return T_NOP; }
.if { return T_IF; }
.else { return T_ELSE; }
.endif { return T_ENDIF; }
else { return T_ELSE; }
/* Allowed Symbols */
[-+,:()~|&."{};<>[\]!] { return yytext[0]; }
[-+,:()~|&."{};<>[\]!] { return yytext[0]; }
/* Number processing */
0[0-7]* {
@ -144,7 +173,11 @@ nop { return T_NOP; }
}
/* Include Files */
#include { return T_INCLUDE; }
#include { return T_INCLUDE; BEGIN INCLUDE;}
<INCLUDE>[<>\"] { return yytext[0]; }
<INCLUDE>{PATH} { yylval.str = strdup(yytext); return T_PATH; }
<INCLUDE>; { BEGIN INITIAL; return yytext[0]; }
<INCLUDE>. { stop("Invalid include line", EX_DATAERR); }
/* For parsing C include files with #define foo */
#define { yylval.value = TRUE; return T_CONST; }

View File

@ -10,10 +10,7 @@
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer,
* without modification, immediately at the beginning of the file.
* 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
* 2. 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
@ -28,7 +25,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: aicasm_symbol.c,v 1.3 1997/09/03 03:44:44 gibbs Exp $
* $Id: aicasm_symbol.c,v 1.4 1997/09/27 19:37:30 gibbs Exp $
*/

View File

@ -10,10 +10,7 @@
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer,
* without modification, immediately at the beginning of the file.
* 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
* 2. 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
@ -28,7 +25,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: aicasm_symbol.h,v 1.2 1997/06/27 19:38:56 gibbs Exp $
* $Id: aicasm_symbol.h,v 1.3 1997/09/27 19:37:30 gibbs Exp $
*/
#include <sys/queue.h>
@ -82,7 +79,7 @@ struct label_info {
};
struct cond_info {
int value;
int func_num;
};
typedef struct expression_info {
@ -113,13 +110,32 @@ typedef struct symbol_node {
symbol_t *symbol;
}symbol_node_t;
typedef struct patch {
STAILQ_ENTRY(patch) links;
int negative;
int begin;
int end;
int options;
} patch_t;
typedef enum {
SCOPE_ROOT,
SCOPE_IF,
SCOPE_ELSE_IF,
SCOPE_ELSE
} scope_type;
typedef struct patch_info {
int skip_patch;
int skip_instr;
} patch_info_t;
typedef struct scope {
SLIST_ENTRY(scope) scope_stack_links;
TAILQ_ENTRY(scope) scope_links;
TAILQ_HEAD(, scope) inner_scope;
scope_type type;
int inner_scope_patches;
int begin_addr;
int end_addr;
patch_info_t patches[2];
int func_num;
} scope_t;
SLIST_HEAD(scope_list, scope);
TAILQ_HEAD(scope_tailq, scope);
void symbol_delete __P((symbol_t *symbol));

View File

@ -2,7 +2,7 @@
* Instruction formats for the sequencer program downloaded to
* Aic7xxx SCSI host adapters
*
* Copyright (c) 1997 Justin T. Gibbs.
* Copyright (c) 1997, 1998 Justin T. Gibbs.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -11,10 +11,7 @@
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer,
* without modification, immediately at the beginning of the file.
* 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
* 2. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* Where this Software is combined with software released under the terms of
@ -36,40 +33,44 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: sequencer.h,v 1.2 1997/06/27 19:38:52 gibbs Exp $
* $Id: sequencer.h,v 1.3 1997/09/27 19:37:31 gibbs Exp $
*/
struct ins_format1 {
u_int8_t immediate;
u_int8_t source;
u_int8_t destination;
u_int8_t opcode_ret;
#define DOWNLOAD_CONST_IMMEDIATE 0x80
u_int32_t immediate : 8,
source : 9,
destination : 9,
ret : 1,
opcode : 4,
parity : 1;
};
struct ins_format2 {
u_int8_t shift_control;
u_int8_t source;
u_int8_t destination;
u_int8_t opcode_ret;
#define RETURN_BIT 0x01
u_int32_t shift_control : 8,
source : 9,
destination : 9,
ret : 1,
opcode : 4,
parity : 1;
};
struct ins_format3 {
u_int8_t immediate;
u_int8_t source;
u_int8_t address;
u_int8_t opcode_addr;
#define ADDR_HIGH_BIT 0x01
u_int32_t immediate : 8,
source : 9,
address : 10,
opcode : 4,
parity : 1;
};
struct instruction {
union {
union ins_formats {
struct ins_format1 format1;
struct ins_format2 format2;
struct ins_format3 format3;
u_int8_t bytes[4];
} format;
u_int32_t integer;
};
struct instruction {
union ins_formats format;
u_int srcline;
struct symbol *patch_label;
STAILQ_ENTRY(instruction) links;
@ -81,6 +82,7 @@ struct instruction {
#define AIC_OP_ADD 0x3
#define AIC_OP_ADC 0x4
#define AIC_OP_ROL 0x5
#define AIC_OP_BMOV 0x6
#define AIC_OP_JMP 0x8
#define AIC_OP_JC 0x9