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