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:
parent
44de612bd0
commit
3bafc9d432
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=39220
174
sys/dev/aic7xxx/93cx6.c
Normal file
174
sys/dev/aic7xxx/93cx6.c
Normal 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
95
sys/dev/aic7xxx/93cx6.h
Normal 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
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
524
sys/dev/aic7xxx/aic7xxx.h
Normal 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_ */
|
@ -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
174
sys/dev/aic7xxx/aic7xxx_93cx6.c
Normal file
174
sys/dev/aic7xxx/aic7xxx_93cx6.c
Normal 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/aic7xxx_93cx6.h
Normal file
95
sys/dev/aic7xxx/aic7xxx_93cx6.h
Normal 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 */
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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 *);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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 *);
|
||||
|
@ -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
|
||||
|
@ -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; }
|
||||
|
@ -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 $
|
||||
*/
|
||||
|
||||
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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
|
||||
|
@ -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; }
|
||||
|
@ -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 $
|
||||
*/
|
||||
|
||||
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user