summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcvs2svn <cvs2svn@FreeBSD.org>1997-03-16 07:21:33 +0000
committercvs2svn <cvs2svn@FreeBSD.org>1997-03-16 07:21:33 +0000
commit274b8bdee754bb048d0267ee40ac9b784862ef31 (patch)
tree12b7be06e20d85a9bcd2e7c43eaa6857653a79b0
parentbd168eeaadcfee496a59b227380fa527f10183df (diff)
Notes
-rw-r--r--contrib/texinfo/info/info.1232
-rwxr-xr-xrelease/scripts/ports-install.sh8
-rw-r--r--sys/dev/aic7xxx/Makefile18
-rw-r--r--sys/dev/aic7xxx/aic7xxx.reg1112
-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
-rw-r--r--sys/i386/isa/wdc_p.h24
-rw-r--r--sys/pci/wdc_p.c79
15 files changed, 5844 insertions, 0 deletions
diff --git a/contrib/texinfo/info/info.1 b/contrib/texinfo/info/info.1
new file mode 100644
index 000000000000..c80058649465
--- /dev/null
+++ b/contrib/texinfo/info/info.1
@@ -0,0 +1,232 @@
+.\" $Id$
+.\"
+.TH info 1 "7th December 1990"
+.SH NAME
+info \- GNU's hypertext system
+.SH SYNOPSIS
+.B info
+[
+.B \-\-option-name option-value
+]
+.B \menu-item...
+.SH COPYRIGHT
+.if n Copyright (C) 1989, 1993 Free Software Foundation, Inc.
+.if t Copyright \(co 1989, 1993 Free Software Foundation, Inc.
+.SH DESCRIPTION
+.LP
+The GNU project has a hypertext system called
+.I Info
+which allows the same source file to be either printed as a
+paper manual, or viewed using
+.B info.
+It is possible to use the
+.B info
+program from inside Emacs, or to use the stand-alone version described here.
+This manual page gives a brief summary of its capabilities.
+
+.SH OPTIONS
+.TP
+.B \-\-directory directory-path
+Add
+.B directory-path
+to the list of directory paths searched when
+.B info
+needs to find a file. You may issue
+.B \-\-directory
+multiple times.
+Alternatively, you may specify a value for the environment variable
+.B INFOPATH;
+if
+.B \-\-directory
+is not given, the value of
+.B INFOPATH
+is used. The value of
+.B INFOPATH
+is a colon separated list of directory names. If you do not supply either
+.B INFOPATH
+or
+.B \-\-directory-path,
+.B info
+uses a default path.
+.TP
+.B \-f filename
+Specify a particular
+.B info
+file to visit. By default,
+.B info
+visits
+the file
+.B dir;
+if you use this option,
+.B info
+will start with
+.B (FILENAME)Top
+as the first file and node.
+.TP
+.B \-n nodename
+Specify a particular node to visit in the initial file that
+.B info
+loads. This is especially useful in conjunction with
+.B \-\-file.
+You may specify
+.B \-\-node
+multiple times.
+.TP
+.B -o file
+Direct output to
+.B file
+instead of starting an interactive
+.B info
+session.
+.TP
+.B \-h
+Produce a relatively brief description of the available
+.B info
+options.
+.TP
+.B \-\-version
+Print the version information of
+.B info
+and exit.
+.TP
+.B menu-item
+.B info
+treats its remaining arguments as the names of menu items.
+The first argument is a menu item in the initial node visited,
+while the second argument is a menu item in the first argument's
+node. You can easily move to the node of your choice by
+specifying the menu names which describe the path to that node.
+For example,
+
+.B info emacs buffers
+
+first selects the menu item
+.B emacs
+in the node
+.B (dir)Top,
+and then selects the menu item
+.B buffers
+in the node
+.B (emacs)Top.
+.SH COMMANDS
+When in
+.B info
+the following commands are available:
+.TP
+.B h
+Invoke the Info tutorial.
+.TP
+.B ?
+Get a short summary of
+.B info
+commands.
+.TP
+.B h
+Select the
+.B info
+node from the main directory; this is much more complete than just
+using
+.B ?.
+.TP
+.B Ctrl-g
+Abort whatever you are doing.
+.TP
+.B Ctrl-l
+Redraw the screen.
+.PP
+Selecting other nodes:
+.TP
+.B n
+Move to the "next" node of this node.
+.TP
+.B p
+Move to the "previous" node of this node.
+.TP
+.B u
+Move to this node's "up" node.
+.TP
+.B m
+Pick a menu item specified by name. Picking a menu item causes another
+node to be selected. You do not need to type a complete nodename; if
+you type a few letters and then a space or tab
+.B info
+will try to fill in the rest of the nodename. If you ask for further
+completion without typing any more characters you'll be given a list
+of possibilities; you can also get the list with
+.B ?.
+If you type a few characters and then hit return
+.B info
+will try to do a completion, and if it is ambigous use the first possibility.
+.TP
+.B f
+Follow a cross reference. You are asked for the name of the reference,
+using command completion as for
+.B m.
+.TP
+.B l
+Move to the last node you were at.
+.PP
+Moving within a node:
+.TP
+.B Space
+Scroll forward a page.
+.TP
+.B DEL
+Scroll backward a page.
+.TP
+.B b
+Go to the beginning of this node.
+.PP
+Advanced commands:
+.TP
+.B q
+Quit
+.B info.
+.TP
+.B 1
+Pick first item in node's menu.
+.TP
+.B 2 \-\- 5
+Pick second ... fifth item in node's menu.
+.TP
+.B g
+Move to node specified by name. You may include a filename as well,
+as
+.B (FILENAME)NODENAME.
+.TP
+.B s
+Search through this
+.B info
+file for a specified string, and select the node in which
+the next occurrence is found.
+.TP
+.B M-x print-node
+Pipe the contents of the current node through the command in the
+environment variable
+.B INFO_PRINT_COMMAND.
+If the variable does not exist, the node is simply piped to
+.B lpr.
+.SH ENVIRONMENT
+.TP
+.B INFOPATH
+A colon-separated list of directories to search for
+.B info
+files. Used if
+.B \-\-directory
+is not given.
+.TP
+.B INFO_PRINT_COMMAND
+The command used for printing.
+.SH SEE ALSO
+.BR man (1)
+.\" .BR emacs (1)
+.SH AUTHOR
+.RS
+Brian Fox, Free Software Foundation
+.br
+bfox@ai.mit.edu
+.SH MANUAL AUTHOR
+.RS
+Robert Lupton; updated by Robert J. Chassell.
+.br
+rhl@astro.princeton.edu; bob@gnu.ai.mit.edu
diff --git a/release/scripts/ports-install.sh b/release/scripts/ports-install.sh
new file mode 100755
index 000000000000..22d2246ba214
--- /dev/null
+++ b/release/scripts/ports-install.sh
@@ -0,0 +1,8 @@
+#!/bin/sh
+#
+if [ "`id -u`" != "0" ]; then
+ echo "Sorry, this must be done as root."
+ exit 1
+fi
+cat ports.tgz | tar --unlink -xpzf - -C /usr
+exit 0
diff --git a/sys/dev/aic7xxx/Makefile b/sys/dev/aic7xxx/Makefile
new file mode 100644
index 000000000000..2a142b0a5885
--- /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 000000000000..d021d9a6f63d
--- /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/aicasm_gram.y b/sys/dev/aic7xxx/aicasm_gram.y
new file mode 100644
index 000000000000..0c75edca3b3e
--- /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 000000000000..d77ceddf4c99
--- /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 000000000000..e2b93efbd2ee
--- /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 000000000000..cf8fa0071225
--- /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 000000000000..0c75edca3b3e
--- /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 000000000000..d77ceddf4c99
--- /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 000000000000..ed227158f5d1
--- /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 000000000000..e2b93efbd2ee
--- /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 000000000000..cf8fa0071225
--- /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));
diff --git a/sys/i386/isa/wdc_p.h b/sys/i386/isa/wdc_p.h
new file mode 100644
index 000000000000..4ef4b5629549
--- /dev/null
+++ b/sys/i386/isa/wdc_p.h
@@ -0,0 +1,24 @@
+/*
+ *
+ * Copyright (c) 1996 Wolfgang Helbig <helbig@ba-stuttgart.de>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * this list of conditions, and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Absolutely no warranty of function or purpose is made by the author.
+ * 4. Modifications may be freely made to this file if the above conditions
+ * are met.
+ *
+ * $Id$
+ */
+
+#define Q_CMD640B 0x00000001 /* CMD640B quirk: serialize IDE channels */
+
+void wdc_pci(int quirks);
diff --git a/sys/pci/wdc_p.c b/sys/pci/wdc_p.c
new file mode 100644
index 000000000000..7f2cd707703c
--- /dev/null
+++ b/sys/pci/wdc_p.c
@@ -0,0 +1,79 @@
+/*
+ *
+ * Copyright (c) 1996 Wolfgang Helbig <helbig@ba-stuttgart.de>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * this list of conditions, and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Absolutely no warranty of function or purpose is made by the author.
+ * 4. Modifications may be freely made to this file if the above conditions
+ * are met.
+ *
+ * $Id$
+ */
+
+/*
+ * The sole purpose of this code currently is to tell the ISA wdc driver,
+ * whether there is a CMD640 IDE chip attached to the PCI bus.
+ */
+
+#include "pci.h"
+#if NPCI > 0
+#ifdef CMD640
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <pci/pcireg.h>
+#include <pci/pcivar.h>
+#include <i386/isa/wdc_p.h>
+
+#include "wdc.h"
+
+/*
+ * PCI-ID's of IDE-Controller
+ */
+
+#define CMD640B_PCI_ID 0x06401095
+
+static char* wdc_pci_probe __P((pcici_t tag, pcidi_t type));
+static void wdc_pci_attach __P((pcici_t config_id, int unit));
+
+static u_long wdc_pci_count = 0;
+
+static struct pci_device wdc_pci_driver = {
+ "wdc",
+ wdc_pci_probe,
+ wdc_pci_attach,
+ &wdc_pci_count,
+ NULL
+};
+
+DATA_SET (pcidevice_set, wdc_pci_driver);
+
+static char*
+wdc_pci_probe (pcici_t tag, pcidi_t type)
+{
+ if (type == CMD640B_PCI_ID)
+ return "CMD 640B IDE";
+
+ return NULL;
+}
+
+static void
+wdc_pci_attach(pcici_t config_id, int unit)
+{
+ if (pci_conf_read(config_id, PCI_ID_REG) == CMD640B_PCI_ID)
+ wdc_pci(Q_CMD640B);
+}
+
+#endif /* CMD640 */
+#endif /* NPCI > 0 */