aboutsummaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorJustin T. Gibbs <gibbs@FreeBSD.org>1997-03-16 07:08:19 +0000
committerJustin T. Gibbs <gibbs@FreeBSD.org>1997-03-16 07:08:19 +0000
commitc5cb388883ad364ee874fb9f5e3aac73e48548af (patch)
treed5a340e22c305efbee883e4b96d2a386052b5a59 /sys/dev
parent2edd1d66963095763c3acd1ca9f4c3c7d16dffd3 (diff)
Notes
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/aic7xxx/Makefile18
-rw-r--r--sys/dev/aic7xxx/aic7xxx.reg1112
-rw-r--r--sys/dev/aic7xxx/aic7xxx.seq1047
-rw-r--r--sys/dev/aic7xxx/aic7xxx_asm.170
-rw-r--r--sys/dev/aic7xxx/aic7xxx_asm.c918
-rw-r--r--sys/dev/aic7xxx/aic7xxx_reg.h801
-rw-r--r--sys/dev/aic7xxx/aicasm.c918
-rw-r--r--sys/dev/aic7xxx/aicasm/Makefile18
-rw-r--r--sys/dev/aic7xxx/aicasm/aicasm.c918
-rw-r--r--sys/dev/aic7xxx/aicasm/aicasm_gram.y1304
-rw-r--r--sys/dev/aic7xxx/aicasm/aicasm_scan.l242
-rw-r--r--sys/dev/aic7xxx/aicasm/aicasm_symbol.c451
-rw-r--r--sys/dev/aic7xxx/aicasm/aicasm_symbol.h144
-rw-r--r--sys/dev/aic7xxx/aicasm_gram.y1304
-rw-r--r--sys/dev/aic7xxx/aicasm_scan.l242
-rw-r--r--sys/dev/aic7xxx/aicasm_symbol.c451
-rw-r--r--sys/dev/aic7xxx/aicasm_symbol.h144
-rw-r--r--sys/dev/aic7xxx/gram.y1304
-rw-r--r--sys/dev/aic7xxx/scan.l242
-rw-r--r--sys/dev/aic7xxx/sequencer.h89
-rw-r--r--sys/dev/aic7xxx/symbol.c451
-rw-r--r--sys/dev/aic7xxx/symbol.h144
22 files changed, 9139 insertions, 3193 deletions
diff --git a/sys/dev/aic7xxx/Makefile b/sys/dev/aic7xxx/Makefile
new file mode 100644
index 0000000000000..2a142b0a58852
--- /dev/null
+++ b/sys/dev/aic7xxx/Makefile
@@ -0,0 +1,18 @@
+# $Id$
+
+PROG= aic7xxx_asm
+
+CSRCS= aic7xxx_asm.c symbol.c
+GENSRCS= gram.c scan.c
+
+GENHDRS= y.tab.h token.h
+# Hack so non root users you can build kernels
+BINOWN!= id -u -n
+BINGRP!= id -g -n
+
+SRCS= ${GENSRCS} ${CSRCS}
+CLEANFILES+= ${GENSRCS} ${GENHDRS} y.output
+DPADD+= ${LIBL}
+LDADD+= -ll
+NOMAN= noman
+.include <bsd.prog.mk>
diff --git a/sys/dev/aic7xxx/aic7xxx.reg b/sys/dev/aic7xxx/aic7xxx.reg
new file mode 100644
index 0000000000000..d021d9a6f63d0
--- /dev/null
+++ b/sys/dev/aic7xxx/aic7xxx.reg
@@ -0,0 +1,1112 @@
+/*
+ * Aic7xxx register and scratch ram definitions.
+ *
+ * Copyright (c) 1994, 1995, 1996, 1997 Justin T. Gibbs.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * this list of conditions, and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+/*
+ * This file is processed by the aic7xxx_asm utility for use in assembling
+ * firmware for the aic7xxx family of SCSI host adapters as well as to generate
+ * a C header file for use in the kernel portion of the Aic7xxx driver.
+ *
+ * All page numbers refer to the Adaptec AIC-7770 Data Book available from
+ * Adaptec's Technical Documents Department 1-800-934-2766
+ */
+
+/*
+ * SCSI Sequence Control (p. 3-11).
+ * Each bit, when set starts a specific SCSI sequence on the bus
+ */
+register SCSISEQ {
+ address 0x000
+ access_mode RW
+ bit TEMODE 0x80
+ bit ENSELO 0x40
+ bit ENSELI 0x20
+ bit ENRSELI 0x10
+ bit ENAUTOATNO 0x08
+ bit ENAUTOATNI 0x04
+ bit ENAUTOATNP 0x02
+ bit SCSIRSTO 0x01
+}
+
+/*
+ * SCSI Transfer Control 0 Register (pp. 3-13).
+ * Controls the SCSI module data path.
+ */
+register SXFRCTL0 {
+ address 0x001
+ access_mode RW
+ bit DFON 0x80
+ bit DFPEXP 0x40
+ bit FAST20 0x20
+ bit CLRSTCNT 0x10
+ bit SPIOEN 0x08
+ bit SCAMEN 0x04
+ bit CLRCHN 0x02
+}
+
+/*
+ * SCSI Transfer Control 1 Register (pp. 3-14,15).
+ * Controls the SCSI module data path.
+ */
+register SXFRCTL1 {
+ address 0x002
+ access_mode RW
+ bit BITBUCKET 0x80
+ bit SWRAPEN 0x40
+ bit ENSPCHK 0x20
+ mask STIMESEL 0x18
+ bit ENSTIMER 0x04
+ bit ACTNEGEN 0x02
+ bit STPWEN 0x01 /* Powered Termination */
+}
+
+/*
+ * SCSI Control Signal Read Register (p. 3-15).
+ * Reads the actual state of the SCSI bus pins
+ */
+register SCSISIGI {
+ address 0x003
+ access_mode RO
+ bit CDI 0x80
+ bit IOI 0x40
+ bit MSGI 0x20
+ bit ATNI 0x10
+ bit SELI 0x08
+ bit BSYI 0x04
+ bit REQI 0x02
+ bit ACKI 0x01
+/*
+ * Possible phases in SCSISIGI
+ */
+ mask PHASE_MASK CDI|IOI|MSGI
+ mask P_DATAOUT 0x00
+ mask P_DATAIN IOI
+ mask P_COMMAND CDI
+ mask P_MESGOUT CDI|MSGI
+ mask P_STATUS CDI|IOI
+ mask P_MESGIN CDI|IOI|MSGI
+}
+
+/*
+ * SCSI Control Signal Write Register (p. 3-16).
+ * Writing to this register modifies the control signals on the bus. Only
+ * those signals that are allowed in the current mode (Initiator/Target) are
+ * asserted.
+ */
+register SCSISIGO {
+ address 0x003
+ access_mode WO
+ bit CDO 0x80
+ bit IOO 0x40
+ bit MSGO 0x20
+ bit ATNO 0x10
+ bit SELO 0x08
+ bit BSYO 0x04
+ bit REQO 0x02
+ bit ACKO 0x01
+/*
+ * Possible phases to write into SCSISIG0
+ */
+ mask PHASE_MASK CDI|IOI|MSGI
+ mask P_DATAOUT 0x00
+ mask P_DATAIN IOI
+ mask P_COMMAND CDI
+ mask P_MESGOUT CDI|MSGI
+ mask P_STATUS CDI|IOI
+ mask P_MESGIN CDI|IOI|MSGI
+}
+
+/*
+ * SCSI Rate Control (p. 3-17).
+ * Contents of this register determine the Synchronous SCSI data transfer
+ * rate and the maximum synchronous Req/Ack offset. An offset of 0 in the
+ * SOFS (3:0) bits disables synchronous data transfers. Any offset value
+ * greater than 0 enables synchronous transfers.
+ */
+register SCSIRATE {
+ address 0x004
+ access_mode RW
+ bit WIDEXFER 0x80 /* Wide transfer control */
+ mask SXFR 0x70 /* Sync transfer rate */
+ mask SOFS 0x0f /* Sync offset */
+}
+
+/*
+ * SCSI ID (p. 3-18).
+ * Contains the ID of the board and the current target on the
+ * selected channel.
+ */
+register SCSIID {
+ address 0x005
+ access_mode RW
+ mask TID 0xf0 /* Target ID mask */
+ mask OID 0x0f /* Our ID mask */
+}
+
+/*
+ * SCSI Latched Data (p. 3-19).
+ * Read/Write latches used to transfer data on the SCSI bus during
+ * Automatic or Manual PIO mode. SCSIDATH can be used for the
+ * upper byte of a 16bit wide asynchronouse data phase transfer.
+ */
+register SCSIDATL {
+ address 0x006
+ access_mode RW
+}
+
+register SCSIDATH {
+ address 0x007
+ access_mode RW
+}
+
+/*
+ * SCSI Transfer Count (pp. 3-19,20)
+ * These registers count down the number of bytes transferred
+ * across the SCSI bus. The counter is decremented only once
+ * the data has been safely transferred. SDONE in SSTAT0 is
+ * set when STCNT goes to 0
+ */
+register STCNT {
+ address 0x008
+ size 3
+ access_mode RW
+}
+
+/*
+ * Clear SCSI Interrupt 0 (p. 3-20)
+ * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT0.
+ */
+register CLRSINT0 {
+ address 0x00b
+ access_mode WO
+ bit CLRSELDO 0x40
+ bit CLRSELDI 0x20
+ bit CLRSELINGO 0x10
+ bit CLRSWRAP 0x08
+ bit CLRSPIORDY 0x02
+}
+
+/*
+ * SCSI Status 0 (p. 3-21)
+ * Contains one set of SCSI Interrupt codes
+ * These are most likely of interest to the sequencer
+ */
+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 */
+}
+
+/*
+ * Clear SCSI Interrupt 1 (p. 3-23)
+ * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT1.
+ */
+register CLRSINT1 {
+ address 0x00c
+ access_mode WO
+ bit CLRSELTIMEO 0x80
+ bit CLRATNO 0x40
+ bit CLRSCSIRSTI 0x20
+ bit CLRBUSFREE 0x08
+ bit CLRSCSIPERR 0x04
+ bit CLRPHASECHG 0x02
+ bit CLRREQINIT 0x01
+}
+
+/*
+ * SCSI Status 1 (p. 3-24)
+ */
+register SSTAT1 {
+ address 0x00c
+ access_mode RO
+ bit SELTO 0x80
+ bit ATNTARG 0x40
+ bit SCSIRSTI 0x20
+ bit PHASEMIS 0x10
+ bit BUSFREE 0x08
+ bit SCSIPERR 0x04
+ bit PHASECHG 0x02
+ bit REQINIT 0x01
+}
+
+/*
+ * SCSI Status 2 (pp. 3-25,26)
+ */
+register SSTAT2 {
+ address 0x00d
+ access_mode RO
+ bit OVERRUN 0x80
+ mask SFCNT 0x1f
+}
+
+/*
+ * SCSI Status 3 (p. 3-26)
+ */
+register SSTAT3 {
+ address 0x00e
+ access_mode RO
+ mask SCSICNT 0xf0
+ mask OFFCNT 0x0f
+}
+
+/*
+ * SCSI Test Control (p. 3-27)
+ */
+register SCSITEST {
+ address 0x00f
+ access_mode RW
+ bit RQAKCNT 0x04
+ bit CNTRTEST 0x02
+ bit CMODE 0x01
+}
+
+/*
+ * SCSI Interrupt Mode 1 (p. 3-28)
+ * Setting any bit will enable the corresponding function
+ * in SIMODE0 to interrupt via the IRQ pin.
+ */
+register SIMODE0 {
+ address 0x010
+ access_mode RW
+ bit ENSELDO 0x40
+ bit ENSELDI 0x20
+ bit ENSELINGO 0x10
+ bit ENSWRAP 0x08
+ bit ENSDONE 0x04
+ bit ENSPIORDY 0x02
+ bit ENDMADONE 0x01
+}
+
+/*
+ * SCSI Interrupt Mode 1 (pp. 3-28,29)
+ * Setting any bit will enable the corresponding function
+ * in SIMODE1 to interrupt via the IRQ pin.
+ */
+register SIMODE1 {
+ address 0x011
+ access_mode RW
+ bit ENSELTIMO 0x80
+ bit ENATNTARG 0x40
+ bit ENSCSIRST 0x20
+ bit ENPHASEMIS 0x10
+ bit ENBUSFREE 0x08
+ bit ENSCSIPERR 0x04
+ bit ENPHASECHG 0x02
+ bit ENREQINIT 0x01
+}
+
+/*
+ * SCSI Data Bus (High) (p. 3-29)
+ * This register reads data on the SCSI Data bus directly.
+ */
+register SCSIBUSL {
+ address 0x012
+ access_mode RO
+}
+
+register SCSIBUSH {
+ address 0x013
+ access_mode RO
+}
+
+/*
+ * SCSI/Host Address (p. 3-30)
+ * These registers hold the host address for the byte about to be
+ * transferred on the SCSI bus. They are counted up in the same
+ * manner as STCNT is counted down. SHADDR should always be used
+ * to determine the address of the last byte transferred since HADDR
+ * can be skewed by write ahead.
+ */
+register SHADDR {
+ address 0x014
+ size 4
+ access_mode RO
+}
+
+/*
+ * Selection Timeout Timer (p. 3-30)
+ */
+register SELTIMER {
+ address 0x018
+ access_mode RW
+ bit STAGE6 0x20
+ bit STAGE5 0x10
+ bit STAGE4 0x08
+ bit STAGE3 0x04
+ bit STAGE2 0x02
+ bit STAGE1 0x01
+}
+
+/*
+ * Selection/Reselection ID (p. 3-31)
+ * Upper four bits are the device id. The ONEBIT is set when the re/selecting
+ * device did not set its own ID.
+ */
+register SELID {
+ address 0x019
+ access_mode RW
+ mask SELID_MASK 0xf0
+ bit ONEBIT 0x08
+}
+
+/*
+ * SCSI Block Control (p. 3-32)
+ * Controls Bus type and channel selection. In a twin channel configuration
+ * addresses 0x00-0x1e are gated to the appropriate channel based on this
+ * register. SELWIDE allows for the coexistence of 8bit and 16bit devices
+ * on a wide bus.
+ */
+register SBLKCTL {
+ address 0x01f
+ access_mode RW
+ bit DIAGLEDEN 0x80 /* Aic78X0 only */
+ bit DIAGLEDON 0x40 /* Aic78X0 only */
+ bit AUTOFLUSHDIS 0x20
+ bit SELBUSB 0x08
+ bit SELWIDE 0x02
+}
+
+/*
+ * Sequencer Control (p. 3-33)
+ * Error detection mode and speed configuration
+ */
+register SEQCTL {
+ address 0x060
+ access_mode RW
+ bit PERRORDIS 0x80
+ bit PAUSEDIS 0x40
+ bit FAILDIS 0x20
+ bit FASTMODE 0x10
+ bit BRKADRINTEN 0x08
+ bit STEP 0x04
+ bit SEQRESET 0x02
+ bit LOADRAM 0x01
+}
+
+/*
+ * Sequencer RAM Data (p. 3-34)
+ * Single byte window into the Scratch Ram area starting at the address
+ * specified by SEQADDR0 and SEQADDR1. To write a full word, simply write
+ * four bytes in sucessesion. The SEQADDRs will increment after the most
+ * significant byte is written
+ */
+register SEQRAM {
+ address 0x061
+ access_mode RW
+}
+
+/*
+ * Sequencer Address Registers (p. 3-35)
+ * Only the first bit of SEQADDR1 holds addressing information
+ */
+register SEQADDR0 {
+ address 0x062
+ access_mode RW
+}
+
+register SEQADDR1 {
+ address 0x063
+ access_mode RW
+ mask SEQADDR1_MASK 0x01
+}
+
+/*
+ * Accumulator
+ * We cheat by passing arguments in the Accumulator up to the kernel driver
+ */
+register ACCUM {
+ address 0x064
+ access_mode RW
+ accumulator
+}
+
+register SINDEX {
+ address 0x065
+ access_mode RW
+ sindex
+}
+
+register DINDEX {
+ address 0x066
+ access_mode RW
+}
+
+register ALLONES {
+ address 0x069
+ access_mode RO
+ allones
+}
+
+register ALLZEROS {
+ address 0x06a
+ access_mode RO
+ allzeros
+}
+
+register NONE {
+ address 0x06a
+ access_mode WO
+ none
+}
+
+register FLAGS {
+ address 0x06b
+ access_mode RO
+ bit ZERO 0x02
+ bit CARRY 0x01
+}
+
+register SINDIR {
+ address 0x06c
+ access_mode RO
+}
+
+register DINDIR {
+ address 0x06d
+ access_mode WO
+}
+
+register FUNCTION1 {
+ address 0x06e
+ access_mode RW
+}
+
+register STACK {
+ address 0x06f
+ access_mode RO
+}
+
+/*
+ * Board Control (p. 3-43)
+ */
+register BCTL {
+ address 0x084
+ access_mode RW
+ bit ACE 0x08
+ bit ENABLE 0x01
+}
+
+/*
+ * On the aic78X0 chips, Board Control is replaced by the DSCommand
+ * register (p. 4-64)
+ */
+register DSCOMMAND {
+ address 0x084
+ access_mode RW
+ bit CACHETHEN 0x80 /* Cache Threshold enable */
+ bit DPARCKEN 0x40 /* Data Parity Check Enable */
+ bit MPARCKEN 0x20 /* Memory Parity Check Enable */
+ bit EXTREQLCK 0x10 /* External Request Lock */
+}
+
+/*
+ * Bus On/Off Time (p. 3-44)
+ */
+register BUSTIME {
+ address 0x085
+ access_mode RW
+ mask BOFF 0xf0
+ mask BON 0x0f
+}
+
+/*
+ * Bus Speed (p. 3-45)
+ */
+register BUSSPD {
+ address 0x086
+ access_mode RW
+ mask DFTHRSH 0xc0
+ mask STBOFF 0x38
+ mask STBON 0x07
+ mask DFTHRSH_100 0xc0
+}
+
+/*
+ * Host Control (p. 3-47) R/W
+ * Overall host control of the device.
+ */
+register HCNTRL {
+ address 0x087
+ access_mode RW
+ bit POWRDN 0x40
+ bit SWINT 0x10
+ bit IRQMS 0x08
+ bit PAUSE 0x04
+ bit INTEN 0x02
+ bit CHIPRST 0x01
+ bit CHIPRSTACK 0x01
+}
+
+/*
+ * Host Address (p. 3-48)
+ * This register contains the address of the byte about
+ * to be transferred across the host bus.
+ */
+register HADDR {
+ address 0x088
+ size 4
+ access_mode RW
+}
+
+register HCNT {
+ address 0x08c
+ size 3
+ access_mode RW
+}
+
+/*
+ * SCB Pointer (p. 3-49)
+ * Gate one of the four SCBs into the SCBARRAY window.
+ */
+register SCBPTR {
+ address 0x090
+ access_mode RW
+}
+
+/*
+ * Interrupt Status (p. 3-50)
+ * Status for system interrupts
+ */
+register INTSTAT {
+ address 0x091
+ access_mode RW
+ bit BRKADRINT 0x08
+ bit SCSIINT 0x04
+ bit CMDCMPLT 0x02
+ bit SEQINT 0x01
+ mask BAD_PHASE SEQINT /* unknown scsi bus phase */
+ mask SEND_REJECT 0x10|SEQINT /* sending a message reject */
+ 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 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
+ */
+ mask MSGIN_PHASEMIS 0xd0|SEQINT /*
+ * Target changed phase on us
+ * when we were expecting
+ * another msgin byte.
+ */
+ mask DATA_OVERRUN 0xe0|SEQINT /*
+ * Target attempted to write
+ * beyond the bounds of its
+ * command.
+ */
+
+ mask SEQINT_MASK 0xf0|SEQINT /* SEQINT Status Codes */
+ mask INT_PEND (BRKADRINT|SEQINT|SCSIINT|CMDCMPLT)
+}
+
+/*
+ * Hard Error (p. 3-53)
+ * Reporting of catastrophic errors. You usually cannot recover from
+ * these without a full board reset.
+ */
+register ERROR {
+ address 0x092
+ access_mode RO
+ bit PARERR 0x08
+ bit ILLOPCODE 0x04
+ bit ILLSADDR 0x02
+ bit ILLHADDR 0x01
+}
+
+/*
+ * Clear Interrupt Status (p. 3-52)
+ */
+register CLRINT {
+ address 0x092
+ access_mode WO
+ bit CLRBRKADRINT 0x08
+ bit CLRSCSIINT 0x04
+ bit CLRCMDINT 0x02
+ bit CLRSEQINT 0x01
+}
+
+register DFCNTRL {
+ address 0x093
+ access_mode RW
+ bit WIDEODD 0x40
+ bit SCSIEN 0x20
+ bit SDMAEN 0x10
+ bit SDMAENACK 0x10
+ bit HDMAEN 0x08
+ bit HDMAENACK 0x08
+ bit DIRECTION 0x04
+ bit FIFOFLUSH 0x02
+ bit FIFORESET 0x01
+}
+
+register DFSTATUS {
+ address 0x094
+ access_mode RO
+ bit DWORDEMP 0x20
+ bit MREQPEND 0x10
+ bit HDONE 0x08
+ bit DFTHRESH 0x04
+ bit FIFOFULL 0x02
+ bit FIFOEMP 0x01
+}
+
+register DFDAT {
+ address 0x099
+ access_mode RW
+}
+
+/*
+ * SCB Auto Increment (p. 3-59)
+ * Byte offset into the SCB Array and an optional bit to allow auto
+ * incrementing of the address during download and upload operations
+ */
+register SCBCNT {
+ address 0x09a
+ access_mode RW
+ bit SCBAUTO 0x80
+ mask SCBCNT_MASK 0x1f
+}
+
+/*
+ * Queue In FIFO (p. 3-60)
+ * Input queue for queued SCBs (commands that the seqencer has yet to start)
+ */
+register QINFIFO {
+ address 0x09b
+ access_mode RW
+}
+
+/*
+ * Queue In Count (p. 3-60)
+ * Number of queued SCBs
+ */
+register QINCNT {
+ address 0x09c
+ access_mode RO
+}
+
+/*
+ * Queue Out FIFO (p. 3-61)
+ * Queue of SCBs that have completed and await the host
+ */
+register QOUTFIFO {
+ address 0x09d
+ access_mode WO
+}
+
+/*
+ * Queue Out Count (p. 3-61)
+ * Number of queued SCBs in the Out FIFO
+ */
+register QOUTCNT {
+ address 0x09e
+ access_mode RO
+}
+
+/*
+ * SCB Definition (p. 5-4)
+ */
+scb {
+ address 0x0a0
+ SCB_CONTROL {
+ size 1
+ bit MK_MESSAGE 0x80
+ bit DISCENB 0x40
+ bit TAG_ENB 0x20
+ bit SPLIT_SG 0x10
+ bit ABORT_SCB 0x08
+ bit DISCONNECTED 0x04
+ mask SCB_TAG_TYPE 0x03
+ }
+ SCB_TCL {
+ size 1
+ bit SELBUSB 0x08
+ mask TID 0xf0
+ }
+ SCB_TARGET_STATUS {
+ size 1
+ }
+ SCB_SGCOUNT {
+ size 1
+ }
+ SCB_SGPTR {
+ size 4
+ }
+ SCB_RESID_SGCNT {
+ size 1
+ }
+ SCB_RESID_DCNT {
+ size 3
+ }
+ SCB_DATAPTR {
+ size 4
+ }
+ SCB_DATACNT {
+ size 3
+ }
+ SCB_LINKED_NEXT {
+ size 1
+ }
+ SCB_CMDPTR {
+ size 4
+ }
+ SCB_CMDLEN {
+ size 1
+ }
+ SCB_TAG {
+ size 1
+ }
+ SCB_NEXT {
+ size 1
+ }
+ SCB_PREV {
+ size 1
+ }
+ SCB_BUSYTARGETS {
+ size 4
+ }
+}
+
+const SG_SIZEOF 0x08 /* sizeof(struct ahc_dma) */
+
+/* --------------------- AHA-2840-only definitions -------------------- */
+
+register SEECTL_2840 {
+ address 0x0c0
+ access_mode RW
+ bit CS_2840 0x04
+ bit CK_2840 0x02
+ bit DO_2840 0x01
+}
+
+register STATUS_2840 {
+ address 0x0c1
+ access_mode RW
+ bit EEPROM_TF 0x80
+ mask BIOS_SEL 0x60
+ mask ADSEL 0x1e
+ bit DI_2840 0x01
+}
+
+/* --------------------- AIC-7870-only definitions -------------------- */
+
+register DSPCISTATUS {
+ address 0x086
+}
+
+register BRDCTL {
+ address 0x01d
+ bit BRDDAT7 0x80
+ bit BRDDAT6 0x40
+ bit BRDDAT5 0x20
+ bit BRDSTB 0x10
+ bit BRDCS 0x08
+ bit BRDRW 0x04
+ bit BRDCTL1 0x02
+ bit BRDCTL0 0x01
+}
+
+/*
+ * Serial EEPROM Control (p. 4-92 in 7870 Databook)
+ * Controls the reading and writing of an external serial 1-bit
+ * EEPROM Device. In order to access the serial EEPROM, you must
+ * first set the SEEMS bit that generates a request to the memory
+ * port for access to the serial EEPROM device. When the memory
+ * port is not busy servicing another request, it reconfigures
+ * to allow access to the serial EEPROM. When this happens, SEERDY
+ * gets set high to verify that the memory port access has been
+ * granted.
+ *
+ * After successful arbitration for the memory port, the SEECS bit of
+ * the SEECTL register is connected to the chip select. The SEECK,
+ * SEEDO, and SEEDI are connected to the clock, data out, and data in
+ * lines respectively. The SEERDY bit of SEECTL is useful in that it
+ * gives us an 800 nsec timer. After a write to the SEECTL register,
+ * the SEERDY goes high 800 nsec later. The one exception to this is
+ * when we first request access to the memory port. The SEERDY goes
+ * high to signify that access has been granted and, for this case, has
+ * no implied timing.
+ *
+ * See 93cx6.c for detailed information on the protocol necessary to
+ * read the serial EEPROM.
+ */
+register SEECTL {
+ address 0x01e
+ bit EXTARBACK 0x80
+ bit EXTARBREQ 0x40
+ bit SEEMS 0x20
+ bit SEERDY 0x10
+ bit SEECS 0x08
+ bit SEECK 0x04
+ bit SEEDO 0x02
+ bit SEEDI 0x01
+}
+/* ---------------------- Scratch RAM Offsets ------------------------- */
+/* These offsets are either to values that are initialized by the board's
+ * BIOS or are specified by the sequencer code.
+ *
+ * The host adapter card (at least the BIOS) uses 20-2f for SCSI
+ * device information, 32-33 and 5a-5f as well. As it turns out, the
+ * BIOS trashes 20-2f, writing the synchronous negotiation results
+ * on top of the BIOS values, so we re-use those for our per-target
+ * scratchspace (actually a value that can be copied directly into
+ * SCSIRATE). The kernel driver will enable synchronous negotiation
+ * for all targets that have a value other than 0 in the lower four
+ * bits of the target scratch space. This should work regardless of
+ * whether the bios has been installed.
+ */
+
+scratch_ram {
+ address 0x020
+
+ /*
+ * 1 byte per target starting at this address for configuration values
+ */
+ TARG_SCRATCH {
+ size 16
+ }
+ ULTRA_ENB {
+ size 2
+ }
+ /*
+ * Bit vector of targets that have disconnection disabled.
+ */
+ DISC_DSB {
+ size 2
+ }
+ /*
+ * Length of pending message
+ */
+ MSG_LEN {
+ size 1
+ }
+ /* We reserve 8bytes to store outgoing messages */
+ MSG_OUT {
+ size 8
+ }
+ /* Parameters for DMA Logic */
+ DMAPARAMS {
+ size 1
+ bit WIDEODD 0x40
+ bit SCSIEN 0x20
+ bit SDMAEN 0x10
+ bit SDMAENACK 0x10
+ bit HDMAEN 0x08
+ bit HDMAENACK 0x08
+ bit DIRECTION 0x04
+ bit FIFOFLUSH 0x02
+ bit FIFORESET 0x01
+ }
+ /*
+ * Number of SCBs supported by
+ * this card.
+ */
+ SCBCOUNT {
+ size 1
+ }
+ /*
+ * Two's complement of SCBCOUNT
+ */
+ COMP_SCBCOUNT {
+ size 1
+ }
+ /*
+ * Mask of bits to test against
+ * when looking at the Queue Count
+ * registers. Works around a bug
+ * on aic7850 chips.
+ */
+ QCNTMASK {
+ size 1
+ }
+ 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
+ }
+ /*
+ * Temporary storage for the
+ * target/channel/lun of a
+ * reconnecting target
+ */
+ SAVED_TCL {
+ size 1
+ }
+ SG_COUNT {
+ size 1
+ }
+ /* 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 sequencer will stick the frist byte of any rejected message here
+ * so we can see what is getting thrown away.
+ */
+ REJBYTE {
+ size 1
+ }
+ /*
+ * The last bus phase as seen by the sequencer.
+ */
+ LASTPHASE {
+ size 1
+ bit CDI 0x80
+ bit IOI 0x40
+ bit MSGI 0x20
+ mask PHASE_MASK CDI|IOI|MSGI
+ mask P_DATAOUT 0x00
+ mask P_DATAIN IOI
+ mask P_COMMAND CDI
+ mask P_MESGOUT CDI|MSGI
+ mask P_STATUS CDI|IOI
+ 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.
+ */
+ MSGIN_EXT_BYTES {
+ size 3
+ }
+ /*
+ * head of list of SCBs that are
+ * disconnected. Used for SCB
+ * paging.
+ */
+ DISCONNECTED_SCBH {
+ size 1
+ }
+ /*
+ * head of list of SCBs that are
+ * not in use. Used for SCB paging.
+ */
+ FREE_SCBH {
+ size 1
+ }
+ HSCB_ADDR {
+ size 4
+ }
+ CUR_SCBID {
+ size 1
+ }
+ ARG_1 {
+ size 1
+ mask SEND_MSG 0x80
+ mask SEND_SENSE 0x40
+ mask SEND_REJ 0x20
+ alias RETURN_1
+ }
+ /*
+ * These are reserved registers in the card's scratch ram. Some of
+ * the values are specified in the AHA2742 technical reference manual
+ * and are initialized by the BIOS at boot time.
+ */
+ SCSICONF {
+ address 0x05a
+ size 1
+ bit RESET_SCSI 0x40
+ }
+ HOSTCONF {
+ address 0x05d
+ size 1
+ }
+ HA_274_BIOSCTRL {
+ address 0x05f
+ size 1
+ mask BIOSMODE 0x30
+ mask BIOSDISABLED 0x30
+ bit CHANNEL_B_PRIMARY 0x08
+ }
+}
+
+const SCB_LIST_NULL 0xff
+
+
+/* WDTR Message values */
+const BUS_8_BIT 0x00
+const BUS_16_BIT 0x01
+const BUS_32_BIT 0x02
+const MAX_OFFSET_8BIT 0x0f
+const MAX_OFFSET_16BIT 0x08
diff --git a/sys/dev/aic7xxx/aic7xxx.seq b/sys/dev/aic7xxx/aic7xxx.seq
index 391e13e7396a0..3a85e28ad27d0 100644
--- a/sys/dev/aic7xxx/aic7xxx.seq
+++ b/sys/dev/aic7xxx/aic7xxx.seq
@@ -7,7 +7,7 @@
*
*FreeBSD, Twin, Wide, 2 command per target support, tagged queuing,
*SCB paging and other optimizations:
- *Copyright (c) 1994, 1995, 1996 Justin Gibbs. All rights reserved.
+ *Copyright (c) 1994, 1995, 1996, 1997 Justin Gibbs. All rights reserved.
*
*Redistribution and use in source and binary forms, with or without
*modification, are permitted provided that the following conditions
@@ -39,23 +39,8 @@
*
*-M************************************************************************/
-VERSION AIC7XXX_SEQ_VER "$Id: aic7xxx.seq,v 1.62 1997/02/25 03:02:56 gibbs Exp$"
-
-#if defined(__NetBSD__)
-#include "../../../../dev/ic/aic7xxxreg.h"
-#include "../../../../scsi/scsi_message.h"
-#elif defined(__FreeBSD__)
-#include "../../dev/aic7xxx/aic7xxx_reg.h"
-#include "../../scsi/scsi_message.h"
-#endif
-
-/*
- * We can't just use ACCUM in the sequencer code because it
- * must be treated specially by the assembler, and it currently
- * looks for the symbol 'A'. This is the only register defined in
- * the assembler's symbol space.
- */
-A = ACCUM
+#include <dev/aic7xxx/aic7xxx.reg>
+#include <scsi/scsi_message.h>
/*
* A few words on the waiting SCB list:
@@ -80,67 +65,53 @@ A = ACCUM
* middle of a DMA, so clear DFCNTRL too.
*/
reset:
- clr SCSISIGO /* De-assert BSY */
- mvi SCSISEQ,0x12 /* Always allow reselection
- * ENRSELI|ENAUTOATNP
- */
-p_busfree:
- clr DFCNTRL
- clr SCSIRATE /*
- * We don't know the target we will
- * connect to, so default to narrow
- * transfers to avoid parity problems.
- */
- and SXFRCTL0, 0xdf /* ~FAST20*/
- mvi LASTPHASE, P_BUSFREE
- and FLAGS,0x07 /* clear target specific flags */
+ clr SCSISIGO; /* De-assert BSY */
+ /* Always allow reselection */
+ mvi SCSISEQ, ENRSELI|ENAUTOATNP;
+ call clear_target_state;
poll_for_work:
+ test SSTAT0,SELDI|SELDO jnz selection;
+ test SCSISEQ, ENSELO jnz poll_for_work;
+.if ( TWIN_CHANNEL )
/*
- * Are we a twin channel device?
- * For fairness, we check the other bus first,
- * since we just finished a transaction on the
- * current channel.
+ * Twin channel devices cannot handle things like SELTO
+ * interrupts on the "background" channel. So, if we
+ * are selecting, keep polling the current channel util
+ * either a selection or reselection occurs.
*/
- test FLAGS,TWIN_BUS jz start2
- xor SBLKCTL,SELBUSB /* Toggle to the other bus */
- test SSTAT0,SELDI jnz reselect
- xor SBLKCTL,SELBUSB /* Toggle to the original bus */
-start2:
- test SSTAT0,SELDI jnz reselect
- cmp WAITING_SCBH,SCB_LIST_NULL je test_queue
-start_waiting:
- /*
- * Pull the first entry off of the waiting SCB list
- * We don't have to "test_busy" because only transactions that
- * have passed that test can be in the WAITING_SCB list.
- */
- mov SCBPTR,WAITING_SCBH
- jmp start_scb2
+ xor SBLKCTL,SELBUSB; /* Toggle to the other bus */
+ test SSTAT0,SELDI|SELDO jnz selection;
+ test SCSISEQ, ENSELO jnz poll_for_work;
+ xor SBLKCTL,SELBUSB; /* Toggle back */
+.endif
+ cmp WAITING_SCBH,SCB_LIST_NULL jne start_waiting;
test_queue:
/* Has the driver posted any work for us? */
- mov A, QCNTMASK
- test QINCNT,A jz poll_for_work
+ mov A, QCNTMASK;
+ test QINCNT,A jz poll_for_work;
/*
* We have at least one queued SCB now and we don't have any
* SCBs in the list of SCBs awaiting selection. If we have
- * any SCBs availible for use, pull the tag from the QINFIFO
+ * any SCBs available for use, pull the tag from the QINFIFO
* and get to work on it.
*/
- test FLAGS, PAGESCBS jz dequeue_scb
- mov ALLZEROS call get_free_or_disc_scb
- cmp SINDEX, SCB_LIST_NULL je poll_for_work
+.if ( SCB_PAGING )
+ mov ALLZEROS call get_free_or_disc_scb;
+ cmp SINDEX, SCB_LIST_NULL je poll_for_work;
+.endif
dequeue_scb:
- mov CUR_SCBID,QINFIFO
- test FLAGS, PAGESCBS jnz dma_queued_scb
+ mov CUR_SCBID,QINFIFO;
+.if !( SCB_PAGING )
/* In the non-paging case, the SCBID == hardware SCB index */
- mov SCBPTR, CUR_SCBID
+ mov SCBPTR, CUR_SCBID;
+.endif
dma_queued_scb:
/*
* DMA the SCB from host ram into the current SCB location.
*/
- mvi DMAPARAMS, 0xd /* HDMAEN|DIRECTION|FIFORESET */
- mov CUR_SCBID call dma_scb
+ mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
+ mov CUR_SCBID call dma_scb;
/*
* See if there is not already an active SCB for this target. This code
@@ -152,76 +123,109 @@ dma_queued_scb:
* impossible to link up the SCBs.
*/
test_busy:
- test SCB_CONTROL, TAG_ENB jnz start_scb
- mvi SEQCTL,0x50 /* PAUSEDIS|FASTMODE */
- mov SAVED_SCBPTR, SCBPTR
- mov SCB_TCL call index_untagged_scb
- mov ARG_1, SINDIR /*
+ test SCB_CONTROL, TAG_ENB|ABORT_SCB jnz start_scb;
+ mvi SEQCTL, PAUSEDIS|FASTMODE;
+ mov SAVED_SCBPTR, SCBPTR;
+ mov SCB_TCL call index_untagged_scb;
+ mov ARG_1, SINDIR; /*
* ARG_1 should
* now have the SCB ID of
* any active, non-tagged,
* command for this target.
*/
- cmp ARG_1, SCB_LIST_NULL je make_busy
- test FLAGS, PAGESCBS jz simple_busy_link
+ cmp ARG_1, SCB_LIST_NULL je make_busy;
+.if ( SCB_PAGING )
/*
* Put this SCB back onto the free list. It
* may be necessary to satisfy the search for
* the active SCB.
*/
- mov SCBPTR, SAVED_SCBPTR
- call add_scb_to_free_list
+ mov SCBPTR, SAVED_SCBPTR;
+ call add_scb_to_free_list;
/* Find the active SCB */
- mov ALLZEROS call findSCB
+ mov ALLZEROS call findSCB;
/*
* If we couldn't find it, tell the kernel. This should
* never happen.
*/
- cmp SINDEX, SCB_LIST_NULL jne paged_busy_link
- mvi INTSTAT, NO_MATCH_BUSY
+ cmp SINDEX, SCB_LIST_NULL jne paged_busy_link;
+ mvi INTSTAT, NO_MATCH_BUSY;
paged_busy_link:
/* Link us in */
- mov SCB_LINKED_NEXT, CUR_SCBID
+ mov SCB_LINKED_NEXT, CUR_SCBID;
/* Put it back on the disconnected list */
- call add_scb_to_disc_list
- mvi SEQCTL,0x10 /* FASTMODE */
- jmp poll_for_work
+ call add_scb_to_disc_list;
+ mvi SEQCTL, FASTMODE;
+ jmp poll_for_work;
+.endif
simple_busy_link:
- mov SCBPTR, ARG_1
- mov SCB_LINKED_NEXT, CUR_SCBID
- mvi SEQCTL,0x10 /* FASTMODE */
- jmp poll_for_work
+ mov SCBPTR, ARG_1;
+ mov SCB_LINKED_NEXT, CUR_SCBID;
+ mvi SEQCTL, FASTMODE;
+ jmp poll_for_work;
make_busy:
- mov DINDIR, CUR_SCBID
- mov SCBPTR, SAVED_SCBPTR
- mvi SEQCTL,0x10 /* FASTMODE */
+ mov DINDIR, CUR_SCBID;
+ mov SCBPTR, SAVED_SCBPTR;
+ mvi SEQCTL, FASTMODE;
start_scb:
/*
* Place us on the waiting list in case our selection
* doesn't win during bus arbitration.
*/
- mov SCB_NEXT,WAITING_SCBH
- mov WAITING_SCBH, SCBPTR
-start_scb2:
- and SINDEX,0xf7,SBLKCTL /* Clear the channel select bit */
- and A,0x08,SCB_TCL /* Get new channel bit */
- or SINDEX,A
- mov SBLKCTL,SINDEX /* select channel */
- mov SCB_TCL call initialize_scsiid
+ mov SCB_NEXT,WAITING_SCBH;
+ mov WAITING_SCBH, SCBPTR;
+start_waiting:
+ /*
+ * Pull the first entry off of the waiting SCB list
+ * We don't have to "test_busy" because only transactions that
+ * have passed that test can be in the WAITING_SCB list.
+ */
+ mov SCBPTR, WAITING_SCBH;
+ call start_selection;
+ jmp poll_for_work;
+start_selection:
+ and SINDEX,~SELBUSB,SBLKCTL;/* Clear the channel select bit */
+ and A,SELBUSB,SCB_TCL; /* Get new channel bit */
+ or SINDEX,A;
+ mov SBLKCTL,SINDEX; /* select channel */
+initialize_scsiid:
+ and A, TID, SCB_TCL; /* Get target ID */
+ and SCSIID, OID; /* Clear old target */
+ or SCSIID, A;
+ mvi SCSISEQ, ENSELO|ENAUTOATNO|ENRSELI|ENAUTOATNP ret;
/*
- * Enable selection phase as an initiator, and do automatic ATN
- * after the selection. We do this now so that we can overlap the
- * rest of our work to set up this target with the arbitration and
- * selection bus phases.
+ * Reselection has been initiated by a target. Make a note that we've been
+ * reselected, but haven't seen an IDENTIFY message from the target yet.
*/
-start_selection:
- mvi SCSISEQ,0x5a /* ENSELO|ENAUTOATNO|ENRSELI
- * |ENAUTOATNP
- */
+selection:
+ test SSTAT0, SELDI jz select;
+reselect:
+ clr MSG_LEN; /* Don't have anything in the mesg buffer */
+ mvi CLRSINT0, CLRSELDI;
+ /* XXX test for and handle ONE BIT condition */
+ and SAVED_TCL, SELID_MASK, SELID;
+ or SEQ_FLAGS,RESELECTED;
+ jmp select2;
/*
+ * After the selection, remove this SCB from the "waiting SCB"
+ * list. This is achieved by simply moving our "next" pointer into
+ * WAITING_SCBH. Our next pointer will be set to null the next time this
+ * SCB is used, so don't bother with it now.
+ */
+select:
+ /* Turn off the selection hardware */
+ mvi SCSISEQ, ENRSELI|ENAUTOATNP; /*
+ * ATN on parity errors
+ * for "in" phases
+ */
+ mvi CLRSINT0, CLRSELDO;
+ mov SCBPTR, WAITING_SCBH;
+ mov WAITING_SCBH,SCB_NEXT;
+ mov SAVED_TCL, SCB_TCL;
+/*
* As soon as we get a successful selection, the target should go
* into the message out phase since we have ATN asserted. Prepare
* the message to send.
@@ -231,63 +235,33 @@ start_selection:
*/
mk_identify:
- and MSG0,0x7,SCB_TCL /* lun */
- and A,DISCENB,SCB_CONTROL /* mask off disconnect privledge */
- or MSG0,A /* or in disconnect privledge */
- or MSG0,MSG_IDENTIFYFLAG
- mvi MSG_LEN, 1
+ and MSG_OUT,0x7,SCB_TCL; /* lun */
+ and A,DISCENB,SCB_CONTROL; /* mask off disconnect privledge */
+ or MSG_OUT,A; /* or in disconnect privledge */
+ or MSG_OUT,MSG_IDENTIFYFLAG;
+ mvi MSG_LEN, 1;
/*
* Send a tag message if TAG_ENB is set in the SCB control block.
* Use SCB_TAG (the position in the kernel's SCB array) as the tag value.
*/
mk_tag:
- test SCB_CONTROL,TAG_ENB jz mk_message
- and MSG1,0x23,SCB_CONTROL
- mov MSG2,SCB_TAG
- add MSG_LEN,2 /* update message length */
+ test SCB_CONTROL,TAG_ENB jz mk_message;
+ and MSG_OUT[1],TAG_ENB|SCB_TAG_TYPE,SCB_CONTROL;
+ mov MSG_OUT[2],SCB_TAG;
+ add MSG_LEN,2; /* update message length */
/*
* Interrupt the driver, and allow it to tweak the message buffer
* if it asks.
*/
mk_message:
- test SCB_CONTROL,MK_MESSAGE jz wait_for_selection
-
- mvi INTSTAT,AWAITING_MSG
-
-wait_for_selection:
- test SSTAT0,SELDO jnz select
- test SSTAT0,SELDI jz wait_for_selection
+ test SCB_CONTROL,MK_MESSAGE jz select2;
+ mvi INTSTAT,AWAITING_MSG;
-/*
- * Reselection has been initiated by a target. Make a note that we've been
- * reselected, but haven't seen an IDENTIFY message from the target yet.
- */
-reselect:
- clr MSG_LEN /* Don't have anything in the mesg buffer */
- /* XXX test for and handle ONE BIT condition */
- and SAVED_TCL, 0xf0, SELID
- or FLAGS,RESELECTED
- jmp select2
-
-/*
- * After the selection, remove this SCB from the "waiting SCB"
- * list. This is achieved by simply moving our "next" pointer into
- * WAITING_SCBH. Our next pointer will be set to null the next time this
- * SCB is used, so don't bother with it now.
- */
-select:
- mov WAITING_SCBH,SCB_NEXT
select2:
- /* Turn off the selection hardware */
- mvi SCSISEQ, 0x12 /* ENRSELI|ENAUTOATNP
- * ATN on parity errors
- * for "in" phases
- */
- mvi CLRSINT0,0x60 /* CLRSELDI|CLRSELDO */
- mvi CLRSINT1,CLRBUSFREE
- or SIMODE1, ENBUSFREE /*
+ mvi CLRSINT1,CLRBUSFREE;
+ or SIMODE1, ENBUSFREE; /*
* We aren't expecting a
* bus free, so interrupt
* the kernel driver if it
@@ -296,17 +270,18 @@ select2:
/*
* Initialize Ultra mode setting and clear the SCSI channel.
*/
- or SXFRCTL0, 0x1a /* CLRSTCNT|SPIOEN|CLRCHN */
+ or SXFRCTL0, CLRSTCNT|SPIOEN|CLRCHN;
+.if ( ULTRA )
ultra:
- mvi SINDEX, ULTRA_ENB_B
- test SAVED_TCL, 0x80 jnz ultra_2 /* Target ID > 7 */
- test SBLKCTL, SELBUSB jnz ultra_2 /* Second channel */
- dec SINDEX
+ mvi SINDEX, ULTRA_ENB+1;
+ test SAVED_TCL, 0x80 jnz ultra_2; /* Target ID > 7 */
+ dec SINDEX;
ultra_2:
- mov FUNCTION1,SAVED_TCL
- mov A,FUNCTION1
- test SINDIR, A jz ndx_dtr
- or SXFRCTL0, FAST20
+ mov FUNCTION1,SAVED_TCL;
+ mov A,FUNCTION1;
+ test SINDIR, A jz ndx_dtr;
+ or SXFRCTL0, FAST20;
+.endif
/*
* Initialize SCSIRATE with the appropriate value for this target.
@@ -314,13 +289,13 @@ ultra_2:
* based at TARG_SCRATCH.
*/
ndx_dtr:
- shr A,SAVED_TCL,4
- test SBLKCTL,SELBUSB jz ndx_dtr_2
- or SAVED_TCL, SELBUSB /* Add the channel bit while we're here */
- or A,0x08 /* Channel B entries add 8 */
+ shr A,4,SAVED_TCL;
+ test SBLKCTL,SELBUSB jz ndx_dtr_2;
+ or SAVED_TCL, SELBUSB; /* Add the channel bit while we're here */
+ or A,0x08; /* Channel B entries add 8 */
ndx_dtr_2:
- add SINDEX,TARG_SCRATCH,A
- mov SCSIRATE,SINDIR
+ add SINDEX,TARG_SCRATCH,A;
+ mov SCSIRATE,SINDIR;
/*
@@ -331,51 +306,64 @@ ndx_dtr_2:
*
*/
ITloop:
- test SSTAT1,0x9 jz ITloop /* REQINIT|BUSFREE */
- test SSTAT1,BUSFREE jnz p_busfree
+ test SSTAT1,REQINIT jz ITloop;
- and A,PHASE_MASK,SCSISIGI
- mov LASTPHASE,A
- mov SCSISIGO,A
+ and A,PHASE_MASK,SCSISIGI;
+ mov LASTPHASE,A;
+ mov SCSISIGO,A;
- cmp ALLZEROS,A je p_dataout
- cmp A,P_DATAIN je p_datain
- cmp A,P_COMMAND je p_command
- cmp A,P_MESGOUT je p_mesgout
- cmp A,P_STATUS je p_status
- cmp A,P_MESGIN je p_mesgin
+ cmp ALLZEROS,A je p_dataout;
+ cmp A,P_DATAIN je p_datain;
+ cmp A,P_COMMAND je p_command;
+ cmp A,P_MESGOUT je p_mesgout;
+ cmp A,P_STATUS je p_status;
+ cmp A,P_MESGIN je p_mesgin;
- mvi INTSTAT,BAD_PHASE /* unknown phase - signal driver */
- jmp ITloop /* Try reading the bus again. */
+ mvi INTSTAT,BAD_PHASE; /* unknown phase - signal driver */
+ jmp ITloop; /* Try reading the bus again. */
+
+await_busfree:
+ and SIMODE1, ~ENBUSFREE;
+ mov NONE, SCSIDATL; /* Ack the last byte */
+ call clear_target_state;
+ test SSTAT1,REQINIT|BUSFREE jz .;
+ test SSTAT1, BUSFREE jnz poll_for_work;
+ mvi INTSTAT, BAD_PHASE;
+
+clear_target_state:
+ clr DFCNTRL;
+ clr SCSIRATE; /*
+ * We don't know the target we will
+ * connect to, so default to narrow
+ * transfers to avoid parity problems.
+ */
+ and SXFRCTL0, ~FAST20;
+ mvi LASTPHASE, P_BUSFREE;
+ /* clear target specific flags */
+ and SEQ_FLAGS,~(RESELECTED|IDENTIFY_SEEN|TAGGED_SCB|DPHASE) ret;
p_dataout:
- mvi DMAPARAMS,0x7d /*
- * WIDEODD|SCSIEN|SDMAEN|HDMAEN|
- * DIRECTION|FIFORESET
- */
- jmp data_phase_init
+ mvi DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET;
+ jmp data_phase_init;
/*
* If we re-enter the data phase after going through another phase, the
* STCNT may have been cleared, so restore it from the residual field.
*/
data_phase_reinit:
- mvi DINDEX, STCNT0
- mvi SCB_RESID_DCNT0 call bcopy_3
- jmp data_phase_loop
+ mvi DINDEX, STCNT;
+ mvi SCB_RESID_DCNT call bcopy_3;
+ jmp data_phase_loop;
p_datain:
- mvi DMAPARAMS,0x79 /*
- * WIDEODD|SCSIEN|SDMAEN|HDMAEN|
- * !DIRECTION|FIFORESET
- */
+ mvi DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET;
data_phase_init:
- call assert /*
+ call assert; /*
* Ensure entering a data
* phase is okay - seen identify, etc.
*/
- test FLAGS, DPHASE jnz data_phase_reinit
+ test SEQ_FLAGS, DPHASE jnz data_phase_reinit;
/*
* Initialize the DMA address and counter from the SCB.
@@ -383,55 +371,55 @@ data_phase_init:
* modify the values in the SCB itself until we see a
* save data pointers message.
*/
- mvi DINDEX, HADDR0
- mvi SCB_DATAPTR call bcopy_7
+ mvi DINDEX, HADDR;
+ mvi SCB_DATAPTR call bcopy_7;
- call set_stcnt_from_hcnt
+ call set_stcnt_from_hcnt;
- mov SG_COUNT,SCB_SGCOUNT
+ mov SG_COUNT,SCB_SGCOUNT;
- mvi DINDEX, SG_NEXT
- mvi SCB_SGPTR call bcopy_4
+ mvi DINDEX, SG_NEXT;
+ mvi SCB_SGPTR call bcopy_4;
data_phase_loop:
/* Guard against overruns */
- test SG_COUNT, 0xff jnz data_phase_inbounds
+ test SG_COUNT, 0xff jnz data_phase_inbounds;
/*
* Turn on 'Bit Bucket' mode, set the transfer count to
* 16meg and let the target run until it changes phase.
* When the transfer completes, notify the host that we
* had an overrun.
*/
- or SXFRCTL1,BITBUCKET
- mvi HCNT0, 0xff
- mvi HCNT1, 0xff
- mvi HCNT2, 0xff
- call set_stcnt_from_hcnt
+ or SXFRCTL1,BITBUCKET;
+ mvi HCNT[0], 0xff;
+ mvi HCNT[1], 0xff;
+ mvi HCNT[2], 0xff;
+ call set_stcnt_from_hcnt;
data_phase_inbounds:
/* If we are the last SG block, ensure wideodd is off. */
- cmp SG_COUNT,0x01 jne data_phase_wideodd
- and DMAPARAMS, 0xbf /* Turn off WIDEODD */
+ cmp SG_COUNT,0x01 jne data_phase_wideodd;
+ and DMAPARAMS, ~WIDEODD;
data_phase_wideodd:
- mov DMAPARAMS call dma
+ mov DMAPARAMS call dma;
/* Go tell the host about any overruns */
- test SXFRCTL1,BITBUCKET jnz data_phase_overrun
+ test SXFRCTL1,BITBUCKET jnz data_phase_overrun;
/* Exit if we had an underrun. dma clears SINDEX in this case. */
- test SINDEX,0xff jz data_phase_finish
+ test SINDEX,0xff jz data_phase_finish;
/*
* Advance the scatter-gather pointers if needed
*/
sg_advance:
- dec SG_COUNT /* one less segment to go */
+ dec SG_COUNT; /* one less segment to go */
- test SG_COUNT, 0xff jz data_phase_finish /* Are we done? */
+ test SG_COUNT, 0xff jz data_phase_finish; /* Are we done? */
- clr A /* add sizeof(struct scatter) */
- add SG_NEXT0,SG_SIZEOF,SG_NEXT0
- adc SG_NEXT1,A,SG_NEXT1
+ clr A; /* add sizeof(struct scatter) */
+ add SG_NEXT[0],SG_SIZEOF;
+ adc SG_NEXT[1],A;
/*
* Load a struct scatter and set up the data address and length.
@@ -441,16 +429,16 @@ sg_advance:
* This, like all DMA's, assumes little-endian host data storage.
*/
sg_load:
- mvi DINDEX, HADDR0
- mvi SG_NEXT0 call bcopy_4
+ mvi DINDEX, HADDR;
+ mvi SG_NEXT call bcopy_4;
- mvi HCNT0,SG_SIZEOF
- clr HCNT1
- clr HCNT2
+ mvi HCNT[0],SG_SIZEOF;
+ clr HCNT[1];
+ clr HCNT[2];
- or DFCNTRL,0xd /* HDMAEN|DIRECTION|FIFORESET */
+ or DFCNTRL, HDMAEN|DIRECTION|FIFORESET;
- call dma_finish
+ call dma_finish;
/*
* Copy data from FIFO into SCB data pointer and data count. This assumes
@@ -461,11 +449,11 @@ sg_load:
* u_int32_t len; four bytes, little endian order
* };
*/
- mvi HADDR0 call dfdat_in_7
+ mvi HADDR call dfdat_in_7;
/* Load STCNT as well. It is a mirror of HCNT */
- call set_stcnt_from_hcnt
- test SSTAT1,PHASEMIS jz data_phase_loop
+ call set_stcnt_from_hcnt;
+ test SSTAT1,PHASEMIS jz data_phase_loop;
data_phase_finish:
/*
@@ -473,117 +461,118 @@ data_phase_finish:
* We use STCNT instead of HCNT, since it's a reflection of how many bytes
* were transferred on the SCSI (as opposed to the host) bus.
*/
- mov SCB_RESID_DCNT0,STCNT0
- mov SCB_RESID_DCNT1,STCNT1
- mov SCB_RESID_DCNT2,STCNT2
- mov SCB_RESID_SGCNT, SG_COUNT
+ mov SCB_RESID_DCNT[0],STCNT[0];
+ mov SCB_RESID_DCNT[1],STCNT[1];
+ mov SCB_RESID_DCNT[2],STCNT[2];
+ mov SCB_RESID_SGCNT, SG_COUNT;
/* We have seen a data phase */
- or FLAGS, DPHASE
+ or SEQ_FLAGS, DPHASE;
- jmp ITloop
+ jmp ITloop;
data_phase_overrun:
/*
* Turn off BITBUCKET mode and notify the host
*/
- and SXFRCTL1,0x7f /* ~BITBUCKET */
- mvi INTSTAT,DATA_OVERRUN
- jmp ITloop
+ and SXFRCTL1, ~BITBUCKET;
+ mvi INTSTAT,DATA_OVERRUN;
+ jmp ITloop;
/*
* Command phase. Set up the DMA registers and let 'er rip.
*/
p_command:
- call assert
+ call assert;
/*
* Load HADDR and HCNT.
*/
- mvi DINDEX, HADDR0
- mvi SCB_CMDPTR call bcopy_5
- clr HCNT1
- clr HCNT2
+ mvi DINDEX, HADDR;
+ mvi SCB_CMDPTR call bcopy_5;
+ clr HCNT[1];
+ clr HCNT[2];
- call set_stcnt_from_hcnt
+ call set_stcnt_from_hcnt;
- mvi 0x3d call dma /* SCSIEN|SDMAEN|HDMAEN
- * |DIRECTION|FIFORESET
- */
- jmp ITloop
+ mvi (SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET) call dma;
+ jmp ITloop;
/*
* Status phase. Wait for the data byte to appear, then read it
* and store it into the SCB.
*/
p_status:
- call assert
+ call assert;
- mov SCB_TARGET_STATUS, SCSIDATL
- jmp ITloop
+ mov SCB_TARGET_STATUS, SCSIDATL;
+ jmp ITloop;
/*
* Message out phase. If there is not an active message, but the target
* took us into this phase anyway, build a no-op message and send it.
*/
p_mesgout:
- test MSG_LEN, 0xff jnz p_mesgout_start
- mvi MSG_NOOP call mk_mesg /* build NOP message */
+ test MSG_LEN, 0xff jnz p_mesgout_start;
+ mvi MSG_NOOP call mk_mesg; /* build NOP message */
p_mesgout_start:
/*
- * Set up automatic PIO transfer from MSG0. Bit 3 in
+ * Set up automatic PIO transfer from MSG_OUT. Bit 3 in
* SXFRCTL0 (SPIOEN) is already on.
*/
- mvi SINDEX,MSG0
- mov DINDEX,MSG_LEN
+ mvi SINDEX,MSG_OUT;
+ mov DINDEX,MSG_LEN;
/*
* When target asks for a byte, drop ATN if it's the last one in
* the message. Otherwise, keep going until the message is exhausted.
+ * ATN must be dropped *at least* 90ns before we ack the last byte, so
+ * the code is aranged to execute two instructions before the byte is
+ * transferred to give a good margin of safety
*
* Keep an eye out for a phase change, in case the target issues
* a MESSAGE REJECT.
*/
p_mesgout_loop:
- test SSTAT1, REQINIT jz p_mesgout_loop
- and LASTPHASE, PHASE_MASK, SCSISIGI
- cmp LASTPHASE, P_MESGOUT jne p_mesgout_done
+ test SSTAT1, REQINIT jz p_mesgout_loop;
+ and LASTPHASE, PHASE_MASK, SCSISIGI;
+ cmp LASTPHASE, P_MESGOUT jne p_mesgout_done;
/*
* If the next bus phase after ATN drops is a message out, it means
* that the target is requesting that the last message(s) be resent.
*/
-p_mesgout_testretry:
- test DINDEX,0xff jnz p_mesgout_dropatn
- or SCSISIGO,ATNO,LASTPHASE /* turn on ATN for the retry */
- jmp p_mesgout_start
p_mesgout_dropatn:
- cmp DINDEX,1 jne p_mesgout_outb /* last byte? */
- mvi CLRSINT1,CLRATNO /* drop ATN */
+ cmp DINDEX,1 jne p_mesgout_testretry;/* last byte? */
+ mvi CLRSINT1,CLRATNO; /* drop ATN */
+p_mesgout_testretry:
+ test DINDEX,0xff jnz p_mesgout_outb;
+ or SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */
+ jmp p_mesgout_start;
p_mesgout_outb:
- mov SCSIDATL,SINDIR
- dec DINDEX
- jmp p_mesgout_loop
+ dec DINDEX;
+ mov SCSIDATL,SINDIR;
+ jmp p_mesgout_loop;
p_mesgout_done:
- mvi CLRSINT1,CLRATNO /* Be sure to turn ATNO off */
- clr MSG_LEN /* no active msg */
- jmp ITloop
+ mvi CLRSINT1,CLRATNO; /* Be sure to turn ATNO off */
+ clr MSG_LEN; /* no active msg */
+ jmp ITloop;
/*
* Message in phase. Bytes are read using Automatic PIO mode.
*/
p_mesgin:
- mvi A call inb_first /* read the 1st message byte */
- mov REJBYTE,A /* save it for the driver */
+ mvi ACCUM call inb_first; /* read the 1st message byte */
+ mov REJBYTE,A; /* save it for the driver */
- test A,MSG_IDENTIFYFLAG jnz mesgin_identify
- cmp A,MSG_DISCONNECT je mesgin_disconnect
- cmp A,MSG_SAVEDATAPOINTER je mesgin_sdptrs
- cmp ALLZEROS,A je mesgin_complete
- cmp A,MSG_RESTOREPOINTERS je mesgin_rdptrs
- cmp A,MSG_EXTENDED je mesgin_extended
- cmp A,MSG_MESSAGE_REJECT je mesgin_reject
- cmp A,MSG_NOOP je mesgin_done
+ test A,MSG_IDENTIFYFLAG jnz mesgin_identify;
+ cmp A,MSG_DISCONNECT je mesgin_disconnect;
+ cmp A,MSG_SAVEDATAPOINTER je mesgin_sdptrs;
+ cmp ALLZEROS,A je mesgin_complete;
+ cmp A,MSG_RESTOREPOINTERS je mesgin_rdptrs;
+ cmp A,MSG_EXTENDED je mesgin_extended;
+ cmp A,MSG_MESSAGE_REJECT je mesgin_reject;
+ cmp A,MSG_NOOP je mesgin_done;
rej_mesgin:
/*
@@ -591,13 +580,13 @@ rej_mesgin:
* and hope for the best. In any case, rejection should be a rare
* occurrence - signal the driver when it happens.
*/
- mvi INTSTAT,SEND_REJECT /* let driver know */
+ mvi INTSTAT,SEND_REJECT; /* let driver know */
- mvi MSG_MESSAGE_REJECT call mk_mesg
+ mvi MSG_MESSAGE_REJECT call mk_mesg;
mesgin_done:
- call inb_last
- jmp ITloop
+ mov NONE,SCSIDATL; /*dummy read from latch to ACK*/
+ jmp ITloop;
mesgin_complete:
@@ -620,63 +609,65 @@ mesgin_complete:
*/
/*
- * We expect to go to bus free after this message.
- */
- and SIMODE1, 0xf7 /* ~ENBUSFREE */
-/*
* First check for residuals
*/
- test SCB_RESID_SGCNT,0xff jnz upload_scb
- test SCB_TARGET_STATUS,0xff jz status_ok /* Good Status? */
+ test SCB_RESID_SGCNT,0xff jnz upload_scb;
+ test SCB_TARGET_STATUS,0xff jz status_ok; /* Good Status? */
upload_scb:
- mvi DMAPARAMS, 0x9 /* HDMAEN | FIFORESET*/
- mov SCB_TAG call dma_scb
+ mvi DMAPARAMS, FIFORESET;
+ mov SCB_TAG call dma_scb;
check_status:
- test SCB_TARGET_STATUS,0xff jz status_ok /* Just a residual? */
- mvi INTSTAT,BAD_STATUS /* let driver know */
- cmp RETURN_1, SEND_SENSE jne status_ok
+ test SCB_TARGET_STATUS,0xff jz status_ok; /* Just a residual? */
+ mvi INTSTAT,BAD_STATUS; /* let driver know */
+ cmp RETURN_1, SEND_SENSE jne status_ok;
/* This SCB becomes the next to execute as it will retrieve sense */
- mov SCB_LINKED_NEXT, SCB_TAG
- jmp dma_next_scb
+ mov SCB_LINKED_NEXT, SCB_TAG;
+ jmp dma_next_scb;
status_ok:
/* First, mark this target as free. */
- test SCB_CONTROL,TAG_ENB jnz complete /*
+ test SCB_CONTROL,TAG_ENB jnz complete; /*
* Tagged commands
* don't busy the
* target.
*/
- mov SAVED_SCBPTR, SCBPTR
- mov SAVED_LINKPTR, SCB_LINKED_NEXT
- mov SCB_TCL call index_untagged_scb
- mov DINDIR, SAVED_LINKPTR
- mov SCBPTR, SAVED_SCBPTR
+ mov SAVED_SCBPTR, SCBPTR;
+ mov SAVED_LINKPTR, SCB_LINKED_NEXT;
+ mov SCB_TCL call index_untagged_scb;
+ mov DINDIR, SAVED_LINKPTR;
+ mov SCBPTR, SAVED_SCBPTR;
complete:
/* Post the SCB and issue an interrupt */
- mov QOUTFIFO,SCB_TAG
- mvi INTSTAT,CMDCMPLT
- test SCB_CONTROL, ABORT_SCB jz dma_next_scb
- mvi INTSTAT ABORT_CMDCMPLT
+ mov QOUTFIFO,SCB_TAG;
+ mvi INTSTAT,CMDCMPLT;
+ test SCB_CONTROL, ABORT_SCB jz dma_next_scb;
+ mvi INTSTAT, ABORT_CMDCMPLT;
dma_next_scb:
- cmp SCB_LINKED_NEXT, SCB_LIST_NULL je add_to_free_list
- test FLAGS, PAGESCBS jnz dma_next_scb2
+ cmp SCB_LINKED_NEXT, SCB_LIST_NULL je add_to_free_list;
+.if !( SCB_PAGING )
/* Only DMA on top of ourselves if we are the SCB to download */
- mov A, SCB_LINKED_NEXT
- cmp SCB_TAG, A je dma_next_scb2
- mov SCBPTR, A
- jmp add_to_waiting_list
+ mov A, SCB_LINKED_NEXT;
+ cmp SCB_TAG, A je dma_next_scb2;
+ mov SCBPTR, A;
+ jmp add_to_waiting_list;
+.endif
dma_next_scb2:
- mvi DMAPARAMS, 0xd /* HDMAEN|DIRECTION|FIFORESET */
- mov SCB_LINKED_NEXT call dma_scb
+ mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
+ mov SCB_LINKED_NEXT call dma_scb;
add_to_waiting_list:
- mov SCB_NEXT,WAITING_SCBH
- mov WAITING_SCBH, SCBPTR
- jmp mesgin_done
+ mov SCB_NEXT,WAITING_SCBH;
+ mov WAITING_SCBH, SCBPTR;
+ /*
+ * Prepare our selection hardware before the busfree so we have a
+ * high probability of winning arbitration.
+ */
+ call start_selection;
+ jmp await_busfree;
add_to_free_list:
- call add_scb_to_free_list
- jmp mesgin_done
+ call add_scb_to_free_list;
+ jmp await_busfree;
/*
* Is it an extended message? Copy the message to our message buffer and
@@ -685,33 +676,33 @@ add_to_free_list:
* or simply to do nothing.
*/
mesgin_extended:
- mvi MSGIN_EXT_LEN call inb_next
- mov A, MSGIN_EXT_LEN
+ mvi MSGIN_EXT_LEN call inb_next;
+ mov A, MSGIN_EXT_LEN;
mesgin_extended_loop:
- mov DINDEX call inb_next
- dec A
- cmp DINDEX, MSGIN_EXT_LASTBYTE jne mesgin_extended_loop_test
- dec DINDEX /* dump by repeatedly filling the last byte */
+ mov DINDEX call inb_next;
+ dec A;
+ cmp DINDEX, MSGIN_EXT_BYTES+3 jne mesgin_extended_loop_test;
+ dec DINDEX; /* dump by repeatedly filling the last byte */
mesgin_extended_loop_test:
- test A, 0xFF jnz mesgin_extended_loop
+ test A, 0xFF jnz mesgin_extended_loop;
mesgin_extended_intr:
- mvi INTSTAT,EXTENDED_MSG /* let driver know */
- cmp RETURN_1,SEND_REJ je rej_mesgin
- cmp RETURN_1,SEND_MSG jne mesgin_done
+ mvi INTSTAT,EXTENDED_MSG; /* let driver know */
+ cmp RETURN_1,SEND_REJ je rej_mesgin;
+ cmp RETURN_1,SEND_MSG jne mesgin_done;
/* The kernel has setup a message to be sent */
- or SCSISIGO,ATNO,LASTPHASE /* turn on ATNO */
- jmp mesgin_done
+ or SCSISIGO,ATNO,LASTPHASE; /* turn on ATNO */
+ jmp mesgin_done;
/*
* Is it a disconnect message? Set a flag in the SCB to remind us
* and await the bus going free.
*/
mesgin_disconnect:
- and SIMODE1, 0xf7 /* ~ENBUSFREE */
- or SCB_CONTROL,DISCONNECTED
- test FLAGS, PAGESCBS jz mesgin_done
- call add_scb_to_disc_list
- jmp mesgin_done
+ or SCB_CONTROL,DISCONNECTED;
+.if ( SCB_PAGING )
+ call add_scb_to_disc_list;
+.endif
+ jmp await_busfree;
/*
* Save data pointers message:
@@ -721,23 +712,23 @@ mesgin_disconnect:
* since they are only initialized when we go into data_in or data_out.
*/
mesgin_sdptrs:
- test FLAGS, DPHASE jz mesgin_done
- mov SCB_SGCOUNT,SG_COUNT
+ test SEQ_FLAGS, DPHASE jz mesgin_done;
+ mov SCB_SGCOUNT,SG_COUNT;
/* The SCB SGPTR becomes the next one we'll download */
- mvi DINDEX, SCB_SGPTR
- mvi SG_NEXT0 call bcopy_4
+ mvi DINDEX, SCB_SGPTR;
+ mvi SG_NEXT call bcopy_4;
/* The SCB DATAPTR0 becomes the current SHADDR */
- mvi DINDEX, SCB_DATAPTR0
- mvi SHADDR0 call bcopy_4
+ mvi DINDEX, SCB_DATAPTR;
+ mvi SHADDR call bcopy_4;
/*
* Use the residual number since STCNT is corrupted by any message transfer.
*/
- mvi SCB_RESID_DCNT0 call bcopy_3
+ mvi SCB_RESID_DCNT call bcopy_3;
- jmp mesgin_done
+ jmp mesgin_done;
/*
* Restore pointers message? Data pointers are recopied from the
@@ -746,11 +737,12 @@ mesgin_sdptrs:
* code do the rest.
*/
mesgin_rdptrs:
- and FLAGS,0xef /*
- * !DPHASE we'll reload them
+ and SEQ_FLAGS, ~DPHASE; /*
+ * We'll reload them
* the next time through
+ * the dataphase.
*/
- jmp mesgin_done
+ jmp mesgin_done;
/*
* Identify message? For a reconnecting target, this tells us the lun
@@ -758,12 +750,13 @@ mesgin_rdptrs:
* clearing the "disconnected" bit so we don't "find" it by accident later.
*/
mesgin_identify:
- test A,0x78 jnz rej_mesgin /*!DiscPriv|!LUNTAR|!Reserved*/
- and A,0x07 /* lun in lower three bits */
- or SAVED_TCL,A /* SAVED_TCL should be complete now */
- mov SAVED_TCL call index_untagged_scb
- mov ARG_1, SINDIR
- cmp ARG_1,SCB_LIST_NULL jne use_findSCB
+ test A,0x78 jnz rej_mesgin; /*!DiscPriv|!LUNTAR|!Reserved*/
+ and A,0x07; /* lun in lower three bits */
+ or SAVED_TCL,A; /* SAVED_TCL should be complete now */
+ mov SAVED_TCL call index_untagged_scb;
+ mov ARG_1, SINDIR;
+ /* XXX Directly index in the non paging case */
+ cmp ARG_1,SCB_LIST_NULL jne use_findSCB;
/*
* Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message.
* If we get one, we use the tag returned to find the proper
@@ -772,58 +765,60 @@ mesgin_identify:
* If we're not using SCB paging, we can use the tag as the direct
* index to the SCB.
*/
- call inb_last /* ACK Identify MSG */
+ mov NONE,SCSIDATL; /* ACK Identify MSG */
snoop_tag_loop:
- test SSTAT1,REQINIT jz snoop_tag_loop
- and LASTPHASE, PHASE_MASK, SCSISIGI
- cmp LASTPHASE, P_MESGIN jne not_found
- cmp SCSIBUSL,MSG_SIMPLE_Q_TAG jne not_found
+ test SSTAT1,REQINIT jz snoop_tag_loop;
+ and LASTPHASE, PHASE_MASK, SCSISIGI;
+ cmp LASTPHASE, P_MESGIN jne not_found;
+ cmp SCSIBUSL,MSG_SIMPLE_Q_TAG jne not_found;
get_tag:
- or FLAGS, TAGGED_SCB
- mvi ARG_1 call inb_next /* tag value */
+ or SEQ_FLAGS, TAGGED_SCB;
+ mvi ARG_1 call inb_next; /* tag value */
/*
* See if the tag is in range. The tag is < SCBCOUNT if we add
* the complement of SCBCOUNT to the incomming tag and there is
* no carry.
*/
- mov A,COMP_SCBCOUNT
- add SINDEX,A,ARG_1
- jc not_found
+ mov A,COMP_SCBCOUNT;
+ add SINDEX,A,ARG_1;
+ jc not_found;
+.if ! ( SCB_PAGING )
+ jmp index_by_tag;
+.endif
/*
* Ensure that the SCB the tag points to is for an SCB transaction
* to the reconnecting target.
*/
- test FLAGS, PAGESCBS jz index_by_tag
use_findSCB:
- mov ALLZEROS call findSCB /* Have to search */
- cmp SINDEX, SCB_LIST_NULL, je not_found
+ mov ALLZEROS call findSCB; /* Have to search */
+ cmp SINDEX, SCB_LIST_NULL je not_found;
setup_SCB:
- and SCB_CONTROL,0xfb /* clear disconnect bit in SCB */
- or FLAGS,IDENTIFY_SEEN /* make note of IDENTIFY */
- jmp mesgin_done
+ and SCB_CONTROL,~DISCONNECTED;
+ or SEQ_FLAGS,IDENTIFY_SEEN; /* make note of IDENTIFY */
+ jmp mesgin_done;
index_by_tag:
- mov SCBPTR,ARG_1
- mov A, SAVED_TCL
- cmp SCB_TCL,A jne not_found
- test SCB_CONTROL,TAG_ENB jz not_found
- test SCB_CONTROL,DISCONNECTED jz not_found
- jmp setup_SCB
+ mov SCBPTR,ARG_1;
+ mov A, SAVED_TCL;
+ cmp SCB_TCL,A jne not_found;
+ test SCB_CONTROL,TAG_ENB jz not_found;
+ test SCB_CONTROL,DISCONNECTED jz not_found;
+ jmp setup_SCB;
not_found:
- mvi INTSTAT, NO_MATCH
+ mvi INTSTAT, NO_MATCH;
send_abort_msg:
- test FLAGS, TAGGED_SCB jnz send_abort_tag_msg
- mvi MSG_ABORT call mk_mesg
- jmp send_abort_done
+ test SEQ_FLAGS, TAGGED_SCB jnz send_abort_tag_msg;
+ mvi MSG_ABORT call mk_mesg;
+ jmp send_abort_done;
send_abort_tag_msg:
- mvi MSG_ABORT_TAG call mk_mesg /* ABORT TAG message */
+ mvi MSG_ABORT_TAG call mk_mesg; /* ABORT TAG message */
send_abort_done:
/* If we don't have the tag ID yet, we're "looking ahead" at state
* that hasn't been processed, so don't ack.
*/
- cmp ARG_1, SCB_LIST_NULL je ITloop
- jmp mesgin_done
+ cmp ARG_1, SCB_LIST_NULL je ITloop;
+ jmp mesgin_done;
/*
* Message reject? Let the kernel driver handle this. If we have an
@@ -832,8 +827,8 @@ send_abort_done:
* it since we have no clue what it pertains to.
*/
mesgin_reject:
- mvi INTSTAT, REJECT_MSG
- jmp mesgin_done
+ mvi INTSTAT, REJECT_MSG;
+ jmp mesgin_done;
/*
* [ ADD MORE MESSAGE HANDLING HERE ]
@@ -844,8 +839,8 @@ mesgin_reject:
* if there is no active message already. SINDEX is returned intact.
*/
mk_mesg:
- mvi SEQCTL,0x50 /* PAUSEDIS|FASTMODE */
- test MSG_LEN,0xff jz mk_mesg1 /* Should always succeed */
+ mvi SEQCTL, PAUSEDIS|FASTMODE;
+ test MSG_LEN,0xff jz mk_mesg1; /* Should always succeed */
/*
* Hmmm. For some reason the mesg buffer is in use.
@@ -853,14 +848,14 @@ mk_mesg:
* out what we wanted to use the buffer for and resolve
* the conflict.
*/
- mvi SEQCTL,0x10 /* !PAUSEDIS|FASTMODE */
- mvi INTSTAT,MSG_BUFFER_BUSY
+ mvi SEQCTL,FASTMODE;
+ mvi INTSTAT,MSG_BUFFER_BUSY;
mk_mesg1:
- or SCSISIGO,ATNO,LASTPHASE /* turn on ATNO */
- mvi MSG_LEN,1 /* length = 1 */
- mov MSG0,SINDEX /* 1-byte message */
- mvi SEQCTL,0x10 ret /* !PAUSEDIS|FASTMODE */
+ or SCSISIGO,ATNO,LASTPHASE;/* turn on ATNO */
+ mvi MSG_LEN,1; /* length = 1 */
+ mov MSG_OUT,SINDEX; /* 1-byte message */
+ mvi SEQCTL,FASTMODE ret;
/*
* Functions to read data in Automatic PIO mode.
@@ -879,29 +874,29 @@ mk_mesg1:
*/
inb_next:
- mov NONE,SCSIDATL /*dummy read from latch to ACK*/
+ mov NONE,SCSIDATL; /*dummy read from latch to ACK*/
inb_next_wait:
/*
* If there is a parity error, wait for the kernel to
* see the interrupt and prepare our message response
* before continuing.
*/
- test SSTAT1, REQINIT jz inb_next_wait
- test SSTAT1, SCSIPERR jnz inb_next_wait
- and LASTPHASE, PHASE_MASK, SCSISIGI
- cmp LASTPHASE, P_MESGIN jne mesgin_phasemis
+ test SSTAT1, REQINIT jz inb_next_wait;
+ test SSTAT1, SCSIPERR jnz inb_next_wait;
+ and LASTPHASE, PHASE_MASK, SCSISIGI;
+ cmp LASTPHASE, P_MESGIN jne mesgin_phasemis;
inb_first:
- mov DINDEX,SINDEX
- mov DINDIR,SCSIBUSL ret /*read byte directly from bus*/
+ mov DINDEX,SINDEX;
+ mov DINDIR,SCSIBUSL ret; /*read byte directly from bus*/
inb_last:
- mov NONE,SCSIDATL ret /*dummy read from latch to ACK*/
+ mov NONE,SCSIDATL ret; /*dummy read from latch to ACK*/
mesgin_phasemis:
/*
* We expected to receive another byte, but the target changed phase
*/
- mvi INTSTAT, MSGIN_PHASEMIS
- jmp ITloop
+ mvi INTSTAT, MSGIN_PHASEMIS;
+ jmp ITloop;
/*
* DMA data transfer. HADDR and HCNT must be loaded first, and
@@ -910,13 +905,13 @@ mesgin_phasemis:
* during initialization.
*/
dma:
- mov DFCNTRL,SINDEX
+ mov DFCNTRL,SINDEX;
dma_loop:
- test SSTAT0,DMADONE jnz dma_dmadone
- test SSTAT1,PHASEMIS jz dma_loop /* ie. underrun */
+ test SSTAT0,DMADONE jnz dma_dmadone;
+ test SSTAT1,PHASEMIS jz dma_loop; /* ie. underrun */
dma_phasemis:
- test SSTAT0,SDONE jnz dma_checkfifo
- mov SINDEX,ALLZEROS /* Notify caller of phasemiss */
+ test SSTAT0,SDONE jnz dma_checkfifo;
+ mov SINDEX,ALLZEROS; /* Notify caller of phasemiss */
/*
* We will be "done" DMAing when the transfer count goes to zero, or
@@ -927,45 +922,33 @@ dma_phasemis:
* status.
*/
dma_checkfifo:
- test DFCNTRL,DIRECTION jnz dma_fifoempty
+ test DFCNTRL,DIRECTION jnz dma_fifoempty;
dma_fifoflush:
- test DFSTATUS,FIFOEMP jz dma_fifoflush
+ test DFSTATUS,FIFOEMP jz dma_fifoflush;
dma_fifoempty:
/* Don't clobber an inprogress host data transfer */
- test DFSTATUS, MREQPEND jnz dma_fifoempty
+ test DFSTATUS, MREQPEND jnz dma_fifoempty;
/*
* Now shut the DMA enables off and make sure that the DMA enables are
* actually off first lest we get an ILLSADDR.
*/
dma_dmadone:
- and DFCNTRL, 0xc7 /* ~(SCSIEN|SDMAEN|HDMAEN) */
+ and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN);
dma_halt:
- test DFCNTRL, 0x38 jnz dma_halt /* (SCSIEN|SDMAEN|HDMAEN) */
+ test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt;
return:
- ret
-
-/*
- * Common SCSI initialization for selection and reselection. Expects
- * the target SCSI ID to be in the upper four bits of SINDEX, and A's
- * contents are stomped on return.
- */
-initialize_scsiid:
- and SINDEX,0xf0 /* Get target ID */
- mov SAVED_TCL, SINDEX /* Update the target portion of this */
- and A,0x0f,SCSIID
- or SINDEX,A
- mov SCSIID,SINDEX ret
+ ret;
/*
* Assert that if we've been reselected, then we've seen an IDENTIFY
* message.
*/
assert:
- test FLAGS,RESELECTED jz return /* reselected? */
- test FLAGS,IDENTIFY_SEEN jnz return /* seen IDENTIFY? */
+ test SEQ_FLAGS,RESELECTED jz return; /* reselected? */
+ test SEQ_FLAGS,IDENTIFY_SEEN jnz return; /* seen IDENTIFY? */
- mvi INTSTAT,NO_IDENT ret /* no - tell the kernel */
+ mvi INTSTAT,NO_IDENT ret; /* no - tell the kernel */
/*
* Locate a disconnected SCB either by SAVED_TCL (ARG_1 is SCB_LIST_NULL)
@@ -974,167 +957,175 @@ assert:
* otherwise, SCBPTR is set to the proper SCB.
*/
findSCB:
- mov SCBPTR,SINDEX /* switch to next SCB */
- mov A, ARG_1 /* Tag passed in ARG_1 */
- cmp SCB_TAG,A jne findSCB_loop
- test SCB_CONTROL,DISCONNECTED jnz foundSCB /*should be disconnected*/
+ mov SCBPTR,SINDEX; /* switch to next SCB */
+ mov A, ARG_1; /* Tag passed in ARG_1 */
+ cmp SCB_TAG,A jne findSCB_loop;
+ test SCB_CONTROL,DISCONNECTED jnz foundSCB;/*should be disconnected*/
findSCB_loop:
- inc SINDEX
- mov A,SCBCOUNT
- cmp SINDEX,A jne findSCB
+ inc SINDEX;
+ mov A,SCBCOUNT;
+ cmp SINDEX,A jne findSCB;
/*
* We didn't find it. If we're paging, pull an SCB and DMA down the
* one we want. If we aren't paging or the SCB we dma down has the
* abort flag set, return not found.
*/
- test FLAGS, PAGESCBS jz find_error
- mov ALLZEROS call get_free_or_disc_scb
- mvi DMAPARAMS, 0xd /* HDMAEN|DIRECTION|FIFORESET */
- mov ARG_1 call dma_scb
- test SCB_CONTROL, ABORT_SCB jz return
+.if ( SCB_PAGING )
+ mov ALLZEROS call get_free_or_disc_scb;
+ mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
+ mov ARG_1 call dma_scb;
+ test SCB_CONTROL, ABORT_SCB jz return;
+.endif
find_error:
- mvi SINDEX, SCB_LIST_NULL ret
+ mvi SINDEX, SCB_LIST_NULL ret;
foundSCB:
- test SCB_CONTROL, ABORT_SCB jnz find_error
- test FLAGS,PAGESCBS jz return
+ test SCB_CONTROL, ABORT_SCB jnz find_error;
+.if ( SCB_PAGING )
rem_scb_from_disc_list:
/* Remove this SCB from the disconnection list */
- cmp SCB_NEXT,SCB_LIST_NULL je unlink_prev
- mov SAVED_LINKPTR, SCB_PREV
- mov SCBPTR, SCB_NEXT
- mov SCB_PREV, SAVED_LINKPTR
- mov SCBPTR, SINDEX
+ cmp SCB_NEXT,SCB_LIST_NULL je unlink_prev;
+ mov SAVED_LINKPTR, SCB_PREV;
+ mov SCBPTR, SCB_NEXT;
+ mov SCB_PREV, SAVED_LINKPTR;
+ mov SCBPTR, SINDEX;
unlink_prev:
- cmp SCB_PREV,SCB_LIST_NULL je rHead/* At the head of the list */
- mov SAVED_LINKPTR, SCB_NEXT
- mov SCBPTR, SCB_PREV
- mov SCB_NEXT, SAVED_LINKPTR
- mov SCBPTR, SINDEX ret
+ cmp SCB_PREV,SCB_LIST_NULL je rHead;/* At the head of the list */
+ mov SAVED_LINKPTR, SCB_NEXT;
+ mov SCBPTR, SCB_PREV;
+ mov SCB_NEXT, SAVED_LINKPTR;
+ mov SCBPTR, SINDEX ret;
rHead:
- mov DISCONNECTED_SCBH,SCB_NEXT ret
+ mov DISCONNECTED_SCBH,SCB_NEXT ret;
+.else
+ ret;
+.endif
set_stcnt_from_hcnt:
- mov STCNT0, HCNT0
- mov STCNT1, HCNT1
- mov STCNT2, HCNT2 ret
+ mov STCNT[0], HCNT[0];
+ mov STCNT[1], HCNT[1];
+ mov STCNT[2], HCNT[2] ret;
bcopy_7:
- mov DINDIR, SINDIR
- mov DINDIR, SINDIR
+ mov DINDIR, SINDIR;
+ mov DINDIR, SINDIR;
bcopy_5:
- mov DINDIR, SINDIR
+ mov DINDIR, SINDIR;
bcopy_4:
- mov DINDIR, SINDIR
+ mov DINDIR, SINDIR;
bcopy_3:
- mov DINDIR, SINDIR
- mov DINDIR, SINDIR
- mov DINDIR, SINDIR ret
+ mov DINDIR, SINDIR;
+ mov DINDIR, SINDIR;
+ mov DINDIR, SINDIR ret;
dma_scb:
/*
* SCB index is in SINDEX. Determine the physical address in
* the host where this SCB is located and load HADDR with it.
*/
- shr DINDEX, SINDEX, 3
- shl A, SINDEX, 5
- add HADDR0, A, HSCB_ADDR0
- mov A, DINDEX
- adc HADDR1, A, HSCB_ADDR1
- clr A
- adc HADDR2, A, HSCB_ADDR2
- adc HADDR3, A, HSCB_ADDR3
+ shr DINDEX, 3, SINDEX;
+ shl A, 5, SINDEX;
+ add HADDR[0], A, HSCB_ADDR[0];
+ mov A, DINDEX;
+ adc HADDR[1], A, HSCB_ADDR[1];
+ clr A;
+ adc HADDR[2], A, HSCB_ADDR[2];
+ adc HADDR[3], A, HSCB_ADDR[3];
/* Setup Count */
- mvi HCNT0, 28
- clr HCNT1
- clr HCNT2
- mov DFCNTRL, DMAPARAMS
- test DMAPARAMS, DIRECTION jnz dma_scb_fromhost
+ mvi HCNT[0], 28;
+ clr HCNT[1];
+ clr HCNT[2];
+ mov DFCNTRL, DMAPARAMS;
+ test DMAPARAMS, DIRECTION jnz dma_scb_fromhost;
/* Fill it with the SCB data */
- call copy_scb_tofifo
- mvi DFCNTRL, 0xa /* HDMAEN | FIFOFLUSH */
+ call copy_scb_tofifo;
+ or DFCNTRL, HDMAEN|FIFOFLUSH;
dma_scb_fromhost:
- call dma_finish
+ call dma_finish;
/* If we were putting the SCB, we are done */
- test DMAPARAMS, DIRECTION jz return
- mvi SCBARRAY call dfdat_in_7
- call dfdat_in_7_continued
- call dfdat_in_7_continued
- jmp dfdat_in_7_continued
+ test DMAPARAMS, DIRECTION jz return;
+ mvi SCB_CONTROL call dfdat_in_7;
+ call dfdat_in_7_continued;
+ call dfdat_in_7_continued;
+ jmp dfdat_in_7_continued;
dfdat_in_7:
- mov DINDEX,SINDEX
+ mov DINDEX,SINDEX;
dfdat_in_7_continued:
- mov DINDIR,DFDAT
- mov DINDIR,DFDAT
- mov DINDIR,DFDAT
- mov DINDIR,DFDAT
- mov DINDIR,DFDAT
- mov DINDIR,DFDAT
- mov DINDIR,DFDAT ret
+ mov DINDIR,DFDAT;
+ mov DINDIR,DFDAT;
+ mov DINDIR,DFDAT;
+ mov DINDIR,DFDAT;
+ mov DINDIR,DFDAT;
+ mov DINDIR,DFDAT;
+ mov DINDIR,DFDAT ret;
copy_scb_tofifo:
- mvi SCBARRAY call dfdat_out_7
- call dfdat_out_7
- call dfdat_out_7
+ mvi SCB_CONTROL call dfdat_out_7;
+ call dfdat_out_7;
+ call dfdat_out_7;
dfdat_out_7:
- mov DFDAT,SINDIR
- mov DFDAT,SINDIR
- mov DFDAT,SINDIR
- mov DFDAT,SINDIR
- mov DFDAT,SINDIR
- mov DFDAT,SINDIR
- mov DFDAT,SINDIR ret
+ mov DFDAT,SINDIR;
+ mov DFDAT,SINDIR;
+ mov DFDAT,SINDIR;
+ mov DFDAT,SINDIR;
+ mov DFDAT,SINDIR;
+ mov DFDAT,SINDIR;
+ mov DFDAT,SINDIR ret;
/*
* Wait for DMA from host memory to data FIFO to complete, then disable
* DMA and wait for it to acknowledge that it's off.
*/
dma_finish:
- test DFSTATUS,HDONE jz dma_finish
+ test DFSTATUS,HDONE jz dma_finish;
/* Turn off DMA */
- and DFCNTRL, 0xf7 ret # ~HDMAEN
+ and DFCNTRL, ~HDMAEN;
+ test DFCNTRL, HDMAEN jnz .;
+ ret;
index_untagged_scb:
- mov DINDEX, SINDEX
- shr DINDEX, 4
- and DINDEX, 0x03 /* Bottom two bits of tid */
- add DINDEX, SCB_ACTIVE0
- shr A, SINDEX, 6 /* Target ID divided by 4 */
- test SINDEX, SELBUSB jz index_untagged_scb2
- add A, 2 /* Add 2 positions */
+ mov DINDEX, SINDEX;
+ shr DINDEX, 4;
+ and DINDEX, 0x03; /* Bottom two bits of tid */
+ add DINDEX, SCB_BUSYTARGETS;
+ shr A, 6, SINDEX; /* Target ID divided by 4 */
+ test SINDEX, SELBUSB jz index_untagged_scb2;
+ add A, 2; /* Add 2 positions */
index_untagged_scb2:
- mov SCBPTR, A /*
+ mov SCBPTR, A; /*
* Select the SCB with this
* target's information.
*/
- mov SINDEX, DINDEX ret
+ mov SINDEX, DINDEX ret;
+add_scb_to_free_list:
+ mov SCB_NEXT, FREE_SCBH;
+ mvi SCB_TAG, SCB_LIST_NULL;
+ mov FREE_SCBH, SCBPTR ret;
+.if ( SCB_PAGING )
get_free_or_disc_scb:
- cmp FREE_SCBH, SCB_LIST_NULL jne dequeue_free_scb
- cmp DISCONNECTED_SCBH, SCB_LIST_NULL jne dequeue_disc_scb
+ cmp FREE_SCBH, SCB_LIST_NULL jne dequeue_free_scb;
+ cmp DISCONNECTED_SCBH, SCB_LIST_NULL jne dequeue_disc_scb;
return_error:
- mvi SINDEX, SCB_LIST_NULL ret
+ mvi SINDEX, SCB_LIST_NULL ret;
dequeue_disc_scb:
- mov SCBPTR, DISCONNECTED_SCBH
+ mov SCBPTR, DISCONNECTED_SCBH;
/*
* If we have a residual, then we are in the middle of some I/O
* and we have to send this SCB back up to the kernel so that the
* saved data pointers and residual information isn't lost.
*/
- test SCB_RESID_SGCNT,0xff jz unlink_disc_scb
- mvi DMAPARAMS, 0x9 /* HDMAEN | FIFORESET*/
- mov SCB_TAG call dma_scb
+ test SCB_RESID_SGCNT,0xff jnz dma_up_scb;
+ cmp SCB_LINKED_NEXT, SCB_LIST_NULL je unlink_disc_scb;
+dma_up_scb:
+ mvi DMAPARAMS, FIFORESET;
+ mov SCB_TAG call dma_scb;
unlink_disc_scb:
/* jmp instead of call since we want to return anyway */
- mov SCBPTR jmp rem_scb_from_disc_list
+ mov SCBPTR jmp rem_scb_from_disc_list;
dequeue_free_scb:
- mov SCBPTR, FREE_SCBH
- mov FREE_SCBH, SCB_NEXT ret
-
-add_scb_to_free_list:
- mov SCB_NEXT, FREE_SCBH
- mvi SCB_TAG, SCB_LIST_NULL
- mov FREE_SCBH, SCBPTR ret
+ mov SCBPTR, FREE_SCBH;
+ mov FREE_SCBH, SCB_NEXT ret;
add_scb_to_disc_list:
/*
@@ -1142,11 +1133,11 @@ add_scb_to_disc_list:
* candidates for paging out an SCB if one is needed for a new command.
* Modifying the disconnected list is a critical(pause dissabled) section.
*/
- mvi SCB_PREV, SCB_LIST_NULL
- mov SCB_NEXT, DISCONNECTED_SCBH
- mov DISCONNECTED_SCBH, SCBPTR
- cmp SCB_NEXT,SCB_LIST_NULL je return
- mov SCBPTR,SCB_NEXT
- mov SCB_PREV,DISCONNECTED_SCBH
- mov SCBPTR,DISCONNECTED_SCBH ret
-
+ mvi SCB_PREV, SCB_LIST_NULL;
+ mov SCB_NEXT, DISCONNECTED_SCBH;
+ mov DISCONNECTED_SCBH, SCBPTR;
+ cmp SCB_NEXT,SCB_LIST_NULL je return;
+ mov SCBPTR,SCB_NEXT;
+ mov SCB_PREV,DISCONNECTED_SCBH;
+ mov SCBPTR,DISCONNECTED_SCBH ret;
+.endif
diff --git a/sys/dev/aic7xxx/aic7xxx_asm.1 b/sys/dev/aic7xxx/aic7xxx_asm.1
deleted file mode 100644
index 2ff33b7819005..0000000000000
--- a/sys/dev/aic7xxx/aic7xxx_asm.1
+++ /dev/null
@@ -1,70 +0,0 @@
-.\" 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.
-.\" 2. Redistributions in binary form must reproduce the above copyright
-.\" notice, this list of conditions and the following disclaimer in the
-.\" documentation and/or other materials provided with the distribution.
-.\" 3. The name of the author may not be used to endorse or promote products
-.\" derived from this software without specific prior written permission.
-.\"
-.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
-.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
-.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-.\"
-.\"
-.Dd November 11, 1994
-.Dt AIC7XXX_ASM 1
-.Os BSD 4
-.Sh NAME
-.Nm aic7xxx_asm
-.Nd Assembler for the Adaptec aic7xxx family of asics
-.Sh SYNOPSIS
-.Nm aic7xxx_asm
-.Op Fl d
-.Op Fl D Ar variable=value
-.Op Fl v
-.Op Fl o Ar file
-.Ar source-file
-.Sh DESCRIPTION
-The Adaptec aic7xxx family of asics are single chip SCSI controllers with a
-RISC like command processor. This assembler parses the language outlined
-in the Adaptec technical document
-.%T "AIC-7770 (EISA/ISA Bus Master Single-Chip SCSI Host Adaptor) Data Book"
-and produces ascii output intended for a C byte array.
-.Pp
-The aic7xxx assembler is required to compile kernels with aic7xxx SCSI
-adaptor support (AHA-274x, AHA-284x, AHA-294x controllers) and is compiled,
-installed, and used automatically in the kernel compile directory when
-necessary.
-.Pp
-The options are as follows:
-.Bl -tag -width Ds
-.It Fl D Ar variable=value
-Define
-.Ar variable
-to be
-.Ar value
-in the global context
-.It Fl d
-Turn on debugging
-.It Fl v
-Print version information
-.It Fl o Ar file
-Redirect assembler output to
-.Ar file
-.Pp
-.Sh AUTHOR
-This aic7770 assembler was written by
-John Aycock (aycock@cpsc.ucalgary.ca)
diff --git a/sys/dev/aic7xxx/aic7xxx_asm.c b/sys/dev/aic7xxx/aic7xxx_asm.c
index d3e09f6aeba03..efed828a13a3a 100644
--- a/sys/dev/aic7xxx/aic7xxx_asm.c
+++ b/sys/dev/aic7xxx/aic7xxx_asm.c
@@ -1,31 +1,26 @@
-/*+M*************************************************************************
- * Adaptec AIC7770/AIC7870 sequencer code assembler.
+/*
+ * Aic7xxx SCSI host adapter firmware asssembler
*
- * Copyright (c) 1994 John Aycock
- * The University of Calgary Department of Computer Science.
- * All rights reserved.
+ * Copyright (c) 1997 Justin T. Gibbs.
+ * All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer.
+ * 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. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of Calgary
- * Department of Computer Science and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * 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
@@ -33,653 +28,380 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * Comments are started by `#' and continue to the end of the line; lines
- * may be of the form:
- * <label>*
- * <label>* <undef-sym> = <value>
- * <label>* <opcode> <operand>*
- *
- * A <label> is an <undef-sym> ending in a colon. Spaces, tabs, and commas
- * are token separators.
- *
- *-M*************************************************************************/
-static char id[] = "$Id$";
-#include <ctype.h>
+ * $Id$
+ */
+#include <sys/types.h>
+#include <sys/mman.h>
+
#include <stdio.h>
-#include <string.h>
#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
#include <unistd.h>
-#include <fcntl.h>
-#define MEMORY 448
-#define MAXLINE 1024
-#define MAXTOKEN 32
-#define ADOTOUT "a.out"
-#define NOVALUE -1
+#include "aic7xxx_asm.h"
+#include "symbol.h"
+#include "sequencer.h"
-/*
- * AIC-7770/AIC-7870 register definitions
- */
-#define R_SINDEX 0x65
-#define R_ALLONES 0x69
-#define R_ALLZEROS 0x6a
-#define R_NONE 0x6a
+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));
-int debug;
-int lineno, LC;
-char *filename;
-unsigned char M[MEMORY][4];
+struct path_list search_path;
+int includes_search_curdir;
+char *appname;
+FILE *ofile;
+char *ofilename;
-void
-error(char *s)
-{
- fprintf(stderr, "%s: %s at line %d\n", filename, s, lineno);
- exit(EXIT_FAILURE);
-}
+static STAILQ_HEAD(,instruction) seq_program;
+static STAILQ_HEAD(, patch) patch_list;
+symlist_t patch_options;
-void *
-Malloc(size_t size)
-{
- void *p = malloc(size);
- if (!p)
- error("out of memory");
- return(p);
-}
+#if DEBUG
+extern int yy_flex_debug;
+extern int yydebug;
+#endif
+extern FILE *yyin;
+extern int yyparse __P((void));
-void *
-Realloc(void *ptr, size_t size)
-{
- void *p = realloc(ptr, size);
- if (!p)
- error("out of memory");
- return(p);
-}
-
-char *
-Strdup(char *s)
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
{
- char *p = (char *)Malloc(strlen(s) + 1);
- strcpy(p, s);
- return(p);
-}
+ extern char *optarg;
+ extern int optind;
+ int ch;
+ int retval;
+ char *inputfilename;
+ char *regfilename;
+ FILE *regfile;
+ char *listfilename;
+ FILE *listfile;
-typedef struct sym_t {
- struct sym_t *next; /* MUST BE FIRST */
- char *name;
- int value;
- int npatch;
- int *patch;
-} sym_t;
-
-sym_t *head;
-
-void
-define(char *name, int value)
-{
- sym_t *p, *q;
+ SLIST_INIT(&search_path);
+ STAILQ_INIT(&seq_program);
+ STAILQ_INIT(&patch_list);
+ SLIST_INIT(&patch_options);
+ includes_search_curdir = 1;
+ appname = *argv;
+ regfile = NULL;
+ listfile = NULL;
+#if DEBUG
+ yy_flex_debug = 0;
+#endif
+ while ((ch = getopt(argc, argv, "d:l:n:o:r:I:")) != EOF) {
+ switch(ch) {
+ case 'd':
+#if DEBUG
+ if (strcmp(optarg, "s") == 0)
+ yy_flex_debug = 1;
+ else if (strcmp(optarg, "p") == 0)
+ yydebug = 1;
+#else
+ stop("-d: Assembler not built with debugging "
+ "information", EX_SOFTWARE);
+#endif
+ break;
+ case 'l':
+ /* Create a program listing */
+ if ((listfile = fopen(optarg, "w")) == NULL) {
+ perror(optarg);
+ stop(NULL, EX_CANTCREAT);
+ }
+ listfilename = optarg;
+ break;
+ case 'n':
+ /* Don't complain about the -nostdinc directrive */
+ if (strcmp(optarg, "ostdinc")) {
+ fprintf(stderr, "%s: Unknown option -%c%s\n",
+ appname, ch, optarg);
+ usage();
+ /* NOTREACHED */
+ }
+ break;
+ case 'o':
+ if ((ofile = fopen(optarg, "w")) == NULL) {
+ perror(optarg);
+ stop(NULL, EX_CANTCREAT);
+ }
+ ofilename = optarg;
+ break;
+ case 'r':
+ if ((regfile = fopen(optarg, "w")) == NULL) {
+ perror(optarg);
+ stop(NULL, EX_CANTCREAT);
+ }
+ regfilename = optarg;
+ break;
+ case 'I':
+ {
+ path_entry_t include_dir;
- for (p = head, q = (sym_t *)&head; p; p = p->next) {
- if (!strcmp(p->name, name))
- error("redefined symbol");
- q = p;
+ if (strcmp(optarg, "-") == 0) {
+ if (includes_search_curdir == 0) {
+ fprintf(stderr, "%s: Warning - '-I-' "
+ "specified multiple "
+ "times\n", appname);
+ }
+ includes_search_curdir = 0;
+ for (include_dir = search_path.slh_first;
+ include_dir != NULL;
+ include_dir = include_dir->links.sle_next)
+ /*
+ * All entries before a '-I-' only
+ * apply to includes specified with
+ * quotes instead of "<>".
+ */
+ include_dir->quoted_includes_only = 1;
+ } else {
+ include_dir =
+ (path_entry_t)malloc(sizeof(*include_dir));
+ if (include_dir == NULL) {
+ perror(optarg);
+ stop(NULL, EX_OSERR);
+ }
+ include_dir->directory = strdup(optarg);
+ if (include_dir->directory == NULL) {
+ perror(optarg);
+ stop(NULL, EX_OSERR);
+ }
+ include_dir->quoted_includes_only = 0;
+ SLIST_INSERT_HEAD(&search_path, include_dir,
+ links);
+ }
+ break;
+ }
+ case '?':
+ default:
+ usage();
+ /* NOTREACHED */
+ }
}
+ argc -= optind;
+ argv += optind;
- p = q->next = (sym_t *)Malloc(sizeof(sym_t));
- p->next = NULL;
- p->name = Strdup(name);
- p->value = value;
- p->npatch = 0;
- p->patch = NULL;
-
- if (debug) {
- fprintf(stderr, "\"%s\" ", p->name);
- if (p->value != NOVALUE)
- fprintf(stderr, "defined as 0x%x\n", p->value);
- else
- fprintf(stderr, "undefined\n");
+ if (argc != 1) {
+ fprintf(stderr, "%s: No input file specifiled\n", appname);
+ usage();
+ /* NOTREACHED */
}
-}
-sym_t *
-lookup(char *name)
-{
- sym_t *p;
+ symtable_open();
+ inputfilename = *argv;
+ include_file(*argv, SOURCE_FILE);
+ retval = yyparse();
+ if (retval == 0) {
+ back_patch();
+ if (ofile != NULL)
+ output_code(ofile);
+ if (regfile != NULL)
+ symtable_dump(regfile);
+ if (listfile != NULL)
+ output_listing(listfile, inputfilename);
+ }
- for (p = head; p; p = p->next)
- if (!strcmp(p->name, name))
- return(p);
- return(NULL);
+ stop(NULL, 0);
+ /* NOTREACHED */
+ return (0);
}
-void
-patch(sym_t *p, int location)
+static void
+usage()
{
- p->npatch += 1;
- p->patch = (int *)Realloc(p->patch, p->npatch * sizeof(int *));
- p->patch[p->npatch - 1] = location;
+ (void)fprintf(stderr, "usage: %s [-I directory] [-o output_file] "
+ "input_file\n", appname);
+ exit(EX_USAGE);
}
-void backpatch(void)
+static void
+back_patch()
{
- int i;
- sym_t *p;
+ struct instruction *cur_instr;
- for (p = head; p; p = p->next) {
+ for(cur_instr = seq_program.stqh_first;
+ cur_instr != NULL;
+ cur_instr = cur_instr->links.stqe_next) {
+ if (cur_instr->patch_label != NULL) {
+ struct ins_format3 *f3_instr;
+ u_int address;
- if (p->value == NOVALUE) {
- fprintf(stderr,
- "%s: undefined symbol \"%s\"\n",
- filename, p->name);
- exit(EXIT_FAILURE);
- }
+ if (cur_instr->patch_label->type != LABEL) {
+ char buf[255];
- if (p->npatch) {
- if (debug)
- fprintf(stderr,
- "\"%s\" (0x%x) patched at",
- p->name, p->value);
-
- for (i = 0; i < p->npatch; i++) {
- M[p->patch[i]][0] &= ~1;
- M[p->patch[i]][0] |= ((p->value >> 8) & 1);
- M[p->patch[i]][1] = p->value & 0xff;
-
- if (debug)
- fprintf(stderr, " 0x%x", p->patch[i]);
+ snprintf(buf, sizeof(buf),
+ "Undefined label %s",
+ cur_instr->patch_label->name);
+ stop(buf, EX_DATAERR);
+ /* NOTREACHED */
}
-
- if (debug)
- fputc('\n', stderr);
+ f3_instr = &cur_instr->format.format3;
+ address = ((f3_instr->opcode_addr & ADDR_HIGH_BIT) << 8)
+ | f3_instr->address;
+ address += cur_instr->patch_label->info.linfo->address;
+ f3_instr->opcode_addr &= ~ADDR_HIGH_BIT;
+ f3_instr->opcode_addr |= (address >> 8) & ADDR_HIGH_BIT;
+ f3_instr->address = address & 0xFF;
}
}
}
-/*
- * Output words in byte-reversed order (least significant first)
- * since the sequencer RAM is loaded that way.
- */
-void
-output(FILE *fp)
-{
- int i;
-
- for (i = 0; i < LC; i++)
- fprintf(fp, "\t0x%02x, 0x%02x, 0x%02x, 0x%02x,\n",
- M[i][3],
- M[i][2],
- M[i][1],
- M[i][0]);
- printf("%d out of %d instructions used.\n", LC, MEMORY);
-}
-
-char **
-getl(int *n)
+static void
+output_code(ofile)
+ FILE *ofile;
{
- int i;
- char *p, *quote;
- static char buf[MAXLINE];
- static char *a[MAXTOKEN];
-
- i = 0;
-
- while (fgets(buf, sizeof(buf), stdin)) {
-
- lineno += 1;
+ struct instruction *cur_instr;
+ patch_t *cur_patch;
+ symbol_node_t *cur_node;
+ int instrcount;
- if (buf[strlen(buf)-1] != '\n')
- error("line too long");
+ instrcount = 0;
+ fprintf(ofile,
+"/*
+ * DO NOT EDIT - This file is automatically generated.
+ */\n");
- p = strchr(buf, '#');
- if (p)
- *p = '\0';
- p = buf;
-rescan:
- quote = strchr(p, '\"');
- if (quote)
- *quote = '\0';
- for (p = strtok(p, ", \t\n"); p; p = strtok(NULL, ", \t\n"))
- if (i < MAXTOKEN-1)
- a[i++] = p;
- else
- error("too many tokens");
- if (quote) {
- quote++;
- p = strchr(quote, '\"');
- if (!p)
- error("unterminated string constant");
- else if (i < MAXTOKEN-1) {
- a[i++] = quote;
- *p = '\0';
- p++;
- }
- else
- error("too many tokens");
- goto rescan;
- }
- if (i) {
- *n = i;
- return(a);
- }
+ fprintf(ofile, "static u_int8_t seqprog[] = {\n");
+ for(cur_instr = seq_program.stqh_first;
+ cur_instr != NULL;
+ cur_instr = cur_instr->links.stqe_next) {
+ fprintf(ofile, "\t0x%02x, 0x%02x, 0x%02x, 0x%02x,\n",
+ cur_instr->format.bytes[0],
+ cur_instr->format.bytes[1],
+ cur_instr->format.bytes[2],
+ cur_instr->format.bytes[3]);
+ instrcount++;
}
- return(NULL);
-}
+ fprintf(ofile, "};\n");
-#define A 0x8000 /* `A'ccumulator ok */
-#define I 0x4000 /* use as immediate value */
-#define SL 0x2000 /* shift left */
-#define SR 0x1000 /* shift right */
-#define RL 0x0800 /* rotate left */
-#define RR 0x0400 /* rotate right */
-#define LO 0x8000 /* lookup: ori-{jmp,jc,jnc,call} */
-#define LA 0x4000 /* lookup: and-{jz,jnz} */
-#define LX 0x2000 /* lookup: xor-{je,jne} */
-#define NA -1 /* not applicable */
-
-struct {
- char *name;
- int n; /* number of operands, including opcode */
- unsigned int op; /* immediate or L?|pos_from_0 */
- unsigned int dest; /* NA, pos_from_0, or I|immediate */
- unsigned int src; /* NA, pos_from_0, or I|immediate */
- unsigned int imm; /* pos_from_0, A|pos_from_0, or I|immediate */
- unsigned int addr; /* NA or pos_from_0 */
- int fmt; /* instruction format - 1, 2, or 3 */
-} instr[] = {
-/*
- * N OP DEST SRC IMM ADDR FMT
- */
- { "mov", 3, 1, 1, 2, I|0xff, NA, 1 },
- { "mov", 4, LO|2, NA, 1, I|0, 3, 3 },
- { "mvi", 3, 0, 1, I|R_ALLZEROS, A|2, NA, 1 },
- { "mvi", 4, LO|2, NA, I|R_ALLZEROS, 1, 3, 3 },
- { "not", 2, 2, 1, 1, I|0xff, NA, 1 },
- { "and", 3, 1, 1, 1, A|2, NA, 1 },
- { "and", 4, 1, 1, 3, A|2, NA, 1 },
- { "or", 3, 0, 1, 1, A|2, NA, 1 },
- { "or", 4, 0, 1, 3, A|2, NA, 1 },
- { "or", 5, LO|3, NA, 1, 2, 4, 3 },
- { "xor", 3, 2, 1, 1, A|2, NA, 1 },
- { "xor", 4, 2, 1, 3, A|2, NA, 1 },
- { "nop", 1, 1, I|R_NONE, I|R_ALLZEROS, I|0xff, NA, 1 },
- { "inc", 2, 3, 1, 1, I|1, NA, 1 },
- { "inc", 3, 3, 1, 2, I|1, NA, 1 },
- { "dec", 2, 3, 1, 1, I|0xff, NA, 1 },
- { "dec", 3, 3, 1, 2, I|0xff, NA, 1 },
- { "jmp", 2, LO|0, NA, I|R_SINDEX, I|0, 1, 3 },
- { "jc", 2, LO|0, NA, I|R_SINDEX, I|0, 1, 3 },
- { "jnc", 2, LO|0, NA, I|R_SINDEX, I|0, 1, 3 },
- { "call", 2, LO|0, NA, I|R_SINDEX, I|0, 1, 3 },
- { "test", 5, LA|3, NA, 1, A|2, 4, 3 },
- { "cmp", 5, LX|3, NA, 1, A|2, 4, 3 },
- { "ret", 1, 1, I|R_NONE, I|R_ALLZEROS, I|0xff, NA, 1 },
- { "ret", 1, 1, I|R_NONE, I|R_ALLZEROS, I|0xff, NA, 1 },
- { "clc", 1, 3, I|R_NONE, I|R_ALLZEROS, I|1, NA, 1 },
- { "clc", 4, 3, 2, I|R_ALLZEROS, A|3, NA, 1 },
- { "stc", 2, 3, 1, I|R_ALLONES, I|1, NA, 1 },
- { "add", 3, 3, 1, 1, A|2, NA, 1 },
- { "add", 4, 3, 1, 3, A|2, NA, 1 },
- { "adc", 3, 4, 1, 1, A|2, NA, 1 },
- { "adc", 4, 4, 1, 3, A|2, NA, 1 },
- { "shl", 3, 5, 1, 1, SL|2, NA, 2 },
- { "shl", 4, 5, 1, 2, SL|3, NA, 2 },
- { "shr", 3, 5, 1, 1, SR|2, NA, 2 },
- { "shr", 4, 5, 1, 2, SR|3, NA, 2 },
- { "rol", 3, 5, 1, 1, RL|2, NA, 2 },
- { "rol", 4, 5, 1, 2, RL|3, NA, 2 },
- { "ror", 3, 5, 1, 1, RR|2, NA, 2 },
- { "ror", 4, 5, 1, 2, RR|3, NA, 2 },
/*
- * Extensions (note also that mvi allows A)
+ * Output the patch list, option definitions first.
*/
- { "clr", 2, 1, 1, I|R_ALLZEROS, I|0xff, NA, 1 },
- { 0, 0, 0, 0, 0, 0, 0, 0 }
-};
-
-int
-eval_operand(char **a, int spec)
-{
- int i;
- unsigned int want = spec & (LO|LA|LX);
-
- static struct {
- unsigned int what;
- char *name;
- int value;
- } jmptab[] = {
- { LO, "jmp", 8 },
- { LO, "jc", 9 },
- { LO, "jnc", 10 },
- { LO, "call", 11 },
- { LA, "jz", 15 },
- { LA, "jnz", 13 },
- { LX, "je", 14 },
- { LX, "jne", 12 },
- };
-
- spec &= ~(LO|LA|LX);
-
- for (i = 0; i < sizeof(jmptab)/sizeof(jmptab[0]); i++)
- if (jmptab[i].what == want &&
- !strcmp(jmptab[i].name, a[spec]))
- {
- return(jmptab[i].value);
- }
-
- if (want)
- error("invalid jump");
-
- return(spec); /* "case 0" - no flags set */
-}
-
-int
-eval_sdi(char **a, int spec)
-{
- sym_t *p;
- unsigned val;
-
- if (spec == NA)
- return(NA);
-
- switch (spec & (A|I|SL|SR|RL|RR)) {
- case SL:
- case SR:
- case RL:
- case RR:
- if (isdigit(*a[spec &~ (SL|SR|RL|RR)]))
- val = strtol(a[spec &~ (SL|SR|RL|RR)], NULL, 0);
- else {
- p = lookup(a[spec &~ (SL|SR|RL|RR)]);
- if (!p)
- error("undefined symbol used");
- val = p->value;
- }
-
- switch (spec & (SL|SR|RL|RR)) { /* blech */
- case SL:
- if (val > 7)
- return(0xf0);
- return(((val % 8) << 4) |
- (val % 8));
- case SR:
- if (val > 7)
- return(0xf0);
- return(((val % 8) << 4) |
- (1 << 3) |
- ((8 - (val % 8)) % 8));
- case RL:
- return(val % 8);
- case RR:
- return((8 - (val % 8)) % 8);
- }
- case I:
- return(spec &~ I);
- case A:
- /*
- * An immediate field of zero selects
- * the accumulator. Vigorously object
- * if zero is given otherwise - it's
- * most likely an error.
- */
- spec &= ~A;
- if (!strcmp("A", a[spec]))
- return(0);
- if (isdigit(*a[spec]) &&
- strtol(a[spec], NULL, 0) == 0)
- {
- error("immediate value of zero selects accumulator");
- }
- /* falls through */
- case 0:
- if (isdigit(*a[spec]))
- return(strtol(a[spec], NULL, 0));
- p = lookup(a[spec]);
- if (p)
- return(p->value);
- error("undefined symbol used");
+ for(cur_node = patch_options.slh_first;
+ cur_node != NULL;
+ cur_node = cur_node->links.sle_next) {
+ fprintf(ofile, "#define\t%-16s\t0x%x\n", cur_node->symbol->name,
+ cur_node->symbol->info.condinfo->value);
}
+ symlist_free(&patch_options);
- return(NA); /* shut the compiler up */
-}
-
-int
-eval_addr(char **a, int spec)
-{
- sym_t *p;
+ fprintf(ofile,
+"struct patch {
+ int options;
+ int negative;
+ int begin;
+ int end;
+} patches[] = {\n");
- if (spec == NA)
- return(NA);
- if (isdigit(*a[spec]))
- return(strtol(a[spec], NULL, 0));
+ for(cur_patch = patch_list.stqh_first;
+ cur_patch != NULL;
+ cur_patch = cur_patch->links.stqe_next)
- p = lookup(a[spec]);
+ fprintf(ofile, "\t{ 0x%08x, %d, 0x%03x, 0x%03x },\n",
+ cur_patch->options, cur_patch->negative, cur_patch->begin,
+ cur_patch->end);
- if (p) {
- if (p->value != NOVALUE)
- return(p->value);
- patch(p, LC);
- } else {
- define(a[spec], NOVALUE);
- p = lookup(a[spec]);
- patch(p, LC);
- }
-
- return(NA); /* will be patched in later */
+ 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);
}
-int
-crack(char **a, int n)
+void
+output_listing(listfile, ifilename)
+ FILE *listfile;
+ char *ifilename;
{
- int i;
- int I_imm, I_addr;
- int I_op, I_dest, I_src, I_ret;
+ FILE *ifile;
+ int line;
+ struct instruction *cur_instr;
+ int instrcount;
+ char buf[1024];
- /*
- * Check for "ret" at the end of the line; remove
- * it unless it's "ret" alone - we still want to
- * look it up in the table.
- */
- I_ret = (strcmp(a[n-1], "ret") ? 0 : !0);
- if (I_ret && n > 1)
- n -= 1;
-
- for (i = 0; instr[i].name; i++) {
- /*
- * Look for match in table given constraints,
- * currently just the name and the number of
- * operands.
- */
- if (!strcmp(instr[i].name, *a) && instr[i].n == n)
- break;
+ instrcount = 0;
+ line = 1;
+ if ((ifile = fopen(ifilename, "r")) == NULL) {
+ perror(ifilename);
+ stop(NULL, EX_DATAERR);
}
- if (!instr[i].name)
- error("unknown opcode or wrong number of operands");
-
- I_op = eval_operand(a, instr[i].op);
- I_src = eval_sdi(a, instr[i].src);
- I_imm = eval_sdi(a, instr[i].imm);
- I_dest = eval_sdi(a, instr[i].dest);
- I_addr = eval_addr(a, instr[i].addr);
-
- if( LC >= MEMORY )
- error("Memory exhausted!\n");
-
- switch (instr[i].fmt) {
- case 1:
- case 2:
- M[LC][0] = (I_op << 1) | I_ret;
- M[LC][1] = I_dest;
- M[LC][2] = I_src;
- M[LC][3] = I_imm;
- break;
- case 3:
- if (I_ret)
- error("illegal use of \"ret\"");
- M[LC][0] = (I_op << 1) | ((I_addr >> 8) & 1);
- M[LC][1] = I_addr & 0xff;
- M[LC][2] = I_src;
- M[LC][3] = I_imm;
- break;
+ for(cur_instr = seq_program.stqh_first;
+ cur_instr != NULL;
+ cur_instr = cur_instr->links.stqe_next) {
+ while (line < cur_instr->srcline) {
+ fgets(buf, sizeof(buf), ifile);
+ fprintf(listfile, "\t\t%s", buf);
+ line++;
+ }
+ fprintf(listfile, "%03x %02x%02x%02x%02x", instrcount,
+ cur_instr->format.bytes[0],
+ cur_instr->format.bytes[1],
+ cur_instr->format.bytes[2],
+ cur_instr->format.bytes[3]);
+ fgets(buf, sizeof(buf), ifile);
+ fprintf(listfile, "%s", buf);
+ line++;
+ instrcount++;
}
-
- return (1); /* no two-byte instructions yet */
+ fclose(ifile);
}
-#undef SL
-#undef SR
-#undef RL
-#undef RR
-#undef LX
-#undef LA
-#undef LO
-#undef I
-#undef A
-
+/*
+ * Print out error information if appropriate, and clean up before
+ * terminating the program.
+ */
void
-assemble(FILE *ofile)
+stop(string, err_code)
+ const char *string;
+ int err_code;
{
- int n;
- char **a;
- sym_t *p;
-
- while ((a = getl(&n))) {
-
- while (a[0][strlen(*a)-1] == ':') {
- a[0][strlen(*a)-1] = '\0';
- p = lookup(*a);
- if (p)
- p->value = LC;
- else
- define(*a, LC);
- a += 1;
- n -= 1;
+ if (string != NULL) {
+ fprintf(stderr, "%s: ", appname);
+ if (yyfilename != NULL) {
+ fprintf(stderr, "Stopped at file %s, line %d - ",
+ yyfilename, yylineno);
}
+ fprintf(stderr, "%s\n", string);
+ }
- if (!n) /* line was all labels */
- continue;
-
- if (n == 3 && !strcmp("VERSION", *a))
- fprintf(ofile, "#define %s \"%s\"\n", a[1], a[2]);
- else {
- if (n == 3 && !strcmp("=", a[1]))
- define(*a, strtol(a[2], NULL, 0));
- else
- LC += crack(a, n);
+ if (ofile != NULL) {
+ fclose(ofile);
+ if (err_code != 0) {
+ fprintf(stderr, "%s: Removing %s due to error\n",
+ appname, ofilename);
+ unlink(ofilename);
}
}
- backpatch();
- output(ofile);
+ symtable_close();
- if (debug)
- output(stderr);
+ exit(err_code);
}
-int
-main(int argc, char **argv)
+struct instruction *
+seq_alloc()
{
- int c;
- int pid;
- int ifile;
- FILE *ofile;
- int fd[2];
+ struct instruction *new_instr;
- ofile = NULL;
- while ((c = getopt(argc, argv, "dho:vD:")) != EOF) {
- switch (c) {
- case 'd':
- debug = !0;
- break;
- case 'D':
- {
- char *p;
- if ((p = strchr(optarg, '=')) != NULL) {
- *p = '\0';
- define(optarg, strtol(p + 1, NULL, 0));
- }
- else
- define(optarg, 1);
- break;
- }
- case 'o':
-
- if ((ofile = fopen(optarg, "w")) == NULL) {
- perror(optarg);
- exit(EXIT_FAILURE);
- }
- break;
- case 'h':
- printf("usage: %s [-d] [-Dname] [-ooutput] input\n",
- *argv);
- exit(EXIT_SUCCESS);
- break;
- case 'v':
- printf("%s\n", id);
- exit(EXIT_SUCCESS);
- break;
- default:
- exit(EXIT_FAILURE);
- break;
- }
- }
-
- if (argc - optind != 1) {
- fprintf(stderr, "%s: must have one input file\n", *argv);
- exit(EXIT_FAILURE);
- }
- filename = argv[optind];
-
-
- if ((ifile = open(filename, O_RDONLY)) < 0) {
- perror(filename);
- exit(EXIT_FAILURE);
- }
-
- if (!ofile) {
- if ((ofile = fopen(ADOTOUT, "w")) == NULL) {
- perror(ADOTOUT);
- exit(EXIT_FAILURE);
- }
- }
+ new_instr = (struct instruction *)malloc(sizeof(struct instruction));
+ if (new_instr == NULL)
+ stop("Unable to malloc instruction object", EX_SOFTWARE);
+ memset(new_instr, 0, sizeof(*new_instr));
+ STAILQ_INSERT_TAIL(&seq_program, new_instr, links);
+ new_instr->srcline = yylineno;
+ return new_instr;
+}
- if (pipe(fd) < 0) {
- perror("pipe failed");
- exit(1);
- }
+patch_t *
+patch_alloc()
+{
+ patch_t *new_patch;
- if ((pid = fork()) < 0 ) {
- perror("fork failed");
- exit(1);
- }
- else if (pid > 0) { /* Parent */
- close(fd[1]); /* Close write end */
- if (fd[0] != STDIN_FILENO) {
- if (dup2(fd[0], STDIN_FILENO) != STDIN_FILENO) {
- perror("dup2 error on stdin");
- exit(EXIT_FAILURE);
- }
- close(fd[0]);
- }
- assemble(ofile);
- exit(EXIT_SUCCESS);
- }
- else { /* Child */
- close(fd[0]); /* Close Read end */
- if (fd[1] != STDOUT_FILENO) {
- if (dup2(fd[1], STDOUT_FILENO) != STDOUT_FILENO) {
- perror("dup2 error on stdout");
- exit(EXIT_FAILURE);
- }
- close(fd[1]);
- }
- if (ifile != STDIN_FILENO) {
- if (dup2(ifile, STDIN_FILENO) != STDIN_FILENO) {
- perror("dup2 error on stdin");
- exit(EXIT_FAILURE);
- }
- close(ifile);
- }
- execl("/usr/bin/cpp", "/usr/bin/cpp", "-P", "-", "-", NULL);
- }
- return(EXIT_SUCCESS);
+ 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;
}
diff --git a/sys/dev/aic7xxx/aic7xxx_reg.h b/sys/dev/aic7xxx/aic7xxx_reg.h
deleted file mode 100644
index ced6bea4bb431..0000000000000
--- a/sys/dev/aic7xxx/aic7xxx_reg.h
+++ /dev/null
@@ -1,801 +0,0 @@
-/*
- * Aic7xxx register and scratch ram definitions.
- *
- * Copyright (c) 1994, 1995, 1996, 1997 Justin T. Gibbs.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice immediately at the beginning of the file, without modification,
- * this list of conditions, and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $Id: aic7xxx_reg.h,v 1.25 1997/02/22 09:28:53 peter Exp $
- */
-
-/*
- * This header is shared by the sequencer code and the kernel level driver.
- *
- * All page numbers refer to the Adaptec AIC-7770 Data Book availible from
- * Adaptec's Technical Documents Department 1-800-934-2766
- */
-
-/*
- * SCSI Sequence Control (p. 3-11).
- * Each bit, when set starts a specific SCSI sequence on the bus
- */
-#define SCSISEQ 0x000
-#define TEMODEO 0x80
-#define ENSELO 0x40
-#define ENSELI 0x20
-#define ENRSELI 0x10
-#define ENAUTOATNO 0x08
-#define ENAUTOATNI 0x04
-#define ENAUTOATNP 0x02
-#define SCSIRSTO 0x01
-
-/*
- * SCSI Transfer Control 0 Register (pp. 3-13).
- * Controls the SCSI module data path.
- */
-#define SXFRCTL0 0x001
-#define DFON 0x80
-#define DFPEXP 0x40
-#define FAST20 0x20
-#define CLRSTCNT 0x10
-#define SPIOEN 0x08
-#define SCAMEN 0x04
-#define CLRCHN 0x02
-/* UNUSED 0x01 */
-
-/*
- * SCSI Transfer Control 1 Register (pp. 3-14,15).
- * Controls the SCSI module data path.
- */
-#define SXFRCTL1 0x002
-#define BITBUCKET 0x80
-#define SWRAPEN 0x40
-#define ENSPCHK 0x20
-#define STIMESEL 0x18
-#define ENSTIMER 0x04
-#define ACTNEGEN 0x02
-#define STPWEN 0x01 /* Powered Termination */
-
-/*
- * SCSI Control Signal Read Register (p. 3-15).
- * Reads the actual state of the SCSI bus pins
- */
-#define SCSISIGI 0x003
-#define CDI 0x80
-#define IOI 0x40
-#define MSGI 0x20
-#define ATNI 0x10
-#define SELI 0x08
-#define BSYI 0x04
-#define REQI 0x02
-#define ACKI 0x01
-
-/*
- * Possible phases in SCSISIGI
- */
-#define PHASE_MASK 0xe0
-#define P_DATAOUT 0x00
-#define P_DATAIN 0x40
-#define P_COMMAND 0x80
-#define P_MESGOUT 0xa0
-#define P_STATUS 0xc0
-#define P_MESGIN 0xe0
-/*
- * SCSI Contol Signal Write Register (p. 3-16).
- * Writing to this register modifies the control signals on the bus. Only
- * those signals that are allowed in the current mode (Initiator/Target) are
- * asserted.
- */
-#define SCSISIGO 0x003
-#define CDO 0x80
-#define IOO 0x40
-#define MSGO 0x20
-#define ATNO 0x10
-#define SELO 0x08
-#define BSYO 0x04
-#define REQO 0x02
-#define ACKO 0x01
-
-/*
- * SCSI Rate Control (p. 3-17).
- * Contents of this register determine the Synchronous SCSI data transfer
- * rate and the maximum synchronous Req/Ack offset. An offset of 0 in the
- * SOFS (3:0) bits disables synchronous data transfers. Any offset value
- * greater than 0 enables synchronous transfers.
- */
-#define SCSIRATE 0x004
-#define WIDEXFER 0x80 /* Wide transfer control */
-#define SXFR 0x70 /* Sync transfer rate */
-#define SOFS 0x0f /* Sync offset */
-
-/*
- * SCSI ID (p. 3-18).
- * Contains the ID of the board and the current target on the
- * selected channel.
- */
-#define SCSIID 0x005
-#define TID 0xf0 /* Target ID mask */
-#define OID 0x0f /* Our ID mask */
-
-/*
- * SCSI Latched Data (p. 3-19).
- * Read/Write latchs used to transfer data on the SCSI bus during
- * Automatic or Manual PIO mode. SCSIDATH can be used for the
- * upper byte of a 16bit wide asyncronouse data phase transfer.
- */
-#define SCSIDATL 0x006
-#define SCSIDATH 0x007
-
-/*
- * SCSI Transfer Count (pp. 3-19,20)
- * These registers count down the number of bytes transfered
- * across the SCSI bus. The counter is decremented only once
- * the data has been safely transfered. SDONE in SSTAT0 is
- * set when STCNT goes to 0
- */
-#define STCNT 0x008
-#define STCNT0 0x008
-#define STCNT1 0x009
-#define STCNT2 0x00a
-
-/*
- * Clear SCSI Interrupt 0 (p. 3-20)
- * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT0.
- */
-#define CLRSINT0 0x00b
-#define CLRSELDO 0x40
-#define CLRSELDI 0x20
-#define CLRSELINGO 0x10
-#define CLRSWRAP 0x08
-/* UNUSED 0x04 */
-#define CLRSPIORDY 0x02
-/* UNUSED 0x01 */
-
-/*
- * SCSI Status 0 (p. 3-21)
- * Contains one set of SCSI Interrupt codes
- * These are most likely of interest to the sequencer
- */
-#define SSTAT0 0x00b
-#define TARGET 0x80 /* Board acting as target */
-#define SELDO 0x40 /* Selection Done */
-#define SELDI 0x20 /* Board has been selected */
-#define SELINGO 0x10 /* Selection In Progress */
-#define SWRAP 0x08 /* 24bit counter wrap */
-#define SDONE 0x04 /* STCNT = 0x000000 */
-#define SPIORDY 0x02 /* SCSI PIO Ready */
-#define DMADONE 0x01 /* DMA transfer completed */
-
-/*
- * Clear SCSI Interrupt 1 (p. 3-23)
- * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT1.
- */
-#define CLRSINT1 0x00c
-#define CLRSELTIMEO 0x80
-#define CLRATNO 0x40
-#define CLRSCSIRSTI 0x20
-/* UNUSED 0x10 */
-#define CLRBUSFREE 0x08
-#define CLRSCSIPERR 0x04
-#define CLRPHASECHG 0x02
-#define CLRREQINIT 0x01
-
-/*
- * SCSI Status 1 (p. 3-24)
- */
-#define SSTAT1 0x00c
-#define SELTO 0x80
-#define ATNTARG 0x40
-#define SCSIRSTI 0x20
-#define PHASEMIS 0x10
-#define BUSFREE 0x08
-#define SCSIPERR 0x04
-#define PHASECHG 0x02
-#define REQINIT 0x01
-
-/*
- * SCSI Interrupt Mode 1 (pp. 3-28,29)
- * Setting any bit will enable the corresponding function
- * in SIMODE1 to interrupt via the IRQ pin.
- */
-#define SIMODE1 0x011
-#define ENSELTIMO 0x80
-#define ENATNTARG 0x40
-#define ENSCSIRST 0x20
-#define ENPHASEMIS 0x10
-#define ENBUSFREE 0x08
-#define ENSCSIPERR 0x04
-#define ENPHASECHG 0x02
-#define ENREQINIT 0x01
-
-/*
- * SCSI Data Bus (High) (p. 3-29)
- * This register reads data on the SCSI Data bus directly.
- */
-#define SCSIBUSL 0x012
-#define SCSIBUSH 0x013
-
-/*
- * SCSI/Host Address (p. 3-30)
- * These registers hold the host address for the byte about to be
- * transfered on the SCSI bus. They are counted up in the same
- * manner as STCNT is counted down. SHADDR should always be used
- * to determine the address of the last byte transfered since HADDR
- * can be squewed by write ahead.
- */
-#define SHADDR 0x014
-#define SHADDR0 0x014
-#define SHADDR1 0x015
-#define SHADDR2 0x016
-#define SHADDR3 0x017
-
-/*
- * Selection/Reselection ID (p. 3-31)
- * Upper four bits are the device id. The ONEBIT is set when the re/selecting
- * device did not set its own ID.
- */
-#define SELID 0x019
-#define SELID_MASK 0xf0
-#define ONEBIT 0x08
-/* UNUSED 0x07 */
-
-/*
- * SCSI Block Control (p. 3-32)
- * Controls Bus type and channel selection. In a twin channel configuration
- * addresses 0x00-0x1e are gated to the appropriate channel based on this
- * register. SELWIDE allows for the coexistence of 8bit and 16bit devices
- * on a wide bus.
- */
-#define SBLKCTL 0x01f
-#define DIAGLEDEN 0x80 /* Aic78X0 only */
-#define DIAGLEDON 0x40 /* Aic78X0 only */
-#define AUTOFLUSHDIS 0x20
-/* UNUSED 0x10 */
-#define SELBUS_MASK 0x0a
-#define SELBUSB 0x08
-/* UNUSED 0x04 */
-#define SELWIDE 0x02
-/* UNUSED 0x01 */
-#define SELNARROW 0x00
-
-/*
- * Sequencer Control (p. 3-33)
- * Error detection mode and speed configuration
- */
-#define SEQCTL 0x060
-#define PERRORDIS 0x80
-#define PAUSEDIS 0x40
-#define FAILDIS 0x20
-#define FASTMODE 0x10
-#define BRKADRINTEN 0x08
-#define STEP 0x04
-#define SEQRESET 0x02
-#define LOADRAM 0x01
-
-/*
- * Sequencer RAM Data (p. 3-34)
- * Single byte window into the Scratch Ram area starting at the address
- * specified by SEQADDR0 and SEQADDR1. To write a full word, simply write
- * four bytes in sucessesion. The SEQADDRs will increment after the most
- * significant byte is written
- */
-#define SEQRAM 0x061
-
-/*
- * Sequencer Address Registers (p. 3-35)
- * Only the first bit of SEQADDR1 holds addressing information
- */
-#define SEQADDR0 0x062
-#define SEQADDR1 0x063
-#define SEQADDR1_MASK 0x01
-
-/*
- * Accumulator
- * We cheat by passing arguments in the Accumulator up to the kernel driver
- */
-#define ACCUM 0x064
-
-#define SINDEX 0x065
-#define DINDEX 0x066
-#define ALLONES 0x069
-#define ALLZEROS 0x06a
-#define NONE 0x06a
-#define SINDIR 0x06c
-#define DINDIR 0x06d
-#define FUNCTION1 0x06e
-
-/*
- * Host Address (p. 3-48)
- * This register contains the address of the byte about
- * to be transfered across the host bus.
- */
-#define HADDR 0x088
-#define HADDR0 0x088
-#define HADDR1 0x089
-#define HADDR2 0x08a
-#define HADDR3 0x08b
-
-#define HCNT 0x08c
-#define HCNT0 0x08c
-#define HCNT1 0x08d
-#define HCNT2 0x08e
-/*
- * SCB Pointer (p. 3-49)
- * Gate one of the four SCBs into the SCBARRAY window.
- */
-#define SCBPTR 0x090
-
-/*
- * Board Control (p. 3-43)
- */
-#define BCTL 0x084
-/* RSVD 0xf0 */
-#define ACE 0x08 /* Support for external processors */
-/* RSVD 0x06 */
-#define ENABLE 0x01
-
-/*
- * On the aic78X0 chips, Board Control is replaced by the DSCommand
- * register (p. 4-64)
- */
-#define DSCOMMAND 0x084
-#define CACHETHEN 0x80 /* Cache Threshold enable */
-#define DPARCKEN 0x40 /* Data Parity Check Enable */
-#define MPARCKEN 0x20 /* Memory Parity Check Enable */
-#define EXTREQLCK 0x10 /* External Request Lock */
-
-/*
- * Bus On/Off Time (p. 3-44)
- */
-#define BUSTIME 0x085
-#define BOFF 0xf0
-#define BON 0x0f
-
-/*
- * Bus Speed (p. 3-45)
- */
-#define BUSSPD 0x086
-#define DFTHRSH 0xc0
-#define STBOFF 0x38
-#define STBON 0x07
-#define DFTHRSH_100 0xc0
-#define DFTHRSH_75 0x80
-
-/*
- * Host Control (p. 3-47) R/W
- * Overal host control of the device.
- */
-#define HCNTRL 0x087
-/* UNUSED 0x80 */
-#define POWRDN 0x40
-/* UNUSED 0x20 */
-#define SWINT 0x10
-#define IRQMS 0x08
-#define PAUSE 0x04
-#define INTEN 0x02
-#define CHIPRST 0x01
-#define CHIPRSTACK 0x01
-
-/*
- * Interrupt Status (p. 3-50)
- * Status for system interrupts
- */
-#define INTSTAT 0x091
-#define SEQINT_MASK 0xf1 /* SEQINT Status Codes */
-#define BAD_PHASE 0x01 /* unknown scsi bus phase */
-#define SEND_REJECT 0x11 /* sending a message reject */
-#define NO_IDENT 0x21 /* no IDENTIFY after reconnect*/
-#define NO_MATCH 0x31 /* no cmd match for reconnect */
-#define EXTENDED_MSG 0x41 /* Extended message received */
-#define NO_MATCH_BUSY 0x51 /* Couldn't find BUSY SCB */
-#define REJECT_MSG 0x61 /* Reject message received */
-#define BAD_STATUS 0x71 /* Bad status from target */
-#define RESIDUAL 0x81 /* Residual byte count != 0 */
-#define ABORT_CMDCMPLT 0x91 /*
- * Command tagged for abort
- * completed successfully.
- */
-#define AWAITING_MSG 0xa1 /*
- * Kernel requested to specify
- * a message to this target
- * (command was null), so tell
- * it that it can fill the
- * message buffer.
- */
-#define MSG_BUFFER_BUSY 0xc1 /*
- * Sequencer wants to use the
- * message buffer, but it
- * already contains a message
- */
-#define MSGIN_PHASEMIS 0xd1 /*
- * Target changed phase on us
- * when we were expecting
- * another msgin byte.
- */
-#define DATA_OVERRUN 0xe1 /*
- * Target attempted to write
- * beyond the bounds of its
- * command.
- */
-
-#define BRKADRINT 0x08
-#define SCSIINT 0x04
-#define CMDCMPLT 0x02
-#define SEQINT 0x01
-#define INT_PEND (BRKADRINT | SEQINT | SCSIINT | CMDCMPLT)
-
-/*
- * Hard Error (p. 3-53)
- * Reporting of catastrophic errors. You usually cannot recover from
- * these without a full board reset.
- */
-#define ERROR 0x092
-/* UNUSED 0xf0 */
-#define PARERR 0x08
-#define ILLOPCODE 0x04
-#define ILLSADDR 0x02
-#define ILLHADDR 0x01
-
-/*
- * Clear Interrupt Status (p. 3-52)
- */
-#define CLRINT 0x092
-#define CLRBRKADRINT 0x08
-#define CLRSCSIINT 0x04
-#define CLRCMDINT 0x02
-#define CLRSEQINT 0x01
-
-#define DFCNTRL 0x093
-#define WIDEODD 0x40
-#define SCSIEN 0x20
-#define SDMAEN 0x10
-#define SDMAENACK 0x10
-#define HDMAEN 0x08
-#define HDMAENACK 0x08
-#define DIRECTION 0x04
-#define FIFOFLUSH 0x02
-#define FIFORESET 0x01
-
-#define DFSTATUS 0x094
-#define MREQPEND 0x10
-#define HDONE 0x08
-#define FIFOEMP 0x01
-
-#define DFDAT 0x099
-
-/*
- * SCB Auto Increment (p. 3-59)
- * Byte offset into the SCB Array and an optional bit to allow auto
- * incrementing of the address during download and upload operations
- */
-#define SCBCNT 0x09a
-#define SCBAUTO 0x80
-#define SCBCNT_MASK 0x1f
-
-/*
- * Queue In FIFO (p. 3-60)
- * Input queue for queued SCBs (commands that the seqencer has yet to start)
- */
-#define QINFIFO 0x09b
-
-/*
- * Queue In Count (p. 3-60)
- * Number of queued SCBs
- */
-#define QINCNT 0x09c
-
-/*
- * Queue Out FIFO (p. 3-61)
- * Queue of SCBs that have completed and await the host
- */
-#define QOUTFIFO 0x09d
-
-/*
- * Queue Out Count (p. 3-61)
- * Number of queued SCBs in the Out FIFO
- */
-#define QOUTCNT 0x09e
-
-/*
- * SCB Definition (p. 5-4)
- * The two reserved bytes at SCBARRAY+1[23] are expected to be set to
- * zero. Bit 3 in SCBARRAY+0 is used as an internal flag to indicate
- * whether or not to DMA an SCB from host ram. This flag prevents the
- * "re-fetching" of transactions that are requed because the target is
- * busy with another command. We also use bits 6 & 7 to indicate whether
- * or not to initiate SDTR or WDTR repectively when starting this command.
- */
-#define SCBARRAY 0x0a0
-#define SCB_CONTROL 0x0a0
-#define MK_MESSAGE 0x80
-#define DISCENB 0x40
-#define TAG_ENB 0x20
-#define SPLIT_SG 0x10
-#define ABORT_SCB 0x08
-#define DISCONNECTED 0x04
-#define SCB_TAG_TYPE 0x03
-#define SCB_TCL 0x0a1
-#define SCB_TARGET_STATUS 0x0a2
-#define SCB_SGCOUNT 0x0a3
-#define SCB_SGPTR 0x0a4
-#define SCB_SGPTR0 0x0a4
-#define SCB_SGPTR1 0x0a5
-#define SCB_SGPTR2 0x0a6
-#define SCB_SGPTR3 0x0a7
-#define SCB_RESID_SGCNT 0x0a8
-#define SCB_RESID_DCNT 0x0a9
-#define SCB_RESID_DCNT0 0x0a9
-#define SCB_RESID_DCNT1 0x0aa
-#define SCB_RESID_DCNT2 0x0ab
-#define SCB_DATAPTR 0x0ac
-#define SCB_DATAPTR0 0x0ac
-#define SCB_DATAPTR1 0x0ad
-#define SCB_DATAPTR2 0x0ae
-#define SCB_DATAPTR3 0x0af
-#define SCB_DATACNT 0x0b0
-#define SCB_DATACNT0 0x0b0
-#define SCB_DATACNT1 0x0b1
-#define SCB_DATACNT2 0x0b2
-#define SCB_LINKED_NEXT 0x0b3
-#define SCB_CMDPTR 0x0b4
-#define SCB_CMDPTR0 0x0b4
-#define SCB_CMDPTR1 0x0b5
-#define SCB_CMDPTR2 0x0b6
-#define SCB_CMDPTR3 0x0b7
-#define SCB_CMDLEN 0x0b8
-#define SCB_TAG 0x0b9
-#define SCB_NEXT 0x0ba
-#define SCB_PREV 0x0bb
-#define SCB_ACTIVE0 0x0bc
-#define SCB_ACTIVE1 0x0bd
-#define SCB_ACTIVE2 0x0be
-#define SCB_ACTIVE3 0x0bf
-
-#define SG_SIZEOF 0x08 /* sizeof(struct ahc_dma) */
-
-/* --------------------- AHA-2840-only definitions -------------------- */
-
-#define SEECTL_2840 0x0c0
-/* UNUSED 0xf8 */
-#define CS_2840 0x04
-#define CK_2840 0x02
-#define DO_2840 0x01
-
-#define STATUS_2840 0x0c1
-#define EEPROM_TF 0x80
-#define BIOS_SEL 0x60
-#define ADSEL 0x1e
-#define DI_2840 0x01
-
-/* --------------------- AIC-7870-only definitions -------------------- */
-
-#define DSPCISTATUS 0x086
-
-#define BRDCTL 0x01d
-#define BRDDAT7 0x80
-#define BRDDAT6 0x40
-#define BRDDAT5 0x20
-#define BRDSTB 0x10
-#define BRDCS 0x08
-#define BRDRW 0x04
-#define BRDCTL1 0x02
-#define BRDCTL0 0x01
-
-/*
- * Serial EEPROM Control (p. 4-92 in 7870 Databook)
- * Controls the reading and writing of an external serial 1-bit
- * EEPROM Device. In order to access the serial EEPROM, you must
- * first set the SEEMS bit that generates a request to the memory
- * port for access to the serial EEPROM device. When the memory
- * port is not busy servicing another request, it reconfigures
- * to allow access to the serial EEPROM. When this happens, SEERDY
- * gets set high to verify that the memory port access has been
- * granted.
- *
- * After successful arbitration for the memory port, the SEECS bit of
- * the SEECTL register is connected to the chip select. The SEECK,
- * SEEDO, and SEEDI are connected to the clock, data out, and data in
- * lines respectively. The SEERDY bit of SEECTL is useful in that it
- * gives us an 800 nsec timer. After a write to the SEECTL register,
- * the SEERDY goes high 800 nsec later. The one exception to this is
- * when we first request access to the memory port. The SEERDY goes
- * high to signify that access has been granted and, for this case, has
- * no implied timing.
- *
- * See 93cx6.c for detailed information on the protocol necessary to
- * read the serial EEPROM.
- */
-#define SEECTL 0x01e
-#define EXTARBACK 0x80
-#define EXTARBREQ 0x40
-#define SEEMS 0x20
-#define SEERDY 0x10
-#define SEECS 0x08
-#define SEECK 0x04
-#define SEEDO 0x02
-#define SEEDI 0x01
-/* ---------------------- Scratch RAM Offsets ------------------------- */
-/* These offsets are either to values that are initialized by the board's
- * BIOS or are specified by the sequencer code.
- *
- * The host adapter card (at least the BIOS) uses 20-2f for SCSI
- * device information, 32-33 and 5a-5f as well. As it turns out, the
- * BIOS trashes 20-2f, writing the synchronous negotiation results
- * on top of the BIOS values, so we re-use those for our per-target
- * scratchspace (actually a value that can be copied directly into
- * SCSIRATE). The kernel driver will enable synchronous negotiation
- * for all targets that have a value other than 0 in the lower four
- * bits of the target scratch space. This should work regardless of
- * whether the bios has been installed.
- */
-
-/*
- * 1 byte per target starting at this address for configuration values
- */
-#define TARG_SCRATCH 0x020
-
-/*
- * The sequencer will stick the frist byte of any rejected message here so
- * we can see what is getting thrown away.
- */
-#define REJBYTE 0x030
-#define LASTPHASE 0x031
-#define P_BUSFREE 0x01
-
-/*
- * Bit vector of targets that have disconnection disabled.
- */
-#define DISC_DSB 0x032
-#define DISC_DSB_A 0x032
-#define DISC_DSB_B 0x033
-
-/*
- * Length of pending message
- */
-#define MSG_LEN 0x034
-
-/* We reserve 8bytes to store outgoing messages */
-#define MSG0 0x035
-#define COMP_MSG0 0xcb /* 2's complement of MSG0 */
-#define MSG1 0x036
-#define MSG2 0x037
-#define MSG3 0x038
-#define MSG4 0x039
-#define MSG5 0x03a
-#define MSG6 0x03b
-#define MSG7 0x03c
-
-#define DMAPARAMS 0x03d /* Parameters for DMA Logic */
-
-#define SCBCOUNT 0x03e /*
- * Number of SCBs supported by
- * this card.
- */
-#define COMP_SCBCOUNT 0x03f /*
- * Two's compliment of SCBCOUNT
- */
-#define QCNTMASK 0x040 /*
- * Mask of bits to test against
- * when looking at the Queue Count
- * registers. Works around a bug
- * on aic7850 chips.
- */
-#define FLAGS 0x041
-#define SINGLE_BUS 0x00
-#define TWIN_BUS 0x01
-#define WIDE_BUS 0x02
-#define PAGESCBS 0x04
-#define DPHASE 0x10
-#define TAGGED_SCB 0x20
-#define IDENTIFY_SEEN 0x40
-#define RESELECTED 0x80
-
-#define SAVED_TCL 0x042 /*
- * Temporary storage for the
- * target/channel/lun of a
- * reconnecting target
- */
-#define SG_COUNT 0x043
-#define SG_NEXT 0x044 /* working value of SG pointer */
-#define SG_NEXT0 0x044
-#define SG_NEXT1 0x045
-#define SG_NEXT2 0x046
-#define SG_NEXT3 0x047
-
-#define WAITING_SCBH 0x048 /*
- * head of list of SCBs awaiting
- * selection
- */
-#define SAVED_LINKPTR 0x049
-#define SAVED_SCBPTR 0x04a
-#define ULTRA_ENB 0x04b
-#define ULTRA_ENB_B 0x04c
-
-#define MSGIN_EXT_LEN 0x04d
-#define MSGIN_EXT_OPCODE 0x04e
-#define MSGIN_EXT_BYTE0 0x04f
-#define MSGIN_EXT_BYTE1 0x050
-#define MSGIN_EXT_BYTE2 0x051 /*
- * This location, 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.
- */
-#define MSGIN_EXT_LASTBYTE 0x052 /* Used as the address for range
- * checking, not used for storage.
- */
-
-#define DISCONNECTED_SCBH 0x052 /*
- * head of list of SCBs that are
- * disconnected. Used for SCB
- * paging.
- */
-#define FREE_SCBH 0x053 /*
- * head of list of SCBs that are
- * not in use. Used for SCB paging.
- */
-
-
-#define HSCB_ADDR0 0x054
-#define HSCB_ADDR1 0x055
-#define HSCB_ADDR2 0x056
-#define HSCB_ADDR3 0x057
-
-#define CUR_SCBID 0x058
-#define ARG_1 0x059
-#define RETURN_1 0x059
-#define SEND_MSG 0x80
-#define SEND_SENSE 0x40
-#define SEND_REJ 0x20
-#define SCB_PAGEDIN 0x10
-
-#define SCB_LIST_NULL 0xff
-
-/*
- * These are offsets into the card's scratch ram. Some of the values are
- * specified in the AHA2742 technical reference manual and are initialized
- * by the BIOS at boot time.
- */
-#define SCSICONF 0x05a
-#define RESET_SCSI 0x40
-
-#define HOSTCONF 0x05d
-
-#define HA_274_BIOSCTRL 0x05f
-#define BIOSMODE 0x30
-#define BIOSDISABLED 0x30
-#define CHANNEL_B_PRIMARY 0x08
-
-/* WDTR Message values */
-#define BUS_8_BIT 0x00
-#define BUS_16_BIT 0x01
-#define BUS_32_BIT 0x02
-
-#define MAX_OFFSET_8BIT 0x0f
-#define MAX_OFFSET_16BIT 0x08
diff --git a/sys/dev/aic7xxx/aicasm.c b/sys/dev/aic7xxx/aicasm.c
index d3e09f6aeba03..efed828a13a3a 100644
--- a/sys/dev/aic7xxx/aicasm.c
+++ b/sys/dev/aic7xxx/aicasm.c
@@ -1,31 +1,26 @@
-/*+M*************************************************************************
- * Adaptec AIC7770/AIC7870 sequencer code assembler.
+/*
+ * Aic7xxx SCSI host adapter firmware asssembler
*
- * Copyright (c) 1994 John Aycock
- * The University of Calgary Department of Computer Science.
- * All rights reserved.
+ * Copyright (c) 1997 Justin T. Gibbs.
+ * All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer.
+ * 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. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of Calgary
- * Department of Computer Science and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * 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
@@ -33,653 +28,380 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * Comments are started by `#' and continue to the end of the line; lines
- * may be of the form:
- * <label>*
- * <label>* <undef-sym> = <value>
- * <label>* <opcode> <operand>*
- *
- * A <label> is an <undef-sym> ending in a colon. Spaces, tabs, and commas
- * are token separators.
- *
- *-M*************************************************************************/
-static char id[] = "$Id$";
-#include <ctype.h>
+ * $Id$
+ */
+#include <sys/types.h>
+#include <sys/mman.h>
+
#include <stdio.h>
-#include <string.h>
#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
#include <unistd.h>
-#include <fcntl.h>
-#define MEMORY 448
-#define MAXLINE 1024
-#define MAXTOKEN 32
-#define ADOTOUT "a.out"
-#define NOVALUE -1
+#include "aic7xxx_asm.h"
+#include "symbol.h"
+#include "sequencer.h"
-/*
- * AIC-7770/AIC-7870 register definitions
- */
-#define R_SINDEX 0x65
-#define R_ALLONES 0x69
-#define R_ALLZEROS 0x6a
-#define R_NONE 0x6a
+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));
-int debug;
-int lineno, LC;
-char *filename;
-unsigned char M[MEMORY][4];
+struct path_list search_path;
+int includes_search_curdir;
+char *appname;
+FILE *ofile;
+char *ofilename;
-void
-error(char *s)
-{
- fprintf(stderr, "%s: %s at line %d\n", filename, s, lineno);
- exit(EXIT_FAILURE);
-}
+static STAILQ_HEAD(,instruction) seq_program;
+static STAILQ_HEAD(, patch) patch_list;
+symlist_t patch_options;
-void *
-Malloc(size_t size)
-{
- void *p = malloc(size);
- if (!p)
- error("out of memory");
- return(p);
-}
+#if DEBUG
+extern int yy_flex_debug;
+extern int yydebug;
+#endif
+extern FILE *yyin;
+extern int yyparse __P((void));
-void *
-Realloc(void *ptr, size_t size)
-{
- void *p = realloc(ptr, size);
- if (!p)
- error("out of memory");
- return(p);
-}
-
-char *
-Strdup(char *s)
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
{
- char *p = (char *)Malloc(strlen(s) + 1);
- strcpy(p, s);
- return(p);
-}
+ extern char *optarg;
+ extern int optind;
+ int ch;
+ int retval;
+ char *inputfilename;
+ char *regfilename;
+ FILE *regfile;
+ char *listfilename;
+ FILE *listfile;
-typedef struct sym_t {
- struct sym_t *next; /* MUST BE FIRST */
- char *name;
- int value;
- int npatch;
- int *patch;
-} sym_t;
-
-sym_t *head;
-
-void
-define(char *name, int value)
-{
- sym_t *p, *q;
+ SLIST_INIT(&search_path);
+ STAILQ_INIT(&seq_program);
+ STAILQ_INIT(&patch_list);
+ SLIST_INIT(&patch_options);
+ includes_search_curdir = 1;
+ appname = *argv;
+ regfile = NULL;
+ listfile = NULL;
+#if DEBUG
+ yy_flex_debug = 0;
+#endif
+ while ((ch = getopt(argc, argv, "d:l:n:o:r:I:")) != EOF) {
+ switch(ch) {
+ case 'd':
+#if DEBUG
+ if (strcmp(optarg, "s") == 0)
+ yy_flex_debug = 1;
+ else if (strcmp(optarg, "p") == 0)
+ yydebug = 1;
+#else
+ stop("-d: Assembler not built with debugging "
+ "information", EX_SOFTWARE);
+#endif
+ break;
+ case 'l':
+ /* Create a program listing */
+ if ((listfile = fopen(optarg, "w")) == NULL) {
+ perror(optarg);
+ stop(NULL, EX_CANTCREAT);
+ }
+ listfilename = optarg;
+ break;
+ case 'n':
+ /* Don't complain about the -nostdinc directrive */
+ if (strcmp(optarg, "ostdinc")) {
+ fprintf(stderr, "%s: Unknown option -%c%s\n",
+ appname, ch, optarg);
+ usage();
+ /* NOTREACHED */
+ }
+ break;
+ case 'o':
+ if ((ofile = fopen(optarg, "w")) == NULL) {
+ perror(optarg);
+ stop(NULL, EX_CANTCREAT);
+ }
+ ofilename = optarg;
+ break;
+ case 'r':
+ if ((regfile = fopen(optarg, "w")) == NULL) {
+ perror(optarg);
+ stop(NULL, EX_CANTCREAT);
+ }
+ regfilename = optarg;
+ break;
+ case 'I':
+ {
+ path_entry_t include_dir;
- for (p = head, q = (sym_t *)&head; p; p = p->next) {
- if (!strcmp(p->name, name))
- error("redefined symbol");
- q = p;
+ if (strcmp(optarg, "-") == 0) {
+ if (includes_search_curdir == 0) {
+ fprintf(stderr, "%s: Warning - '-I-' "
+ "specified multiple "
+ "times\n", appname);
+ }
+ includes_search_curdir = 0;
+ for (include_dir = search_path.slh_first;
+ include_dir != NULL;
+ include_dir = include_dir->links.sle_next)
+ /*
+ * All entries before a '-I-' only
+ * apply to includes specified with
+ * quotes instead of "<>".
+ */
+ include_dir->quoted_includes_only = 1;
+ } else {
+ include_dir =
+ (path_entry_t)malloc(sizeof(*include_dir));
+ if (include_dir == NULL) {
+ perror(optarg);
+ stop(NULL, EX_OSERR);
+ }
+ include_dir->directory = strdup(optarg);
+ if (include_dir->directory == NULL) {
+ perror(optarg);
+ stop(NULL, EX_OSERR);
+ }
+ include_dir->quoted_includes_only = 0;
+ SLIST_INSERT_HEAD(&search_path, include_dir,
+ links);
+ }
+ break;
+ }
+ case '?':
+ default:
+ usage();
+ /* NOTREACHED */
+ }
}
+ argc -= optind;
+ argv += optind;
- p = q->next = (sym_t *)Malloc(sizeof(sym_t));
- p->next = NULL;
- p->name = Strdup(name);
- p->value = value;
- p->npatch = 0;
- p->patch = NULL;
-
- if (debug) {
- fprintf(stderr, "\"%s\" ", p->name);
- if (p->value != NOVALUE)
- fprintf(stderr, "defined as 0x%x\n", p->value);
- else
- fprintf(stderr, "undefined\n");
+ if (argc != 1) {
+ fprintf(stderr, "%s: No input file specifiled\n", appname);
+ usage();
+ /* NOTREACHED */
}
-}
-sym_t *
-lookup(char *name)
-{
- sym_t *p;
+ symtable_open();
+ inputfilename = *argv;
+ include_file(*argv, SOURCE_FILE);
+ retval = yyparse();
+ if (retval == 0) {
+ back_patch();
+ if (ofile != NULL)
+ output_code(ofile);
+ if (regfile != NULL)
+ symtable_dump(regfile);
+ if (listfile != NULL)
+ output_listing(listfile, inputfilename);
+ }
- for (p = head; p; p = p->next)
- if (!strcmp(p->name, name))
- return(p);
- return(NULL);
+ stop(NULL, 0);
+ /* NOTREACHED */
+ return (0);
}
-void
-patch(sym_t *p, int location)
+static void
+usage()
{
- p->npatch += 1;
- p->patch = (int *)Realloc(p->patch, p->npatch * sizeof(int *));
- p->patch[p->npatch - 1] = location;
+ (void)fprintf(stderr, "usage: %s [-I directory] [-o output_file] "
+ "input_file\n", appname);
+ exit(EX_USAGE);
}
-void backpatch(void)
+static void
+back_patch()
{
- int i;
- sym_t *p;
+ struct instruction *cur_instr;
- for (p = head; p; p = p->next) {
+ for(cur_instr = seq_program.stqh_first;
+ cur_instr != NULL;
+ cur_instr = cur_instr->links.stqe_next) {
+ if (cur_instr->patch_label != NULL) {
+ struct ins_format3 *f3_instr;
+ u_int address;
- if (p->value == NOVALUE) {
- fprintf(stderr,
- "%s: undefined symbol \"%s\"\n",
- filename, p->name);
- exit(EXIT_FAILURE);
- }
+ if (cur_instr->patch_label->type != LABEL) {
+ char buf[255];
- if (p->npatch) {
- if (debug)
- fprintf(stderr,
- "\"%s\" (0x%x) patched at",
- p->name, p->value);
-
- for (i = 0; i < p->npatch; i++) {
- M[p->patch[i]][0] &= ~1;
- M[p->patch[i]][0] |= ((p->value >> 8) & 1);
- M[p->patch[i]][1] = p->value & 0xff;
-
- if (debug)
- fprintf(stderr, " 0x%x", p->patch[i]);
+ snprintf(buf, sizeof(buf),
+ "Undefined label %s",
+ cur_instr->patch_label->name);
+ stop(buf, EX_DATAERR);
+ /* NOTREACHED */
}
-
- if (debug)
- fputc('\n', stderr);
+ f3_instr = &cur_instr->format.format3;
+ address = ((f3_instr->opcode_addr & ADDR_HIGH_BIT) << 8)
+ | f3_instr->address;
+ address += cur_instr->patch_label->info.linfo->address;
+ f3_instr->opcode_addr &= ~ADDR_HIGH_BIT;
+ f3_instr->opcode_addr |= (address >> 8) & ADDR_HIGH_BIT;
+ f3_instr->address = address & 0xFF;
}
}
}
-/*
- * Output words in byte-reversed order (least significant first)
- * since the sequencer RAM is loaded that way.
- */
-void
-output(FILE *fp)
-{
- int i;
-
- for (i = 0; i < LC; i++)
- fprintf(fp, "\t0x%02x, 0x%02x, 0x%02x, 0x%02x,\n",
- M[i][3],
- M[i][2],
- M[i][1],
- M[i][0]);
- printf("%d out of %d instructions used.\n", LC, MEMORY);
-}
-
-char **
-getl(int *n)
+static void
+output_code(ofile)
+ FILE *ofile;
{
- int i;
- char *p, *quote;
- static char buf[MAXLINE];
- static char *a[MAXTOKEN];
-
- i = 0;
-
- while (fgets(buf, sizeof(buf), stdin)) {
-
- lineno += 1;
+ struct instruction *cur_instr;
+ patch_t *cur_patch;
+ symbol_node_t *cur_node;
+ int instrcount;
- if (buf[strlen(buf)-1] != '\n')
- error("line too long");
+ instrcount = 0;
+ fprintf(ofile,
+"/*
+ * DO NOT EDIT - This file is automatically generated.
+ */\n");
- p = strchr(buf, '#');
- if (p)
- *p = '\0';
- p = buf;
-rescan:
- quote = strchr(p, '\"');
- if (quote)
- *quote = '\0';
- for (p = strtok(p, ", \t\n"); p; p = strtok(NULL, ", \t\n"))
- if (i < MAXTOKEN-1)
- a[i++] = p;
- else
- error("too many tokens");
- if (quote) {
- quote++;
- p = strchr(quote, '\"');
- if (!p)
- error("unterminated string constant");
- else if (i < MAXTOKEN-1) {
- a[i++] = quote;
- *p = '\0';
- p++;
- }
- else
- error("too many tokens");
- goto rescan;
- }
- if (i) {
- *n = i;
- return(a);
- }
+ fprintf(ofile, "static u_int8_t seqprog[] = {\n");
+ for(cur_instr = seq_program.stqh_first;
+ cur_instr != NULL;
+ cur_instr = cur_instr->links.stqe_next) {
+ fprintf(ofile, "\t0x%02x, 0x%02x, 0x%02x, 0x%02x,\n",
+ cur_instr->format.bytes[0],
+ cur_instr->format.bytes[1],
+ cur_instr->format.bytes[2],
+ cur_instr->format.bytes[3]);
+ instrcount++;
}
- return(NULL);
-}
+ fprintf(ofile, "};\n");
-#define A 0x8000 /* `A'ccumulator ok */
-#define I 0x4000 /* use as immediate value */
-#define SL 0x2000 /* shift left */
-#define SR 0x1000 /* shift right */
-#define RL 0x0800 /* rotate left */
-#define RR 0x0400 /* rotate right */
-#define LO 0x8000 /* lookup: ori-{jmp,jc,jnc,call} */
-#define LA 0x4000 /* lookup: and-{jz,jnz} */
-#define LX 0x2000 /* lookup: xor-{je,jne} */
-#define NA -1 /* not applicable */
-
-struct {
- char *name;
- int n; /* number of operands, including opcode */
- unsigned int op; /* immediate or L?|pos_from_0 */
- unsigned int dest; /* NA, pos_from_0, or I|immediate */
- unsigned int src; /* NA, pos_from_0, or I|immediate */
- unsigned int imm; /* pos_from_0, A|pos_from_0, or I|immediate */
- unsigned int addr; /* NA or pos_from_0 */
- int fmt; /* instruction format - 1, 2, or 3 */
-} instr[] = {
-/*
- * N OP DEST SRC IMM ADDR FMT
- */
- { "mov", 3, 1, 1, 2, I|0xff, NA, 1 },
- { "mov", 4, LO|2, NA, 1, I|0, 3, 3 },
- { "mvi", 3, 0, 1, I|R_ALLZEROS, A|2, NA, 1 },
- { "mvi", 4, LO|2, NA, I|R_ALLZEROS, 1, 3, 3 },
- { "not", 2, 2, 1, 1, I|0xff, NA, 1 },
- { "and", 3, 1, 1, 1, A|2, NA, 1 },
- { "and", 4, 1, 1, 3, A|2, NA, 1 },
- { "or", 3, 0, 1, 1, A|2, NA, 1 },
- { "or", 4, 0, 1, 3, A|2, NA, 1 },
- { "or", 5, LO|3, NA, 1, 2, 4, 3 },
- { "xor", 3, 2, 1, 1, A|2, NA, 1 },
- { "xor", 4, 2, 1, 3, A|2, NA, 1 },
- { "nop", 1, 1, I|R_NONE, I|R_ALLZEROS, I|0xff, NA, 1 },
- { "inc", 2, 3, 1, 1, I|1, NA, 1 },
- { "inc", 3, 3, 1, 2, I|1, NA, 1 },
- { "dec", 2, 3, 1, 1, I|0xff, NA, 1 },
- { "dec", 3, 3, 1, 2, I|0xff, NA, 1 },
- { "jmp", 2, LO|0, NA, I|R_SINDEX, I|0, 1, 3 },
- { "jc", 2, LO|0, NA, I|R_SINDEX, I|0, 1, 3 },
- { "jnc", 2, LO|0, NA, I|R_SINDEX, I|0, 1, 3 },
- { "call", 2, LO|0, NA, I|R_SINDEX, I|0, 1, 3 },
- { "test", 5, LA|3, NA, 1, A|2, 4, 3 },
- { "cmp", 5, LX|3, NA, 1, A|2, 4, 3 },
- { "ret", 1, 1, I|R_NONE, I|R_ALLZEROS, I|0xff, NA, 1 },
- { "ret", 1, 1, I|R_NONE, I|R_ALLZEROS, I|0xff, NA, 1 },
- { "clc", 1, 3, I|R_NONE, I|R_ALLZEROS, I|1, NA, 1 },
- { "clc", 4, 3, 2, I|R_ALLZEROS, A|3, NA, 1 },
- { "stc", 2, 3, 1, I|R_ALLONES, I|1, NA, 1 },
- { "add", 3, 3, 1, 1, A|2, NA, 1 },
- { "add", 4, 3, 1, 3, A|2, NA, 1 },
- { "adc", 3, 4, 1, 1, A|2, NA, 1 },
- { "adc", 4, 4, 1, 3, A|2, NA, 1 },
- { "shl", 3, 5, 1, 1, SL|2, NA, 2 },
- { "shl", 4, 5, 1, 2, SL|3, NA, 2 },
- { "shr", 3, 5, 1, 1, SR|2, NA, 2 },
- { "shr", 4, 5, 1, 2, SR|3, NA, 2 },
- { "rol", 3, 5, 1, 1, RL|2, NA, 2 },
- { "rol", 4, 5, 1, 2, RL|3, NA, 2 },
- { "ror", 3, 5, 1, 1, RR|2, NA, 2 },
- { "ror", 4, 5, 1, 2, RR|3, NA, 2 },
/*
- * Extensions (note also that mvi allows A)
+ * Output the patch list, option definitions first.
*/
- { "clr", 2, 1, 1, I|R_ALLZEROS, I|0xff, NA, 1 },
- { 0, 0, 0, 0, 0, 0, 0, 0 }
-};
-
-int
-eval_operand(char **a, int spec)
-{
- int i;
- unsigned int want = spec & (LO|LA|LX);
-
- static struct {
- unsigned int what;
- char *name;
- int value;
- } jmptab[] = {
- { LO, "jmp", 8 },
- { LO, "jc", 9 },
- { LO, "jnc", 10 },
- { LO, "call", 11 },
- { LA, "jz", 15 },
- { LA, "jnz", 13 },
- { LX, "je", 14 },
- { LX, "jne", 12 },
- };
-
- spec &= ~(LO|LA|LX);
-
- for (i = 0; i < sizeof(jmptab)/sizeof(jmptab[0]); i++)
- if (jmptab[i].what == want &&
- !strcmp(jmptab[i].name, a[spec]))
- {
- return(jmptab[i].value);
- }
-
- if (want)
- error("invalid jump");
-
- return(spec); /* "case 0" - no flags set */
-}
-
-int
-eval_sdi(char **a, int spec)
-{
- sym_t *p;
- unsigned val;
-
- if (spec == NA)
- return(NA);
-
- switch (spec & (A|I|SL|SR|RL|RR)) {
- case SL:
- case SR:
- case RL:
- case RR:
- if (isdigit(*a[spec &~ (SL|SR|RL|RR)]))
- val = strtol(a[spec &~ (SL|SR|RL|RR)], NULL, 0);
- else {
- p = lookup(a[spec &~ (SL|SR|RL|RR)]);
- if (!p)
- error("undefined symbol used");
- val = p->value;
- }
-
- switch (spec & (SL|SR|RL|RR)) { /* blech */
- case SL:
- if (val > 7)
- return(0xf0);
- return(((val % 8) << 4) |
- (val % 8));
- case SR:
- if (val > 7)
- return(0xf0);
- return(((val % 8) << 4) |
- (1 << 3) |
- ((8 - (val % 8)) % 8));
- case RL:
- return(val % 8);
- case RR:
- return((8 - (val % 8)) % 8);
- }
- case I:
- return(spec &~ I);
- case A:
- /*
- * An immediate field of zero selects
- * the accumulator. Vigorously object
- * if zero is given otherwise - it's
- * most likely an error.
- */
- spec &= ~A;
- if (!strcmp("A", a[spec]))
- return(0);
- if (isdigit(*a[spec]) &&
- strtol(a[spec], NULL, 0) == 0)
- {
- error("immediate value of zero selects accumulator");
- }
- /* falls through */
- case 0:
- if (isdigit(*a[spec]))
- return(strtol(a[spec], NULL, 0));
- p = lookup(a[spec]);
- if (p)
- return(p->value);
- error("undefined symbol used");
+ for(cur_node = patch_options.slh_first;
+ cur_node != NULL;
+ cur_node = cur_node->links.sle_next) {
+ fprintf(ofile, "#define\t%-16s\t0x%x\n", cur_node->symbol->name,
+ cur_node->symbol->info.condinfo->value);
}
+ symlist_free(&patch_options);
- return(NA); /* shut the compiler up */
-}
-
-int
-eval_addr(char **a, int spec)
-{
- sym_t *p;
+ fprintf(ofile,
+"struct patch {
+ int options;
+ int negative;
+ int begin;
+ int end;
+} patches[] = {\n");
- if (spec == NA)
- return(NA);
- if (isdigit(*a[spec]))
- return(strtol(a[spec], NULL, 0));
+ for(cur_patch = patch_list.stqh_first;
+ cur_patch != NULL;
+ cur_patch = cur_patch->links.stqe_next)
- p = lookup(a[spec]);
+ fprintf(ofile, "\t{ 0x%08x, %d, 0x%03x, 0x%03x },\n",
+ cur_patch->options, cur_patch->negative, cur_patch->begin,
+ cur_patch->end);
- if (p) {
- if (p->value != NOVALUE)
- return(p->value);
- patch(p, LC);
- } else {
- define(a[spec], NOVALUE);
- p = lookup(a[spec]);
- patch(p, LC);
- }
-
- return(NA); /* will be patched in later */
+ 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);
}
-int
-crack(char **a, int n)
+void
+output_listing(listfile, ifilename)
+ FILE *listfile;
+ char *ifilename;
{
- int i;
- int I_imm, I_addr;
- int I_op, I_dest, I_src, I_ret;
+ FILE *ifile;
+ int line;
+ struct instruction *cur_instr;
+ int instrcount;
+ char buf[1024];
- /*
- * Check for "ret" at the end of the line; remove
- * it unless it's "ret" alone - we still want to
- * look it up in the table.
- */
- I_ret = (strcmp(a[n-1], "ret") ? 0 : !0);
- if (I_ret && n > 1)
- n -= 1;
-
- for (i = 0; instr[i].name; i++) {
- /*
- * Look for match in table given constraints,
- * currently just the name and the number of
- * operands.
- */
- if (!strcmp(instr[i].name, *a) && instr[i].n == n)
- break;
+ instrcount = 0;
+ line = 1;
+ if ((ifile = fopen(ifilename, "r")) == NULL) {
+ perror(ifilename);
+ stop(NULL, EX_DATAERR);
}
- if (!instr[i].name)
- error("unknown opcode or wrong number of operands");
-
- I_op = eval_operand(a, instr[i].op);
- I_src = eval_sdi(a, instr[i].src);
- I_imm = eval_sdi(a, instr[i].imm);
- I_dest = eval_sdi(a, instr[i].dest);
- I_addr = eval_addr(a, instr[i].addr);
-
- if( LC >= MEMORY )
- error("Memory exhausted!\n");
-
- switch (instr[i].fmt) {
- case 1:
- case 2:
- M[LC][0] = (I_op << 1) | I_ret;
- M[LC][1] = I_dest;
- M[LC][2] = I_src;
- M[LC][3] = I_imm;
- break;
- case 3:
- if (I_ret)
- error("illegal use of \"ret\"");
- M[LC][0] = (I_op << 1) | ((I_addr >> 8) & 1);
- M[LC][1] = I_addr & 0xff;
- M[LC][2] = I_src;
- M[LC][3] = I_imm;
- break;
+ for(cur_instr = seq_program.stqh_first;
+ cur_instr != NULL;
+ cur_instr = cur_instr->links.stqe_next) {
+ while (line < cur_instr->srcline) {
+ fgets(buf, sizeof(buf), ifile);
+ fprintf(listfile, "\t\t%s", buf);
+ line++;
+ }
+ fprintf(listfile, "%03x %02x%02x%02x%02x", instrcount,
+ cur_instr->format.bytes[0],
+ cur_instr->format.bytes[1],
+ cur_instr->format.bytes[2],
+ cur_instr->format.bytes[3]);
+ fgets(buf, sizeof(buf), ifile);
+ fprintf(listfile, "%s", buf);
+ line++;
+ instrcount++;
}
-
- return (1); /* no two-byte instructions yet */
+ fclose(ifile);
}
-#undef SL
-#undef SR
-#undef RL
-#undef RR
-#undef LX
-#undef LA
-#undef LO
-#undef I
-#undef A
-
+/*
+ * Print out error information if appropriate, and clean up before
+ * terminating the program.
+ */
void
-assemble(FILE *ofile)
+stop(string, err_code)
+ const char *string;
+ int err_code;
{
- int n;
- char **a;
- sym_t *p;
-
- while ((a = getl(&n))) {
-
- while (a[0][strlen(*a)-1] == ':') {
- a[0][strlen(*a)-1] = '\0';
- p = lookup(*a);
- if (p)
- p->value = LC;
- else
- define(*a, LC);
- a += 1;
- n -= 1;
+ if (string != NULL) {
+ fprintf(stderr, "%s: ", appname);
+ if (yyfilename != NULL) {
+ fprintf(stderr, "Stopped at file %s, line %d - ",
+ yyfilename, yylineno);
}
+ fprintf(stderr, "%s\n", string);
+ }
- if (!n) /* line was all labels */
- continue;
-
- if (n == 3 && !strcmp("VERSION", *a))
- fprintf(ofile, "#define %s \"%s\"\n", a[1], a[2]);
- else {
- if (n == 3 && !strcmp("=", a[1]))
- define(*a, strtol(a[2], NULL, 0));
- else
- LC += crack(a, n);
+ if (ofile != NULL) {
+ fclose(ofile);
+ if (err_code != 0) {
+ fprintf(stderr, "%s: Removing %s due to error\n",
+ appname, ofilename);
+ unlink(ofilename);
}
}
- backpatch();
- output(ofile);
+ symtable_close();
- if (debug)
- output(stderr);
+ exit(err_code);
}
-int
-main(int argc, char **argv)
+struct instruction *
+seq_alloc()
{
- int c;
- int pid;
- int ifile;
- FILE *ofile;
- int fd[2];
+ struct instruction *new_instr;
- ofile = NULL;
- while ((c = getopt(argc, argv, "dho:vD:")) != EOF) {
- switch (c) {
- case 'd':
- debug = !0;
- break;
- case 'D':
- {
- char *p;
- if ((p = strchr(optarg, '=')) != NULL) {
- *p = '\0';
- define(optarg, strtol(p + 1, NULL, 0));
- }
- else
- define(optarg, 1);
- break;
- }
- case 'o':
-
- if ((ofile = fopen(optarg, "w")) == NULL) {
- perror(optarg);
- exit(EXIT_FAILURE);
- }
- break;
- case 'h':
- printf("usage: %s [-d] [-Dname] [-ooutput] input\n",
- *argv);
- exit(EXIT_SUCCESS);
- break;
- case 'v':
- printf("%s\n", id);
- exit(EXIT_SUCCESS);
- break;
- default:
- exit(EXIT_FAILURE);
- break;
- }
- }
-
- if (argc - optind != 1) {
- fprintf(stderr, "%s: must have one input file\n", *argv);
- exit(EXIT_FAILURE);
- }
- filename = argv[optind];
-
-
- if ((ifile = open(filename, O_RDONLY)) < 0) {
- perror(filename);
- exit(EXIT_FAILURE);
- }
-
- if (!ofile) {
- if ((ofile = fopen(ADOTOUT, "w")) == NULL) {
- perror(ADOTOUT);
- exit(EXIT_FAILURE);
- }
- }
+ new_instr = (struct instruction *)malloc(sizeof(struct instruction));
+ if (new_instr == NULL)
+ stop("Unable to malloc instruction object", EX_SOFTWARE);
+ memset(new_instr, 0, sizeof(*new_instr));
+ STAILQ_INSERT_TAIL(&seq_program, new_instr, links);
+ new_instr->srcline = yylineno;
+ return new_instr;
+}
- if (pipe(fd) < 0) {
- perror("pipe failed");
- exit(1);
- }
+patch_t *
+patch_alloc()
+{
+ patch_t *new_patch;
- if ((pid = fork()) < 0 ) {
- perror("fork failed");
- exit(1);
- }
- else if (pid > 0) { /* Parent */
- close(fd[1]); /* Close write end */
- if (fd[0] != STDIN_FILENO) {
- if (dup2(fd[0], STDIN_FILENO) != STDIN_FILENO) {
- perror("dup2 error on stdin");
- exit(EXIT_FAILURE);
- }
- close(fd[0]);
- }
- assemble(ofile);
- exit(EXIT_SUCCESS);
- }
- else { /* Child */
- close(fd[0]); /* Close Read end */
- if (fd[1] != STDOUT_FILENO) {
- if (dup2(fd[1], STDOUT_FILENO) != STDOUT_FILENO) {
- perror("dup2 error on stdout");
- exit(EXIT_FAILURE);
- }
- close(fd[1]);
- }
- if (ifile != STDIN_FILENO) {
- if (dup2(ifile, STDIN_FILENO) != STDIN_FILENO) {
- perror("dup2 error on stdin");
- exit(EXIT_FAILURE);
- }
- close(ifile);
- }
- execl("/usr/bin/cpp", "/usr/bin/cpp", "-P", "-", "-", NULL);
- }
- return(EXIT_SUCCESS);
+ 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;
}
diff --git a/sys/dev/aic7xxx/aicasm/Makefile b/sys/dev/aic7xxx/aicasm/Makefile
new file mode 100644
index 0000000000000..2a142b0a58852
--- /dev/null
+++ b/sys/dev/aic7xxx/aicasm/Makefile
@@ -0,0 +1,18 @@
+# $Id$
+
+PROG= aic7xxx_asm
+
+CSRCS= aic7xxx_asm.c symbol.c
+GENSRCS= gram.c scan.c
+
+GENHDRS= y.tab.h token.h
+# Hack so non root users you can build kernels
+BINOWN!= id -u -n
+BINGRP!= id -g -n
+
+SRCS= ${GENSRCS} ${CSRCS}
+CLEANFILES+= ${GENSRCS} ${GENHDRS} y.output
+DPADD+= ${LIBL}
+LDADD+= -ll
+NOMAN= noman
+.include <bsd.prog.mk>
diff --git a/sys/dev/aic7xxx/aicasm/aicasm.c b/sys/dev/aic7xxx/aicasm/aicasm.c
index d3e09f6aeba03..efed828a13a3a 100644
--- a/sys/dev/aic7xxx/aicasm/aicasm.c
+++ b/sys/dev/aic7xxx/aicasm/aicasm.c
@@ -1,31 +1,26 @@
-/*+M*************************************************************************
- * Adaptec AIC7770/AIC7870 sequencer code assembler.
+/*
+ * Aic7xxx SCSI host adapter firmware asssembler
*
- * Copyright (c) 1994 John Aycock
- * The University of Calgary Department of Computer Science.
- * All rights reserved.
+ * Copyright (c) 1997 Justin T. Gibbs.
+ * All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer.
+ * 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. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of Calgary
- * Department of Computer Science and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * 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
@@ -33,653 +28,380 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * Comments are started by `#' and continue to the end of the line; lines
- * may be of the form:
- * <label>*
- * <label>* <undef-sym> = <value>
- * <label>* <opcode> <operand>*
- *
- * A <label> is an <undef-sym> ending in a colon. Spaces, tabs, and commas
- * are token separators.
- *
- *-M*************************************************************************/
-static char id[] = "$Id$";
-#include <ctype.h>
+ * $Id$
+ */
+#include <sys/types.h>
+#include <sys/mman.h>
+
#include <stdio.h>
-#include <string.h>
#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
#include <unistd.h>
-#include <fcntl.h>
-#define MEMORY 448
-#define MAXLINE 1024
-#define MAXTOKEN 32
-#define ADOTOUT "a.out"
-#define NOVALUE -1
+#include "aic7xxx_asm.h"
+#include "symbol.h"
+#include "sequencer.h"
-/*
- * AIC-7770/AIC-7870 register definitions
- */
-#define R_SINDEX 0x65
-#define R_ALLONES 0x69
-#define R_ALLZEROS 0x6a
-#define R_NONE 0x6a
+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));
-int debug;
-int lineno, LC;
-char *filename;
-unsigned char M[MEMORY][4];
+struct path_list search_path;
+int includes_search_curdir;
+char *appname;
+FILE *ofile;
+char *ofilename;
-void
-error(char *s)
-{
- fprintf(stderr, "%s: %s at line %d\n", filename, s, lineno);
- exit(EXIT_FAILURE);
-}
+static STAILQ_HEAD(,instruction) seq_program;
+static STAILQ_HEAD(, patch) patch_list;
+symlist_t patch_options;
-void *
-Malloc(size_t size)
-{
- void *p = malloc(size);
- if (!p)
- error("out of memory");
- return(p);
-}
+#if DEBUG
+extern int yy_flex_debug;
+extern int yydebug;
+#endif
+extern FILE *yyin;
+extern int yyparse __P((void));
-void *
-Realloc(void *ptr, size_t size)
-{
- void *p = realloc(ptr, size);
- if (!p)
- error("out of memory");
- return(p);
-}
-
-char *
-Strdup(char *s)
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
{
- char *p = (char *)Malloc(strlen(s) + 1);
- strcpy(p, s);
- return(p);
-}
+ extern char *optarg;
+ extern int optind;
+ int ch;
+ int retval;
+ char *inputfilename;
+ char *regfilename;
+ FILE *regfile;
+ char *listfilename;
+ FILE *listfile;
-typedef struct sym_t {
- struct sym_t *next; /* MUST BE FIRST */
- char *name;
- int value;
- int npatch;
- int *patch;
-} sym_t;
-
-sym_t *head;
-
-void
-define(char *name, int value)
-{
- sym_t *p, *q;
+ SLIST_INIT(&search_path);
+ STAILQ_INIT(&seq_program);
+ STAILQ_INIT(&patch_list);
+ SLIST_INIT(&patch_options);
+ includes_search_curdir = 1;
+ appname = *argv;
+ regfile = NULL;
+ listfile = NULL;
+#if DEBUG
+ yy_flex_debug = 0;
+#endif
+ while ((ch = getopt(argc, argv, "d:l:n:o:r:I:")) != EOF) {
+ switch(ch) {
+ case 'd':
+#if DEBUG
+ if (strcmp(optarg, "s") == 0)
+ yy_flex_debug = 1;
+ else if (strcmp(optarg, "p") == 0)
+ yydebug = 1;
+#else
+ stop("-d: Assembler not built with debugging "
+ "information", EX_SOFTWARE);
+#endif
+ break;
+ case 'l':
+ /* Create a program listing */
+ if ((listfile = fopen(optarg, "w")) == NULL) {
+ perror(optarg);
+ stop(NULL, EX_CANTCREAT);
+ }
+ listfilename = optarg;
+ break;
+ case 'n':
+ /* Don't complain about the -nostdinc directrive */
+ if (strcmp(optarg, "ostdinc")) {
+ fprintf(stderr, "%s: Unknown option -%c%s\n",
+ appname, ch, optarg);
+ usage();
+ /* NOTREACHED */
+ }
+ break;
+ case 'o':
+ if ((ofile = fopen(optarg, "w")) == NULL) {
+ perror(optarg);
+ stop(NULL, EX_CANTCREAT);
+ }
+ ofilename = optarg;
+ break;
+ case 'r':
+ if ((regfile = fopen(optarg, "w")) == NULL) {
+ perror(optarg);
+ stop(NULL, EX_CANTCREAT);
+ }
+ regfilename = optarg;
+ break;
+ case 'I':
+ {
+ path_entry_t include_dir;
- for (p = head, q = (sym_t *)&head; p; p = p->next) {
- if (!strcmp(p->name, name))
- error("redefined symbol");
- q = p;
+ if (strcmp(optarg, "-") == 0) {
+ if (includes_search_curdir == 0) {
+ fprintf(stderr, "%s: Warning - '-I-' "
+ "specified multiple "
+ "times\n", appname);
+ }
+ includes_search_curdir = 0;
+ for (include_dir = search_path.slh_first;
+ include_dir != NULL;
+ include_dir = include_dir->links.sle_next)
+ /*
+ * All entries before a '-I-' only
+ * apply to includes specified with
+ * quotes instead of "<>".
+ */
+ include_dir->quoted_includes_only = 1;
+ } else {
+ include_dir =
+ (path_entry_t)malloc(sizeof(*include_dir));
+ if (include_dir == NULL) {
+ perror(optarg);
+ stop(NULL, EX_OSERR);
+ }
+ include_dir->directory = strdup(optarg);
+ if (include_dir->directory == NULL) {
+ perror(optarg);
+ stop(NULL, EX_OSERR);
+ }
+ include_dir->quoted_includes_only = 0;
+ SLIST_INSERT_HEAD(&search_path, include_dir,
+ links);
+ }
+ break;
+ }
+ case '?':
+ default:
+ usage();
+ /* NOTREACHED */
+ }
}
+ argc -= optind;
+ argv += optind;
- p = q->next = (sym_t *)Malloc(sizeof(sym_t));
- p->next = NULL;
- p->name = Strdup(name);
- p->value = value;
- p->npatch = 0;
- p->patch = NULL;
-
- if (debug) {
- fprintf(stderr, "\"%s\" ", p->name);
- if (p->value != NOVALUE)
- fprintf(stderr, "defined as 0x%x\n", p->value);
- else
- fprintf(stderr, "undefined\n");
+ if (argc != 1) {
+ fprintf(stderr, "%s: No input file specifiled\n", appname);
+ usage();
+ /* NOTREACHED */
}
-}
-sym_t *
-lookup(char *name)
-{
- sym_t *p;
+ symtable_open();
+ inputfilename = *argv;
+ include_file(*argv, SOURCE_FILE);
+ retval = yyparse();
+ if (retval == 0) {
+ back_patch();
+ if (ofile != NULL)
+ output_code(ofile);
+ if (regfile != NULL)
+ symtable_dump(regfile);
+ if (listfile != NULL)
+ output_listing(listfile, inputfilename);
+ }
- for (p = head; p; p = p->next)
- if (!strcmp(p->name, name))
- return(p);
- return(NULL);
+ stop(NULL, 0);
+ /* NOTREACHED */
+ return (0);
}
-void
-patch(sym_t *p, int location)
+static void
+usage()
{
- p->npatch += 1;
- p->patch = (int *)Realloc(p->patch, p->npatch * sizeof(int *));
- p->patch[p->npatch - 1] = location;
+ (void)fprintf(stderr, "usage: %s [-I directory] [-o output_file] "
+ "input_file\n", appname);
+ exit(EX_USAGE);
}
-void backpatch(void)
+static void
+back_patch()
{
- int i;
- sym_t *p;
+ struct instruction *cur_instr;
- for (p = head; p; p = p->next) {
+ for(cur_instr = seq_program.stqh_first;
+ cur_instr != NULL;
+ cur_instr = cur_instr->links.stqe_next) {
+ if (cur_instr->patch_label != NULL) {
+ struct ins_format3 *f3_instr;
+ u_int address;
- if (p->value == NOVALUE) {
- fprintf(stderr,
- "%s: undefined symbol \"%s\"\n",
- filename, p->name);
- exit(EXIT_FAILURE);
- }
+ if (cur_instr->patch_label->type != LABEL) {
+ char buf[255];
- if (p->npatch) {
- if (debug)
- fprintf(stderr,
- "\"%s\" (0x%x) patched at",
- p->name, p->value);
-
- for (i = 0; i < p->npatch; i++) {
- M[p->patch[i]][0] &= ~1;
- M[p->patch[i]][0] |= ((p->value >> 8) & 1);
- M[p->patch[i]][1] = p->value & 0xff;
-
- if (debug)
- fprintf(stderr, " 0x%x", p->patch[i]);
+ snprintf(buf, sizeof(buf),
+ "Undefined label %s",
+ cur_instr->patch_label->name);
+ stop(buf, EX_DATAERR);
+ /* NOTREACHED */
}
-
- if (debug)
- fputc('\n', stderr);
+ f3_instr = &cur_instr->format.format3;
+ address = ((f3_instr->opcode_addr & ADDR_HIGH_BIT) << 8)
+ | f3_instr->address;
+ address += cur_instr->patch_label->info.linfo->address;
+ f3_instr->opcode_addr &= ~ADDR_HIGH_BIT;
+ f3_instr->opcode_addr |= (address >> 8) & ADDR_HIGH_BIT;
+ f3_instr->address = address & 0xFF;
}
}
}
-/*
- * Output words in byte-reversed order (least significant first)
- * since the sequencer RAM is loaded that way.
- */
-void
-output(FILE *fp)
-{
- int i;
-
- for (i = 0; i < LC; i++)
- fprintf(fp, "\t0x%02x, 0x%02x, 0x%02x, 0x%02x,\n",
- M[i][3],
- M[i][2],
- M[i][1],
- M[i][0]);
- printf("%d out of %d instructions used.\n", LC, MEMORY);
-}
-
-char **
-getl(int *n)
+static void
+output_code(ofile)
+ FILE *ofile;
{
- int i;
- char *p, *quote;
- static char buf[MAXLINE];
- static char *a[MAXTOKEN];
-
- i = 0;
-
- while (fgets(buf, sizeof(buf), stdin)) {
-
- lineno += 1;
+ struct instruction *cur_instr;
+ patch_t *cur_patch;
+ symbol_node_t *cur_node;
+ int instrcount;
- if (buf[strlen(buf)-1] != '\n')
- error("line too long");
+ instrcount = 0;
+ fprintf(ofile,
+"/*
+ * DO NOT EDIT - This file is automatically generated.
+ */\n");
- p = strchr(buf, '#');
- if (p)
- *p = '\0';
- p = buf;
-rescan:
- quote = strchr(p, '\"');
- if (quote)
- *quote = '\0';
- for (p = strtok(p, ", \t\n"); p; p = strtok(NULL, ", \t\n"))
- if (i < MAXTOKEN-1)
- a[i++] = p;
- else
- error("too many tokens");
- if (quote) {
- quote++;
- p = strchr(quote, '\"');
- if (!p)
- error("unterminated string constant");
- else if (i < MAXTOKEN-1) {
- a[i++] = quote;
- *p = '\0';
- p++;
- }
- else
- error("too many tokens");
- goto rescan;
- }
- if (i) {
- *n = i;
- return(a);
- }
+ fprintf(ofile, "static u_int8_t seqprog[] = {\n");
+ for(cur_instr = seq_program.stqh_first;
+ cur_instr != NULL;
+ cur_instr = cur_instr->links.stqe_next) {
+ fprintf(ofile, "\t0x%02x, 0x%02x, 0x%02x, 0x%02x,\n",
+ cur_instr->format.bytes[0],
+ cur_instr->format.bytes[1],
+ cur_instr->format.bytes[2],
+ cur_instr->format.bytes[3]);
+ instrcount++;
}
- return(NULL);
-}
+ fprintf(ofile, "};\n");
-#define A 0x8000 /* `A'ccumulator ok */
-#define I 0x4000 /* use as immediate value */
-#define SL 0x2000 /* shift left */
-#define SR 0x1000 /* shift right */
-#define RL 0x0800 /* rotate left */
-#define RR 0x0400 /* rotate right */
-#define LO 0x8000 /* lookup: ori-{jmp,jc,jnc,call} */
-#define LA 0x4000 /* lookup: and-{jz,jnz} */
-#define LX 0x2000 /* lookup: xor-{je,jne} */
-#define NA -1 /* not applicable */
-
-struct {
- char *name;
- int n; /* number of operands, including opcode */
- unsigned int op; /* immediate or L?|pos_from_0 */
- unsigned int dest; /* NA, pos_from_0, or I|immediate */
- unsigned int src; /* NA, pos_from_0, or I|immediate */
- unsigned int imm; /* pos_from_0, A|pos_from_0, or I|immediate */
- unsigned int addr; /* NA or pos_from_0 */
- int fmt; /* instruction format - 1, 2, or 3 */
-} instr[] = {
-/*
- * N OP DEST SRC IMM ADDR FMT
- */
- { "mov", 3, 1, 1, 2, I|0xff, NA, 1 },
- { "mov", 4, LO|2, NA, 1, I|0, 3, 3 },
- { "mvi", 3, 0, 1, I|R_ALLZEROS, A|2, NA, 1 },
- { "mvi", 4, LO|2, NA, I|R_ALLZEROS, 1, 3, 3 },
- { "not", 2, 2, 1, 1, I|0xff, NA, 1 },
- { "and", 3, 1, 1, 1, A|2, NA, 1 },
- { "and", 4, 1, 1, 3, A|2, NA, 1 },
- { "or", 3, 0, 1, 1, A|2, NA, 1 },
- { "or", 4, 0, 1, 3, A|2, NA, 1 },
- { "or", 5, LO|3, NA, 1, 2, 4, 3 },
- { "xor", 3, 2, 1, 1, A|2, NA, 1 },
- { "xor", 4, 2, 1, 3, A|2, NA, 1 },
- { "nop", 1, 1, I|R_NONE, I|R_ALLZEROS, I|0xff, NA, 1 },
- { "inc", 2, 3, 1, 1, I|1, NA, 1 },
- { "inc", 3, 3, 1, 2, I|1, NA, 1 },
- { "dec", 2, 3, 1, 1, I|0xff, NA, 1 },
- { "dec", 3, 3, 1, 2, I|0xff, NA, 1 },
- { "jmp", 2, LO|0, NA, I|R_SINDEX, I|0, 1, 3 },
- { "jc", 2, LO|0, NA, I|R_SINDEX, I|0, 1, 3 },
- { "jnc", 2, LO|0, NA, I|R_SINDEX, I|0, 1, 3 },
- { "call", 2, LO|0, NA, I|R_SINDEX, I|0, 1, 3 },
- { "test", 5, LA|3, NA, 1, A|2, 4, 3 },
- { "cmp", 5, LX|3, NA, 1, A|2, 4, 3 },
- { "ret", 1, 1, I|R_NONE, I|R_ALLZEROS, I|0xff, NA, 1 },
- { "ret", 1, 1, I|R_NONE, I|R_ALLZEROS, I|0xff, NA, 1 },
- { "clc", 1, 3, I|R_NONE, I|R_ALLZEROS, I|1, NA, 1 },
- { "clc", 4, 3, 2, I|R_ALLZEROS, A|3, NA, 1 },
- { "stc", 2, 3, 1, I|R_ALLONES, I|1, NA, 1 },
- { "add", 3, 3, 1, 1, A|2, NA, 1 },
- { "add", 4, 3, 1, 3, A|2, NA, 1 },
- { "adc", 3, 4, 1, 1, A|2, NA, 1 },
- { "adc", 4, 4, 1, 3, A|2, NA, 1 },
- { "shl", 3, 5, 1, 1, SL|2, NA, 2 },
- { "shl", 4, 5, 1, 2, SL|3, NA, 2 },
- { "shr", 3, 5, 1, 1, SR|2, NA, 2 },
- { "shr", 4, 5, 1, 2, SR|3, NA, 2 },
- { "rol", 3, 5, 1, 1, RL|2, NA, 2 },
- { "rol", 4, 5, 1, 2, RL|3, NA, 2 },
- { "ror", 3, 5, 1, 1, RR|2, NA, 2 },
- { "ror", 4, 5, 1, 2, RR|3, NA, 2 },
/*
- * Extensions (note also that mvi allows A)
+ * Output the patch list, option definitions first.
*/
- { "clr", 2, 1, 1, I|R_ALLZEROS, I|0xff, NA, 1 },
- { 0, 0, 0, 0, 0, 0, 0, 0 }
-};
-
-int
-eval_operand(char **a, int spec)
-{
- int i;
- unsigned int want = spec & (LO|LA|LX);
-
- static struct {
- unsigned int what;
- char *name;
- int value;
- } jmptab[] = {
- { LO, "jmp", 8 },
- { LO, "jc", 9 },
- { LO, "jnc", 10 },
- { LO, "call", 11 },
- { LA, "jz", 15 },
- { LA, "jnz", 13 },
- { LX, "je", 14 },
- { LX, "jne", 12 },
- };
-
- spec &= ~(LO|LA|LX);
-
- for (i = 0; i < sizeof(jmptab)/sizeof(jmptab[0]); i++)
- if (jmptab[i].what == want &&
- !strcmp(jmptab[i].name, a[spec]))
- {
- return(jmptab[i].value);
- }
-
- if (want)
- error("invalid jump");
-
- return(spec); /* "case 0" - no flags set */
-}
-
-int
-eval_sdi(char **a, int spec)
-{
- sym_t *p;
- unsigned val;
-
- if (spec == NA)
- return(NA);
-
- switch (spec & (A|I|SL|SR|RL|RR)) {
- case SL:
- case SR:
- case RL:
- case RR:
- if (isdigit(*a[spec &~ (SL|SR|RL|RR)]))
- val = strtol(a[spec &~ (SL|SR|RL|RR)], NULL, 0);
- else {
- p = lookup(a[spec &~ (SL|SR|RL|RR)]);
- if (!p)
- error("undefined symbol used");
- val = p->value;
- }
-
- switch (spec & (SL|SR|RL|RR)) { /* blech */
- case SL:
- if (val > 7)
- return(0xf0);
- return(((val % 8) << 4) |
- (val % 8));
- case SR:
- if (val > 7)
- return(0xf0);
- return(((val % 8) << 4) |
- (1 << 3) |
- ((8 - (val % 8)) % 8));
- case RL:
- return(val % 8);
- case RR:
- return((8 - (val % 8)) % 8);
- }
- case I:
- return(spec &~ I);
- case A:
- /*
- * An immediate field of zero selects
- * the accumulator. Vigorously object
- * if zero is given otherwise - it's
- * most likely an error.
- */
- spec &= ~A;
- if (!strcmp("A", a[spec]))
- return(0);
- if (isdigit(*a[spec]) &&
- strtol(a[spec], NULL, 0) == 0)
- {
- error("immediate value of zero selects accumulator");
- }
- /* falls through */
- case 0:
- if (isdigit(*a[spec]))
- return(strtol(a[spec], NULL, 0));
- p = lookup(a[spec]);
- if (p)
- return(p->value);
- error("undefined symbol used");
+ for(cur_node = patch_options.slh_first;
+ cur_node != NULL;
+ cur_node = cur_node->links.sle_next) {
+ fprintf(ofile, "#define\t%-16s\t0x%x\n", cur_node->symbol->name,
+ cur_node->symbol->info.condinfo->value);
}
+ symlist_free(&patch_options);
- return(NA); /* shut the compiler up */
-}
-
-int
-eval_addr(char **a, int spec)
-{
- sym_t *p;
+ fprintf(ofile,
+"struct patch {
+ int options;
+ int negative;
+ int begin;
+ int end;
+} patches[] = {\n");
- if (spec == NA)
- return(NA);
- if (isdigit(*a[spec]))
- return(strtol(a[spec], NULL, 0));
+ for(cur_patch = patch_list.stqh_first;
+ cur_patch != NULL;
+ cur_patch = cur_patch->links.stqe_next)
- p = lookup(a[spec]);
+ fprintf(ofile, "\t{ 0x%08x, %d, 0x%03x, 0x%03x },\n",
+ cur_patch->options, cur_patch->negative, cur_patch->begin,
+ cur_patch->end);
- if (p) {
- if (p->value != NOVALUE)
- return(p->value);
- patch(p, LC);
- } else {
- define(a[spec], NOVALUE);
- p = lookup(a[spec]);
- patch(p, LC);
- }
-
- return(NA); /* will be patched in later */
+ 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);
}
-int
-crack(char **a, int n)
+void
+output_listing(listfile, ifilename)
+ FILE *listfile;
+ char *ifilename;
{
- int i;
- int I_imm, I_addr;
- int I_op, I_dest, I_src, I_ret;
+ FILE *ifile;
+ int line;
+ struct instruction *cur_instr;
+ int instrcount;
+ char buf[1024];
- /*
- * Check for "ret" at the end of the line; remove
- * it unless it's "ret" alone - we still want to
- * look it up in the table.
- */
- I_ret = (strcmp(a[n-1], "ret") ? 0 : !0);
- if (I_ret && n > 1)
- n -= 1;
-
- for (i = 0; instr[i].name; i++) {
- /*
- * Look for match in table given constraints,
- * currently just the name and the number of
- * operands.
- */
- if (!strcmp(instr[i].name, *a) && instr[i].n == n)
- break;
+ instrcount = 0;
+ line = 1;
+ if ((ifile = fopen(ifilename, "r")) == NULL) {
+ perror(ifilename);
+ stop(NULL, EX_DATAERR);
}
- if (!instr[i].name)
- error("unknown opcode or wrong number of operands");
-
- I_op = eval_operand(a, instr[i].op);
- I_src = eval_sdi(a, instr[i].src);
- I_imm = eval_sdi(a, instr[i].imm);
- I_dest = eval_sdi(a, instr[i].dest);
- I_addr = eval_addr(a, instr[i].addr);
-
- if( LC >= MEMORY )
- error("Memory exhausted!\n");
-
- switch (instr[i].fmt) {
- case 1:
- case 2:
- M[LC][0] = (I_op << 1) | I_ret;
- M[LC][1] = I_dest;
- M[LC][2] = I_src;
- M[LC][3] = I_imm;
- break;
- case 3:
- if (I_ret)
- error("illegal use of \"ret\"");
- M[LC][0] = (I_op << 1) | ((I_addr >> 8) & 1);
- M[LC][1] = I_addr & 0xff;
- M[LC][2] = I_src;
- M[LC][3] = I_imm;
- break;
+ for(cur_instr = seq_program.stqh_first;
+ cur_instr != NULL;
+ cur_instr = cur_instr->links.stqe_next) {
+ while (line < cur_instr->srcline) {
+ fgets(buf, sizeof(buf), ifile);
+ fprintf(listfile, "\t\t%s", buf);
+ line++;
+ }
+ fprintf(listfile, "%03x %02x%02x%02x%02x", instrcount,
+ cur_instr->format.bytes[0],
+ cur_instr->format.bytes[1],
+ cur_instr->format.bytes[2],
+ cur_instr->format.bytes[3]);
+ fgets(buf, sizeof(buf), ifile);
+ fprintf(listfile, "%s", buf);
+ line++;
+ instrcount++;
}
-
- return (1); /* no two-byte instructions yet */
+ fclose(ifile);
}
-#undef SL
-#undef SR
-#undef RL
-#undef RR
-#undef LX
-#undef LA
-#undef LO
-#undef I
-#undef A
-
+/*
+ * Print out error information if appropriate, and clean up before
+ * terminating the program.
+ */
void
-assemble(FILE *ofile)
+stop(string, err_code)
+ const char *string;
+ int err_code;
{
- int n;
- char **a;
- sym_t *p;
-
- while ((a = getl(&n))) {
-
- while (a[0][strlen(*a)-1] == ':') {
- a[0][strlen(*a)-1] = '\0';
- p = lookup(*a);
- if (p)
- p->value = LC;
- else
- define(*a, LC);
- a += 1;
- n -= 1;
+ if (string != NULL) {
+ fprintf(stderr, "%s: ", appname);
+ if (yyfilename != NULL) {
+ fprintf(stderr, "Stopped at file %s, line %d - ",
+ yyfilename, yylineno);
}
+ fprintf(stderr, "%s\n", string);
+ }
- if (!n) /* line was all labels */
- continue;
-
- if (n == 3 && !strcmp("VERSION", *a))
- fprintf(ofile, "#define %s \"%s\"\n", a[1], a[2]);
- else {
- if (n == 3 && !strcmp("=", a[1]))
- define(*a, strtol(a[2], NULL, 0));
- else
- LC += crack(a, n);
+ if (ofile != NULL) {
+ fclose(ofile);
+ if (err_code != 0) {
+ fprintf(stderr, "%s: Removing %s due to error\n",
+ appname, ofilename);
+ unlink(ofilename);
}
}
- backpatch();
- output(ofile);
+ symtable_close();
- if (debug)
- output(stderr);
+ exit(err_code);
}
-int
-main(int argc, char **argv)
+struct instruction *
+seq_alloc()
{
- int c;
- int pid;
- int ifile;
- FILE *ofile;
- int fd[2];
+ struct instruction *new_instr;
- ofile = NULL;
- while ((c = getopt(argc, argv, "dho:vD:")) != EOF) {
- switch (c) {
- case 'd':
- debug = !0;
- break;
- case 'D':
- {
- char *p;
- if ((p = strchr(optarg, '=')) != NULL) {
- *p = '\0';
- define(optarg, strtol(p + 1, NULL, 0));
- }
- else
- define(optarg, 1);
- break;
- }
- case 'o':
-
- if ((ofile = fopen(optarg, "w")) == NULL) {
- perror(optarg);
- exit(EXIT_FAILURE);
- }
- break;
- case 'h':
- printf("usage: %s [-d] [-Dname] [-ooutput] input\n",
- *argv);
- exit(EXIT_SUCCESS);
- break;
- case 'v':
- printf("%s\n", id);
- exit(EXIT_SUCCESS);
- break;
- default:
- exit(EXIT_FAILURE);
- break;
- }
- }
-
- if (argc - optind != 1) {
- fprintf(stderr, "%s: must have one input file\n", *argv);
- exit(EXIT_FAILURE);
- }
- filename = argv[optind];
-
-
- if ((ifile = open(filename, O_RDONLY)) < 0) {
- perror(filename);
- exit(EXIT_FAILURE);
- }
-
- if (!ofile) {
- if ((ofile = fopen(ADOTOUT, "w")) == NULL) {
- perror(ADOTOUT);
- exit(EXIT_FAILURE);
- }
- }
+ new_instr = (struct instruction *)malloc(sizeof(struct instruction));
+ if (new_instr == NULL)
+ stop("Unable to malloc instruction object", EX_SOFTWARE);
+ memset(new_instr, 0, sizeof(*new_instr));
+ STAILQ_INSERT_TAIL(&seq_program, new_instr, links);
+ new_instr->srcline = yylineno;
+ return new_instr;
+}
- if (pipe(fd) < 0) {
- perror("pipe failed");
- exit(1);
- }
+patch_t *
+patch_alloc()
+{
+ patch_t *new_patch;
- if ((pid = fork()) < 0 ) {
- perror("fork failed");
- exit(1);
- }
- else if (pid > 0) { /* Parent */
- close(fd[1]); /* Close write end */
- if (fd[0] != STDIN_FILENO) {
- if (dup2(fd[0], STDIN_FILENO) != STDIN_FILENO) {
- perror("dup2 error on stdin");
- exit(EXIT_FAILURE);
- }
- close(fd[0]);
- }
- assemble(ofile);
- exit(EXIT_SUCCESS);
- }
- else { /* Child */
- close(fd[0]); /* Close Read end */
- if (fd[1] != STDOUT_FILENO) {
- if (dup2(fd[1], STDOUT_FILENO) != STDOUT_FILENO) {
- perror("dup2 error on stdout");
- exit(EXIT_FAILURE);
- }
- close(fd[1]);
- }
- if (ifile != STDIN_FILENO) {
- if (dup2(ifile, STDIN_FILENO) != STDIN_FILENO) {
- perror("dup2 error on stdin");
- exit(EXIT_FAILURE);
- }
- close(ifile);
- }
- execl("/usr/bin/cpp", "/usr/bin/cpp", "-P", "-", "-", NULL);
- }
- return(EXIT_SUCCESS);
+ 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;
}
diff --git a/sys/dev/aic7xxx/aicasm/aicasm_gram.y b/sys/dev/aic7xxx/aicasm/aicasm_gram.y
new file mode 100644
index 0000000000000..0c75edca3b3ee
--- /dev/null
+++ b/sys/dev/aic7xxx/aicasm/aicasm_gram.y
@@ -0,0 +1,1304 @@
+%{
+/*
+ * Parser for the Aic7xxx SCSI Host adapter sequencer assembler.
+ *
+ * Copyright (c) 1997 Justin T. Gibbs.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * this list of conditions, and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+
+#include <sys/types.h>
+#include <sys/queue.h>
+
+#include "aic7xxx_asm.h"
+#include "symbol.h"
+#include "sequencer.h"
+
+int yylineno;
+char *yyfilename;
+static symbol_t *cur_symbol;
+static symtype cur_symtype;
+static symbol_t *accumulator;
+static symbol_ref_t allones;
+static symbol_ref_t allzeros;
+static symbol_ref_t none;
+static symbol_ref_t sindex;
+static int instruction_ptr;
+static int sram_or_scb_offset;
+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));
+static void process_register __P((symbol_t **p_symbol));
+static void format_1_instr __P((int opcode, symbol_ref_t *dest,
+ expression_t *immed, symbol_ref_t *src,
+ int ret));
+static void format_2_instr __P((int opcode, symbol_ref_t *dest,
+ expression_t *places, symbol_ref_t *src,
+ int ret));
+static void format_3_instr __P((int opcode, symbol_ref_t *src,
+ expression_t *immed, symbol_ref_t *address));
+static void test_readable_symbol __P((symbol_t *symbol));
+static void test_writable_symbol __P((symbol_t *symbol));
+static void type_check __P((symbol_t *symbol, expression_t *expression,
+ int and_op));
+static void make_expression __P((expression_t *immed, int value));
+static void add_conditional __P((symbol_t *symbol));
+
+#define YYDEBUG 1
+#define SRAM_SYMNAME "SRAM_BASE"
+#define SCB_SYMNAME "SCB_BASE"
+%}
+
+%union {
+ int value;
+ char *str;
+ symbol_t *sym;
+ symbol_ref_t sym_ref;
+ expression_t expression;
+}
+
+%token T_REGISTER
+
+%token <value> T_CONST
+
+%token T_SCB
+
+%token T_SRAM
+
+%token T_ALIAS
+
+%token T_SIZE
+
+%token <value> T_ADDRESS
+
+%token T_ACCESS_MODE
+
+%token <value> T_MODE
+
+%token T_BIT
+
+%token T_MASK
+
+%token <value> T_NUMBER
+
+%token <str> T_PATH
+
+%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_JMP T_JC T_JNC T_JE T_JNE T_JNZ T_JZ T_CALL
+
+%token <value> T_ADD T_ADC
+
+%token <value> T_INC T_DEC
+
+%token <value> T_STC T_CLC
+
+%token <value> T_CMP T_XOR
+
+%token <value> T_TEST T_AND
+
+%token <value> T_OR
+
+%token T_RET
+
+%token T_NOP
+
+%token T_ACCUM T_ALLONES T_ALLZEROS T_NONE T_SINDEX
+
+%token T_A
+
+%token <sym> T_SYMBOL
+
+%token T_NL
+
+%token T_IF T_ELSE T_ENDIF
+
+%type <sym_ref> reg_symbol address destination source opt_source
+
+%type <expression> expression immediate immediate_or_a
+
+%type <value> ret f1_opcode f2_opcode jmp_jc_jnc_call jz_jnz je_jne
+
+%left '|'
+%left '&'
+%left '+' '-'
+%right '~'
+%nonassoc UMINUS
+%%
+
+program:
+ include
+| program include
+| register
+| program register
+| constant
+| program constant
+| scratch_ram
+| program scratch_ram
+| scb
+| program scb
+| label
+| program label
+| conditional
+| program conditional
+| code
+| program code
+;
+
+include:
+ T_INCLUDE '<' T_PATH '>'
+ { include_file($3, BRACKETED_INCLUDE); }
+| T_INCLUDE '"' T_PATH '"'
+ { include_file($3, QUOTED_INCLUDE); }
+;
+
+register:
+ T_REGISTER { cur_symtype = REGISTER; } reg_definition
+;
+
+reg_definition:
+ T_SYMBOL '{'
+ {
+ if ($1->type != UNINITIALIZED) {
+ stop("Register multiply defined", EX_DATAERR);
+ /* NOTREACHED */
+ }
+ cur_symbol = $1;
+ cur_symbol->type = cur_symtype;
+ initialize_symbol(cur_symbol);
+ }
+ reg_attribute_list
+ '}'
+ {
+ /*
+ * Default to allowing everything in for registers
+ * with no bit or mask definitions.
+ */
+ if (cur_symbol->info.rinfo->valid_bitmask == 0)
+ cur_symbol->info.rinfo->valid_bitmask = 0xFF;
+
+ if (cur_symbol->info.rinfo->size == 0)
+ cur_symbol->info.rinfo->size = 1;
+
+ /*
+ * This might be useful for registers too.
+ */
+ if (cur_symbol->type != REGISTER) {
+ if (cur_symbol->info.rinfo->address == 0)
+ cur_symbol->info.rinfo->address =
+ sram_or_scb_offset;
+ sram_or_scb_offset +=
+ cur_symbol->info.rinfo->size;
+ }
+ cur_symbol = NULL;
+ }
+;
+
+reg_attribute_list:
+ reg_attribute
+| reg_attribute_list reg_attribute
+;
+
+reg_attribute:
+ reg_address
+| size
+| access_mode
+| bit_defn
+| mask_defn
+| alias
+| accumulator
+| allones
+| allzeros
+| none
+| sindex
+;
+
+reg_address:
+ T_ADDRESS T_NUMBER
+ {
+ cur_symbol->info.rinfo->address = $2;
+ }
+;
+
+size:
+ T_SIZE T_NUMBER
+ {
+ cur_symbol->info.rinfo->size = $2;
+ }
+;
+
+access_mode:
+ T_ACCESS_MODE T_MODE
+ {
+ cur_symbol->info.rinfo->mode = $2;
+ }
+;
+
+bit_defn:
+ T_BIT T_SYMBOL T_NUMBER
+ {
+ process_bitmask(BIT, $2, $3);
+ }
+;
+
+mask_defn:
+ T_MASK T_SYMBOL expression
+ {
+ process_bitmask(MASK, $2, $3.value);
+ }
+;
+
+alias:
+ T_ALIAS T_SYMBOL
+ {
+ if ($2->type != UNINITIALIZED) {
+ stop("Re-definition of register alias",
+ EX_DATAERR);
+ /* NOTREACHED */
+ }
+ $2->type = ALIAS;
+ initialize_symbol($2);
+ $2->info.ainfo->parent = cur_symbol;
+ }
+;
+
+accumulator:
+ T_ACCUM
+ {
+ if (accumulator != NULL) {
+ stop("Only one accumulator definition allowed",
+ EX_DATAERR);
+ /* NOTREACHED */
+ }
+ accumulator = cur_symbol;
+ }
+;
+
+allones:
+ T_ALLONES
+ {
+ if (allones.symbol != NULL) {
+ stop("Only one definition of allones allowed",
+ EX_DATAERR);
+ /* NOTREACHED */
+ }
+ allones.symbol = cur_symbol;
+ }
+;
+
+allzeros:
+ T_ALLZEROS
+ {
+ if (allzeros.symbol != NULL) {
+ stop("Only one definition of allzeros allowed",
+ EX_DATAERR);
+ /* NOTREACHED */
+ }
+ allzeros.symbol = cur_symbol;
+ }
+;
+
+none:
+ T_NONE
+ {
+ if (none.symbol != NULL) {
+ stop("Only one definition of none allowed",
+ EX_DATAERR);
+ /* NOTREACHED */
+ }
+ none.symbol = cur_symbol;
+ }
+;
+
+sindex:
+ T_SINDEX
+ {
+ if (sindex.symbol != NULL) {
+ stop("Only one definition of sindex allowed",
+ EX_DATAERR);
+ /* NOTREACHED */
+ }
+ sindex.symbol = cur_symbol;
+ }
+;
+
+expression:
+ expression '|' expression
+ {
+ $$.value = $1.value | $3.value;
+ symlist_merge(&$$.referenced_syms,
+ &$1.referenced_syms,
+ &$3.referenced_syms);
+ }
+| expression '&' expression
+ {
+ $$.value = $1.value & $3.value;
+ symlist_merge(&$$.referenced_syms,
+ &$1.referenced_syms,
+ &$3.referenced_syms);
+ }
+| expression '+' expression
+ {
+ $$.value = $1.value + $3.value;
+ symlist_merge(&$$.referenced_syms,
+ &$1.referenced_syms,
+ &$3.referenced_syms);
+ }
+| expression '-' expression
+ {
+ $$.value = $1.value - $3.value;
+ symlist_merge(&($$.referenced_syms),
+ &($1.referenced_syms),
+ &($3.referenced_syms));
+ }
+| '(' expression ')'
+ {
+ $$ = $2;
+ }
+| '~' expression
+ {
+ $$ = $2;
+ $$.value = (~$$.value) & 0xFF;
+ }
+| '-' expression %prec UMINUS
+ {
+ $$ = $2;
+ $$.value = -$$.value;
+ }
+| T_NUMBER
+ {
+ $$.value = $1;
+ SLIST_INIT(&$$.referenced_syms);
+ }
+| T_SYMBOL
+ {
+ symbol_t *symbol;
+
+ symbol = $1;
+ switch (symbol->type) {
+ case ALIAS:
+ symbol = $1->info.ainfo->parent;
+ case REGISTER:
+ case SCBLOC:
+ case SRAMLOC:
+ $$.value = symbol->info.rinfo->address;
+ break;
+ case MASK:
+ case BIT:
+ $$.value = symbol->info.minfo->mask;
+ break;
+ case CONST:
+ $$.value = symbol->info.cinfo->value;
+ break;
+ case UNINITIALIZED:
+ default:
+ {
+ char buf[255];
+
+ snprintf(buf, sizeof(buf),
+ "Undefined symbol %s referenced",
+ symbol->name);
+ stop(buf, EX_DATAERR);
+ /* NOTREACHED */
+ break;
+ }
+ }
+ SLIST_INIT(&$$.referenced_syms);
+ symlist_add(&$$.referenced_syms, symbol, SYMLIST_INSERT_HEAD);
+ }
+;
+
+constant:
+ T_CONST T_SYMBOL T_NUMBER
+ {
+ if ($2->type != UNINITIALIZED) {
+ stop("Re-definition of constant variable",
+ EX_DATAERR);
+ /* NOTREACHED */
+ }
+ $2->type = CONST;
+ initialize_symbol($2);
+ $2->info.cinfo->value = $3;
+ $2->info.cinfo->define = $1;
+ }
+;
+
+scratch_ram:
+ T_SRAM '{'
+ {
+ cur_symbol = symtable_get(SRAM_SYMNAME);
+ cur_symtype = SRAMLOC;
+ if (cur_symbol->type != UNINITIALIZED) {
+ stop("Only one SRAM definition allowed",
+ EX_DATAERR);
+ /* NOTREACHED */
+ }
+ cur_symbol->type = SRAMLOC;
+ initialize_symbol(cur_symbol);
+ }
+ reg_address
+ {
+ sram_or_scb_offset = cur_symbol->info.rinfo->address;
+ }
+ scb_or_sram_reg_list
+ '}'
+ {
+ cur_symbol = NULL;
+ }
+;
+
+scb:
+ T_SCB '{'
+ {
+ cur_symbol = symtable_get(SCB_SYMNAME);
+ cur_symtype = SCBLOC;
+ if (cur_symbol->type != UNINITIALIZED) {
+ stop("Only one SRAM definition allowed",
+ EX_SOFTWARE);
+ /* NOTREACHED */
+ }
+ cur_symbol->type = SCBLOC;
+ initialize_symbol(cur_symbol);
+ }
+ reg_address
+ {
+ sram_or_scb_offset = cur_symbol->info.rinfo->address;
+ }
+ scb_or_sram_reg_list
+ '}'
+ {
+ cur_symbol = NULL;
+ }
+;
+
+scb_or_sram_reg_list:
+ reg_definition
+| scb_or_sram_reg_list reg_definition
+;
+
+reg_symbol:
+ T_SYMBOL
+ {
+ process_register(&$1);
+ $$.symbol = $1;
+ $$.offset = 0;
+ }
+| T_SYMBOL '[' T_NUMBER ']'
+ {
+ process_register(&$1);
+ if (($3 + 1) > $1->info.rinfo->size) {
+ stop("Accessing offset beyond range of register",
+ EX_DATAERR);
+ /* NOTREACHED */
+ }
+ $$.symbol = $1;
+ $$.offset = $3;
+ }
+| T_A
+ {
+ if (accumulator == NULL) {
+ stop("No accumulator has been defined", EX_DATAERR);
+ /* NOTREACHED */
+ }
+ $$.symbol = accumulator;
+ $$.offset = 0;
+ }
+;
+
+destination:
+ reg_symbol
+ {
+ test_writable_symbol($1.symbol);
+ $$ = $1;
+ }
+;
+
+immediate:
+ expression
+ { $$ = $1; }
+;
+
+immediate_or_a:
+ expression
+ {
+ $$ = $1;
+ }
+| T_A
+ {
+ SLIST_INIT(&$$.referenced_syms);
+ $$.value = 0;
+ }
+;
+
+source:
+ reg_symbol
+ {
+ test_readable_symbol($1.symbol);
+ $$ = $1;
+ }
+;
+
+opt_source:
+ {
+ $$.symbol = NULL;
+ $$.offset = 0;
+ }
+| ',' source
+ { $$ = $2; }
+;
+
+ret:
+ { $$ = 0; }
+| T_RET
+ { $$ = 1; }
+;
+
+label:
+ T_SYMBOL ':'
+ {
+ if ($1->type != UNINITIALIZED) {
+ stop("Program label multiply defined", EX_DATAERR);
+ /* NOTREACHED */
+ }
+ $1->type = LABEL;
+ initialize_symbol($1);
+ $1->info.linfo->address = instruction_ptr;
+ }
+;
+
+address:
+ T_SYMBOL
+ {
+ $$.symbol = $1;
+ $$.offset = 0;
+ }
+| T_SYMBOL '+' T_NUMBER
+ {
+ $$.symbol = $1;
+ $$.offset = $3;
+ }
+| T_SYMBOL '-' T_NUMBER
+ {
+ $$.symbol = $1;
+ $$.offset = -$3;
+ }
+| '.'
+ {
+ $$.symbol = NULL;
+ $$.offset = 0;
+ }
+| '.' '+' T_NUMBER
+ {
+ $$.symbol = NULL;
+ $$.offset = $3;
+ }
+| '.' '-' T_NUMBER
+ {
+ $$.symbol = NULL;
+ $$.offset = -$3;
+ }
+;
+
+conditional:
+ T_IF
+ {
+ if (cur_patch != NULL) {
+ stop("Nested .if directive", 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);
+ }
+;
+
+f1_opcode:
+ T_AND { $$ = AIC_OP_AND; }
+| T_XOR { $$ = AIC_OP_XOR; }
+| T_ADD { $$ = AIC_OP_ADD; }
+| T_ADC { $$ = AIC_OP_ADC; }
+;
+
+code:
+ f1_opcode destination ',' immediate_or_a opt_source ret ';'
+ {
+ format_1_instr($1, &$2, &$4, &$5, $6);
+ }
+;
+
+code:
+ T_OR reg_symbol ',' immediate_or_a opt_source ret ';'
+ {
+ format_1_instr(AIC_OP_OR, &$2, &$4, &$5, $6);
+ }
+;
+
+code:
+ T_INC destination opt_source ret ';'
+ {
+ expression_t immed;
+
+ make_expression(&immed, 1);
+ format_1_instr(AIC_OP_ADD, &$2, &immed, &$3, $4);
+ }
+;
+
+code:
+ T_DEC destination opt_source ret ';'
+ {
+ expression_t immed;
+
+ make_expression(&immed, -1);
+ format_1_instr(AIC_OP_ADD, &$2, &immed, &$3, $4);
+ }
+;
+
+code:
+ T_CLC ret ';'
+ {
+ expression_t immed;
+
+ make_expression(&immed, -1);
+ format_1_instr(AIC_OP_ADD, &none, &immed, &allzeros, $2);
+ }
+| T_CLC T_MVI destination ',' immediate_or_a ret ';'
+ {
+ format_1_instr(AIC_OP_ADD, &$3, &$5, &allzeros, $6);
+ }
+;
+
+code:
+ T_STC ret ';'
+ {
+ expression_t immed;
+
+ make_expression(&immed, 1);
+ format_1_instr(AIC_OP_ADD, &none, &immed, &allones, $2);
+ }
+| T_STC destination ret ';'
+ {
+ expression_t immed;
+
+ make_expression(&immed, 1);
+ format_1_instr(AIC_OP_ADD, &$2, &immed, &allones, $3);
+ }
+;
+
+code:
+ T_MOV destination ',' source ret ';'
+ {
+ expression_t immed;
+
+ make_expression(&immed, 0xff);
+ format_1_instr(AIC_OP_AND, &$2, &immed, &$4, $5);
+ }
+;
+
+code:
+ T_MVI destination ',' immediate_or_a ret ';'
+ {
+ format_1_instr(AIC_OP_OR, &$2, &$4, &allzeros, $5);
+ }
+;
+
+code:
+ T_CLR destination ret ';'
+ {
+ expression_t immed;
+
+ make_expression(&immed, 0xff);
+ format_1_instr(AIC_OP_AND, &$2, &immed, &allzeros, $3);
+ }
+;
+
+code:
+ T_NOP ';'
+ {
+ expression_t immed;
+
+ make_expression(&immed, 0xff);
+ format_1_instr(AIC_OP_AND, &none, &immed, &allzeros, FALSE);
+ }
+;
+
+code:
+ T_RET ';'
+ {
+ expression_t immed;
+
+ make_expression(&immed, 0xff);
+ format_1_instr(AIC_OP_AND, &none, &immed, &allzeros, TRUE);
+ }
+;
+
+ /*
+ * This grammer differs from the one in the aic7xxx
+ * reference manual since the grammer listed there is
+ * ambiguous and causes a shift/reduce conflict.
+ * It also seems more logical as the "immediate"
+ * argument is listed as the second arg like the
+ * other formats.
+ */
+
+f2_opcode:
+ T_SHL { $$ = AIC_OP_SHL; }
+| T_SHR { $$ = AIC_OP_SHR; }
+| T_ROL { $$ = AIC_OP_ROL; }
+| T_ROR { $$ = AIC_OP_ROR; }
+;
+
+code:
+ f2_opcode destination ',' expression opt_source ret ';'
+ {
+ format_2_instr($1, &$2, &$4, &$5, $6);
+ }
+;
+
+jmp_jc_jnc_call:
+ T_JMP { $$ = AIC_OP_JMP; }
+| T_JC { $$ = AIC_OP_JC; }
+| T_JNC { $$ = AIC_OP_JNC; }
+| T_CALL { $$ = AIC_OP_CALL; }
+;
+
+jz_jnz:
+ T_JZ { $$ = AIC_OP_JZ; }
+| T_JNZ { $$ = AIC_OP_JNZ; }
+;
+
+je_jne:
+ T_JE { $$ = AIC_OP_JE; }
+| T_JNE { $$ = AIC_OP_JNE; }
+;
+
+code:
+ jmp_jc_jnc_call address ';'
+ {
+ expression_t immed;
+
+ make_expression(&immed, 0);
+ format_3_instr($1, &sindex, &immed, &$2);
+ }
+;
+
+code:
+ T_OR reg_symbol ',' immediate jmp_jc_jnc_call address ';'
+ {
+ format_3_instr($5, &$2, &$4, &$6);
+ }
+;
+
+code:
+ T_TEST source ',' immediate_or_a jz_jnz address ';'
+ {
+ format_3_instr($5, &$2, &$4, &$6);
+ }
+;
+
+code:
+ T_CMP source ',' immediate_or_a je_jne address ';'
+ {
+ format_3_instr($5, &$2, &$4, &$6);
+ }
+;
+
+code:
+ T_MOV source jmp_jc_jnc_call address ';'
+ {
+ expression_t immed;
+
+ make_expression(&immed, 0);
+ format_3_instr($3, &$2, &immed, &$4);
+ }
+;
+
+code:
+ T_MVI immediate jmp_jc_jnc_call address ';'
+ {
+ format_3_instr($3, &allzeros, &$2, &$4);
+ }
+;
+
+%%
+
+static void
+process_bitmask(mask_type, sym, mask)
+ int mask_type;
+ symbol_t *sym;
+ int mask;
+{
+ /*
+ * Add the current register to its
+ * symbol list, if it already exists,
+ * warn if we are setting it to a
+ * different value, or in the bit to
+ * the "allowed bits" of this register.
+ */
+ if (sym->type == UNINITIALIZED) {
+ sym->type = mask_type;
+ initialize_symbol(sym);
+ if (mask_type == BIT) {
+ if (mask == 0) {
+ stop("Bitmask with no bits set", EX_DATAERR);
+ /* NOTREACHED */
+ }
+ if ((mask & ~(0x01 << (ffs(mask) - 1))) != 0) {
+ stop("Bitmask with more than one bit set",
+ EX_DATAERR);
+ /* NOTREACHED */
+ }
+ }
+ sym->info.minfo->mask = mask;
+ } else if (sym->type != mask_type) {
+ stop("Bit definition mirrors a definition of the same "
+ " name, but a different type", EX_DATAERR);
+ /* NOTREACHED */
+ } else if (mask != sym->info.minfo->mask) {
+ stop("Bitmask redefined with a conflicting value", EX_DATAERR);
+ /* NOTREACHED */
+ }
+ /* Fail if this symbol is already listed */
+ if (symlist_search(&(sym->info.minfo->symrefs),
+ cur_symbol->name) != NULL) {
+ stop("Bitmask defined multiple times for register", EX_DATAERR);
+ /* NOTREACHED */
+ }
+ symlist_add(&(sym->info.minfo->symrefs), cur_symbol,
+ SYMLIST_INSERT_HEAD);
+ cur_symbol->info.rinfo->valid_bitmask |= mask;
+ cur_symbol->info.rinfo->typecheck_masks = TRUE;
+}
+
+static void
+initialize_symbol(symbol)
+ symbol_t *symbol;
+{
+ switch (symbol->type) {
+ case UNINITIALIZED:
+ stop("Call to initialize_symbol with type field unset",
+ EX_SOFTWARE);
+ /* NOTREACHED */
+ break;
+ case REGISTER:
+ case SRAMLOC:
+ case SCBLOC:
+ symbol->info.rinfo =
+ (struct reg_info *)malloc(sizeof(struct reg_info));
+ if (symbol->info.rinfo == NULL) {
+ stop("Can't create register info", EX_SOFTWARE);
+ /* NOTREACHED */
+ }
+ memset(symbol->info.rinfo, 0,
+ sizeof(struct reg_info));
+ break;
+ case ALIAS:
+ symbol->info.ainfo =
+ (struct alias_info *)malloc(sizeof(struct alias_info));
+ if (symbol->info.ainfo == NULL) {
+ stop("Can't create alias info", EX_SOFTWARE);
+ /* NOTREACHED */
+ }
+ memset(symbol->info.ainfo, 0,
+ sizeof(struct alias_info));
+ break;
+ case MASK:
+ case BIT:
+ symbol->info.minfo =
+ (struct mask_info *)malloc(sizeof(struct mask_info));
+ if (symbol->info.minfo == NULL) {
+ stop("Can't create bitmask info", EX_SOFTWARE);
+ /* NOTREACHED */
+ }
+ memset(symbol->info.minfo, 0, sizeof(struct mask_info));
+ SLIST_INIT(&(symbol->info.minfo->symrefs));
+ break;
+ case CONST:
+ symbol->info.cinfo =
+ (struct const_info *)malloc(sizeof(struct const_info));
+ if (symbol->info.cinfo == NULL) {
+ stop("Can't create alias info", EX_SOFTWARE);
+ /* NOTREACHED */
+ }
+ memset(symbol->info.cinfo, 0,
+ sizeof(struct const_info));
+ break;
+ case LABEL:
+ symbol->info.linfo =
+ (struct label_info *)malloc(sizeof(struct label_info));
+ if (symbol->info.linfo == NULL) {
+ stop("Can't create label info", EX_SOFTWARE);
+ /* NOTREACHED */
+ }
+ memset(symbol->info.linfo, 0,
+ sizeof(struct label_info));
+ break;
+ case CONDITIONAL:
+ symbol->info.condinfo =
+ (struct cond_info *)malloc(sizeof(struct cond_info));
+ if (symbol->info.condinfo == NULL) {
+ stop("Can't create conditional info", EX_SOFTWARE);
+ /* NOTREACHED */
+ }
+ memset(symbol->info.condinfo, 0,
+ sizeof(struct cond_info));
+ break;
+ default:
+ stop("Call to initialize_symbol with invalid symbol type",
+ EX_SOFTWARE);
+ /* NOTREACHED */
+ break;
+ }
+}
+
+static void
+process_register(p_symbol)
+ symbol_t **p_symbol;
+{
+ char buf[255];
+ symbol_t *symbol = *p_symbol;
+
+ if (symbol->type == UNINITIALIZED) {
+ snprintf(buf, sizeof(buf), "Undefined register %s",
+ symbol->name);
+ stop(buf, EX_DATAERR);
+ /* NOTREACHED */
+ } else if (symbol->type == ALIAS) {
+ *p_symbol = symbol->info.ainfo->parent;
+ } else if ((symbol->type != REGISTER)
+ && (symbol->type != SCBLOC)
+ && (symbol->type != SRAMLOC)) {
+ snprintf(buf, sizeof(buf),
+ "Specified symbol %s is not a register",
+ symbol->name);
+ stop(buf, EX_DATAERR);
+ }
+}
+
+static void
+format_1_instr(opcode, dest, immed, src, ret)
+ int opcode;
+ symbol_ref_t *dest;
+ expression_t *immed;
+ symbol_ref_t *src;
+ int ret;
+{
+ struct instruction *instr;
+ struct ins_format1 *f1_instr;
+
+ if (src->symbol == NULL)
+ src = dest;
+
+ /* Test register permissions */
+ test_writable_symbol(dest->symbol);
+ test_readable_symbol(src->symbol);
+
+ /* Ensure that immediate makes sense for this destination */
+ type_check(dest->symbol, immed, opcode);
+
+ /* 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->destination = dest->symbol->info.rinfo->address
+ + dest->offset;
+ f1_instr->source = src->symbol->info.rinfo->address
+ + src->offset;
+ f1_instr->immediate = immed->value;
+ symlist_free(&immed->referenced_syms);
+ instruction_ptr++;
+}
+
+static void
+format_2_instr(opcode, dest, places, src, ret)
+ int opcode;
+ symbol_ref_t *dest;
+ expression_t *places;
+ symbol_ref_t *src;
+ int ret;
+{
+ struct instruction *instr;
+ struct ins_format2 *f2_instr;
+ u_int8_t shift_control;
+
+ if (src->symbol == NULL)
+ src = dest;
+
+ /* Test register permissions */
+ test_writable_symbol(dest->symbol);
+ test_readable_symbol(src->symbol);
+
+ /* 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->destination = dest->symbol->info.rinfo->address
+ + dest->offset;
+ f2_instr->source = src->symbol->info.rinfo->address
+ + src->offset;
+ if (places->value > 8 || places->value <= 0) {
+ stop("illegal shift value", EX_DATAERR);
+ /* NOTREACHED */
+ }
+ switch (opcode) {
+ case AIC_OP_SHL:
+ if (places->value == 8)
+ shift_control = 0xf0;
+ else
+ shift_control = (places->value << 4) | places->value;
+ break;
+ case AIC_OP_SHR:
+ if (places->value == 8) {
+ shift_control = 0xf8;
+ } else {
+ shift_control = (places->value << 4)
+ | (8 - places->value)
+ | 0x08;
+ }
+ break;
+ case AIC_OP_ROL:
+ shift_control = places->value & 0x7;
+ break;
+ case AIC_OP_ROR:
+ shift_control = (8 - places->value) | 0x08;
+ break;
+ default:
+ shift_control = 0; /* Quiet Compiler */
+ stop("Invalid shift operation specified", EX_SOFTWARE);
+ /* NOTREACHED */
+ break;
+ };
+ f2_instr->shift_control = shift_control;
+ symlist_free(&places->referenced_syms);
+ instruction_ptr++;
+}
+
+static void
+format_3_instr(opcode, src, immed, address)
+ int opcode;
+ symbol_ref_t *src;
+ expression_t *immed;
+ symbol_ref_t *address;
+{
+ struct instruction *instr;
+ struct ins_format3 *f3_instr;
+ int addr;
+
+ /* Test register permissions */
+ test_readable_symbol(src->symbol);
+
+ /* Ensure that immediate makes sense for this source */
+ type_check(src->symbol, immed, opcode);
+
+ /* Allocate sequencer space for the instruction and fill it out */
+ instr = seq_alloc();
+ f3_instr = &instr->format.format3;
+ if (address->symbol == NULL) {
+ /* 'dot' referrence. Use the current instruction pointer */
+ addr = instruction_ptr + address->offset;
+ } else if (address->symbol->type == UNINITIALIZED) {
+ /* forward reference */
+ addr = address->offset;
+ 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->source = src->symbol->info.rinfo->address
+ + src->offset;
+ f3_instr->immediate = immed->value;
+ symlist_free(&immed->referenced_syms);
+ instruction_ptr++;
+}
+
+static void
+test_readable_symbol(symbol)
+ symbol_t *symbol;
+{
+ if (symbol->info.rinfo->mode == WO) {
+ stop("Write Only register specified as source",
+ EX_DATAERR);
+ /* NOTREACHED */
+ }
+}
+
+static void
+test_writable_symbol(symbol)
+ symbol_t *symbol;
+{
+ if (symbol->info.rinfo->mode == RO) {
+ stop("Read Only register specified as destination",
+ EX_DATAERR);
+ /* NOTREACHED */
+ }
+}
+
+static void
+type_check(symbol, expression, opcode)
+ symbol_t *symbol;
+ expression_t *expression;
+ int opcode;
+{
+ symbol_node_t *node;
+ int and_op;
+ char buf[255];
+
+ and_op = FALSE;
+ if (opcode == AIC_OP_AND || opcode == AIC_OP_JNZ || AIC_OP_JZ)
+ and_op = TRUE;
+ /*
+ * Make sure that we aren't attempting to write something
+ * that hasn't been defined. If this is an and operation,
+ * this is a mask, so "undefined" bits are okay.
+ */
+ if (and_op == FALSE
+ && (expression->value & ~symbol->info.rinfo->valid_bitmask) != 0) {
+ snprintf(buf, sizeof(buf),
+ "Invalid bit(s) 0x%x in immediate written to %s",
+ expression->value & ~symbol->info.rinfo->valid_bitmask,
+ symbol->name);
+ stop(buf, EX_DATAERR);
+ /* NOTREACHED */
+ }
+
+ /*
+ * Now make sure that all of the symbols referenced by the
+ * expression are defined for this register.
+ */
+ if(symbol->info.rinfo->typecheck_masks != FALSE) {
+ for(node = expression->referenced_syms.slh_first;
+ node != NULL;
+ node = node->links.sle_next) {
+ if ((node->symbol->type == MASK
+ || node->symbol->type == BIT)
+ && symlist_search(&node->symbol->info.minfo->symrefs,
+ symbol->name) == NULL) {
+ snprintf(buf, sizeof(buf),
+ "Invalid bit or mask %s "
+ "for register %s",
+ node->symbol->name, symbol->name);
+ stop(buf, EX_DATAERR);
+ /* NOTREACHED */
+ }
+ }
+ }
+}
+
+static void
+make_expression(immed, value)
+ expression_t *immed;
+ int value;
+{
+ SLIST_INIT(&immed->referenced_syms);
+ immed->value = value & 0xff;
+}
+
+static void
+add_conditional(symbol)
+ symbol_t *symbol;
+{
+ static int numoptions = 1;
+
+ 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",
+ EX_DATAERR);
+ /* NOTREACHED */
+ }
+ cur_patch->options |= symbol->info.condinfo->value;
+}
+
+void
+yyerror(string)
+ const char *string;
+{
+ stop(string, EX_DATAERR);
+}
diff --git a/sys/dev/aic7xxx/aicasm/aicasm_scan.l b/sys/dev/aic7xxx/aicasm/aicasm_scan.l
new file mode 100644
index 0000000000000..d77ceddf4c993
--- /dev/null
+++ b/sys/dev/aic7xxx/aicasm/aicasm_scan.l
@@ -0,0 +1,242 @@
+%{
+/*
+ * Lexical Analyzer for the Aic7xxx SCSI Host adapter sequencer assembler.
+ *
+ * Copyright (c) 1997 Justin T. Gibbs.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * this list of conditions, and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <sysexits.h>
+#include <sys/queue.h>
+
+#include "aic7xxx_asm.h"
+#include "symbol.h"
+#include "y.tab.h"
+%}
+
+PATH [-/A-Za-z0-9_.]*[./][-/A-Za-z0-9_.]*
+WORD [A-Za-z_][-A-Za-z_0-9]*
+SPACE [ \t]+
+
+%x COMMENT
+
+%%
+\n { ++yylineno; }
+"/*" { BEGIN COMMENT; /* Enter comment eating state */ }
+<COMMENT>"/*" { fprintf(stderr, "Warning! Comment within comment."); }
+<COMMENT>\n { ++yylineno; }
+<COMMENT>[^*/\n]* ;
+<COMMENT>"*"+[^*/\n]* ;
+<COMMENT>"/"+[^*/\n]* ;
+<COMMENT>"*"+"/" { BEGIN INITIAL; }
+
+{SPACE} ;
+
+ /* Register/SCB/SRAM definition keywords */
+register { return T_REGISTER; }
+const { yylval.value = FALSE; return T_CONST; }
+address { return T_ADDRESS; }
+access_mode { return T_ACCESS_MODE; }
+RW|RO|WO {
+ if (strcmp(yytext, "RW") == 0)
+ yylval.value = RW;
+ else if (strcmp(yytext, "RO") == 0)
+ yylval.value = RO;
+ else
+ yylval.value = WO;
+ return T_MODE;
+ }
+bit { return T_BIT; }
+mask { return T_MASK; }
+alias { return T_ALIAS; }
+size { return T_SIZE; }
+scb { return T_SCB; }
+scratch_ram { return T_SRAM; }
+accumulator { return T_ACCUM; }
+allones { return T_ALLONES; }
+allzeros { return T_ALLZEROS; }
+none { return T_NONE; }
+sindex { return T_SINDEX; }
+A { return T_A; }
+
+ /* Opcodes */
+shl { return T_SHL; }
+shr { return T_SHR; }
+ror { return T_ROR; }
+rol { return T_ROL; }
+mvi { return T_MVI; }
+mov { return T_MOV; }
+clr { return T_CLR; }
+jmp { return T_JMP; }
+jc { return T_JC; }
+jnc { return T_JNC; }
+je { return T_JE; }
+jne { return T_JNE; }
+jz { return T_JZ; }
+jnz { return T_JNZ; }
+call { return T_CALL; }
+add { return T_ADD; }
+adc { return T_ADC; }
+inc { return T_INC; }
+dec { return T_DEC; }
+stc { return T_STC; }
+clc { return T_CLC; }
+cmp { return T_CMP; }
+xor { return T_XOR; }
+test { return T_TEST;}
+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; }
+
+ /* Allowed Symbols */
+[-+,:()~|&."{};<>[\]!] { return yytext[0]; }
+
+ /* Number processing */
+0[0-7]* {
+ yylval.value = strtol(yytext, NULL, 8);
+ return T_NUMBER;
+ }
+
+0[xX][0-9a-fA-F]+ {
+ yylval.value = strtoul(yytext + 2, NULL, 16);
+ return T_NUMBER;
+ }
+
+[1-9][0-9]* {
+ yylval.value = strtol(yytext, NULL, 10);
+ return T_NUMBER;
+ }
+
+ /* Include Files */
+#include { return T_INCLUDE; }
+
+ /* For parsing C include files with #define foo */
+#define { yylval.value = TRUE; return T_CONST; }
+ /* Throw away macros */
+#define[^\n]*[()]+[^\n]* ;
+{PATH} { yylval.str = strdup(yytext); return T_PATH; }
+
+{WORD} { yylval.sym = symtable_get(yytext); return T_SYMBOL; }
+
+. {
+ char buf[255];
+
+ snprintf(buf, sizeof(buf), "Invalid character "
+ "'%c'", yytext[0]);
+ stop(buf, EX_DATAERR);
+ }
+%%
+
+typedef struct include {
+ YY_BUFFER_STATE buffer;
+ int lineno;
+ char *filename;
+ SLIST_ENTRY(include) links;
+}include_t;
+
+SLIST_HEAD(, include) include_stack;
+
+void
+include_file(file_name, type)
+ char *file_name;
+ include_type type;
+{
+ FILE *newfile;
+ include_t *include;
+
+ newfile = NULL;
+ /* Try the current directory first */
+ if (includes_search_curdir != 0 || type == SOURCE_FILE)
+ newfile = fopen(file_name, "r");
+
+ if (newfile == NULL && type != SOURCE_FILE) {
+ path_entry_t include_dir;
+ for (include_dir = search_path.slh_first;
+ include_dir != NULL;
+ include_dir = include_dir->links.sle_next) {
+ char fullname[PATH_MAX];
+
+ if ((include_dir->quoted_includes_only == TRUE)
+ && (type != QUOTED_INCLUDE))
+ continue;
+
+ snprintf(fullname, sizeof(fullname),
+ "%s/%s", include_dir->directory, file_name);
+
+ if ((newfile = fopen(fullname, "r")) != NULL)
+ break;
+ }
+ }
+
+ if (newfile == NULL) {
+ perror(file_name);
+ stop("Unable to open input file", EX_SOFTWARE);
+ /* NOTREACHED */
+ }
+ include = (include_t *)malloc(sizeof(include_t));
+ if (include == NULL) {
+ stop("Unable to allocate include stack entry", EX_SOFTWARE);
+ /* NOTREACHED */
+ }
+ include->buffer = YY_CURRENT_BUFFER;
+ include->lineno = yylineno;
+ include->filename = yyfilename;
+ SLIST_INSERT_HEAD(&include_stack, include, links);
+ yy_switch_to_buffer(yy_create_buffer(newfile, YY_BUF_SIZE));
+ yylineno = 1;
+ yyfilename = strdup(file_name);
+}
+
+int
+yywrap()
+{
+ include_t *include;
+
+ yy_delete_buffer(YY_CURRENT_BUFFER);
+ (void)fclose(yyin);
+ if (yyfilename != NULL)
+ free(yyfilename);
+ include = include_stack.slh_first;
+ if (include != NULL) {
+ yy_switch_to_buffer(include->buffer);
+ yylineno = include->lineno;
+ yyfilename = include->filename;
+ SLIST_REMOVE_HEAD(&include_stack, links);
+ free(include);
+ return (0);
+ }
+ return (1);
+}
diff --git a/sys/dev/aic7xxx/aicasm/aicasm_symbol.c b/sys/dev/aic7xxx/aicasm/aicasm_symbol.c
new file mode 100644
index 0000000000000..e2b93efbd2ee1
--- /dev/null
+++ b/sys/dev/aic7xxx/aicasm/aicasm_symbol.c
@@ -0,0 +1,451 @@
+/*
+ * Aic7xxx SCSI host adapter firmware asssembler symbol table implementation
+ *
+ * Copyright (c) 1997 Justin T. Gibbs.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * this list of conditions, and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+
+#include <sys/types.h>
+
+#include <db.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+
+#include "symbol.h"
+#include "aic7xxx_asm.h"
+
+static DB *symtable;
+
+symbol_t *
+symbol_create(name)
+ char *name;
+{
+ symbol_t *new_symbol;
+
+ new_symbol = (symbol_t *)malloc(sizeof(symbol_t));
+ if (new_symbol == NULL) {
+ perror("Unable to create new symbol");
+ exit(EX_SOFTWARE);
+ }
+ memset(new_symbol, 0, sizeof(*new_symbol));
+ new_symbol->name = strdup(name);
+ new_symbol->type = UNINITIALIZED;
+ return (new_symbol);
+}
+
+void
+symbol_delete(symbol)
+ symbol_t *symbol;
+{
+ if (symtable != NULL) {
+ DBT key;
+
+ key.data = symbol->name;
+ key.size = strlen(symbol->name);
+ symtable->del(symtable, &key, /*flags*/0);
+ }
+ switch(symbol->type) {
+ case SCBLOC:
+ case SRAMLOC:
+ case REGISTER:
+ if (symbol->info.rinfo != NULL)
+ free(symbol->info.rinfo);
+ break;
+ case ALIAS:
+ if (symbol->info.ainfo != NULL)
+ free(symbol->info.ainfo);
+ break;
+ case MASK:
+ case BIT:
+ if (symbol->info.minfo != NULL) {
+ symlist_free(&symbol->info.minfo->symrefs);
+ free(symbol->info.minfo);
+ }
+ break;
+ case CONST:
+ if (symbol->info.cinfo != NULL)
+ free(symbol->info.cinfo);
+ break;
+ case LABEL:
+ if (symbol->info.linfo != NULL)
+ free(symbol->info.linfo);
+ break;
+ case UNINITIALIZED:
+ default:
+ break;
+ }
+ free(symbol->name);
+ free(symbol);
+}
+
+void
+symtable_open()
+{
+ symtable = dbopen(/*filename*/NULL,
+ O_CREAT | O_NONBLOCK | O_RDWR, /*mode*/0, DB_HASH,
+ /*openinfo*/NULL);
+
+ if (symtable == NULL) {
+ perror("Symbol table creation failed");
+ exit(EX_SOFTWARE);
+ /* NOTREACHED */
+ }
+}
+
+void
+symtable_close()
+{
+ if (symtable != NULL) {
+ DBT key;
+ DBT data;
+
+ while (symtable->seq(symtable, &key, &data, R_FIRST) == 0) {
+ symbol_t *cursym;
+
+ cursym = *(symbol_t **)data.data;
+ symbol_delete(cursym);
+ }
+ symtable->close(symtable);
+ }
+}
+
+/*
+ * The semantics of get is to return an uninitialized symbol entry
+ * if a lookup fails.
+ */
+symbol_t *
+symtable_get(name)
+ char *name;
+{
+ DBT key;
+ DBT data;
+ int retval;
+
+ key.data = (void *)name;
+ key.size = strlen(name);
+
+ if ((retval = symtable->get(symtable, &key, &data, /*flags*/0)) != 0) {
+ if (retval == -1) {
+ perror("Symbol table get operation failed");
+ exit(EX_SOFTWARE);
+ /* NOTREACHED */
+ } else if (retval == 1) {
+ /* Symbol wasn't found, so create a new one */
+ symbol_t *new_symbol;
+
+ new_symbol = symbol_create(name);
+ data.data = &new_symbol;
+ data.size = sizeof(new_symbol);
+ if (symtable->put(symtable, &key, &data,
+ /*flags*/0) !=0) {
+ perror("Symtable put failed");
+ exit(EX_SOFTWARE);
+ }
+ return (new_symbol);
+ } else {
+ perror("Unexpected return value from db get routine");
+ exit(EX_SOFTWARE);
+ /* NOTREACHED */
+ }
+ }
+ return (*(symbol_t **)data.data);
+}
+
+symbol_node_t *
+symlist_search(symlist, symname)
+ symlist_t *symlist;
+ char *symname;
+{
+ symbol_node_t *curnode;
+
+ curnode = symlist->slh_first;
+ while(curnode != NULL) {
+ if (strcmp(symname, curnode->symbol->name) == 0)
+ break;
+ curnode = curnode->links.sle_next;
+ }
+ return (curnode);
+}
+
+void
+symlist_add(symlist, symbol, how)
+ symlist_t *symlist;
+ symbol_t *symbol;
+ int how;
+{
+ symbol_node_t *newnode;
+
+ newnode = (symbol_node_t *)malloc(sizeof(symbol_node_t));
+ if (newnode == NULL) {
+ stop("symlist_add: Unable to malloc symbol_node", EX_SOFTWARE);
+ /* NOTREACHED */
+ }
+ newnode->symbol = symbol;
+ if (how == SYMLIST_SORT) {
+ symbol_node_t *curnode;
+ int mask;
+
+ mask = FALSE;
+ switch(symbol->type) {
+ case REGISTER:
+ case SCBLOC:
+ case SRAMLOC:
+ break;
+ case BIT:
+ case MASK:
+ mask = TRUE;
+ break;
+ default:
+ stop("symlist_add: Invalid symbol type for sorting",
+ EX_SOFTWARE);
+ /* NOTREACHED */
+ }
+
+ curnode = symlist->slh_first;
+ if (curnode == NULL
+ || (mask && (curnode->symbol->info.minfo->mask >
+ newnode->symbol->info.minfo->mask))
+ || (!mask && (curnode->symbol->info.rinfo->address >
+ newnode->symbol->info.rinfo->address))) {
+ SLIST_INSERT_HEAD(symlist, newnode, links);
+ return;
+ }
+
+ while (1) {
+ if (curnode->links.sle_next == NULL) {
+ SLIST_INSERT_AFTER(curnode, newnode,
+ links);
+ break;
+ } else {
+ symbol_t *cursymbol;
+
+ cursymbol = curnode->links.sle_next->symbol;
+ if ((mask && (cursymbol->info.minfo->mask >
+ symbol->info.minfo->mask))
+ || (!mask &&(cursymbol->info.rinfo->address >
+ symbol->info.rinfo->address))){
+ SLIST_INSERT_AFTER(curnode, newnode,
+ links);
+ break;
+ }
+ }
+ curnode = curnode->links.sle_next;
+ }
+ } else {
+ SLIST_INSERT_HEAD(symlist, newnode, links);
+ }
+}
+
+void
+symlist_free(symlist)
+ symlist_t *symlist;
+{
+ symbol_node_t *node1, *node2;
+
+ node1 = symlist->slh_first;
+ while (node1 != NULL) {
+ node2 = node1->links.sle_next;
+ free(node1);
+ node1 = node2;
+ }
+ SLIST_INIT(symlist);
+}
+
+void
+symlist_merge(symlist_dest, symlist_src1, symlist_src2)
+ symlist_t *symlist_dest;
+ symlist_t *symlist_src1;
+ symlist_t *symlist_src2;
+{
+ symbol_node_t *node;
+
+ *symlist_dest = *symlist_src1;
+ while((node = symlist_src2->slh_first) != NULL) {
+ SLIST_REMOVE_HEAD(symlist_src2, links);
+ SLIST_INSERT_HEAD(symlist_dest, node, links);
+ }
+
+ /* These are now empty */
+ SLIST_INIT(symlist_src1);
+ SLIST_INIT(symlist_src2);
+}
+
+void
+symtable_dump(ofile)
+ FILE *ofile;
+{
+ /*
+ * Sort the registers by address with a simple insertion sort.
+ * Put bitmasks next to the first register that defines them.
+ * Put constants at the end.
+ */
+ symlist_t registers;
+ symlist_t masks;
+ symlist_t constants;
+ symlist_t aliases;
+
+ SLIST_INIT(&registers);
+ SLIST_INIT(&masks);
+ SLIST_INIT(&constants);
+ SLIST_INIT(&aliases);
+
+ if (symtable != NULL) {
+ DBT key;
+ DBT data;
+ int flag = R_FIRST;
+
+ while (symtable->seq(symtable, &key, &data, flag) == 0) {
+ symbol_t *cursym;
+
+ cursym = *(symbol_t **)data.data;
+ switch(cursym->type) {
+ case REGISTER:
+ case SCBLOC:
+ case SRAMLOC:
+ symlist_add(&registers, cursym, SYMLIST_SORT);
+ break;
+ case MASK:
+ case BIT:
+ symlist_add(&masks, cursym, SYMLIST_SORT);
+ break;
+ case CONST:
+ if (cursym->info.cinfo->define == FALSE) {
+ symlist_add(&constants, cursym,
+ SYMLIST_INSERT_HEAD);
+ }
+ break;
+ case ALIAS:
+ symlist_add(&aliases, cursym,
+ SYMLIST_INSERT_HEAD);
+ default:
+ break;
+ }
+ flag = R_NEXT;
+ }
+
+ /* Put in the masks and bits */
+ while (masks.slh_first != NULL) {
+ symbol_node_t *curnode;
+ symbol_node_t *regnode;
+ char *regname;
+
+ curnode = masks.slh_first;
+ SLIST_REMOVE_HEAD(&masks, links);
+
+ regnode =
+ curnode->symbol->info.minfo->symrefs.slh_first;
+ regname = regnode->symbol->name;
+ regnode = symlist_search(&registers, regname);
+ SLIST_INSERT_AFTER(regnode, curnode, links);
+ }
+
+ /* Add the aliases */
+ while (aliases.slh_first != NULL) {
+ symbol_node_t *curnode;
+ symbol_node_t *regnode;
+ char *regname;
+
+ curnode = aliases.slh_first;
+ SLIST_REMOVE_HEAD(&aliases, links);
+
+ regname = curnode->symbol->info.ainfo->parent->name;
+ regnode = symlist_search(&registers, regname);
+ SLIST_INSERT_AFTER(regnode, curnode, links);
+ }
+
+ /* Output what we have */
+ fprintf(ofile,
+"/*
+ * DO NOT EDIT - This file is automatically generated.
+ */\n");
+ while (registers.slh_first != NULL) {
+ symbol_node_t *curnode;
+ u_int8_t value;
+ char *tab_str;
+ char *tab_str2;
+
+ curnode = registers.slh_first;
+ SLIST_REMOVE_HEAD(&registers, links);
+ switch(curnode->symbol->type) {
+ case REGISTER:
+ case SCBLOC:
+ case SRAMLOC:
+ fprintf(ofile, "\n");
+ value = curnode->symbol->info.rinfo->address;
+ tab_str = "\t";
+ tab_str2 = "\t\t";
+ break;
+ case ALIAS:
+ {
+ symbol_t *parent;
+
+ parent = curnode->symbol->info.ainfo->parent;
+ value = parent->info.rinfo->address;
+ tab_str = "\t";
+ tab_str2 = "\t\t";
+ break;
+ }
+ case MASK:
+ case BIT:
+ value = curnode->symbol->info.minfo->mask;
+ tab_str = "\t\t";
+ tab_str2 = "\t";
+ break;
+ default:
+ value = 0; /* Quiet compiler */
+ tab_str = NULL;
+ tab_str2 = NULL;
+ stop("symtable_dump: Invalid symbol type "
+ "encountered", EX_SOFTWARE);
+ break;
+ }
+ fprintf(ofile, "#define%s%-16s%s0x%02x\n",
+ tab_str, curnode->symbol->name, tab_str2,
+ value);
+ free(curnode);
+ }
+ fprintf(ofile, "\n\n");
+
+ while (constants.slh_first != NULL) {
+ symbol_node_t *curnode;
+
+ curnode = constants.slh_first;
+ SLIST_REMOVE_HEAD(&constants, links);
+ fprintf(ofile, "#define\t%-8s\t0x%02x\n",
+ curnode->symbol->name,
+ curnode->symbol->info.cinfo->value);
+ free(curnode);
+ }
+ }
+}
+
diff --git a/sys/dev/aic7xxx/aicasm/aicasm_symbol.h b/sys/dev/aic7xxx/aicasm/aicasm_symbol.h
new file mode 100644
index 0000000000000..cf8fa0071225a
--- /dev/null
+++ b/sys/dev/aic7xxx/aicasm/aicasm_symbol.h
@@ -0,0 +1,144 @@
+/*
+ * Aic7xxx SCSI host adapter firmware asssembler symbol table definitions
+ *
+ * Copyright (c) 1997 Justin T. Gibbs.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * this list of conditions, and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#include <sys/queue.h>
+
+typedef enum {
+ UNINITIALIZED,
+ REGISTER,
+ ALIAS,
+ SCBLOC,
+ SRAMLOC,
+ MASK,
+ BIT,
+ CONST,
+ LABEL,
+ CONDITIONAL
+}symtype;
+
+typedef enum {
+ RO = 0x01,
+ WO = 0x02,
+ RW = 0x03
+}amode_t;
+
+struct reg_info {
+ u_int8_t address;
+ int size;
+ amode_t mode;
+ u_int8_t valid_bitmask;
+ int typecheck_masks;
+};
+
+typedef SLIST_HEAD(symlist, symbol_node) symlist_t;
+
+struct mask_info {
+ symlist_t symrefs;
+ u_int8_t mask;
+};
+
+struct const_info {
+ u_int8_t value;
+ int define;
+};
+
+struct alias_info {
+ struct symbol *parent;
+};
+
+struct label_info {
+ int address;
+};
+
+struct cond_info {
+ int value;
+};
+
+typedef struct expression_info {
+ symlist_t referenced_syms;
+ int value;
+} expression_t;
+
+typedef struct symbol {
+ char *name;
+ symtype type;
+ union {
+ struct reg_info *rinfo;
+ struct mask_info *minfo;
+ struct const_info *cinfo;
+ struct alias_info *ainfo;
+ struct label_info *linfo;
+ struct cond_info *condinfo;
+ }info;
+} symbol_t;
+
+typedef struct symbol_ref {
+ symbol_t *symbol;
+ int offset;
+} symbol_ref_t;
+
+typedef struct symbol_node {
+ SLIST_ENTRY(symbol_node) links;
+ symbol_t *symbol;
+}symbol_node_t;
+
+typedef struct patch {
+ STAILQ_ENTRY(patch) links;
+ int negative;
+ int begin;
+ int end;
+ int options;
+} patch_t;
+
+void symbol_delete __P((symbol_t *symbol));
+
+void symtable_open __P((void));
+
+void symtable_close __P((void));
+
+symbol_t *
+ symtable_get __P((char *name));
+
+symbol_node_t *
+ symlist_search __P((symlist_t *symlist, char *symname));
+
+void
+ symlist_add __P((symlist_t *symlist, symbol_t *symbol, int how));
+#define SYMLIST_INSERT_HEAD 0x00
+#define SYMLIST_SORT 0x01
+
+void symlist_free __P((symlist_t *symlist));
+
+void symlist_merge __P((symlist_t *symlist_dest, symlist_t *symlist_src1,
+ symlist_t *symlist_src2));
+void symtable_dump __P((FILE *ofile));
diff --git a/sys/dev/aic7xxx/aicasm_gram.y b/sys/dev/aic7xxx/aicasm_gram.y
new file mode 100644
index 0000000000000..0c75edca3b3ee
--- /dev/null
+++ b/sys/dev/aic7xxx/aicasm_gram.y
@@ -0,0 +1,1304 @@
+%{
+/*
+ * Parser for the Aic7xxx SCSI Host adapter sequencer assembler.
+ *
+ * Copyright (c) 1997 Justin T. Gibbs.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * this list of conditions, and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+
+#include <sys/types.h>
+#include <sys/queue.h>
+
+#include "aic7xxx_asm.h"
+#include "symbol.h"
+#include "sequencer.h"
+
+int yylineno;
+char *yyfilename;
+static symbol_t *cur_symbol;
+static symtype cur_symtype;
+static symbol_t *accumulator;
+static symbol_ref_t allones;
+static symbol_ref_t allzeros;
+static symbol_ref_t none;
+static symbol_ref_t sindex;
+static int instruction_ptr;
+static int sram_or_scb_offset;
+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));
+static void process_register __P((symbol_t **p_symbol));
+static void format_1_instr __P((int opcode, symbol_ref_t *dest,
+ expression_t *immed, symbol_ref_t *src,
+ int ret));
+static void format_2_instr __P((int opcode, symbol_ref_t *dest,
+ expression_t *places, symbol_ref_t *src,
+ int ret));
+static void format_3_instr __P((int opcode, symbol_ref_t *src,
+ expression_t *immed, symbol_ref_t *address));
+static void test_readable_symbol __P((symbol_t *symbol));
+static void test_writable_symbol __P((symbol_t *symbol));
+static void type_check __P((symbol_t *symbol, expression_t *expression,
+ int and_op));
+static void make_expression __P((expression_t *immed, int value));
+static void add_conditional __P((symbol_t *symbol));
+
+#define YYDEBUG 1
+#define SRAM_SYMNAME "SRAM_BASE"
+#define SCB_SYMNAME "SCB_BASE"
+%}
+
+%union {
+ int value;
+ char *str;
+ symbol_t *sym;
+ symbol_ref_t sym_ref;
+ expression_t expression;
+}
+
+%token T_REGISTER
+
+%token <value> T_CONST
+
+%token T_SCB
+
+%token T_SRAM
+
+%token T_ALIAS
+
+%token T_SIZE
+
+%token <value> T_ADDRESS
+
+%token T_ACCESS_MODE
+
+%token <value> T_MODE
+
+%token T_BIT
+
+%token T_MASK
+
+%token <value> T_NUMBER
+
+%token <str> T_PATH
+
+%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_JMP T_JC T_JNC T_JE T_JNE T_JNZ T_JZ T_CALL
+
+%token <value> T_ADD T_ADC
+
+%token <value> T_INC T_DEC
+
+%token <value> T_STC T_CLC
+
+%token <value> T_CMP T_XOR
+
+%token <value> T_TEST T_AND
+
+%token <value> T_OR
+
+%token T_RET
+
+%token T_NOP
+
+%token T_ACCUM T_ALLONES T_ALLZEROS T_NONE T_SINDEX
+
+%token T_A
+
+%token <sym> T_SYMBOL
+
+%token T_NL
+
+%token T_IF T_ELSE T_ENDIF
+
+%type <sym_ref> reg_symbol address destination source opt_source
+
+%type <expression> expression immediate immediate_or_a
+
+%type <value> ret f1_opcode f2_opcode jmp_jc_jnc_call jz_jnz je_jne
+
+%left '|'
+%left '&'
+%left '+' '-'
+%right '~'
+%nonassoc UMINUS
+%%
+
+program:
+ include
+| program include
+| register
+| program register
+| constant
+| program constant
+| scratch_ram
+| program scratch_ram
+| scb
+| program scb
+| label
+| program label
+| conditional
+| program conditional
+| code
+| program code
+;
+
+include:
+ T_INCLUDE '<' T_PATH '>'
+ { include_file($3, BRACKETED_INCLUDE); }
+| T_INCLUDE '"' T_PATH '"'
+ { include_file($3, QUOTED_INCLUDE); }
+;
+
+register:
+ T_REGISTER { cur_symtype = REGISTER; } reg_definition
+;
+
+reg_definition:
+ T_SYMBOL '{'
+ {
+ if ($1->type != UNINITIALIZED) {
+ stop("Register multiply defined", EX_DATAERR);
+ /* NOTREACHED */
+ }
+ cur_symbol = $1;
+ cur_symbol->type = cur_symtype;
+ initialize_symbol(cur_symbol);
+ }
+ reg_attribute_list
+ '}'
+ {
+ /*
+ * Default to allowing everything in for registers
+ * with no bit or mask definitions.
+ */
+ if (cur_symbol->info.rinfo->valid_bitmask == 0)
+ cur_symbol->info.rinfo->valid_bitmask = 0xFF;
+
+ if (cur_symbol->info.rinfo->size == 0)
+ cur_symbol->info.rinfo->size = 1;
+
+ /*
+ * This might be useful for registers too.
+ */
+ if (cur_symbol->type != REGISTER) {
+ if (cur_symbol->info.rinfo->address == 0)
+ cur_symbol->info.rinfo->address =
+ sram_or_scb_offset;
+ sram_or_scb_offset +=
+ cur_symbol->info.rinfo->size;
+ }
+ cur_symbol = NULL;
+ }
+;
+
+reg_attribute_list:
+ reg_attribute
+| reg_attribute_list reg_attribute
+;
+
+reg_attribute:
+ reg_address
+| size
+| access_mode
+| bit_defn
+| mask_defn
+| alias
+| accumulator
+| allones
+| allzeros
+| none
+| sindex
+;
+
+reg_address:
+ T_ADDRESS T_NUMBER
+ {
+ cur_symbol->info.rinfo->address = $2;
+ }
+;
+
+size:
+ T_SIZE T_NUMBER
+ {
+ cur_symbol->info.rinfo->size = $2;
+ }
+;
+
+access_mode:
+ T_ACCESS_MODE T_MODE
+ {
+ cur_symbol->info.rinfo->mode = $2;
+ }
+;
+
+bit_defn:
+ T_BIT T_SYMBOL T_NUMBER
+ {
+ process_bitmask(BIT, $2, $3);
+ }
+;
+
+mask_defn:
+ T_MASK T_SYMBOL expression
+ {
+ process_bitmask(MASK, $2, $3.value);
+ }
+;
+
+alias:
+ T_ALIAS T_SYMBOL
+ {
+ if ($2->type != UNINITIALIZED) {
+ stop("Re-definition of register alias",
+ EX_DATAERR);
+ /* NOTREACHED */
+ }
+ $2->type = ALIAS;
+ initialize_symbol($2);
+ $2->info.ainfo->parent = cur_symbol;
+ }
+;
+
+accumulator:
+ T_ACCUM
+ {
+ if (accumulator != NULL) {
+ stop("Only one accumulator definition allowed",
+ EX_DATAERR);
+ /* NOTREACHED */
+ }
+ accumulator = cur_symbol;
+ }
+;
+
+allones:
+ T_ALLONES
+ {
+ if (allones.symbol != NULL) {
+ stop("Only one definition of allones allowed",
+ EX_DATAERR);
+ /* NOTREACHED */
+ }
+ allones.symbol = cur_symbol;
+ }
+;
+
+allzeros:
+ T_ALLZEROS
+ {
+ if (allzeros.symbol != NULL) {
+ stop("Only one definition of allzeros allowed",
+ EX_DATAERR);
+ /* NOTREACHED */
+ }
+ allzeros.symbol = cur_symbol;
+ }
+;
+
+none:
+ T_NONE
+ {
+ if (none.symbol != NULL) {
+ stop("Only one definition of none allowed",
+ EX_DATAERR);
+ /* NOTREACHED */
+ }
+ none.symbol = cur_symbol;
+ }
+;
+
+sindex:
+ T_SINDEX
+ {
+ if (sindex.symbol != NULL) {
+ stop("Only one definition of sindex allowed",
+ EX_DATAERR);
+ /* NOTREACHED */
+ }
+ sindex.symbol = cur_symbol;
+ }
+;
+
+expression:
+ expression '|' expression
+ {
+ $$.value = $1.value | $3.value;
+ symlist_merge(&$$.referenced_syms,
+ &$1.referenced_syms,
+ &$3.referenced_syms);
+ }
+| expression '&' expression
+ {
+ $$.value = $1.value & $3.value;
+ symlist_merge(&$$.referenced_syms,
+ &$1.referenced_syms,
+ &$3.referenced_syms);
+ }
+| expression '+' expression
+ {
+ $$.value = $1.value + $3.value;
+ symlist_merge(&$$.referenced_syms,
+ &$1.referenced_syms,
+ &$3.referenced_syms);
+ }
+| expression '-' expression
+ {
+ $$.value = $1.value - $3.value;
+ symlist_merge(&($$.referenced_syms),
+ &($1.referenced_syms),
+ &($3.referenced_syms));
+ }
+| '(' expression ')'
+ {
+ $$ = $2;
+ }
+| '~' expression
+ {
+ $$ = $2;
+ $$.value = (~$$.value) & 0xFF;
+ }
+| '-' expression %prec UMINUS
+ {
+ $$ = $2;
+ $$.value = -$$.value;
+ }
+| T_NUMBER
+ {
+ $$.value = $1;
+ SLIST_INIT(&$$.referenced_syms);
+ }
+| T_SYMBOL
+ {
+ symbol_t *symbol;
+
+ symbol = $1;
+ switch (symbol->type) {
+ case ALIAS:
+ symbol = $1->info.ainfo->parent;
+ case REGISTER:
+ case SCBLOC:
+ case SRAMLOC:
+ $$.value = symbol->info.rinfo->address;
+ break;
+ case MASK:
+ case BIT:
+ $$.value = symbol->info.minfo->mask;
+ break;
+ case CONST:
+ $$.value = symbol->info.cinfo->value;
+ break;
+ case UNINITIALIZED:
+ default:
+ {
+ char buf[255];
+
+ snprintf(buf, sizeof(buf),
+ "Undefined symbol %s referenced",
+ symbol->name);
+ stop(buf, EX_DATAERR);
+ /* NOTREACHED */
+ break;
+ }
+ }
+ SLIST_INIT(&$$.referenced_syms);
+ symlist_add(&$$.referenced_syms, symbol, SYMLIST_INSERT_HEAD);
+ }
+;
+
+constant:
+ T_CONST T_SYMBOL T_NUMBER
+ {
+ if ($2->type != UNINITIALIZED) {
+ stop("Re-definition of constant variable",
+ EX_DATAERR);
+ /* NOTREACHED */
+ }
+ $2->type = CONST;
+ initialize_symbol($2);
+ $2->info.cinfo->value = $3;
+ $2->info.cinfo->define = $1;
+ }
+;
+
+scratch_ram:
+ T_SRAM '{'
+ {
+ cur_symbol = symtable_get(SRAM_SYMNAME);
+ cur_symtype = SRAMLOC;
+ if (cur_symbol->type != UNINITIALIZED) {
+ stop("Only one SRAM definition allowed",
+ EX_DATAERR);
+ /* NOTREACHED */
+ }
+ cur_symbol->type = SRAMLOC;
+ initialize_symbol(cur_symbol);
+ }
+ reg_address
+ {
+ sram_or_scb_offset = cur_symbol->info.rinfo->address;
+ }
+ scb_or_sram_reg_list
+ '}'
+ {
+ cur_symbol = NULL;
+ }
+;
+
+scb:
+ T_SCB '{'
+ {
+ cur_symbol = symtable_get(SCB_SYMNAME);
+ cur_symtype = SCBLOC;
+ if (cur_symbol->type != UNINITIALIZED) {
+ stop("Only one SRAM definition allowed",
+ EX_SOFTWARE);
+ /* NOTREACHED */
+ }
+ cur_symbol->type = SCBLOC;
+ initialize_symbol(cur_symbol);
+ }
+ reg_address
+ {
+ sram_or_scb_offset = cur_symbol->info.rinfo->address;
+ }
+ scb_or_sram_reg_list
+ '}'
+ {
+ cur_symbol = NULL;
+ }
+;
+
+scb_or_sram_reg_list:
+ reg_definition
+| scb_or_sram_reg_list reg_definition
+;
+
+reg_symbol:
+ T_SYMBOL
+ {
+ process_register(&$1);
+ $$.symbol = $1;
+ $$.offset = 0;
+ }
+| T_SYMBOL '[' T_NUMBER ']'
+ {
+ process_register(&$1);
+ if (($3 + 1) > $1->info.rinfo->size) {
+ stop("Accessing offset beyond range of register",
+ EX_DATAERR);
+ /* NOTREACHED */
+ }
+ $$.symbol = $1;
+ $$.offset = $3;
+ }
+| T_A
+ {
+ if (accumulator == NULL) {
+ stop("No accumulator has been defined", EX_DATAERR);
+ /* NOTREACHED */
+ }
+ $$.symbol = accumulator;
+ $$.offset = 0;
+ }
+;
+
+destination:
+ reg_symbol
+ {
+ test_writable_symbol($1.symbol);
+ $$ = $1;
+ }
+;
+
+immediate:
+ expression
+ { $$ = $1; }
+;
+
+immediate_or_a:
+ expression
+ {
+ $$ = $1;
+ }
+| T_A
+ {
+ SLIST_INIT(&$$.referenced_syms);
+ $$.value = 0;
+ }
+;
+
+source:
+ reg_symbol
+ {
+ test_readable_symbol($1.symbol);
+ $$ = $1;
+ }
+;
+
+opt_source:
+ {
+ $$.symbol = NULL;
+ $$.offset = 0;
+ }
+| ',' source
+ { $$ = $2; }
+;
+
+ret:
+ { $$ = 0; }
+| T_RET
+ { $$ = 1; }
+;
+
+label:
+ T_SYMBOL ':'
+ {
+ if ($1->type != UNINITIALIZED) {
+ stop("Program label multiply defined", EX_DATAERR);
+ /* NOTREACHED */
+ }
+ $1->type = LABEL;
+ initialize_symbol($1);
+ $1->info.linfo->address = instruction_ptr;
+ }
+;
+
+address:
+ T_SYMBOL
+ {
+ $$.symbol = $1;
+ $$.offset = 0;
+ }
+| T_SYMBOL '+' T_NUMBER
+ {
+ $$.symbol = $1;
+ $$.offset = $3;
+ }
+| T_SYMBOL '-' T_NUMBER
+ {
+ $$.symbol = $1;
+ $$.offset = -$3;
+ }
+| '.'
+ {
+ $$.symbol = NULL;
+ $$.offset = 0;
+ }
+| '.' '+' T_NUMBER
+ {
+ $$.symbol = NULL;
+ $$.offset = $3;
+ }
+| '.' '-' T_NUMBER
+ {
+ $$.symbol = NULL;
+ $$.offset = -$3;
+ }
+;
+
+conditional:
+ T_IF
+ {
+ if (cur_patch != NULL) {
+ stop("Nested .if directive", 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);
+ }
+;
+
+f1_opcode:
+ T_AND { $$ = AIC_OP_AND; }
+| T_XOR { $$ = AIC_OP_XOR; }
+| T_ADD { $$ = AIC_OP_ADD; }
+| T_ADC { $$ = AIC_OP_ADC; }
+;
+
+code:
+ f1_opcode destination ',' immediate_or_a opt_source ret ';'
+ {
+ format_1_instr($1, &$2, &$4, &$5, $6);
+ }
+;
+
+code:
+ T_OR reg_symbol ',' immediate_or_a opt_source ret ';'
+ {
+ format_1_instr(AIC_OP_OR, &$2, &$4, &$5, $6);
+ }
+;
+
+code:
+ T_INC destination opt_source ret ';'
+ {
+ expression_t immed;
+
+ make_expression(&immed, 1);
+ format_1_instr(AIC_OP_ADD, &$2, &immed, &$3, $4);
+ }
+;
+
+code:
+ T_DEC destination opt_source ret ';'
+ {
+ expression_t immed;
+
+ make_expression(&immed, -1);
+ format_1_instr(AIC_OP_ADD, &$2, &immed, &$3, $4);
+ }
+;
+
+code:
+ T_CLC ret ';'
+ {
+ expression_t immed;
+
+ make_expression(&immed, -1);
+ format_1_instr(AIC_OP_ADD, &none, &immed, &allzeros, $2);
+ }
+| T_CLC T_MVI destination ',' immediate_or_a ret ';'
+ {
+ format_1_instr(AIC_OP_ADD, &$3, &$5, &allzeros, $6);
+ }
+;
+
+code:
+ T_STC ret ';'
+ {
+ expression_t immed;
+
+ make_expression(&immed, 1);
+ format_1_instr(AIC_OP_ADD, &none, &immed, &allones, $2);
+ }
+| T_STC destination ret ';'
+ {
+ expression_t immed;
+
+ make_expression(&immed, 1);
+ format_1_instr(AIC_OP_ADD, &$2, &immed, &allones, $3);
+ }
+;
+
+code:
+ T_MOV destination ',' source ret ';'
+ {
+ expression_t immed;
+
+ make_expression(&immed, 0xff);
+ format_1_instr(AIC_OP_AND, &$2, &immed, &$4, $5);
+ }
+;
+
+code:
+ T_MVI destination ',' immediate_or_a ret ';'
+ {
+ format_1_instr(AIC_OP_OR, &$2, &$4, &allzeros, $5);
+ }
+;
+
+code:
+ T_CLR destination ret ';'
+ {
+ expression_t immed;
+
+ make_expression(&immed, 0xff);
+ format_1_instr(AIC_OP_AND, &$2, &immed, &allzeros, $3);
+ }
+;
+
+code:
+ T_NOP ';'
+ {
+ expression_t immed;
+
+ make_expression(&immed, 0xff);
+ format_1_instr(AIC_OP_AND, &none, &immed, &allzeros, FALSE);
+ }
+;
+
+code:
+ T_RET ';'
+ {
+ expression_t immed;
+
+ make_expression(&immed, 0xff);
+ format_1_instr(AIC_OP_AND, &none, &immed, &allzeros, TRUE);
+ }
+;
+
+ /*
+ * This grammer differs from the one in the aic7xxx
+ * reference manual since the grammer listed there is
+ * ambiguous and causes a shift/reduce conflict.
+ * It also seems more logical as the "immediate"
+ * argument is listed as the second arg like the
+ * other formats.
+ */
+
+f2_opcode:
+ T_SHL { $$ = AIC_OP_SHL; }
+| T_SHR { $$ = AIC_OP_SHR; }
+| T_ROL { $$ = AIC_OP_ROL; }
+| T_ROR { $$ = AIC_OP_ROR; }
+;
+
+code:
+ f2_opcode destination ',' expression opt_source ret ';'
+ {
+ format_2_instr($1, &$2, &$4, &$5, $6);
+ }
+;
+
+jmp_jc_jnc_call:
+ T_JMP { $$ = AIC_OP_JMP; }
+| T_JC { $$ = AIC_OP_JC; }
+| T_JNC { $$ = AIC_OP_JNC; }
+| T_CALL { $$ = AIC_OP_CALL; }
+;
+
+jz_jnz:
+ T_JZ { $$ = AIC_OP_JZ; }
+| T_JNZ { $$ = AIC_OP_JNZ; }
+;
+
+je_jne:
+ T_JE { $$ = AIC_OP_JE; }
+| T_JNE { $$ = AIC_OP_JNE; }
+;
+
+code:
+ jmp_jc_jnc_call address ';'
+ {
+ expression_t immed;
+
+ make_expression(&immed, 0);
+ format_3_instr($1, &sindex, &immed, &$2);
+ }
+;
+
+code:
+ T_OR reg_symbol ',' immediate jmp_jc_jnc_call address ';'
+ {
+ format_3_instr($5, &$2, &$4, &$6);
+ }
+;
+
+code:
+ T_TEST source ',' immediate_or_a jz_jnz address ';'
+ {
+ format_3_instr($5, &$2, &$4, &$6);
+ }
+;
+
+code:
+ T_CMP source ',' immediate_or_a je_jne address ';'
+ {
+ format_3_instr($5, &$2, &$4, &$6);
+ }
+;
+
+code:
+ T_MOV source jmp_jc_jnc_call address ';'
+ {
+ expression_t immed;
+
+ make_expression(&immed, 0);
+ format_3_instr($3, &$2, &immed, &$4);
+ }
+;
+
+code:
+ T_MVI immediate jmp_jc_jnc_call address ';'
+ {
+ format_3_instr($3, &allzeros, &$2, &$4);
+ }
+;
+
+%%
+
+static void
+process_bitmask(mask_type, sym, mask)
+ int mask_type;
+ symbol_t *sym;
+ int mask;
+{
+ /*
+ * Add the current register to its
+ * symbol list, if it already exists,
+ * warn if we are setting it to a
+ * different value, or in the bit to
+ * the "allowed bits" of this register.
+ */
+ if (sym->type == UNINITIALIZED) {
+ sym->type = mask_type;
+ initialize_symbol(sym);
+ if (mask_type == BIT) {
+ if (mask == 0) {
+ stop("Bitmask with no bits set", EX_DATAERR);
+ /* NOTREACHED */
+ }
+ if ((mask & ~(0x01 << (ffs(mask) - 1))) != 0) {
+ stop("Bitmask with more than one bit set",
+ EX_DATAERR);
+ /* NOTREACHED */
+ }
+ }
+ sym->info.minfo->mask = mask;
+ } else if (sym->type != mask_type) {
+ stop("Bit definition mirrors a definition of the same "
+ " name, but a different type", EX_DATAERR);
+ /* NOTREACHED */
+ } else if (mask != sym->info.minfo->mask) {
+ stop("Bitmask redefined with a conflicting value", EX_DATAERR);
+ /* NOTREACHED */
+ }
+ /* Fail if this symbol is already listed */
+ if (symlist_search(&(sym->info.minfo->symrefs),
+ cur_symbol->name) != NULL) {
+ stop("Bitmask defined multiple times for register", EX_DATAERR);
+ /* NOTREACHED */
+ }
+ symlist_add(&(sym->info.minfo->symrefs), cur_symbol,
+ SYMLIST_INSERT_HEAD);
+ cur_symbol->info.rinfo->valid_bitmask |= mask;
+ cur_symbol->info.rinfo->typecheck_masks = TRUE;
+}
+
+static void
+initialize_symbol(symbol)
+ symbol_t *symbol;
+{
+ switch (symbol->type) {
+ case UNINITIALIZED:
+ stop("Call to initialize_symbol with type field unset",
+ EX_SOFTWARE);
+ /* NOTREACHED */
+ break;
+ case REGISTER:
+ case SRAMLOC:
+ case SCBLOC:
+ symbol->info.rinfo =
+ (struct reg_info *)malloc(sizeof(struct reg_info));
+ if (symbol->info.rinfo == NULL) {
+ stop("Can't create register info", EX_SOFTWARE);
+ /* NOTREACHED */
+ }
+ memset(symbol->info.rinfo, 0,
+ sizeof(struct reg_info));
+ break;
+ case ALIAS:
+ symbol->info.ainfo =
+ (struct alias_info *)malloc(sizeof(struct alias_info));
+ if (symbol->info.ainfo == NULL) {
+ stop("Can't create alias info", EX_SOFTWARE);
+ /* NOTREACHED */
+ }
+ memset(symbol->info.ainfo, 0,
+ sizeof(struct alias_info));
+ break;
+ case MASK:
+ case BIT:
+ symbol->info.minfo =
+ (struct mask_info *)malloc(sizeof(struct mask_info));
+ if (symbol->info.minfo == NULL) {
+ stop("Can't create bitmask info", EX_SOFTWARE);
+ /* NOTREACHED */
+ }
+ memset(symbol->info.minfo, 0, sizeof(struct mask_info));
+ SLIST_INIT(&(symbol->info.minfo->symrefs));
+ break;
+ case CONST:
+ symbol->info.cinfo =
+ (struct const_info *)malloc(sizeof(struct const_info));
+ if (symbol->info.cinfo == NULL) {
+ stop("Can't create alias info", EX_SOFTWARE);
+ /* NOTREACHED */
+ }
+ memset(symbol->info.cinfo, 0,
+ sizeof(struct const_info));
+ break;
+ case LABEL:
+ symbol->info.linfo =
+ (struct label_info *)malloc(sizeof(struct label_info));
+ if (symbol->info.linfo == NULL) {
+ stop("Can't create label info", EX_SOFTWARE);
+ /* NOTREACHED */
+ }
+ memset(symbol->info.linfo, 0,
+ sizeof(struct label_info));
+ break;
+ case CONDITIONAL:
+ symbol->info.condinfo =
+ (struct cond_info *)malloc(sizeof(struct cond_info));
+ if (symbol->info.condinfo == NULL) {
+ stop("Can't create conditional info", EX_SOFTWARE);
+ /* NOTREACHED */
+ }
+ memset(symbol->info.condinfo, 0,
+ sizeof(struct cond_info));
+ break;
+ default:
+ stop("Call to initialize_symbol with invalid symbol type",
+ EX_SOFTWARE);
+ /* NOTREACHED */
+ break;
+ }
+}
+
+static void
+process_register(p_symbol)
+ symbol_t **p_symbol;
+{
+ char buf[255];
+ symbol_t *symbol = *p_symbol;
+
+ if (symbol->type == UNINITIALIZED) {
+ snprintf(buf, sizeof(buf), "Undefined register %s",
+ symbol->name);
+ stop(buf, EX_DATAERR);
+ /* NOTREACHED */
+ } else if (symbol->type == ALIAS) {
+ *p_symbol = symbol->info.ainfo->parent;
+ } else if ((symbol->type != REGISTER)
+ && (symbol->type != SCBLOC)
+ && (symbol->type != SRAMLOC)) {
+ snprintf(buf, sizeof(buf),
+ "Specified symbol %s is not a register",
+ symbol->name);
+ stop(buf, EX_DATAERR);
+ }
+}
+
+static void
+format_1_instr(opcode, dest, immed, src, ret)
+ int opcode;
+ symbol_ref_t *dest;
+ expression_t *immed;
+ symbol_ref_t *src;
+ int ret;
+{
+ struct instruction *instr;
+ struct ins_format1 *f1_instr;
+
+ if (src->symbol == NULL)
+ src = dest;
+
+ /* Test register permissions */
+ test_writable_symbol(dest->symbol);
+ test_readable_symbol(src->symbol);
+
+ /* Ensure that immediate makes sense for this destination */
+ type_check(dest->symbol, immed, opcode);
+
+ /* 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->destination = dest->symbol->info.rinfo->address
+ + dest->offset;
+ f1_instr->source = src->symbol->info.rinfo->address
+ + src->offset;
+ f1_instr->immediate = immed->value;
+ symlist_free(&immed->referenced_syms);
+ instruction_ptr++;
+}
+
+static void
+format_2_instr(opcode, dest, places, src, ret)
+ int opcode;
+ symbol_ref_t *dest;
+ expression_t *places;
+ symbol_ref_t *src;
+ int ret;
+{
+ struct instruction *instr;
+ struct ins_format2 *f2_instr;
+ u_int8_t shift_control;
+
+ if (src->symbol == NULL)
+ src = dest;
+
+ /* Test register permissions */
+ test_writable_symbol(dest->symbol);
+ test_readable_symbol(src->symbol);
+
+ /* 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->destination = dest->symbol->info.rinfo->address
+ + dest->offset;
+ f2_instr->source = src->symbol->info.rinfo->address
+ + src->offset;
+ if (places->value > 8 || places->value <= 0) {
+ stop("illegal shift value", EX_DATAERR);
+ /* NOTREACHED */
+ }
+ switch (opcode) {
+ case AIC_OP_SHL:
+ if (places->value == 8)
+ shift_control = 0xf0;
+ else
+ shift_control = (places->value << 4) | places->value;
+ break;
+ case AIC_OP_SHR:
+ if (places->value == 8) {
+ shift_control = 0xf8;
+ } else {
+ shift_control = (places->value << 4)
+ | (8 - places->value)
+ | 0x08;
+ }
+ break;
+ case AIC_OP_ROL:
+ shift_control = places->value & 0x7;
+ break;
+ case AIC_OP_ROR:
+ shift_control = (8 - places->value) | 0x08;
+ break;
+ default:
+ shift_control = 0; /* Quiet Compiler */
+ stop("Invalid shift operation specified", EX_SOFTWARE);
+ /* NOTREACHED */
+ break;
+ };
+ f2_instr->shift_control = shift_control;
+ symlist_free(&places->referenced_syms);
+ instruction_ptr++;
+}
+
+static void
+format_3_instr(opcode, src, immed, address)
+ int opcode;
+ symbol_ref_t *src;
+ expression_t *immed;
+ symbol_ref_t *address;
+{
+ struct instruction *instr;
+ struct ins_format3 *f3_instr;
+ int addr;
+
+ /* Test register permissions */
+ test_readable_symbol(src->symbol);
+
+ /* Ensure that immediate makes sense for this source */
+ type_check(src->symbol, immed, opcode);
+
+ /* Allocate sequencer space for the instruction and fill it out */
+ instr = seq_alloc();
+ f3_instr = &instr->format.format3;
+ if (address->symbol == NULL) {
+ /* 'dot' referrence. Use the current instruction pointer */
+ addr = instruction_ptr + address->offset;
+ } else if (address->symbol->type == UNINITIALIZED) {
+ /* forward reference */
+ addr = address->offset;
+ 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->source = src->symbol->info.rinfo->address
+ + src->offset;
+ f3_instr->immediate = immed->value;
+ symlist_free(&immed->referenced_syms);
+ instruction_ptr++;
+}
+
+static void
+test_readable_symbol(symbol)
+ symbol_t *symbol;
+{
+ if (symbol->info.rinfo->mode == WO) {
+ stop("Write Only register specified as source",
+ EX_DATAERR);
+ /* NOTREACHED */
+ }
+}
+
+static void
+test_writable_symbol(symbol)
+ symbol_t *symbol;
+{
+ if (symbol->info.rinfo->mode == RO) {
+ stop("Read Only register specified as destination",
+ EX_DATAERR);
+ /* NOTREACHED */
+ }
+}
+
+static void
+type_check(symbol, expression, opcode)
+ symbol_t *symbol;
+ expression_t *expression;
+ int opcode;
+{
+ symbol_node_t *node;
+ int and_op;
+ char buf[255];
+
+ and_op = FALSE;
+ if (opcode == AIC_OP_AND || opcode == AIC_OP_JNZ || AIC_OP_JZ)
+ and_op = TRUE;
+ /*
+ * Make sure that we aren't attempting to write something
+ * that hasn't been defined. If this is an and operation,
+ * this is a mask, so "undefined" bits are okay.
+ */
+ if (and_op == FALSE
+ && (expression->value & ~symbol->info.rinfo->valid_bitmask) != 0) {
+ snprintf(buf, sizeof(buf),
+ "Invalid bit(s) 0x%x in immediate written to %s",
+ expression->value & ~symbol->info.rinfo->valid_bitmask,
+ symbol->name);
+ stop(buf, EX_DATAERR);
+ /* NOTREACHED */
+ }
+
+ /*
+ * Now make sure that all of the symbols referenced by the
+ * expression are defined for this register.
+ */
+ if(symbol->info.rinfo->typecheck_masks != FALSE) {
+ for(node = expression->referenced_syms.slh_first;
+ node != NULL;
+ node = node->links.sle_next) {
+ if ((node->symbol->type == MASK
+ || node->symbol->type == BIT)
+ && symlist_search(&node->symbol->info.minfo->symrefs,
+ symbol->name) == NULL) {
+ snprintf(buf, sizeof(buf),
+ "Invalid bit or mask %s "
+ "for register %s",
+ node->symbol->name, symbol->name);
+ stop(buf, EX_DATAERR);
+ /* NOTREACHED */
+ }
+ }
+ }
+}
+
+static void
+make_expression(immed, value)
+ expression_t *immed;
+ int value;
+{
+ SLIST_INIT(&immed->referenced_syms);
+ immed->value = value & 0xff;
+}
+
+static void
+add_conditional(symbol)
+ symbol_t *symbol;
+{
+ static int numoptions = 1;
+
+ 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",
+ EX_DATAERR);
+ /* NOTREACHED */
+ }
+ cur_patch->options |= symbol->info.condinfo->value;
+}
+
+void
+yyerror(string)
+ const char *string;
+{
+ stop(string, EX_DATAERR);
+}
diff --git a/sys/dev/aic7xxx/aicasm_scan.l b/sys/dev/aic7xxx/aicasm_scan.l
new file mode 100644
index 0000000000000..d77ceddf4c993
--- /dev/null
+++ b/sys/dev/aic7xxx/aicasm_scan.l
@@ -0,0 +1,242 @@
+%{
+/*
+ * Lexical Analyzer for the Aic7xxx SCSI Host adapter sequencer assembler.
+ *
+ * Copyright (c) 1997 Justin T. Gibbs.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * this list of conditions, and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <sysexits.h>
+#include <sys/queue.h>
+
+#include "aic7xxx_asm.h"
+#include "symbol.h"
+#include "y.tab.h"
+%}
+
+PATH [-/A-Za-z0-9_.]*[./][-/A-Za-z0-9_.]*
+WORD [A-Za-z_][-A-Za-z_0-9]*
+SPACE [ \t]+
+
+%x COMMENT
+
+%%
+\n { ++yylineno; }
+"/*" { BEGIN COMMENT; /* Enter comment eating state */ }
+<COMMENT>"/*" { fprintf(stderr, "Warning! Comment within comment."); }
+<COMMENT>\n { ++yylineno; }
+<COMMENT>[^*/\n]* ;
+<COMMENT>"*"+[^*/\n]* ;
+<COMMENT>"/"+[^*/\n]* ;
+<COMMENT>"*"+"/" { BEGIN INITIAL; }
+
+{SPACE} ;
+
+ /* Register/SCB/SRAM definition keywords */
+register { return T_REGISTER; }
+const { yylval.value = FALSE; return T_CONST; }
+address { return T_ADDRESS; }
+access_mode { return T_ACCESS_MODE; }
+RW|RO|WO {
+ if (strcmp(yytext, "RW") == 0)
+ yylval.value = RW;
+ else if (strcmp(yytext, "RO") == 0)
+ yylval.value = RO;
+ else
+ yylval.value = WO;
+ return T_MODE;
+ }
+bit { return T_BIT; }
+mask { return T_MASK; }
+alias { return T_ALIAS; }
+size { return T_SIZE; }
+scb { return T_SCB; }
+scratch_ram { return T_SRAM; }
+accumulator { return T_ACCUM; }
+allones { return T_ALLONES; }
+allzeros { return T_ALLZEROS; }
+none { return T_NONE; }
+sindex { return T_SINDEX; }
+A { return T_A; }
+
+ /* Opcodes */
+shl { return T_SHL; }
+shr { return T_SHR; }
+ror { return T_ROR; }
+rol { return T_ROL; }
+mvi { return T_MVI; }
+mov { return T_MOV; }
+clr { return T_CLR; }
+jmp { return T_JMP; }
+jc { return T_JC; }
+jnc { return T_JNC; }
+je { return T_JE; }
+jne { return T_JNE; }
+jz { return T_JZ; }
+jnz { return T_JNZ; }
+call { return T_CALL; }
+add { return T_ADD; }
+adc { return T_ADC; }
+inc { return T_INC; }
+dec { return T_DEC; }
+stc { return T_STC; }
+clc { return T_CLC; }
+cmp { return T_CMP; }
+xor { return T_XOR; }
+test { return T_TEST;}
+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; }
+
+ /* Allowed Symbols */
+[-+,:()~|&."{};<>[\]!] { return yytext[0]; }
+
+ /* Number processing */
+0[0-7]* {
+ yylval.value = strtol(yytext, NULL, 8);
+ return T_NUMBER;
+ }
+
+0[xX][0-9a-fA-F]+ {
+ yylval.value = strtoul(yytext + 2, NULL, 16);
+ return T_NUMBER;
+ }
+
+[1-9][0-9]* {
+ yylval.value = strtol(yytext, NULL, 10);
+ return T_NUMBER;
+ }
+
+ /* Include Files */
+#include { return T_INCLUDE; }
+
+ /* For parsing C include files with #define foo */
+#define { yylval.value = TRUE; return T_CONST; }
+ /* Throw away macros */
+#define[^\n]*[()]+[^\n]* ;
+{PATH} { yylval.str = strdup(yytext); return T_PATH; }
+
+{WORD} { yylval.sym = symtable_get(yytext); return T_SYMBOL; }
+
+. {
+ char buf[255];
+
+ snprintf(buf, sizeof(buf), "Invalid character "
+ "'%c'", yytext[0]);
+ stop(buf, EX_DATAERR);
+ }
+%%
+
+typedef struct include {
+ YY_BUFFER_STATE buffer;
+ int lineno;
+ char *filename;
+ SLIST_ENTRY(include) links;
+}include_t;
+
+SLIST_HEAD(, include) include_stack;
+
+void
+include_file(file_name, type)
+ char *file_name;
+ include_type type;
+{
+ FILE *newfile;
+ include_t *include;
+
+ newfile = NULL;
+ /* Try the current directory first */
+ if (includes_search_curdir != 0 || type == SOURCE_FILE)
+ newfile = fopen(file_name, "r");
+
+ if (newfile == NULL && type != SOURCE_FILE) {
+ path_entry_t include_dir;
+ for (include_dir = search_path.slh_first;
+ include_dir != NULL;
+ include_dir = include_dir->links.sle_next) {
+ char fullname[PATH_MAX];
+
+ if ((include_dir->quoted_includes_only == TRUE)
+ && (type != QUOTED_INCLUDE))
+ continue;
+
+ snprintf(fullname, sizeof(fullname),
+ "%s/%s", include_dir->directory, file_name);
+
+ if ((newfile = fopen(fullname, "r")) != NULL)
+ break;
+ }
+ }
+
+ if (newfile == NULL) {
+ perror(file_name);
+ stop("Unable to open input file", EX_SOFTWARE);
+ /* NOTREACHED */
+ }
+ include = (include_t *)malloc(sizeof(include_t));
+ if (include == NULL) {
+ stop("Unable to allocate include stack entry", EX_SOFTWARE);
+ /* NOTREACHED */
+ }
+ include->buffer = YY_CURRENT_BUFFER;
+ include->lineno = yylineno;
+ include->filename = yyfilename;
+ SLIST_INSERT_HEAD(&include_stack, include, links);
+ yy_switch_to_buffer(yy_create_buffer(newfile, YY_BUF_SIZE));
+ yylineno = 1;
+ yyfilename = strdup(file_name);
+}
+
+int
+yywrap()
+{
+ include_t *include;
+
+ yy_delete_buffer(YY_CURRENT_BUFFER);
+ (void)fclose(yyin);
+ if (yyfilename != NULL)
+ free(yyfilename);
+ include = include_stack.slh_first;
+ if (include != NULL) {
+ yy_switch_to_buffer(include->buffer);
+ yylineno = include->lineno;
+ yyfilename = include->filename;
+ SLIST_REMOVE_HEAD(&include_stack, links);
+ free(include);
+ return (0);
+ }
+ return (1);
+}
diff --git a/sys/dev/aic7xxx/aicasm_symbol.c b/sys/dev/aic7xxx/aicasm_symbol.c
new file mode 100644
index 0000000000000..e2b93efbd2ee1
--- /dev/null
+++ b/sys/dev/aic7xxx/aicasm_symbol.c
@@ -0,0 +1,451 @@
+/*
+ * Aic7xxx SCSI host adapter firmware asssembler symbol table implementation
+ *
+ * Copyright (c) 1997 Justin T. Gibbs.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * this list of conditions, and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+
+#include <sys/types.h>
+
+#include <db.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+
+#include "symbol.h"
+#include "aic7xxx_asm.h"
+
+static DB *symtable;
+
+symbol_t *
+symbol_create(name)
+ char *name;
+{
+ symbol_t *new_symbol;
+
+ new_symbol = (symbol_t *)malloc(sizeof(symbol_t));
+ if (new_symbol == NULL) {
+ perror("Unable to create new symbol");
+ exit(EX_SOFTWARE);
+ }
+ memset(new_symbol, 0, sizeof(*new_symbol));
+ new_symbol->name = strdup(name);
+ new_symbol->type = UNINITIALIZED;
+ return (new_symbol);
+}
+
+void
+symbol_delete(symbol)
+ symbol_t *symbol;
+{
+ if (symtable != NULL) {
+ DBT key;
+
+ key.data = symbol->name;
+ key.size = strlen(symbol->name);
+ symtable->del(symtable, &key, /*flags*/0);
+ }
+ switch(symbol->type) {
+ case SCBLOC:
+ case SRAMLOC:
+ case REGISTER:
+ if (symbol->info.rinfo != NULL)
+ free(symbol->info.rinfo);
+ break;
+ case ALIAS:
+ if (symbol->info.ainfo != NULL)
+ free(symbol->info.ainfo);
+ break;
+ case MASK:
+ case BIT:
+ if (symbol->info.minfo != NULL) {
+ symlist_free(&symbol->info.minfo->symrefs);
+ free(symbol->info.minfo);
+ }
+ break;
+ case CONST:
+ if (symbol->info.cinfo != NULL)
+ free(symbol->info.cinfo);
+ break;
+ case LABEL:
+ if (symbol->info.linfo != NULL)
+ free(symbol->info.linfo);
+ break;
+ case UNINITIALIZED:
+ default:
+ break;
+ }
+ free(symbol->name);
+ free(symbol);
+}
+
+void
+symtable_open()
+{
+ symtable = dbopen(/*filename*/NULL,
+ O_CREAT | O_NONBLOCK | O_RDWR, /*mode*/0, DB_HASH,
+ /*openinfo*/NULL);
+
+ if (symtable == NULL) {
+ perror("Symbol table creation failed");
+ exit(EX_SOFTWARE);
+ /* NOTREACHED */
+ }
+}
+
+void
+symtable_close()
+{
+ if (symtable != NULL) {
+ DBT key;
+ DBT data;
+
+ while (symtable->seq(symtable, &key, &data, R_FIRST) == 0) {
+ symbol_t *cursym;
+
+ cursym = *(symbol_t **)data.data;
+ symbol_delete(cursym);
+ }
+ symtable->close(symtable);
+ }
+}
+
+/*
+ * The semantics of get is to return an uninitialized symbol entry
+ * if a lookup fails.
+ */
+symbol_t *
+symtable_get(name)
+ char *name;
+{
+ DBT key;
+ DBT data;
+ int retval;
+
+ key.data = (void *)name;
+ key.size = strlen(name);
+
+ if ((retval = symtable->get(symtable, &key, &data, /*flags*/0)) != 0) {
+ if (retval == -1) {
+ perror("Symbol table get operation failed");
+ exit(EX_SOFTWARE);
+ /* NOTREACHED */
+ } else if (retval == 1) {
+ /* Symbol wasn't found, so create a new one */
+ symbol_t *new_symbol;
+
+ new_symbol = symbol_create(name);
+ data.data = &new_symbol;
+ data.size = sizeof(new_symbol);
+ if (symtable->put(symtable, &key, &data,
+ /*flags*/0) !=0) {
+ perror("Symtable put failed");
+ exit(EX_SOFTWARE);
+ }
+ return (new_symbol);
+ } else {
+ perror("Unexpected return value from db get routine");
+ exit(EX_SOFTWARE);
+ /* NOTREACHED */
+ }
+ }
+ return (*(symbol_t **)data.data);
+}
+
+symbol_node_t *
+symlist_search(symlist, symname)
+ symlist_t *symlist;
+ char *symname;
+{
+ symbol_node_t *curnode;
+
+ curnode = symlist->slh_first;
+ while(curnode != NULL) {
+ if (strcmp(symname, curnode->symbol->name) == 0)
+ break;
+ curnode = curnode->links.sle_next;
+ }
+ return (curnode);
+}
+
+void
+symlist_add(symlist, symbol, how)
+ symlist_t *symlist;
+ symbol_t *symbol;
+ int how;
+{
+ symbol_node_t *newnode;
+
+ newnode = (symbol_node_t *)malloc(sizeof(symbol_node_t));
+ if (newnode == NULL) {
+ stop("symlist_add: Unable to malloc symbol_node", EX_SOFTWARE);
+ /* NOTREACHED */
+ }
+ newnode->symbol = symbol;
+ if (how == SYMLIST_SORT) {
+ symbol_node_t *curnode;
+ int mask;
+
+ mask = FALSE;
+ switch(symbol->type) {
+ case REGISTER:
+ case SCBLOC:
+ case SRAMLOC:
+ break;
+ case BIT:
+ case MASK:
+ mask = TRUE;
+ break;
+ default:
+ stop("symlist_add: Invalid symbol type for sorting",
+ EX_SOFTWARE);
+ /* NOTREACHED */
+ }
+
+ curnode = symlist->slh_first;
+ if (curnode == NULL
+ || (mask && (curnode->symbol->info.minfo->mask >
+ newnode->symbol->info.minfo->mask))
+ || (!mask && (curnode->symbol->info.rinfo->address >
+ newnode->symbol->info.rinfo->address))) {
+ SLIST_INSERT_HEAD(symlist, newnode, links);
+ return;
+ }
+
+ while (1) {
+ if (curnode->links.sle_next == NULL) {
+ SLIST_INSERT_AFTER(curnode, newnode,
+ links);
+ break;
+ } else {
+ symbol_t *cursymbol;
+
+ cursymbol = curnode->links.sle_next->symbol;
+ if ((mask && (cursymbol->info.minfo->mask >
+ symbol->info.minfo->mask))
+ || (!mask &&(cursymbol->info.rinfo->address >
+ symbol->info.rinfo->address))){
+ SLIST_INSERT_AFTER(curnode, newnode,
+ links);
+ break;
+ }
+ }
+ curnode = curnode->links.sle_next;
+ }
+ } else {
+ SLIST_INSERT_HEAD(symlist, newnode, links);
+ }
+}
+
+void
+symlist_free(symlist)
+ symlist_t *symlist;
+{
+ symbol_node_t *node1, *node2;
+
+ node1 = symlist->slh_first;
+ while (node1 != NULL) {
+ node2 = node1->links.sle_next;
+ free(node1);
+ node1 = node2;
+ }
+ SLIST_INIT(symlist);
+}
+
+void
+symlist_merge(symlist_dest, symlist_src1, symlist_src2)
+ symlist_t *symlist_dest;
+ symlist_t *symlist_src1;
+ symlist_t *symlist_src2;
+{
+ symbol_node_t *node;
+
+ *symlist_dest = *symlist_src1;
+ while((node = symlist_src2->slh_first) != NULL) {
+ SLIST_REMOVE_HEAD(symlist_src2, links);
+ SLIST_INSERT_HEAD(symlist_dest, node, links);
+ }
+
+ /* These are now empty */
+ SLIST_INIT(symlist_src1);
+ SLIST_INIT(symlist_src2);
+}
+
+void
+symtable_dump(ofile)
+ FILE *ofile;
+{
+ /*
+ * Sort the registers by address with a simple insertion sort.
+ * Put bitmasks next to the first register that defines them.
+ * Put constants at the end.
+ */
+ symlist_t registers;
+ symlist_t masks;
+ symlist_t constants;
+ symlist_t aliases;
+
+ SLIST_INIT(&registers);
+ SLIST_INIT(&masks);
+ SLIST_INIT(&constants);
+ SLIST_INIT(&aliases);
+
+ if (symtable != NULL) {
+ DBT key;
+ DBT data;
+ int flag = R_FIRST;
+
+ while (symtable->seq(symtable, &key, &data, flag) == 0) {
+ symbol_t *cursym;
+
+ cursym = *(symbol_t **)data.data;
+ switch(cursym->type) {
+ case REGISTER:
+ case SCBLOC:
+ case SRAMLOC:
+ symlist_add(&registers, cursym, SYMLIST_SORT);
+ break;
+ case MASK:
+ case BIT:
+ symlist_add(&masks, cursym, SYMLIST_SORT);
+ break;
+ case CONST:
+ if (cursym->info.cinfo->define == FALSE) {
+ symlist_add(&constants, cursym,
+ SYMLIST_INSERT_HEAD);
+ }
+ break;
+ case ALIAS:
+ symlist_add(&aliases, cursym,
+ SYMLIST_INSERT_HEAD);
+ default:
+ break;
+ }
+ flag = R_NEXT;
+ }
+
+ /* Put in the masks and bits */
+ while (masks.slh_first != NULL) {
+ symbol_node_t *curnode;
+ symbol_node_t *regnode;
+ char *regname;
+
+ curnode = masks.slh_first;
+ SLIST_REMOVE_HEAD(&masks, links);
+
+ regnode =
+ curnode->symbol->info.minfo->symrefs.slh_first;
+ regname = regnode->symbol->name;
+ regnode = symlist_search(&registers, regname);
+ SLIST_INSERT_AFTER(regnode, curnode, links);
+ }
+
+ /* Add the aliases */
+ while (aliases.slh_first != NULL) {
+ symbol_node_t *curnode;
+ symbol_node_t *regnode;
+ char *regname;
+
+ curnode = aliases.slh_first;
+ SLIST_REMOVE_HEAD(&aliases, links);
+
+ regname = curnode->symbol->info.ainfo->parent->name;
+ regnode = symlist_search(&registers, regname);
+ SLIST_INSERT_AFTER(regnode, curnode, links);
+ }
+
+ /* Output what we have */
+ fprintf(ofile,
+"/*
+ * DO NOT EDIT - This file is automatically generated.
+ */\n");
+ while (registers.slh_first != NULL) {
+ symbol_node_t *curnode;
+ u_int8_t value;
+ char *tab_str;
+ char *tab_str2;
+
+ curnode = registers.slh_first;
+ SLIST_REMOVE_HEAD(&registers, links);
+ switch(curnode->symbol->type) {
+ case REGISTER:
+ case SCBLOC:
+ case SRAMLOC:
+ fprintf(ofile, "\n");
+ value = curnode->symbol->info.rinfo->address;
+ tab_str = "\t";
+ tab_str2 = "\t\t";
+ break;
+ case ALIAS:
+ {
+ symbol_t *parent;
+
+ parent = curnode->symbol->info.ainfo->parent;
+ value = parent->info.rinfo->address;
+ tab_str = "\t";
+ tab_str2 = "\t\t";
+ break;
+ }
+ case MASK:
+ case BIT:
+ value = curnode->symbol->info.minfo->mask;
+ tab_str = "\t\t";
+ tab_str2 = "\t";
+ break;
+ default:
+ value = 0; /* Quiet compiler */
+ tab_str = NULL;
+ tab_str2 = NULL;
+ stop("symtable_dump: Invalid symbol type "
+ "encountered", EX_SOFTWARE);
+ break;
+ }
+ fprintf(ofile, "#define%s%-16s%s0x%02x\n",
+ tab_str, curnode->symbol->name, tab_str2,
+ value);
+ free(curnode);
+ }
+ fprintf(ofile, "\n\n");
+
+ while (constants.slh_first != NULL) {
+ symbol_node_t *curnode;
+
+ curnode = constants.slh_first;
+ SLIST_REMOVE_HEAD(&constants, links);
+ fprintf(ofile, "#define\t%-8s\t0x%02x\n",
+ curnode->symbol->name,
+ curnode->symbol->info.cinfo->value);
+ free(curnode);
+ }
+ }
+}
+
diff --git a/sys/dev/aic7xxx/aicasm_symbol.h b/sys/dev/aic7xxx/aicasm_symbol.h
new file mode 100644
index 0000000000000..cf8fa0071225a
--- /dev/null
+++ b/sys/dev/aic7xxx/aicasm_symbol.h
@@ -0,0 +1,144 @@
+/*
+ * Aic7xxx SCSI host adapter firmware asssembler symbol table definitions
+ *
+ * Copyright (c) 1997 Justin T. Gibbs.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * this list of conditions, and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#include <sys/queue.h>
+
+typedef enum {
+ UNINITIALIZED,
+ REGISTER,
+ ALIAS,
+ SCBLOC,
+ SRAMLOC,
+ MASK,
+ BIT,
+ CONST,
+ LABEL,
+ CONDITIONAL
+}symtype;
+
+typedef enum {
+ RO = 0x01,
+ WO = 0x02,
+ RW = 0x03
+}amode_t;
+
+struct reg_info {
+ u_int8_t address;
+ int size;
+ amode_t mode;
+ u_int8_t valid_bitmask;
+ int typecheck_masks;
+};
+
+typedef SLIST_HEAD(symlist, symbol_node) symlist_t;
+
+struct mask_info {
+ symlist_t symrefs;
+ u_int8_t mask;
+};
+
+struct const_info {
+ u_int8_t value;
+ int define;
+};
+
+struct alias_info {
+ struct symbol *parent;
+};
+
+struct label_info {
+ int address;
+};
+
+struct cond_info {
+ int value;
+};
+
+typedef struct expression_info {
+ symlist_t referenced_syms;
+ int value;
+} expression_t;
+
+typedef struct symbol {
+ char *name;
+ symtype type;
+ union {
+ struct reg_info *rinfo;
+ struct mask_info *minfo;
+ struct const_info *cinfo;
+ struct alias_info *ainfo;
+ struct label_info *linfo;
+ struct cond_info *condinfo;
+ }info;
+} symbol_t;
+
+typedef struct symbol_ref {
+ symbol_t *symbol;
+ int offset;
+} symbol_ref_t;
+
+typedef struct symbol_node {
+ SLIST_ENTRY(symbol_node) links;
+ symbol_t *symbol;
+}symbol_node_t;
+
+typedef struct patch {
+ STAILQ_ENTRY(patch) links;
+ int negative;
+ int begin;
+ int end;
+ int options;
+} patch_t;
+
+void symbol_delete __P((symbol_t *symbol));
+
+void symtable_open __P((void));
+
+void symtable_close __P((void));
+
+symbol_t *
+ symtable_get __P((char *name));
+
+symbol_node_t *
+ symlist_search __P((symlist_t *symlist, char *symname));
+
+void
+ symlist_add __P((symlist_t *symlist, symbol_t *symbol, int how));
+#define SYMLIST_INSERT_HEAD 0x00
+#define SYMLIST_SORT 0x01
+
+void symlist_free __P((symlist_t *symlist));
+
+void symlist_merge __P((symlist_t *symlist_dest, symlist_t *symlist_src1,
+ symlist_t *symlist_src2));
+void symtable_dump __P((FILE *ofile));
diff --git a/sys/dev/aic7xxx/gram.y b/sys/dev/aic7xxx/gram.y
new file mode 100644
index 0000000000000..0c75edca3b3ee
--- /dev/null
+++ b/sys/dev/aic7xxx/gram.y
@@ -0,0 +1,1304 @@
+%{
+/*
+ * Parser for the Aic7xxx SCSI Host adapter sequencer assembler.
+ *
+ * Copyright (c) 1997 Justin T. Gibbs.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * this list of conditions, and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+
+#include <sys/types.h>
+#include <sys/queue.h>
+
+#include "aic7xxx_asm.h"
+#include "symbol.h"
+#include "sequencer.h"
+
+int yylineno;
+char *yyfilename;
+static symbol_t *cur_symbol;
+static symtype cur_symtype;
+static symbol_t *accumulator;
+static symbol_ref_t allones;
+static symbol_ref_t allzeros;
+static symbol_ref_t none;
+static symbol_ref_t sindex;
+static int instruction_ptr;
+static int sram_or_scb_offset;
+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));
+static void process_register __P((symbol_t **p_symbol));
+static void format_1_instr __P((int opcode, symbol_ref_t *dest,
+ expression_t *immed, symbol_ref_t *src,
+ int ret));
+static void format_2_instr __P((int opcode, symbol_ref_t *dest,
+ expression_t *places, symbol_ref_t *src,
+ int ret));
+static void format_3_instr __P((int opcode, symbol_ref_t *src,
+ expression_t *immed, symbol_ref_t *address));
+static void test_readable_symbol __P((symbol_t *symbol));
+static void test_writable_symbol __P((symbol_t *symbol));
+static void type_check __P((symbol_t *symbol, expression_t *expression,
+ int and_op));
+static void make_expression __P((expression_t *immed, int value));
+static void add_conditional __P((symbol_t *symbol));
+
+#define YYDEBUG 1
+#define SRAM_SYMNAME "SRAM_BASE"
+#define SCB_SYMNAME "SCB_BASE"
+%}
+
+%union {
+ int value;
+ char *str;
+ symbol_t *sym;
+ symbol_ref_t sym_ref;
+ expression_t expression;
+}
+
+%token T_REGISTER
+
+%token <value> T_CONST
+
+%token T_SCB
+
+%token T_SRAM
+
+%token T_ALIAS
+
+%token T_SIZE
+
+%token <value> T_ADDRESS
+
+%token T_ACCESS_MODE
+
+%token <value> T_MODE
+
+%token T_BIT
+
+%token T_MASK
+
+%token <value> T_NUMBER
+
+%token <str> T_PATH
+
+%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_JMP T_JC T_JNC T_JE T_JNE T_JNZ T_JZ T_CALL
+
+%token <value> T_ADD T_ADC
+
+%token <value> T_INC T_DEC
+
+%token <value> T_STC T_CLC
+
+%token <value> T_CMP T_XOR
+
+%token <value> T_TEST T_AND
+
+%token <value> T_OR
+
+%token T_RET
+
+%token T_NOP
+
+%token T_ACCUM T_ALLONES T_ALLZEROS T_NONE T_SINDEX
+
+%token T_A
+
+%token <sym> T_SYMBOL
+
+%token T_NL
+
+%token T_IF T_ELSE T_ENDIF
+
+%type <sym_ref> reg_symbol address destination source opt_source
+
+%type <expression> expression immediate immediate_or_a
+
+%type <value> ret f1_opcode f2_opcode jmp_jc_jnc_call jz_jnz je_jne
+
+%left '|'
+%left '&'
+%left '+' '-'
+%right '~'
+%nonassoc UMINUS
+%%
+
+program:
+ include
+| program include
+| register
+| program register
+| constant
+| program constant
+| scratch_ram
+| program scratch_ram
+| scb
+| program scb
+| label
+| program label
+| conditional
+| program conditional
+| code
+| program code
+;
+
+include:
+ T_INCLUDE '<' T_PATH '>'
+ { include_file($3, BRACKETED_INCLUDE); }
+| T_INCLUDE '"' T_PATH '"'
+ { include_file($3, QUOTED_INCLUDE); }
+;
+
+register:
+ T_REGISTER { cur_symtype = REGISTER; } reg_definition
+;
+
+reg_definition:
+ T_SYMBOL '{'
+ {
+ if ($1->type != UNINITIALIZED) {
+ stop("Register multiply defined", EX_DATAERR);
+ /* NOTREACHED */
+ }
+ cur_symbol = $1;
+ cur_symbol->type = cur_symtype;
+ initialize_symbol(cur_symbol);
+ }
+ reg_attribute_list
+ '}'
+ {
+ /*
+ * Default to allowing everything in for registers
+ * with no bit or mask definitions.
+ */
+ if (cur_symbol->info.rinfo->valid_bitmask == 0)
+ cur_symbol->info.rinfo->valid_bitmask = 0xFF;
+
+ if (cur_symbol->info.rinfo->size == 0)
+ cur_symbol->info.rinfo->size = 1;
+
+ /*
+ * This might be useful for registers too.
+ */
+ if (cur_symbol->type != REGISTER) {
+ if (cur_symbol->info.rinfo->address == 0)
+ cur_symbol->info.rinfo->address =
+ sram_or_scb_offset;
+ sram_or_scb_offset +=
+ cur_symbol->info.rinfo->size;
+ }
+ cur_symbol = NULL;
+ }
+;
+
+reg_attribute_list:
+ reg_attribute
+| reg_attribute_list reg_attribute
+;
+
+reg_attribute:
+ reg_address
+| size
+| access_mode
+| bit_defn
+| mask_defn
+| alias
+| accumulator
+| allones
+| allzeros
+| none
+| sindex
+;
+
+reg_address:
+ T_ADDRESS T_NUMBER
+ {
+ cur_symbol->info.rinfo->address = $2;
+ }
+;
+
+size:
+ T_SIZE T_NUMBER
+ {
+ cur_symbol->info.rinfo->size = $2;
+ }
+;
+
+access_mode:
+ T_ACCESS_MODE T_MODE
+ {
+ cur_symbol->info.rinfo->mode = $2;
+ }
+;
+
+bit_defn:
+ T_BIT T_SYMBOL T_NUMBER
+ {
+ process_bitmask(BIT, $2, $3);
+ }
+;
+
+mask_defn:
+ T_MASK T_SYMBOL expression
+ {
+ process_bitmask(MASK, $2, $3.value);
+ }
+;
+
+alias:
+ T_ALIAS T_SYMBOL
+ {
+ if ($2->type != UNINITIALIZED) {
+ stop("Re-definition of register alias",
+ EX_DATAERR);
+ /* NOTREACHED */
+ }
+ $2->type = ALIAS;
+ initialize_symbol($2);
+ $2->info.ainfo->parent = cur_symbol;
+ }
+;
+
+accumulator:
+ T_ACCUM
+ {
+ if (accumulator != NULL) {
+ stop("Only one accumulator definition allowed",
+ EX_DATAERR);
+ /* NOTREACHED */
+ }
+ accumulator = cur_symbol;
+ }
+;
+
+allones:
+ T_ALLONES
+ {
+ if (allones.symbol != NULL) {
+ stop("Only one definition of allones allowed",
+ EX_DATAERR);
+ /* NOTREACHED */
+ }
+ allones.symbol = cur_symbol;
+ }
+;
+
+allzeros:
+ T_ALLZEROS
+ {
+ if (allzeros.symbol != NULL) {
+ stop("Only one definition of allzeros allowed",
+ EX_DATAERR);
+ /* NOTREACHED */
+ }
+ allzeros.symbol = cur_symbol;
+ }
+;
+
+none:
+ T_NONE
+ {
+ if (none.symbol != NULL) {
+ stop("Only one definition of none allowed",
+ EX_DATAERR);
+ /* NOTREACHED */
+ }
+ none.symbol = cur_symbol;
+ }
+;
+
+sindex:
+ T_SINDEX
+ {
+ if (sindex.symbol != NULL) {
+ stop("Only one definition of sindex allowed",
+ EX_DATAERR);
+ /* NOTREACHED */
+ }
+ sindex.symbol = cur_symbol;
+ }
+;
+
+expression:
+ expression '|' expression
+ {
+ $$.value = $1.value | $3.value;
+ symlist_merge(&$$.referenced_syms,
+ &$1.referenced_syms,
+ &$3.referenced_syms);
+ }
+| expression '&' expression
+ {
+ $$.value = $1.value & $3.value;
+ symlist_merge(&$$.referenced_syms,
+ &$1.referenced_syms,
+ &$3.referenced_syms);
+ }
+| expression '+' expression
+ {
+ $$.value = $1.value + $3.value;
+ symlist_merge(&$$.referenced_syms,
+ &$1.referenced_syms,
+ &$3.referenced_syms);
+ }
+| expression '-' expression
+ {
+ $$.value = $1.value - $3.value;
+ symlist_merge(&($$.referenced_syms),
+ &($1.referenced_syms),
+ &($3.referenced_syms));
+ }
+| '(' expression ')'
+ {
+ $$ = $2;
+ }
+| '~' expression
+ {
+ $$ = $2;
+ $$.value = (~$$.value) & 0xFF;
+ }
+| '-' expression %prec UMINUS
+ {
+ $$ = $2;
+ $$.value = -$$.value;
+ }
+| T_NUMBER
+ {
+ $$.value = $1;
+ SLIST_INIT(&$$.referenced_syms);
+ }
+| T_SYMBOL
+ {
+ symbol_t *symbol;
+
+ symbol = $1;
+ switch (symbol->type) {
+ case ALIAS:
+ symbol = $1->info.ainfo->parent;
+ case REGISTER:
+ case SCBLOC:
+ case SRAMLOC:
+ $$.value = symbol->info.rinfo->address;
+ break;
+ case MASK:
+ case BIT:
+ $$.value = symbol->info.minfo->mask;
+ break;
+ case CONST:
+ $$.value = symbol->info.cinfo->value;
+ break;
+ case UNINITIALIZED:
+ default:
+ {
+ char buf[255];
+
+ snprintf(buf, sizeof(buf),
+ "Undefined symbol %s referenced",
+ symbol->name);
+ stop(buf, EX_DATAERR);
+ /* NOTREACHED */
+ break;
+ }
+ }
+ SLIST_INIT(&$$.referenced_syms);
+ symlist_add(&$$.referenced_syms, symbol, SYMLIST_INSERT_HEAD);
+ }
+;
+
+constant:
+ T_CONST T_SYMBOL T_NUMBER
+ {
+ if ($2->type != UNINITIALIZED) {
+ stop("Re-definition of constant variable",
+ EX_DATAERR);
+ /* NOTREACHED */
+ }
+ $2->type = CONST;
+ initialize_symbol($2);
+ $2->info.cinfo->value = $3;
+ $2->info.cinfo->define = $1;
+ }
+;
+
+scratch_ram:
+ T_SRAM '{'
+ {
+ cur_symbol = symtable_get(SRAM_SYMNAME);
+ cur_symtype = SRAMLOC;
+ if (cur_symbol->type != UNINITIALIZED) {
+ stop("Only one SRAM definition allowed",
+ EX_DATAERR);
+ /* NOTREACHED */
+ }
+ cur_symbol->type = SRAMLOC;
+ initialize_symbol(cur_symbol);
+ }
+ reg_address
+ {
+ sram_or_scb_offset = cur_symbol->info.rinfo->address;
+ }
+ scb_or_sram_reg_list
+ '}'
+ {
+ cur_symbol = NULL;
+ }
+;
+
+scb:
+ T_SCB '{'
+ {
+ cur_symbol = symtable_get(SCB_SYMNAME);
+ cur_symtype = SCBLOC;
+ if (cur_symbol->type != UNINITIALIZED) {
+ stop("Only one SRAM definition allowed",
+ EX_SOFTWARE);
+ /* NOTREACHED */
+ }
+ cur_symbol->type = SCBLOC;
+ initialize_symbol(cur_symbol);
+ }
+ reg_address
+ {
+ sram_or_scb_offset = cur_symbol->info.rinfo->address;
+ }
+ scb_or_sram_reg_list
+ '}'
+ {
+ cur_symbol = NULL;
+ }
+;
+
+scb_or_sram_reg_list:
+ reg_definition
+| scb_or_sram_reg_list reg_definition
+;
+
+reg_symbol:
+ T_SYMBOL
+ {
+ process_register(&$1);
+ $$.symbol = $1;
+ $$.offset = 0;
+ }
+| T_SYMBOL '[' T_NUMBER ']'
+ {
+ process_register(&$1);
+ if (($3 + 1) > $1->info.rinfo->size) {
+ stop("Accessing offset beyond range of register",
+ EX_DATAERR);
+ /* NOTREACHED */
+ }
+ $$.symbol = $1;
+ $$.offset = $3;
+ }
+| T_A
+ {
+ if (accumulator == NULL) {
+ stop("No accumulator has been defined", EX_DATAERR);
+ /* NOTREACHED */
+ }
+ $$.symbol = accumulator;
+ $$.offset = 0;
+ }
+;
+
+destination:
+ reg_symbol
+ {
+ test_writable_symbol($1.symbol);
+ $$ = $1;
+ }
+;
+
+immediate:
+ expression
+ { $$ = $1; }
+;
+
+immediate_or_a:
+ expression
+ {
+ $$ = $1;
+ }
+| T_A
+ {
+ SLIST_INIT(&$$.referenced_syms);
+ $$.value = 0;
+ }
+;
+
+source:
+ reg_symbol
+ {
+ test_readable_symbol($1.symbol);
+ $$ = $1;
+ }
+;
+
+opt_source:
+ {
+ $$.symbol = NULL;
+ $$.offset = 0;
+ }
+| ',' source
+ { $$ = $2; }
+;
+
+ret:
+ { $$ = 0; }
+| T_RET
+ { $$ = 1; }
+;
+
+label:
+ T_SYMBOL ':'
+ {
+ if ($1->type != UNINITIALIZED) {
+ stop("Program label multiply defined", EX_DATAERR);
+ /* NOTREACHED */
+ }
+ $1->type = LABEL;
+ initialize_symbol($1);
+ $1->info.linfo->address = instruction_ptr;
+ }
+;
+
+address:
+ T_SYMBOL
+ {
+ $$.symbol = $1;
+ $$.offset = 0;
+ }
+| T_SYMBOL '+' T_NUMBER
+ {
+ $$.symbol = $1;
+ $$.offset = $3;
+ }
+| T_SYMBOL '-' T_NUMBER
+ {
+ $$.symbol = $1;
+ $$.offset = -$3;
+ }
+| '.'
+ {
+ $$.symbol = NULL;
+ $$.offset = 0;
+ }
+| '.' '+' T_NUMBER
+ {
+ $$.symbol = NULL;
+ $$.offset = $3;
+ }
+| '.' '-' T_NUMBER
+ {
+ $$.symbol = NULL;
+ $$.offset = -$3;
+ }
+;
+
+conditional:
+ T_IF
+ {
+ if (cur_patch != NULL) {
+ stop("Nested .if directive", 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);
+ }
+;
+
+f1_opcode:
+ T_AND { $$ = AIC_OP_AND; }
+| T_XOR { $$ = AIC_OP_XOR; }
+| T_ADD { $$ = AIC_OP_ADD; }
+| T_ADC { $$ = AIC_OP_ADC; }
+;
+
+code:
+ f1_opcode destination ',' immediate_or_a opt_source ret ';'
+ {
+ format_1_instr($1, &$2, &$4, &$5, $6);
+ }
+;
+
+code:
+ T_OR reg_symbol ',' immediate_or_a opt_source ret ';'
+ {
+ format_1_instr(AIC_OP_OR, &$2, &$4, &$5, $6);
+ }
+;
+
+code:
+ T_INC destination opt_source ret ';'
+ {
+ expression_t immed;
+
+ make_expression(&immed, 1);
+ format_1_instr(AIC_OP_ADD, &$2, &immed, &$3, $4);
+ }
+;
+
+code:
+ T_DEC destination opt_source ret ';'
+ {
+ expression_t immed;
+
+ make_expression(&immed, -1);
+ format_1_instr(AIC_OP_ADD, &$2, &immed, &$3, $4);
+ }
+;
+
+code:
+ T_CLC ret ';'
+ {
+ expression_t immed;
+
+ make_expression(&immed, -1);
+ format_1_instr(AIC_OP_ADD, &none, &immed, &allzeros, $2);
+ }
+| T_CLC T_MVI destination ',' immediate_or_a ret ';'
+ {
+ format_1_instr(AIC_OP_ADD, &$3, &$5, &allzeros, $6);
+ }
+;
+
+code:
+ T_STC ret ';'
+ {
+ expression_t immed;
+
+ make_expression(&immed, 1);
+ format_1_instr(AIC_OP_ADD, &none, &immed, &allones, $2);
+ }
+| T_STC destination ret ';'
+ {
+ expression_t immed;
+
+ make_expression(&immed, 1);
+ format_1_instr(AIC_OP_ADD, &$2, &immed, &allones, $3);
+ }
+;
+
+code:
+ T_MOV destination ',' source ret ';'
+ {
+ expression_t immed;
+
+ make_expression(&immed, 0xff);
+ format_1_instr(AIC_OP_AND, &$2, &immed, &$4, $5);
+ }
+;
+
+code:
+ T_MVI destination ',' immediate_or_a ret ';'
+ {
+ format_1_instr(AIC_OP_OR, &$2, &$4, &allzeros, $5);
+ }
+;
+
+code:
+ T_CLR destination ret ';'
+ {
+ expression_t immed;
+
+ make_expression(&immed, 0xff);
+ format_1_instr(AIC_OP_AND, &$2, &immed, &allzeros, $3);
+ }
+;
+
+code:
+ T_NOP ';'
+ {
+ expression_t immed;
+
+ make_expression(&immed, 0xff);
+ format_1_instr(AIC_OP_AND, &none, &immed, &allzeros, FALSE);
+ }
+;
+
+code:
+ T_RET ';'
+ {
+ expression_t immed;
+
+ make_expression(&immed, 0xff);
+ format_1_instr(AIC_OP_AND, &none, &immed, &allzeros, TRUE);
+ }
+;
+
+ /*
+ * This grammer differs from the one in the aic7xxx
+ * reference manual since the grammer listed there is
+ * ambiguous and causes a shift/reduce conflict.
+ * It also seems more logical as the "immediate"
+ * argument is listed as the second arg like the
+ * other formats.
+ */
+
+f2_opcode:
+ T_SHL { $$ = AIC_OP_SHL; }
+| T_SHR { $$ = AIC_OP_SHR; }
+| T_ROL { $$ = AIC_OP_ROL; }
+| T_ROR { $$ = AIC_OP_ROR; }
+;
+
+code:
+ f2_opcode destination ',' expression opt_source ret ';'
+ {
+ format_2_instr($1, &$2, &$4, &$5, $6);
+ }
+;
+
+jmp_jc_jnc_call:
+ T_JMP { $$ = AIC_OP_JMP; }
+| T_JC { $$ = AIC_OP_JC; }
+| T_JNC { $$ = AIC_OP_JNC; }
+| T_CALL { $$ = AIC_OP_CALL; }
+;
+
+jz_jnz:
+ T_JZ { $$ = AIC_OP_JZ; }
+| T_JNZ { $$ = AIC_OP_JNZ; }
+;
+
+je_jne:
+ T_JE { $$ = AIC_OP_JE; }
+| T_JNE { $$ = AIC_OP_JNE; }
+;
+
+code:
+ jmp_jc_jnc_call address ';'
+ {
+ expression_t immed;
+
+ make_expression(&immed, 0);
+ format_3_instr($1, &sindex, &immed, &$2);
+ }
+;
+
+code:
+ T_OR reg_symbol ',' immediate jmp_jc_jnc_call address ';'
+ {
+ format_3_instr($5, &$2, &$4, &$6);
+ }
+;
+
+code:
+ T_TEST source ',' immediate_or_a jz_jnz address ';'
+ {
+ format_3_instr($5, &$2, &$4, &$6);
+ }
+;
+
+code:
+ T_CMP source ',' immediate_or_a je_jne address ';'
+ {
+ format_3_instr($5, &$2, &$4, &$6);
+ }
+;
+
+code:
+ T_MOV source jmp_jc_jnc_call address ';'
+ {
+ expression_t immed;
+
+ make_expression(&immed, 0);
+ format_3_instr($3, &$2, &immed, &$4);
+ }
+;
+
+code:
+ T_MVI immediate jmp_jc_jnc_call address ';'
+ {
+ format_3_instr($3, &allzeros, &$2, &$4);
+ }
+;
+
+%%
+
+static void
+process_bitmask(mask_type, sym, mask)
+ int mask_type;
+ symbol_t *sym;
+ int mask;
+{
+ /*
+ * Add the current register to its
+ * symbol list, if it already exists,
+ * warn if we are setting it to a
+ * different value, or in the bit to
+ * the "allowed bits" of this register.
+ */
+ if (sym->type == UNINITIALIZED) {
+ sym->type = mask_type;
+ initialize_symbol(sym);
+ if (mask_type == BIT) {
+ if (mask == 0) {
+ stop("Bitmask with no bits set", EX_DATAERR);
+ /* NOTREACHED */
+ }
+ if ((mask & ~(0x01 << (ffs(mask) - 1))) != 0) {
+ stop("Bitmask with more than one bit set",
+ EX_DATAERR);
+ /* NOTREACHED */
+ }
+ }
+ sym->info.minfo->mask = mask;
+ } else if (sym->type != mask_type) {
+ stop("Bit definition mirrors a definition of the same "
+ " name, but a different type", EX_DATAERR);
+ /* NOTREACHED */
+ } else if (mask != sym->info.minfo->mask) {
+ stop("Bitmask redefined with a conflicting value", EX_DATAERR);
+ /* NOTREACHED */
+ }
+ /* Fail if this symbol is already listed */
+ if (symlist_search(&(sym->info.minfo->symrefs),
+ cur_symbol->name) != NULL) {
+ stop("Bitmask defined multiple times for register", EX_DATAERR);
+ /* NOTREACHED */
+ }
+ symlist_add(&(sym->info.minfo->symrefs), cur_symbol,
+ SYMLIST_INSERT_HEAD);
+ cur_symbol->info.rinfo->valid_bitmask |= mask;
+ cur_symbol->info.rinfo->typecheck_masks = TRUE;
+}
+
+static void
+initialize_symbol(symbol)
+ symbol_t *symbol;
+{
+ switch (symbol->type) {
+ case UNINITIALIZED:
+ stop("Call to initialize_symbol with type field unset",
+ EX_SOFTWARE);
+ /* NOTREACHED */
+ break;
+ case REGISTER:
+ case SRAMLOC:
+ case SCBLOC:
+ symbol->info.rinfo =
+ (struct reg_info *)malloc(sizeof(struct reg_info));
+ if (symbol->info.rinfo == NULL) {
+ stop("Can't create register info", EX_SOFTWARE);
+ /* NOTREACHED */
+ }
+ memset(symbol->info.rinfo, 0,
+ sizeof(struct reg_info));
+ break;
+ case ALIAS:
+ symbol->info.ainfo =
+ (struct alias_info *)malloc(sizeof(struct alias_info));
+ if (symbol->info.ainfo == NULL) {
+ stop("Can't create alias info", EX_SOFTWARE);
+ /* NOTREACHED */
+ }
+ memset(symbol->info.ainfo, 0,
+ sizeof(struct alias_info));
+ break;
+ case MASK:
+ case BIT:
+ symbol->info.minfo =
+ (struct mask_info *)malloc(sizeof(struct mask_info));
+ if (symbol->info.minfo == NULL) {
+ stop("Can't create bitmask info", EX_SOFTWARE);
+ /* NOTREACHED */
+ }
+ memset(symbol->info.minfo, 0, sizeof(struct mask_info));
+ SLIST_INIT(&(symbol->info.minfo->symrefs));
+ break;
+ case CONST:
+ symbol->info.cinfo =
+ (struct const_info *)malloc(sizeof(struct const_info));
+ if (symbol->info.cinfo == NULL) {
+ stop("Can't create alias info", EX_SOFTWARE);
+ /* NOTREACHED */
+ }
+ memset(symbol->info.cinfo, 0,
+ sizeof(struct const_info));
+ break;
+ case LABEL:
+ symbol->info.linfo =
+ (struct label_info *)malloc(sizeof(struct label_info));
+ if (symbol->info.linfo == NULL) {
+ stop("Can't create label info", EX_SOFTWARE);
+ /* NOTREACHED */
+ }
+ memset(symbol->info.linfo, 0,
+ sizeof(struct label_info));
+ break;
+ case CONDITIONAL:
+ symbol->info.condinfo =
+ (struct cond_info *)malloc(sizeof(struct cond_info));
+ if (symbol->info.condinfo == NULL) {
+ stop("Can't create conditional info", EX_SOFTWARE);
+ /* NOTREACHED */
+ }
+ memset(symbol->info.condinfo, 0,
+ sizeof(struct cond_info));
+ break;
+ default:
+ stop("Call to initialize_symbol with invalid symbol type",
+ EX_SOFTWARE);
+ /* NOTREACHED */
+ break;
+ }
+}
+
+static void
+process_register(p_symbol)
+ symbol_t **p_symbol;
+{
+ char buf[255];
+ symbol_t *symbol = *p_symbol;
+
+ if (symbol->type == UNINITIALIZED) {
+ snprintf(buf, sizeof(buf), "Undefined register %s",
+ symbol->name);
+ stop(buf, EX_DATAERR);
+ /* NOTREACHED */
+ } else if (symbol->type == ALIAS) {
+ *p_symbol = symbol->info.ainfo->parent;
+ } else if ((symbol->type != REGISTER)
+ && (symbol->type != SCBLOC)
+ && (symbol->type != SRAMLOC)) {
+ snprintf(buf, sizeof(buf),
+ "Specified symbol %s is not a register",
+ symbol->name);
+ stop(buf, EX_DATAERR);
+ }
+}
+
+static void
+format_1_instr(opcode, dest, immed, src, ret)
+ int opcode;
+ symbol_ref_t *dest;
+ expression_t *immed;
+ symbol_ref_t *src;
+ int ret;
+{
+ struct instruction *instr;
+ struct ins_format1 *f1_instr;
+
+ if (src->symbol == NULL)
+ src = dest;
+
+ /* Test register permissions */
+ test_writable_symbol(dest->symbol);
+ test_readable_symbol(src->symbol);
+
+ /* Ensure that immediate makes sense for this destination */
+ type_check(dest->symbol, immed, opcode);
+
+ /* 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->destination = dest->symbol->info.rinfo->address
+ + dest->offset;
+ f1_instr->source = src->symbol->info.rinfo->address
+ + src->offset;
+ f1_instr->immediate = immed->value;
+ symlist_free(&immed->referenced_syms);
+ instruction_ptr++;
+}
+
+static void
+format_2_instr(opcode, dest, places, src, ret)
+ int opcode;
+ symbol_ref_t *dest;
+ expression_t *places;
+ symbol_ref_t *src;
+ int ret;
+{
+ struct instruction *instr;
+ struct ins_format2 *f2_instr;
+ u_int8_t shift_control;
+
+ if (src->symbol == NULL)
+ src = dest;
+
+ /* Test register permissions */
+ test_writable_symbol(dest->symbol);
+ test_readable_symbol(src->symbol);
+
+ /* 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->destination = dest->symbol->info.rinfo->address
+ + dest->offset;
+ f2_instr->source = src->symbol->info.rinfo->address
+ + src->offset;
+ if (places->value > 8 || places->value <= 0) {
+ stop("illegal shift value", EX_DATAERR);
+ /* NOTREACHED */
+ }
+ switch (opcode) {
+ case AIC_OP_SHL:
+ if (places->value == 8)
+ shift_control = 0xf0;
+ else
+ shift_control = (places->value << 4) | places->value;
+ break;
+ case AIC_OP_SHR:
+ if (places->value == 8) {
+ shift_control = 0xf8;
+ } else {
+ shift_control = (places->value << 4)
+ | (8 - places->value)
+ | 0x08;
+ }
+ break;
+ case AIC_OP_ROL:
+ shift_control = places->value & 0x7;
+ break;
+ case AIC_OP_ROR:
+ shift_control = (8 - places->value) | 0x08;
+ break;
+ default:
+ shift_control = 0; /* Quiet Compiler */
+ stop("Invalid shift operation specified", EX_SOFTWARE);
+ /* NOTREACHED */
+ break;
+ };
+ f2_instr->shift_control = shift_control;
+ symlist_free(&places->referenced_syms);
+ instruction_ptr++;
+}
+
+static void
+format_3_instr(opcode, src, immed, address)
+ int opcode;
+ symbol_ref_t *src;
+ expression_t *immed;
+ symbol_ref_t *address;
+{
+ struct instruction *instr;
+ struct ins_format3 *f3_instr;
+ int addr;
+
+ /* Test register permissions */
+ test_readable_symbol(src->symbol);
+
+ /* Ensure that immediate makes sense for this source */
+ type_check(src->symbol, immed, opcode);
+
+ /* Allocate sequencer space for the instruction and fill it out */
+ instr = seq_alloc();
+ f3_instr = &instr->format.format3;
+ if (address->symbol == NULL) {
+ /* 'dot' referrence. Use the current instruction pointer */
+ addr = instruction_ptr + address->offset;
+ } else if (address->symbol->type == UNINITIALIZED) {
+ /* forward reference */
+ addr = address->offset;
+ 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->source = src->symbol->info.rinfo->address
+ + src->offset;
+ f3_instr->immediate = immed->value;
+ symlist_free(&immed->referenced_syms);
+ instruction_ptr++;
+}
+
+static void
+test_readable_symbol(symbol)
+ symbol_t *symbol;
+{
+ if (symbol->info.rinfo->mode == WO) {
+ stop("Write Only register specified as source",
+ EX_DATAERR);
+ /* NOTREACHED */
+ }
+}
+
+static void
+test_writable_symbol(symbol)
+ symbol_t *symbol;
+{
+ if (symbol->info.rinfo->mode == RO) {
+ stop("Read Only register specified as destination",
+ EX_DATAERR);
+ /* NOTREACHED */
+ }
+}
+
+static void
+type_check(symbol, expression, opcode)
+ symbol_t *symbol;
+ expression_t *expression;
+ int opcode;
+{
+ symbol_node_t *node;
+ int and_op;
+ char buf[255];
+
+ and_op = FALSE;
+ if (opcode == AIC_OP_AND || opcode == AIC_OP_JNZ || AIC_OP_JZ)
+ and_op = TRUE;
+ /*
+ * Make sure that we aren't attempting to write something
+ * that hasn't been defined. If this is an and operation,
+ * this is a mask, so "undefined" bits are okay.
+ */
+ if (and_op == FALSE
+ && (expression->value & ~symbol->info.rinfo->valid_bitmask) != 0) {
+ snprintf(buf, sizeof(buf),
+ "Invalid bit(s) 0x%x in immediate written to %s",
+ expression->value & ~symbol->info.rinfo->valid_bitmask,
+ symbol->name);
+ stop(buf, EX_DATAERR);
+ /* NOTREACHED */
+ }
+
+ /*
+ * Now make sure that all of the symbols referenced by the
+ * expression are defined for this register.
+ */
+ if(symbol->info.rinfo->typecheck_masks != FALSE) {
+ for(node = expression->referenced_syms.slh_first;
+ node != NULL;
+ node = node->links.sle_next) {
+ if ((node->symbol->type == MASK
+ || node->symbol->type == BIT)
+ && symlist_search(&node->symbol->info.minfo->symrefs,
+ symbol->name) == NULL) {
+ snprintf(buf, sizeof(buf),
+ "Invalid bit or mask %s "
+ "for register %s",
+ node->symbol->name, symbol->name);
+ stop(buf, EX_DATAERR);
+ /* NOTREACHED */
+ }
+ }
+ }
+}
+
+static void
+make_expression(immed, value)
+ expression_t *immed;
+ int value;
+{
+ SLIST_INIT(&immed->referenced_syms);
+ immed->value = value & 0xff;
+}
+
+static void
+add_conditional(symbol)
+ symbol_t *symbol;
+{
+ static int numoptions = 1;
+
+ 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",
+ EX_DATAERR);
+ /* NOTREACHED */
+ }
+ cur_patch->options |= symbol->info.condinfo->value;
+}
+
+void
+yyerror(string)
+ const char *string;
+{
+ stop(string, EX_DATAERR);
+}
diff --git a/sys/dev/aic7xxx/scan.l b/sys/dev/aic7xxx/scan.l
new file mode 100644
index 0000000000000..d77ceddf4c993
--- /dev/null
+++ b/sys/dev/aic7xxx/scan.l
@@ -0,0 +1,242 @@
+%{
+/*
+ * Lexical Analyzer for the Aic7xxx SCSI Host adapter sequencer assembler.
+ *
+ * Copyright (c) 1997 Justin T. Gibbs.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * this list of conditions, and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <sysexits.h>
+#include <sys/queue.h>
+
+#include "aic7xxx_asm.h"
+#include "symbol.h"
+#include "y.tab.h"
+%}
+
+PATH [-/A-Za-z0-9_.]*[./][-/A-Za-z0-9_.]*
+WORD [A-Za-z_][-A-Za-z_0-9]*
+SPACE [ \t]+
+
+%x COMMENT
+
+%%
+\n { ++yylineno; }
+"/*" { BEGIN COMMENT; /* Enter comment eating state */ }
+<COMMENT>"/*" { fprintf(stderr, "Warning! Comment within comment."); }
+<COMMENT>\n { ++yylineno; }
+<COMMENT>[^*/\n]* ;
+<COMMENT>"*"+[^*/\n]* ;
+<COMMENT>"/"+[^*/\n]* ;
+<COMMENT>"*"+"/" { BEGIN INITIAL; }
+
+{SPACE} ;
+
+ /* Register/SCB/SRAM definition keywords */
+register { return T_REGISTER; }
+const { yylval.value = FALSE; return T_CONST; }
+address { return T_ADDRESS; }
+access_mode { return T_ACCESS_MODE; }
+RW|RO|WO {
+ if (strcmp(yytext, "RW") == 0)
+ yylval.value = RW;
+ else if (strcmp(yytext, "RO") == 0)
+ yylval.value = RO;
+ else
+ yylval.value = WO;
+ return T_MODE;
+ }
+bit { return T_BIT; }
+mask { return T_MASK; }
+alias { return T_ALIAS; }
+size { return T_SIZE; }
+scb { return T_SCB; }
+scratch_ram { return T_SRAM; }
+accumulator { return T_ACCUM; }
+allones { return T_ALLONES; }
+allzeros { return T_ALLZEROS; }
+none { return T_NONE; }
+sindex { return T_SINDEX; }
+A { return T_A; }
+
+ /* Opcodes */
+shl { return T_SHL; }
+shr { return T_SHR; }
+ror { return T_ROR; }
+rol { return T_ROL; }
+mvi { return T_MVI; }
+mov { return T_MOV; }
+clr { return T_CLR; }
+jmp { return T_JMP; }
+jc { return T_JC; }
+jnc { return T_JNC; }
+je { return T_JE; }
+jne { return T_JNE; }
+jz { return T_JZ; }
+jnz { return T_JNZ; }
+call { return T_CALL; }
+add { return T_ADD; }
+adc { return T_ADC; }
+inc { return T_INC; }
+dec { return T_DEC; }
+stc { return T_STC; }
+clc { return T_CLC; }
+cmp { return T_CMP; }
+xor { return T_XOR; }
+test { return T_TEST;}
+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; }
+
+ /* Allowed Symbols */
+[-+,:()~|&."{};<>[\]!] { return yytext[0]; }
+
+ /* Number processing */
+0[0-7]* {
+ yylval.value = strtol(yytext, NULL, 8);
+ return T_NUMBER;
+ }
+
+0[xX][0-9a-fA-F]+ {
+ yylval.value = strtoul(yytext + 2, NULL, 16);
+ return T_NUMBER;
+ }
+
+[1-9][0-9]* {
+ yylval.value = strtol(yytext, NULL, 10);
+ return T_NUMBER;
+ }
+
+ /* Include Files */
+#include { return T_INCLUDE; }
+
+ /* For parsing C include files with #define foo */
+#define { yylval.value = TRUE; return T_CONST; }
+ /* Throw away macros */
+#define[^\n]*[()]+[^\n]* ;
+{PATH} { yylval.str = strdup(yytext); return T_PATH; }
+
+{WORD} { yylval.sym = symtable_get(yytext); return T_SYMBOL; }
+
+. {
+ char buf[255];
+
+ snprintf(buf, sizeof(buf), "Invalid character "
+ "'%c'", yytext[0]);
+ stop(buf, EX_DATAERR);
+ }
+%%
+
+typedef struct include {
+ YY_BUFFER_STATE buffer;
+ int lineno;
+ char *filename;
+ SLIST_ENTRY(include) links;
+}include_t;
+
+SLIST_HEAD(, include) include_stack;
+
+void
+include_file(file_name, type)
+ char *file_name;
+ include_type type;
+{
+ FILE *newfile;
+ include_t *include;
+
+ newfile = NULL;
+ /* Try the current directory first */
+ if (includes_search_curdir != 0 || type == SOURCE_FILE)
+ newfile = fopen(file_name, "r");
+
+ if (newfile == NULL && type != SOURCE_FILE) {
+ path_entry_t include_dir;
+ for (include_dir = search_path.slh_first;
+ include_dir != NULL;
+ include_dir = include_dir->links.sle_next) {
+ char fullname[PATH_MAX];
+
+ if ((include_dir->quoted_includes_only == TRUE)
+ && (type != QUOTED_INCLUDE))
+ continue;
+
+ snprintf(fullname, sizeof(fullname),
+ "%s/%s", include_dir->directory, file_name);
+
+ if ((newfile = fopen(fullname, "r")) != NULL)
+ break;
+ }
+ }
+
+ if (newfile == NULL) {
+ perror(file_name);
+ stop("Unable to open input file", EX_SOFTWARE);
+ /* NOTREACHED */
+ }
+ include = (include_t *)malloc(sizeof(include_t));
+ if (include == NULL) {
+ stop("Unable to allocate include stack entry", EX_SOFTWARE);
+ /* NOTREACHED */
+ }
+ include->buffer = YY_CURRENT_BUFFER;
+ include->lineno = yylineno;
+ include->filename = yyfilename;
+ SLIST_INSERT_HEAD(&include_stack, include, links);
+ yy_switch_to_buffer(yy_create_buffer(newfile, YY_BUF_SIZE));
+ yylineno = 1;
+ yyfilename = strdup(file_name);
+}
+
+int
+yywrap()
+{
+ include_t *include;
+
+ yy_delete_buffer(YY_CURRENT_BUFFER);
+ (void)fclose(yyin);
+ if (yyfilename != NULL)
+ free(yyfilename);
+ include = include_stack.slh_first;
+ if (include != NULL) {
+ yy_switch_to_buffer(include->buffer);
+ yylineno = include->lineno;
+ yyfilename = include->filename;
+ SLIST_REMOVE_HEAD(&include_stack, links);
+ free(include);
+ return (0);
+ }
+ return (1);
+}
diff --git a/sys/dev/aic7xxx/sequencer.h b/sys/dev/aic7xxx/sequencer.h
new file mode 100644
index 0000000000000..ed227158f5d19
--- /dev/null
+++ b/sys/dev/aic7xxx/sequencer.h
@@ -0,0 +1,89 @@
+/*
+ * Instruction formats for the sequencer program downloaded to
+ * Aic7xxx SCSI host adapters
+ *
+ * Copyright (c) 1997 Justin T. Gibbs.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * this list of conditions, and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+struct ins_format1 {
+ u_int8_t immediate;
+ u_int8_t source;
+ u_int8_t destination;
+ u_int8_t opcode_ret;
+};
+
+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
+};
+
+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
+};
+
+struct instruction {
+ union {
+ struct ins_format1 format1;
+ struct ins_format2 format2;
+ struct ins_format3 format3;
+ u_int8_t bytes[4];
+ } format;
+ u_int srcline;
+ struct symbol *patch_label;
+ STAILQ_ENTRY(instruction) links;
+};
+
+#define AIC_OP_OR 0x0
+#define AIC_OP_AND 0x1
+#define AIC_OP_XOR 0x2
+#define AIC_OP_ADD 0x3
+#define AIC_OP_ADC 0x4
+#define AIC_OP_ROL 0x5
+
+#define AIC_OP_JMP 0x8
+#define AIC_OP_JC 0x9
+#define AIC_OP_JNC 0xa
+#define AIC_OP_CALL 0xb
+#define AIC_OP_JNE 0xc
+#define AIC_OP_JNZ 0xd
+#define AIC_OP_JE 0xe
+#define AIC_OP_JZ 0xf
+
+/* Pseudo Ops */
+#define AIC_OP_SHL 0x10
+#define AIC_OP_SHR 0x20
+#define AIC_OP_ROR 0x30
diff --git a/sys/dev/aic7xxx/symbol.c b/sys/dev/aic7xxx/symbol.c
new file mode 100644
index 0000000000000..e2b93efbd2ee1
--- /dev/null
+++ b/sys/dev/aic7xxx/symbol.c
@@ -0,0 +1,451 @@
+/*
+ * Aic7xxx SCSI host adapter firmware asssembler symbol table implementation
+ *
+ * Copyright (c) 1997 Justin T. Gibbs.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * this list of conditions, and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+
+#include <sys/types.h>
+
+#include <db.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+
+#include "symbol.h"
+#include "aic7xxx_asm.h"
+
+static DB *symtable;
+
+symbol_t *
+symbol_create(name)
+ char *name;
+{
+ symbol_t *new_symbol;
+
+ new_symbol = (symbol_t *)malloc(sizeof(symbol_t));
+ if (new_symbol == NULL) {
+ perror("Unable to create new symbol");
+ exit(EX_SOFTWARE);
+ }
+ memset(new_symbol, 0, sizeof(*new_symbol));
+ new_symbol->name = strdup(name);
+ new_symbol->type = UNINITIALIZED;
+ return (new_symbol);
+}
+
+void
+symbol_delete(symbol)
+ symbol_t *symbol;
+{
+ if (symtable != NULL) {
+ DBT key;
+
+ key.data = symbol->name;
+ key.size = strlen(symbol->name);
+ symtable->del(symtable, &key, /*flags*/0);
+ }
+ switch(symbol->type) {
+ case SCBLOC:
+ case SRAMLOC:
+ case REGISTER:
+ if (symbol->info.rinfo != NULL)
+ free(symbol->info.rinfo);
+ break;
+ case ALIAS:
+ if (symbol->info.ainfo != NULL)
+ free(symbol->info.ainfo);
+ break;
+ case MASK:
+ case BIT:
+ if (symbol->info.minfo != NULL) {
+ symlist_free(&symbol->info.minfo->symrefs);
+ free(symbol->info.minfo);
+ }
+ break;
+ case CONST:
+ if (symbol->info.cinfo != NULL)
+ free(symbol->info.cinfo);
+ break;
+ case LABEL:
+ if (symbol->info.linfo != NULL)
+ free(symbol->info.linfo);
+ break;
+ case UNINITIALIZED:
+ default:
+ break;
+ }
+ free(symbol->name);
+ free(symbol);
+}
+
+void
+symtable_open()
+{
+ symtable = dbopen(/*filename*/NULL,
+ O_CREAT | O_NONBLOCK | O_RDWR, /*mode*/0, DB_HASH,
+ /*openinfo*/NULL);
+
+ if (symtable == NULL) {
+ perror("Symbol table creation failed");
+ exit(EX_SOFTWARE);
+ /* NOTREACHED */
+ }
+}
+
+void
+symtable_close()
+{
+ if (symtable != NULL) {
+ DBT key;
+ DBT data;
+
+ while (symtable->seq(symtable, &key, &data, R_FIRST) == 0) {
+ symbol_t *cursym;
+
+ cursym = *(symbol_t **)data.data;
+ symbol_delete(cursym);
+ }
+ symtable->close(symtable);
+ }
+}
+
+/*
+ * The semantics of get is to return an uninitialized symbol entry
+ * if a lookup fails.
+ */
+symbol_t *
+symtable_get(name)
+ char *name;
+{
+ DBT key;
+ DBT data;
+ int retval;
+
+ key.data = (void *)name;
+ key.size = strlen(name);
+
+ if ((retval = symtable->get(symtable, &key, &data, /*flags*/0)) != 0) {
+ if (retval == -1) {
+ perror("Symbol table get operation failed");
+ exit(EX_SOFTWARE);
+ /* NOTREACHED */
+ } else if (retval == 1) {
+ /* Symbol wasn't found, so create a new one */
+ symbol_t *new_symbol;
+
+ new_symbol = symbol_create(name);
+ data.data = &new_symbol;
+ data.size = sizeof(new_symbol);
+ if (symtable->put(symtable, &key, &data,
+ /*flags*/0) !=0) {
+ perror("Symtable put failed");
+ exit(EX_SOFTWARE);
+ }
+ return (new_symbol);
+ } else {
+ perror("Unexpected return value from db get routine");
+ exit(EX_SOFTWARE);
+ /* NOTREACHED */
+ }
+ }
+ return (*(symbol_t **)data.data);
+}
+
+symbol_node_t *
+symlist_search(symlist, symname)
+ symlist_t *symlist;
+ char *symname;
+{
+ symbol_node_t *curnode;
+
+ curnode = symlist->slh_first;
+ while(curnode != NULL) {
+ if (strcmp(symname, curnode->symbol->name) == 0)
+ break;
+ curnode = curnode->links.sle_next;
+ }
+ return (curnode);
+}
+
+void
+symlist_add(symlist, symbol, how)
+ symlist_t *symlist;
+ symbol_t *symbol;
+ int how;
+{
+ symbol_node_t *newnode;
+
+ newnode = (symbol_node_t *)malloc(sizeof(symbol_node_t));
+ if (newnode == NULL) {
+ stop("symlist_add: Unable to malloc symbol_node", EX_SOFTWARE);
+ /* NOTREACHED */
+ }
+ newnode->symbol = symbol;
+ if (how == SYMLIST_SORT) {
+ symbol_node_t *curnode;
+ int mask;
+
+ mask = FALSE;
+ switch(symbol->type) {
+ case REGISTER:
+ case SCBLOC:
+ case SRAMLOC:
+ break;
+ case BIT:
+ case MASK:
+ mask = TRUE;
+ break;
+ default:
+ stop("symlist_add: Invalid symbol type for sorting",
+ EX_SOFTWARE);
+ /* NOTREACHED */
+ }
+
+ curnode = symlist->slh_first;
+ if (curnode == NULL
+ || (mask && (curnode->symbol->info.minfo->mask >
+ newnode->symbol->info.minfo->mask))
+ || (!mask && (curnode->symbol->info.rinfo->address >
+ newnode->symbol->info.rinfo->address))) {
+ SLIST_INSERT_HEAD(symlist, newnode, links);
+ return;
+ }
+
+ while (1) {
+ if (curnode->links.sle_next == NULL) {
+ SLIST_INSERT_AFTER(curnode, newnode,
+ links);
+ break;
+ } else {
+ symbol_t *cursymbol;
+
+ cursymbol = curnode->links.sle_next->symbol;
+ if ((mask && (cursymbol->info.minfo->mask >
+ symbol->info.minfo->mask))
+ || (!mask &&(cursymbol->info.rinfo->address >
+ symbol->info.rinfo->address))){
+ SLIST_INSERT_AFTER(curnode, newnode,
+ links);
+ break;
+ }
+ }
+ curnode = curnode->links.sle_next;
+ }
+ } else {
+ SLIST_INSERT_HEAD(symlist, newnode, links);
+ }
+}
+
+void
+symlist_free(symlist)
+ symlist_t *symlist;
+{
+ symbol_node_t *node1, *node2;
+
+ node1 = symlist->slh_first;
+ while (node1 != NULL) {
+ node2 = node1->links.sle_next;
+ free(node1);
+ node1 = node2;
+ }
+ SLIST_INIT(symlist);
+}
+
+void
+symlist_merge(symlist_dest, symlist_src1, symlist_src2)
+ symlist_t *symlist_dest;
+ symlist_t *symlist_src1;
+ symlist_t *symlist_src2;
+{
+ symbol_node_t *node;
+
+ *symlist_dest = *symlist_src1;
+ while((node = symlist_src2->slh_first) != NULL) {
+ SLIST_REMOVE_HEAD(symlist_src2, links);
+ SLIST_INSERT_HEAD(symlist_dest, node, links);
+ }
+
+ /* These are now empty */
+ SLIST_INIT(symlist_src1);
+ SLIST_INIT(symlist_src2);
+}
+
+void
+symtable_dump(ofile)
+ FILE *ofile;
+{
+ /*
+ * Sort the registers by address with a simple insertion sort.
+ * Put bitmasks next to the first register that defines them.
+ * Put constants at the end.
+ */
+ symlist_t registers;
+ symlist_t masks;
+ symlist_t constants;
+ symlist_t aliases;
+
+ SLIST_INIT(&registers);
+ SLIST_INIT(&masks);
+ SLIST_INIT(&constants);
+ SLIST_INIT(&aliases);
+
+ if (symtable != NULL) {
+ DBT key;
+ DBT data;
+ int flag = R_FIRST;
+
+ while (symtable->seq(symtable, &key, &data, flag) == 0) {
+ symbol_t *cursym;
+
+ cursym = *(symbol_t **)data.data;
+ switch(cursym->type) {
+ case REGISTER:
+ case SCBLOC:
+ case SRAMLOC:
+ symlist_add(&registers, cursym, SYMLIST_SORT);
+ break;
+ case MASK:
+ case BIT:
+ symlist_add(&masks, cursym, SYMLIST_SORT);
+ break;
+ case CONST:
+ if (cursym->info.cinfo->define == FALSE) {
+ symlist_add(&constants, cursym,
+ SYMLIST_INSERT_HEAD);
+ }
+ break;
+ case ALIAS:
+ symlist_add(&aliases, cursym,
+ SYMLIST_INSERT_HEAD);
+ default:
+ break;
+ }
+ flag = R_NEXT;
+ }
+
+ /* Put in the masks and bits */
+ while (masks.slh_first != NULL) {
+ symbol_node_t *curnode;
+ symbol_node_t *regnode;
+ char *regname;
+
+ curnode = masks.slh_first;
+ SLIST_REMOVE_HEAD(&masks, links);
+
+ regnode =
+ curnode->symbol->info.minfo->symrefs.slh_first;
+ regname = regnode->symbol->name;
+ regnode = symlist_search(&registers, regname);
+ SLIST_INSERT_AFTER(regnode, curnode, links);
+ }
+
+ /* Add the aliases */
+ while (aliases.slh_first != NULL) {
+ symbol_node_t *curnode;
+ symbol_node_t *regnode;
+ char *regname;
+
+ curnode = aliases.slh_first;
+ SLIST_REMOVE_HEAD(&aliases, links);
+
+ regname = curnode->symbol->info.ainfo->parent->name;
+ regnode = symlist_search(&registers, regname);
+ SLIST_INSERT_AFTER(regnode, curnode, links);
+ }
+
+ /* Output what we have */
+ fprintf(ofile,
+"/*
+ * DO NOT EDIT - This file is automatically generated.
+ */\n");
+ while (registers.slh_first != NULL) {
+ symbol_node_t *curnode;
+ u_int8_t value;
+ char *tab_str;
+ char *tab_str2;
+
+ curnode = registers.slh_first;
+ SLIST_REMOVE_HEAD(&registers, links);
+ switch(curnode->symbol->type) {
+ case REGISTER:
+ case SCBLOC:
+ case SRAMLOC:
+ fprintf(ofile, "\n");
+ value = curnode->symbol->info.rinfo->address;
+ tab_str = "\t";
+ tab_str2 = "\t\t";
+ break;
+ case ALIAS:
+ {
+ symbol_t *parent;
+
+ parent = curnode->symbol->info.ainfo->parent;
+ value = parent->info.rinfo->address;
+ tab_str = "\t";
+ tab_str2 = "\t\t";
+ break;
+ }
+ case MASK:
+ case BIT:
+ value = curnode->symbol->info.minfo->mask;
+ tab_str = "\t\t";
+ tab_str2 = "\t";
+ break;
+ default:
+ value = 0; /* Quiet compiler */
+ tab_str = NULL;
+ tab_str2 = NULL;
+ stop("symtable_dump: Invalid symbol type "
+ "encountered", EX_SOFTWARE);
+ break;
+ }
+ fprintf(ofile, "#define%s%-16s%s0x%02x\n",
+ tab_str, curnode->symbol->name, tab_str2,
+ value);
+ free(curnode);
+ }
+ fprintf(ofile, "\n\n");
+
+ while (constants.slh_first != NULL) {
+ symbol_node_t *curnode;
+
+ curnode = constants.slh_first;
+ SLIST_REMOVE_HEAD(&constants, links);
+ fprintf(ofile, "#define\t%-8s\t0x%02x\n",
+ curnode->symbol->name,
+ curnode->symbol->info.cinfo->value);
+ free(curnode);
+ }
+ }
+}
+
diff --git a/sys/dev/aic7xxx/symbol.h b/sys/dev/aic7xxx/symbol.h
new file mode 100644
index 0000000000000..cf8fa0071225a
--- /dev/null
+++ b/sys/dev/aic7xxx/symbol.h
@@ -0,0 +1,144 @@
+/*
+ * Aic7xxx SCSI host adapter firmware asssembler symbol table definitions
+ *
+ * Copyright (c) 1997 Justin T. Gibbs.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * this list of conditions, and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#include <sys/queue.h>
+
+typedef enum {
+ UNINITIALIZED,
+ REGISTER,
+ ALIAS,
+ SCBLOC,
+ SRAMLOC,
+ MASK,
+ BIT,
+ CONST,
+ LABEL,
+ CONDITIONAL
+}symtype;
+
+typedef enum {
+ RO = 0x01,
+ WO = 0x02,
+ RW = 0x03
+}amode_t;
+
+struct reg_info {
+ u_int8_t address;
+ int size;
+ amode_t mode;
+ u_int8_t valid_bitmask;
+ int typecheck_masks;
+};
+
+typedef SLIST_HEAD(symlist, symbol_node) symlist_t;
+
+struct mask_info {
+ symlist_t symrefs;
+ u_int8_t mask;
+};
+
+struct const_info {
+ u_int8_t value;
+ int define;
+};
+
+struct alias_info {
+ struct symbol *parent;
+};
+
+struct label_info {
+ int address;
+};
+
+struct cond_info {
+ int value;
+};
+
+typedef struct expression_info {
+ symlist_t referenced_syms;
+ int value;
+} expression_t;
+
+typedef struct symbol {
+ char *name;
+ symtype type;
+ union {
+ struct reg_info *rinfo;
+ struct mask_info *minfo;
+ struct const_info *cinfo;
+ struct alias_info *ainfo;
+ struct label_info *linfo;
+ struct cond_info *condinfo;
+ }info;
+} symbol_t;
+
+typedef struct symbol_ref {
+ symbol_t *symbol;
+ int offset;
+} symbol_ref_t;
+
+typedef struct symbol_node {
+ SLIST_ENTRY(symbol_node) links;
+ symbol_t *symbol;
+}symbol_node_t;
+
+typedef struct patch {
+ STAILQ_ENTRY(patch) links;
+ int negative;
+ int begin;
+ int end;
+ int options;
+} patch_t;
+
+void symbol_delete __P((symbol_t *symbol));
+
+void symtable_open __P((void));
+
+void symtable_close __P((void));
+
+symbol_t *
+ symtable_get __P((char *name));
+
+symbol_node_t *
+ symlist_search __P((symlist_t *symlist, char *symname));
+
+void
+ symlist_add __P((symlist_t *symlist, symbol_t *symbol, int how));
+#define SYMLIST_INSERT_HEAD 0x00
+#define SYMLIST_SORT 0x01
+
+void symlist_free __P((symlist_t *symlist));
+
+void symlist_merge __P((symlist_t *symlist_dest, symlist_t *symlist_src1,
+ symlist_t *symlist_src2));
+void symtable_dump __P((FILE *ofile));