diff -u --recursive --new-file v1.3.93/linux/CREDITS linux/CREDITS --- v1.3.93/linux/CREDITS Fri Apr 19 10:07:57 1996 +++ linux/CREDITS Mon Apr 22 07:14:01 1996 @@ -1365,3 +1365,10 @@ S: 3078 Sulphur Spring Court S: San Jose, California 95148 S: USA + +N: Dmitry S. Gorodchanin +E: begemot@bgm.rosprint.net +D: RISCom/8 driver, misc kernel fixes. +S: 6/1 M.Koneva bl, apt #125 +S: Poltava 314023 +S: Ukraine diff -u --recursive --new-file v1.3.93/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v1.3.93/linux/Documentation/Configure.help Sun Apr 21 19:21:58 1996 +++ linux/Documentation/Configure.help Mon Apr 22 07:14:01 1996 @@ -2803,6 +2803,15 @@ order to become a BBS. If you have a card like that, say Y here and read the file Documentation/digiboard.txt. +SDL RISCom/8 card support +CONFIG_RISCOM8 + This is a driver for the SDL Communications RISCom/8 multiport card, + that give you many serial ports. You would need something like this + to connect more than two modems to your linux box, for instance in + order to become a BBS. If you have a card like that, say Y here and + read the file Documentation/riscom8.txt. Also it's possible to say + M here and compile this driver as kernel loadable module. + Cyclades async mux support CONFIG_CYCLADES This is a driver for a card that gives you many serial ports. You diff -u --recursive --new-file v1.3.93/linux/Documentation/riscom8.txt linux/Documentation/riscom8.txt --- v1.3.93/linux/Documentation/riscom8.txt Thu Jan 1 02:00:00 1970 +++ linux/Documentation/riscom8.txt Mon Apr 22 07:14:01 1996 @@ -0,0 +1,56 @@ + This is the README for RISCom/8 multi-port serial driver + (C) 1994-1996 D.Gorodchanin (begemot@bgm.rosrpint.net) + See file LICENSE for terms and conditions. + +NOTE: English is not my native language. + I'm sorry for any mistakes in this text. + +Misc. notes for RISCom/8 serial driver, in no particule order :) + +1) This driver can support up to 4 boards at time. + Use string "riscom8=0xXXX,0xXXX,0xXXX,0xXXX" at LILO prompt, for + setting I/O base addresses for boards. If you compile driver + as module use insmod options "iobase=0xXXX iobase1=0xXXX iobase2=..." + +2) The driver partially supports famous 'setserial' program, you can use almost + any it option, exclude port & irq settings. + +3) There are some misc. defines at the beginning of riscom8.c, please read the + comments and try to change some of them in case of problems. + +4) I consider the current state of the driver as BETA. + If you REALLY think you found the bug, send me e-mail, I hope I'll + fix it. For any other problems please ask support@sdlcomm.com. + +5) SDL Communications WWW page is http://www.sdlcomm.com. + +6) You can use the script at the end of this file to create RISCom/8 devices. + +7) Minors number for 1-st board are 0-7, for second 8-15, etc. + +22 Apr 1996. + +-------------------------------cut here------------------------------------- +#!/bin/bash +NORMAL_DEVICE=/dev/ttyL +CALLOUT_DEVICE=/dev/cuL +NORMAL_MAJOR=48 +CALLOUT_MAJOR=49 + +echo "Creating devices... " +for i in 0 1 2 3; do + echo "Board No $[$i+1]" + for j in 0 1 2 3 4 5 6 7; do + k=$[ 8 * $i + $j] + rm -f $NORMAL_DEVICE$k + mknod $NORMAL_DEVICE$k c $NORMAL_MAJOR $k + chmod a+rw $NORMAL_DEVICE$k + echo -n $NORMAL_DEVICE$k" " + rm -f $CALLOUT_DEVICE$k + mknod $CALLOUT_DEVICE$k c $CALLOUT_MAJOR $k + chmod a+rw $CALLOUT_DEVICE$k + echo $CALLOUT_DEVICE$k + done +done +echo "done." +-------------------------------cut here------------------------------------- diff -u --recursive --new-file v1.3.93/linux/MAGIC linux/MAGIC --- v1.3.93/linux/MAGIC Fri Mar 22 12:58:41 1996 +++ linux/MAGIC Mon Apr 22 07:14:01 1996 @@ -61,6 +61,7 @@ SERIAL_MAGIC 0x5301 struct async_struct include/linux/serial.h SLIP_MAGIC 0x5302 struct slip drivers/net/slip.h SCC_MAGIC 0x8530 struct scc_channel include/linux/scc.h +RISCOM8_MAGIC 0x0907 struct riscom_port drivers/char/riscom8.h diff -u --recursive --new-file v1.3.93/linux/MAINTAINERS linux/MAINTAINERS --- v1.3.93/linux/MAINTAINERS Sun Apr 21 19:21:59 1996 +++ linux/MAINTAINERS Mon Apr 22 11:44:26 1996 @@ -159,7 +159,7 @@ FTAPE/QIC-117: P: Kai Harrekilde-Petersen -M: khp@@dolphinics.no +M: khp@dolphinics.no L: linux-tape@vger.rutgers.edu S: Maintained @@ -260,6 +260,13 @@ M: clameter@fuller.edu L: digiboard@list.fuller.edu S: Maintained + +RISCOM8 DRIVER: +P: Dmitry Gorodchanin +M: begemot@bgm.rosprint.net +L: linux-kernel@vger.rutgers.edu +S: Maintained + MOUSE AND MISC DEVICES [GENERAL] P: Alessandro Rubini diff -u --recursive --new-file v1.3.93/linux/Makefile linux/Makefile --- v1.3.93/linux/Makefile Sun Apr 21 19:21:59 1996 +++ linux/Makefile Mon Apr 22 11:03:24 1996 @@ -1,6 +1,6 @@ VERSION = 1 PATCHLEVEL = 3 -SUBLEVEL = 93 +SUBLEVEL = 94 ARCH = i386 diff -u --recursive --new-file v1.3.93/linux/arch/alpha/defconfig linux/arch/alpha/defconfig --- v1.3.93/linux/arch/alpha/defconfig Sun Apr 21 12:39:00 1996 +++ linux/arch/alpha/defconfig Mon Apr 22 13:44:45 1996 @@ -96,7 +96,6 @@ # # CONFIG_SCSI_MULTI_LUN is not set CONFIG_SCSI_CONSTANTS=y -# CONFIG_SCSI_AUTO_BIOSP is not set # # SCSI low-level drivers @@ -151,6 +150,7 @@ # CONFIG_APRICOT is not set CONFIG_DE4X5=y # CONFIG_DEC_ELCP is not set +# CONFIG_DGRS is not set # CONFIG_ZNET is not set # CONFIG_NET_POCKET is not set # CONFIG_TR is not set @@ -180,6 +180,7 @@ CONFIG_ISO9660_FS=y # CONFIG_HPFS_FS is not set # CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set # # Character devices @@ -188,6 +189,7 @@ # CONFIG_DIGI is not set # CONFIG_CYCLADES is not set # CONFIG_STALDRV is not set +# CONFIG_RISCOM8 is not set # CONFIG_PRINTER is not set # CONFIG_BUSMOUSE is not set CONFIG_PSMOUSE=y diff -u --recursive --new-file v1.3.93/linux/arch/i386/defconfig linux/arch/i386/defconfig --- v1.3.93/linux/arch/i386/defconfig Mon Apr 15 12:20:17 1996 +++ linux/arch/i386/defconfig Mon Apr 22 12:12:57 1996 @@ -138,6 +138,7 @@ CONFIG_ISO9660_FS=y # CONFIG_HPFS_FS is not set # CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set # # Character devices @@ -146,6 +147,7 @@ # CONFIG_DIGI is not set # CONFIG_CYCLADES is not set # CONFIG_STALDRV is not set +# CONFIG_RISCOM8 is not set # CONFIG_PRINTER is not set # CONFIG_BUSMOUSE is not set # CONFIG_PSMOUSE is not set diff -u --recursive --new-file v1.3.93/linux/arch/m68k/Makefile linux/arch/m68k/Makefile --- v1.3.93/linux/arch/m68k/Makefile Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/Makefile Sat Mar 23 16:41:07 1996 @@ -0,0 +1,106 @@ +# +# m68k/Makefile +# +# This file is included by the global makefile so that you can add your own +# architecture-specific flags and dependencies. Remember to do have actions +# for "archclean" and "archdep" for cleaning up and making dependencies for +# this architecture +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# +# Copyright (C) 1994 by Hamish Macdonald +# + +# override top level makefile +ifdef CONFIG_KERNEL_ELF +AS = as -m68020 +LD = ld -m m68kelf +CC := $(CC) +# set up for cross compiling +COMPILE_ARCH = $(shell uname -m) +ifneq ($(COMPILE_ARCH),$(ARCH)) + CROSSDIR=/usr/$(ARCH)-linux + CC := $(CROSSDIR)/$(CC) + AS := $(CROSSDIR)/$(AS) + LD := $(CROSSDIR)/$(LD) + AR := $(CROSSDIR)/$(AR) + NM := $(CROSSDIR)/$(NM) + STRIP := $(CROSSDIR)/$(STRIP) +endif +else +AS = /usr/m68k-linuxaout/bin/as -m68020 +CC := $(CC) -pipe -b m68k-linuxaout +LD = ld -m m68klinux +endif + +# +# Set these to indicate how to link it.. +# +# -zmagic: +# +# LINKFLAGS = -Ttext 0x100000 +# +# -qmagic (we need to remove the 32 byte header for bootup purposes) +# + +ifdef CONFIG_KERNEL_ELF +LINKFLAGS = -Ttext 0x1000 +else +LINKFLAGS = -qmagic -Ttext 0xFE0 +endif +CFLAGS := $(CFLAGS) -pipe + +HEAD := arch/m68k/kernel/head.o + +SUBDIRS += arch/m68k/kernel arch/m68k/mm arch/m68k/console arch/m68k/lib +#SUBDIRS += arch/m68k/kernel arch/m68k/mm arch/m68k/lib +ARCHIVES := arch/m68k/kernel/kernel.o arch/m68k/mm/mm.o $(ARCHIVES) +LIBS += arch/m68k/lib/lib.a + +ifdef CONFIG_AMIGA +ARCHIVES := $(ARCHIVES) arch/m68k/amiga/amiga.o +SUBDIRS := $(SUBDIRS) arch/m68k/amiga +endif + +ifdef CONFIG_ATARI +ARCHIVES := $(ARCHIVES) arch/m68k/atari/atari.o +SUBDIRS := $(SUBDIRS) arch/m68k/atari +endif + +ifdef CONFIG_MAC +ARCHIVES := $(ARCHIVES) arch/m68k/mac/mac.o +SUBDIRS := $(SUBDIRS) arch/m68k/mac +endif + +# add in console.a after {amiga,atari}.o that need it +ARCHIVES := $(ARCHIVES) arch/m68k/console/console.a + +ifdef CONFIG_FPSP_040 +ARCHIVES := $(ARCHIVES) arch/m68k/fpsp040/fpsp.o +SUBDIRS := $(SUBDIRS) arch/m68k/fpsp040 +endif + +ifdef CONFIG_IFPSP_060 +ARCHIVES := $(ARCHIVES) arch/m68k/ifpsp060/ifpsp.o +SUBDIRS := $(SUBDIRS) arch/m68k/ifpsp060 +endif + +MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot + +lilo: vmlinux + if [ -f $(INSTALL_PATH)/vmlinux ]; then mv -f $(INSTALL_PATH)/vmlinux $(INSTALL_PATH)/vmlinux.old; fi + if [ -f $(INSTALL_PATH)/System.map ]; then mv -f $(INSTALL_PATH)/System.map $(INSTALL_PATH)/System.old; fi + cat vmlinux > $(INSTALL_PATH)/vmlinux + cp System.map $(INSTALL_PATH)/System.map + if [ -x /sbin/lilo ]; then /sbin/lilo; else /etc/lilo/install; fi + +bootstrap: + @$(MAKEBOOT) bootstrap + +archclean: + @$(MAKEBOOT) clean + +archdep: + $(MAKEBOOT) dep diff -u --recursive --new-file v1.3.93/linux/arch/m68k/Makefile_elf linux/arch/m68k/Makefile_elf --- v1.3.93/linux/arch/m68k/Makefile_elf Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/Makefile_elf Wed Dec 27 22:51:18 1995 @@ -0,0 +1,91 @@ +# +# m68k/Makefile +# +# This file is included by the global makefile so that you can add your own +# architecture-specific flags and dependencies. Remember to do have actions +# for "archclean" and "archdep" for cleaning up and making dependencies for +# this architecture +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# +# Copyright (C) 1994 by Hamish Macdonald +# + +# override top level makefile +AS = as -m68020 +#CC := $(CC) -b m68kelf +LD = ld -m m68kelf + + +# +# Set these to indicate how to link it.. +# +# -zmagic: +# +# LINKFLAGS = -Ttext 0x100000 +# +# -qmagic (we need to remove the 32 byte header for bootup purposes) +# + +LINKFLAGS = -qmagic -Ttext 0xFE0 + +HEAD := arch/m68k/kernel/head.o + +SUBDIRS := $(SUBDIRS) arch/m68k/kernel arch/m68k/mm arch/m68k/lib +ARCHIVES := arch/m68k/kernel/kernel.o arch/m68k/mm/mm.o $(ARCHIVES) +LIBS := $(TOPDIR)/arch/m68k/lib/lib.a $(LIBS) $(TOPDIR)/arch/m68k/lib/lib.a + +ifdef CONFIG_AMIGA +ARCHIVES := $(ARCHIVES) arch/m68k/amiga/amiga.o +SUBDIRS := $(SUBDIRS) arch/m68k/amiga +endif + +ifdef CONFIG_ATARI +ARCHIVES := $(ARCHIVES) arch/m68k/atari/atari.o +SUBDIRS := $(SUBDIRS) arch/m68k/atari +endif + +ifdef CONFIG_MAC +ARCHIVES := $(ARCHIVES) arch/m68k/mac/mac.o +SUBDIRS := $(SUBDIRS) arch/m68k/mac +endif + +ifdef CONFIG_FPSP_040 +ARCHIVES := $(ARCHIVES) arch/m68k/fpsp040/fpsp.o +SUBDIRS := $(SUBDIRS) arch/m68k/fpsp040 +endif + +arch/m68k/kernel: dummy + $(MAKE) linuxsubdirs SUBDIRS=arch/m68k/kernel + +arch/m68k/mm: dummy + $(MAKE) linuxsubdirs SUBDIRS=arch/m68k/mm + +arch/m68k/lib: dummy + $(MAKE) linuxsubdirs SUBDIRS=arch/m68k/lib + +arch/m68k/amiga: dummy + $(MAKE) linuxsubdirs SUBDIRS=arch/m68k/amiga + +arch/m68k/atari: dummy + $(MAKE) linuxsubdirs SUBDIRS=arch/m68k/atari + +MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot + +lilo: vmlinux + if [ -f $(INSTALL_PATH)/vmlinux ]; then mv -f $(INSTALL_PATH)/vmlinux $(INSTALL_PATH)/vmlinux.old; fi + if [ -f $(INSTALL_PATH)/System.map ]; then mv -f $(INSTALL_PATH)/System.map $(INSTALL_PATH)/System.old; fi + cat vmlinux > $(INSTALL_PATH)/vmlinux + cp System.map $(INSTALL_PATH)/System.map + if [ -x /sbin/lilo ]; then /sbin/lilo; else /etc/lilo/install; fi + +bootstrap: + @$(MAKEBOOT) bootstrap + +archclean: + @$(MAKEBOOT) clean + +archdep: + $(MAKEBOOT) dep diff -u --recursive --new-file v1.3.93/linux/arch/m68k/amiga/Makefile linux/arch/m68k/amiga/Makefile --- v1.3.93/linux/arch/m68k/amiga/Makefile Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/amiga/Makefile Tue Apr 2 00:27:34 1996 @@ -0,0 +1,15 @@ +# +# Makefile for Linux arch/m68k/amiga source directory +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now in the main makefile... + +O_TARGET := amiga.o +O_OBJS := config.o amikeyb.o amiints.o amipart.o \ + chipram.o amisound.o amifb.o zorro.o +OX_OBJS = ksyms.o + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.93/linux/arch/m68k/amiga/amifb.c linux/arch/m68k/amiga/amifb.c --- v1.3.93/linux/arch/m68k/amiga/amifb.c Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/amiga/amifb.c Mon Apr 1 22:05:42 1996 @@ -0,0 +1,5086 @@ +/* + * linux/arch/m68k/amiga/amifb.c -- Low level implementation of the Amiga frame + * buffer device + * + * Copyright (C) 1995 Geert Uytterhoeven + * + * + * This file is based on the Atari frame buffer device (atafb.c): + * + * Copyright (C) 1994 Martin Schaller + * Roman Hodek + * + * with work by Andreas Schwab + * Guenther Kelleter + * + * and on the original Amiga console driver (amicon.c): + * + * Copyright (C) 1993 Hamish Macdonald + * Greg Harp + * Copyright (C) 1994 David Carter [carter@compsci.bristol.ac.uk] + * + * with work by William Rucklidge (wjr@cs.cornell.edu) + * Geert Uytterhoeven + * Jes Sorensen (jds@kom.auc.dk) + * + * + * History: + * + * - 2 Dec 95: AGA version by Geert Uytterhoeven + * + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file README.legal in the main directory of this archive + * for more details. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#undef CONFIG_AMIFB_OCS +#undef CONFIG_AMIFB_ECS +#define CONFIG_AMIFB_AGA /* Only AGA support at the moment */ + +#define USE_MONO_AMIFB_IF_NON_AGA + + +/* -------------------- BEGIN: TODO ----------------------------------------- ** + + + - scan the sources for `TODO' + + - timings and monspecs can be set via the kernel command line (cfr. Atari) + + - OCS and ECS + + - hardware cursor + + - Interlaced screen -> Interlaced sprite/hardware cursor + + +** -------------------- END: TODO ------------------------------------------- */ + + +/******************************************************************************* + + + Generic video timings + --------------------- + + Timings used by the frame buffer interface: + + +----------+---------------------------------------------+----------+-------+ + | | ^ | | | + | | |upper_margin | | | + | | ¥ | | | + +----------###############################################----------+-------+ + | # ^ # | | + | # | # | | + | # | # | | + | # | # | | + | left # | # right | hsync | + | margin # | xres # margin | len | + |<-------->#<---------------+--------------------------->#<-------->|<----->| + | # | # | | + | # | # | | + | # | # | | + | # |yres # | | + | # | # | | + | # | # | | + | # | # | | + | # | # | | + | # | # | | + | # | # | | + | # | # | | + | # | # | | + | # ¥ # | | + +----------###############################################----------+-------+ + | | ^ | | | + | | |lower_margin | | | + | | ¥ | | | + +----------+---------------------------------------------+----------+-------+ + | | ^ | | | + | | |vsync_len | | | + | | ¥ | | | + +----------+---------------------------------------------+----------+-------+ + + + Amiga video timings + ------------------- + + The Amiga native chipsets uses another timing scheme: + + - hsstrt: Start of horizontal synchronization pulse + - hsstop: End of horizontal synchronization pulse + - htotal: Last value on the line (i.e. line length = htotal+1) + - vsstrt: Start of vertical synchronization pulse + - vsstop: Start of vertical synchronization pulse + - vtotal: Last line value (i.e. number of lines = vtotal+1) + - hcenter: Start of vertical retrace for interlace + + You can specify the blanking timings independently. Currently I just set + them equal to the respective synchronization values: + + - hbstrt: Start of horizontal blank + - hbstop: End of horizontal blank + - vbstrt: Start of vertical blank + - vbstop: Start of vertical blank + + Horizontal values are in color clock cycles (280 ns), vertical values are in + scanlines. + + (0, 0) is somewhere in the upper-left corner :-) + + + Amiga visible window definitions + -------------------------------- + + Currently I only have values for AGA, SHRES (28 MHz dotclock). Feel free to + make corrections and/or additions. + + Within the above synchronization specifications, the visible window is + defined by the following parameters (actual register resolutions may be + different; all horizontal values are normalized with respect to the pixel + clock): + + - diwstrt_h: Horizontal start of the visible window + - diwstop_h: Horizontal stop+1(*) of the visible window + - diwstrt_v: Vertical start of the visible window + - diwstop_v: Vertical stop of the visible window + - ddfstrt: Horizontal start of display DMA + - ddfstop: Horizontal stop of display DMA + - hscroll: Horizontal display output delay + + Sprite positioning: + + - sprstrt_h: Horizontal start-4 of sprite + - sprstrt_v: Vertical start of sprite + + (*) Even Commodore did it wrong in the AGA monitor drivers by not adding 1. + + Horizontal values are in dotclock cycles (35 ns), vertical values are in + scanlines. + + (0, 0) is somewhere in the upper-left corner :-) + + + Dependencies (AGA, SHRES (35 ns dotclock)) + ------------------------------------------- + + Since there are much more parameters for the Amiga display than for the + frame buffer interface, there must be some depencies among the Amiga display + parameters. Here's what I found out: + + - ddfstrt and ddfstop are best aligned to 64 pixels. + - the chipset needs 64+4 horizontal pixels after the DMA start before the + first pixel is output, so diwstrt_h = ddfstrt+64+4 if you want to + display the first pixel on the line too. Increase diwstrt_h for virtual + screen panning. + - the display DMA always fetches 64 pixels at a time (*). + - ddfstop is ddfstrt+#pixels-64. + - diwstop_h = diwstrt_h+xres+1. Because of the additional 1 this can be 1 + more than htotal. + - hscroll simply adds a delay to the display output. Smooth horizontal + panning needs an extra 64 pixels on the left to prefetch the pixels that + `fall off' on the left. + - if ddfstrt < 192, the sprite DMA cycles are all stolen by the bitplane + DMA, so it's best to make the DMA start as late as possible. + - you really don't want to make ddfstrt < 128, since this will steal DMA + cycles from the other DMA channels (audio, floppy and Chip RAM refresh). + - I make diwstop_h and diwstop_v as large as possible. + + (*) This is for fmode = 3. Lower fmodes allow for more freedom w.r.t. the + timings, but they limit the maximum display depth, and cause more stress + on the custom chip bus. + + + DMA priorities + -------------- + + Since there are limits on the earliest start value for display DMA and the + display of sprites, I use the following policy on horizontal panning and + the hardware cursor: + + - if you want to start display DMA too early, you loose the ability to + do smooth horizontal panning (xpanstep 1 -> 64). + - if you want to go even further, you loose the hardware cursor too. + + IMHO a hardware cursor is more important for X than horizontal scrolling, + so that's my motivation. + + + Implementation + -------------- + + aga_decode_var() converts the frame buffer values to the Amiga values. It's + just a `straightforward' implementation of the above rules. + + + Standard VGA timings + -------------------- + + xres yres left right upper lower hsync vsync + ---- ---- ---- ----- ----- ----- ----- ----- + 80x25 720 400 27 45 35 12 108 2 + 80x30 720 480 27 45 30 9 108 2 + + These were taken from a XFree86 configuration file, recalculated for a 28 MHz + dotclock (Amigas don't have a 25 MHz dotclock) and converted to frame buffer + generic timings. + + As a comparison, graphics/monitor.h suggests the following: + + xres yres left right upper lower hsync vsync + ---- ---- ---- ----- ----- ----- ----- ----- + + VGA 640 480 52 112 24 19 112 - 2 + + VGA70 640 400 52 112 27 21 112 - 2 - + + + Sync polarities + --------------- + + VSYNC HSYNC Vertical size Vertical total + ----- ----- ------------- -------------- + + + Reserved Reserved + + - 400 414 + - + 350 362 + - - 480 496 + + Source: CL-GD542X Technical Reference Manual, Cirrus Logic, Oct 1992 + + + Broadcast video timings + ----------------------- + + Since broadcast video timings are `fixed' and only depend on the video + system (PAL/NTSC), hsync_len and vsync_len are not used and must be set to + zero. All xres/yres and margin values are defined within the `visible + rectangle' of the display. + + According to the CCIR and RETMA specifications, we have the following values: + + CCIR -> PAL + ----------- + + - a scanline is 64 µs long, of which 52.48 µs are visible. This is about + 736 visible 70 ns pixels per line. + - we have 625 scanlines, of which 575 are visible (interlaced); after + rounding this becomes 576. + + RETMA -> NTSC + ------------- + + - a scanline is 63.5 µs long, of which 53.5 µs are visible. This is about + 736 visible 70 ns pixels per line. + - we have 525 scanlines, of which 485 are visible (interlaced); after + rounding this becomes 484. + + Thus if you want a PAL compatible display, you have to do the following: + + - set the FB_SYNC_BROADCAST flag to indicate that standard broadcast + timings are to be used. + - make sure upper_margin+yres+lower_margin = 576 for an interlaced, 288 + for a non-interlaced and 144 for a doublescanned display. + - make sure (left_margin+xres+right_margin)*pixclock is a reasonable + approximation to 52.48 µs. + + The settings for a NTSC compatible display are straightforward. + + Note that in a strict sense the PAL and NTSC standards only define the + encoding of the color part (chrominance) of the video signal and don't say + anything about horizontal/vertical synchronization nor refresh rates. + But since Amigas have RGB output, this issue isn't of any importance here. + + + -- Geert -- + +*******************************************************************************/ + + + /* + * Custom Chipset Definitions + */ + +#define CUSTOM_OFS(fld) ((long)&((struct CUSTOM*)0)->fld) + + + /* + * BPLCON0 -- Bitplane Control Register 0 + */ + +#define BPC0_HIRES (0x8000) +#define BPC0_BPU2 (0x4000) /* Bit plane used count */ +#define BPC0_BPU1 (0x2000) +#define BPC0_BPU0 (0x1000) +#define BPC0_HAM (0x0800) /* HAM mode */ +#define BPC0_DPF (0x0400) /* Double playfield */ +#define BPC0_COLOR (0x0200) /* Enable colorburst */ +#define BPC0_GAUD (0x0100) /* Genlock audio enable */ +#define BPC0_UHRES (0x0080) /* Ultrahi res enable */ +#define BPC0_SHRES (0x0040) /* Super hi res mode */ +#define BPC0_BYPASS (0x0020) /* Bypass LUT - AGA */ +#define BPC0_BPU3 (0x0010) /* AGA */ +#define BPC0_LPEN (0x0008) /* Light pen enable */ +#define BPC0_LACE (0x0004) /* Interlace */ +#define BPC0_ERSY (0x0002) /* External resync */ +#define BPC0_ECSENA (0x0001) /* ECS emulation disable */ + + + /* + * BPLCON2 -- Bitplane Control Register 2 + */ + +#define BPC2_ZDBPSEL2 (0x4000) /* Bitplane to be used for ZD - AGA */ +#define BPC2_ZDBPSEL1 (0x2000) +#define BPC2_ZDBPSEL0 (0x1000) +#define BPC2_ZDBPEN (0x0800) /* Enable ZD with ZDBPSELx - AGA */ +#define BPC2_ZDCTEN (0x0400) /* Enable ZD with palette bit #31 - AGA */ +#define BPC2_KILLEHB (0x0200) /* Kill EHB mode - AGA */ +#define BPC2_RDRAM (0x0100) /* Color table accesses read, not write - AGA */ +#define BPC2_SOGEN (0x0080) /* SOG output pin high - AGA */ +#define BPC2_PF2PRI (0x0040) /* PF2 priority over PF1 */ +#define BPC2_PF2P2 (0x0020) /* PF2 priority wrt sprites */ +#define BPC2_PF2P1 (0x0010) +#define BPC2_PF2P0 (0x0008) +#define BPC2_PF1P2 (0x0004) /* ditto PF1 */ +#define BPC2_PF1P1 (0x0002) +#define BPC2_PF1P0 (0x0001) + + + /* + * BPLCON3 -- Bitplane Control Register 3 (AGA) + */ + +#define BPC3_BANK2 (0x8000) /* Bits to select color register bank */ +#define BPC3_BANK1 (0x4000) +#define BPC3_BANK0 (0x2000) +#define BPC3_PF2OF2 (0x1000) /* Bits for color table offset when PF2 */ +#define BPC3_PF2OF1 (0x0800) +#define BPC3_PF2OF0 (0x0400) +#define BPC3_LOCT (0x0200) /* Color register writes go to low bits */ +#define BPC3_SPRES1 (0x0080) /* Sprite resolution bits */ +#define BPC3_SPRES0 (0x0040) +#define BPC3_BRDRBLNK (0x0020) /* Border blanked? */ +#define BPC3_BRDRTRAN (0x0010) /* Border transparent? */ +#define BPC3_ZDCLKEN (0x0004) /* ZD pin is 14 MHz (HIRES) clock output */ +#define BPC3_BRDRSPRT (0x0002) /* Sprites in border? */ +#define BPC3_EXTBLKEN (0x0001) /* BLANK programmable */ + + + /* + * BPLCON4 -- Bitplane Control Register 4 (AGA) + */ + +#define BPC4_BPLAM7 (0x8000) /* bitplane color XOR field */ +#define BPC4_BPLAM6 (0x4000) +#define BPC4_BPLAM5 (0x2000) +#define BPC4_BPLAM4 (0x1000) +#define BPC4_BPLAM3 (0x0800) +#define BPC4_BPLAM2 (0x0400) +#define BPC4_BPLAM1 (0x0200) +#define BPC4_BPLAM0 (0x0100) +#define BPC4_ESPRM7 (0x0080) /* 4 high bits for even sprite colors */ +#define BPC4_ESPRM6 (0x0040) +#define BPC4_ESPRM5 (0x0020) +#define BPC4_ESPRM4 (0x0010) +#define BPC4_OSPRM7 (0x0008) /* 4 high bits for odd sprite colors */ +#define BPC4_OSPRM6 (0x0004) +#define BPC4_OSPRM5 (0x0002) +#define BPC4_OSPRM4 (0x0001) + + + /* + * BEAMCON0 -- Beam Control Register + */ + +#define BMC0_HARDDIS (0x4000) /* Disable hardware limits */ +#define BMC0_LPENDIS (0x2000) /* Disable light pen latch */ +#define BMC0_VARVBEN (0x1000) /* Enable variable vertical blank */ +#define BMC0_LOLDIS (0x0800) /* Disable long/short line toggle */ +#define BMC0_CSCBEN (0x0400) /* Composite sync/blank */ +#define BMC0_VARVSYEN (0x0200) /* Enable variable vertical sync */ +#define BMC0_VARHSYEN (0x0100) /* Enable variable horizontal sync */ +#define BMC0_VARBEAMEN (0x0080) /* Enable variable beam counters */ +#define BMC0_DUAL (0x0080) /* Enable alternate horizontal beam counter */ +#define BMC0_PAL (0x0020) /* Set decodes for PAL */ +#define BMC0_VARCSYEN (0x0010) /* Enable variable composite sync */ +#define BMC0_BLANKEN (0x0008) /* Blank enable (no longer used on AGA) */ +#define BMC0_CSYTRUE (0x0004) /* CSY polarity */ +#define BMC0_VSYTRUE (0x0002) /* VSY polarity */ +#define BMC0_HSYTRUE (0x0001) /* HSY polarity */ + + + /* + * FMODE -- Fetch Mode Control Register (AGA) + */ + +#define FMODE_SSCAN2 (0x8000) /* Sprite scan-doubling */ +#define FMODE_BSCAN2 (0x4000) /* Use PF2 modulus every other line */ +#define FMODE_SPAGEM (0x0008) /* Sprite page mode */ +#define FMODE_SPR32 (0x0004) /* Sprite 32 bit fetch */ +#define FMODE_BPAGEM (0x0002) /* Bitplane page mode */ +#define FMODE_BPL32 (0x0001) /* Bitplane 32 bit fetch */ + + + /* + * Tags used to indicate a specific Pixel Clock + * + * clk_shift is the shift value to get the timings in 35 ns units + */ + +#define TAG_SHRES (1) /* SHRES, clk_shift = TAG_SHRES-1 */ +#define TAG_HIRES (2) /* HIRES, clk_shift = TAG_HIRES-1 */ +#define TAG_LORES (3) /* LORES, clk_shift = TAG_LORES-1 */ + + + /* + * Clock Definitions, Maximum Display Depth + * + * These depend on the E-Clock or the Chipset, so they are filled in + * dynamically + */ + +static u_long pixclock[3]; /* SHRES/HIRES/LORES: index = clk_shift */ +static u_short maxdepth[3]; /* SHRES/HIRES/LORES: index = clk_shift */ + + + /* + * Broadcast Video Timings + * + * Horizontal values are in 35 ns (SHRES) units + * Vertical values are in non-interlaced scanlines + */ + +#define PAL_WINDOW_H (1472) /* PAL Window Limits */ +#define PAL_WINDOW_V (288) +#define PAL_DIWSTRT_H (360) +#define PAL_DIWSTRT_V (24) + +#define NTSC_WINDOW_H (1472) /* NTSC Window Limits */ +#define NTSC_WINDOW_V (242) +#define NTSC_DIWSTRT_H (360) +#define NTSC_DIWSTRT_V (20) + +#define PAL_HTOTAL (1816) /* Total line length */ +#define NTSC_HTOTAL (1816) /* Needed for YWRAP */ + + + /* + * Monitor Specifications + * + * These are typical for a `generic' Amiga monitor (e.g. A1960) + */ + +static long vfmin = 50, vfmax = 90, hfmin = 15000, hfmax = 38000; + +static u_short pwrsave = 0; /* VESA suspend mode (not for PAL/NTSC) */ + + + /* + * Various macros + */ + +#define up8(x) (((x)+7) & ~7) +#define down8(x) ((x) & ~7) +#define div8(x) ((x)>>3) +#define mod8(x) ((x) & 7) + +#define up16(x) (((x)+15) & ~15) +#define down16(x) ((x) & ~15) +#define div16(x) ((x)>>4) +#define mod16(x) ((x) & 15) + +#define up32(x) (((x)+31) & ~31) +#define down32(x) ((x) & ~31) +#define div32(x) ((x)>>5) +#define mod32(x) ((x) & 31) + +#define up64(x) (((x)+63) & ~63) +#define down64(x) ((x) & ~63) +#define div64(x) ((x)>>6) +#define mod64(x) ((x) & 63) + +#define min(a, b) ((a) < (b) ? (a) : (b)) +#define max(a, b) ((a) > (b) ? (a) : (b)) + +#define highw(x) ((u_long)(x)>>16 & 0xffff) +#define loww(x) ((u_long)(x) & 0xffff) + +#define arraysize(x) (sizeof(x)/sizeof(*(x))) + + + /* + * Chip RAM we reserve for the Frame Buffer + * + * This defines the Maximum Virtual Screen Size + */ + +#define VIDEOMEMSIZE_AGA_2M (1280*1024) /* AGA (2MB) : max 1280*1024*256 */ +#define VIDEOMEMSIZE_AGA_1M (1024*768) /* AGA (1MB) : max 1024*768*256 */ +#define VIDEOMEMSIZE_ECS_2M (1280*1024/2) /* ECS (2MB) : max 1280*1024*16 */ +#define VIDEOMEMSIZE_ECS_1M (1024*768/2) /* ECS (1MB) : max 1024*768*16 */ +#define VIDEOMEMSIZE_OCS (800*600/2) /* OCS : max 800*600*16 */ + + +static u_long videomemory; +static u_long videomemorysize; + +#define assignchunk(name, type, ptr, size) \ +{ \ + (name) = (type)(ptr); \ + ptr += size; \ +} + + + /* + * Copper Instructions + */ + +#define CMOVE(val, reg) (CUSTOM_OFS(reg)<<16 | (val)) +#define CMOVE2(val, reg) ((CUSTOM_OFS(reg)+2)<<16 | (val)) +#define CWAIT(x, y) (((y) & 0xff)<<24 | ((x) & 0xfe)<<16 | 0x0001fffe) +#define CEND (0xfffffffe) + + +typedef union { + u_long l; + u_short w[2]; +} copins; + + + /* + * Frame Header Copper List + */ + +struct clist_hdr { + copins bplcon0; + copins diwstrt; + copins diwstop; + copins diwhigh; + copins sprfix[8]; + copins sprstrtup[16]; + copins wait; + copins jump; + copins wait_forever; +}; + + + /* + * Long Frame/Short Frame Copper List + */ + +struct clist_dyn { + copins diwstrt; + copins diwstop; + copins diwhigh; + copins bplcon0; + copins sprpt[2]; /* Sprite 0 */ + copins rest[64]; +}; + + +static struct clist_hdr *clist_hdr; +static struct clist_dyn *clist_lof; +static struct clist_dyn *clist_shf; /* Only used for Interlace */ + + + /* + * Hardware Cursor + */ + +#define CRSR_RATE (20) /* Number of frames/flash toggle */ + +static u_long *lofsprite, *shfsprite, *dummysprite; +static u_short cursormode = FB_CURSOR_FLASH; + + + /* + * Current Video Mode + */ + +struct amiga_fb_par { + + /* General Values */ + + int xres; /* vmode */ + int yres; /* vmode */ + int vxres; /* vmode */ + int vyres; /* vmode */ + int xoffset; /* vmode */ + int yoffset; /* vmode */ + u_short bpp; /* vmode */ + u_short clk_shift; /* vmode */ + int vmode; /* vmode */ + u_short diwstrt_h; /* vmode */ + u_short diwstrt_v; /* vmode */ + u_long next_line; /* modulo for next line */ + u_long next_plane; /* modulo for next plane */ + short crsr_x; /* movecursor */ + short crsr_y; /* movecursor */ + + /* OCS Hardware Registers */ + + u_long bplpt0; /* vmode, pan (Note: physical address) */ + u_short bplcon0; /* vmode */ + u_short bplcon1; /* vmode, pan */ + u_short bpl1mod; /* vmode, pan */ + u_short bpl2mod; /* vmode, pan */ + u_short diwstrt; /* vmode */ + u_short diwstop; /* vmode */ + u_short ddfstrt; /* vmode, pan */ + u_short ddfstop; /* vmode, pan */ + +#if defined(CONFIG_AMIFB_ECS) || defined(CONFIG_AMIFB_AGA) + /* Additional ECS Hardware Registers */ + + u_short diwhigh; /* vmode */ + u_short bplcon3; /* vmode */ + u_short beamcon0; /* vmode */ + u_short htotal; /* vmode */ + u_short hsstrt; /* vmode */ + u_short hsstop; /* vmode */ + u_short vtotal; /* vmode */ + u_short vsstrt; /* vmode */ + u_short vsstop; /* vmode */ + u_short hcenter; /* vmode */ +#endif /* defined(CONFIG_AMIFB_ECS) || defined(CONFIG_AMIFB_AGA) */ + +#if defined(CONFIG_AMIFB_AGA) + /* Additional AGA Hardware Registers */ + + u_short fmode; /* vmode */ +#endif /* defined(CONFIG_AMIFB_AGA) */ +}; + +static struct amiga_fb_par current_par; + +static int current_par_valid = 0; +static int currcon = 0; + +static struct display disp[MAX_NR_CONSOLES]; +static struct fb_info fb_info; + +static int node; /* node of the /dev/fb?current file */ + + + /* + * The minimum period for audio depends on htotal (for OCS/ECS/AGA) + */ + +volatile u_short amiga_audio_min_period = 124; /* Default for pre-OCS */ + + + /* + * Since we can't read the palette on OCS/ECS, and since reading one + * single color palette entry requires 5 expensive custom chip bus + * accesses on AGA, we keep a copy of the current palette. + */ + +#ifdef CONFIG_AMIFB_AGA +static struct { u_char red, green, blue, pad; } palette[256]; +#else /* CONFIG_AMIFB_AGA */ +static struct { u_char red, green, blue, pad; } palette[32]; +#endif /* CONFIG_AMIFB_AGA */ + + + /* + * Latches and Flags for display changes during VBlank + */ + +static volatile u_short do_vmode = 0; /* Change the Video Mode */ +static volatile short do_blank = 0; /* (Un)Blank the Screen (±1) */ +static volatile u_short do_movecursor = 0; /* Move the Cursor */ +static volatile u_short full_vmode_change = 1; /* Full Change or Only Pan */ +static volatile u_short is_blanked = 0; /* Screen is Blanked */ + + + /* + * Switch for Chipset Independency + */ + +static struct fb_hwswitch { + + /* Initialization */ + int (*init)(void); + + /* Display Control */ + int (*encode_fix)(struct fb_fix_screeninfo *fix, struct amiga_fb_par *par); + int (*decode_var)(struct fb_var_screeninfo *var, struct amiga_fb_par *par); + int (*encode_var)(struct fb_var_screeninfo *var, struct amiga_fb_par *par); + int (*getcolreg)(u_int regno, u_int *red, u_int *green, u_int *blue, + u_int *transp); + int (*setcolreg)(u_int regno, u_int red, u_int green, u_int blue, + u_int transp); + int (*pan_display)(struct fb_var_screeninfo *var, struct amiga_fb_par *par); + + /* Routines Called by VBlank Interrupt to minimize flicker */ + void (*do_vmode)(void); + void (*do_blank)(int blank); + void (*do_movecursor)(void); + void (*do_flashcursor)(void); +} *fbhw; + + + /* + * Frame Buffer Name + * + * The rest of the name is filled in by amiga_fb_init + */ + +static char amiga_fb_name[16] = "Amiga "; + + + /* + * Predefined Video Mode Names + * + * The a2024-?? modes don't work yet because there's no A2024 driver. + */ + +static char *amiga_fb_modenames[] = { + + /* + * Autodetect (Default) Video Mode + */ + + "default", + + /* + * AmigaOS Video Modes + */ + + "ntsc", /* 640x200, 15 kHz, 60 Hz (NTSC) */ + "ntsc-lace", /* 640x400, 15 kHz, 60 Hz interlaced (NTSC) */ + "pal", /* 640x256, 15 kHz, 50 Hz (PAL) */ + "pal-lace", /* 640x512, 15 kHz, 50 Hz interlaced (PAL) */ + "multiscan", /* 640x480, 29 kHz, 57 Hz */ + "multiscan-lace", /* 640x960, 29 kHz, 57 Hz interlaced */ + "a2024-10", /* 1024x800, 10 Hz (Not yet supported) */ + "a2024-15", /* 1024x800, 15 Hz (Not yet supported) */ + "euro36", /* 640x200, 15 kHz, 72 Hz */ + "euro36-lace", /* 640x400, 15 kHz, 72 Hz interlaced */ + "euro72", /* 640x400, 29 kHz, 68 Hz */ + "euro72-lace", /* 640x800, 29 kHz, 68 Hz interlaced */ + "super72", /* 800x300, 23 kHz, 70 Hz */ + "super72-lace", /* 800x600, 23 kHz, 70 Hz interlaced */ + "dblntsc", /* 640x200, 27 kHz, 57 Hz doublescan */ + "dblntsc-ff", /* 640x400, 27 kHz, 57 Hz */ + "dblntsc-lace", /* 640x800, 27 kHz, 57 Hz interlaced */ + "dblpal", /* 640x256, 27 kHz, 47 Hz doublescan */ + "dblpal-ff", /* 640x512, 27 kHz, 47 Hz */ + "dblpal-lace", /* 640x1024, 27 kHz, 47 Hz interlaced */ + + /* + * VGA Video Modes + */ + + "vga", /* 640x480, 31 kHz, 60 Hz (VGA) */ + "vga70", /* 640x400, 31 kHz, 70 Hz (VGA) */ + + /* + * User Defined Video Modes: to be set after boot up using e.g. fbset + */ + + "user0", "user1", "user2", "user3", "user4", "user5", "user6", "user7" +}; + + + /* + * Predefined Video Mode Definitions + * + * Since the actual pixclock values depend on the E-Clock, we use the + * TAG_* values and fill in the real values during initialization. + * Thus we assume no one has pixel clocks of 333, 500 or 1000 GHz :-) + */ + +static struct fb_var_screeninfo amiga_fb_predefined[] = { + + /* + * Autodetect (Default) Video Mode + */ + + { 0, }, + + /* + * AmigaOS Video Modes + */ + + { + /* ntsc */ + 640, 200, 640, 200, 0, 0, 4, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 78, 18, 24, 18, 0, 0, + FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED + }, { + /* ntsc-lace */ + 640, 400, 640, 400, 0, 0, 4, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 78, 18, 48, 36, 0, 0, + FB_SYNC_BROADCAST, FB_VMODE_INTERLACED + }, { + /* pal */ + 640, 256, 640, 256, 0, 0, 4, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 78, 18, 20, 12, 0, 0, + FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED + }, { + /* pal-lace */ + 640, 512, 640, 512, 0, 0, 4, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 78, 18, 40, 24, 0, 0, + FB_SYNC_BROADCAST, FB_VMODE_INTERLACED + }, { + /* multiscan */ + 640, 480, 640, 480, 0, 0, 4, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 164, 92, 9, 9, 80, 8, + 0, FB_VMODE_NONINTERLACED + }, { + /* multiscan-lace */ + 640, 960, 640, 960, 0, 0, 4, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 164, 92, 18, 18, 80, 16, + 0, FB_VMODE_INTERLACED + }, { + /* a2024-10 (Not yet supported) */ + 1024, 800, 1024, 800, 0, 0, 2, 0, + {0, 2, 0}, {0, 2, 0}, {0, 2, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 0, 0, 0, 0, 0, 0, + 0, FB_VMODE_NONINTERLACED + }, { + /* a2024-15 (Not yet supported) */ + 1024, 800, 1024, 800, 0, 0, 2, 0, + {0, 2, 0}, {0, 2, 0}, {0, 2, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 0, 0, 0, 0, 0, 0, + 0, FB_VMODE_NONINTERLACED + }, { + /* euro36 */ + 640, 200, 640, 200, 0, 0, 4, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 92, 124, 6, 6, 52, 5, + 0, FB_VMODE_NONINTERLACED + }, { + /* euro36-lace */ + 640, 400, 640, 400, 0, 0, 4, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 92, 124, 12, 12, 52, 10, + 0, FB_VMODE_INTERLACED + }, { + /* euro72 */ + 640, 400, 640, 400, 0, 0, 4, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 164, 92, 9, 9, 80, 8, + 0, FB_VMODE_NONINTERLACED + }, { + /* euro72-lace */ + 640, 800, 640, 800, 0, 0, 4, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 164, 92, 18, 18, 80, 16, + 0, FB_VMODE_INTERLACED + }, { + /* super72 */ + 800, 300, 800, 300, 0, 0, 4, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 212, 140, 10, 11, 80, 7, + 0, FB_VMODE_NONINTERLACED + }, { + /* super72-lace */ + 800, 600, 800, 600, 0, 0, 4, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 212, 140, 20, 22, 80, 14, + 0, FB_VMODE_INTERLACED + }, { + /* dblntsc */ + 640, 200, 640, 200, 0, 0, 4, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 196, 124, 18, 17, 80, 4, + 0, FB_VMODE_DOUBLE + }, { + /* dblntsc-ff */ + 640, 400, 640, 400, 0, 0, 4, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 196, 124, 36, 35, 80, 7, + 0, FB_VMODE_NONINTERLACED + }, { + /* dblntsc-lace */ + 640, 800, 640, 800, 0, 0, 4, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 196, 124, 72, 70, 80, 14, + 0, FB_VMODE_INTERLACED + }, { + /* dblpal */ + 640, 256, 640, 256, 0, 0, 4, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 196, 124, 14, 13, 80, 4, + 0, FB_VMODE_DOUBLE + }, { + /* dblpal-ff */ + 640, 512, 640, 512, 0, 0, 4, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 196, 124, 28, 27, 80, 7, + 0, FB_VMODE_NONINTERLACED + }, { + /* dblpal-lace */ + 640, 1024, 640, 1024, 0, 0, 4, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 196, 124, 56, 54, 80, 14, + 0, FB_VMODE_INTERLACED + }, + + /* + * VGA Video Modes + */ + + { + /* vga */ + 640, 480, 640, 480, 0, 0, 4, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 64, 96, 30, 9, 112, 2, + 0, FB_VMODE_NONINTERLACED + }, { + /* vga70 */ + 640, 400, 640, 400, 0, 0, 4, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 64, 96, 35, 12, 112, 2, + FB_SYNC_VERT_HIGH_ACT | FB_SYNC_COMP_HIGH_ACT, FB_VMODE_NONINTERLACED + }, + + /* + * User Defined Video Modes + */ + + { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, } +}; + + +#define NUM_USER_MODES (8) +#define NUM_TOTAL_MODES arraysize(amiga_fb_predefined) +#define NUM_PREDEF_MODES (NUM_TOTAL_MODES-NUM_USER_MODES) + + +static int amifb_ilbm = 0; /* interleaved or normal bitplanes */ + +static int amifb_inverse = 0; +static int amifb_mode = 0; + + + /* + * Support for Graphics Boards + */ + +#ifdef CONFIG_FB_CYBER /* Cybervision */ +extern int Cyber_probe(void); +extern void Cyber_video_setup(char *options, int *ints); +extern struct fb_info *Cyber_fb_init(long *mem_start); + +static int amifb_Cyber = 0; +#endif /* CONFIG_FB_CYBER */ + + + /* + * Some default modes + */ + +#define DEFMODE_PAL "pal" /* for PAL OCS/ECS */ +#define DEFMODE_NTSC "ntsc" /* for NTSC OCS/ECS */ +#define DEFMODE_AMBER_PAL "pal-lace" /* for flicker fixed PAL (A3000) */ +#define DEFMODE_AMBER_NTSC "ntsc-lace" /* for flicker fixed NTSC (A3000) */ +#define DEFMODE_AGA "vga70" /* for AGA */ + + + /* + * Interface used by the world + */ + +void amiga_video_setup(char *options, int *ints); + +static int amiga_fb_get_fix(struct fb_fix_screeninfo *fix, int con); +static int amiga_fb_get_var(struct fb_var_screeninfo *var, int con); +static int amiga_fb_set_var(struct fb_var_screeninfo *var, int con); +static int amiga_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con); +static int amiga_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con); +static int amiga_fb_pan_display(struct fb_var_screeninfo *var, int con); + +static int amiga_fb_ioctl(struct inode *inode, struct file *file, u_int cmd, + u_long arg, int con); + +static int amiga_fb_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con); +static int amiga_fb_get_var_cursorinfo(struct fb_var_cursorinfo *var, int con); +static int amiga_fb_set_var_cursorinfo(struct fb_var_cursorinfo *var, int con); +static int amiga_fb_get_cursorstate(struct fb_cursorstate *state, int con); +static int amiga_fb_set_cursorstate(struct fb_cursorstate *state, int con); + + + /* + * Interface to the low level console driver + */ + +struct fb_info *amiga_fb_init(long *mem_start); +static int amifb_switch(int con); +static int amifb_updatevar(int con); +static void amifb_blank(int blank); + + + /* + * Support for OCS + */ + +#ifdef CONFIG_AMIFB_OCS +#error "OCS support: not yet implemented" +#endif /* CONFIG_AMIFB_OCS */ + + + /* + * Support for ECS + */ + +#ifdef CONFIG_AMIFB_ECS +#error "ECS support: not yet implemented" +#endif /* CONFIG_AMIFB_ECS */ + + + /* + * Support for AGA + */ + +#ifdef CONFIG_AMIFB_AGA +static int aga_init(void); +static int aga_encode_fix(struct fb_fix_screeninfo *fix, + struct amiga_fb_par *par); +static int aga_decode_var(struct fb_var_screeninfo *var, + struct amiga_fb_par *par); +static int aga_encode_var(struct fb_var_screeninfo *var, + struct amiga_fb_par *par); +static int aga_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, + u_int *transp); +static int aga_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp); +static int aga_pan_display(struct fb_var_screeninfo *var, + struct amiga_fb_par *par); +static void aga_do_vmode(void); +static void aga_do_blank(int blank); +static void aga_do_movecursor(void); +static void aga_do_flashcursor(void); + +static int aga_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con); +static int aga_get_var_cursorinfo(struct fb_var_cursorinfo *var, int con); +static int aga_set_var_cursorinfo(struct fb_var_cursorinfo *var, int con); +static int aga_get_cursorstate(struct fb_cursorstate *state, int con); +static int aga_set_cursorstate(struct fb_cursorstate *state, int con); + +static __inline__ void aga_build_clist_hdr(struct clist_hdr *cop); +static __inline__ void aga_update_clist_hdr(struct clist_hdr *cop, + struct amiga_fb_par *par); +static void aga_build_clist_dyn(struct clist_dyn *cop, + struct clist_dyn *othercop, u_short shf, + struct amiga_fb_par *par); +#endif /* CONFIG_AMIFB_AGA */ + + + /* + * Internal routines + */ + +static u_long chipalloc(u_long size); +static void amiga_fb_get_par(struct amiga_fb_par *par); +static void amiga_fb_set_par(struct amiga_fb_par *par); +static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive); +static struct fb_cmap *get_default_colormap(int bpp); +static int do_fb_get_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var, + int kspc); +static int do_fb_set_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var, + int kspc); +static void do_install_cmap(int con); +static void memcpy_fs(int fsfromto, void *to, void *from, int len); +static void copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto); +static int alloc_cmap(struct fb_cmap *cmap, int len, int transp); +static void amiga_fb_set_disp(int con); +static void amifb_interrupt(int irq, struct pt_regs *fp, void *dummy); +static char * strtoke(char * s,const char * ct); +static int get_video_mode(const char *name); +static void check_default_mode(void); + + +#ifdef USE_MONO_AMIFB_IF_NON_AGA + +/****************************************************************************** +* +* This is the old monochrome frame buffer device. It's invoked if we're running +* on a non-AGA machine, until the color support for OCS/ECS is finished. +* +******************************************************************************/ + +/* + * atari/atafb.c -- Low level implementation of Atari frame buffer device + * amiga/amifb.c -- Low level implementation of Amiga frame buffer device + * + * Copyright (C) 1994 Martin Schaller & Roman Hodek & Geert Uytterhoeven + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file README.legal in the main directory of this archive + * for more details. + * + * History: + * - 03 Jan 95: Original version my Martin Schaller: The TT driver and + * all the device independant stuff + * - 09 Jan 95: Roman: I've added the hardware abstraction (hw_switch) + * and wrote the Falcon, ST(E), and External drivers + * based on the original TT driver. + * - 26 Jan 95: Geert: Amiga version + * - 19 Feb 95: Hamish: added Jes Sorensen's ECS patches to the Amiga + * frame buffer device. This provdes ECS support and the + * following screen-modes: multiscan, multiscan-lace, + * super72, super72-lace, dblntsc, dblpal & euro72. + * He suggests that we remove the old AGA screenmodes, + * as they are non-standard, and some of them doesn't work + * under ECS. + */ + +static struct mono_mono_amiga_fb_par { + u_long smem_start; + u_long smem_len; + struct geometry *geometry; + ushort scr_max_height; /* screen dimensions */ + ushort scr_max_width; + ushort scr_height; + ushort scr_width; + ushort scr_depth; + int bytes_per_row; /* offset to one line below */ + ulong fgcol; + ulong bgcol; + ulong crsrcol; + ushort scroll_latch; /* Vblank support for hardware scroll */ + ushort y_wrap; + ushort cursor_latch; /* Hardware cursor */ + ushort *cursor, *dummy; + ushort cursor_flash; + ushort cursor_visible; + ushort diwstrt_v, diwstrt_h; /* display window control */ + ushort diwstop_v, diwstop_h; + ushort bplcon0; /* display mode */ + ushort htotal; + u_char *bitplane[8]; /* pointers to display bitplanes */ + ulong plane_size; + ushort *coplist1hdr; /* List 1 static component */ + ushort *coplist1dyn; /* List 1 dynamic component */ + ushort *coplist2hdr; /* List 2 static component */ + ushort *coplist2dyn; /* List 2 dynamic component */ +} mono_current_par; + + +static ushort mono_cursor_data[] = +{ + 0x2c81,0x2d00, + 0xf000,0x0000, + 0x0000,0x0000 +}; + + +/* + * Color definitions + */ + +#define FG_COLOR (0x000000) /* black */ +#define BG_COLOR (0xaaaaaa) /* lt. grey */ +#define CRSR_COLOR (0xff0000) /* bright red */ + +#define FG_COLOR_INV BG_COLOR +#define BG_COLOR_INV FG_COLOR +#define CRSR_COLOR_INV (0x6677aa) /* a blue-ish color */ + +/* + * Split 24-bit RGB colors in 12-bit MSB (for OCS/ECS/AGA) and LSB (for AGA) + */ + +#define COLOR_MSB(rgb) (((rgb>>12)&0xf00)|((rgb>>8)&0x0f0)|((rgb>>4)&0x00f)) +#define COLOR_LSB(rgb) (((rgb>>8) &0xf00)|((rgb>>4)&0x0f0)|((rgb) &0x00f)) + +/* Cursor definitions */ + +#define CRSR_FLASH 1 /* Cursor flashing on(1)/off(0) */ +#define CRSR_BLOCK 1 /* Block(1) or line(0) cursor */ + + +/* controlling screen blanking (read in VBL handler) */ +static int mono_do_blank; +static int mono_do_unblank; +static unsigned short mono_save_bplcon3; + +/* + * mono_ecs_color_zero is used to keep custom.color[0] for the special ECS color- + * table, as custom.color[0] is cleared at vblank interrupts. + * -Jes (jds@kom.auc.dk) + */ + +static ushort mono_ecs_color_zero; + +static struct { + int right_count; + int done; +} mono_vblank; + + +static __inline__ void mono_init_vblank(void) +{ + mono_vblank.right_count = 0; + mono_vblank.done = 0; +} + +/* Geometry structure contains all useful information about given mode. + * + * Strictly speaking `scr_max_height' and `scr_max_width' is redundant + * information with DIWSTRT value provided. Might be useful if modes + * can be hotwired by user in future. It fits for the moment. + * + * At the moment, the code only distinguishes between OCS and AGA. ECS + * lies somewhere in between - someone more familiar with it could make + * appropriate modifications so that some advanced display modes are + * available, without confusing the poor chipset. OCS modes use only the + * bplcon0, diwstrt, diwstop, ddfstrt, ddfstop registers (a few others could + * be used as well). -wjr + * + * The code now supports ECS aswell, except for FMODE all control registers + * are the same under ECS. A special color-table has to be generated though. + * -Jes + */ +struct geometry { + char *modename; /* Name this thing */ + char isOCS; /* Is it OCS or ECS/AGA */ + ushort bplcon0; /* Values for bit plane control register 0 */ + ushort scr_width; + ushort scr_height; + ushort scr_depth; + ushort scr_max_width; /* Historical, might be useful still */ + ushort scr_max_height; + ushort diwstrt_h; /* Where the display window starts */ + ushort diwstrt_v; + ushort alignment; /* Pixels per scanline must be a multiple of this */ + /* OCS doesn't need anything past here */ + ushort bplcon2; + ushort bplcon3; + /* The rest of these control variable sync */ + ushort htotal; /* Total hclocks */ + ushort hsstrt; /* HSYNC start and stop */ + ushort hsstop; + ushort hbstrt; /* HBLANK start and stop */ + ushort hbstop; + ushort vtotal; /* Total vlines */ + ushort vsstrt; /* VSYNC, VBLANK ditto */ + ushort vsstop; + ushort vbstrt; + ushort vbstop; + ushort hcenter; /* Center of line, for interlaced modes */ + ushort beamcon0; /* Beam control */ + ushort fmode; /* Memory fetch mode */ +}; + +#define MAX_COP_LIST_ENTS 64 +#define COP_MEM_REQ (MAX_COP_LIST_ENTS*4*2) +#define SPR_MEM_REQ (24) + + +static struct geometry mono_modes[] = { + /* NTSC modes: !!! can't guarantee anything about overscan modes !!! */ + { + "ntsc-lace", 1, + BPC0_HIRES | BPC0_LACE, + 640, 400, 1, + 704, 480, + 0x71, 0x18, /* diwstrt h,v */ + 16 /* WORD aligned */ + }, { + "ntsc", 1, + BPC0_HIRES, + 640, 200, 1, + 704, 240, + 0x71, 0x18, + 16 /* WORD aligned */ + }, { + "ntsc-lace-over", 1, + BPC0_HIRES | BPC0_LACE, + 704, 480, 1, + 704, 480, + 0x71, 0x18, + 16 /* WORD aligned */ + }, { + "ntsc-over", 1, + BPC0_HIRES, + 704, 240, 1, + 704, 240, + 0x71, 0x18, + 16 /* WORD aligned */ + }, + /* PAL modes. Warning: + * + * PAL overscan causes problems on my machine because maximum diwstop_h + * value seems to be ~0x1c2, rather than 0x1e0+ inferred by RKM 1.1 + * and 0x1d5 inferred by original `amicon.c' source. Is this a hardware + * limitation of OCS/pal or 1084?. Or am I doing something stupid here? + * + * Included a couple of overscan modes that DO work on my machine, + * although not particularly useful. + */ + { + "pal-lace", 1, + BPC0_HIRES | BPC0_LACE, + 640, 512, 1, + 704, 592, + 0x71, 0x18, + 16 /* WORD aligned */ + }, { + "pal", 1, + BPC0_HIRES, + 640, 256, 1, + 704, 296, + 0x71, 0x18, + 16 /* WORD aligned */ + }, { + "pal-lace-over", 1, + BPC0_HIRES | BPC0_LACE, + 704, 592, 1, + 704, 582, + 0x5b, 0x18, + 16 /* WORD aligned */ + }, { + "pal-over", 1, + BPC0_HIRES, + 704, 296, 1, + 704, 296, + 0x5b, 0x18, + 16 /* WORD aligned */ + + }, + /* ECS modes, these are real ECS modes */ + { + "multiscan", 0, + BPC0_SHRES | BPC0_ECSENA, /* bplcon0 */ + 640, 480, 1, + 640, 480, + 0x0041, 0x002c, /* diwstrt h,v */ + 64, /* 64-bit aligned */ + BPC2_KILLEHB, /* bplcon2 */ + BPC3_PF2OF1 | BPC3_PF2OF0 | BPC3_SPRES1 | BPC3_SPRES0 | + BPC3_BRDRBLNK | BPC3_EXTBLKEN, /* bplcon3 */ + + 0x0072, /* htotal */ + 0x000a, /* hsstrt */ + 0x0013, /* hsstop */ + 0x0002, /* hbstrt */ + 0x001c, /* hbstop */ + 0x020c, /* vtotal */ + 0x0008, /* vsstrt */ + 0x0011, /* vsstop */ + 0x0000, /* vbstrt */ + 0x001c, /* vbstop */ + 0x0043, /* hcenter */ + BMC0_VARVBEN | BMC0_LOLDIS | BMC0_VARVSYEN | + BMC0_VARHSYEN | BMC0_VARBEAMEN | BMC0_BLANKEN, + /* beamcon0 */ + FMODE_BPAGEM | FMODE_BPL32 /* fmode */ + }, + { + "multiscan-lace", 0, + BPC0_SHRES | BPC0_LACE | BPC0_ECSENA, /* bplcon0 */ + 640, 960, 1, + 640, 960, + 0x0041, 0x002c, /* diwstrt h,v */ + 64, /* 64-bit aligned */ + BPC2_KILLEHB, /* bplcon2 */ + BPC3_PF2OF1 | BPC3_PF2OF0 | BPC3_SPRES1 | BPC3_SPRES0 | + BPC3_BRDRBLNK | BPC3_EXTBLKEN, /* bplcon3 */ + + 0x0072, /* htotal */ + 0x000a, /* hsstrt */ + 0x0013, /* hsstop */ + 0x0002, /* hbstrt */ + 0x001c, /* hbstop */ + 0x020c, /* vtotal */ + 0x0008, /* vsstrt */ + 0x0011, /* vsstop */ + 0x0000, /* vbstrt */ + 0x001c, /* vbstop */ + 0x0043, /* hcenter */ + BMC0_VARVBEN | BMC0_LOLDIS | BMC0_VARVSYEN | + BMC0_VARHSYEN | BMC0_VARBEAMEN | BMC0_BLANKEN, + /* beamcon0 */ + FMODE_BPAGEM | FMODE_BPL32 /* fmode */ + }, + /* Super 72 - 800x300 72Hz noninterlaced mode. */ + { + "super72", 0, + BPC0_SHRES | BPC0_ECSENA, /* bplcon0 */ + 800, 304, 1, /* need rows%8 == 0 */ + 800, 304, /* (cols too) */ + 0x0051, 0x0021, /* diwstrt h,v */ + 64, /* 64-bit aligned */ + BPC2_KILLEHB, /* bplcon2 */ + BPC3_PF2OF1 | BPC3_PF2OF0 | BPC3_SPRES1 | BPC3_SPRES0 | + BPC3_BRDRBLNK | BPC3_EXTBLKEN, /* bplcon3 */ + 0x0091, /* htotal */ + 0x000a, /* hsstrt */ + 0x0013, /* hsstop */ + 0x0001, /* hbstrt */ + 0x001e, /* hbstop */ + 0x0156, /* vtotal */ + 0x0009, /* vsstrt */ + 0x0012, /* vsstop */ + 0x0000, /* vbstrt */ + 0x001c, /* vbstop */ + 0x0052, /* hcenter */ + BMC0_VARVBEN | BMC0_LOLDIS | BMC0_VARVSYEN | + BMC0_VARHSYEN | BMC0_VARBEAMEN | BMC0_BLANKEN, + /* beamcon0 */ + FMODE_BPAGEM | FMODE_BPL32 /* fmode */ + }, + /* Super 72 lace - 800x600 72Hz interlaced mode. */ + { + "super72-lace", 0, + BPC0_SHRES | BPC0_LACE | BPC0_ECSENA, /* bplcon0 */ + 800, 600, 1, /* need rows%8 == 0 */ + 800, 600, /* (cols too) */ + 0x0051, 0x0021, /* diwstrt h,v */ + 64, /* 64-bit aligned */ + BPC2_KILLEHB, /* bplcon2 */ + BPC3_PF2OF1 | BPC3_PF2OF0 | BPC3_SPRES1 | BPC3_SPRES0 | + BPC3_BRDRBLNK | BPC3_EXTBLKEN, + /* bplcon3 */ + 0x0091, /* htotal */ + 0x000a, /* hsstrt */ + 0x0013, /* hsstop */ + 0x0001, /* hbstrt */ + 0x001e, /* hbstop */ + 0x0150, /* vtotal */ + 0x0009, /* vsstrt */ + 0x0012, /* vsstop */ + 0x0000, /* vbstrt */ + 0x001c, /* vbstop */ + 0x0052, /* hcenter */ + BMC0_VARVBEN | BMC0_LOLDIS | BMC0_VARVSYEN | + BMC0_VARHSYEN | BMC0_VARBEAMEN | BMC0_BLANKEN, + /* beamcon0 */ + FMODE_BPAGEM | FMODE_BPL32 /* fmode */ + }, + /* DblNtsc - 640x400 59Hz noninterlaced mode. */ + { + "dblntsc", 0, + BPC0_SHRES | BPC0_ECSENA, /* bplcon0 */ + 640, 400, 1, /* need rows%8 == 0 */ + 640, 400, /* (cols too) */ + 0x0049, 0x0021, /* diwstrt h,v */ + 64, /* 64-bit aligned */ + BPC2_KILLEHB, /* bplcon2 */ + BPC3_PF2OF1 | BPC3_PF2OF0 | BPC3_SPRES1 | BPC3_SPRES0 | + BPC3_BRDRBLNK | BPC3_EXTBLKEN, + /* bplcon3 */ + 0x0079, /* htotal */ + 0x0007, /* hsstrt */ + 0x0013, /* hsstop */ + 0x0001, /* hbstrt */ + 0x001e, /* hbstop */ + 0x01ec, /* vtotal */ + 0x0008, /* vsstrt */ + 0x0010, /* vsstop */ + 0x0000, /* vbstrt */ + 0x0019, /* vbstop */ + 0x0046, /* hcenter */ + BMC0_VARVBEN | BMC0_LOLDIS | BMC0_VARVSYEN | + BMC0_VARHSYEN | BMC0_VARBEAMEN | BMC0_BLANKEN, + /* beamcon0 */ + FMODE_BPAGEM | FMODE_BPL32 /* fmode */ + }, + /* DblPal - 640x512 52Hz noninterlaced mode. */ + { + "dblpal", 0, + BPC0_SHRES | BPC0_ECSENA, /* bplcon0 */ + 640, 512, 1, /* need rows%8 == 0 */ + 640, 512, /* (cols too) */ + 0x0049, 0x0021, /* diwstrt h,v */ + 64, /* 64-bit aligned */ + BPC2_KILLEHB, /* bplcon2 */ + BPC3_PF2OF1 | BPC3_PF2OF0 | BPC3_SPRES1 | BPC3_SPRES0 | + BPC3_BRDRBLNK | BPC3_EXTBLKEN, + /* bplcon3 */ + 0x0079, /* htotal */ + 0x0007, /* hsstrt */ + 0x0013, /* hsstop */ + 0x0001, /* hbstrt */ + 0x001e, /* hbstop */ + 0x0234, /* vtotal */ + 0x0008, /* vsstrt */ + 0x0010, /* vsstop */ + 0x0000, /* vbstrt */ + 0x0019, /* vbstop */ + 0x0046, /* hcenter */ + BMC0_VARVBEN | BMC0_LOLDIS | BMC0_VARVSYEN | + BMC0_VARHSYEN | BMC0_VARBEAMEN | BMC0_BLANKEN, + /* beamcon0 */ + FMODE_BPAGEM | FMODE_BPL32 /* fmode */ + }, + /* Euro72 - productivity - 640x400 71Hz noninterlaced mode. */ + { + "euro72", 0, + BPC0_SHRES | BPC0_ECSENA, /* bplcon0 */ + 640, 400, 1, /* need rows%8 == 0 */ + 640, 400, /* (cols too) */ + 0x0041, 0x0021, /* diwstrt h,v */ + 64, /* 64-bit aligned */ + BPC2_KILLEHB, /* bplcon2 */ + BPC3_PF2OF1 | BPC3_PF2OF0 | BPC3_SPRES1 | BPC3_SPRES0 | + BPC3_BRDRBLNK | BPC3_EXTBLKEN, + /* bplcon3 */ + 0x0071, /* htotal */ + 0x0009, /* hsstrt */ + 0x0013, /* hsstop */ + 0x0001, /* hbstrt */ + 0x001e, /* hbstop */ + 0x01be, /* vtotal */ + 0x0008, /* vsstrt */ + 0x0016, /* vsstop */ + 0x0000, /* vbstrt */ + 0x001f, /* vbstop */ + 0x0041, /* hcenter */ + BMC0_VARVBEN | BMC0_LOLDIS | BMC0_VARVSYEN | + BMC0_VARHSYEN | BMC0_VARBEAMEN | BMC0_BLANKEN, + /* beamcon0 */ + FMODE_BPAGEM | FMODE_BPL32 /* fmode */ + }, + /* AGA modes */ + { + /* + * A 640x480, 60Hz noninterlaced AGA mode. It would be nice to be + * able to have some of these values computed dynamically, but that + * requires more knowledge of AGA than I have. At the moment, + * the values make it centered on my 1960 monitor. -wjr + * + * For random reasons to do with the way arguments are parsed, + * these names can't start with a digit. + * + * Don't count on being able to reduce scr_width and scr_height + * and ending up with a smaller but well-formed screen - this + * doesn't seem to work well at the moment. + */ + "aga640x480", 0, + BPC0_SHRES | BPC0_ECSENA, /* bplcon0 */ + 640, 480, 1, + 640, 480, + 0x0041, 0x002b, /* diwstrt h,v */ + 64, /* 64-bit aligned */ + BPC2_KILLEHB, /* bplcon2 */ + BPC3_PF2OF1 | BPC3_PF2OF0 | BPC3_SPRES1 | BPC3_SPRES0 | + BPC3_BRDRBLNK | BPC3_EXTBLKEN, /* bplcon3 */ + 0x0071, /* htotal */ + 0x000c, /* hsstrt */ + 0x001c, /* hsstop */ + 0x0008, /* hbstrt */ + 0x001e, /* hbstop */ + 0x020c, /* vtotal */ + 0x0001, /* vsstrt */ + 0x0003, /* vsstop */ + 0x0000, /* vbstrt */ + 0x000f, /* vbstop */ + 0x0046, /* hcenter */ + BMC0_HARDDIS | BMC0_VARVBEN | BMC0_LOLDIS | BMC0_VARVSYEN | + BMC0_VARHSYEN | BMC0_VARBEAMEN | BMC0_BLANKEN, /* beamcon0 */ + FMODE_BPAGEM | FMODE_BPL32 /* fmode */ + }, { + /* An 800x600 72Hz interlaced mode. */ + "aga800x600", 0, + BPC0_SHRES | BPC0_LACE | BPC0_ECSENA, /* bplcon0 */ + 896, 624, 1, /* need rows%8 == 0 */ + 896, 624, /* (cols too) */ + 0x0041, 0x001e, /* diwstrt h,v */ + 64, /* 64-bit aligned */ + BPC2_KILLEHB, /* bplcon2 */ + BPC3_PF2OF1 | BPC3_PF2OF0 | BPC3_SPRES1 | BPC3_SPRES0 | + BPC3_BRDRBLNK | BPC3_EXTBLKEN, /* bplcon3 */ + 0x0091, /* htotal */ + 0x000e, /* hsstrt */ + 0x001d, /* hsstop */ + 0x000a, /* hbstrt */ + 0x001e, /* hbstop */ + 0x0156, /* vtotal */ + 0x0001, /* vsstrt */ + 0x0003, /* vsstop */ + 0x0000, /* vbstrt */ + 0x000f, /* vbstop */ + 0x0050, /* hcenter */ + BMC0_HARDDIS | BMC0_VARVBEN | BMC0_LOLDIS | BMC0_VARVSYEN | + BMC0_VARHSYEN | BMC0_VARBEAMEN | BMC0_BLANKEN, /* beamcon0 */ + FMODE_BPAGEM | FMODE_BPL32 /* fmode */ + }, + /* + * Additional AGA modes by Geert Uytterhoeven + */ + { + /* + * A 720x400, 70 Hz noninterlaced AGA mode (29.27 kHz) + */ + "aga720x400", 0, + BPC0_SHRES | BPC0_ECSENA, /* bplcon0 */ + 720, 400, 1, + 720, 400, + 0x0041, 0x0013, /* diwstrt h,v */ + 64, /* 64-bit aligned */ + BPC2_KILLEHB, /* bplcon2 */ + BPC3_PF2OF1 | BPC3_PF2OF0 | BPC3_SPRES1 | BPC3_SPRES0 | + BPC3_BRDRBLNK | BPC3_EXTBLKEN, /* bplcon3 */ + 0x0079, /* htotal */ + 0x000e, /* hsstrt */ + 0x0018, /* hsstop */ + 0x0001, /* hbstrt */ + 0x0021, /* hbstop */ + 0x01a2, /* vtotal */ + 0x0003, /* vsstrt */ + 0x0005, /* vsstop */ + 0x0000, /* vbstrt */ + 0x0012, /* vbstop */ + 0x0046, /* hcenter */ + BMC0_VARVBEN | BMC0_LOLDIS | BMC0_VARVSYEN | BMC0_VARHSYEN | + BMC0_VARBEAMEN | BMC0_PAL | BMC0_VARCSYEN | BMC0_CSYTRUE | + BMC0_VSYTRUE, /* beamcon0 */ + FMODE_BPAGEM | FMODE_BPL32 /* fmode */ + }, { + /* + * A 640x400, 76 Hz noninterlaced AGA mode (31.89 kHz) + */ + "aga640x400", 0, + BPC0_SHRES | BPC0_ECSENA, /* bplcon0 */ + 640, 400, 1, + 640, 400, + 0x0041, 0x0015, /* diwstrt h,v */ + 64, /* 64-bit aligned */ + BPC2_KILLEHB, /* bplcon2 */ + BPC3_PF2OF1 | BPC3_PF2OF0 | BPC3_SPRES1 | BPC3_SPRES0 | + BPC3_BRDRBLNK | BPC3_EXTBLKEN, /* bplcon3 */ + 0x006f, /* htotal */ + 0x000d, /* hsstrt */ + 0x0018, /* hsstop */ + 0x0001, /* hbstrt */ + 0x0021, /* hbstop */ + 0x01a4, /* vtotal */ + 0x0003, /* vsstrt */ + 0x0005, /* vsstop */ + 0x0000, /* vbstrt */ + 0x0014, /* vbstop */ + 0x0046, /* hcenter */ + BMC0_VARVBEN | BMC0_LOLDIS | BMC0_VARVSYEN | BMC0_VARHSYEN | + BMC0_VARBEAMEN | BMC0_PAL | BMC0_VARCSYEN | BMC0_CSYTRUE | + BMC0_VSYTRUE, /* beamcon0 */ + FMODE_BPAGEM | FMODE_BPL32 /* fmode */ + }, { + /* + * A 640x480, 64 Hz noninterlaced AGA mode (31.89 kHz) + */ + "aga640x480a", 0, + BPC0_SHRES | BPC0_ECSENA, /* bplcon0 */ + 640, 480, 1, + 640, 480, + 0x0041, 0x0015, /* diwstrt h,v */ + 64, /* 64-bit aligned */ + BPC2_KILLEHB, /* bplcon2 */ + BPC3_PF2OF1 | BPC3_PF2OF0 | BPC3_SPRES1 | BPC3_SPRES0 | + BPC3_BRDRBLNK | BPC3_EXTBLKEN, /* bplcon3 */ + 0x006f, /* htotal */ + 0x000e, /* hsstrt */ + 0x0018, /* hsstop */ + 0x0001, /* hbstrt */ + 0x0021, /* hbstop */ + 0x01f4, /* vtotal */ + 0x0003, /* vsstrt */ + 0x0005, /* vsstop */ + 0x0000, /* vbstrt */ + 0x0014, /* vbstop */ + 0x0046, /* hcenter */ + BMC0_VARVBEN | BMC0_LOLDIS | BMC0_VARVSYEN | BMC0_VARHSYEN | + BMC0_VARBEAMEN | BMC0_PAL | BMC0_VARCSYEN | BMC0_CSYTRUE | + BMC0_VSYTRUE, /* beamcon0 */ + FMODE_BPAGEM | FMODE_BPL32 /* fmode */ + } +}; + +#define NMODES (sizeof(mono_modes) / sizeof(struct geometry)) + +static struct fb_var_screeninfo mono_mono_amiga_fb_predefined[] = { + { /* autodetect */ + 0, 0, 0, 0, 0, 0, 0, 0, /* xres-grayscale */ + {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, /* red green blue tran*/ + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 } +}; + +static int mono_num_mono_amiga_fb_predefined= sizeof(mono_mono_amiga_fb_predefined)/sizeof(struct fb_var_screeninfo); + + + +/* Some default modes */ +#define OCS_PAL_LOWEND_DEFMODE 5 /* PAL non-laced for 500/2000 */ +#define OCS_PAL_3000_DEFMODE 4 /* PAL laced for 3000 */ +#define OCS_NTSC_LOWEND_DEFMODE 1 /* NTSC non-laced for 500/2000 */ +#define OCS_NTSC_3000_DEFMODE 0 /* NTSC laced for 3000 */ +#define AGA_DEFMODE 8 /* 640x480 non-laced for AGA */ + +static int mono_amifb_inverse = 0; +static int mono_amifb_mode = -1; + +static void mono_video_setup (char *options, int *ints) +{ + char *this_opt; + int i; + + fb_info.fontname[0] = '\0'; + + if (!options || !*options) + return; + + for (this_opt = strtok(options,","); this_opt; this_opt = strtok(NULL,",")) + if (!strcmp (this_opt, "inverse")) + mono_amifb_inverse = 1; + else if (!strncmp(this_opt, "font:", 5)) + strcpy(fb_info.fontname, this_opt+5); + else + for (i = 0; i < NMODES; i++) + if (!strcmp(this_opt, mono_modes[i].modename)) { + mono_amifb_mode = i; + break; + } +} + +/* Notes about copper scrolling: + * + * 1. The VBLANK routine dynamically rewrites a LIVE copper list that is + * currently being executed. Don't mess with it unless you know the + * complications. Fairly sure that double buffered lists doesn't + * make our life any easier. + * + * 2. The vblank code starts executing at logical line 0. Display must be + * set up and ready to run by line DIWSTRT_V, typically 0x2c, minimum + * value is 0x18 for maximum overscan. + * + * Tests on my A500/030 for dynamically generating a 37 element copper + * list during the VBLANK period under AmigaDos required between + * 0x10 and 0x14 scanlines. This should be pathological case, and + * should do better under Linux/68k. It is however IMPERATIVE that I am + * first in the VBLANK isr chain. Try to keep 'buildclist' as fast as + * possible. Don't think that it justifies assembler thou' + * + * 3. PAL 640x256 display (no overscan) has copper-wait y positions in range + * 0x02c -> 0x12c. NTSC overscan uses values > 256 too. However counter + * is 8 bit, will wrap. RKM 1.1 suggests use of a WAIT(0x00,0xff), + * WAIT(x,y-0x100) pair to handle this case. This is WRONG - must use + * WAIT(0xe2,0xff) to ensure that wrap occures by next copper + * instruction. Argghh! + * + * 4. RKM 1.1 suggests Copper-wait x positions are in range [0,0xe2]. + * Horizontal blanking occurs in range 0x0f -> 0x35. Black screen + * shown in range 0x04 -> 0x47. + * + * Experiments suggest that using WAIT(0x00,y), we can replace up to + * 7 bitplane pointers before display fetch start. Using a + * WAIT(0xe0,y-1) instead, we can replace 8 pointers that should be + * all that we need for a full AGA display. Should work because of + * fetch latency with bitmapped display. + * + * I think that this works. Someone please tell me if something breaks. + * + * Is diwstop_h the right value to use for "close to the end of line"? + * It seems to work for me, at least for the modes I've defined. -wjr + * + * I changed the Wait(diwstop_h, 0xff) for 256-line chunk skipping to + * Wait(diwstop_h-2, 0xff) to make it work with the additional + * `get-all-you-can-get-out-of-it' AGA modes. Maybe we should derive the + * wait position from the HTOTAL value? - G.U. + * + * The Wait(diwstop_h-2, 0xff) didn't work in Super72 under ECS, instead + * I changed it to Wait(htotal-4, 0xff). Dunno whether it works under AGA, + * and don't ask my why it works. I'm trying to get some facts on this issue + * from Commodore. + * -Jes + */ + +static __inline__ ushort *mono_build_clist_hdr(register struct display *p, + ushort *cop, + ushort *othercop) /* Interlace: List for next frame */ +{ + int i; + ushort diwstrt_v = mono_current_par.diwstrt_v; + ushort diwstop_h = mono_current_par.diwstop_h; + + if (othercop) { + *cop++ = CUSTOM_OFS(cop1lc); + *cop++ = (long)othercop >> 16; + *cop++ = CUSTOM_OFS(cop1lc) + 2; + *cop++ = (long)othercop; + } + + /* Point Sprite 0 at cursor sprite: */ + *cop++ = CUSTOM_OFS(sprpt[0]); + *cop++ = (ushort)((long)mono_current_par.cursor >> 16); + *cop++ = CUSTOM_OFS(sprpt[0]) + 2; + *cop++ = (ushort)((long)mono_current_par.cursor & 0x0000ffff); + + /* Point Sprites 1-7 at dummy sprite: */ + for (i=1; i<8; i++) { + *cop++ = CUSTOM_OFS(sprpt[i]); + *cop++ = (ushort)((long)mono_current_par.dummy >> 16); + *cop++ = CUSTOM_OFS(sprpt[i]) + 2; + *cop++ = (ushort)((long)mono_current_par.dummy & 0x0000ffff); + } + + /* Halt copper until we have rebuilt the display list */ + + *cop++ = ((diwstrt_v - 2) << 8) | (diwstop_h >> 1) | 0x1; + *cop++ = 0xfffe; + + return(cop); +} + +static __inline__ ushort *mono_build_clist_dyn(register struct display *p, + ushort *cop, + int shf) /* Interlace: Short frame */ +{ + ushort diwstrt_v = mono_current_par.diwstrt_v; + ushort diwstop_h = mono_current_par.diwstop_h; + ushort y_wrap = mono_current_par.y_wrap; + ulong offset = y_wrap * mono_current_par.bytes_per_row; + long scrmem; + int i; + + /* Set up initial bitplane ptrs */ + + for (i = 0 ; i < mono_current_par.scr_depth ; i++) { + scrmem = ((long)mono_current_par.bitplane[i]) + offset; + + if (shf) + scrmem += mono_current_par.bytes_per_row; + + *cop++ = CUSTOM_OFS(bplpt[i]); + *cop++ = (long)scrmem >> 16; + *cop++ = CUSTOM_OFS(bplpt[i]) + 2; + *cop++ = (long)scrmem; + } + + /* If wrapped frame needed - wait for line then switch bitplXs */ + + if (y_wrap) { + ushort line; + + if (mono_current_par.bplcon0 & BPC0_LACE) + line = diwstrt_v + (mono_current_par.scr_height - y_wrap)/2; + else + line = diwstrt_v + mono_current_par.scr_height - y_wrap; + + /* Handle skipping over 256-line chunks */ + while (line > 256) { + /* Hardware limitation - 8 bit counter */ + /* Wait(diwstop_h-2, 0xff) */ + if (mono_current_par.bplcon0 & BPC0_SHRES) + /* + * htotal-4 is used in SHRES-mode, as diwstop_h-2 doesn't work under ECS. + * Does this work under AGA? + * -Jes + */ + *cop++ = 0xff00 | ((mono_current_par.htotal-4) | 1); + else + *cop++ = 0xff00 | ((diwstop_h-2) >> 1) | 0x1; + + *cop++ = 0xfffe; + /* Wait(0, 0) - make sure we're in the new segment */ + *cop++ = 0x0001; + *cop++ = 0xfffe; + line -= 256; + + /* + * Under ECS we have to keep color[0], as it is part of a special color-table. + */ + + if (boot_info.bi_amiga.chipset == CS_ECS && mono_current_par.bplcon0 & BPC0_ECSENA) { + *cop++ = 0x0180; + *cop++ = mono_ecs_color_zero; + } + } + + /* Wait(diwstop_h, line - 1) */ + *cop++ = ((line - 1) << 8) | (diwstop_h >> 1) | 0x1; + *cop++ = 0xfffe; + + for (i = 0 ; i < mono_current_par.scr_depth ; i++) { + scrmem = (long)mono_current_par.bitplane[i]; + if (shf) + scrmem += mono_current_par.bytes_per_row; + + *cop++ = CUSTOM_OFS(bplpt[i]); + *cop++ = (long)scrmem >> 16; + *cop++ = CUSTOM_OFS(bplpt[i]) + 2; + *cop++ = (long)scrmem; + } + } + + /* End of Copper list */ + *cop++ = 0xffff; + *cop++ = 0xfffe; + + return(cop); +} + + +static __inline__ void mono_build_cursor(register struct display *p) +{ + int vs, hs, ve; + ushort diwstrt_v = mono_current_par.diwstrt_v; + ushort diwstrt_h = mono_current_par.diwstrt_h; + + if (mono_current_par.bplcon0 & BPC0_LACE) { + vs = diwstrt_v + (p->cursor_y * p->fontheight)/2; + ve = vs + p->fontheight/2; + } else { + vs = diwstrt_v + (p->cursor_y * p->fontheight); + ve = vs + p->fontheight; + } + + if (mono_current_par.bplcon0 & BPC0_ECSENA) + /* + * It's an AGA mode. We'll assume that the sprite was set + * into 35ns resolution by the appropriate SPRES bits in bplcon3. + */ + hs = diwstrt_h * 4 + (p->cursor_x * p->fontwidth) - 4; + else + hs = diwstrt_h + (p->cursor_x * p->fontwidth) / 2 - 1; + + if (mono_current_par.bplcon0 & BPC0_ECSENA) { + /* There are some high-order bits on the sprite position */ + *((ulong *) mono_current_par.cursor) = + ((((vs & 0xff) << 24) | ((vs & 0x100) >> 6) | + ((vs & 0x200) >> 3)) | + (((hs & 0x7f8) << 13) | ((hs & 0x4) >> 2) | + ((hs & 0x3) << 3)) | + (((ve & 0xff) << 8) | ((ve & 0x100) >> 7) | + ((ve & 0x200) >> 4))); + } else { + *((ulong *) mono_current_par.cursor) = + ((vs << 24) | ((vs & 0x00000100) >> 6) | + ((hs & 0x000001fe) << 15) | (hs & 0x00000001) | + ((ve & 0x000000ff) << 8) | ((ve & 0x00000100) >> 7)); + } +} + +static void mono_build_ecs_colors(ushort color1, ushort color2, ushort color3, + ushort color4, ushort *table) +{ +/* + * This function calculates the special ECS color-tables needed when running + * new screen-modes available under ECS. See the hardware reference manual + * 3rd edition for details. + * -Jes + */ +ushort t; + + t = (color1 & 0x0ccc); + table[0] = t; + table[4] = t; + table[8] = t; + table[12] = t; + t = t >> 2; + table[0] = (table[0] | t); + table[1] = t; + table[2] = t; + table[3] = t; + + t = (color2 & 0x0ccc); + table[1] = (table[1] | t); + table[5] = t; + table[9] = t; + table[13] = t; + t = t >> 2; + table[4] = (table[4] | t); + table[5] = (table[5] | t); + table[6] = t; + table[7] = t; + + t = (color3 & 0x0ccc); + table[2] = (table[2] | t); + table[6] = (table[6] | t); + table[10] = t; + table[14] = t; + t = t >> 2; + table[8] = (table[8] | t); + table[9] = (table[9] | t); + table[10] = (table[10] | t); + table[11] = t; + + t = (color4 & 0x0ccc); + table[3] = (table[3] | t); + table[7] = (table[7] | t); + table[11] = (table[11] | t); + table[15] = t; + t = t >> 2; + table[12] = (table[12] | t); + table[13] = (table[13] | t); + table[14] = (table[14] | t); + table[15] = (table[15] | t); + +} + +/* mono_display_init(): + * + * Fills out (struct display *) given a geometry structure + */ + +static void mono_display_init(struct display *p, + struct geometry *geom, ushort inverse) +{ + ushort ecs_table[16]; + int i; + char *chipptr; + ushort diwstrt_v, diwstop_v; + ushort diwstrt_h, diwstop_h; + ushort diw_min_h, diw_min_v; + ushort bplmod, diwstrt, diwstop, diwhigh, ddfstrt, ddfstop; + ushort cursorheight, cursormask = 0; + u_long size; + + /* Decide colour scheme */ + + if (inverse) { + mono_current_par.fgcol = FG_COLOR_INV; + mono_current_par.bgcol = BG_COLOR_INV; + mono_current_par.crsrcol = CRSR_COLOR_INV; + } else { + mono_current_par.fgcol = FG_COLOR; + mono_current_par.bgcol = BG_COLOR; + mono_current_par.crsrcol = CRSR_COLOR; + } + + /* Define screen geometry */ + + mono_current_par.scr_max_height = geom->scr_max_height; + mono_current_par.scr_max_width = geom->scr_max_width; + mono_current_par.scr_height = geom->scr_height; + mono_current_par.scr_width = geom->scr_width; + mono_current_par.scr_depth = geom->scr_depth; + mono_current_par.bplcon0 = geom->bplcon0 | BPC0_COLOR; + mono_current_par.htotal = geom->htotal; + + /* htotal was added, as I use it to calc the pal-line. -Jes */ + + if (mono_current_par.scr_depth < 8) + mono_current_par.bplcon0 |= (mono_current_par.scr_depth << 12); + else { + /* must be exactly 8 */ + mono_current_par.bplcon0 |= BPC0_BPU3; + } + + diw_min_v = geom->diwstrt_v; + diw_min_h = geom->diwstrt_h; + + /* We can derive everything else from this, at least for OCS */ + /* + * For AGA: we don't use the finer position control available for + * diw* yet (could be set by 35ns increments). + */ + + /* Calculate line and plane size while respecting the alignment restrictions */ + mono_current_par.bytes_per_row = ((mono_current_par.scr_width+geom->alignment-1)&~(geom->alignment-1)) >> 3; + mono_current_par.plane_size = mono_current_par.bytes_per_row * mono_current_par.scr_height; + + + /* + * Quick hack for frame buffer mmap(): + * + * plane_size must be a multiple of the page size + */ + + mono_current_par.plane_size = PAGE_ALIGN(mono_current_par.plane_size); + + + mono_current_par.y_wrap = 0; mono_current_par.scroll_latch = 1; + p->cursor_x = 0; p->cursor_y = 0; mono_current_par.cursor_latch = 1; + + if (mono_current_par.bplcon0 & BPC0_LACE) { + bplmod = mono_current_par.bytes_per_row; + diwstrt_v = diw_min_v + (mono_current_par.scr_max_height - mono_current_par.scr_height)/4; + diwstop_v = (diwstrt_v + mono_current_par.scr_height/2); + } else { + bplmod = 0; + diwstrt_v = diw_min_v + (mono_current_par.scr_max_height - mono_current_par.scr_height)/2; + diwstop_v = (diwstrt_v + mono_current_par.scr_height); + } + + if (mono_current_par.bplcon0 & BPC0_HIRES) { + diwstrt_h = diw_min_h + (mono_current_par.scr_max_width - mono_current_par.scr_width)/4; + diwstop_h = (diwstrt_h + mono_current_par.scr_width/2); + /* ??? Where did 0x1d5 come from in original code ??? */ + } else if (mono_current_par.bplcon0 & BPC0_SHRES) { + diwstrt_h = diw_min_h + (mono_current_par.scr_max_width - mono_current_par.scr_width)/8; + diwstop_h = (diwstrt_h + mono_current_par.scr_width/4); + } else { + diwstrt_h = diw_min_h + (mono_current_par.scr_max_width - mono_current_par.scr_width)/2; + diwstop_h = (diwstrt_h + mono_current_par.scr_width); + } + + if (mono_current_par.bplcon0 & BPC0_HIRES) { + ddfstrt = (diwstrt_h >> 1) - 4; + ddfstop = ddfstrt + (4 * (mono_current_par.bytes_per_row>>1)) - 8; + } else if (mono_current_par.bplcon0 & BPC0_SHRES && boot_info.bi_amiga.chipset == CS_AGA) { + /* There may be some interaction with FMODE here... -8 is magic. */ + + /* + * This should be fixed, so it supports all different + * FMODE's. FMODE varies the speed with 1,2 & 4 the + * standard ECS speed. Someone else has to do it, as + * I don't have an AGA machine with MMU available + * here. + * + * This particular speed looks like FMODE = 3 to me. + * ddfstop should be changed so it depends on FMODE under AGA. + * -Jes + */ + ddfstrt = (diwstrt_h >> 1) - 8; + ddfstop = ddfstrt + (2 * (mono_current_par.bytes_per_row>>1)) - 8; + } else if (mono_current_par.bplcon0 & BPC0_SHRES && boot_info.bi_amiga.chipset == CS_ECS){ + /* + * Normal speed for ECS, should be the same for FMODE = 0 + * -Jes + */ + ddfstrt = (diwstrt_h >> 1) - 2; + ddfstop = ddfstrt + (2 * (mono_current_par.bytes_per_row>>1)) - 8; + } else { + ddfstrt = (diwstrt_h >> 1) - 8; + ddfstop = ddfstrt + (8 * (mono_current_par.bytes_per_row>>1)) - 8; + } + + if (mono_current_par.bplcon0 & BPC0_LACE) + cursorheight = p->fontheight/2; + else + cursorheight = p->fontheight; + + /* + * Quick hack for frame buffer mmap(): + * + * chipptr must be at a page boundary + */ + + size = mono_current_par.scr_depth*mono_current_par.plane_size+COP_MEM_REQ+SPR_MEM_REQ+4*(cursorheight-1); + size += PAGE_SIZE-1; + chipptr = amiga_chip_alloc(size); + chipptr = (char *)PAGE_ALIGN((u_long)chipptr); + + + /* locate the bitplanes */ + /* These MUST be 64 bit aligned for full AGA compatibility!! */ + + mono_current_par.smem_start = (u_long)chipptr; + mono_current_par.smem_len = mono_current_par.plane_size*mono_current_par.scr_depth; + mono_current_par.geometry = geom; + + for (i = 0 ; i < mono_current_par.scr_depth ; i++, chipptr += mono_current_par.plane_size) { + mono_current_par.bitplane[i] = (u_char *) chipptr; + memset ((void *)chipptr, 0, mono_current_par.plane_size); /* and clear */ + } + + /* locate the copper lists */ + mono_current_par.coplist1hdr = (ushort *) chipptr; chipptr += MAX_COP_LIST_ENTS * 4; + mono_current_par.coplist2hdr = (ushort *) chipptr; chipptr += MAX_COP_LIST_ENTS * 4; + + /* locate the sprite data */ + mono_current_par.cursor = (ushort *) chipptr; chipptr += 8+4*cursorheight; + mono_current_par.dummy = (ushort *) chipptr; chipptr += 12; + + /* create the sprite data for the cursor image */ + memset((void *)mono_current_par.cursor, 0, 8+4*cursorheight); + /* + * Only AGA supplies hires sprites. + */ + if (mono_current_par.bplcon0 & BPC0_ECSENA && boot_info.bi_amiga.chipset == CS_AGA) + /* AGA cursor is SHIRES, ECS sprites differ */ + for (i = 0; (i < p->fontwidth) && (i < 16); i++) + cursormask |= 1<<(15-i); + else + /* For OCS & ECS sprites are pure LORES 8-< */ + for (i = 0; (i < p->fontwidth/2) && (i < 8); i++) + cursormask |= 1<<(15-i); + + mono_current_par.cursor[0] = mono_cursor_data[0]; + mono_current_par.cursor[1] = mono_cursor_data[1]; + +#if (CRSR_BLOCK == 1) + for (i = 0; i < cursorheight; i++) +#else + for (i = cursorheight-2; i < cursorheight; i++) +#endif + mono_current_par.cursor[2+2*i] = cursormask; + + /* set dummy sprite data to a blank sprite */ + memset((void *)mono_current_par.dummy, 0, 12); + + /* set cursor flashing */ + mono_current_par.cursor_flash = CRSR_FLASH; + + /* Make the cursor invisible */ + mono_current_par.cursor_visible = 0; + + /* Initialise the chipregs */ + mono_current_par.diwstrt_v = diwstrt_v; + mono_current_par.diwstrt_h = diwstrt_h; + mono_current_par.diwstop_v = diwstop_v; + mono_current_par.diwstop_h = diwstop_h; + diwstrt = ((diwstrt_v << 8) | diwstrt_h); + diwstop = ((diwstop_v & 0xff) << 8) | (diwstop_h & 0xff); + + custom.bplcon0 = mono_current_par.bplcon0; /* set the display mode */ + custom.bplcon1 = 0; /* Needed for horizontal scrolling */ + custom.bplcon2 = 0; + custom.bpl1mod = bplmod; + custom.bpl2mod = bplmod; + custom.diwstrt = diwstrt; + custom.diwstop = diwstop; + custom.ddfstrt = ddfstrt; + custom.ddfstop = ddfstop; + + custom.color[0] = COLOR_MSB(mono_current_par.bgcol); + custom.color[1] = COLOR_MSB(mono_current_par.fgcol); + custom.color[17] = COLOR_MSB(mono_current_par.crsrcol); /* Sprite 0 color */ + + if (boot_info.bi_amiga.chipset == CS_AGA) { + /* Fill in the LSB of the 24 bit color palette */ + /* Must happen after MSB */ + custom.bplcon3 = geom->bplcon3 | BPC3_LOCT; + custom.color[0] = COLOR_LSB(mono_current_par.bgcol); + custom.color[1] = COLOR_LSB(mono_current_par.fgcol); + custom.color[17] = COLOR_LSB(mono_current_par.crsrcol); + custom.bplcon3 = geom->bplcon3; + } + + if (boot_info.bi_amiga.chipset == CS_ECS && mono_current_par.bplcon0 & BPC0_ECSENA) { + /* + * Calculation of the special ECS color-tables for + * planes and sprites is done in the function + * build_ecs_table + */ + + /* + * Calcs a special ECS colortable for the bitplane, + * and copies it to the custom registers + */ + mono_build_ecs_colors(COLOR_MSB(mono_current_par.bgcol), COLOR_MSB(mono_current_par.fgcol), + 0, 0, ecs_table); + +#if 0 + for (i = 0; i < 8; i++){ + custom.color[i] = ecs_table[i*2]; + custom.color[i+8] = ecs_table[i*2+1]; + } +#else + for (i = 0; i < 16; i++){ + custom.color[i] = ecs_table[i]; + } +#endif + + mono_ecs_color_zero = ecs_table[0]; + + /* + * Calcs a special ECS colortable for the cursor + * sprite, and copies it to the appropriate custom + * registers + */ + mono_build_ecs_colors(0, COLOR_MSB(mono_current_par.crsrcol), 0, 0, ecs_table); + + for (i = 0; i < 16; i++){ + custom.color[i+16] = ecs_table[i]; + } + } + + if (!(geom->isOCS)) { + /* Need to set up a bunch more regs */ + /* Assumes that diwstrt is in the (0,0) sector, but stop might not be */ + diwhigh = (diwstop_v & 0x700) | ((diwstop_h & 0x100) << 5); + + custom.bplcon2 = geom->bplcon2; + custom.bplcon3 = geom->bplcon3; + /* save bplcon3 for blanking */ + mono_save_bplcon3 = geom->bplcon3; + + custom.diwhigh = diwhigh; /* must happen AFTER diwstrt, stop */ + + custom.htotal = geom->htotal; + custom.hsstrt = geom->hsstrt; + custom.hsstop = geom->hsstop; + custom.hbstrt = geom->hbstrt; + custom.hbstop = geom->hbstop; + custom.vtotal = geom->vtotal; + custom.vsstrt = geom->vsstrt; + custom.vsstop = geom->vsstop; + custom.vbstrt = geom->vbstrt; + custom.vbstop = geom->vbstop; + custom.hcenter = geom->hcenter; + custom.beamcon0 = geom->beamcon0; + if (boot_info.bi_amiga.chipset == CS_AGA) { + custom.fmode = geom->fmode; + } + /* + * fmode does NOT! exist under ECS, weird things might happen + */ + + /* We could load 8-bit colors here, if we wanted */ + + /* + * The minimum period for audio depends on htotal (for OCS/ECS/AGA) + */ + if (boot_info.bi_amiga.chipset != CS_STONEAGE) + amiga_audio_min_period = (geom->htotal>>1)+1; + } + + + /* Build initial copper lists. sprites must be set up, and mono_current_par.diwstrt. */ + + if (mono_current_par.bplcon0 & BPC0_LACE) { + mono_current_par.coplist1dyn = mono_build_clist_hdr(p,mono_current_par.coplist1hdr, mono_current_par.coplist2hdr), + mono_build_clist_dyn(p, mono_current_par.coplist1dyn, 0); + + mono_current_par.coplist2dyn = mono_build_clist_hdr(p,mono_current_par.coplist2hdr, mono_current_par.coplist1hdr), + mono_build_clist_dyn(p, mono_current_par.coplist2dyn, 1); + } else { + mono_current_par.coplist1dyn = mono_build_clist_hdr(p,mono_current_par.coplist1hdr, NULL), + mono_build_clist_dyn(p, mono_current_par.coplist1dyn, 0); + } + + + /* Get ready to run first copper list */ + custom.cop1lc = mono_current_par.coplist1hdr; + custom.copjmp1 = 0; + + /* turn on DMA for bitplane and sprites */ + custom.dmacon = DMAF_SETCLR | DMAF_RASTER | DMAF_COPPER | DMAF_SPRITE; + + if (mono_current_par.bplcon0 & BPC0_LACE) { + /* Make sure we get the fields in the right order */ + + /* wait for LOF frame bit to go low */ + while (custom.vposr & 0x8000) + ; + + /* wait for LOF frame bit to go high */ + while (!(custom.vposr & 0x8000)) + ; + + /* start again at the beginning of copper list 1 */ + custom.cop1lc = mono_current_par.coplist1hdr; + custom.copjmp1 = 0; + } +} + + +static void mono_amifb_interrupt(int irq, struct pt_regs *fp, void *data) +{ + register struct display *p = disp; + + static ushort cursorcount = 0; + static ushort cursorstate = 0; + + /* I *think* that you should only change display lists on long frame. + * At least it goes awfully perculiar on my A500 without the following + * test. Not really in a position to test this hypothesis, so sorry + * for the slow scrolling, all you flicker-fixed souls + */ + + if (!(mono_current_par.bplcon0 & BPC0_LACE) || (custom.vposr & 0x8000)) { + if (mono_current_par.scroll_latch || mono_current_par.cursor_latch) + mono_build_cursor(p); + + if (mono_current_par.scroll_latch) + if (mono_current_par.bplcon0 & BPC0_LACE) { + mono_build_clist_dyn(p, mono_current_par.coplist1dyn, 0); + mono_build_clist_dyn(p, mono_current_par.coplist2dyn, 1); + } else + mono_build_clist_dyn(p, mono_current_par.coplist1dyn, 0); + mono_current_par.scroll_latch = 0; + mono_current_par.cursor_latch = 0; + } + + if (!(custom.potgor & (1<<10))) + mono_vblank.right_count++; + + if (mono_current_par.cursor_visible) { + if (mono_current_par.cursor_flash) { + if (cursorcount) + cursorcount--; + else { + cursorcount = CRSR_RATE; + if ((cursorstate = !cursorstate)) + custom.dmacon = DMAF_SETCLR | DMAF_SPRITE; + else + custom.dmacon = DMAF_SPRITE; + } + } + } else + custom.dmacon = DMAF_SPRITE; + + if (mono_do_blank) { + custom.dmacon = DMAF_RASTER | DMAF_SPRITE; + custom.color[0] = 0; + if (boot_info.bi_amiga.chipset == CS_AGA) { + /* Fill in the LSB of the 24 bit color palette */ + /* Must happen after MSB */ + custom.bplcon3 = mono_save_bplcon3 | BPC3_LOCT; + custom.color[0]= 0; + custom.bplcon3 = mono_save_bplcon3; + } + mono_do_blank = 0; + } + + if (mono_do_unblank) { + if (mono_current_par.cursor_visible) + custom.dmacon = DMAF_SETCLR | DMAF_RASTER | DMAF_SPRITE; + else + custom.dmacon = DMAF_SETCLR | DMAF_RASTER; + custom.color[0] = COLOR_MSB(mono_current_par.bgcol); + if (boot_info.bi_amiga.chipset == CS_AGA) { + /* Fill in the LSB of the 24 bit color palette */ + /* Must happen after MSB */ + custom.bplcon3 = mono_save_bplcon3 | BPC3_LOCT; + custom.color[0] = COLOR_LSB(mono_current_par.bgcol); + custom.bplcon3 = mono_save_bplcon3; + } + /* color[0] is set to mono_ecs_color_zero under ECS */ + if (boot_info.bi_amiga.chipset == CS_ECS && mono_current_par.bplcon0 & BPC0_ECSENA) { + custom.color[0] = mono_ecs_color_zero; + } + mono_do_unblank = 0; + } + + mono_vblank.done = 1; +} + + +static int mono_amiga_fb_get_fix(struct fb_fix_screeninfo *fix, int con) +{ + int i; + + strcpy(fix->id, mono_current_par.geometry->modename); + fix->smem_start = mono_current_par.smem_start; + fix->smem_len = mono_current_par.smem_len; + + /* + * Only monochrome bitmap at the moment + */ + + fix->type = FB_TYPE_PACKED_PIXELS; + + fix->type_aux = 0; + if (mono_amifb_inverse) + fix->visual = FB_VISUAL_MONO10; + else + fix->visual = FB_VISUAL_MONO01; + + fix->xpanstep = 0; + fix->ypanstep = 0; + fix->ywrapstep = 1; + + for (i = 0; i < arraysize(fix->reserved); i++) + fix->reserved[i] = 0; + return(0); +} + + +static int mono_amiga_fb_get_var(struct fb_var_screeninfo *var, int con) +{ + int i; + + var->xres = mono_current_par.geometry->scr_width; + var->yres = mono_current_par.geometry->scr_height; + var->xres_virtual = var->xres; + var->yres_virtual = var->yres; + var->xoffset = 0; + var->yoffset = 0; + + var->bits_per_pixel = mono_current_par.geometry->scr_depth; + var->grayscale = 0; + + if (boot_info.bi_amiga.chipset == CS_AGA) { + var->red.offset = 0; + var->red.length = 8; + var->red.msb_right = 0; + var->green = var->red; + var->blue = var->red; + } else { + var->red.offset = 0; + var->red.length = 4; + var->red.msb_right = 0; + var->green = var->red; + var->blue = var->red; + } + + var->nonstd = 0; + var->activate = 0; + + var->width = -1; + var->height = -1; + + var->accel = FB_ACCEL_NONE; + + var->pixclock = 35242; + var->left_margin = (mono_current_par.geometry->hbstop-mono_current_par.geometry->hsstrt)*8; + var->right_margin = (mono_current_par.geometry->hsstrt-mono_current_par.geometry->hbstrt)*8; + var->upper_margin = (mono_current_par.geometry->vbstop-mono_current_par.geometry->vsstrt)*8; + var->lower_margin = (mono_current_par.geometry->vsstrt-mono_current_par.geometry->vbstrt)*8; + var->hsync_len = (mono_current_par.geometry->hsstop-mono_current_par.geometry->hsstrt)*8; + var->vsync_len = (mono_current_par.geometry->vsstop-mono_current_par.geometry->vsstrt)*8; + var->sync = 0; + if (mono_current_par.geometry->bplcon0 & BPC0_LACE) + var->vmode = FB_VMODE_INTERLACED; + else if ((boot_info.bi_amiga.chipset == CS_AGA) && (mono_current_par.geometry->fmode & FMODE_BSCAN2)) + var->vmode = FB_VMODE_DOUBLE; + else + var->vmode = FB_VMODE_NONINTERLACED; + + for (i = 0; i < arraysize(var->reserved); i++) + var->reserved[i] = 0; + + return(0); +} + + +static void mono_amiga_fb_set_disp(int con) +{ + struct fb_fix_screeninfo fix; + + mono_amiga_fb_get_fix(&fix, con); + if (con == -1) + con = 0; + disp[con].screen_base = (u_char *)fix.smem_start; + disp[con].visual = fix.visual; + disp[con].type = fix.type; + disp[con].type_aux = fix.type_aux; + disp[con].ypanstep = fix.ypanstep; + disp[con].ywrapstep = fix.ywrapstep; + disp[con].can_soft_blank = 1; + disp[con].inverse = mono_amifb_inverse; +} + + +static int mono_amiga_fb_set_var(struct fb_var_screeninfo *var, int con) +{ + /* + * Not yet implemented + */ + return 0; /* The X server needs this */ + return(-EINVAL); +} + + +static short mono_red_normal[] = { + ((BG_COLOR & 0xff0000)>>8) | ((BG_COLOR & 0xff0000)>>16), + ((FG_COLOR & 0xff0000)>>8) | ((FG_COLOR & 0xff0000)>>16) +}; +static short mono_green_normal[] = { + ((BG_COLOR & 0x00ff00)) | ((BG_COLOR & 0x00ff00)>>8), + ((FG_COLOR & 0x00ff00)) | ((FG_COLOR & 0x00ff00)>>8) +}; +static short mono_blue_normal[] = { + ((BG_COLOR & 0x0000ff)<<8) | ((BG_COLOR & 0x0000ff)), + ((FG_COLOR & 0x0000ff)<<8) | ((FG_COLOR & 0x0000ff)) +}; + +static short mono_red_inverse[] = { + ((BG_COLOR_INV & 0xff0000)>>8) | ((BG_COLOR_INV & 0xff0000)>>16), + ((FG_COLOR_INV & 0xff0000)>>8) | ((FG_COLOR_INV & 0xff0000)>>16) +}; +static short mono_green_inverse[] = { + ((BG_COLOR_INV & 0x00ff00)) | ((BG_COLOR_INV & 0x00ff00)>>8), + ((FG_COLOR_INV & 0x00ff00)) | ((FG_COLOR_INV & 0x00ff00)>>8) +}; +static short mono_blue_inverse[] = { + ((BG_COLOR_INV & 0x0000ff)<<8) | ((BG_COLOR_INV & 0x0000ff)), + ((FG_COLOR_INV & 0x0000ff)<<8) | ((FG_COLOR & 0x0000ff)) +}; + +static struct fb_cmap mono_default_cmap_normal = { 0, 2, mono_red_normal, mono_green_normal, mono_blue_normal, NULL }; +static struct fb_cmap mono_default_cmap_inverse = { 0, 2, mono_red_inverse, mono_green_inverse, mono_blue_inverse, NULL }; + +static int mono_amiga_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con) +{ + int i, start; + unsigned short *red, *green, *blue, *transp; + unsigned int hred, hgreen, hblue, htransp; + struct fb_cmap *def_cmap; + + red = cmap->red; + green = cmap->green; + blue = cmap->blue; + transp = cmap->transp; + start = cmap->start; + if (start < 0) + return(-EINVAL); + + if (mono_amifb_inverse) + def_cmap = &mono_default_cmap_inverse; + else + def_cmap = &mono_default_cmap_normal; + + for (i = 0; i < cmap->len; i++) { + if (i < def_cmap->len) { + hred = def_cmap->red[i]; + hgreen = def_cmap->green[i]; + hblue = def_cmap->blue[i]; + if (def_cmap->transp) + htransp = def_cmap->transp[i]; + else + htransp = 0; + } else + hred = hgreen = hblue = htransp = 0; + if (kspc) { + *red = hred; + *green = hgreen; + *blue = hblue; + if (transp) + *transp = htransp; + } else { + put_fs_word(hred, red); + put_fs_word(hgreen, green); + put_fs_word(hblue, blue); + if (transp) + put_fs_word(htransp, transp); + } + red++; + green++; + blue++; + if (transp) + transp++; + } + return(0); +} + + +static int mono_amiga_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con) +{ + /* + * Not yet implemented + */ + return(-EINVAL); +} + + +static int mono_amiga_fb_pan_display(struct fb_var_screeninfo *var, int con) +{ + /* + * Not yet implemented + */ + return(-EINVAL); +} + + +static int mono_amiga_fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg, int con) +{ + return(-EINVAL); +} + +static struct fb_ops mono_amiga_fb_ops = { + mono_amiga_fb_get_fix, mono_amiga_fb_get_var, mono_amiga_fb_set_var, mono_amiga_fb_get_cmap, + mono_amiga_fb_set_cmap, mono_amiga_fb_pan_display, mono_amiga_fb_ioctl +}; + + +static int mono_amifb_switch (int con) +{ + mono_current_par.y_wrap = disp[con].var.yoffset; + mono_current_par.cursor_latch = 1; + mono_current_par.scroll_latch = 1; + return(0); +} + + +static int mono_amifb_updatevar(int con) +{ + mono_current_par.y_wrap = disp[con].var.yoffset; + mono_current_par.cursor_latch = 1; + mono_current_par.scroll_latch = 1; + return(0); +} + + +static void mono_amifb_blank(int blank) +{ + if (blank) + mono_do_blank = 1; + else + mono_do_unblank = 1; +} + + +static struct fb_info *mono_amiga_fb_init(long *mem_start) +{ + int mode = mono_amifb_mode; + ulong model; + int inverse_video = mono_amifb_inverse; + int err; + + err=register_framebuffer("Amiga Builtin", &node, &mono_amiga_fb_ops, mono_num_mono_amiga_fb_predefined, + mono_mono_amiga_fb_predefined); + + model = boot_info.bi_un.bi_ami.model; + if (mode == -1) + if (boot_info.bi_amiga.chipset == CS_AGA) + mode = AGA_DEFMODE; + else if (model == AMI_3000) + mode = boot_info.bi_un.bi_ami.vblank == 50 ? OCS_PAL_3000_DEFMODE : OCS_NTSC_3000_DEFMODE; + else + mode = boot_info.bi_un.bi_ami.vblank == 50 ? OCS_PAL_LOWEND_DEFMODE : OCS_NTSC_LOWEND_DEFMODE; + + mono_init_vblank(); + mono_display_init(disp, &mono_modes[mode], inverse_video); + if (!add_isr(IRQ_AMIGA_VERTB, mono_amifb_interrupt, 0, NULL, "frame buffer")) + panic("Couldn't add vblank interrupt"); + + mono_amiga_fb_get_var(&disp[0].var, 0); + if (mono_amifb_inverse) + disp[0].cmap = mono_default_cmap_inverse; + else + disp[0].cmap = mono_default_cmap_normal; + mono_amiga_fb_set_disp(-1); + + strcpy(fb_info.modename, "Amiga Builtin "); + fb_info.disp = disp; + fb_info.switch_con = &mono_amifb_switch; + fb_info.updatevar = &mono_amifb_updatevar; + fb_info.blank = &mono_amifb_blank; + strcat(fb_info.modename, mono_modes[mode].modename); + + return(&fb_info); +} +#endif /* USE_MONO_AMIFB_IF_NON_AGA */ + + +/* -------------------- OCS specific routines ------------------------------- */ + + +#ifdef CONFIG_AMIFB_OCS + /* + * Initialization + * + * Allocate the required chip memory. + * Set the default video mode for this chipset. If a video mode was + * specified on the command line, it will override the default mode. + */ + +static int ocs_init(void) +{ + u_long p; + + /* + * Disable Display DMA + */ + + custom.dmacon = DMAF_ALL | DMAF_MASTER; + + /* + * Set the Default Video Mode + */ + + if (!amifb_mode) + amifb_mode = get_video_mode(boot_info.bi_un.bi_ami.vblank == 50 ? + DEFMODE_PAL : DEFMODE_NTSC); + + /* + * Allocate Chip RAM Structures + */ + + videomemorysize = VIDEOMEMSIZE_OCS; + + + ... + ... + ... + + + /* + * Enable Display DMA + */ + + custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER | DMAF_COPPER | + DMAF_SPRITE; + + return(0); +} +#endif /* CONFIG_AMIFB_OCS */ + + +/* -------------------- ECS specific routines ------------------------------- */ + + +#ifdef CONFIG_AMIFB_ECS + /* + * Initialization + * + * Allocate the required chip memory. + * Set the default video mode for this chipset. If a video mode was + * specified on the command line, it will override the default mode. + */ + +static int ecs_init(void) +{ + u_long p; + + /* + * Disable Display DMA + */ + + custom.dmacon = DMAF_ALL | DMAF_MASTER; + + /* + * Set the Default Video Mode + */ + + if (!amifb_mode) + if (AMIGAHW_PRESENT(AMBER_FF)) + amifb_mode = get_video_mode(boot_info.bi_un.bi_ami.vblank == 50 ? + DEFMODE_AMBER_PAL : DEFMODE_AMBER_NTSC); + else + amifb_mode = get_video_mode(boot_info.bi_un.bi_ami.vblank == 50 ? + DEFMODE_PAL : DEFMODE_NTSC); + + /* + * Allocate Chip RAM Structures + */ + + if (boot_info.bi_amiga.chip_size > 1048576) + videomemorysize = VIDEOMEMSIZE_ECS_2M; + else + videomemorysize = VIDEOMEMSIZE_ECS_1M; + + + ... + ... + ... + + + /* + * Enable Display DMA + */ + + custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER | DMAF_COPPER | + DMAF_SPRITE; + + return(0); +} +#endif /* CONFIG_AMIFB_ECS */ + + +/* -------------------- AGA specific routines ------------------------------- */ + + +#ifdef CONFIG_AMIFB_AGA + /* + * Macros for the conversion from real world values to hardware register + * values (and vice versa). + * + * This helps us to keep our attention on the real stuff... + * + * Hardware limits: + * + * parameter min max step + * --------- --- ---- ---- + * diwstrt_h 0 2047 1 + * diwstrt_v 0 2047 1 + * diwstop_h 0 2047 1 + * diwstop_v 0 2047 1 + * + * ddfstrt 0 2032 16 + * ddfstop 0 2032 16 + * + * htotal 8 2048 8 + * hsstrt 0 2040 8 + * hsstop 0 2040 8 + * vtotal 1 2048 1 + * vsstrt 0 2047 1 + * vsstop 0 2047 1 + * hcenter 0 2040 8 + * + * hbstrt 0 2047 1 + * hbstop 0 2047 1 + * vbstrt 0 2047 1 + * vbstop 0 2047 1 + * + * Horizontal values are in 35 ns (SHRES) pixels + * Vertical values are in scanlines + */ + +/* bplcon1 (smooth scrolling) */ + +#define hscroll2hw(hscroll) \ + (((hscroll)<<12 & 0x3000) | ((hscroll)<<8 & 0xc300) | \ + ((hscroll)<<4 & 0x0c00) | ((hscroll)<<2 & 0x00f0) | ((hscroll)>>2 & 0x000f)) + +#define hw2hscroll(hscroll) \ + (((hscroll)>>8 & 0x00c3) | ((hscroll)<<2 & 0x003c)) + +/* diwstrt/diwstop/diwhigh (visible display window) */ + +#define diwstrt2hw(diwstrt_h, diwstrt_v) \ + (((diwstrt_v)<<8 & 0xff00) | ((diwstrt_h)>>2 & 0x00ff)) +#define diwstop2hw(distop_h, diwstop_v) \ + (((diwstop_v)<<8 & 0xff00) | ((diwstop_h)>>2 & 0x00ff)) +#define diw2hw_high(diwstrt_h, diwstrt_v, distop_h, diwstop_v) \ + (((diwstop_h)<<3 & 0x2000) | ((diwstop_h)<<11 & 0x1800) | \ + ((diwstop_v) & 0x0700) | ((diwstrt_h)>>5 & 0x0020) | \ + ((diwstrt_h)<<3 & 0x0018) | ((diwstrt_v)>>8 & 0x0007)) + +#define hw2diwstrt_h(diwstrt, diwhigh) \ + (((diwhigh)<<5 & 0x0400) | ((diwstrt)<<2 & 0x03fc) | ((diwhigh)>>3 & 0x0003)) +#define hw2diwstrt_v(diwstrt, diwhigh) \ + (((diwhigh)<<8 & 0x0700) | ((diwstrt)>>8 & 0x00ff)) +#define hw2diwstop_h(diwstop, diwhigh) \ + (((diwhigh)>>3 & 0x0400) | ((diwstop)<<2 & 0x03fc) | \ + ((diwhigh)>>11 & 0x0003)) +#define hw2diwstop_v(diwstop, diwhigh) \ + (((diwhigh) & 0x0700) | ((diwstop)>>8 & 0x00ff)) + +/* ddfstrt/ddfstop (display DMA) */ + +#define ddfstrt2hw(ddfstrt) (div8(ddfstrt) & 0x00fe) +#define ddfstop2hw(ddfstop) (div8(ddfstop) & 0x00fe) + +#define hw2ddfstrt(ddfstrt) ((ddfstrt)<<3) +#define hw2ddfstop(ddfstop) ((ddfstop)<<3) + +/* hsstrt/hsstop/htotal/vsstrt/vsstop/vtotal (sync timings) */ + +#define hsstrt2hw(hsstrt) (div8(hsstrt)) +#define hsstop2hw(hsstop) (div8(hsstop)) +#define htotal2hw(htotal) (div8(htotal)-1) +#define vsstrt2hw(vsstrt) (vsstrt) +#define vsstop2hw(vsstop) (vsstop) +#define vtotal2hw(vtotal) ((vtotal)-1) + +#define hw2hsstrt(hsstrt) ((hsstrt)<<3) +#define hw2hsstop(hsstop) ((hsstop)<<3) +#define hw2htotal(htotal) (((htotal)+1)<<3) +#define hw2vsstrt(vsstrt) (vsstrt) +#define hw2vsstop(vsstop) (vsstop) +#define hw2vtotal(vtotal) ((vtotal)+1) + +/* hbstrt/hbstop/vbstrt/vbstop (blanking timings) */ + +#define hbstrt2hw(hbstrt) (((hbstrt)<<8 & 0x0700) | ((hbstrt)>>3 & 0x00ff)) +#define hbstop2hw(hbstop) (((hbstop)<<8 & 0x0700) | ((hbstop)>>3 & 0x00ff)) +#define vbstrt2hw(vbstrt) (vbstrt) +#define vbstop2hw(vbstop) (vbstop) + +#define hw2hbstrt(hbstrt) (((hbstrt)<<3 & 0x07f8) | ((hbstrt)>>8 & 0x0007)) +#define hw2hbstop(hbstop) (((hbstop)<<3 & 0x07f8) | ((hbstop)>>8 & 0x0007)) +#define hw2vbstrt(vbstrt) (vbstrt) +#define hw2vbstop(vbstop) (vbstop) + +/* color */ + +#define rgb2hw_high(red, green, blue) \ + (((red)<<4 & 0xf00) | ((green) & 0x0f0) | ((blue)>>4 & 0x00f)) +#define rgb2hw_low(red, green, blue) \ + (((red)<<8 & 0xf00) | ((green)<<4 & 0x0f0) | ((blue) & 0x00f)) + +#define hw2red(high, low) (((high)>>4 & 0xf0) | ((low)>>8 & 0x0f)) +#define hw2green(high, low) (((high) & 0xf0) | ((low)>>4 & 0x0f)) +#define hw2blue(high, low) (((high)<<4 & 0xf0) | ((low) & 0x0f)) + +/* sprpos/sprctl (sprite positioning) */ + +#define spr2hw_pos(start_v, start_h) \ + (((start_v)<<8&0xff00) | ((start_h)>>3&0x00ff)) +#define spr2hw_ctl(start_v, start_h, stop_v) \ + (((stop_v)<<8&0xff00) | ((start_v)>>3&0x0040) | ((stop_v)>>4&0x0020) | \ + ((start_h)<<3&0x0018) | ((start_v)>>6&0x0004) | ((stop_v)>>7&0x0002) | \ + ((start_h)>>2&0x0001)) + + + /* + * Hardware Cursor + */ + +struct aga_cursorsprite { + u_short sprpos; + u_short pad1[3]; + u_short sprctl; + u_short pad2[3]; + union { + struct { + u_long data[64*4]; + u_long trailer[4]; + } nonlaced; + struct { + u_long data[32*4]; + u_long trailer[4]; + } laced; + } u; +}; + +struct aga_dummysprite { + u_short sprpos; + u_short pad1[3]; + u_short sprctl; + u_short pad2[3]; + u_long data[4]; + u_long trailer[4]; +}; + + + /* + * Pixel modes for Bitplanes and Sprites + */ + +static u_short bplpixmode[3] = { + BPC0_SHRES, /* 35 ns / 28 MHz */ + BPC0_HIRES, /* 70 ns / 14 MHz */ + 0 /* 140 ns / 7 MHz */ +}; + +static u_short sprpixmode[3] = { + BPC3_SPRES1 | BPC3_SPRES0, /* 35 ns / 28 MHz */ + BPC3_SPRES1, /* 70 ns / 14 MHz */ + BPC3_SPRES0 /* 140 ns / 7 MHz */ +}; + + + /* + * Initialization + * + * Allocate the required chip memory. + * Set the default video mode for this chipset. If a video mode was + * specified on the command line, it will override the default mode. + */ + +static int aga_init(void) +{ + u_long p; + + /* + * Disable Display DMA + */ + + custom.dmacon = DMAF_ALL | DMAF_MASTER; + + /* + * Set the Default Video Mode + */ + + if (!amifb_mode) + amifb_mode = get_video_mode(DEFMODE_AGA); + + /* + * Allocate Chip RAM Structures + */ + + if (boot_info.bi_amiga.chip_size > 1048576) + videomemorysize = VIDEOMEMSIZE_AGA_2M; + else + videomemorysize = VIDEOMEMSIZE_AGA_1M; + + p = chipalloc(videomemorysize+ /* Bitplanes */ + sizeof(struct clist_hdr)+ /* Copper Lists */ + 2*sizeof(struct clist_dyn)+ + 2*sizeof(struct aga_cursorsprite)+ /* Sprites */ + sizeof(struct aga_dummysprite)); + + assignchunk(videomemory, u_long, p, videomemorysize); + assignchunk(clist_hdr, struct clist_hdr *, p, sizeof(struct clist_hdr)); + assignchunk(clist_lof, struct clist_dyn *, p, sizeof(struct clist_dyn)); + assignchunk(clist_shf, struct clist_dyn *, p, sizeof(struct clist_dyn)); + assignchunk(lofsprite, u_long *, p, sizeof(struct aga_cursorsprite)); + assignchunk(shfsprite, u_long *, p, sizeof(struct aga_cursorsprite)); + assignchunk(dummysprite, u_long *, p, sizeof(struct aga_dummysprite)); + + /* + * Make sure the Copper has something to do + */ + + aga_build_clist_hdr(clist_hdr); + + custom.cop1lc = (u_short *)ZTWO_PADDR(clist_hdr); + custom.cop2lc = (u_short *)ZTWO_PADDR(&clist_hdr->wait_forever); + custom.copjmp1 = 0; + + /* + * Enable Display DMA + */ + + custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER | DMAF_COPPER | + DMAF_SPRITE; + + /* + * These hardware register values will never be changed later + */ + + custom.bplcon2 = BPC2_KILLEHB | BPC2_PF2P2 | BPC2_PF1P2; + custom.bplcon4 = BPC4_ESPRM4 | BPC4_OSPRM4; + + return(0); +} + + + /* + * This function should fill in the `fix' structure based on the + * values in the `par' structure. + */ + +static int aga_encode_fix(struct fb_fix_screeninfo *fix, + struct amiga_fb_par *par) +{ + int i; + + strcpy(fix->id, amiga_fb_name); + fix->smem_start = videomemory; + fix->smem_len = videomemorysize; + + if (amifb_ilbm) { + fix->type = FB_TYPE_INTERLEAVED_PLANES; + fix->type_aux = par->next_line; + } else { + fix->type = FB_TYPE_PLANES; + fix->type_aux = 0; + } + fix->visual = FB_VISUAL_PSEUDOCOLOR; + + if (par->diwstrt_h >= 323) + fix->xpanstep = 1; + else + fix->xpanstep = 64; + fix->ypanstep = 1; + + if (hw2ddfstrt(par->ddfstrt) >= (par->bpp-1)*64) + fix->ywrapstep = 1; + else + fix->ywrapstep = 0; + + for (i = 0; i < arraysize(fix->reserved); i++) + fix->reserved[i] = 0; + + return(0); +} + + + /* + * Get the video params out of `var'. If a value doesn't fit, round + * it up, if it's too big, return -EINVAL. + */ + +static int aga_decode_var(struct fb_var_screeninfo *var, + struct amiga_fb_par *par) +{ + u_short clk_shift, line_shift_incd; + u_long upper, lower, hslen, vslen; + int xres_n, yres_n, xoffset_n; /* normalized */ + u_long left_n, right_n, upper_n, lower_n, hslen_n, vslen_n; /* normalized */ + u_long diwstrt_h, diwstrt_v, diwstop_h, diwstop_v; + u_long hsstrt, vsstrt, hsstop, vsstop, htotal, vtotal; + u_long ddfmin, ddfmax, ddfstrt, ddfstop, hscroll; + double hrate, vrate; + u_short loopcnt = 0; + + /* + * Find a matching Pixel Clock + */ + + for (clk_shift = 0; clk_shift < 3; clk_shift++) + if (var->pixclock <= pixclock[clk_shift]) + break; + if (clk_shift >= 3) + return(-EINVAL); + par->clk_shift = clk_shift; + + /* + * Round up the Geometry Values (if necessary) + */ + + par->xres = max(var->xres, 64); + par->yres = max(var->yres, 64); + par->vxres = up64(max(var->xres_virtual, par->xres)); + par->vyres = max(var->yres_virtual, par->yres); + + par->bpp = var->bits_per_pixel; + if (par->bpp > 8) + return(-EINVAL); + + if (!var->nonstd) { + if (par->bpp < 1) + par->bpp = 1; + } else if (var->nonstd == FB_NONSTD_HAM) + par->bpp = par->bpp <= 6 ? 6 : 8; + else + return(-EINVAL); + + upper = var->upper_margin; + lower = var->lower_margin; + hslen = var->hsync_len; + vslen = var->vsync_len; + + par->vmode = var->vmode; + switch (par->vmode & FB_VMODE_MASK) { + case FB_VMODE_NONINTERLACED: + line_shift_incd = 1; + break; + case FB_VMODE_INTERLACED: + line_shift_incd = 0; + if (par->yres & 1) + par->yres++; /* even */ + if (upper & 1) + upper++; /* even */ + if (!(lower & 1)) + lower++; /* odd */ + if (vslen & 1) + vslen++; /* even */ + break; + case FB_VMODE_DOUBLE: + line_shift_incd = 2; + break; + default: + return(-EINVAL); + break; + } + + par->xoffset = var->xoffset; + par->yoffset = var->yoffset; + if (par->vmode & FB_VMODE_YWRAP) { + if (par->xoffset || par->yoffset < 0 || par->yoffset >= par->yres) + return(-EINVAL); + } else { + if (par->xoffset < 0 || par->xoffset+par->xres > par->vxres || + par->yoffset < 0 || par->yoffset+par->yres > par->vyres) + return(-EINVAL); + } + + if (var->sync & FB_SYNC_BROADCAST) { + if (hslen || vslen) + return(-EINVAL); + } else { + hslen = hslen < 1 ? 1 : hslen; + vslen = vslen < 1 ? 1 : vslen; + } + + /* + * Check the Memory Requirements + */ + + if (par->vxres*par->vyres*par->bpp > videomemorysize<<3) + return(-EINVAL); + + /* + * Normalize all values: + * + * - horizontal: in 35 ns (SHRES) pixels + * - vertical: in non-interlaced scanlines + */ + + xres_n = par->xres<xoffset<yres<>1; + + left_n = var->left_margin<right_margin<>1; + lower_n = lower<>1; + vslen_n = vslen<>1; + + /* + * Vertical and Horizontal Timings + */ + + par->bplcon3 = sprpixmode[clk_shift]; +aga_calculate_timings: + if (var->sync & FB_SYNC_BROADCAST) { + if (upper_n+yres_n+lower_n == PAL_WINDOW_V) { + /* PAL video mode */ + diwstrt_v = PAL_DIWSTRT_V+upper_n; + diwstop_v = diwstrt_v+yres_n; + diwstrt_h = PAL_DIWSTRT_H+left_n; + diwstop_h = diwstrt_h+xres_n+1; + par->htotal = htotal2hw(PAL_HTOTAL); + hrate = 15625; + vrate = 50; + par->beamcon0 = BMC0_PAL; + } else if (upper_n+yres_n+lower_n == NTSC_WINDOW_V) { + /* NTSC video mode */ + diwstrt_v = NTSC_DIWSTRT_V+upper_n; + diwstop_v = diwstrt_v+yres_n; + diwstrt_h = NTSC_DIWSTRT_H+left_n; + diwstop_h = diwstrt_h+xres_n+1; + par->htotal = htotal2hw(NTSC_HTOTAL); + hrate = 15750; + vrate = 60; + par->beamcon0 = 0; + } else + return(-EINVAL); + } else { + /* Programmable video mode */ + vsstrt = lower_n; + vsstop = vsstrt+vslen_n; + diwstrt_v = vsstop+upper_n; + diwstop_v = diwstrt_v+yres_n; + vtotal = diwstop_v; + hslen_n = up8(hslen_n); + htotal = up8(left_n+xres_n+right_n+hslen_n); + if (vtotal > 2048 || htotal > 2048) + return(-EINVAL); + right_n = htotal-left_n-xres_n-hslen_n; + hsstrt = down8(right_n+4); + hsstop = hsstrt+hslen_n; + diwstop_h = htotal+hsstrt-right_n+1; + diwstrt_h = diwstop_h-xres_n-1; + hrate = (double)amiga_masterclock/htotal; + vrate = hrate/vtotal; + par->bplcon3 |= BPC3_BRDRBLNK | BPC3_EXTBLKEN; + par->beamcon0 = BMC0_HARDDIS | BMC0_VARVBEN | BMC0_LOLDIS | + BMC0_VARVSYEN | BMC0_VARHSYEN | BMC0_VARBEAMEN | + BMC0_PAL | BMC0_VARCSYEN; + if (var->sync & FB_SYNC_HOR_HIGH_ACT) + par->beamcon0 |= BMC0_HSYTRUE; + if (var->sync & FB_SYNC_VERT_HIGH_ACT) + par->beamcon0 |= BMC0_VSYTRUE; + if (var->sync & FB_SYNC_COMP_HIGH_ACT) + par->beamcon0 |= BMC0_CSYTRUE; + par->htotal = htotal2hw(htotal); + par->hsstrt = hsstrt2hw(hsstrt); + par->hsstop = hsstop2hw(hsstop); + par->vtotal = vtotal2hw(vtotal); + par->vsstrt = vsstrt2hw(vsstrt); + par->vsstop = vsstop2hw(vsstop); + par->hcenter = par->hsstrt+(par->htotal>>1); + } + par->diwstrt_v = diwstrt_v; + par->diwstrt_h = diwstrt_h; + par->crsr_x = 0; + par->crsr_y = 0; + + /* + * DMA Timings + */ + + ddfmin = down64(xoffset_n); + ddfmax = up64(xoffset_n+xres_n); + hscroll = diwstrt_h-68-mod64(xoffset_n); + ddfstrt = down64(hscroll); + if (ddfstrt < 128) { + right_n += (128-hscroll); + /* Prevent an infinite loop */ + if (loopcnt++) + return(-EINVAL); + goto aga_calculate_timings; + } + hscroll -= ddfstrt; + ddfstop = ddfstrt+ddfmax-ddfmin-(64<next_plane = div8(par->vxres); + par->next_line = par->bpp*par->next_plane; + } else { + par->next_line = div8(par->vxres); + par->next_plane = par->vyres*par->next_line; + } + par->bplpt0 = ZTWO_PADDR((u_long)videomemory+div8(ddfmin>>clk_shift)+ + par->yoffset*par->next_line); + par->bpl1mod = par->next_line-div8((ddfmax-ddfmin)>>clk_shift); + par->bpl2mod = par->bpl1mod; + + /* + * Hardware Register Values + */ + + par->bplcon0 = BPC0_COLOR | BPC0_ECSENA | bplpixmode[clk_shift]; + if (par->bpp == 8) + par->bplcon0 |= BPC0_BPU3; + else + par->bplcon0 |= par->bpp<<12; + if (var->nonstd == FB_NONSTD_HAM) + par->bplcon0 |= BPC0_HAM; + if (var->sync & FB_SYNC_EXT) + par->bplcon0 |= BPC0_ERSY; + par->bplcon1 = hscroll2hw(hscroll); + par->diwstrt = diwstrt2hw(diwstrt_h, diwstrt_v); + par->diwstop = diwstop2hw(diwstop_h, diwstop_v); + par->diwhigh = diw2hw_high(diwstrt_h, diwstrt_v, distop_h, diwstop_v); + par->ddfstrt = ddfstrt2hw(ddfstrt); + par->ddfstop = ddfstop2hw(ddfstop); + par->fmode = FMODE_SPAGEM | FMODE_SPR32 | FMODE_BPAGEM | FMODE_BPL32; + + switch (par->vmode & FB_VMODE_MASK) { + case FB_VMODE_INTERLACED: + par->bpl1mod += par->next_line; + par->bpl2mod += par->next_line; + par->bplcon0 |= BPC0_LACE; + break; + case FB_VMODE_DOUBLE: + par->bpl1mod -= par->next_line; + par->fmode |= FMODE_SSCAN2 | FMODE_BSCAN2; + break; + } + + if (hrate < hfmin || hrate > hfmax || vrate < vfmin || vrate > vfmax) + return(-EINVAL); + + return(0); +} + + + /* + * Fill the `var' structure based on the values in `par' and maybe + * other values read out of the hardware. + */ + +static int aga_encode_var(struct fb_var_screeninfo *var, + struct amiga_fb_par *par) +{ + u_short clk_shift, line_shift_incd; + u_long left, right, upper, lower, hslen, vslen; + u_short diwstop_h, diwstop_v; + u_short hsstrt, vsstrt, hsstop, vsstop, htotal; + int i; + + var->xres = par->xres; + var->yres = par->yres; + var->xres_virtual = par->vxres; + var->yres_virtual = par->vyres; + var->xoffset = par->xoffset; + var->yoffset = par->yoffset; + + var->bits_per_pixel = par->bpp; + var->grayscale = 0; + + var->red.offset = 0; + var->red.length = 8; + var->red.msb_right = 0; + var->blue = var->green = var->red; + var->transp.offset = 0; + var->transp.length = 0; + var->transp.msb_right = 0; + + if (par->bplcon0 & BPC0_HAM) + var->nonstd = FB_NONSTD_HAM; + else + var->nonstd = 0; + var->activate = 0; + + var->height = -1; + var->width = -1; + var->accel = FB_ACCEL_NONE; + + clk_shift = par->clk_shift; + var->pixclock = pixclock[clk_shift]; + + diwstop_h = hw2diwstop_h(par->diwstop, par->diwhigh); + if (par->beamcon0 & BMC0_VARBEAMEN) { + hsstrt = hw2hsstrt(par->hsstrt); + vsstrt = hw2vsstrt(par->vsstrt); + hsstop = hw2hsstop(par->hsstop); + vsstop = hw2vsstop(par->vsstop); + htotal = hw2htotal(par->htotal); + left = par->diwstrt_h-hsstop; + right = htotal+hsstrt-diwstop_h+1; + hslen = hsstop-hsstrt; + upper = par->diwstrt_v-vsstop; + lower = vsstrt; + vslen = vsstop-vsstrt; + var->sync = 0; + } else { + diwstop_v = hw2diwstop_v(par->diwstop, par->diwhigh); + if (par->beamcon0 & BMC0_PAL) { + left = par->diwstrt_h-PAL_DIWSTRT_H; + right = PAL_DIWSTRT_H+PAL_WINDOW_H-diwstop_h+1; + upper = par->diwstrt_v-PAL_DIWSTRT_V; + lower = PAL_DIWSTRT_V+PAL_WINDOW_V-diwstop_v; + } else { + left = par->diwstrt_h-NTSC_DIWSTRT_H; + right = NTSC_DIWSTRT_H+NTSC_WINDOW_H-diwstop_h; + upper = par->diwstrt_v-NTSC_DIWSTRT_V; + lower = NTSC_DIWSTRT_V+NTSC_WINDOW_V-diwstop_v; + } + hslen = 0; + vslen = 0; + var->sync = FB_SYNC_BROADCAST; + } + + if (par->bplcon0 & BPC0_ERSY) + var->sync |= FB_SYNC_EXT; + if (par->beamcon0 & BMC0_HSYTRUE) + var->sync |= FB_SYNC_HOR_HIGH_ACT; + if (par->beamcon0 & BMC0_VSYTRUE) + var->sync |= FB_SYNC_VERT_HIGH_ACT; + if (par->beamcon0 & BMC0_CSYTRUE) + var->sync |= FB_SYNC_COMP_HIGH_ACT; + + switch (par->vmode & FB_VMODE_MASK) { + case FB_VMODE_NONINTERLACED: + line_shift_incd = 1; + break; + case FB_VMODE_INTERLACED: + line_shift_incd = 0; + break; + case FB_VMODE_DOUBLE: + line_shift_incd = 2; + break; + } + + var->left_margin = left>>clk_shift; + var->right_margin = right>>clk_shift; + var->upper_margin = upper<<1>>line_shift_incd; + var->lower_margin = lower<<1>>line_shift_incd; + var->hsync_len = hslen>>clk_shift; + var->vsync_len = vslen<<1>>line_shift_incd; + var->vmode = par->vmode; + for (i = 0; i < arraysize(var->reserved); i++) + var->reserved[i] = 0; + + return(0); +} + + + /* + * Read a single color register and split it into + * colors/transparent. Return != 0 for invalid regno. + */ + +static int aga_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, + u_int *transp) +{ + if (regno > 255) + return(1); + + *red = palette[regno].red; + *green = palette[regno].green; + *blue = palette[regno].blue; + return(0); +} + + + /* + * Set a single color register. The values supplied are already + * rounded down to the hardware's capabilities (according to the + * entries in the var structure). Return != 0 for invalid regno. + */ + +static int aga_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp) +{ + u_short bplcon3 = current_par.bplcon3; + + if (regno > 255) + return(1); + + /* + * Update the corresponding Hardware Color Register, unless it's Color + * Register 0 and the screen is blanked. + * + * The cli()/sti() pair is here to protect bplcon3 from being changed by + * the VBlank interrupt routine. + */ + + cli(); + if (regno || !is_blanked) { + custom.bplcon3 = bplcon3 | (regno<<8 & 0xe000); + custom.color[regno&31] = rgb2hw_high(red, green, blue); + custom.bplcon3 = bplcon3 | (regno<<8 & 0xe000) | BPC3_LOCT; + custom.color[regno&31] = rgb2hw_low(red, green, blue); + custom.bplcon3 = bplcon3; + } + sti(); + + palette[regno].red = red; + palette[regno].green = green; + palette[regno].blue = blue; + + return(0); +} + + + /* + * Pan or Wrap the Display + * + * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag + * in `var'. + */ + +static int aga_pan_display(struct fb_var_screeninfo *var, + struct amiga_fb_par *par) +{ + int xoffset, yoffset, vmode, xres_n, xoffset_n; + u_short clk_shift, line_shift_incd; + u_long ddfmin, ddfmax, ddfstrt, ddfstop, hscroll; + + xoffset = var->xoffset; + yoffset = var->yoffset; + if (var->vmode & FB_VMODE_YWRAP) { + if (hw2ddfstrt(par->ddfstrt) < (par->bpp-1)*64 || xoffset || + yoffset < 0 || yoffset >= par->yres) + return(-EINVAL); + vmode = par->vmode | FB_VMODE_YWRAP; + } else { + if (par->diwstrt_h < 323) + xoffset = up64(xoffset); + if (xoffset < 0 || xoffset+par->xres > par->vxres || + yoffset < 0 || yoffset+par->yres > par->vyres) + return(-EINVAL); + vmode = par->vmode & ~FB_VMODE_YWRAP; + } + + clk_shift = par->clk_shift; + switch (vmode & FB_VMODE_MASK) { + case FB_VMODE_NONINTERLACED: + line_shift_incd = 1; + break; + case FB_VMODE_INTERLACED: + line_shift_incd = 0; + break; + case FB_VMODE_DOUBLE: + line_shift_incd = 2; + break; + } + xres_n = par->xres<diwstrt_h-68-mod64(xoffset_n); + ddfstrt = down64(hscroll); + if (ddfstrt < 128) + return(-EINVAL); + hscroll -= ddfstrt; + ddfstop = ddfstrt+ddfmax-ddfmin-(64<bplcon1 = hscroll2hw(hscroll); + par->ddfstrt = ddfstrt2hw(ddfstrt); + par->ddfstop = ddfstop2hw(ddfstop); + + /* + * Bitplane calculations + */ + + par->bplpt0 = ZTWO_PADDR((u_long)videomemory+div8(ddfmin>>clk_shift)+ + yoffset*par->next_line); + par->bpl1mod = par->next_line-div8((ddfmax-ddfmin)>>clk_shift); + par->bpl2mod = par->bpl1mod; + switch (vmode & FB_VMODE_MASK) { + case FB_VMODE_INTERLACED: + par->bpl1mod += par->next_line; + par->bpl2mod += par->next_line; + break; + case FB_VMODE_DOUBLE: + par->bpl1mod -= par->next_line; + break; + } + + par->xoffset = var->xoffset = xoffset; + par->yoffset = var->yoffset = yoffset; + par->vmode = var->vmode = vmode; + return(0); +} + + + /* + * Change the video mode (called by VBlank interrupt) + */ + +void aga_do_vmode(void) +{ + struct amiga_fb_par *par = ¤t_par; + + /* + * Rebuild the dynamic part of the Copper List and activate the right + * Copper List as soon as possible + * + * Make sure we're in a Long Frame if the video mode is interlaced. + * This is always the case if we already were in an interlaced mode, + * since then the VBlank only calls us during a Long Frame. + * But this _is_ necessary if we're switching from a non-interlaced + * to an interlaced mode. + */ + + if ((par->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) { + custom.vposw = 0x8000; + aga_build_clist_dyn(clist_lof, clist_shf, 0, par); + custom.cop2lc = (u_short *)ZTWO_PADDR(clist_lof); + aga_build_clist_dyn(clist_shf, clist_lof, 1, par); + } else { + aga_build_clist_dyn(clist_lof, NULL, 0, par); + custom.cop2lc = (u_short *)ZTWO_PADDR(clist_lof); + } + + /* + * Update the hardware registers + */ + + if (full_vmode_change) { + custom.fmode = par->fmode; + custom.beamcon0 = par->beamcon0; + if (par->beamcon0 & BMC0_VARBEAMEN) { + custom.htotal = par->htotal; + custom.vtotal = par->vtotal; + custom.hsstrt = par->hsstrt; + custom.hsstop = par->hsstop; + custom.hbstrt = par->hsstrt; + custom.hbstop = par->hsstop; + custom.vsstrt = par->vsstrt; + custom.vsstop = par->vsstop; + custom.vbstrt = par->vsstrt; + custom.vbstop = par->vsstop; + custom.hcenter = par->hcenter; + } + custom.bplcon3 = par->bplcon3; + full_vmode_change = 0; + } + custom.ddfstrt = par->ddfstrt; + custom.ddfstop = par->ddfstop; + custom.bpl1mod = par->bpl1mod; + custom.bpl2mod = par->bpl2mod; + custom.bplcon1 = par->bplcon1; + + /* + * Update the Frame Header Copper List + */ + + aga_update_clist_hdr(clist_hdr, par); + + /* + * The minimum period for audio depends on htotal (for OCS/ECS/AGA) + */ + + if ((boot_info.bi_amiga.chipset != CS_STONEAGE) && full_vmode_change) + amiga_audio_min_period = (par->htotal>>1)+1; +} + + + /* + * (Un)Blank the screen (called by VBlank interrupt) + */ + +void aga_do_blank(int blank) +{ + struct amiga_fb_par *par = ¤t_par; + u_short bplcon3 = par->bplcon3; + u_char red, green, blue; + + if (blank) { + custom.dmacon = DMAF_RASTER | DMAF_SPRITE; + red = green = blue = 0; + if (pwrsave && par->beamcon0 & BMC0_VARBEAMEN) { + /* VESA suspend mode, switch off HSYNC */ + custom.hsstrt = par->htotal+2; + custom.hsstop = par->htotal+2; + } + } else { + custom.dmacon = DMAF_SETCLR | DMAF_RASTER; + red = palette[0].red; + green = palette[0].green; + blue = palette[0].blue; + if (pwrsave && par->beamcon0 & BMC0_VARBEAMEN) { + custom.hsstrt = par->hsstrt; + custom.hsstop = par->hsstop; + } + } + custom.bplcon3 = bplcon3; + custom.color[0] = rgb2hw_high(red, green, blue); + custom.bplcon3 = bplcon3 | BPC3_LOCT; + custom.color[0] = rgb2hw_low(red, green, blue); + custom.bplcon3 = bplcon3; + + is_blanked = blank; +} + + + /* + * Move the cursor (called by VBlank interrupt) + */ + +void aga_do_movecursor(void) +{ + struct amiga_fb_par *par = ¤t_par; + struct aga_cursorsprite *sprite = (struct aga_cursorsprite *)lofsprite; + long hs, vs, ve; + u_short s1, s2, is_double = 0; + + if (par->crsr_x <= -64 || par->crsr_x >= par->xres || par->crsr_y <= -64 || + par->crsr_y >= par->yres) + hs = vs = ve = 0; + else { + hs = par->diwstrt_h-4+(par->crsr_x<clk_shift); + vs = par->crsr_y; + ve = min(vs+64, par->yres); + switch (par->vmode & FB_VMODE_MASK) { + case FB_VMODE_INTERLACED: + vs >>= 1; + ve >>= 1; + break; + case FB_VMODE_DOUBLE: + vs <<= 1; + ve <<= 1; + is_double = 1; + break; + } + vs += par->diwstrt_v; + ve += par->diwstrt_v; + } + s1 = spr2hw_pos(vs, hs); + if (is_double) + s1 |= 0x80; + s2 = spr2hw_ctl(vs, hs, ve); + sprite->sprpos = s1; + sprite->sprctl = s2; + + /* + * TODO: Special cases: + * + * - Interlaced: fill position in in both lofsprite & shfsprite + * swap lofsprite & shfsprite on odd lines + * + * - Doublescan: OK? + * + * - ve <= bottom of display: OK? + */ +} + + + /* + * Flash the cursor (called by VBlank interrupt) + */ + +void aga_do_flashcursor(void) +{ +#if 1 + static int cursorcount = 0; + static int cursorstate = 0; + + switch (cursormode) { + case FB_CURSOR_OFF: + custom.dmacon = DMAF_SPRITE; + break; + case FB_CURSOR_ON: + custom.dmacon = DMAF_SETCLR | DMAF_SPRITE; + break; + case FB_CURSOR_FLASH: + if (cursorcount) + cursorcount--; + else { + cursorcount = CRSR_RATE; + if ((cursorstate = !cursorstate)) + custom.dmacon = DMAF_SETCLR | DMAF_SPRITE; + else + custom.dmacon = DMAF_SPRITE; + } + break; + } +#endif +} + + +#if 1 +static int aga_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con) +{ +#if 0 + if (ddfstrt >= 192) { +#endif + fix->crsr_width = 64; + fix->crsr_height = 64; + fix->crsr_xsize = 64; + fix->crsr_ysize = 64; + fix->crsr_color1 = 17; + fix->crsr_color2 = 18; +#if 0 + } else { + fix->crsr_width = 0; + fix->crsr_height = 0; + fix->crsr_xsize = 0; + fix->crsr_ysize = 0; + fix->crsr_color1 = 0; + fix->crsr_color2 = 0; + } +#endif + return(0); +} + + +static int aga_get_var_cursorinfo(struct fb_var_cursorinfo *var, int con) +{ + struct aga_cursorsprite *sprite = (struct aga_cursorsprite *)lofsprite; + + /* TODO: interlaced sprites */ + memcpy(var->data, sprite->u.nonlaced.data, sizeof(var->data)); + return(0); +} + + +static int aga_set_var_cursorinfo(struct fb_var_cursorinfo *var, int con) +{ + struct aga_cursorsprite *sprite = (struct aga_cursorsprite *)lofsprite; + + /* TODO: interlaced sprites */ + memcpy(sprite->u.nonlaced.data, var->data, sizeof(var->data)); + return(0); +} + + +static int aga_get_cursorstate(struct fb_cursorstate *state, int con) +{ + state->xoffset = current_par.crsr_x; + state->yoffset = current_par.crsr_y; + state->mode = cursormode; + return(0); +} + + +static int aga_set_cursorstate(struct fb_cursorstate *state, int con) +{ + current_par.crsr_x = state->xoffset; + current_par.crsr_y = state->yoffset; + cursormode = state->mode; + do_movecursor = 1; + return(0); +} +#endif + + + /* + * Build the Frame Header Copper List + */ + +static __inline__ void aga_build_clist_hdr(struct clist_hdr *cop) +{ + int i, j; + u_long p; + + cop->bplcon0.l = CMOVE(BPC0_COLOR | BPC0_SHRES | BPC0_ECSENA, bplcon0); + cop->diwstrt.l = CMOVE(0x0181, diwstrt); + cop->diwstop.l = CMOVE(0x0281, diwstop); + cop->diwhigh.l = CMOVE(0x0000, diwhigh); + for (i = 0; i < 8; i++) + cop->sprfix[i].l = CMOVE(0, spr[i].pos); + for (i = 0, j = 0; i < 8; i++) { + p = ZTWO_PADDR(dummysprite); + cop->sprstrtup[j++].l = CMOVE(highw(p), sprpt[i]); + cop->sprstrtup[j++].l = CMOVE2(loww(p), sprpt[i]); + } + cop->wait.l = CWAIT(0, 12); /* Initial value */ + cop->jump.l = CMOVE(0, copjmp2); + cop->wait_forever.l = CEND; +} + + + /* + * Update the Frame Header Copper List + */ + +static __inline__ void aga_update_clist_hdr(struct clist_hdr *cop, + struct amiga_fb_par *par) +{ + cop->bplcon0.l = CMOVE(~(BPC0_BPU3 | BPC0_BPU2 | BPC0_BPU1 | BPC0_BPU0) & + par->bplcon0, bplcon0); + cop->wait.l = CWAIT(0, par->diwstrt_v-2); +} + + + /* + * Build the Long Frame/Short Frame Copper List + */ + +static void aga_build_clist_dyn(struct clist_dyn *cop, + struct clist_dyn *othercop, u_short shf, + struct amiga_fb_par *par) +{ + u_long y_wrap, bplpt0, p, line; + int i, j = 0; + + cop->diwstrt.l = CMOVE(par->diwstrt, diwstrt); + cop->diwstop.l = CMOVE(par->diwstop, diwstop); + cop->diwhigh.l = CMOVE(par->diwhigh, diwhigh); + cop->bplcon0.l = CMOVE(par->bplcon0, bplcon0); + + /* Point Sprite 0 at cursor sprite */ + + /* TODO: This should depend on the vertical sprite position too */ + if (shf) { + p = ZTWO_PADDR(shfsprite); + cop->sprpt[0].l = CMOVE(highw(p), sprpt[0]); + cop->sprpt[1].l = CMOVE2(loww(p), sprpt[0]); + } else { + p = ZTWO_PADDR(lofsprite); + cop->sprpt[0].l = CMOVE(highw(p), sprpt[0]); + cop->sprpt[1].l = CMOVE2(loww(p), sprpt[0]); + } + + bplpt0 = par->bplpt0; + if (shf) + bplpt0 += par->next_line; + y_wrap = par->vmode & FB_VMODE_YWRAP ? par->yoffset : 0; + + /* Set up initial bitplane ptrs */ + + for (i = 0, p = bplpt0; i < par->bpp; i++, p += par->next_plane) { + cop->rest[j++].l = CMOVE(highw(p), bplpt[i]); + cop->rest[j++].l = CMOVE2(loww(p), bplpt[i]); + } + + if (y_wrap) { + bplpt0 -= y_wrap*par->next_line; + line = par->yres-y_wrap; + switch (par->vmode & FB_VMODE_MASK) { + case FB_VMODE_INTERLACED: + line >>= 1; + break; + case FB_VMODE_DOUBLE: + line <<= 1; + break; + } + line += par->diwstrt_v; + + /* Handle skipping over 256-line chunks */ + + while (line > 256) { + /* Hardware limitation - 8 bit counter */ + cop->rest[j++].l = CWAIT(par->htotal-4, 255); + /* Wait(0, 0) - make sure we're in the new segment */ + cop->rest[j++].l = CWAIT(0, 0); + line -= 256; + } + cop->rest[j++].l = CWAIT(par->htotal-11, line-1); + + for (i = 0, p = bplpt0; i < par->bpp; i++, p += par->next_plane) { + cop->rest[j++].l = CMOVE(highw(p), bplpt[i]); + cop->rest[j++].l = CMOVE2(loww(p), bplpt[i]); + } + } + + if (othercop) { + p = ZTWO_PADDR(othercop); + cop->rest[j++].l = CMOVE(highw(p), cop2lc); + cop->rest[j++].l = CMOVE2(loww(p), cop2lc); + } + + /* End of Copper list */ + cop->rest[j++].l = CEND; + + if (j > arraysize(cop->rest)) + printk("aga_build_clist_dyn: copper list overflow (%d entries)\n", j); +} +#endif /* CONFIG_AMIFB_AGA */ + + +/* -------------------- Interfaces to hardware functions -------------------- */ + + +#ifdef CONFIG_AMIFB_OCS +static struct fb_hwswitch ocs_switch = { + ocs_init, ocs_encode_fix, ocs_decode_var, ocs_encode_var, ocs_getcolreg, + ocs_setcolreg, ocs_pan_display, ocs_do_vmode, ocs_do_blank, + ocs_do_movecursor, ocs_do_flashcursor +}; +#endif /* CONFIG_AMIFB_OCS */ + +#ifdef CONFIG_AMIFB_ECS +static struct fb_hwswitch ecs_switch = { + ecs_init, ecs_encode_fix, ecs_decode_var, ecs_encode_var, ecs_getcolreg, + ecs_setcolreg, ecs_pan_display, ecs_do_vmode, ecs_do_blank, + ecs_do_movecursor, ecs_do_flashcursor +}; +#endif /* CONFIG_AMIFB_ECS */ + +#ifdef CONFIG_AMIFB_AGA +static struct fb_hwswitch aga_switch = { + aga_init, aga_encode_fix, aga_decode_var, aga_encode_var, aga_getcolreg, + aga_setcolreg, aga_pan_display, aga_do_vmode, aga_do_blank, + aga_do_movecursor, aga_do_flashcursor +}; +#endif /* CONFIG_AMIFB_AGA */ + + +/* -------------------- Generic routines ------------------------------------ */ + + + /* + * Allocate, Clear and Align a Block of Chip Memory + */ + +static u_long chipalloc(u_long size) +{ + u_long ptr; + + size += PAGE_SIZE-1; + if (!(ptr = (u_long)amiga_chip_alloc(size))) + panic("No Chip RAM for frame buffer"); + memset((void *)ptr, 0, size); + ptr = PAGE_ALIGN(ptr); + + return(ptr); +} + + + /* + * Fill the hardware's `par' structure. + */ + +static void amiga_fb_get_par(struct amiga_fb_par *par) +{ + if (current_par_valid) + *par = current_par; + else + fbhw->decode_var(&amiga_fb_predefined[amifb_mode], par); +} + + +static void amiga_fb_set_par(struct amiga_fb_par *par) +{ + do_vmode = 0; + current_par = *par; + full_vmode_change = 1; + do_vmode = 1; + current_par_valid = 1; +} + + +static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive) +{ + int err, activate; + struct amiga_fb_par par; + + if ((err = fbhw->decode_var(var, &par))) + return(err); + activate = var->activate; + if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW && isactive) + amiga_fb_set_par(&par); + fbhw->encode_var(var, &par); + var->activate = activate; + return(0); +} + + + /* + * Default Colormaps + */ + +static u_short red2[] = + { 0x0000, 0xc000 }; +static u_short green2[] = + { 0x0000, 0xc000 }; +static u_short blue2[] = + { 0x0000, 0xc000 }; + +static u_short red4[] = + { 0x0000, 0xc000, 0x8000, 0xffff }; +static u_short green4[] = + { 0x0000, 0xc000, 0x8000, 0xffff }; +static u_short blue4[] = + { 0x0000, 0xc000, 0x8000, 0xffff }; + +static u_short red8[] = + { 0x0000, 0x0000, 0x0000, 0x0000, 0xc000, 0xc000, 0xc000, 0xc000 }; +static u_short green8[] = + { 0x0000, 0x0000, 0xc000, 0xc000, 0x0000, 0x0000, 0xc000, 0xc000 }; +static u_short blue8[] = + { 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0xc000 }; + +static u_short red16[] = + { 0x0000, 0x0000, 0x0000, 0x0000, 0xc000, 0xc000, 0xc000, 0xc000, + 0x8000, 0x0000, 0x0000, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff }; +static u_short green16[] = + { 0x0000, 0x0000, 0xc000, 0xc000, 0x0000, 0x0000, 0xc000, 0xc000, + 0x8000, 0x0000, 0xffff, 0xffff, 0x0000, 0x0000, 0xffff, 0xffff }; +static u_short blue16[] = + { 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0xc000, + 0x8000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff }; + + +static struct fb_cmap default_2_colors = + { 0, 2, red2, green2, blue2, NULL }; +static struct fb_cmap default_8_colors = + { 0, 8, red8, green8, blue8, NULL }; +static struct fb_cmap default_4_colors = + { 0, 4, red4, green4, blue4, NULL }; +static struct fb_cmap default_16_colors = + { 0, 16, red16, green16, blue16, NULL }; + + +static struct fb_cmap *get_default_colormap(int bpp) +{ + switch (bpp) { + case 1: + return(&default_2_colors); + break; + case 2: + return(&default_4_colors); + break; + case 3: + return(&default_8_colors); + break; + default: + return(&default_16_colors); + break; + } +} + + +#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7fff-(val))>>16) +#define CNVT_FROMHW(val,width) (((width) ? ((((val)<<16)-(val)) / \ + ((1<<(width))-1)) : 0)) + +static int do_fb_get_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var, + int kspc) +{ + int i, start; + u_short *red, *green, *blue, *transp; + u_int hred, hgreen, hblue, htransp; + + red = cmap->red; + green = cmap->green; + blue = cmap->blue; + transp = cmap->transp; + start = cmap->start; + if (start < 0) + return(-EINVAL); + for (i = 0; i < cmap->len; i++) { + if (fbhw->getcolreg(start++, &hred, &hgreen, &hblue, &htransp)) + return(0); + hred = CNVT_FROMHW(hred, var->red.length); + hgreen = CNVT_FROMHW(hgreen, var->green.length); + hblue = CNVT_FROMHW(hblue, var->blue.length); + htransp = CNVT_FROMHW(htransp, var->transp.length); + if (kspc) { + *red = hred; + *green = hgreen; + *blue = hblue; + if (transp) + *transp = htransp; + } else { + put_fs_word(hred, red); + put_fs_word(hgreen, green); + put_fs_word(hblue, blue); + if (transp) + put_fs_word(htransp, transp); + } + red++; + green++; + blue++; + if (transp) + transp++; + } + return(0); +} + + +static int do_fb_set_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var, + int kspc) +{ + int i, start; + u_short *red, *green, *blue, *transp; + u_int hred, hgreen, hblue, htransp; + + red = cmap->red; + green = cmap->green; + blue = cmap->blue; + transp = cmap->transp; + start = cmap->start; + + if (start < 0) + return(-EINVAL); + for (i = 0; i < cmap->len; i++) { + if (kspc) { + hred = *red; + hgreen = *green; + hblue = *blue; + htransp = transp ? *transp : 0; + } else { + hred = get_fs_word(red); + hgreen = get_fs_word(green); + hblue = get_fs_word(blue); + htransp = transp ? get_fs_word(transp) : 0; + } + hred = CNVT_TOHW(hred, var->red.length); + hgreen = CNVT_TOHW(hgreen, var->green.length); + hblue = CNVT_TOHW(hblue, var->blue.length); + htransp = CNVT_TOHW(htransp, var->transp.length); + red++; + green++; + blue++; + if (transp) + transp++; + if (fbhw->setcolreg(start++, hred, hgreen, hblue, htransp)) + return(0); + } + return(0); +} + + +static void do_install_cmap(int con) +{ + if (con != currcon) + return; + if (disp[con].cmap.len) + do_fb_set_cmap(&disp[con].cmap, &disp[con].var, 1); + else + do_fb_set_cmap(get_default_colormap(disp[con].var.bits_per_pixel), + &disp[con].var, 1); +} + + +static void memcpy_fs(int fsfromto, void *to, void *from, int len) +{ + switch (fsfromto) { + case 0: + memcpy(to, from, len); + return; + case 1: + memcpy_fromfs(to, from, len); + return; + case 2: + memcpy_tofs(to, from, len); + return; + } +} + + +static void copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto) +{ + int size; + int tooff = 0, fromoff = 0; + + if (to->start > from->start) + fromoff = to->start-from->start; + else + tooff = from->start-to->start; + size = to->len-tooff; + if (size > from->len-fromoff) + size = from->len-fromoff; + if (size < 0) + return; + size *= sizeof(u_short); + memcpy_fs(fsfromto, to->red+tooff, from->red+fromoff, size); + memcpy_fs(fsfromto, to->green+tooff, from->green+fromoff, size); + memcpy_fs(fsfromto, to->blue+tooff, from->blue+fromoff, size); + if (from->transp && to->transp) + memcpy_fs(fsfromto, to->transp+tooff, from->transp+fromoff, size); +} + + +static int alloc_cmap(struct fb_cmap *cmap, int len, int transp) +{ + int size = len*sizeof(u_short); + + if (cmap->len != len) { + if (cmap->red) + kfree(cmap->red); + if (cmap->green) + kfree(cmap->green); + if (cmap->blue) + kfree(cmap->blue); + if (cmap->transp) + kfree(cmap->transp); + cmap->red = cmap->green = cmap->blue = cmap->transp = NULL; + cmap->len = 0; + if (!len) + return(0); + if (!(cmap->red = kmalloc(size, GFP_ATOMIC))) + return(-1); + if (!(cmap->green = kmalloc(size, GFP_ATOMIC))) + return(-1); + if (!(cmap->blue = kmalloc(size, GFP_ATOMIC))) + return(-1); + if (transp) { + if (!(cmap->transp = kmalloc(size, GFP_ATOMIC))) + return(-1); + } else + cmap->transp = NULL; + } + cmap->start = 0; + cmap->len = len; + copy_cmap(get_default_colormap(len), cmap, 0); + return(0); +} + + + /* + * Get the Fixed Part of the Display + */ + +static int amiga_fb_get_fix(struct fb_fix_screeninfo *fix, int con) +{ + struct amiga_fb_par par; + int error = 0; + + if (con == -1) + amiga_fb_get_par(&par); + else + error = fbhw->decode_var(&disp[con].var, &par); + return(error ? error : fbhw->encode_fix(fix, &par)); +} + + + /* + * Get the User Defined Part of the Display + */ + +static int amiga_fb_get_var(struct fb_var_screeninfo *var, int con) +{ + struct amiga_fb_par par; + int error = 0; + + if (con == -1) { + amiga_fb_get_par(&par); + error = fbhw->encode_var(var, &par); + } else + *var = disp[con].var; + return(error); +} + + +static void amiga_fb_set_disp(int con) +{ + struct fb_fix_screeninfo fix; + + amiga_fb_get_fix(&fix, con); + if (con == -1) + con = 0; + disp[con].screen_base = (u_char *)fix.smem_start; + disp[con].visual = fix.visual; + disp[con].type = fix.type; + disp[con].type_aux = fix.type_aux; + disp[con].ypanstep = fix.ypanstep; + disp[con].ywrapstep = fix.ywrapstep; + disp[con].can_soft_blank = 1; + disp[con].inverse = amifb_inverse; +} + + + /* + * Set the User Defined Part of the Display + */ + +static int amiga_fb_set_var(struct fb_var_screeninfo *var, int con) +{ + int err, oldxres, oldyres, oldvxres, oldvyres, oldbpp; + + if ((err = do_fb_set_var(var, con == currcon))) + return(err); + if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { + oldxres = disp[con].var.xres; + oldyres = disp[con].var.yres; + oldvxres = disp[con].var.xres_virtual; + oldvyres = disp[con].var.yres_virtual; + oldbpp = disp[con].var.bits_per_pixel; + disp[con].var = *var; + if (oldxres != var->xres || oldyres != var->yres || + oldvxres != var->xres_virtual || oldvyres != var->yres_virtual || + oldbpp != var->bits_per_pixel) { + amiga_fb_set_disp(con); + (*fb_info.changevar)(con); + alloc_cmap(&disp[con].cmap, 0, 0); + do_install_cmap(con); + } + } + var->activate = 0; + return(0); +} + + + /* + * Get the Colormap + */ + +static int amiga_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con) +{ + if (con == currcon) /* current console? */ + return(do_fb_get_cmap(cmap, &disp[con].var, kspc)); + else if (disp[con].cmap.len) /* non default colormap? */ + copy_cmap(&disp[con].cmap, cmap, kspc ? 0 : 2); + else + copy_cmap(get_default_colormap(disp[con].var.bits_per_pixel), cmap, + kspc ? 0 : 2); + return(0); +} + + + /* + * Set the Colormap + */ + +static int amiga_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con) +{ + int err; + + if (!disp[con].cmap.len) { /* no colormap allocated? */ + if ((err = alloc_cmap(&disp[con].cmap, 1<vmode & FB_VMODE_YWRAP) { + if (var->xoffset || var->yoffset >= disp[con].var.yres) + return(-EINVAL); + } else { + if (var->xoffset+disp[con].var.xres > disp[con].var.xres_virtual || + var->yoffset+disp[con].var.yres > disp[con].var.yres_virtual) + return(-EINVAL); + } + if (con == currcon) { + cli(); + oldlatch = do_vmode; + do_vmode = 0; + sti(); + if ((err = fbhw->pan_display(var, ¤t_par))) { + if (oldlatch) + do_vmode = 1; + return(err); + } + do_vmode = 1; + } + disp[con].var.xoffset = var->xoffset; + disp[con].var.yoffset = var->yoffset; + if (var->vmode & FB_VMODE_YWRAP) + disp[con].var.vmode |= FB_VMODE_YWRAP; + else + disp[con].var.vmode &= ~FB_VMODE_YWRAP; + return(0); +} + + + /* + * Amiga Frame Buffer Specific ioctls + */ + +static int amiga_fb_ioctl(struct inode *inode, struct file *file, + u_int cmd, u_long arg, int con) +{ + int i; + struct fb_fix_cursorinfo crsrfix; + struct fb_var_cursorinfo crsrvar; + struct fb_cursorstate crsrstate; + + switch (cmd) { +#ifdef CONFIG_AMIFB_AGA + case FBIOGET_FCURSORINFO: + i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(crsrfix)); + if (i) + return(i); + i = amiga_fb_get_fix_cursorinfo(&crsrfix, con); + memcpy_tofs((void *)arg, &crsrfix, sizeof(crsrfix)); + return(i); + case FBIOGET_VCURSORINFO: + i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(crsrvar)); + if (i) + return(i); + i = amiga_fb_get_var_cursorinfo(&crsrvar, con); + memcpy_tofs((void *)arg, &crsrvar, sizeof(crsrvar)); + return(i); + case FBIOPUT_VCURSORINFO: + i = verify_area(VERIFY_READ, (void *)arg, sizeof(crsrvar)); + if (i) + return(i); + memcpy_fromfs(&crsrvar, (void *)arg, sizeof(crsrvar)); + i = amiga_fb_set_var_cursorinfo(&crsrvar, con); + return(i); + case FBIOGET_CURSORSTATE: + i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(crsrstate)); + if (i) + return(i); + i = amiga_fb_get_cursorstate(&crsrstate, con); + memcpy_tofs((void *)arg, &crsrstate, sizeof(crsrstate)); + return(i); + case FBIOPUT_CURSORSTATE: + i = verify_area(VERIFY_READ, (void *)arg, sizeof(crsrstate)); + if (i) + return(i); + memcpy_fromfs(&crsrstate, (void *)arg, sizeof(crsrstate)); + i = amiga_fb_set_cursorstate(&crsrstate, con); + return(i); +#endif /* CONFIG_AMIFB_AGA */ +#if 1 + case FBCMD_GET_CURRENTPAR: + if ((i = verify_area(VERIFY_WRITE, (void *)arg, + sizeof(struct amiga_fb_par)))) + return(i); + memcpy_tofs((void *)arg, (void *)¤t_par, + sizeof(struct amiga_fb_par)); + return(0); + break; + case FBCMD_SET_CURRENTPAR: + if ((i = verify_area(VERIFY_READ, (void *)arg, + sizeof(struct amiga_fb_par)))) + return(i); + memcpy_fromfs((void *)¤t_par, (void *)arg, + sizeof(struct amiga_fb_par)); + return(0); + break; +#endif + } + return(-EINVAL); +} + + +#ifdef CONFIG_AMIFB_AGA + /* + * Hardware Cursor + */ + +static int amiga_fb_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con) +{ + if (boot_info.bi_amiga.chipset == CS_AGA) + return(aga_get_fix_cursorinfo(fix, con)); + return(-EINVAL); +} + + +static int amiga_fb_get_var_cursorinfo(struct fb_var_cursorinfo *var, int con) +{ + if (boot_info.bi_amiga.chipset == CS_AGA) + return(aga_get_var_cursorinfo(var, con)); + return(-EINVAL); +} + + +static int amiga_fb_set_var_cursorinfo(struct fb_var_cursorinfo *var, int con) +{ + if (boot_info.bi_amiga.chipset == CS_AGA) + return(aga_set_var_cursorinfo(var, con)); + return(-EINVAL); +} + + +static int amiga_fb_get_cursorstate(struct fb_cursorstate *state, int con) +{ + if (boot_info.bi_amiga.chipset == CS_AGA) + return(aga_get_cursorstate(state, con)); + return(-EINVAL); +} + + +static int amiga_fb_set_cursorstate(struct fb_cursorstate *state, int con) +{ + if (boot_info.bi_amiga.chipset == CS_AGA) + return(aga_set_cursorstate(state, con)); + return(-EINVAL); +} +#endif /* CONFIG_AMIFB_AGA */ + + +static struct fb_ops amiga_fb_ops = { + amiga_fb_get_fix, amiga_fb_get_var, amiga_fb_set_var, amiga_fb_get_cmap, + amiga_fb_set_cmap, amiga_fb_pan_display, amiga_fb_ioctl +}; + + +void amiga_video_setup(char *options, int *ints) +{ + char *this_opt; + int i; + char mcap_spec[80]; + + /* + * Check for a Graphics Board + */ + +#ifdef CONFIG_FB_CYBER + if (options && *options) + if (!strncmp(options, "cyber", 5) && Cyber_probe()) { + amifb_Cyber = 1; + Cyber_video_setup(options, ints); + return; + } +#endif /* CONFIG_FB_CYBER */ + +#ifdef USE_MONO_AMIFB_IF_NON_AGA + if (boot_info.bi_amiga.chipset != CS_AGA) { + mono_video_setup(options, ints); + return; + } +#endif /* USE_MONO_AMIFB_IF_NON_AGA */ + + mcap_spec[0] = '\0'; + fb_info.fontname[0] = '\0'; + + if (!options || !*options) + return; + + for (this_opt = strtok(options, ","); this_opt; this_opt = strtok(NULL, ",")) + if (!strcmp(this_opt, "inverse")) { + amifb_inverse = 1; + for (i = 0; i < 16; i++) { + red16[i] = ~red16[i]; + green16[i] = ~green16[i]; + blue16[i] = ~blue16[i]; + } + for (i = 0; i < 8; i++) { + red8[i] = ~red8[i]; + green8[i] = ~green8[i]; + blue8[i] = ~blue8[i]; + } + for (i = 0; i < 4; i++) { + red4[i] = ~red4[i]; + green4[i] = ~green4[i]; + blue4[i] = ~blue4[i]; + } + for (i = 0; i < 2; i++) { + red2[i] = ~red2[i]; + green2[i] = ~green2[i]; + blue2[i] = ~blue2[i]; + } + } else if (!strcmp(this_opt, "ilbm")) + amifb_ilbm = 1; + else if (!strcmp(this_opt, "pwrsave")) + pwrsave = 1; + else if (!strncmp(this_opt, "monitorcap:", 11)) + strcpy(mcap_spec, this_opt+11); + else if (!strncmp(this_opt, "font:", 5)) + strcpy(fb_info.fontname, this_opt+5); + else + amifb_mode = get_video_mode(this_opt); + + if (*mcap_spec) { + char *p; + int vmin, vmax, hmin, hmax; + + /* Format for monitor capabilities is: ;;; + * vertical freq. in Hz + * horizontal freq. in kHz + */ + + if (!(p = strtoke(mcap_spec, ";")) || !*p) + goto cap_invalid; + vmin = simple_strtoul(p, NULL, 10); + if (vmin <= 0) + goto cap_invalid; + if (!(p = strtoke(NULL, ";")) || !*p) + goto cap_invalid; + vmax = simple_strtoul(p, NULL, 10); + if (vmax <= 0 || vmax <= vmin) + goto cap_invalid; + if (!(p = strtoke(NULL, ";")) || !*p) + goto cap_invalid; + hmin = 1000 * simple_strtoul(p, NULL, 10); + if (hmin <= 0) + goto cap_invalid; + if (!(p = strtoke(NULL, "")) || !*p) + goto cap_invalid; + hmax = 1000 * simple_strtoul(p, NULL, 10); + if (hmax <= 0 || hmax <= hmin) + goto cap_invalid; + + vfmin = vmin; + vfmax = vmax; + hfmin = hmin; + hfmax = hmax; +cap_invalid: + ; + } +} + + + /* + * Initialization + */ + +struct fb_info *amiga_fb_init(long *mem_start) +{ + int err, tag, i; + struct fb_var_screeninfo *var; + + /* + * Check for a Graphics Board + */ + +#ifdef CONFIG_FB_CYBER + if (amifb_Cyber) + return(Cyber_fb_init(mem_start)); +#endif /* CONFIG_FB_CYBER */ + + /* + * Use the Builtin Chipset + */ + + if (!AMIGAHW_PRESENT(AMI_VIDEO)) + return(NULL); + +#ifdef USE_MONO_AMIFB_IF_NON_AGA + if (boot_info.bi_amiga.chipset != CS_AGA) + return(mono_amiga_fb_init(mem_start)); +#endif /* USE_MONO_AMIFB_IF_NON_AGA */ + + switch (boot_info.bi_amiga.chipset) { +#ifdef CONFIG_AMIFB_OCS + case CS_OCS: + strcat(amiga_fb_name, "OCS"); +default_chipset: + fbhw = &ocs_switch; + maxdepth[TAG_SHRES-1] = 0; /* OCS means no SHRES */ + maxdepth[TAG_HIRES-1] = 4; + maxdepth[TAG_LORES-1] = 6; + break; +#endif /* CONFIG_AMIFB_OCS */ + +#ifdef CONFIG_AMIFB_ECS + case CS_ECS: + strcat(amiga_fb_name, "ECS"); + fbhw = &ecs_switch; + maxdepth[TAG_SHRES-1] = 2; + maxdepth[TAG_HIRES-1] = 4; + maxdepth[TAG_LORES-1] = 6; + break; +#endif /* CONFIG_AMIFB_ECS */ + +#ifdef CONFIG_AMIFB_AGA + case CS_AGA: + strcat(amiga_fb_name, "AGA"); + fbhw = &aga_switch; + maxdepth[TAG_SHRES-1] = 8; + maxdepth[TAG_HIRES-1] = 8; + maxdepth[TAG_LORES-1] = 8; + break; +#endif /* CONFIG_AMIFB_AGA */ + + default: +#ifdef CONFIG_AMIFB_OCS + printk("Unknown graphics chipset, defaulting to OCS\n"); + strcat(amiga_fb_name, "Unknown"); + goto default_chipset; +#else /* CONFIG_AMIFB_OCS */ + panic("Unknown graphics chipset, no default driver"); +#endif /* CONFIG_AMIFB_OCS */ + break; + } + + /* + * Calculate the Pixel Clock Values for this Machine + */ + + pixclock[TAG_SHRES-1] = 25E9/amiga_eclock; /* SHRES: 35 ns / 28 MHz */ + pixclock[TAG_HIRES-1] = 50E9/amiga_eclock; /* HIRES: 70 ns / 14 MHz */ + pixclock[TAG_LORES-1] = 100E9/amiga_eclock; /* LORES: 140 ns / 7 MHz */ + + /* + * Replace the Tag Values with the Real Pixel Clock Values + */ + + for (i = 0; i < NUM_PREDEF_MODES; i++) { + tag = amiga_fb_predefined[i].pixclock; + if (tag == TAG_SHRES || tag == TAG_HIRES || tag == TAG_LORES) { + amiga_fb_predefined[i].pixclock = pixclock[tag-1]; + if (amiga_fb_predefined[i].bits_per_pixel > maxdepth[tag-1]) + amiga_fb_predefined[i].bits_per_pixel = maxdepth[tag-1]; + } + } + + err = register_framebuffer(amiga_fb_name, &node, &amiga_fb_ops, + NUM_TOTAL_MODES, amiga_fb_predefined); + if (err < 0) + panic("Cannot register frame buffer"); + + fbhw->init(); + check_default_mode(); + + if (!add_isr(IRQ_AMIGA_VERTB, amifb_interrupt, 0, NULL, "frame buffer")) + panic("Couldn't add vblank interrupt"); + + strcpy(fb_info.modename, amiga_fb_name); + fb_info.disp = disp; + fb_info.switch_con = &amifb_switch; + fb_info.updatevar = &amifb_updatevar; + fb_info.blank = &amifb_blank; + + var = &amiga_fb_predefined[amifb_mode]; + do_fb_set_var(var, 1); + strcat(fb_info.modename, " "); + strcat(fb_info.modename, amiga_fb_modenames[amifb_mode]); + + amiga_fb_get_var(&disp[0].var, -1); + amiga_fb_set_disp(-1); + do_install_cmap(0); + return(&fb_info); +} + + +static int amifb_switch(int con) +{ + /* Do we have to save the colormap? */ + if (disp[currcon].cmap.len) + do_fb_get_cmap(&disp[currcon].cmap, &disp[currcon].var, 1); + + do_fb_set_var(&disp[con].var, 1); + currcon = con; + /* Install new colormap */ + do_install_cmap(con); + return(0); +} + + + /* + * Update the `var' structure (called by fbcon.c) + * + * This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'. + * Since it's called by a kernel driver, no range checking is done. + */ + +static int amifb_updatevar(int con) +{ + do_vmode = 0; + current_par.yoffset = disp[con].var.yoffset; + current_par.vmode = disp[con].var.vmode; + current_par.bplpt0 = ZTWO_PADDR((u_long)videomemory+ + current_par.yoffset*current_par.next_line); + do_vmode = 1; + return(0); +} + + + /* + * Blank the display. + */ + +static void amifb_blank(int blank) +{ + do_blank = blank ? 1 : -1; +} + + + /* + * VBlank Display Interrupt + */ + +static void amifb_interrupt(int irq, struct pt_regs *fp, void *dummy) +{ + static int is_laced = 0; + +#if 0 + /* + * This test should be here, in case current_par isn't initialized yet + * + * Fortunately only do_flashcursor() will be called in that case, and + * currently that function doesn't use current_par. But this may change + * in future... + */ + if (!current_par_valid) + return; +#endif + + /* + * If interlaced, only change the display on a long frame + */ + + if (!is_laced || custom.vposr & 0x8000) { + if (do_vmode) { + fbhw->do_vmode(); + do_vmode = 0; + is_laced = (current_par.vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED; + } + if (do_movecursor) { + fbhw->do_movecursor(); + do_movecursor = 0; + } + } + if (do_blank) { + fbhw->do_blank(do_blank > 0 ? 1 : 0); + do_blank = 0; + } + if (!is_blanked) + fbhw->do_flashcursor(); +} + + + /* + * A strtok which returns empty strings, too + */ + +static char * strtoke(char * s,const char * ct) +{ + char *sbegin, *send; + static char *ssave = NULL; + + sbegin = s ? s : ssave; + if (!sbegin) + return(NULL); + if (*sbegin == '\0') { + ssave = NULL; + return(NULL); + } + send = strpbrk(sbegin, ct); + if (send && *send != '\0') + *send++ = '\0'; + ssave = send; + return(sbegin); +} + + + /* + * Get a Video Modes + */ + +static int get_video_mode(const char *name) +{ + int i; + + for (i = 1; i < NUM_PREDEF_MODES; i++) + if (!strcmp(name, amiga_fb_modenames[i])) + return(i); + return(0); +} + + + /* + * Check the Default Video Mode + */ + +static void check_default_mode(void) +{ + struct fb_var_screeninfo var; + + /* First check the user supplied or system default video mode */ + if (amifb_mode) { + var = amiga_fb_predefined[amifb_mode]; + var.activate = FB_ACTIVATE_TEST; + if (!do_fb_set_var(&var, 1)) + goto found_video_mode; + } + + /* Try some other modes... */ + printk("Can't use default video mode. Probing video modes...\n"); + for (amifb_mode = 1; amifb_mode < NUM_PREDEF_MODES; amifb_mode++) { + var = amiga_fb_predefined[amifb_mode]; + var.activate = FB_ACTIVATE_TEST; + if (!do_fb_set_var(&var, 1)) + goto found_video_mode; + } + panic("Can't find any usable video mode"); + +found_video_mode: + amiga_fb_predefined[0] = var; +} diff -u --recursive --new-file v1.3.93/linux/arch/m68k/amiga/amiints.c linux/arch/m68k/amiga/amiints.c --- v1.3.93/linux/arch/m68k/amiga/amiints.c Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/amiga/amiints.c Wed Mar 20 20:02:50 1996 @@ -0,0 +1,376 @@ +/* + * amiints.c -- Amiga Linux interrupt handling code + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file README.legal in the main directory of this archive + * for more details. + * + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +/* isr node variables for amiga interrupt sources */ +static isr_node_t *ami_lists[NUM_AMIGA_SOURCES]; + +static const ushort ami_intena_vals[NUM_AMIGA_SOURCES] = { + IF_VERTB, IF_COPER, IF_AUD0, IF_AUD1, IF_AUD2, IF_AUD3, IF_BLIT, + IF_DSKSYN, IF_DSKBLK, IF_RBF, IF_TBE, IF_PORTS, IF_PORTS, IF_PORTS, + IF_PORTS, IF_PORTS, IF_EXTER, IF_EXTER, IF_EXTER, IF_EXTER, IF_EXTER, + IF_SOFT, IF_PORTS, IF_EXTER + }; + +struct ciadata +{ + volatile struct CIA *ciaptr; + unsigned long baseirq; +} ciadata[2]; + +/* + * index into ami_lists for IRQs. CIA IRQs are special, because + * the same cia interrupt handler is used for both CIAs. + */ +#define IRQ_IDX(source) (source & ~IRQ_MACHSPEC) +#define CIA_IRQ_IDX(source) (IRQ_IDX(datap->baseirq) \ + +(source-IRQ_AMIGA_CIAA_TA)) + +/* + * void amiga_init_INTS (void) + * + * Parameters: None + * + * Returns: Nothing + * + * This function should be called during kernel startup to initialize + * the amiga IRQ handling routines. + */ + +static void + ami_int1(int irq, struct pt_regs *fp, void *data), + ami_int2(int irq, struct pt_regs *fp, void *data), + ami_int3(int irq, struct pt_regs *fp, void *data), + ami_int4(int irq, struct pt_regs *fp, void *data), + ami_int5(int irq, struct pt_regs *fp, void *data), + ami_int6(int irq, struct pt_regs *fp, void *data), + ami_int7(int irq, struct pt_regs *fp, void *data), + ami_intcia(int irq, struct pt_regs *fp, void *data); + +void amiga_init_INTS (void) +{ + int i; + + /* initialize handlers */ + for (i = 0; i < NUM_AMIGA_SOURCES; i++) + ami_lists[i] = NULL; + + add_isr (IRQ1, ami_int1, 0, NULL, "int1 handler"); + add_isr (IRQ2, ami_int2, 0, NULL, "int2 handler"); + add_isr (IRQ3, ami_int3, 0, NULL, "int3 handler"); + add_isr (IRQ4, ami_int4, 0, NULL, "int4 handler"); + add_isr (IRQ5, ami_int5, 0, NULL, "int5 handler"); + add_isr (IRQ6, ami_int6, 0, NULL, "int6 handler"); + add_isr (IRQ7, ami_int7, 0, NULL, "int7 handler"); + + /* hook in the CIA interrupts */ + ciadata[0].ciaptr = &ciaa; + ciadata[0].baseirq = IRQ_AMIGA_CIAA_TA; + add_isr (IRQ_AMIGA_PORTS, ami_intcia, 0, NULL, "Amiga CIAA"); + ciadata[1].ciaptr = &ciab; + ciadata[1].baseirq = IRQ_AMIGA_CIAB_TA; + add_isr (IRQ_AMIGA_EXTER, ami_intcia, 0, NULL, "Amiga CIAB"); + + /* turn off all interrupts and enable the master interrupt bit */ + custom.intena = 0x7fff; + custom.intreq = 0x7fff; + custom.intena = 0xc000; + + /* turn off all CIA interrupts */ + ciaa.icr = 0x7f; + ciab.icr = 0x7f; + + /* clear any pending CIA interrupts */ + i = ciaa.icr; + i = ciab.icr; +} + + +/* + * The builtin Amiga hardware interrupt handlers. + */ + +static void ami_int1 (int irq, struct pt_regs *fp, void *data) +{ + ushort ints = custom.intreqr & custom.intenar; + + /* if serial transmit buffer empty, interrupt */ + if (ints & IF_TBE) { + if (ami_lists[IRQ_IDX(IRQ_AMIGA_TBE)]) { + call_isr_list (IRQ_AMIGA_TBE, + ami_lists[IRQ_IDX(IRQ_AMIGA_TBE)], fp); + /* + * don't acknowledge.... + * allow serial code to turn off interrupts, but + * leave it pending so that when interrupts are + * turned on, transmission will resume + */ + } else + /* acknowledge the interrupt */ + custom.intreq = IF_TBE; + } + + /* if floppy disk transfer complete, interrupt */ + if (ints & IF_DSKBLK) { + call_isr_list (IRQ_AMIGA_DSKBLK, + ami_lists[IRQ_IDX(IRQ_AMIGA_DSKBLK)], fp); + + /* acknowledge */ + custom.intreq = IF_DSKBLK; + } + + /* if software interrupt set, interrupt */ + if (ints & IF_SOFT) { + call_isr_list (IRQ_AMIGA_SOFT, + ami_lists[IRQ_IDX(IRQ_AMIGA_SOFT)], fp); + + /* acknowledge */ + custom.intreq = IF_SOFT; + } +} + +static void ami_int2 (int irq, struct pt_regs *fp, void *data) +{ + ushort ints = custom.intreqr & custom.intenar; + + if (ints & IF_PORTS) { + /* call routines which have hooked into the PORTS interrupt */ + call_isr_list (IRQ_AMIGA_PORTS, + ami_lists[IRQ_IDX(IRQ_AMIGA_PORTS)], fp); + + /* acknowledge */ + custom.intreq = IF_PORTS; + } +} + +static void ami_int3 (int irq, struct pt_regs *fp, void *data) +{ + ushort ints = custom.intreqr & custom.intenar; + + /* if a copper interrupt */ + if (ints & IF_COPER) { + call_isr_list (IRQ_AMIGA_COPPER, + ami_lists[IRQ_IDX(IRQ_AMIGA_COPPER)], fp); + + /* acknowledge */ + custom.intreq = IF_COPER; + } + + /* if a vertical blank interrupt */ + if (ints & IF_VERTB) { + call_isr_list (IRQ_AMIGA_VERTB, + ami_lists[IRQ_IDX(IRQ_AMIGA_VERTB)], fp); + + /* acknowledge */ + custom.intreq = IF_VERTB; + } + + /* if a blitter interrupt */ + if (ints & IF_BLIT) { + call_isr_list (IRQ_AMIGA_BLIT, + ami_lists[IRQ_IDX(IRQ_AMIGA_BLIT)], fp); + + /* acknowledge */ + custom.intreq = IF_BLIT; + } +} + +static void ami_int4 (int irq, struct pt_regs *fp, void *data) +{ + ushort ints = custom.intreqr & custom.intenar; + + /* if audio 0 interrupt */ + if (ints & IF_AUD0) { + call_isr_list (IRQ_AMIGA_AUD0, + ami_lists[IRQ_IDX(IRQ_AMIGA_AUD0)], fp); + + /* acknowledge */ + custom.intreq = IF_AUD0; + } + + /* if audio 1 interrupt */ + if (ints & IF_AUD1) { + call_isr_list (IRQ_AMIGA_AUD1, + ami_lists[IRQ_IDX(IRQ_AMIGA_AUD1)], fp); + + /* acknowledge */ + custom.intreq = IF_AUD1; + } + + /* if audio 2 interrupt */ + if (ints & IF_AUD2) { + call_isr_list (IRQ_AMIGA_AUD2, + ami_lists[IRQ_IDX(IRQ_AMIGA_AUD2)], fp); + + /* acknowledge */ + custom.intreq = IF_AUD2; + } + + /* if audio 3 interrupt */ + if (ints & IF_AUD3) { + call_isr_list (IRQ_AMIGA_AUD3, + ami_lists[IRQ_IDX(IRQ_AMIGA_AUD3)], fp); + + /* acknowledge */ + custom.intreq = IF_AUD3; + } +} + +static void ami_int5 (int irq, struct pt_regs *fp, void *data) +{ + ushort ints = custom.intreqr & custom.intenar; + + /* if serial receive buffer full interrupt */ + if (ints & IF_RBF) { + if (ami_lists[IRQ_IDX(IRQ_AMIGA_RBF)]) { + call_isr_list (IRQ_AMIGA_RBF, + ami_lists[IRQ_IDX(IRQ_AMIGA_RBF)], fp); + /* don't acknowledge ; leave that for the handler */ + } else + /* acknowledge the interrupt */ + custom.intreq = IF_RBF; + } + + /* if a disk sync interrupt */ + if (ints & IF_DSKSYN) { + call_isr_list (IRQ_AMIGA_DSKSYN, + ami_lists[IRQ_IDX(IRQ_AMIGA_DSKSYN)], fp); + + /* acknowledge */ + custom.intreq = IF_DSKSYN; + } +} + +static void ami_int6 (int irq, struct pt_regs *fp, void *data) +{ + ushort ints = custom.intreqr & custom.intenar; + + if (ints & IF_EXTER) { + /* call routines which have hooked into the EXTER interrupt */ + call_isr_list (IRQ_AMIGA_EXTER, + ami_lists[IRQ_IDX(IRQ_AMIGA_EXTER)], fp); + + /* acknowledge */ + custom.intreq = IF_EXTER; + } +} + +static void ami_int7 (int irq, struct pt_regs *fp, void *data) +{ + panic ("level 7 interrupt received\n"); +} + +static void ami_intcia (int irq, struct pt_regs *fp, void *data) +{ + /* check CIA interrupts */ + struct ciadata *datap; + u_char cia_ints; + + /* setup data correctly */ + if (irq == IRQ_AMIGA_PORTS) + datap = &ciadata[0]; + else + datap = &ciadata[1]; + + cia_ints = datap->ciaptr->icr; + + /* if timer A interrupt */ + if (cia_ints & CIA_ICR_TA) + call_isr_list (IRQ_AMIGA_CIAA_TA, + ami_lists[CIA_IRQ_IDX(IRQ_AMIGA_CIAA_TA)], fp); + + /* if timer B interrupt */ + if (cia_ints & CIA_ICR_TB) + call_isr_list (IRQ_AMIGA_CIAA_TB, + ami_lists[CIA_IRQ_IDX(IRQ_AMIGA_CIAA_TB)], fp); + + /* if the alarm interrupt */ + if (cia_ints & CIA_ICR_ALRM) + call_isr_list (IRQ_AMIGA_CIAA_ALRM, + ami_lists[CIA_IRQ_IDX(IRQ_AMIGA_CIAA_ALRM)], fp); + + /* if serial port interrupt (keyboard) */ + if (cia_ints & CIA_ICR_SP) + call_isr_list (IRQ_AMIGA_CIAA_SP, + ami_lists[CIA_IRQ_IDX(IRQ_AMIGA_CIAA_SP)], fp); + + /* if flag interrupt (parallel port) */ + if (cia_ints & CIA_ICR_FLG) + call_isr_list (IRQ_AMIGA_CIAA_FLG, + ami_lists[CIA_IRQ_IDX(IRQ_AMIGA_CIAA_FLG)], fp); +} + +/* + * amiga_add_isr : add an interrupt service routine for a particular + * machine specific interrupt source. + * If the addition was successful, it returns 1, otherwise + * it returns 0. It will fail if another routine is already + * bound into the specified source. + * Note that the "pri" argument is currently unused. + */ + +int amiga_add_isr (unsigned long source, isrfunc isr, int pri, void + *data, char *name) +{ + unsigned long amiga_source = source & ~IRQ_MACHSPEC; + isr_node_t *p; + + if (amiga_source > NUM_AMIGA_SOURCES) { + printk ("amiga_add_isr: Unknown interrupt source %ld\n", source); + return 0; + } + + p = new_isr_node(); + p->isr = isr; + p->pri = pri; + p->data = data; + p->name = name; + p->next = NULL; + insert_isr (&ami_lists[amiga_source], p); + + /* enable the interrupt */ + custom.intena = IF_SETCLR | ami_intena_vals[amiga_source]; + + /* if a CIAA interrupt, enable the appropriate CIA ICR bit */ + if (source >= IRQ_AMIGA_CIAA_TA && source <= IRQ_AMIGA_CIAA_FLG) + ciaa.icr = 0x80 | (1 << (source - IRQ_AMIGA_CIAA_TA)); + + /* if a CIAB interrupt, enable the appropriate CIA ICR bit */ + if (source >= IRQ_AMIGA_CIAB_TA && source <= IRQ_AMIGA_CIAB_FLG) + ciab.icr = 0x80 | (1 << (source - IRQ_AMIGA_CIAB_TA)); + + return 1; +} + +int amiga_get_irq_list( char *buf, int len ) +{ int i; + isr_node_t *p; + + for( i = 0; i < NUM_AMIGA_SOURCES; ++i ) { + if (!ami_lists[i]) + continue; + len += sprintf( buf+len, "ami %2d: ???????? ", i ); + for( p = ami_lists[i]; p; p = p->next ) { + len += sprintf( buf+len, "%s\n", p->name ); + if (p->next) + len += sprintf( buf+len, " " ); + } + } + + return( len ); +} diff -u --recursive --new-file v1.3.93/linux/arch/m68k/amiga/amikeyb.c linux/arch/m68k/amiga/amikeyb.c --- v1.3.93/linux/arch/m68k/amiga/amikeyb.c Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/amiga/amikeyb.c Sat Mar 30 20:29:34 1996 @@ -0,0 +1,300 @@ +/* + * linux/amiga/amikeyb.c + * + * Amiga Keyboard driver for 680x0 Linux + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file README.legal in the main directory of this archive + * for more details. + */ + +/* + * Amiga support by Hamish Macdonald + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +extern int do_poke_blanked_console; +extern void process_keycode (int); + +#define AMIKEY_CAPS (0x62) +#define BREAK_MASK (0x80) + +static u_short amiplain_map[NR_KEYS] = { + 0xf060, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, 0xf037, + 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf05c, 0xf200, 0xf300, + 0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69, + 0xfb6f, 0xfb70, 0xf05b, 0xf05d, 0xf200, 0xf301, 0xf302, 0xf303, + 0xfb61, 0xfb73, 0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, + 0xfb6c, 0xf03b, 0xf027, 0xf200, 0xf200, 0xf304, 0xf305, 0xf306, + 0xf200, 0xfb7a, 0xfb78, 0xfb63, 0xfb76, 0xfb62, 0xfb6e, 0xfb6d, + 0xf02c, 0xf02e, 0xf02f, 0xf200, 0xf310, 0xf307, 0xf308, 0xf309, + 0xf020, 0xf07f, 0xf009, 0xf30e, 0xf201, 0xf01b, 0xf07f, 0xf200, + 0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601, + 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, 0xf105, 0xf106, 0xf107, + 0xf108, 0xf109, 0xf208, 0xf209, 0xf30d, 0xf30c, 0xf30a, 0xf10a, + 0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +static u_short amishift_map[NR_KEYS] = { + 0xf07e, 0xf021, 0xf040, 0xf023, 0xf024, 0xf025, 0xf05e, 0xf026, + 0xf02a, 0xf028, 0xf029, 0xf05f, 0xf02b, 0xf07c, 0xf200, 0xf300, + 0xfb51, 0xfb57, 0xfb45, 0xfb52, 0xfb54, 0xfb59, 0xfb55, 0xfb49, + 0xfb4f, 0xfb50, 0xf07b, 0xf07d, 0xf200, 0xf301, 0xf302, 0xf303, + 0xfb41, 0xfb53, 0xfb44, 0xfb46, 0xfb47, 0xfb48, 0xfb4a, 0xfb4b, + 0xfb4c, 0xf03a, 0xf022, 0xf200, 0xf200, 0xf304, 0xf305, 0xf306, + 0xf200, 0xfb5a, 0xfb58, 0xfb43, 0xfb56, 0xfb42, 0xfb4e, 0xfb4d, + 0xf03c, 0xf03e, 0xf03f, 0xf200, 0xf310, 0xf307, 0xf308, 0xf309, + 0xf020, 0xf07f, 0xf009, 0xf30e, 0xf201, 0xf01b, 0xf07f, 0xf200, + 0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601, + 0xf10a, 0xf10b, 0xf10c, 0xf10d, 0xf10e, 0xf10f, 0xf110, 0xf111, + 0xf112, 0xf113, 0xf208, 0xf203, 0xf30d, 0xf30c, 0xf30a, 0xf10a, + 0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +static u_short amialtgr_map[NR_KEYS] = { + 0xf200, 0xf200, 0xf040, 0xf200, 0xf024, 0xf200, 0xf200, 0xf07b, + 0xf05b, 0xf05d, 0xf07d, 0xf05c, 0xf200, 0xf200, 0xf200, 0xf300, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf07e, 0xf200, 0xf301, 0xf302, 0xf303, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf304, 0xf305, 0xf306, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf310, 0xf307, 0xf308, 0xf309, + 0xf200, 0xf07f, 0xf200, 0xf30e, 0xf201, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601, + 0xf50c, 0xf50d, 0xf50e, 0xf50f, 0xf510, 0xf511, 0xf512, 0xf513, + 0xf514, 0xf515, 0xf208, 0xf202, 0xf30d, 0xf30c, 0xf30a, 0xf516, + 0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +static u_short amictrl_map[NR_KEYS] = { + 0xf000, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01d, 0xf01e, 0xf01f, + 0xf07f, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf01c, 0xf200, 0xf300, + 0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009, + 0xf00f, 0xf010, 0xf01b, 0xf01d, 0xf200, 0xf301, 0xf302, 0xf303, + 0xf001, 0xf013, 0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, + 0xf00c, 0xf200, 0xf007, 0xf200, 0xf200, 0xf304, 0xf305, 0xf306, + 0xf200, 0xf01a, 0xf018, 0xf003, 0xf016, 0xf002, 0xf00e, 0xf00d, + 0xf200, 0xf200, 0xf07f, 0xf200, 0xf310, 0xf307, 0xf308, 0xf309, + 0xf000, 0xf07f, 0xf200, 0xf30e, 0xf201, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601, + 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, 0xf105, 0xf106, 0xf107, + 0xf108, 0xf109, 0xf208, 0xf204, 0xf30d, 0xf30c, 0xf30a, 0xf10a, + 0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +static u_short amishift_ctrl_map[NR_KEYS] = { + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf300, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf301, 0xf302, 0xf303, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf304, 0xf305, 0xf306, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf310, 0xf307, 0xf308, 0xf309, + 0xf200, 0xf07f, 0xf200, 0xf30e, 0xf201, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf208, 0xf200, 0xf30d, 0xf30c, 0xf30a, 0xf200, + 0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +static u_short amialt_map[NR_KEYS] = { + 0xf860, 0xf831, 0xf832, 0xf833, 0xf834, 0xf835, 0xf836, 0xf837, + 0xf838, 0xf839, 0xf830, 0xf82d, 0xf83d, 0xf85c, 0xf200, 0xf900, + 0xf871, 0xf877, 0xf865, 0xf872, 0xf874, 0xf879, 0xf875, 0xf869, + 0xf86f, 0xf870, 0xf85b, 0xf85d, 0xf200, 0xf901, 0xf902, 0xf903, + 0xf861, 0xf873, 0xf864, 0xf866, 0xf867, 0xf868, 0xf86a, 0xf86b, + 0xf86c, 0xf83b, 0xf827, 0xf200, 0xf200, 0xf904, 0xf905, 0xf906, + 0xf200, 0xf87a, 0xf878, 0xf863, 0xf876, 0xf862, 0xf86e, 0xf86d, + 0xf82c, 0xf82e, 0xf82f, 0xf200, 0xf310, 0xf907, 0xf908, 0xf909, + 0xf820, 0xf87f, 0xf809, 0xf30e, 0xf80d, 0xf81b, 0xf87f, 0xf200, + 0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601, + 0xf500, 0xf501, 0xf502, 0xf503, 0xf504, 0xf505, 0xf506, 0xf507, + 0xf508, 0xf509, 0xf208, 0xf209, 0xf30d, 0xf30c, 0xf30a, 0xf50a, + 0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +static u_short amictrl_alt_map[NR_KEYS] = { + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf300, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf301, 0xf302, 0xf303, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf304, 0xf305, 0xf306, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf20c, 0xf307, 0xf308, 0xf309, + 0xf200, 0xf07f, 0xf200, 0xf30e, 0xf201, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf208, 0xf200, 0xf30d, 0xf30c, 0xf30a, 0xf200, + 0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +#define DEFAULT_KEYB_REP_DELAY (HZ/4) +#define DEFAULT_KEYB_REP_RATE (HZ/25) + +/* These could be settable by some ioctl() in future... */ +static unsigned int key_repeat_delay = DEFAULT_KEYB_REP_DELAY; +static unsigned int key_repeat_rate = DEFAULT_KEYB_REP_RATE; + +static unsigned char rep_scancode; +static void amikeyb_rep (unsigned long ignore); +static struct timer_list amikeyb_rep_timer = {NULL, NULL, 0, 0, amikeyb_rep}; + +extern struct pt_regs *pt_regs; + +static void amikeyb_rep (unsigned long ignore) +{ + unsigned long flags; + save_flags(flags); + cli(); + + pt_regs = NULL; + + amikeyb_rep_timer.expires = jiffies + key_repeat_rate; + amikeyb_rep_timer.prev = amikeyb_rep_timer.next = NULL; + add_timer(&amikeyb_rep_timer); + process_keycode (rep_scancode); + + restore_flags(flags); +} + +static void keyboard_interrupt (int irq, struct pt_regs *fp, void *dummy) +{ + unsigned char scancode, break_flag; + + /* save frame for register dump */ + pt_regs = (struct pt_regs *)fp; + + /* get and invert scancode (keyboard is active low) */ + scancode = ~ciaa.sdr; + + /* switch SP pin to output for handshake */ + ciaa.cra |= 0x40; + /* wait until 85 us have expired */ + udelay(85); + /* switch CIA serial port to input mode */ + ciaa.cra &= ~0x40; + + /* rotate scan code to get up/down bit in proper position */ + __asm__ __volatile__ ("rorb #1,%0" : "=g" (scancode) : "0" (scancode)); + + /* + * do machine independent keyboard processing of "normalized" scancode + * A "normalized" scancode is one that an IBM PC might generate + * Check make/break first + */ + break_flag = scancode & BREAK_MASK; + scancode &= (unsigned char )~BREAK_MASK; + + if (scancode == AMIKEY_CAPS) { + /* if the key is CAPS, fake a press/release. */ + process_keycode (AMIKEY_CAPS); + process_keycode (BREAK_MASK | AMIKEY_CAPS); + } else { + /* handle repeat */ + if (break_flag) { + del_timer(&amikeyb_rep_timer); + rep_scancode = 0; + } else { + del_timer(&amikeyb_rep_timer); + rep_scancode = break_flag | scancode; + amikeyb_rep_timer.expires = jiffies + key_repeat_delay; + amikeyb_rep_timer.prev = amikeyb_rep_timer.next = NULL; + add_timer(&amikeyb_rep_timer); + } + process_keycode (break_flag | scancode); + } + + do_poke_blanked_console = 1; + mark_bh(CONSOLE_BH); + add_keyboard_randomness(scancode); + + return; +} + +int amiga_keyb_init (void) +{ + if (!AMIGAHW_PRESENT(AMI_KEYBOARD)) + return -EIO; + + /* setup key map */ + key_maps[0] = amiplain_map; + key_maps[1] = amishift_map; + key_maps[2] = amialtgr_map; + key_maps[4] = amictrl_map; + key_maps[5] = amishift_ctrl_map; + key_maps[8] = amialt_map; + key_maps[12] = amictrl_alt_map; + memcpy (plain_map, amiplain_map, sizeof(plain_map)); + + /* + * Initialize serial data direction. + */ + ciaa.cra &= ~0x41; /* serial data in, turn off TA */ + + /* + * arrange for processing of keyboard interrupt + */ + add_isr (IRQ_AMIGA_CIAA_SP, keyboard_interrupt, 0, NULL, "keyboard"); + + return 0; +} + +int amiga_kbdrate( struct kbd_repeat *k ) + +{ + if (k->delay > 0) { + /* convert from msec to jiffies */ + key_repeat_delay = (k->delay * HZ + 500) / 1000; + if (key_repeat_delay < 1) + key_repeat_delay = 1; + } + if (k->rate > 0) { + key_repeat_rate = (k->rate * HZ + 500) / 1000; + if (key_repeat_rate < 1) + key_repeat_rate = 1; + } + + k->delay = key_repeat_delay * 1000 / HZ; + k->rate = key_repeat_rate * 1000 / HZ; + + return( 0 ); +} diff -u --recursive --new-file v1.3.93/linux/arch/m68k/amiga/amipart.c linux/arch/m68k/amiga/amipart.c --- v1.3.93/linux/arch/m68k/amiga/amipart.c Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/amiga/amipart.c Wed Mar 20 20:03:41 1996 @@ -0,0 +1,119 @@ +/* + * linux/amiga/amipart.c + * + * Amiga partition checking driver for 680x0 Linux + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file README.legal in the main directory of this archive + * for more details. + */ + +#include +#include +#include + +#include +#include + +extern int current_minor; + +static ulong checksum (ulong *ptr, int len) +{ + ulong sum; + int cnt; + + for (sum = 0, cnt = 0; cnt < len; cnt++) + sum += ptr[cnt]; + + return sum; +} + +/* XXX */ +/* int current_minor = 0; */ + +void amiga_check_partition(struct gendisk *hd, kdev_t dev) +{ + int i, minor = current_minor, m_lim = current_minor + hd->max_p; + struct buffer_head *bh; + struct RigidDiskBlock *rdb; + struct PartitionBlock *pb; + ulong bnum, partsect; + + for (bnum = 0; bnum < RDB_LOCATION_LIMIT/2; bnum++) { + if (!(bh = bread(dev,bnum,1024))) { + printk (" unable to read block %ld\n", bnum); + return; + } +#ifdef DEBUG + printk ("block read, press mousebutton to continue\n"); + waitbut(); +#endif + rdb = (struct RigidDiskBlock *)bh->b_data; + if (rdb->rdb_ID == IDNAME_RIGIDDISK) + break; + rdb = (struct RigidDiskBlock *)&bh->b_data[512]; + if (rdb->rdb_ID == IDNAME_RIGIDDISK) + break; + brelse (bh); + } + if (bnum == RDB_LOCATION_LIMIT/2) { + /* no RDB on the disk! */ + printk (" unable to find RigidDiskBlock\n"); + return; + } + + /* checksum the RigidDiskBlock */ + if (checksum ((ulong *)rdb, rdb->rdb_SummedLongs) != 0) { + printk (" RDB checksum bad\n"); + return; + } + + printk(" %s%c:", hd->major_name, 'a'+(minor >> hd->minor_shift)); + + partsect = rdb->rdb_PartitionList; + brelse (bh); + + for (i = 1; minor < m_lim && partsect != 0xffffffff; minor++, i++) + { + ulong *env; + + if (!(bh = bread(dev,partsect/2,1024))) { + printk (" block %ld read failed\n", partsect); + return; + } +#ifdef DEBUG + printk ("block read, press mousebutton to continue\n"); + waitbut(); +#endif + pb = (struct PartitionBlock *)bh->b_data; + if (partsect & 1) + pb = (struct PartitionBlock *)&bh->b_data[512]; + if (pb->pb_ID != IDNAME_PARTITION) { + printk (" block %ld Not a partition block (%#lx)\n", + partsect, pb->pb_ID); + brelse (bh); + return; + } + if (checksum ((ulong *)pb, pb->pb_SummedLongs) != 0) { + printk (" block %ld checksum bad\n", partsect); + brelse (bh); + return; + } + + env = pb->pb_Environment; + + hd->part[minor].start_sect = env[DE_LOWCYL] + * env[DE_NUMHEADS] * env[DE_BLKSPERTRACK]; + hd->part[minor].nr_sects = (env[DE_UPPERCYL] + - env[DE_LOWCYL] + 1) + * env[DE_NUMHEADS] * env[DE_BLKSPERTRACK]; + + printk(" %s%c%d", hd->major_name, + 'a'+(minor >> hd->minor_shift), i); + + partsect = pb->pb_Next; + brelse (bh); + } + + printk ("\n"); +} diff -u --recursive --new-file v1.3.93/linux/arch/m68k/amiga/amisound.c linux/arch/m68k/amiga/amisound.c --- v1.3.93/linux/arch/m68k/amiga/amisound.c Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/amiga/amisound.c Thu Apr 18 02:26:30 1996 @@ -0,0 +1,110 @@ +/* + * linux/amiga/amisound.c + * + * amiga sound driver for 680x0 Linux + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file README.legal in the main directory of this archive + * for more details. + */ + +#include +#include + +#include +#include +#include + +static u_short *snd_data = NULL; +static const signed char sine_data[] = { + 0, 39, 75, 103, 121, 127, 121, 103, 75, 39, + 0, -39, -75, -103, -121, -127, -121, -103, -75, -39 +}; +#define DATA_SIZE (sizeof(sine_data)/sizeof(sine_data[0])) + +/* Imported from arch/m68k/amiga/amifb.c */ +extern volatile u_short amiga_audio_min_period; + +#define MAX_PERIOD (65535) + + + /* + * Current period (set by dmasound.c) + */ + +u_short amiga_audio_period = MAX_PERIOD; + +static u_long clock_constant; + +static void init_sound(void) +{ + snd_data = amiga_chip_alloc(sizeof(sine_data)); + if (!snd_data) { + printk (KERN_CRIT "amiga init_sound: failed to allocate chipmem\n"); + return; + } + memcpy (snd_data, sine_data, sizeof(sine_data)); + + /* setup divisor */ + clock_constant = (amiga_colorclock+DATA_SIZE/2)/DATA_SIZE; +} + +static void nosound( unsigned long ignored ); +static struct timer_list sound_timer = { NULL, NULL, 0, 0, nosound }; + +void amiga_mksound( unsigned int hz, unsigned int ticks ) +{ + static int inited = 0; + unsigned long flags; + + if (!inited) { + init_sound(); + inited = 1; + } + + if (!snd_data) + return; + + save_flags(flags); + cli(); + del_timer( &sound_timer ); + + if (hz > 20 && hz < 32767) { + u_long period = (clock_constant / hz); + + if (period < amiga_audio_min_period) + period = amiga_audio_min_period; + if (period > MAX_PERIOD) + period = MAX_PERIOD; + + /* setup pointer to data, period, length and volume */ + custom.aud[0].audlc = snd_data; + custom.aud[0].audlen = sizeof(sine_data)/2; + custom.aud[0].audper = (u_short)period; + custom.aud[0].audvol = 64; /* maxvol */ + + if (ticks) { + sound_timer.expires = jiffies + ticks; + add_timer( &sound_timer ); + } + + /* turn on DMA for audio channel 0 */ + custom.dmacon = DMAF_SETCLR | DMAF_AUD0; + + restore_flags(flags); + return; + } else { + nosound( 0 ); + restore_flags(flags); + return; + } +} + + +static void nosound( unsigned long ignored ) +{ + /* turn off DMA for audio channel 0 */ + custom.dmacon = DMAF_AUD0; + /* restore period to previous value after beeping */ + custom.aud[0].audper = amiga_audio_period; +} diff -u --recursive --new-file v1.3.93/linux/arch/m68k/amiga/chipram.c linux/arch/m68k/amiga/chipram.c --- v1.3.93/linux/arch/m68k/amiga/chipram.c Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/amiga/chipram.c Thu Mar 7 18:19:55 1996 @@ -0,0 +1,158 @@ +/* +** linux/amiga/chipram.c +** +** Modified 03-May-94 by Geert Uytterhoeven +** (Geert.Uytterhoeven@cs.kuleuven.ac.be) +** - 64-bit aligned allocations for full AGA compatibility +*/ + +#include +#include +#include +#include + +struct chip_desc { + unsigned first : 1; + unsigned last : 1; + unsigned alloced : 1; + unsigned length : 24; + long pad; /* We suppose this makes this struct 64 bits long!! */ +}; + +#define DP(ptr) ((struct chip_desc *)(ptr)) + +static unsigned long chipsize; + +void amiga_chip_init (void) +{ + struct chip_desc *dp; + + if (!AMIGAHW_PRESENT(CHIP_RAM)) + return; + + chipsize = boot_info.bi_amiga.chip_size; + + /* initialize start boundary */ + + custom.color[0] = 0xfff; + + dp = DP(chipaddr); + dp->first = 1; + + custom.color[0] = 0x0f00; + + dp->alloced = 0; + dp->length = chipsize - 2*sizeof(*dp); + + /* initialize end boundary */ + dp = DP(chipaddr + chipsize) - 1; + dp->last = 1; + + custom.color[0] = 0x00f0; + + dp->alloced = 0; + dp->length = chipsize - 2*sizeof(*dp); + + custom.color[0] = 0x000f; + +#ifdef DEBUG + printk ("chipram end boundary is %p, length is %d\n", dp, + dp->length); +#endif +} + +void *amiga_chip_alloc (long size) +{ + /* last chunk */ + struct chip_desc *dp; + void *ptr; + + /* round off */ + size = (size + 7) & ~7; + +#ifdef DEBUG + printk ("chip_alloc: allocate %ld bytes\n", size); +#endif + + /* + * get pointer to descriptor for last chunk by + * going backwards from end chunk + */ + dp = DP(chipaddr + chipsize) - 1; + dp = DP((unsigned long)dp - dp->length) - 1; + + while ((dp->alloced || dp->length < size) + && !dp->first) + dp = DP ((unsigned long)dp - dp[-1].length) - 2; + + if (dp->alloced || dp->length < size) { + printk ("no chipmem available for %ld allocation\n", size); + return NULL; + } + + if (dp->length < (size + 2*sizeof(*dp))) { + /* length too small to split; allocate the whole thing */ + dp->alloced = 1; + ptr = (void *)(dp+1); + dp = DP((unsigned long)ptr + dp->length); + dp->alloced = 1; +#ifdef DEBUG + printk ("chip_alloc: no split\n"); +#endif + } else { + /* split the extent; use the end part */ + long newsize = dp->length - (2*sizeof(*dp) + size); + +#ifdef DEBUG + printk ("chip_alloc: splitting %d to %ld\n", dp->length, + newsize); +#endif + dp->length = newsize; + dp = DP((unsigned long)(dp+1) + newsize); + dp->first = dp->last = 0; + dp->alloced = 0; + dp->length = newsize; + dp++; + dp->first = dp->last = 0; + dp->alloced = 1; + dp->length = size; + ptr = (void *)(dp+1); + dp = DP((unsigned long)ptr + size); + dp->alloced = 1; + dp->length = size; + } + +#ifdef DEBUG + printk ("chip_alloc: returning %p\n", ptr); +#endif + + if ((unsigned long)ptr & 7) + panic("chip_alloc: alignment violation\n"); + + return ptr; +} + +void amiga_chip_free (void *ptr) +{ + struct chip_desc *sdp = DP(ptr) - 1, *dp2; + struct chip_desc *edp = DP((unsigned long)ptr + sdp->length); + + /* deallocate the chunk */ + sdp->alloced = edp->alloced = 0; + + /* check if we should merge with the previous chunk */ + if (!sdp->first && !sdp[-1].alloced) { + dp2 = DP((unsigned long)sdp - sdp[-1].length) - 2; + dp2->length += sdp->length + 2*sizeof(*sdp); + edp->length = dp2->length; + sdp = dp2; + } + + /* check if we should merge with the following chunk */ + if (!edp->last && !edp[1].alloced) { + dp2 = DP((unsigned long)edp + edp[1].length) + 2; + dp2->length += edp->length + 2*sizeof(*sdp); + sdp->length = dp2->length; + edp = dp2; + } +} diff -u --recursive --new-file v1.3.93/linux/arch/m68k/amiga/config.c linux/arch/m68k/amiga/config.c --- v1.3.93/linux/arch/m68k/amiga/config.c Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/amiga/config.c Fri Apr 19 02:41:15 1996 @@ -0,0 +1,881 @@ +/* + * linux/amiga/config.c + * + * Copyright (C) 1993 Hamish Macdonald + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file README.legal in the main directory of this archive + * for more details. + */ + +/* + * Miscellaneous Amiga stuff + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +u_long amiga_masterclock; +u_long amiga_colorclock; + +extern char m68k_debug_device[]; + +extern void amiga_sched_init(isrfunc handler); +extern int amiga_keyb_init(void); +extern int amiga_kbdrate (struct kbd_repeat *); +extern void amiga_init_INTS (void); +extern int amiga_add_isr (unsigned long, isrfunc, int, void *, char *); +extern int amiga_remove_isr (unsigned long, isrfunc); +extern int amiga_get_irq_list (char *, int); +extern void amiga_enable_irq(unsigned int); +extern void amiga_disable_irq(unsigned int); +extern unsigned long amiga_gettimeoffset (void); +extern void a3000_gettod (int *, int *, int *, int *, int *, int *); +extern void a2000_gettod (int *, int *, int *, int *, int *, int *); +extern int amiga_hwclk (int, struct hwclk_time *); +extern int amiga_set_clock_mmss (unsigned long); +extern void amiga_check_partition (struct gendisk *hd, unsigned int dev); +extern void amiga_mksound( unsigned int count, unsigned int ticks ); +#ifdef CONFIG_BLK_DEV_FD +extern int amiga_floppy_init (void); +extern void amiga_floppy_setup(char *, int *); +#endif +extern void amiga_reset (void); +extern void amiga_waitbut(void); +extern struct consw fb_con; +extern struct fb_info *amiga_fb_init(long *); +extern void zorro_init(void); +static void ami_savekmsg_init(void); +static void ami_mem_print(const char *b); +extern void amiga_debug_init(void); +extern void amiga_video_setup(char *, int *); + +extern void (*kd_mksound)(unsigned int, unsigned int); + +void config_amiga(void) +{ + char *type = NULL; + + switch(boot_info.bi_amiga.model) { + case AMI_500: + type = "A500"; + break; + case AMI_500PLUS: + type = "A500+"; + break; + case AMI_600: + type = "A600"; + break; + case AMI_1000: + type = "A1000"; + break; + case AMI_1200: + type = "A1200"; + break; + case AMI_2000: + type = "A2000"; + break; + case AMI_2500: + type = "A2500"; + break; + case AMI_3000: + type = "A3000"; + break; + case AMI_3000T: + type = "A3000T"; + break; + case AMI_3000PLUS: + type = "A3000+"; + break; + case AMI_4000: + type = "A4000"; + break; + case AMI_4000T: + type = "A4000T"; + break; + case AMI_CDTV: + type = "CDTV"; + break; + case AMI_CD32: + type = "CD32"; + break; + case AMI_DRACO: + type = "Draco"; + break; + } + printk("Amiga hardware found: "); + if (type) + printk("[%s] ", type); + switch(boot_info.bi_amiga.model) { + case AMI_UNKNOWN: + goto Generic; + + case AMI_500: + case AMI_500PLUS: + case AMI_1000: + AMIGAHW_SET(A2000_CLK); /* Is this correct? */ + printk("A2000_CLK "); + goto Generic; + + case AMI_600: + case AMI_1200: + AMIGAHW_SET(A1200_IDE); + printk("A1200_IDE "); + AMIGAHW_SET(A2000_CLK); /* Is this correct? */ + printk("A2000_CLK "); + goto Generic; + + case AMI_2000: + case AMI_2500: + AMIGAHW_SET(A2000_CLK); + printk("A2000_CLK "); + goto Generic; + + case AMI_3000: + case AMI_3000T: + AMIGAHW_SET(AMBER_FF); + printk("AMBER_FF "); + AMIGAHW_SET(MAGIC_REKICK); + printk("MAGIC_REKICK "); + /* fall through */ + case AMI_3000PLUS: + AMIGAHW_SET(A3000_SCSI); + printk("A3000_SCSI "); + AMIGAHW_SET(A3000_CLK); + printk("A3000_CLK "); + goto Generic; + + case AMI_4000T: + AMIGAHW_SET(A4000_SCSI); + printk("A4000_SCSI "); + /* fall through */ + case AMI_4000: + AMIGAHW_SET(A4000_IDE); + printk("A4000_IDE "); + AMIGAHW_SET(A3000_CLK); + printk("A3000_CLK "); + goto Generic; + + case AMI_CDTV: + case AMI_CD32: + AMIGAHW_SET(CD_ROM); + printk("CD_ROM "); + AMIGAHW_SET(A2000_CLK); /* Is this correct? */ + printk("A2000_CLK "); + goto Generic; + + Generic: + AMIGAHW_SET(AMI_VIDEO); + AMIGAHW_SET(AMI_BLITTER); + AMIGAHW_SET(AMI_AUDIO); + AMIGAHW_SET(AMI_FLOPPY); + AMIGAHW_SET(AMI_KEYBOARD); + AMIGAHW_SET(AMI_MOUSE); + AMIGAHW_SET(AMI_SERIAL); + AMIGAHW_SET(AMI_PARALLEL); + AMIGAHW_SET(CHIP_RAM); + AMIGAHW_SET(PAULA); + printk("VIDEO BLITTER AUDIO FLOPPY KEYBOARD MOUSE SERIAL PARALLEL " + "CHIP_RAM PAULA "); + + switch(boot_info.bi_amiga.chipset) { + case CS_OCS: + case CS_ECS: + case CS_AGA: + switch (custom.deniseid & 0xf) { + case 0x0c: + AMIGAHW_SET(DENISE_HR); + printk("DENISE_HR"); + break; + case 0x08: + AMIGAHW_SET(LISA); + printk("LISA "); + break; + } + break; + default: + AMIGAHW_SET(DENISE); + printk("DENISE "); + break; + } + switch ((custom.vposr>>8) & 0x7f) { + case 0x00: + AMIGAHW_SET(AGNUS_PAL); + printk("AGNUS_PAL "); + break; + case 0x10: + AMIGAHW_SET(AGNUS_NTSC); + printk("AGNUS_NTSC "); + break; + case 0x20: + case 0x21: + AMIGAHW_SET(AGNUS_HR_PAL); + printk("AGNUS_HR_PAL "); + break; + case 0x30: + case 0x31: + AMIGAHW_SET(AGNUS_HR_NTSC); + printk("AGNUS_HR_NTSC "); + break; + case 0x22: + case 0x23: + AMIGAHW_SET(ALICE_PAL); + printk("ALICE_PAL "); + break; + case 0x32: + case 0x33: + AMIGAHW_SET(ALICE_NTSC); + printk("ALICE_NTSC "); + break; + } + AMIGAHW_SET(ZORRO); + printk("ZORRO "); + break; + + case AMI_DRACO: + panic("No support for Draco yet"); + + default: + panic("Unknown Amiga Model"); + } + printk("\n"); + + mach_sched_init = amiga_sched_init; + mach_keyb_init = amiga_keyb_init; + mach_kbdrate = amiga_kbdrate; + mach_init_INTS = amiga_init_INTS; + mach_add_isr = amiga_add_isr; +#if 0 /* ++1.3++ */ + mach_remove_isr = amiga_remove_isr; + mach_enable_irq = amiga_enable_irq; + mach_disable_irq = amiga_disable_irq; +#endif + mach_get_irq_list = amiga_get_irq_list; + mach_gettimeoffset = amiga_gettimeoffset; + if (AMIGAHW_PRESENT(A3000_CLK)){ + mach_gettod = a3000_gettod; + mach_max_dma_address = 0xffffffff; /* + * default MAX_DMA 0xffffffff + * on Z3 machines - we should + * consider adding something + * like a dma_mask in kmalloc + * later on, so people using Z2 + * boards in Z3 machines won't + * get into trouble - Jes + */ + } + else{ /* if (AMIGAHW_PRESENT(A2000_CLK)) */ + mach_gettod = a2000_gettod; + mach_max_dma_address = 0x00ffffff; /* + * default MAX_DMA 0x00ffffff + * on Z2 machines. + */ + } + mach_hwclk = amiga_hwclk; + mach_set_clock_mmss = amiga_set_clock_mmss; + mach_check_partition = amiga_check_partition; + mach_mksound = amiga_mksound; +#ifdef CONFIG_BLK_DEV_FD + mach_floppy_init = amiga_floppy_init; + mach_floppy_setup = amiga_floppy_setup; +#endif + mach_reset = amiga_reset; + waitbut = amiga_waitbut; + conswitchp = &fb_con; + mach_fb_init = amiga_fb_init; + mach_debug_init = amiga_debug_init; + mach_video_setup = amiga_video_setup; + kd_mksound = amiga_mksound; + + /* Fill in the clock values (based on the 700 kHz E-Clock) */ + amiga_masterclock = 40*amiga_eclock; /* 28 MHz */ + amiga_colorclock = 5*amiga_eclock; /* 3.5 MHz */ + + /* clear all DMA bits */ + custom.dmacon = DMAF_ALL; + /* ensure that the DMA master bit is set */ + custom.dmacon = DMAF_SETCLR | DMAF_MASTER; + + /* initialize chipram allocator */ + amiga_chip_init (); + + /* initialize only once here, not every time the debug level is raised */ + if (!strcmp( m68k_debug_device, "mem" )) + ami_savekmsg_init(); + + /* + * if it is an A3000, set the magic bit that forces + * a hard rekick + */ + if (AMIGAHW_PRESENT(MAGIC_REKICK)) + *(u_char *)ZTWO_VADDR(0xde0002) |= 0x80; + + zorro_init(); +#ifdef CONFIG_ZORRO + /* + * Identify all known AutoConfig Expansion Devices + */ + zorro_identify(); +#endif /* CONFIG_ZORRO */ +} + +extern long time_finetune; /* from kernel/sched.c */ + +static unsigned short jiffy_ticks; + +#if 1 /* ++1.3++ */ +static void timer_wrapper( int irq, struct pt_regs *fp, void *otimerf ) + { + unsigned short flags, old_flags; + + ciab.icr = 0x01; + + save_flags(flags); + old_flags = (flags & ~0x0700) | (fp->sr & 0x0700); + + restore_flags(old_flags); + + (*(isrfunc)otimerf)( irq, fp, NULL ); + + restore_flags(flags); + ciab.icr = 0x81; +} +#endif + +void amiga_sched_init (isrfunc timer_routine) +{ + +#if 0 /* XXX */ /* I think finetune was removed by the 1.3.29 patch */ + double finetune; +#endif + + jiffy_ticks = (amiga_eclock+50)/100; +#if 0 /* XXX */ + finetune = (jiffy_ticks-amiga_eclock/HZ)/amiga_eclock*1000000*(1<<24); + time_finetune = finetune+0.5; +#endif + + ciab.cra &= 0xC0; /* turn off timer A, continous mode, from Eclk */ + ciab.talo = jiffy_ticks % 256; + ciab.tahi = jiffy_ticks / 256; + /* CIA interrupts when counter underflows, so adjust ticks by 1 */ + jiffy_ticks -= 1; + + /* install interrupt service routine for CIAB Timer A */ + /* + * Please don't change this to use ciaa, as it interfers with the + * SCSI code. We'll have to take a look at this later + */ +#if 0 + add_isr (IRQ_AMIGA_CIAB_TA, timer_routine, 0, NULL, "timer"); +#else + add_isr (IRQ_AMIGA_CIAB_TA, timer_wrapper, 0, timer_routine, "timer"); +#endif + /* start timer */ + ciab.cra |= 0x01; +} + +#define TICK_SIZE 10000 + +/* This is always executed with interrupts disabled. */ +unsigned long amiga_gettimeoffset (void) +{ + unsigned short hi, lo, hi2; + unsigned long ticks, offset = 0; + + /* read CIA A timer A current value */ + hi = ciab.tahi; + lo = ciab.talo; + hi2 = ciab.tahi; + + if (hi != hi2) { + lo = ciab.talo; + hi = hi2; + } + + ticks = hi << 8 | lo; + +#if 0 /* XXX */ +/* reading the ICR clears all interrupts. bad idea! */ + if (ticks > jiffy_ticks - jiffy_ticks / 100) + /* check for pending interrupt */ + if (ciab.icr & CIA_ICR_TA) + offset = 10000; +#endif + + ticks = (jiffy_ticks-1) - ticks; + ticks = (10000 * ticks) / jiffy_ticks; + + return ticks + offset; +} + +void a3000_gettod (int *yearp, int *monp, int *dayp, + int *hourp, int *minp, int *secp) +{ + volatile struct tod3000 *tod = TOD_3000; + + tod->cntrl1 = TOD3000_CNTRL1_HOLD; + + *secp = tod->second1 * 10 + tod->second2; + *minp = tod->minute1 * 10 + tod->minute2; + *hourp = tod->hour1 * 10 + tod->hour2; + *dayp = tod->day1 * 10 + tod->day2; + *monp = tod->month1 * 10 + tod->month2; + *yearp = tod->year1 * 10 + tod->year2; + + tod->cntrl1 = TOD3000_CNTRL1_FREE; +} + +void a2000_gettod (int *yearp, int *monp, int *dayp, + int *hourp, int *minp, int *secp) +{ + volatile struct tod2000 *tod = TOD_2000; + + tod->cntrl1 = TOD2000_CNTRL1_HOLD; + + while (tod->cntrl1 & TOD2000_CNTRL1_BUSY) + ; + + *secp = tod->second1 * 10 + tod->second2; + *minp = tod->minute1 * 10 + tod->minute2; + *hourp = (tod->hour1 & 3) * 10 + tod->hour2; + *dayp = tod->day1 * 10 + tod->day2; + *monp = tod->month1 * 10 + tod->month2; + *yearp = tod->year1 * 10 + tod->year2; + + if (!(tod->cntrl3 & TOD2000_CNTRL3_24HMODE)) + if ((!tod->hour1 & TOD2000_HOUR1_PM) && *hourp == 12) + *hourp = 0; + else if ((tod->hour1 & TOD2000_HOUR1_PM) && *hourp != 12) + *hourp += 12; + + tod->cntrl1 &= ~TOD2000_CNTRL1_HOLD; +} + +int amiga_hwclk(int op, struct hwclk_time *t) +{ + if (AMIGAHW_PRESENT(A3000_CLK)) { + volatile struct tod3000 *tod = TOD_3000; + + tod->cntrl1 = TOD3000_CNTRL1_HOLD; + + if (!op) { /* read */ + t->sec = tod->second1 * 10 + tod->second2; + t->min = tod->minute1 * 10 + tod->minute2; + t->hour = tod->hour1 * 10 + tod->hour2; + t->day = tod->day1 * 10 + tod->day2; + t->wday = tod->weekday; + t->mon = tod->month1 * 10 + tod->month2 - 1; + t->year = tod->year1 * 10 + tod->year2; + } else { + tod->second1 = t->sec / 10; + tod->second2 = t->sec % 10; + tod->minute1 = t->min / 10; + tod->minute2 = t->min % 10; + tod->hour1 = t->hour / 10; + tod->hour2 = t->hour % 10; + tod->day1 = t->day / 10; + tod->day2 = t->day % 10; + if (t->wday != -1) + tod->weekday = t->wday; + tod->month1 = (t->mon + 1) / 10; + tod->month2 = (t->mon + 1) % 10; + tod->year1 = t->year / 10; + tod->year2 = t->year % 10; + } + + tod->cntrl1 = TOD3000_CNTRL1_FREE; + } else /* if (AMIGAHW_PRESENT(A2000_CLK)) */ { + volatile struct tod2000 *tod = TOD_2000; + + tod->cntrl1 = TOD2000_CNTRL1_HOLD; + + while (tod->cntrl1 & TOD2000_CNTRL1_BUSY) + ; + + if (!op) { /* read */ + t->sec = tod->second1 * 10 + tod->second2; + t->min = tod->minute1 * 10 + tod->minute2; + t->hour = (tod->hour1 & 3) * 10 + tod->hour2; + t->day = tod->day1 * 10 + tod->day2; + t->wday = tod->weekday; + t->mon = tod->month1 * 10 + tod->month2 - 1; + t->year = tod->year1 * 10 + tod->year2; + + if (!(tod->cntrl3 & TOD2000_CNTRL3_24HMODE)) + if ((!tod->hour1 & TOD2000_HOUR1_PM) && t->hour == 12) + t->hour = 0; + else if ((tod->hour1 & TOD2000_HOUR1_PM) && t->hour != 12) + t->hour += 12; + } else { + tod->second1 = t->sec / 10; + tod->second2 = t->sec % 10; + tod->minute1 = t->min / 10; + tod->minute2 = t->min % 10; + if (tod->cntrl3 & TOD2000_CNTRL3_24HMODE) + tod->hour1 = t->hour / 10; + else if (t->hour >= 12) + tod->hour1 = TOD2000_HOUR1_PM + + (t->hour - 12) / 10; + else + tod->hour1 = t->hour / 10; + tod->hour2 = t->hour % 10; + tod->day1 = t->day / 10; + tod->day2 = t->day % 10; + if (t->wday != -1) + tod->weekday = t->wday; + tod->month1 = (t->mon + 1) / 10; + tod->month2 = (t->mon + 1) % 10; + tod->year1 = t->year / 10; + tod->year2 = t->year % 10; + } + + tod->cntrl1 &= ~TOD2000_CNTRL1_HOLD; + } + + return 0; +} + +int amiga_set_clock_mmss (unsigned long nowtime) +{ + short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60; + + if (AMIGAHW_PRESENT(A3000_CLK)) { + volatile struct tod3000 *tod = TOD_3000; + + tod->cntrl1 = TOD3000_CNTRL1_HOLD; + + tod->second1 = real_seconds / 10; + tod->second2 = real_seconds % 10; + tod->minute1 = real_minutes / 10; + tod->minute2 = real_minutes % 10; + + tod->cntrl1 = TOD3000_CNTRL1_FREE; + } else /* if (AMIGAHW_PRESENT(A2000_CLK)) */ { + volatile struct tod2000 *tod = TOD_2000; + + tod->cntrl1 = TOD2000_CNTRL1_HOLD; + + while (tod->cntrl1 & TOD2000_CNTRL1_BUSY) + ; + + tod->second1 = real_seconds / 10; + tod->second2 = real_seconds % 10; + tod->minute1 = real_minutes / 10; + tod->minute2 = real_minutes % 10; + + tod->cntrl1 &= ~TOD2000_CNTRL1_HOLD; + } + + return 0; +} + +void amiga_waitbut (void) +{ + int i; + + while (1) { + while (ciaa.pra & 0x40); + + /* debounce */ + for (i = 0; i < 1000; i++); + + if (!(ciaa.pra & 0x40)) + break; + } + + /* wait for button up */ + while (1) { + while (!(ciaa.pra & 0x40)); + + /* debounce */ + for (i = 0; i < 1000; i++); + + if (ciaa.pra & 0x40) + break; + } +} + +void ami_serial_print (const char *str) +{ + while (*str) { + if (*str == '\n') { + custom.serdat = (unsigned char)'\r' | 0x100; + while (!(custom.serdatr & 0x2000)) + ; + } + custom.serdat = (unsigned char)*str++ | 0x100; + while (!(custom.serdatr & 0x2000)) + ; + } +} + +void amiga_debug_init (void) +{ + extern void (*debug_print_proc)(const char *); + + if (!strcmp( m68k_debug_device, "ser" )) { + /* no initialization required (?) */ + debug_print_proc = ami_serial_print; + } else if (!strcmp( m68k_debug_device, "mem" )) { + /* already initialized by config_amiga() (needed only once) */ + debug_print_proc = ami_mem_print; + } +} + +void dbprintf(const char *fmt , ...) +{ + static char buf[1024]; + va_list args; + extern void console_print (const char *str); + extern int vsprintf(char * buf, const char * fmt, va_list args); + + va_start(args, fmt); + vsprintf(buf, fmt, args); + va_end(args); + + console_print (buf); +} + +NORET_TYPE void amiga_reset( void ) + ATTRIB_NORET; + +void amiga_reset (void) +{ + unsigned long jmp_addr040 = VTOP(&&jmp_addr_label040); + unsigned long jmp_addr = VTOP(&&jmp_addr_label); + + cli(); + if (m68k_is040or060) + /* Setup transparent translation registers for mapping + * of 16 MB kernel segment before disabling translation + */ + __asm__ __volatile__ + ("movel %0,%/d0\n\t" + "andl #0xff000000,%/d0\n\t" + "orw #0xe020,%/d0\n\t" /* map 16 MB, enable, cacheable */ + ".long 0x4e7b0004\n\t" /* movec d0,itt0 */ + ".long 0x4e7b0006\n\t" /* movec d0,dtt0 */ + "jmp %0@\n\t" + : /* no outputs */ + : "a" (jmp_addr040)); + else + /* for 680[23]0, just disable translation and jump to the physical + * address of the label + */ + __asm__ __volatile__ + ("pmove %/tc,%@\n\t" + "bclr #7,%@\n\t" + "pmove %@,%/tc\n\t" + "jmp %0@\n\t" + : /* no outputs */ + : "a" (jmp_addr)); + jmp_addr_label040: + /* disable translation on '040 now */ + __asm__ __volatile__ + ("moveq #0,%/d0\n\t" + ".long 0x4e7b0003\n\t" /* movec d0,tc; disable MMU */ + : /* no outputs */ + : /* no inputs */ + : "d0"); + + jmp_addr_label: + /* pickup reset address from AmigaOS ROM, reset devices and jump + * to reset address + */ + __asm__ __volatile__ + ("movew #0x2700,%/sr\n\t" + "leal 0x01000000,%/a0\n\t" + "subl %/a0@(-0x14),%/a0\n\t" + "movel %/a0@(4),%/a0\n\t" + "subql #2,%/a0\n\t" + "bra 1f\n\t" + /* align on a longword boundary */ + __ALIGN_STR "\n" + "1:\n\t" + "reset\n\t" + "jmp %/a0@" : /* Just that gcc scans it for % escapes */ ); + + for (;;); + +} + +extern void *amiga_chip_alloc(long size); + + +#define SAVEKMSG_MAXMEM 128*1024 + + +#define SAVEKMSG_MAGIC1 0x53415645 /* 'SAVE' */ +#define SAVEKMSG_MAGIC2 0x4B4D5347 /* 'KMSG' */ + +struct savekmsg { + u_long magic1; /* SAVEKMSG_MAGIC1 */ + u_long magic2; /* SAVEKMSG_MAGIC2 */ + u_long magicptr; /* address of magic1 */ + u_long size; + char data[0]; +}; + +static struct savekmsg *savekmsg = NULL; + + +static void ami_savekmsg_init(void) +{ + savekmsg = (struct savekmsg *)amiga_chip_alloc(SAVEKMSG_MAXMEM); + savekmsg->magic1 = SAVEKMSG_MAGIC1; + savekmsg->magic2 = SAVEKMSG_MAGIC2; + savekmsg->magicptr = VTOP(savekmsg); + savekmsg->size = 0; +} + + +static void ami_mem_print(const char *b) +{ + int len; + + for (len = 0; b[len]; len++); + if (savekmsg->size+len <= SAVEKMSG_MAXMEM) { + memcpy(savekmsg->data+savekmsg->size, b, len); + savekmsg->size += len; + } +} + + +void amiga_get_model(char *model) +{ + strcpy(model, "Amiga "); + switch (boot_info.bi_amiga.model) { + case AMI_500: + strcat(model, "500"); + break; + case AMI_500PLUS: + strcat(model, "500+"); + break; + case AMI_600: + strcat(model, "600"); + break; + case AMI_1000: + strcat(model, "1000"); + break; + case AMI_1200: + strcat(model, "1200"); + break; + case AMI_2000: + strcat(model, "2000"); + break; + case AMI_2500: + strcat(model, "2500"); + break; + case AMI_3000: + strcat(model, "3000"); + break; + case AMI_3000T: + strcat(model, "3000T"); + break; + case AMI_3000PLUS: + strcat(model, "3000+"); + break; + case AMI_4000: + strcat(model, "4000"); + break; + case AMI_4000T: + strcat(model, "4000T"); + break; + case AMI_CDTV: + strcat(model, "CDTV"); + break; + case AMI_CD32: + strcat(model, "CD32"); + break; + case AMI_DRACO: + strcpy(model, "DRACO"); + break; + } +} + + +int amiga_get_hardware_list(char *buffer) +{ + int len = 0; + + if (AMIGAHW_PRESENT(CHIP_RAM)) + len += sprintf(buffer+len, "Chip RAM:\t%ldK\n", + boot_info.bi_amiga.chip_size>>10); + len += sprintf(buffer+len, "PS Freq:\t%dHz\nEClock Freq:\t%ldHz\n", + boot_info.bi_amiga.psfreq, amiga_eclock); + if (AMIGAHW_PRESENT(AMI_VIDEO)) { + char *type; + switch(boot_info.bi_amiga.chipset) { + case CS_OCS: + type = "OCS"; + break; + case CS_ECS: + type = "ECS"; + break; + case CS_AGA: + type = "AGA"; + break; + default: + type = "Old or Unknown"; + break; + } + len += sprintf(buffer+len, "Graphics:\t%s\n", type); + } + +#define AMIGAHW_ANNOUNCE(name, str) \ + if (AMIGAHW_PRESENT(name)) \ + len += sprintf (buffer+len, "\t%s\n", str) + + len += sprintf (buffer + len, "Detected hardware:\n"); + + AMIGAHW_ANNOUNCE(AMI_VIDEO, "Amiga Video"); + AMIGAHW_ANNOUNCE(AMI_BLITTER, "Blitter"); + AMIGAHW_ANNOUNCE(AMBER_FF, "Amber Flicker Fixer"); + AMIGAHW_ANNOUNCE(AMI_AUDIO, "Amiga Audio"); + AMIGAHW_ANNOUNCE(AMI_FLOPPY, "Floppy Controller"); + AMIGAHW_ANNOUNCE(A3000_SCSI, "SCSI Controller WD33C93 (A3000 style)"); + AMIGAHW_ANNOUNCE(A4000_SCSI, "SCSI Controller NCR53C710 (A4000T style)"); + AMIGAHW_ANNOUNCE(A1200_IDE, "IDE Interface (A1200 style)"); + AMIGAHW_ANNOUNCE(A4000_IDE, "IDE Interface (A4000 style)"); + AMIGAHW_ANNOUNCE(CD_ROM, "Internal CD ROM drive"); + AMIGAHW_ANNOUNCE(AMI_KEYBOARD, "Keyboard"); + AMIGAHW_ANNOUNCE(AMI_MOUSE, "Mouse Port"); + AMIGAHW_ANNOUNCE(AMI_SERIAL, "Serial Port"); + AMIGAHW_ANNOUNCE(AMI_PARALLEL, "Parallel Port"); + AMIGAHW_ANNOUNCE(A2000_CLK, "Hardware Clock (A2000 style)"); + AMIGAHW_ANNOUNCE(A3000_CLK, "Hardware Clock (A3000 style)"); + AMIGAHW_ANNOUNCE(CHIP_RAM, "Chip RAM"); + AMIGAHW_ANNOUNCE(PAULA, "Paula 8364"); + AMIGAHW_ANNOUNCE(DENISE, "Denise 8362"); + AMIGAHW_ANNOUNCE(DENISE_HR, "Denise 8373"); + AMIGAHW_ANNOUNCE(LISA, "Lisa 8375"); + AMIGAHW_ANNOUNCE(AGNUS_PAL, "Normal/Fat PAL Agnus 8367/8371"); + AMIGAHW_ANNOUNCE(AGNUS_NTSC, "Normal/Fat NTSC Agnus 8361/8370"); + AMIGAHW_ANNOUNCE(AGNUS_HR_PAL, "Fat Hires PAL Agnus 8372"); + AMIGAHW_ANNOUNCE(AGNUS_HR_NTSC, "Fat Hires NTSC Agnus 8372"); + AMIGAHW_ANNOUNCE(ALICE_PAL, "PAL Alice 8374"); + AMIGAHW_ANNOUNCE(ALICE_NTSC, "NTSC Alice 8374"); + AMIGAHW_ANNOUNCE(MAGIC_REKICK, "Magic Hard Rekick"); + if (AMIGAHW_PRESENT(ZORRO)) + len += sprintf(buffer+len, "\tZorro AutoConfig: %d Expansion Device%s\n", + boot_info.bi_amiga.num_autocon, + boot_info.bi_amiga.num_autocon == 1 ? "" : "s"); + + return(len); +} diff -u --recursive --new-file v1.3.93/linux/arch/m68k/amiga/ksyms.c linux/arch/m68k/amiga/ksyms.c --- v1.3.93/linux/arch/m68k/amiga/ksyms.c Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/amiga/ksyms.c Thu Apr 11 02:26:52 1996 @@ -0,0 +1,20 @@ +#include + +static struct symbol_table mach_amiga_symbol_table = { +#include + + /* + * Add things here when you find the need for it. + */ + + /* examble + X(something_you_need), + */ + +#include +}; + +void mach_amiga_syms_export(void) +{ + register_symtab(&mach_amiga_symbol_table); +} diff -u --recursive --new-file v1.3.93/linux/arch/m68k/amiga/zorro.c linux/arch/m68k/amiga/zorro.c --- v1.3.93/linux/arch/m68k/amiga/zorro.c Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/amiga/zorro.c Wed Mar 20 20:04:17 1996 @@ -0,0 +1,668 @@ +/* + * linux/arch/m68k/amiga/zorro.c + * + * Copyright (C) 1995 Geert Uytterhoeven + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file README.legal in the main directory of this archive + * for more details. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include + + +#ifdef CONFIG_ZORRO + + /* + * Zorro Expansion Device Manufacturers and Products + */ + +struct Manufacturer { + char *Name; + u_short ID; + u_short NumProd; + struct Product *Products; +}; + +struct Product { + char *Name; + u_char ID; +}; + +struct GVP_Product { + char *Name; + enum GVP_ident ID; +}; + + + /* + * Macro's to make life easier + */ + +#define BEGIN_PROD(id) static struct Product Prod_##id[] = { +#define PROD(name, id) \ + { name, PROD_##id }, + +#define BEGIN_GVP_PROD static struct GVP_Product Ext_Prod_GVP[] = { +#define GVP_PROD(name, id) \ + { name, GVP_##id }, + +#define BEGIN_MANUF static struct Manufacturer Manufacturers[] = { +#define MANUF(name, id) \ + { name, MANUF_##id, sizeof(Prod_##id)/sizeof(struct Product), Prod_##id }, + +#define END }; + + + /* + * Known Zorro Expansion Devices + * + * Warning: Make sure the Manufacturer and Product names are not too + * long (max. 80 characters per board identification line) + */ + +BEGIN_PROD(MEMPHIS) + PROD("Stormbringer", STORMBRINGER) +END + +BEGIN_PROD(COMMODORE2) + PROD("A2088 Bridgeboard", A2088) + PROD("A2386-SX Bridgeboard", A2386SX) +END + +BEGIN_PROD(COMMODORE) + PROD("A2090/A2090A HD Controller", A2090A) + PROD("A590 SCSI Controller", A590) + PROD("A2091 SCSI Controller", A2091) + PROD("A2090B 2090 Autoboot Card", A2090B) + PROD("A2060 Arcnet Card", ARCNET) + PROD("A2052/58.RAM | 590/2091.RAM", CBMRAM) + PROD("A560 Memory Module", A560RAM) + PROD("A2232 Serial Prototype", A2232PROTO) + PROD("A2232 Serial Production", A2232) + PROD("A2620 68020/RAM Card", A2620) + PROD("A2630 68030/RAM Card", A2630) + PROD("A4091 SCSI Controller", A4091) + PROD("Romulator Card", ROMULATOR) + PROD("A3000 Test Fixture", A3000TESTFIX) + PROD("A2065 Ethernet Card", A2065) +END + +BEGIN_PROD(CARDCO) + PROD("Cardco A2410 Hires Graphics card", CC_A2410) +END + +BEGIN_PROD(MICROBOTICS) + PROD("VXL-30 Turbo Board", VXL_30) +END + +BEGIN_PROD(ASDG) + PROD("Lan Rover Ethernet", LAN_ROVER) + PROD("Dual Serial Card", ASDG_DUAL_SERIAL) +END + +BEGIN_PROD(UNIV_OF_LOWELL) + PROD("A2410 Hires Graphics Card", A2410) +END + +BEGIN_PROD(AMERISTAR) + PROD("A2065 Ethernet Card", AMERISTAR2065) + PROD("A560 Arcnet Card", A560) + PROD("A4066 Ethernet Card", A4066) +END + +BEGIN_PROD(SUPRA) + PROD("Wordsync SCSI Controller", WORDSYNC) + PROD("Wordsync II SCSI Controller", WORDSYNC_II) + PROD("2400 Modem", SUPRA_2400MODEM) +END + +BEGIN_PROD(CSA) + PROD("Magnum 40 SCSI Controller", MAGNUM) + PROD("12 Gauge SCSI Controller", 12GAUGE) +END + +BEGIN_PROD(POWER_COMPUTING) + PROD("Viper II Turbo Board (DKB 1240)", DKB_1240) +END + +BEGIN_PROD(GVP) + PROD("Generic GVP product", GVP) + PROD("Series II SCSI Controller", GVPIISCSI) + PROD("Series II SCSI Controller", GVPIISCSI_2) + PROD("Series II RAM", GVPIIRAM) + PROD("GFORCE 040 with SCSI Controller", GFORCE_040_SCSI) + PROD("IV-24 Graphics Board", GVPIV_24) +/* + PROD("I/O Extender", GVPIO_EXT) +*/ +END + +BEGIN_GVP_PROD + GVP_PROD("GFORCE 040", GFORCE_040) + GVP_PROD("GFORCE 040 with SCSI controller", GFORCE_040_SCSI) + GVP_PROD("A1291 SCSI controller", A1291_SCSI) + GVP_PROD("COMBO 030 R4", COMBO_R4) + GVP_PROD("COMBO 030 R4 with SCSI controller", COMBO_R4_SCSI) + GVP_PROD("Phone Pak", PHONEPAK) + GVP_PROD("IO-Extender", IOEXT) + GVP_PROD("GFORCE 030", GFORCE_030) + GVP_PROD("GFORCE 030 with SCSI controller", GFORCE_030_SCSI) + GVP_PROD("A530", A530) + GVP_PROD("A530 with SCSI", A530_SCSI) + GVP_PROD("COMBO 030 R3", COMBO_R3) + GVP_PROD("COMBO 030 R3 with SCSI controller", COMBO_R3_SCSI) + GVP_PROD("SERIES-II SCSI controller", SERIESII) +END + +BEGIN_PROD(PPI) + PROD("Mercury Turbo Board", MERCURY) + PROD("PP&S A3000 68040 Turbo Board", PPS_A3000_040) + PROD("PP&S A2000 68040 Turbo Board", PPS_A2000_040) + PROD("Zeus SCSI Controller", ZEUS) + PROD("PP&S A500 68040 Turbo Board", PPS_A500_040) +END + +BEGIN_PROD(BSC) + PROD("ALF 3 SCSI Controller", ALF_3_SCSI) +END + +BEGIN_PROD(C_LTD) + PROD("Kronos SCSI Controller", KRONOS_SCSI) +END + +BEGIN_PROD(JOCHHEIM) + PROD("Jochheim RAM", JOCHHEIM_RAM) +END + +BEGIN_PROD(CHECKPOINT) + PROD("Serial Solution", SERIAL_SOLUTION) +END + +BEGIN_PROD(GOLEM) + PROD("Golem SCSI-II Controller", GOLEM_SCSI_II) +END + +BEGIN_PROD(HARDITAL_SYNTHES) + PROD("SCSI Controller", HARDITAL_SCSI) +END + +BEGIN_PROD(BSC2) + PROD("Oktagon 2008 SCSI Controller", OKTAGON_SCSI) + PROD("Tandem", TANDEM) + PROD("Oktagon 2008 RAM", OKTAGON_RAM) + PROD("Alfa Data MultiFace I", MULTIFACE_I) + PROD("Alfa Data MultiFace II", MULTIFACE_II) + PROD("Alfa Data MultiFace III", MULTIFACE_III) + PROD("ISDN Master", ISDN_MASTER) +END + +BEGIN_PROD(ADV_SYS_SOFT) + PROD("Nexus SCSI Controller", NEXUS_SCSI) + PROD("Nexus RAM", NEXUS_RAM) +END + +BEGIN_PROD(IVS) + PROD("Trumpcard 500 SCSI Controller", TRUMPCARD_500) + PROD("Trumpcard SCSI Controller", TRUMPCARD) + PROD("Vector SCSI Controller", VECTOR) +END + +BEGIN_PROD(XPERT_PRODEV) + PROD("Merlin Graphics Board (RAM)", MERLIN_RAM) + PROD("Merlin Graphics Board (REG)", MERLIN_REG) +END + +BEGIN_PROD(HYDRA_SYSTEMS) + PROD("Amiganet Board", AMIGANET) +END + +BEGIN_PROD(DIG_MICRONICS) + PROD("DMI Resolver Graphics Board", DMI_RESOLVER) +END + +BEGIN_PROD(HELFRICH1) + PROD("Rainbow3 Graphics Board", RAINBOW3) +END + +BEGIN_PROD(SW_RESULT_ENTS) + PROD("GG2+ Bus Converter", GG2PLUS) +END + +BEGIN_PROD(VILLAGE_TRONIC) + PROD("Ariadne Ethernet Card", ARIADNE) + PROD("Picasso II Graphics Board (RAM)", PICASSO_II_RAM) + PROD("Picasso II Graphics Board (REG)", PICASSO_II_REG) +END + +BEGIN_PROD(UTILITIES_ULTD) + PROD("Emplant Deluxe SCSI Controller", EMPLANT_DELUXE) + PROD("Emplant Deluxe SCSI Controller", EMPLANT_DELUXE2) +END + +BEGIN_PROD(MTEC) + PROD("68030 Turbo Board", MTEC_68030) + PROD("T1230/28 Turbo Board", MTEC_T1230) +END + +BEGIN_PROD(GVP2) + PROD("Spectrum Graphics Board (RAM)", SPECTRUM_RAM) + PROD("Spectrum Graphics Board (REG)", SPECTRUM_REG) +END + +BEGIN_PROD(HELFRICH2) + PROD("Piccolo Graphics Board (RAM)", PICCOLO_RAM) + PROD("Piccolo Graphics Board (REG)", PICCOLO_REG) + PROD("PeggyPlus MPEG Decoder Board", PEGGY_PLUS) + PROD("SD64 Graphics Board (RAM)", SD64_RAM) + PROD("SD64 Graphics Board (REG)", SD64_REG) +END + +BEGIN_PROD(MACROSYSTEMS) + PROD("Warp Engine SCSI Controller", WARP_ENGINE) +END + +BEGIN_PROD(HARMS_PROF) + PROD("3500 Turbo board", 3500_TURBO) +END + +BEGIN_PROD(VORTEX) + PROD("Golden Gate 80386 Board", GOLDEN_GATE_386) + PROD("Golden Gate RAM", GOLDEN_GATE_RAM) + PROD("Golden Gate 80486 Board", GOLDEN_GATE_486) +END + +BEGIN_PROD(DATAFLYER) + PROD("4000SX SCSI Controller", DATAFLYER_4000SX) +END + +BEGIN_PROD(PHASE5) + PROD("FastLane RAM", FASTLANE_RAM) + PROD("FastLane/Blizzard 1230-II SCSI Controller", FASTLANE_SCSI) + PROD("Blizzard 1230-III Turbo Board", BLIZZARD_1230_III) + PROD("Blizzard 1230-IV Turbo Board", BLIZZARD_1230_IV) + PROD("CyberVision64 Graphics Board", CYBERVISION) +END + +BEGIN_PROD(APOLLO) + PROD("AT-Apollo", AT_APOLLO) + PROD("Turbo Board", APOLLO_TURBO) +END + +BEGIN_PROD(UWE_GERLACH) + PROD("RAM/ROM", UG_RAM_ROM) +END + +BEGIN_PROD(MACROSYSTEMS2) + PROD("Maestro", MAESTRO) + PROD("VLab", VLAB) + PROD("Maestro Pro", MAESTRO_PRO) + PROD("Retina Z2 Graphics Board", RETINA_Z2) + PROD("MultiEvolution", MULTI_EVOLUTION) + PROD("Retina Z3 Graphics Board", RETINA_Z3) +END + +BEGIN_MANUF + MANUF("Memphis", MEMPHIS) + MANUF("Commodore", COMMODORE2) + MANUF("Commodore", COMMODORE) + MANUF("Cardco", CARDCO) + MANUF("MicroBotics", MICROBOTICS) + MANUF("ASDG", ASDG) + MANUF("University of Lowell", UNIV_OF_LOWELL) + MANUF("Ameristar", AMERISTAR) + MANUF("Supra", SUPRA) + MANUF("CSA", CSA) + MANUF("Power Computing", POWER_COMPUTING) + MANUF("Great Valley Products", GVP) + MANUF("Progressive Peripherals", PPI) + MANUF("BSC", BSC) + MANUF("C Ltd.", C_LTD) + MANUF("Jochheim", JOCHHEIM) + MANUF("Checkpoint Technologies", CHECKPOINT) + MANUF("Golem", GOLEM) + MANUF("Hardital Synthesis", HARDITAL_SYNTHES) + MANUF("BSC", BSC2) + MANUF("Advanced Systems & Software", ADV_SYS_SOFT) + MANUF("IVS", IVS) + MANUF("XPert/ProDev", XPERT_PRODEV) + MANUF("Hydra Systems", HYDRA_SYSTEMS) + MANUF("Digital Micronics", DIG_MICRONICS) + MANUF("Helfrich", HELFRICH1) + MANUF("Software Result Enterprises", SW_RESULT_ENTS) + MANUF("Village Tronic", VILLAGE_TRONIC) + MANUF("Utilities Unlimited", UTILITIES_ULTD) + MANUF("MTEC", MTEC) + MANUF("Great Valley Products", GVP2) + MANUF("Helfrich", HELFRICH2) + MANUF("MacroSystems", MACROSYSTEMS) + MANUF("Harms Professional", HARMS_PROF) + MANUF("Vortex", VORTEX) + MANUF("DataFlyer", DATAFLYER) + MANUF("Phase5", PHASE5) + MANUF("Apollo", APOLLO) + MANUF("Uwe Gerlach", UWE_GERLACH) + MANUF("MacroSystems", MACROSYSTEMS2) +END + +#define NUM_MANUF (sizeof(Manufacturers)/sizeof(struct Manufacturer)) +#define NUM_GVP_PROD (sizeof(Ext_Prod_GVP)/sizeof(struct GVP_Product)) + +#endif /* CONFIG_ZORRO */ + + + /* + * Configured Expansion Devices + */ + +static u_long BoardPartFlags[NUM_AUTO] = { 0, }; + + + /* + * Find the key for the next unconfigured expansion device of a specific + * type. + * + * Part is a device specific number (0 <= part <= 31) to allow for the + * independent configuration of independent parts of an expansion board. + * Thanks to Jes Soerensen for this idea! + * + * Index is used to specify the first board in the autocon list + * to be tested. It was inserted in order to solve the problem + * with the GVP boards that uses the same product code, but + * it should help if there are other companies uses the same + * method as GVP. Drivers for boards which are not using this + * method does not need to think of this - just set index = 0. + * + * Example: + * + * while ((key = zorro_find(MY_MANUF, MY_PROD, MY_PART, 0))) { + * cd = zorro_get_board(key); + * initialise_this_board; + * zorro_config_board(key, MY_PART); + * } + */ + +int zorro_find(int manuf, int prod, int part, int index) +{ + int key; + struct ConfigDev *cd; + + if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(ZORRO)) + return(0); + + if ((part < 0) || (part > 31)) { + printk("zorro_find: bad part %d\n", part); + return(0); + } + + for (key = index + 1; key <= boot_info.bi_amiga.num_autocon; key++) { + cd = &boot_info.bi_amiga.autocon[key-1]; + if ((cd->cd_Rom.er_Manufacturer == manuf) && + (cd->cd_Rom.er_Product == prod) && + !(BoardPartFlags[key-1] & (1< boot_info.bi_amiga.num_autocon)) + printk("zorro_get_board: bad key %d\n", key); + else + cd = &boot_info.bi_amiga.autocon[key-1]; + + return(cd); +} + + + /* + * Mark a part of a board as configured + */ + +void zorro_config_board(int key, int part) +{ + if ((key < 1) || (key > boot_info.bi_amiga.num_autocon)) + printk("zorro_config_board: bad key %d\n", key); + else if ((part < 0) || (part > 31)) + printk("zorro_config_board: bad part %d\n", part); + else + BoardPartFlags[key-1] |= 1< boot_info.bi_amiga.num_autocon)) + printk("zorro_unconfig_board: bad key %d\n", key); + else if ((part < 0) || (part > 31)) + printk("zorro_unconfig_board: bad part %d\n", part); + else + BoardPartFlags[key-1] &= ~(1<cd_Rom.er_Manufacturer; + prod = cd->cd_Rom.er_Product; + addr = (u_long)cd->cd_BoardAddr; + size = cd->cd_BoardSize; + configured = BoardPartFlags[devnum] ? '*' : ' '; + manufname = prodname = ""; + + for (i = 0; i < NUM_MANUF; i++) + if (Manufacturers[i].ID == manuf) { + manufname = Manufacturers[i].Name; + for (j = 0; j < Manufacturers[i].NumProd; j++) + if (Manufacturers[i].Products[j].ID == prod) + if ((manuf != MANUF_GVP) || (prod != PROD_GVP)) { + prodname = Manufacturers[i].Products[j].Name; + identified = 1; + break; + } else { + epc = *(enum GVP_ident *)ZTWO_VADDR(addr+0x8000) & + GVP_EPCMASK; + for (k = 0; k < NUM_GVP_PROD; k++) + if (Ext_Prod_GVP[k].ID == epc) { + prodname = Ext_Prod_GVP[k].Name; + identified = 1; + break; + } + } + break; + } + + switch (cd->cd_Rom.er_Type & ERT_TYPEMASK) { + case ERT_ZORROII: + zorro = '2'; + break; + case ERT_ZORROIII: + zorro = '3'; + break; + default: + zorro = '?'; + break; + } + if (size & 0xfffff) { + size >>= 10; + mag = 'K'; + } else { + size >>= 20; + mag = 'M'; + } + if (cd->cd_Rom.er_Type & ERTF_MEMLIST) + is_mem = " MEM"; + else + is_mem = ""; + + if (identified) + len = sprintf(buf, " %c0x%08lx: %s %s (Z%c, %ld%c%s)\n", configured, addr, + manufname, prodname, zorro, size, mag, is_mem); + else if (manuf == MANUF_HACKER) + len = sprintf(buf, " 0x%08lx: Hacker Test Board 0x%02x (Z%c, %ld%c%s)\n", + addr, prod, zorro, size, mag, is_mem); + else { + len = sprintf(buf, " 0x%08lx: [%04x:%02x] made by %s (Z%c, %ld%c%s)\n", + addr, manuf, prod, manufname, zorro, size, mag, is_mem); + len += sprintf(buf+len, " Please report this unknown device to " + "Geert.Uytterhoeven@cs.kuleuven.ac.be\n"); + } + return(len); +} + + + /* + * Identify all known AutoConfig Expansion Devices + */ + +void zorro_identify(void) +{ + int i; + char tmp[160]; + + if (!AMIGAHW_PRESENT(ZORRO)) + return; + + printk("Probing AutoConfig expansion device(s):\n"); + for (i = 0; i < boot_info.bi_amiga.num_autocon; i++) { + identify(i, tmp); + printk(tmp); + } + if (!boot_info.bi_amiga.num_autocon) + printk("No AutoConfig expansion devices present.\n"); +} + + + /* + * Get the list of all AutoConfig Expansion Devices + */ + +int zorro_get_list(char *buffer) +{ + int i, j, len = 0; + char tmp[160]; + + if (MACH_IS_AMIGA && AMIGAHW_PRESENT(ZORRO)) { + len = sprintf(buffer, "AutoConfig expansion devices:\n"); + for (i = 0; i < boot_info.bi_amiga.num_autocon; i++) { + j = identify(i, tmp); + if (len+j >= 4075) { + len += sprintf(buffer+len, "4K limit reached!\n"); + break; + } + strcpy(buffer+len, tmp); + len += j; + } + } + return(len); +} + +#endif /* CONFIG_ZORRO */ + + + /* + * Bitmask indicating portions of available Zorro II RAM that are unused + * by the system. Every bit represents a 64K chunk, for a maximum of 8MB + * (128 chunks, physical 0x00200000-0x009fffff). + * + * If you want to use (= allocate) portions of this RAM, you should clear + * the corresponding bits. + * + * Possible uses: + * - z2ram device + * - SCSI DMA bounce buffers + */ + +u_long zorro_unused_z2ram[4] = { 0, 0, 0, 0 }; + + +static void mark_region(u_long addr, u_long size, int flag) +{ + u_long start, end, chunk; + + if (flag) { + start = (addr+Z2RAM_CHUNKMASK) & ~Z2RAM_CHUNKMASK; + end = (addr+size) & ~Z2RAM_CHUNKMASK; + } else { + start = addr & ~Z2RAM_CHUNKMASK; + end = (addr+size+Z2RAM_CHUNKMASK) & ~Z2RAM_CHUNKMASK; + } + if (end <= Z2RAM_START || start >= Z2RAM_END) + return; + start = start < Z2RAM_START ? 0x00000000 : start-Z2RAM_START; + end = end > Z2RAM_END ? Z2RAM_SIZE : end-Z2RAM_START; + while (start < end) { + chunk = start>>Z2RAM_CHUNKSHIFT; + if (flag) + set_bit( chunk, zorro_unused_z2ram ); + else + clear_bit( chunk, zorro_unused_z2ram ); + start += Z2RAM_CHUNKSIZE; + } +} + + + /* + * Initialization + */ + +void zorro_init(void) +{ + int i; + struct ConfigDev *cd; + + if (!AMIGAHW_PRESENT(ZORRO)) + return; + + /* Mark all available Zorro II memory */ + for (i = 0; i < boot_info.bi_amiga.num_autocon; i++) { + cd = &boot_info.bi_amiga.autocon[i]; + if (cd->cd_Rom.er_Type & ERTF_MEMLIST) + mark_region((u_long)cd->cd_BoardAddr, cd->cd_BoardSize, 1); + } + /* Unmark all used Zorro II memory */ + for (i = 0; i < boot_info.num_memory; i++) + mark_region(boot_info.memory[i].addr, boot_info.memory[i].size, 0); +} diff -u --recursive --new-file v1.3.93/linux/arch/m68k/atari/Makefile linux/arch/m68k/atari/Makefile --- v1.3.93/linux/arch/m68k/atari/Makefile Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/atari/Makefile Mon Apr 1 22:04:02 1996 @@ -0,0 +1,17 @@ +# +# Makefile for Linux arch/m68k/atari source directory +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now in the main makefile... + +EXTRA_CFLAGS := -Wa,-m68030 + +O_TARGET := atari.o +O_OBJS := config.o atakeyb.o ataints.o \ + atapart.o stdma.o atasound.o joystick.o stram.o atafb.o +OX_OBJS = ksyms.o + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.93/linux/arch/m68k/atari/atafb.c linux/arch/m68k/atari/atafb.c --- v1.3.93/linux/arch/m68k/atari/atafb.c Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/atari/atafb.c Sat Mar 30 21:06:53 1996 @@ -0,0 +1,3175 @@ +/* + * atari/atafb.c -- Low level implementation of Atari frame buffer device + * + * Copyright (C) 1994 Martin Schaller & Roman Hodek + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file README.legal in the main directory of this archive + * for more details. + * + * History: + * - 03 Jan 95: Original version by Martin Schaller: The TT driver and + * all the device independent stuff + * - 09 Jan 95: Roman: I've added the hardware abstraction (hw_switch) + * and wrote the Falcon, ST(E), and External drivers + * based on the original TT driver. + * - 07 May 95: Martin: Added colormap operations for the external driver + * - 21 May 95: Martin: Added support for overscan + * Andreas: some bug fixes for this + * - Jul 95: Guenther Kelleter : + * Programmable Falcon video modes + * (thanks to Christian Cartus for documentation + * of VIDEL registers). + * - 27 Dec 95: Guenther: Implemented user definable video modes "user[0-7]" + * on minor 24...31. "user0" may be set on commandline by + * "R;;". (Makes sense only on Falcon) + * Video mode switch on Falcon now done at next VBL interrupt + * to avoid the annoying right shift of the screen. + * + * + * To do: + * - For the Falcon it is not possible to set random video modes on + * SM124 and SC/TV, only the bootup resolution is supported. + * + */ + +#define ATAFB_TT +#define ATAFB_STE +#define ATAFB_EXT +#define ATAFB_FALCON + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#define SWITCH_ACIA 0x01 /* modes for switch on OverScan */ +#define SWITCH_SND6 0x40 +#define SWITCH_SND7 0x80 +#define SWITCH_NONE 0x00 + + +#define arraysize(x) (sizeof(x)/sizeof(*(x))) + +#define up(x, r) (((x) + (r) - 1) & ~((r)-1)) + + +static int default_par=0; /* default resolution (0=none) */ + +static int node; /* node of the /dev/fb?current file */ + +static unsigned long default_mem_req=0; + +static int hwscroll=-1; + +static int use_hwscroll = 1; + +static int sttt_xres=640,st_yres=400,tt_yres=480; +static int sttt_xres_virtual=640,sttt_yres_virtual=400; +static int ovsc_offset=0, ovsc_addlen=0; +int ovsc_switchmode=0; + +#ifdef ATAFB_FALCON +static int pwrsave = 0; /* use VESA suspend mode instead of blanking only? */ +#endif + +static struct atari_fb_par { + unsigned long screen_base; + int vyres; + union { + struct { + int mode; + int sync; + } tt, st; + struct falcon_hw { + /* Here are fields for storing a video mode, as direct + * parameters for the hardware. + */ + short sync; + short line_width; + short line_offset; + short st_shift; + short f_shift; + short vid_control; + short vid_mode; + short xoffset; + short hht, hbb, hbe, hdb, hde, hss; + short vft, vbb, vbe, vdb, vde, vss; + /* auxiliary informations */ + short mono; + short ste_mode; + short bpp; + } falcon; + /* Nothing needed for external mode */ + } hw; +} current_par; + +/* Don't calculate an own resoltion, and thus don't change the one found when + * booting (currently used for the Falcon to keep settings for internal video + * hardware extensions (e.g. ScreenBlaster) */ +static int DontCalcRes = 0; + +#define HHT hw.falcon.hht +#define HBB hw.falcon.hbb +#define HBE hw.falcon.hbe +#define HDB hw.falcon.hdb +#define HDE hw.falcon.hde +#define HSS hw.falcon.hss +#define VFT hw.falcon.vft +#define VBB hw.falcon.vbb +#define VBE hw.falcon.vbe +#define VDB hw.falcon.vdb +#define VDE hw.falcon.vde +#define VSS hw.falcon.vss +#define VCO_CLOCK25 0x04 +#define VCO_CSYPOS 0x10 +#define VCO_VSYPOS 0x20 +#define VCO_HSYPOS 0x40 +#define VCO_SHORTOFFS 0x100 +#define VMO_DOUBLE 0x01 +#define VMO_INTER 0x02 +#define VMO_PREMASK 0x0c + +static struct fb_info fb_info; + +static unsigned long screen_base; /* base address of screen */ +static unsigned long real_screen_base; /* (only for Overscan) */ + +static int screen_len; + +static int current_par_valid=0; + +static int currcon=0; + +static int mono_moni=0; + +static struct display disp[MAX_NR_CONSOLES]; + + +#ifdef ATAFB_EXT +/* external video handling */ + +static unsigned external_xres; +static unsigned external_yres; +static unsigned external_depth; +static int external_pmode; +static unsigned long external_addr = 0; +static unsigned long external_len; +static unsigned long external_vgaiobase = 0; +static unsigned int external_bitspercol = 6; + +/* +++JOE : +added card type for external driver, is only needed for +colormap handling. +*/ + +enum cardtype { IS_VGA, IS_MV300 }; +static enum cardtype external_card_type = IS_VGA; + +/* +The MV300 mixes the color registers. So we need an array of munged +indices in order to acces the correct reg. +*/ +static int MV300_reg_1bit[2]={0,1}; +static int MV300_reg_4bit[16]={ +0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15 }; +static int MV300_reg_8bit[256]={ +0, 128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208, 48, 176, 112, 240, +8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, 120, 248, +4, 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, 180, 116, 244, +12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252, +2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82, 210, 50, 178, 114, 242, +10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250, +6, 134, 70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246, +14, 142, 78, 206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254, +1, 129, 65, 193, 33, 161, 97, 225, 17, 145, 81, 209, 49, 177, 113, 241, +9, 137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249, +5, 133, 69, 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245, +13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253, +3, 131, 67, 195, 35, 163, 99, 227, 19, 147, 83, 211, 51, 179, 115, 243, +11, 139, 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251, +7, 135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247, +15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, 255 }; + +static int *MV300_reg = MV300_reg_8bit; + +/* +And on the MV300 it's difficult to read out the hardware palette. So we +just keep track of the set colors in our own array here, and use that! +*/ + +struct { unsigned char red,green,blue,pad; } MV300_color[256]; +#endif /* ATAFB_EXT */ + + +int inverse=0; + +extern int fontheight_8x8; +extern int fontwidth_8x8; +extern unsigned char fontdata_8x8[]; + +extern int fontheight_8x16; +extern int fontwidth_8x16; +extern unsigned char fontdata_8x16[]; + +/* import first 16 colors from fbcon.c */ +extern unsigned short packed16_cmap[16]; + + +/* ++roman: This structure abstracts from the underlying hardware (ST(e), + * TT, or Falcon. + * + * int (*detect)( void ) + * This function should detect the current video mode settings and + * store them in atari_fb_predefined[0] for later reference by the + * user. Return the index+1 of an equivalent predefined mode or 0 + * if there is no such. + * + * int (*encode_fix)( struct fb_fix_screeninfo *fix, + * struct atari_fb_par *par ) + * This function should fill in the 'fix' structure based on the + * values in the 'par' structure. + * + * int (*decode_var)( struct fb_var_screeninfo *var, + * struct atari_fb_par *par ) + * Get the video params out of 'var'. If a value doesn't fit, round + * it up, if it's too big, return EINVAL. + * Round up in the following order: bits_per_pixel, xres, yres, + * xres_virtual, yres_virtual, xoffset, yoffset, grayscale, bitfields, + * horizontal timing, vertical timing. + * + * int (*encode_var)( struct fb_var_screeninfo *var, + * struct atari_fb_par *par ); + * Fill the 'var' structure based on the values in 'par' and maybe + * other values read out of the hardware. + * + * void (*get_par)( struct atari_fb_par *par ) + * Fill the hardware's 'par' structure. + * + * void (*set_par)( struct atari_fb_par *par ) + * Set the hardware according to 'par'. + * + * int (*setcolreg)( unsigned regno, unsigned red, + * unsigned green, unsigned blue, + * unsigned transp ) + * Set a single color register. The values supplied are already + * rounded down to the hardware's capabilities (according to the + * entries in the var structure). Return != 0 for invalid regno. + * + * int (*getcolreg)( unsigned regno, unsigned *red, + * unsigned *green, unsigned *blue, + * unsigned *transp ) + * Read a single color register and split it into + * colors/transparent. Return != 0 for invalid regno. + * + * void (*set_screen_base)( unsigned long s_base ) + * Set the base address of the displayed frame buffer. Only called + * if yres_virtual > yres or xres_virtual > xres. + * + * int (*blank)( int blank_mode ) + * Blank the screen if blank_mode != 0, else unblank. If NULL then blanking + * is done by setting the CLUT to black. Return != 0 if un-/blanking + * failed due to e.g. video mode which doesn't support it. + */ + +static struct fb_hwswitch { + int (*detect)( void ); + int (*encode_fix)( struct fb_fix_screeninfo *fix, + struct atari_fb_par *par ); + int (*decode_var)( struct fb_var_screeninfo *var, + struct atari_fb_par *par ); + int (*encode_var)( struct fb_var_screeninfo *var, + struct atari_fb_par *par ); + void (*get_par)( struct atari_fb_par *par ); + void (*set_par)( struct atari_fb_par *par ); + int (*getcolreg)( unsigned regno, unsigned *red, + unsigned *green, unsigned *blue, + unsigned *transp ); + int (*setcolreg)( unsigned regno, unsigned red, + unsigned green, unsigned blue, + unsigned transp ); + void (*set_screen_base)( unsigned long s_base ); + int (*blank)( int blank_mode ); + int (*pan_display)( struct fb_var_screeninfo *var, + struct atari_fb_par *par); +} *fbhw; + +static char *autodetect_names[] = {"autodetect", NULL}; +static char *stlow_names[] = {"stlow", NULL}; +static char *stmid_names[] = {"stmid", "default5", NULL}; +static char *sthigh_names[] = {"sthigh", "default4", NULL}; +static char *ttlow_names[] = {"ttlow", NULL}; +static char *ttmid_names[]= {"ttmid", "default1", NULL}; +static char *tthigh_names[]= {"tthigh", "default2", NULL}; +static char *vga2_names[] = {"vga2", NULL}; +static char *vga4_names[] = {"vga4", NULL}; +static char *vga16_names[] = {"vga16", "default3", NULL}; +static char *vga256_names[] = {"vga256", NULL}; +static char *falh2_names[] = {"falh2", NULL}; +static char *falh16_names[] = {"falh16", NULL}; +static char *user0_names[] = {"user0", NULL}; +static char *user1_names[] = {"user1", NULL}; +static char *user2_names[] = {"user2", NULL}; +static char *user3_names[] = {"user3", NULL}; +static char *user4_names[] = {"user4", NULL}; +static char *user5_names[] = {"user5", NULL}; +static char *user6_names[] = {"user6", NULL}; +static char *user7_names[] = {"user7", NULL}; +static char *dummy_names[] = {"dummy", NULL}; + +char **fb_var_names[] = { + /* Writing the name arrays directly in this array (via "(char *[]){...}") + * crashes gcc 2.5.8 (sigsegv) if the inner array + * contains more than two items. I've also seen that all elements + * were identical to the last (my cross-gcc) :-(*/ + autodetect_names, + stlow_names, + stmid_names, + sthigh_names, + ttlow_names, + ttmid_names, + tthigh_names, + vga2_names, + vga4_names, + vga16_names, + vga256_names, + falh2_names, + falh16_names, + dummy_names, dummy_names, dummy_names, dummy_names, + dummy_names, dummy_names, dummy_names, dummy_names, + dummy_names, dummy_names, + user0_names, + user1_names, + user2_names, + user3_names, + user4_names, + user5_names, + user6_names, + user7_names, + NULL + /* ,NULL */ /* this causes a sigsegv on my gcc-2.5.8 */ +}; + +struct fb_var_screeninfo atari_fb_predefined[] = { + { /* autodetect */ + 0, 0, 0, 0, 0, 0, 0, 0, /* xres-grayscale */ + {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, /* red green blue tran*/ + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { /* st low */ + 320, 200, 320, 200, 0, 0, 4, 0, /* xres-grayscale */ + {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0}, /* red green blue tran*/ + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { /* st mid */ + 640, 200, 640, 200, 0, 0, 2, 0, /* xres-grayscale */ + {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0}, /* red green blue tran*/ + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { /* st high */ + 640, 400, 640, 400, 0, 0, 1, 0, /* xres-grayscale */ + {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0}, /* red green blue tran*/ + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { /* tt low */ + 320, 480, 320, 480, 0, 0, 8, 0, /* xres-grayscale */ + {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0}, /* red green blue tran*/ + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { /* tt mid */ + 640, 480, 640, 480, 0, 0, 4, 0, /* xres-grayscale */ + {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0}, /* red green blue tran*/ + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { /* tt high */ + 1280, 960, 1280, 960, 0, 0, 1, 0, /* xres-grayscale */ + {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0}, /* red green blue tran*/ + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { /* vga2 */ + 640, 480, 640, 480, 0, 0, 1, 0, /* xres-grayscale */ + {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, /* red green blue tran*/ + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { /* vga4 */ + 640, 480, 640, 480, 0, 0, 2, 0, /* xres-grayscale */ + {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0}, /* red green blue tran*/ + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { /* vga16 */ + 640, 480, 640, 480, 0, 0, 4, 0, /* xres-grayscale */ + {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, /* red green blue tran*/ + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { /* vga256 */ + 640, 480, 640, 480, 0, 0, 8, 0, /* xres-grayscale */ + {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, /* red green blue tran*/ + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { /* falh2 */ + 896, 608, 896, 608, 0, 0, 1, 0, /* xres-grayscale */ + {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, /* red green blue tran*/ + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { /* falh16 */ + 896, 608, 896, 608, 0, 0, 4, 0, /* xres-grayscale */ + {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, /* red green blue tran*/ + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* Minor 14..23 free for more standard video modes */ + { 0, }, + { 0, }, + { 0, }, + { 0, }, + { 0, }, + { 0, }, + { 0, }, + { 0, }, + { 0, }, + { 0, }, + /* Minor 24..31 reserved for user defined video modes */ + { /* user0, initialized to Rx;y;d from commandline, if supplied */ + 0, 0, 0, 0, 0, 0, 0, 0, + {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { /* user1 */ + 0, 0, 0, 0, 0, 0, 0, 0, + {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { /* user2 */ + 0, 0, 0, 0, 0, 0, 0, 0, + {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { /* user3 */ + 0, 0, 0, 0, 0, 0, 0, 0, + {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { /* user4 */ + 0, 0, 0, 0, 0, 0, 0, 0, + {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { /* user5 */ + 0, 0, 0, 0, 0, 0, 0, 0, + {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { /* user6 */ + 0, 0, 0, 0, 0, 0, 0, 0, + {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { /* user7 */ + 0, 0, 0, 0, 0, 0, 0, 0, + {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 } +}; + +int num_atari_fb_predefined=arraysize(atari_fb_predefined); + + +static int +get_video_mode(char *vname) +{ + char ***name_list; + char **name; + int i; + name_list=fb_var_names; + for (i = 0 ; i < num_atari_fb_predefined ; i++) { + name=*(name_list++); + if (! name || ! *name) + break; + while (*name) { + if (! strcmp(vname, *name)) + return i+1; + name++; + } + } + return 0; +} + + + +/* ------------------- TT specific functions ---------------------- */ + +#ifdef ATAFB_TT + +static int tt_encode_fix( struct fb_fix_screeninfo *fix, + struct atari_fb_par *par ) + +{ + int mode, i; + + strcpy(fix->id,"Atari Builtin"); + fix->smem_start=real_screen_base; + fix->smem_len = screen_len; + fix->type=FB_TYPE_INTERLEAVED_PLANES; + fix->type_aux=2; + fix->visual=FB_VISUAL_PSEUDOCOLOR; + mode = par->hw.tt.mode & TT_SHIFTER_MODEMASK; + if (mode == TT_SHIFTER_TTHIGH || mode == TT_SHIFTER_STHIGH) { + fix->type=FB_TYPE_PACKED_PIXELS; + fix->type_aux=0; + if (mode == TT_SHIFTER_TTHIGH) + fix->visual=FB_VISUAL_MONO01; + } + fix->xpanstep=0; + fix->ypanstep=1; + fix->ywrapstep=0; + for (i=0; ireserved); i++) + fix->reserved[i]=0; + return 0; +} + + +static int tt_decode_var( struct fb_var_screeninfo *var, + struct atari_fb_par *par ) +{ + int xres=var->xres; + int yres=var->yres; + int bpp=var->bits_per_pixel; + int linelen; + + if (mono_moni) { + if (bpp > 1 || xres > sttt_xres*2 || yres >tt_yres*2) + return -EINVAL; + par->hw.tt.mode=TT_SHIFTER_TTHIGH; + xres=sttt_xres*2; + yres=tt_yres*2; + bpp=1; + } else { + if (bpp > 8 || xres > sttt_xres || yres > tt_yres) + return -EINVAL; + if (bpp > 4) { + if (xres > sttt_xres/2 || yres > tt_yres) + return -EINVAL; + par->hw.tt.mode=TT_SHIFTER_TTLOW; + xres=sttt_xres/2; + yres=tt_yres; + bpp=8; + } + else if (bpp > 2) { + if (xres > sttt_xres || yres > tt_yres) + return -EINVAL; + if (xres > sttt_xres/2 || yres > st_yres/2) { + par->hw.tt.mode=TT_SHIFTER_TTMID; + xres=sttt_xres; + yres=tt_yres; + bpp=4; + } + else { + par->hw.tt.mode=TT_SHIFTER_STLOW; + xres=sttt_xres/2; + yres=st_yres/2; + bpp=4; + } + } + else if (bpp > 1) { + if (xres > sttt_xres || yres > st_yres/2) + return -EINVAL; + par->hw.tt.mode=TT_SHIFTER_STMID; + xres=sttt_xres; + yres=st_yres/2; + bpp=2; + } + else if (var->xres > sttt_xres || var->yres > st_yres) { + return -EINVAL; + } + else { + par->hw.tt.mode=TT_SHIFTER_STHIGH; + xres=sttt_xres; + yres=st_yres; + bpp=1; + } + } + if (var->sync & FB_SYNC_EXT) + par->hw.tt.sync=0; + else + par->hw.tt.sync=1; + linelen=xres*bpp/8; + if ((var->yoffset + yres)*linelen > screen_len && screen_len) + return -EINVAL; + par->screen_base=screen_base+ var->yoffset*linelen; + return 0; +} + +static int tt_encode_var( struct fb_var_screeninfo *var, + struct atari_fb_par *par ) +{ + int linelen, i; + var->red.offset=0; + var->red.length=4; + var->red.msb_right=0; + var->grayscale=0; + + var->pixclock=31041; + var->left_margin=120; /* these may be incorrect */ + var->right_margin=100; + var->upper_margin=8; + var->lower_margin=16; + var->hsync_len=140; + var->vsync_len=30; + + var->height=-1; + var->width=-1; + + if (par->hw.tt.sync & 1) + var->sync=0; + else + var->sync=FB_SYNC_EXT; + + switch (par->hw.tt.mode & TT_SHIFTER_MODEMASK) { + case TT_SHIFTER_STLOW: + var->xres=sttt_xres/2; + var->xres_virtual=sttt_xres_virtual/2; + var->yres=st_yres/2; + var->bits_per_pixel=4; + break; + case TT_SHIFTER_STMID: + var->xres=sttt_xres; + var->xres_virtual=sttt_xres_virtual; + var->yres=st_yres/2; + var->bits_per_pixel=2; + break; + case TT_SHIFTER_STHIGH: + var->xres=sttt_xres; + var->xres_virtual=sttt_xres_virtual; + var->yres=st_yres; + var->bits_per_pixel=1; + break; + case TT_SHIFTER_TTLOW: + var->xres=sttt_xres/2; + var->xres_virtual=sttt_xres_virtual/2; + var->yres=tt_yres; + var->bits_per_pixel=8; + break; + case TT_SHIFTER_TTMID: + var->xres=sttt_xres; + var->xres_virtual=sttt_xres_virtual; + var->yres=tt_yres; + var->bits_per_pixel=4; + break; + case TT_SHIFTER_TTHIGH: + var->red.length=0; + var->xres=sttt_xres*2; + var->xres_virtual=sttt_xres_virtual*2; + var->yres=tt_yres*2; + var->bits_per_pixel=1; + break; + } + var->blue=var->green=var->red; + var->transp.offset=0; + var->transp.length=0; + var->transp.msb_right=0; + linelen=var->xres_virtual * var->bits_per_pixel / 8; + if (! use_hwscroll) + var->yres_virtual=var->yres; + else if (screen_len) + var->yres_virtual=screen_len/linelen; + else { + if (hwscroll < 0) + var->yres_virtual = 2 * var->yres; + else + var->yres_virtual=var->yres+hwscroll * 16; + } + var->xoffset=0; + if (screen_base) + var->yoffset=(par->screen_base - screen_base)/linelen; + else + var->yoffset=0; + var->nonstd=0; + var->activate=0; + var->vmode=FB_VMODE_NONINTERLACED; + for (i=0; ireserved); i++) + var->reserved[i]=0; + return 0; +} + + +static void tt_get_par( struct atari_fb_par *par ) +{ + unsigned long addr; + par->hw.tt.mode=shifter_tt.tt_shiftmode; + par->hw.tt.sync=shifter.syncmode; + addr = ((shifter.bas_hi & 0xff) << 16) | + ((shifter.bas_md & 0xff) << 8) | + ((shifter.bas_lo & 0xff)); + par->screen_base = PTOV(addr); +} + +static void tt_set_par( struct atari_fb_par *par ) +{ + shifter_tt.tt_shiftmode=par->hw.tt.mode; + shifter.syncmode=par->hw.tt.sync; + /* only set screen_base if really necessary */ + if (current_par.screen_base != par->screen_base) + fbhw->set_screen_base(par->screen_base); +} + + +static int tt_getcolreg( unsigned regno, unsigned *red, + unsigned *green, unsigned *blue, + unsigned *transp ) +{ + if ((shifter_tt.tt_shiftmode & TT_SHIFTER_MODEMASK) == TT_SHIFTER_STHIGH) + regno += 254; + if (regno > 255) + return 1; + *blue = tt_palette[regno]; + *green = (*blue >> 4) & 0xf; + *red = (*blue >> 8) & 0xf; + *blue &= 0xf; + *transp = 0; + return 0; +} + + +static int tt_setcolreg( unsigned regno, unsigned red, + unsigned green, unsigned blue, + unsigned transp ) +{ + if ((shifter_tt.tt_shiftmode & TT_SHIFTER_MODEMASK) == TT_SHIFTER_STHIGH) + regno += 254; + if (regno > 255) + return 1; + tt_palette[regno] = (red << 8) | (green << 4) | blue; + if ((shifter_tt.tt_shiftmode & TT_SHIFTER_MODEMASK) == + TT_SHIFTER_STHIGH && regno == 254) + tt_palette[0] = 0; + return 0; +} + + +static int tt_detect( void ) + +{ struct atari_fb_par par; + + /* Determine the connected monitor: The DMA sound must be + * disabled before reading the MFP GPIP, because the Sound + * Done Signal and the Monochrome Detect are XORed together! + * + * Even on a TT, we should look if there is a DMA sound. It was + * announced that the Eagle is TT compatible, but only the PCM is + * missing... + */ + if (ATARIHW_PRESENT(PCM_8BIT)) { + tt_dmasnd.ctrl = DMASND_CTRL_OFF; + udelay(20); /* wait a while for things to settle down */ + } + mono_moni = (mfp.par_dt_reg & 0x80) == 0; + + tt_get_par(&par); + tt_encode_var(&atari_fb_predefined[0], &par); + + return 1; +} + +#endif /* ATAFB_TT */ + +/* ------------------- Falcon specific functions ---------------------- */ + +#ifdef ATAFB_FALCON + +static int mon_type; /* Falcon connected monitor */ +static int f030_bus_width; /* Falcon ram bus width (for vid_control) */ +#define F_MON_SM 0 +#define F_MON_SC 1 +#define F_MON_VGA 2 +#define F_MON_TV 3 + +/* Multisync monitor capabilities */ +/* Atari-TOS defaults if no boot option present */ +static long vfmin=58, vfmax=62, hfmin=31000, hfmax=32000; + +static struct pixel_clock { + unsigned long f; /* f/[Hz] */ + unsigned long t; /* t/[ps] (=1/f) */ + short right, hsync, left; /* standard timing in clock cycles, not pixel */ + /* hsync initialized in falcon_detect() */ + short sync_mask; /* or-mask for hw.falcon.sync to set this clock */ + short control_mask; /* dito, for hw.falcon.vid_control */ +} +f25 = {25175000, 39722, 18, 0, 42, 0x0, VCO_CLOCK25}, +f32 = {32000000, 31250, 18, 0, 42, 0x0, 0}, +fext = { 0, 0, 18, 0, 42, 0x1, 0}; + +/* VIDEL-prescale values [mon_type][pixel_length from VCO] */ +static short vdl_prescale[4][3] = {{4,2,1}, {4,2,1}, {4,2,2}, {4,2,1}}; + +/* Default hsync timing [mon_type] in picoseconds */ +static long h_syncs[4] = {3000000, 4700000, 4000000, 4700000}; + + +static inline int hxx_prescale(struct falcon_hw *hw) +{ + return hw->ste_mode ? 16 : + vdl_prescale[mon_type][hw->vid_mode >> 2 & 0x3]; +} + +static int falcon_encode_fix( struct fb_fix_screeninfo *fix, + struct atari_fb_par *par ) +{ + int i; + + strcpy(fix->id, "Atari Builtin"); + fix->smem_start = real_screen_base; + fix->smem_len = screen_len; + fix->type = FB_TYPE_INTERLEAVED_PLANES; + fix->type_aux = 2; + fix->visual = FB_VISUAL_PSEUDOCOLOR; + if (par->hw.falcon.mono) { + fix->type = FB_TYPE_PACKED_PIXELS; + fix->type_aux = 0; + } + else if (par->hw.falcon.f_shift & 0x100) { + fix->type = FB_TYPE_PACKED_PIXELS; + fix->type_aux = 0; + fix->visual = FB_VISUAL_TRUECOLOR; /* is this ok or should this be DIRECTCOLOR? */ + } + if (par->hw.falcon.mono) + /* no smooth scrolling possible with longword aligned video mem */ + fix->xpanstep = 32; + else + fix->xpanstep = 1; + fix->ypanstep = 1; + fix->ywrapstep = 0; + for (i=0; ireserved); i++) + fix->reserved[i]=0; + return 0; +} + + +static int falcon_decode_var( struct fb_var_screeninfo *var, + struct atari_fb_par *par ) +{ + int use_default_timing = 0; + int bpp = var->bits_per_pixel; + int xres = var->xres; + int yres = var->yres; + int xres_virtual = var->xres_virtual; + int yres_virtual = var->yres_virtual; + int left_margin, right_margin, hsync_len; + int upper_margin, lower_margin, vsync_len; + int linelen; + int interlace = 0, doubleline = 0; + struct pixel_clock *pclock; + int plen; /* width of pixel in clock cycles */ + int xstretch; + int prescale; + int longoffset = 0; + int hfreq, vfreq; + +/* + Get the video params out of 'var'. If a value doesn't fit, round + it up, if it's too big, return EINVAL. + Round up in the following order: bits_per_pixel, xres, yres, + xres_virtual, yres_virtual, xoffset, yoffset, grayscale, bitfields, + horizontal timing, vertical timing. + + There is a maximum of screen resolution determined by pixelclock + and minimum frame rate -- (X+hmarg.)*(Y+vmarg.)*vfmin <= pixelclock. + In interlace mode this is " * " *vfmin <= pixelclock. + Additional constraints: hfreq. + Frequency range for multisync monitors is given via command line. + For TV and SM124 both frequencies are fixed. + + X % 16 == 0 to fit 8x?? font (except 1 bitplane modes must use X%32==0) + Y % 16 == 0 to fit 8x16 font + Y % 8 == 0 if Y<400 + + Currently interlace and doubleline mode in var are ignored. + On SM124 and TV only the standard resolutions can be used. +*/ + + /* Reject uninitialized mode */ + if (!xres || !yres || !bpp) + return -EINVAL; + + if (mon_type == F_MON_SM && bpp != 1) { + return -EINVAL; + } + else if (bpp <= 1) { + bpp = 1; + par->hw.falcon.f_shift = 0x400; + par->hw.falcon.st_shift = 0x200; + } + else if (bpp <= 2) { + bpp = 2; + par->hw.falcon.f_shift = 0x000; + par->hw.falcon.st_shift = 0x100; + } + else if (bpp <= 4) { + bpp = 4; + par->hw.falcon.f_shift = 0x000; + par->hw.falcon.st_shift = 0x000; + } + else if (bpp <= 8) { + bpp = 8; + par->hw.falcon.f_shift = 0x010; + } + else if (bpp <= 16) { + bpp = 16; /* packed pixel mode */ + par->hw.falcon.f_shift = 0x100; /* hicolor, no overlay */ + } + else + return -EINVAL; + par->hw.falcon.bpp = bpp; + + if (mon_type != F_MON_VGA || DontCalcRes) { + /* Skip all calculations, VGA multisync only yet */ + struct fb_var_screeninfo *myvar = &atari_fb_predefined[0]; + + if (bpp > myvar->bits_per_pixel || + var->xres > myvar->xres || + var->yres > myvar->yres) + return -EINVAL; + fbhw->get_par(par); /* Current par will be new par */ + goto set_screen_base; /* Don't forget this */ + } + + /* Only some fixed resolutions < 640x480 */ + if (xres <= 320) + xres = 320; + else if (xres <= 640 && bpp != 16) + xres = 640; + if (yres <= 200) + yres = 200; + else if (yres <= 240) + yres = 240; + else if (yres <= 400) + yres = 400; + else if (yres <= 480) + yres = 480; + + /* 2 planes must use STE compatibility mode */ + par->hw.falcon.ste_mode = bpp==2; + par->hw.falcon.mono = bpp==1; + + /* Total and visible scanline length must be a multiple of one longword, + * this and the console fontwidth yields the alignment for xres and + * xres_virtual. + * + * Special case in STE mode: blank and graphic positions don't align, + * avoid trash at right margin + */ + if (par->hw.falcon.ste_mode) + xres = (xres + 63) & ~63; + else if (bpp == 1) + xres = (xres + 31) & ~31; + else + xres = (xres + 15) & ~15; + if (yres >= 400) + yres = (yres + 15) & ~15; + else + yres = (yres + 7) & ~7; + + if (xres_virtual < xres) + xres_virtual = xres; + else if (bpp == 1) + xres_virtual = (xres_virtual + 31) & ~31; + else + xres_virtual = (xres_virtual + 15) & ~15; + /* <=0 : yres_virtual determined by screensize */ + if (yres_virtual < yres && yres_virtual > 0) + yres_virtual = yres; + + par->hw.falcon.line_width = bpp * xres / 16; + par->hw.falcon.line_offset = bpp * (xres_virtual - xres) / 16; + + /* single or double pixel width */ + xstretch = (xres == 320) ? 2 : 1; + + /* Default values are used for vert./hor. timing if no pixelclock given. */ + if (var->pixclock == 0) + use_default_timing = 1; + +#if 0 /* currently unused */ + if (mon_type == F_MON_SM) { + if (xres != 640 && yres != 400) + return -EINVAL; + plen = 1; + pclock = &f32; + /* SM124-mode is special */ + par->hw.falcon.ste_mode = 1; + par->hw.falcon.f_shift = 0x000; + par->hw.falcon.st_shift = 0x200; + left_margin = hsync_len = 128 / plen; + right_margin = 0; + /* TODO set all margins */ + } + else if (mon_type == F_MON_SC || mon_type == F_MON_TV) { + plen = 2 * xstretch; + pclock = &f32; + hsync_len = 150 / plen; + if (yres > 240) + interlace = 1; + /* TODO set margins */ + } + else +#endif + { /* F_MON_VGA */ + if (bpp == 16) + xstretch = 2; /* hicolor only double pixel width */ + if (use_default_timing) { + int linesize; + + /* Choose master pixelclock depending on hor. timing */ + plen = 1 * xstretch; + if ((plen * xres + f25.right+f25.hsync+f25.left) * hfmin < f25.f) + pclock = &f25; + else if ((plen * xres + f32.right+f32.hsync+f32.left) * hfmin < f32.f) + pclock = &f32; + else if ((plen * xres + fext.right+fext.hsync+fext.left) * hfmin < fext.f + && fext.f) + pclock = &fext; + else + return -EINVAL; + + left_margin = pclock->left / plen; + right_margin = pclock->right / plen; + hsync_len = pclock->hsync / plen; + linesize = left_margin + xres + right_margin + hsync_len; + upper_margin = 31; + lower_margin = 11; + vsync_len = 3; + } + else { +#if 0 /* TODO enable this (untested yet) */ + /* Round down pixelclock */ + int i; unsigned long pcl=0; + for (i=1; i<=4; i*=2) { + if (f25.t*i<=var->pixclock && pclpixclock && pclpixclock && pclt; + +#else + if (var->pixclock == f25.t || var->pixclock == 2*f25.t) + pclock = &f25; + else if (var->pixclock == f32.t || var->pixclock == 2*f32.t) + pclock = &f32; + else if ((var->pixclock == fext.t || var->pixclock == 2*fext.t) && fext.t) { + pclock = &fext; + } + else + return -EINVAL; + plen = var->pixclock / pclock->t; +#endif + + left_margin = var->left_margin; + right_margin = var->right_margin; + hsync_len = var->hsync_len; + upper_margin = var->upper_margin; + lower_margin = var->lower_margin; + vsync_len = var->vsync_len; + if (var->vmode & FB_VMODE_INTERLACED) { + /* # lines in half frame */ + upper_margin = (upper_margin + 1) / 2; + lower_margin = (lower_margin + 1) / 2; + vsync_len = (vsync_len + 1) / 2; + } + } + if (pclock == &fext) + longoffset = 1; /* VIDEL doesn't synchronize on short offset */ + } + /* Is video bus bandwidth (32MB/s) too low for this resolution? */ + /* this is definitely wrong if bus clock != 32MHz */ + if (pclock->f / plen / 8 * bpp > 32000000L) + return -EINVAL; + + if (vsync_len < 1) + vsync_len = 1; + + /* include sync lengths in right/lower margin for all calculations */ + right_margin += hsync_len; + lower_margin += vsync_len; + + /* ! In all calculations of margins we use # of lines in half frame + * (which is a full frame in non-interlace mode), so we can switch + * between interlace and non-interlace without messing around + * with these. + */ + again: + /* Set base_offset 128 and video bus width */ + par->hw.falcon.vid_control = mon_type | f030_bus_width; + if (!longoffset) + par->hw.falcon.vid_control |= VCO_SHORTOFFS; /* base_offset 64 */ + if (var->sync & FB_SYNC_HOR_HIGH_ACT) + par->hw.falcon.vid_control |= VCO_HSYPOS; + if (var->sync & FB_SYNC_VERT_HIGH_ACT) + par->hw.falcon.vid_control |= VCO_VSYPOS; + /* Pixelclock */ + par->hw.falcon.vid_control |= pclock->control_mask; + /* External or internal clock */ + par->hw.falcon.sync = pclock->sync_mask | 0x2; + /* Pixellength and prescale */ + par->hw.falcon.vid_mode = (2/plen) << 2; + if (doubleline) + par->hw.falcon.vid_mode |= VMO_DOUBLE; + if (interlace) + par->hw.falcon.vid_mode |= VMO_INTER; + + /********************* + Horizontal timing: unit = [master clock cycles] + unit of hxx-registers: [master clock cycles * prescale] + Hxx-registers are 9-bit wide + + 1 line = ((hht + 2) * 2 * prescale) clock cycles + + graphic output = hdb & 0x200 ? + ((hht+2)*2 - hdb + hde) * prescale - hdboff + hdeoff: + ( hht + 2 - hdb + hde) * prescale - hdboff + hdeoff + (this must be a multiple of plen*128/bpp, on VGA pixels + to the right may be cut off with a bigger right margin) + + start of graphics relative to start of 1st halfline = hdb & 0x200 ? + (hdb - hht - 2) * prescale + hdboff : + hdb * prescale + hdboff + + end of graphics relative to start of 1st halfline = + (hde + hht + 2) * prescale + hdeoff + *********************/ + /* Calculate VIDEL registers */ + { + int hdb_off, hde_off, base_off; + int gstart, gend1, gend2, align; + + prescale = hxx_prescale(&par->hw.falcon); + base_off = par->hw.falcon.vid_control & VCO_SHORTOFFS ? 64 : 128; + + /* Offsets depend on video mode */ + /* Offsets are in clock cycles, divide by prescale to + * calculate hd[be]-registers + */ + if (par->hw.falcon.f_shift & 0x100) { + align = 1; + hde_off = 0; + hdb_off = (base_off + 16 * plen) + prescale; + } + else { + align = 128 / bpp; + hde_off = ((128 / bpp + 2) * plen); + if (par->hw.falcon.ste_mode) + hdb_off = (64 + base_off + (128 / bpp + 2) * plen) + prescale; + else + hdb_off = (base_off + (128 / bpp + 18) * plen) + prescale; + } + + gstart = (prescale/2 + plen * left_margin) / prescale; + /* gend1 is for hde (gend-gstart multiple of align), shifter's xres */ + gend1 = gstart + ((xres + align-1) / align)*align * plen / prescale; + /* gend2 is for hbb, visible xres (rest to gend1 is cut off by hblank) */ + gend2 = gstart + xres * plen / prescale; + par->HHT = plen * (left_margin + xres + right_margin) / + (2 * prescale) - 2; +/* par->HHT = (gend2 + plen * right_margin / prescale) / 2 - 2;*/ + + par->HDB = gstart - hdb_off/prescale; + par->HBE = gstart; + if (par->HDB < 0) par->HDB += par->HHT + 2 + 0x200; + par->HDE = gend1 - par->HHT - 2 - hde_off/prescale; + par->HBB = gend2 - par->HHT - 2; +#if 0 + /* One more Videl constraint: data fetch of two lines must not overlap */ + if (par->HDB & 0x200 && par->HDB & ~0x200 - par->HDE <= 5) { + /* if this happens increase margins, decrease hfreq. */ + } +#endif + if (hde_off % prescale) + par->HBB++; /* compensate for non matching hde and hbb */ + par->HSS = par->HHT + 2 - plen * hsync_len / prescale; + if (par->HSS < par->HBB) + par->HSS = par->HBB; + } + + /* check hor. frequency */ + hfreq = pclock->f / ((par->HHT+2)*prescale*2); + if (hfreq > hfmax && mon_type!=F_MON_VGA) { + /* ++guenther: ^^^^^^^^^^^^^^^^^^^ can't remember why I did this */ + /* Too high -> enlarge margin */ + left_margin += 1; + right_margin += 1; + goto again; + } + if (hfreq > hfmax || hfreq < hfmin) + return -EINVAL; + + /* Vxx-registers */ + /* All Vxx must be odd in non-interlace, since frame starts in the middle + * of the first displayed line! + * One frame consists of VFT+1 half lines. VFT+1 must be even in + * non-interlace, odd in interlace mode for synchronisation. + * Vxx-registers are 11-bit wide + */ + par->VBE = (upper_margin * 2 + 1); /* must begin on odd halfline */ + par->VDB = par->VBE; + par->VDE = yres; + if (!interlace) par->VDE <<= 1; + if (doubleline) par->VDE <<= 1; /* VDE now half lines per (half-)frame */ + par->VDE += par->VDB; + par->VBB = par->VDE; + par->VFT = par->VBB + (lower_margin * 2 - 1) - 1; + par->VSS = par->VFT+1 - (vsync_len * 2 - 1); + /* vbb,vss,vft must be even in interlace mode */ + if (interlace) { + par->VBB++; + par->VSS++; + par->VFT++; + } + + /* V-frequency check, hope I didn't create any loop here. */ + /* Interlace and doubleline are mutually exclusive. */ + vfreq = (hfreq * 2) / (par->VFT + 1); + if (vfreq > vfmax && !doubleline && !interlace) { + /* Too high -> try again with doubleline */ + doubleline = 1; + goto again; + } + else if (vfreq < vfmin && !interlace && !doubleline) { + /* Too low -> try again with interlace */ + interlace = 1; + goto again; + } + else if (vfreq < vfmin && doubleline) { + /* Doubleline too low -> clear doubleline and enlarge margins */ + int lines; + doubleline = 0; + for (lines=0; (hfreq*2)/(par->VFT+1+4*lines-2*yres)>vfmax; lines++) + ; + upper_margin += lines; + lower_margin += lines; + goto again; + } + else if (vfreq > vfmax && interlace) { + /* Interlace, too high -> enlarge margins */ + int lines; + for (lines=0; (hfreq*2)/(par->VFT+1+4*lines)>vfmax; lines++) + ; + upper_margin += lines; + lower_margin += lines; + goto again; + } + else if (vfreq < vfmin || vfreq > vfmax) + return -EINVAL; + + set_screen_base: + linelen = xres_virtual * bpp / 8; + if ((var->yoffset + yres)*linelen > screen_len && screen_len) + return -EINVAL; + if (var->yres_virtual * linelen > screen_len && screen_len) + return -EINVAL; + if (var->yres * linelen > screen_len && screen_len) + return -EINVAL; + par->vyres = yres_virtual; + par->screen_base = screen_base + var->yoffset * linelen; + par->hw.falcon.xoffset = 0; + + return 0; +} + +static int falcon_encode_var( struct fb_var_screeninfo *var, + struct atari_fb_par *par ) +{ +/* !!! only for VGA !!! */ + int linelen, i; + int prescale, plen; + int hdb_off, hde_off, base_off; + struct falcon_hw *hw = &par->hw.falcon; + + /* possible frequencies: 25.175 or 32MHz */ + var->pixclock = hw->sync & 0x1 ? fext.t : + hw->vid_control & VCO_CLOCK25 ? f25.t : f32.t; + + var->height=-1; + var->width=-1; + + var->sync=0; + if (hw->vid_control & VCO_HSYPOS) + var->sync |= FB_SYNC_HOR_HIGH_ACT; + if (hw->vid_control & VCO_VSYPOS) + var->sync |= FB_SYNC_VERT_HIGH_ACT; + + var->vmode = FB_VMODE_NONINTERLACED; + if (hw->vid_mode & VMO_INTER) + var->vmode |= FB_VMODE_INTERLACED; + if (hw->vid_mode & VMO_DOUBLE) + var->vmode |= FB_VMODE_DOUBLE; + + /* visible y resolution: + * Graphics display starts at line VDB and ends at line + * VDE. If interlace mode off unit of VC-registers is + * half lines, else lines. + */ + var->yres = hw->vde - hw->vdb; + if (!(var->vmode & FB_VMODE_INTERLACED)) + var->yres >>= 1; + if (var->vmode & FB_VMODE_DOUBLE) + var->yres >>= 1; + + /* to get bpp, we must examine f_shift and st_shift. + * f_shift is valid if any of bits no. 10, 8 or 4 + * is set. Priority in f_shift is: 10 ">" 8 ">" 4, i.e. + * if bit 10 set then bit 8 and bit 4 don't care... + * If all these bits are 0 get display depth from st_shift + * (as for ST and STE) + */ + if (hw->f_shift & 0x400) /* 2 colors */ + var->bits_per_pixel = 1; + else if (hw->f_shift & 0x100) /* hicolor */ + var->bits_per_pixel = 16; + else if (hw->f_shift & 0x010) /* 8 bitplanes */ + var->bits_per_pixel = 8; + else if (hw->st_shift == 0) + var->bits_per_pixel = 4; + else if (hw->st_shift == 0x100) + var->bits_per_pixel = 2; + else /* if (hw->st_shift == 0x200) */ + var->bits_per_pixel = 1; + + var->xres = hw->line_width * 16 / var->bits_per_pixel; + var->xres_virtual = var->xres + hw->line_offset * 16 / var->bits_per_pixel; + if (hw->xoffset) + var->xres_virtual += 16; + + if (var->bits_per_pixel == 16) { + var->red.offset=11; + var->red.length=5; + var->red.msb_right=0; + var->green.offset=5; + var->green.length=6; + var->green.msb_right=0; + var->blue.offset=0; + var->blue.length=5; + var->blue.msb_right=0; + } + else { + var->red.offset=0; + var->red.length = hw->ste_mode ? 4 : 6; + var->red.msb_right=0; + var->grayscale=0; + var->blue=var->green=var->red; + } + var->transp.offset=0; + var->transp.length=0; + var->transp.msb_right=0; + + linelen = var->xres_virtual * var->bits_per_pixel / 8; + if (screen_len) + if (par->vyres) + var->yres_virtual = par->vyres; + else + var->yres_virtual=screen_len/linelen; + else { + if (hwscroll < 0) + var->yres_virtual = 2 * var->yres; + else + var->yres_virtual=var->yres+hwscroll * 16; + } + var->xoffset=0; /* TODO change this */ + + /* hdX-offsets */ + prescale = hxx_prescale(hw); + plen = 4 >> (hw->vid_mode >> 2 & 0x3); + base_off = hw->vid_control & VCO_SHORTOFFS ? 64 : 128; + if (hw->f_shift & 0x100) { + hde_off = 0; + hdb_off = (base_off + 16 * plen) + prescale; + } + else { + hde_off = ((128 / var->bits_per_pixel + 2) * plen); + if (hw->ste_mode) + hdb_off = (64 + base_off + (128 / var->bits_per_pixel + 2) * plen) + + prescale; + else + hdb_off = (base_off + (128 / var->bits_per_pixel + 18) * plen) + + prescale; + } + + /* Right margin includes hsync */ + var->left_margin = hdb_off + prescale * ((hw->hdb & 0x1ff) - + (hw->hdb & 0x200 ? 2+hw->hht : 0)); + if (hw->ste_mode || mon_type!=F_MON_VGA) + var->right_margin = prescale * (hw->hht + 2 - hw->hde) - hde_off; + else + /* cant use this in ste_mode, because hbb is +1 off */ + var->right_margin = prescale * (hw->hht + 2 - hw->hbb); + var->hsync_len = prescale * (hw->hht + 2 - hw->hss); + + /* Lower margin includes vsync */ + var->upper_margin = hw->vdb / 2 ; /* round down to full lines */ + var->lower_margin = (hw->vft+1 - hw->vde + 1) / 2; /* round up */ + var->vsync_len = (hw->vft+1 - hw->vss + 1) / 2; /* round up */ + if (var->vmode & FB_VMODE_INTERLACED) { + var->upper_margin *= 2; + var->lower_margin *= 2; + var->vsync_len *= 2; + } + + var->pixclock *= plen; + var->left_margin /= plen; + var->right_margin /= plen; + var->hsync_len /= plen; + + var->right_margin -= var->hsync_len; + var->lower_margin -= var->vsync_len; + + if (screen_base) + var->yoffset=(par->screen_base - screen_base)/linelen; + else + var->yoffset=0; + var->nonstd=0; /* what is this for? */ + var->activate=0; + for (i=0; ireserved); i++) + var->reserved[i]=0; + return 0; +} + + +static int f_change_mode = 0; +static struct falcon_hw f_new_mode; +static int f_pan_display = 0; + +static void falcon_get_par( struct atari_fb_par *par ) +{ + unsigned long addr; + struct falcon_hw *hw = &par->hw.falcon; + + hw->line_width = shifter_f030.scn_width; + hw->line_offset = shifter_f030.off_next; + hw->st_shift = videl.st_shift & 0x300; + hw->f_shift = videl.f_shift; + hw->vid_control = videl.control; + hw->vid_mode = videl.mode; + hw->sync = shifter.syncmode & 0x1; + hw->xoffset = videl.xoffset & 0xf; + hw->hht = videl.hht; + hw->hbb = videl.hbb; + hw->hbe = videl.hbe; + hw->hdb = videl.hdb; + hw->hde = videl.hde; + hw->hss = videl.hss; + hw->vft = videl.vft; + hw->vbb = videl.vbb; + hw->vbe = videl.vbe; + hw->vdb = videl.vdb; + hw->vde = videl.vde; + hw->vss = videl.vss; + + addr = (shifter.bas_hi & 0xff) << 16 | + (shifter.bas_md & 0xff) << 8 | + (shifter.bas_lo & 0xff); + par->screen_base = PTOV(addr); + + /* derived parameters */ + hw->ste_mode = (hw->f_shift & 0x510)==0 && hw->st_shift==0x100; + hw->mono = (hw->f_shift & 0x400) || + ((hw->f_shift & 0x510)==0 && hw->st_shift==0x200); +} + +static void falcon_set_par( struct atari_fb_par *par ) +{ + f_change_mode = 0; + + /* only set screen_base if really necessary */ + if (current_par.screen_base != par->screen_base) + fbhw->set_screen_base(par->screen_base); + + /* Don't touch any other registers if we keep the default resolution */ + if (DontCalcRes) + return; + + /* Tell vbl-handler to change video mode. + * We change modes only on next VBL, to avoid desynchronisation + * (a shift to the right and wrap around by a random number of pixels + * in all monochrome modes). + * This seems to work on my Falcon. + */ + f_new_mode = par->hw.falcon; + f_change_mode = 1; +} + + +static void falcon_vbl_switcher( int irq, struct pt_regs *fp, void *dummy ) +{ + struct falcon_hw *hw = &f_new_mode; + + if (f_change_mode) { + f_change_mode = 0; + + if (hw->sync & 0x1) { + /* Enable external pixelclock. This code only for ScreenWonder */ + *(volatile unsigned short*)0xffff9202 = 0xffbf; + } + else { + /* Turn off external clocks. Read sets all output bits to 1. */ + *(volatile unsigned short*)0xffff9202; + } + shifter.syncmode = hw->sync; + + videl.hht = hw->hht; + videl.hbb = hw->hbb; + videl.hbe = hw->hbe; + videl.hdb = hw->hdb; + videl.hde = hw->hde; + videl.hss = hw->hss; + videl.vft = hw->vft; + videl.vbb = hw->vbb; + videl.vbe = hw->vbe; + videl.vdb = hw->vdb; + videl.vde = hw->vde; + videl.vss = hw->vss; + + /*f030_sreg[2] = 0;*/ + + videl.f_shift = 0; /* write enables Falcon palette, 0: 4 planes */ + if (hw->ste_mode) { + videl.st_shift = hw->st_shift; /* write enables STE palette */ + } + else { + /* IMPORTANT: + * set st_shift 0, so we can tell the screen-depth if f_shift==0. + * Writing 0 to f_shift enables 4 plane Falcon mode but + * doesn't set st_shift. st_shift!=0 (!=4planes) is impossible + * with Falcon palette. + */ + videl.st_shift = 0; + /* now back to Falcon palette mode */ + videl.f_shift = hw->f_shift; + } + /* writing to st_shift changed scn_width and vid_mode */ + videl.xoffset = hw->xoffset; + shifter_f030.scn_width = hw->line_width; + shifter_f030.off_next = hw->line_offset; + videl.control = hw->vid_control; + videl.mode = hw->vid_mode; + } + if (f_pan_display) { + f_pan_display = 0; + videl.xoffset = current_par.hw.falcon.xoffset; + shifter_f030.off_next = current_par.hw.falcon.line_offset; + } +} + + +static int falcon_pan_display( struct fb_var_screeninfo *var, + struct atari_fb_par *par ) +{ + int xoffset; + + if (disp[currcon].var.bits_per_pixel == 1) + var->xoffset = up(var->xoffset, 32); + par->hw.falcon.xoffset = var->xoffset & 15; + par->hw.falcon.line_offset = disp[currcon].var.bits_per_pixel * + (disp[currcon].var.xres_virtual - disp[currcon].var.xres) / 16; + if (par->hw.falcon.xoffset) + par->hw.falcon.line_offset -= disp[currcon].var.bits_per_pixel; + xoffset = var->xoffset - par->hw.falcon.xoffset; + + par->screen_base + = screen_base + (var->yoffset * disp[currcon].var.xres_virtual + + xoffset) * disp[currcon].var.bits_per_pixel / 8; + if (fbhw->set_screen_base) + fbhw->set_screen_base (par->screen_base); + else + return -EINVAL; /* shouldn't happen */ + f_pan_display = 1; + return 0; +} + + +static int falcon_getcolreg( unsigned regno, unsigned *red, + unsigned *green, unsigned *blue, + unsigned *transp ) +{ unsigned long col; + + if (regno > 255) + return 1; + /* This works in STE-mode (with 4bit/color) since f030_col-registers + * hold up to 6bit/color. + * Even with hicolor r/g/b=5/6/5 bit! + */ + col = f030_col[regno]; + *red = (col >> 26) & 0x3f; + *green = (col >> 18) & 0x3f; + *blue = (col >> 2) & 0x3f; + *transp = 0; + return 0; +} + + +static int falcon_setcolreg( unsigned regno, unsigned red, + unsigned green, unsigned blue, + unsigned transp ) +{ + if (regno > 255) + return 1; + f030_col[regno] = (red << 26) | (green << 18) | (blue << 2); + if (regno < 16) { + shifter_tt.color_reg[regno] = + (((red & 0xe) >> 1) | ((red & 1) << 3) << 8) | + (((green & 0xe) >> 1) | ((green & 1) << 3) << 4) | + ((blue & 0xe) >> 1) | ((blue & 1) << 3); + packed16_cmap[regno] = (red << 11) | (green << 5) | blue; + } + return 0; +} + + +static int falcon_blank( int blank_mode ) +{ +/* ++guenther: we can switch off graphics by changing VDB and VDE, + * so VIDEL doesn't hog the bus while saving. + * (this affects usleep()). + */ + if (mon_type == F_MON_SM) /* this doesn't work on SM124 */ + return 1; + if (blank_mode) { + /* disable graphics output (this speeds up the CPU) ... */ + videl.vdb = current_par.VFT + 1; + /* ... and blank all lines */ + videl.hbe = current_par.HHT + 2; + /* VESA suspend mode, switch off HSYNC */ + if (pwrsave && mon_type == F_MON_VGA) + videl.hss = current_par.HHT + 2; + } + else { + videl.vdb = current_par.VDB; + videl.hbe = current_par.HBE; + videl.hss = current_par.HSS; + } + return 0; +} + + +static int falcon_detect( void ) +{ + struct atari_fb_par par; + unsigned char fhw; + + /* Determine connected monitor and set monitor parameters */ + fhw = *(unsigned char*)0xffff8006; + mon_type = fhw >> 6 & 0x3; + /* bit 1 of fhw: 1=32 bit ram bus, 0=16 bit */ + f030_bus_width = fhw << 6 & 0x80; + switch (mon_type) { + case F_MON_SM: + vfmin = 70; + vfmax = 72; + hfmin = 35713; + hfmax = 35715; + break; + case F_MON_SC: + case F_MON_TV: + vfmin = 50; + vfmax = 60; + hfmin = 15624; + hfmax = 15626; + break; + } + /* initialize hsync-len */ + f25.hsync = h_syncs[mon_type] / f25.t; + f32.hsync = h_syncs[mon_type] / f32.t; + if (fext.t) + fext.hsync = h_syncs[mon_type] / fext.t; + + falcon_get_par(&par); + falcon_encode_var(&atari_fb_predefined[0], &par); + + /* Detectet mode is always the "autodetect" slot */ + return 1; +} + +#endif /* ATAFB_FALCON */ + +/* ------------------- ST(E) specific functions ---------------------- */ + +#ifdef ATAFB_STE + +static int stste_encode_fix( struct fb_fix_screeninfo *fix, + struct atari_fb_par *par ) + +{ + int mode, i; + + strcpy(fix->id,"Atari Builtin"); + fix->smem_start=real_screen_base; + fix->smem_len=screen_len; + fix->type=FB_TYPE_INTERLEAVED_PLANES; + fix->type_aux=2; + fix->visual=FB_VISUAL_PSEUDOCOLOR; + mode = par->hw.st.mode & 3; + if (mode == ST_HIGH) { + fix->type=FB_TYPE_PACKED_PIXELS; + fix->type_aux=0; + fix->visual=FB_VISUAL_MONO10; + } + fix->xpanstep = 0; + if (ATARIHW_PRESENT(EXTD_SHIFTER)) + fix->ypanstep = 1; + else + fix->ypanstep = 0; + fix->ywrapstep = 0; + for (i=0; ireserved); i++) + fix->reserved[i]=0; + return 0; +} + + +static int stste_decode_var( struct fb_var_screeninfo *var, + struct atari_fb_par *par ) +{ + int xres=var->xres; + int yres=var->yres; + int bpp=var->bits_per_pixel; + int linelen; + + if (mono_moni) { + if (bpp > 1 || xres > sttt_xres || yres > st_yres) + return -EINVAL; + par->hw.st.mode=ST_HIGH; + xres=sttt_xres; + yres=st_yres; + bpp=1; + } else { + if (bpp > 4 || xres > sttt_xres || yres > st_yres) + return -EINVAL; + if (bpp > 2) { + if (xres > sttt_xres/2 || yres > st_yres/2) + return -EINVAL; + par->hw.st.mode=ST_LOW; + xres=sttt_xres/2; + yres=st_yres/2; + bpp=4; + } + else if (bpp > 1) { + if (xres > sttt_xres || yres > st_yres/2) + return -EINVAL; + par->hw.st.mode=ST_MID; + xres=sttt_xres; + yres=st_yres/2; + bpp=2; + } + else + return -EINVAL; + } + if (var->sync & FB_SYNC_EXT) + par->hw.st.sync=(par->hw.st.sync & ~1) | 1; + else + par->hw.st.sync=(par->hw.st.sync & ~1); + linelen=xres*bpp/8; + if ((var->yoffset + yres)*linelen > screen_len && screen_len) + return -EINVAL; + par->screen_base=screen_base+ var->yoffset*linelen; + return 0; +} + +static int stste_encode_var( struct fb_var_screeninfo *var, + struct atari_fb_par *par ) +{ + int linelen, i; + var->red.offset=0; + var->red.length = ATARIHW_PRESENT(EXTD_SHIFTER) ? 4 : 3; + var->red.msb_right=0; + var->grayscale=0; + + var->pixclock=31041; + var->left_margin=120; /* these are incorrect */ + var->right_margin=100; + var->upper_margin=8; + var->lower_margin=16; + var->hsync_len=140; + var->vsync_len=30; + + var->height=-1; + var->width=-1; + + if (!(par->hw.st.sync & 1)) + var->sync=0; + else + var->sync=FB_SYNC_EXT; + + switch (par->hw.st.mode & 3) { + case ST_LOW: + var->xres=sttt_xres/2; + var->yres=st_yres/2; + var->bits_per_pixel=4; + break; + case ST_MID: + var->xres=sttt_xres; + var->yres=st_yres/2; + var->bits_per_pixel=2; + break; + case ST_HIGH: + var->xres=sttt_xres; + var->yres=st_yres; + var->bits_per_pixel=1; + break; + } + var->blue=var->green=var->red; + var->transp.offset=0; + var->transp.length=0; + var->transp.msb_right=0; + var->xres_virtual=sttt_xres_virtual; + linelen=var->xres_virtual * var->bits_per_pixel / 8; + ovsc_addlen=linelen*(sttt_yres_virtual - st_yres); + + if (! use_hwscroll) + var->yres_virtual=var->yres; + else if (screen_len) + var->yres_virtual=screen_len/linelen; + else { + if (hwscroll < 0) + var->yres_virtual = 2 * var->yres; + else + var->yres_virtual=var->yres+hwscroll * 16; + } + var->xoffset=0; + if (screen_base) + var->yoffset=(par->screen_base - screen_base)/linelen; + else + var->yoffset=0; + var->nonstd=0; + var->activate=0; + var->vmode=FB_VMODE_NONINTERLACED; + for (i=0; ireserved); i++) + var->reserved[i]=0; + return 0; +} + + +static void stste_get_par( struct atari_fb_par *par ) +{ + unsigned long addr; + par->hw.st.mode=shifter_tt.st_shiftmode; + par->hw.st.sync=shifter.syncmode; + addr = ((shifter.bas_hi & 0xff) << 16) | + ((shifter.bas_md & 0xff) << 8); + if (ATARIHW_PRESENT(EXTD_SHIFTER)) + addr |= (shifter.bas_lo & 0xff); + par->screen_base = PTOV(addr); +} + +static void stste_set_par( struct atari_fb_par *par ) +{ + shifter_tt.st_shiftmode=par->hw.st.mode; + shifter.syncmode=par->hw.st.sync; + /* only set screen_base if really necessary */ + if (current_par.screen_base != par->screen_base) + fbhw->set_screen_base(par->screen_base); +} + + +static int stste_getcolreg( unsigned regno, unsigned *red, + unsigned *green, unsigned *blue, + unsigned *transp ) +{ unsigned col; + + if (regno > 15) + return 1; + col = shifter_tt.color_reg[regno]; + if (ATARIHW_PRESENT(EXTD_SHIFTER)) { + *red = ((col >> 7) & 0xe) | ((col >> 11) & 1); + *green = ((col >> 3) & 0xe) | ((col >> 7) & 1); + *blue = ((col << 1) & 0xe) | ((col >> 3) & 1); + } + else { + *red = (col >> 8) & 0x7; + *green = (col >> 4) & 0x7; + *blue = col & 0x7; + } + *transp = 0; + return 0; +} + + +static int stste_setcolreg( unsigned regno, unsigned red, + unsigned green, unsigned blue, + unsigned transp ) +{ + if (regno > 15) + return 1; + if (ATARIHW_PRESENT(EXTD_SHIFTER)) + shifter_tt.color_reg[regno] = + (((red & 0xe) >> 1) | ((red & 1) << 3) << 8) | + (((green & 0xe) >> 1) | ((green & 1) << 3) << 4) | + ((blue & 0xe) >> 1) | ((blue & 1) << 3); + else + shifter_tt.color_reg[regno] = + ((red & 0x7) << 8) | + ((green & 0x7) << 4) | + (blue & 0x7); + return 0; +} + + +static int stste_detect( void ) + +{ struct atari_fb_par par; + + /* Determine the connected monitor: The DMA sound must be + * disabled before reading the MFP GPIP, because the Sound + * Done Signal and the Monochrome Detect are XORed together! + */ + if (ATARIHW_PRESENT(PCM_8BIT)) { + tt_dmasnd.ctrl = DMASND_CTRL_OFF; + udelay(20); /* wait a while for things to settle down */ + } + mono_moni = (mfp.par_dt_reg & 0x80) == 0; + + stste_get_par(&par); + stste_encode_var(&atari_fb_predefined[0], &par); + + if (!ATARIHW_PRESENT(EXTD_SHIFTER)) + use_hwscroll = 0; + return 1; +} + +static void stste_set_screen_base(unsigned long s_base) +{ + unsigned long addr; + addr= VTOP(s_base); + /* Setup Screen Memory */ + shifter.bas_hi=(unsigned char) ((addr & 0xff0000) >> 16); + shifter.bas_md=(unsigned char) ((addr & 0x00ff00) >> 8); + if (ATARIHW_PRESENT(EXTD_SHIFTER)) + shifter.bas_lo=(unsigned char) (addr & 0x0000ff); +} + +#endif /* ATAFB_STE */ + +/* Switching the screen size should be done during vsync, otherwise + * the margins may get messed up. This is a well known problem of + * the ST's video system. + * + * Unfortunately there is hardly any way to find the vsync, as the + * vertical blank interrupt is no longer in time on machines with + * overscan type modifications. + * + * We can, however, use Timer B to safely detect the black shoulder, + * but then we've got to guess an appropriate delay to find the vsync. + * This might not work on every machine. + * + * martin_rogge @ ki.maus.de, 8th Aug 1995 + */ + +#define LINE_DELAY (mono_moni ? 30 : 70) +#define SYNC_DELAY (mono_moni ? 1500 : 2000) + +/* SWITCH_ACIA may be used for Falcon (ScreenBlaster III internal!) */ +static void st_ovsc_switch(int switchmode) +{ + unsigned long flags; + register unsigned char old, new; + + if ((switchmode & (SWITCH_ACIA | SWITCH_SND6 | SWITCH_SND7)) == 0) + return; + save_flags(flags); + cli(); + + mfp.tim_ct_b = 0x10; + mfp.active_edge |= 8; + mfp.tim_ct_b = 0; + mfp.tim_dt_b = 0xf0; + mfp.tim_ct_b = 8; + while (mfp.tim_dt_b > 1) /* TOS does it this way, don't ask why */ + ; + new = mfp.tim_dt_b; + do { + udelay(LINE_DELAY); + old = new; + new = mfp.tim_dt_b; + } while (old != new); + mfp.tim_ct_b = 0x10; + udelay(SYNC_DELAY); + + if (switchmode == SWITCH_ACIA) + acia.key_ctrl = (ACIA_DIV64|ACIA_D8N1S|ACIA_RHTID|ACIA_RIE); + else { + sound_ym.rd_data_reg_sel = 14; + sound_ym.wd_data = sound_ym.rd_data_reg_sel | switchmode; + } + restore_flags(flags); +} + +/* ------------------- External Video ---------------------- */ + +#ifdef ATAFB_EXT + +static int ext_encode_fix( struct fb_fix_screeninfo *fix, + struct atari_fb_par *par ) + +{ + int i; + + strcpy(fix->id,"Unknown Extern"); + fix->smem_start=external_addr; + fix->smem_len=(external_len + PAGE_SIZE -1) & PAGE_MASK; + if (external_depth == 1) { + fix->type = FB_TYPE_PACKED_PIXELS; + /* The letters 'n' and 'i' in the "atavideo=external:" stand + * for "normal" and "inverted", rsp., in the monochrome case */ + fix->visual = + (external_pmode == FB_TYPE_INTERLEAVED_PLANES || + external_pmode == FB_TYPE_PACKED_PIXELS) ? + FB_VISUAL_MONO10 : + FB_VISUAL_MONO01; + } + else { + switch (external_pmode) { + /* All visuals are STATIC, because we don't know how to change + * colors :-( + */ + case -1: /* truecolor */ + fix->type=FB_TYPE_PACKED_PIXELS; + fix->visual=FB_VISUAL_TRUECOLOR; + break; + case FB_TYPE_PACKED_PIXELS: + fix->type=FB_TYPE_PACKED_PIXELS; + fix->visual=FB_VISUAL_STATIC_PSEUDOCOLOR; + break; + case FB_TYPE_PLANES: + fix->type=FB_TYPE_PLANES; + fix->visual=FB_VISUAL_STATIC_PSEUDOCOLOR; + break; + case FB_TYPE_INTERLEAVED_PLANES: + fix->type=FB_TYPE_INTERLEAVED_PLANES; + fix->type_aux=2; + fix->visual=FB_VISUAL_STATIC_PSEUDOCOLOR; + break; + } + } + fix->xpanstep = 0; + fix->ypanstep = 0; + fix->ywrapstep = 0; + for (i=0; ireserved); i++) + fix->reserved[i]=0; + return 0; +} + + +static int ext_decode_var( struct fb_var_screeninfo *var, + struct atari_fb_par *par ) +{ + struct fb_var_screeninfo *myvar = &atari_fb_predefined[0]; + + if (var->bits_per_pixel > myvar->bits_per_pixel || + var->xres > myvar->xres || + var->yres > myvar->yres || + var->xoffset > 0 || + var->yoffset > 0) + return -EINVAL; + return 0; +} + + +static int ext_encode_var( struct fb_var_screeninfo *var, + struct atari_fb_par *par ) +{ + int i; + + var->red.offset=0; + var->red.length=(external_pmode == -1) ? external_depth/3 : + (external_vgaiobase ? external_bitspercol : 0); + var->red.msb_right=0; + var->grayscale=0; + + var->pixclock=31041; + var->left_margin=120; /* these are surely incorrect */ + var->right_margin=100; + var->upper_margin=8; + var->lower_margin=16; + var->hsync_len=140; + var->vsync_len=30; + + var->height=-1; + var->width=-1; + + var->sync=0; + + var->xres = external_xres; + var->yres = external_yres; + var->bits_per_pixel = external_depth; + + var->blue=var->green=var->red; + var->transp.offset=0; + var->transp.length=0; + var->transp.msb_right=0; + var->xres_virtual=var->xres; + var->yres_virtual=var->yres; + var->xoffset=0; + var->yoffset=0; + var->nonstd=0; + var->activate=0; + var->vmode=FB_VMODE_NONINTERLACED; + for (i=0; ireserved); i++) + var->reserved[i]=0; + return 0; +} + + +static void ext_get_par( struct atari_fb_par *par ) +{ + par->screen_base = external_addr; +} + +static void ext_set_par( struct atari_fb_par *par ) +{ +} + +#define OUTB(port,val) \ + *((unsigned volatile char *) ((port)+external_vgaiobase))=(val) +#define INB(port) \ + (*((unsigned volatile char *) ((port)+external_vgaiobase))) +#define DACDelay \ + do { \ + unsigned char tmp=INB(0x3da); \ + tmp=INB(0x3da); \ + } while (0) + +static int ext_getcolreg( unsigned regno, unsigned *red, + unsigned *green, unsigned *blue, + unsigned *transp ) + +{ unsigned char colmask = (1 << external_bitspercol) - 1; + + if (! external_vgaiobase) + return 1; + + switch (external_card_type) { + case IS_VGA: + OUTB(0x3c7, regno); + DACDelay; + *red=INB(0x3c9) & colmask; + DACDelay; + *green=INB(0x3c9) & colmask; + DACDelay; + *blue=INB(0x3c9) & colmask; + DACDelay; + return 0; + + case IS_MV300: + *red = MV300_color[regno].red; + *green = MV300_color[regno].green; + *blue = MV300_color[regno].blue; + *transp=0; + return 0; + + default: + return 1; + } +} + +static int ext_setcolreg( unsigned regno, unsigned red, + unsigned green, unsigned blue, + unsigned transp ) + +{ unsigned char colmask = (1 << external_bitspercol) - 1; + + if (! external_vgaiobase) + return 1; + + switch (external_card_type) { + case IS_VGA: + OUTB(0x3c8, regno); + DACDelay; + OUTB(0x3c9, red & colmask); + DACDelay; + OUTB(0x3c9, green & colmask); + DACDelay; + OUTB(0x3c9, blue & colmask); + DACDelay; + return 0; + + case IS_MV300: + MV300_color[regno].red = red; + MV300_color[regno].green = green; + MV300_color[regno].blue = blue; + OUTB((MV300_reg[regno] << 2)+1, red); + OUTB((MV300_reg[regno] << 2)+1, green); + OUTB((MV300_reg[regno] << 2)+1, blue); + return 0; + + default: + return 1; + } +} + + +static int ext_detect( void ) + +{ + struct fb_var_screeninfo *myvar = &atari_fb_predefined[0]; + struct atari_fb_par dummy_par; + + myvar->xres = external_xres; + myvar->yres = external_yres; + myvar->bits_per_pixel = external_depth; + ext_encode_var(myvar, &dummy_par); + return 1; +} + +#endif /* ATAFB_EXT */ + +/* ------ This is the same for most hardware types -------- */ + +static void set_screen_base(unsigned long s_base) +{ + unsigned long addr; + addr= VTOP(s_base); + /* Setup Screen Memory */ + shifter.bas_hi=(unsigned char) ((addr & 0xff0000) >> 16); + shifter.bas_md=(unsigned char) ((addr & 0x00ff00) >> 8); + shifter.bas_lo=(unsigned char) (addr & 0x0000ff); +} + + +static int pan_display( struct fb_var_screeninfo *var, + struct atari_fb_par *par ) +{ + if (var->xoffset) + return -EINVAL; + par->screen_base + = screen_base + (var->yoffset * disp[currcon].var.xres_virtual + * disp[currcon].var.bits_per_pixel / 8); + if (fbhw->set_screen_base) + fbhw->set_screen_base (par->screen_base); + else + return -EINVAL; + return 0; +} + + +/* ------------ Interfaces to hardware functions ------------ */ + + +#ifdef ATAFB_TT +struct fb_hwswitch tt_switch = { + tt_detect, tt_encode_fix, tt_decode_var, tt_encode_var, + tt_get_par, tt_set_par, tt_getcolreg, tt_setcolreg, + set_screen_base, NULL, pan_display +}; +#endif + +#ifdef ATAFB_FALCON +struct fb_hwswitch falcon_switch = { + falcon_detect, falcon_encode_fix, falcon_decode_var, falcon_encode_var, + falcon_get_par, falcon_set_par, falcon_getcolreg, + falcon_setcolreg, set_screen_base, falcon_blank, falcon_pan_display +}; +#endif + +#ifdef ATAFB_STE +struct fb_hwswitch st_switch = { + stste_detect, stste_encode_fix, stste_decode_var, stste_encode_var, + stste_get_par, stste_set_par, stste_getcolreg, stste_setcolreg, + stste_set_screen_base, NULL, pan_display +}; +#endif + +#ifdef ATAFB_EXT +struct fb_hwswitch ext_switch = { + ext_detect, ext_encode_fix, ext_decode_var, ext_encode_var, + ext_get_par, ext_set_par, ext_getcolreg, ext_setcolreg, NULL, NULL, NULL +}; +#endif + + + +static void atari_fb_get_par( struct atari_fb_par *par ) +{ + if (current_par_valid) { + *par=current_par; + } + else + fbhw->get_par(par); +} + + +static void atari_fb_set_par( struct atari_fb_par *par ) +{ + fbhw->set_par(par); + current_par=*par; + current_par_valid=1; +} + + + +/* =========================================================== */ +/* ============== Hardware Independant Functions ============= */ +/* =========================================================== */ + + +/* used for hardware scrolling */ + +static int +fb_update_var(int con) +{ + int off=disp[con].var.yoffset*disp[con].var.xres_virtual* + disp[con].var.bits_per_pixel>>3; + + current_par.screen_base=screen_base + off; + + if (fbhw->set_screen_base) + fbhw->set_screen_base(current_par.screen_base); + return 0; +} + +static int +do_fb_set_var(struct fb_var_screeninfo *var, int isactive) +{ + int err,activate; + struct atari_fb_par par; + if ((err=fbhw->decode_var(var, &par))) + return err; + activate=var->activate; + if (((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive) + atari_fb_set_par(&par); + fbhw->encode_var(var, &par); + var->activate=activate; + return 0; +} + +/* Functions for handling colormap */ + +/* there seems to be a bug in gcc 2.5.8 which inhibits using an other solution */ +/* I always get a sigsegv */ + +static short red16[]= + { 0x0000,0x0000,0x0000,0x0000,0xc000,0xc000,0xc000,0xc000, + 0x8000,0x0000,0x0000,0x0000,0xffff,0xffff,0xffff,0xffff}; +static short green16[]= + { 0x0000,0x0000,0xc000,0xc000,0x0000,0x0000,0xc000,0xc000, + 0x8000,0x0000,0xffff,0xffff,0x0000,0x0000,0xffff,0xffff}; +static short blue16[]= + { 0x0000,0xc000,0x0000,0xc000,0x0000,0xc000,0x0000,0xc000, + 0x8000,0xffff,0x0000,0xffff,0x0000,0xffff,0x0000,0xffff}; + +static short red4[]= + { 0x0000,0xc000,0x8000,0xffff}; +static short green4[]= + { 0x0000,0xc000,0x8000,0xffff}; +static short blue4[]= + { 0x0000,0xc000,0x8000,0xffff}; + +static short red2[]= + { 0x0000,0xffff}; +static short green2[]= + { 0x0000,0xffff}; +static short blue2[]= + { 0x0000,0xffff}; + +struct fb_cmap default_16_colors = { 0, 16, red16, green16, blue16, NULL }; +struct fb_cmap default_4_colors = { 0, 4, red4, green4, blue4, NULL }; +struct fb_cmap default_2_colors = { 0, 2, red2, green2, blue2, NULL }; + +static struct fb_cmap * +get_default_colormap(int bpp) +{ + if (bpp == 1) + return &default_2_colors; + if (bpp == 2) + return &default_4_colors; + return &default_16_colors; +} + +#define CNVT_TOHW(val,width) (((val) << (width)) + 0x7fff - (val)) >> 16 +#define CNVT_FROMHW(val,width) ((width)?((((val) << 16) - (val)) / ((1<<(width))-1)):0) + + +static int +do_fb_get_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var, int kspc) +{ + int i,start; + unsigned short *red,*green,*blue,*transp; + unsigned int hred,hgreen,hblue,htransp; + + red=cmap->red; + green=cmap->green; + blue=cmap->blue; + transp=cmap->transp; + start=cmap->start; + if (start < 0) + return EINVAL; + for (i=0 ; i < cmap->len ; i++) { + if (fbhw->getcolreg(start++, &hred, &hgreen, &hblue, &htransp)) + return 0; + hred=CNVT_FROMHW(hred,var->red.length); + hgreen=CNVT_FROMHW(hgreen,var->green.length); + hblue=CNVT_FROMHW(hblue,var->blue.length); + htransp=CNVT_FROMHW(htransp,var->transp.length); + if (kspc) { + *red=hred; + *green=hgreen; + *blue=hblue; + if (transp) *transp=htransp; + } + else { + put_fs_word(hred, red); + put_fs_word(hgreen, green); + put_fs_word(hblue, blue); + if (transp) put_fs_word(htransp, transp); + } + red++; + green++; + blue++; + if (transp) transp++; + } + return 0; +} + +static int +do_fb_set_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var, int kspc) +{ + int i,start; + unsigned short *red,*green,*blue,*transp; + unsigned int hred,hgreen,hblue,htransp; + + red=cmap->red; + green=cmap->green; + blue=cmap->blue; + transp=cmap->transp; + start=cmap->start; + + if (start < 0) + return -EINVAL; + for (i=0 ; i < cmap->len ; i++) { + if (kspc) { + hred=*red; + hgreen=*green; + hblue=*blue; + htransp=(transp) ? *transp : 0; + } + else { + hred=get_fs_word(red); + hgreen=get_fs_word(green); + hblue=get_fs_word(blue); + htransp=(transp)?get_fs_word(transp):0; + } + hred=CNVT_TOHW(hred,var->red.length); + hgreen=CNVT_TOHW(hgreen,var->green.length); + hblue=CNVT_TOHW(hblue,var->blue.length); + htransp=CNVT_TOHW(htransp,var->transp.length); + red++; + green++; + blue++; + if (transp) transp++; + if (fbhw->setcolreg(start++, hred, hgreen, hblue, htransp)) + return 0; + } + return 0; +} + +static void +do_install_cmap(int con) +{ + if (con != currcon) + return; + if (disp[con].cmap.len) + do_fb_set_cmap(&disp[con].cmap, &(disp[con].var), 1); + else + do_fb_set_cmap(get_default_colormap( + disp[con].var.bits_per_pixel), &(disp[con].var), 1); +} + +static void +memcpy_fs(int fsfromto, void *to, void *from, int len) +{ + switch (fsfromto) { + case 0: + memcpy(to,from,len); + return; + case 1: + memcpy_fromfs(to,from,len); + return; + case 2: + memcpy_tofs(to,from,len); + return; + } +} + +static void +copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto) +{ + int size; + int tooff=0, fromoff=0; + + if (to->start > from->start) + fromoff=to->start-from->start; + else + tooff=from->start-to->start; + size=to->len-tooff; + if (size > from->len-fromoff) + size=from->len-fromoff; + if (size < 0) + return; + size*=sizeof(unsigned short); + memcpy_fs(fsfromto, to->red+tooff, from->red+fromoff, size); + memcpy_fs(fsfromto, to->green+tooff, from->green+fromoff, size); + memcpy_fs(fsfromto, to->blue+tooff, from->blue+fromoff, size); + if (from->transp && to->transp) + memcpy_fs(fsfromto, to->transp+tooff, from->transp+fromoff, size); +} + +static int +alloc_cmap(struct fb_cmap *cmap,int len,int transp) +{ + int size=len*sizeof(unsigned short); + if (cmap->len != len) { + if (cmap->red) + kfree(cmap->red); + if (cmap->green) + kfree(cmap->green); + if (cmap->blue) + kfree(cmap->blue); + if (cmap->transp) + kfree(cmap->transp); + cmap->red=cmap->green=cmap->blue=cmap->transp=NULL; + cmap->len=0; + if (! len) + return 0; + if (! (cmap->red=kmalloc(size, GFP_ATOMIC))) + return -1; + if (! (cmap->green=kmalloc(size, GFP_ATOMIC))) + return -1; + if (! (cmap->blue=kmalloc(size, GFP_ATOMIC))) + return -1; + if (transp) { + if (! (cmap->transp=kmalloc(size, GFP_ATOMIC))) + return -1; + } + else + cmap->transp=NULL; + } + cmap->start=0; + cmap->len=len; + copy_cmap(get_default_colormap(len), cmap, 0); + return 0; +} + +static int +atari_fb_get_fix(struct fb_fix_screeninfo *fix, int con) +{ + struct atari_fb_par par; + if (con == -1) + atari_fb_get_par(&par); + else + fbhw->decode_var(&disp[con].var,&par); + return fbhw->encode_fix(fix, &par); +} + +static int +atari_fb_get_var(struct fb_var_screeninfo *var, int con) +{ + struct atari_fb_par par; + if (con == -1) { + atari_fb_get_par(&par); + fbhw->encode_var(var, &par); + } + else + *var=disp[con].var; + return 0; +} + +static void +atari_fb_set_disp(int con) +{ + struct fb_fix_screeninfo fix; + + atari_fb_get_fix(&fix, con); + if (con == -1) + con=0; + disp[con].screen_base = (u_char *)fix.smem_start; + disp[con].visual = fix.visual; + disp[con].type = fix.type; + disp[con].type_aux = fix.type_aux; + disp[con].ypanstep = fix.ypanstep; + disp[con].ywrapstep = fix.ywrapstep; + if (fix.visual != FB_VISUAL_PSEUDOCOLOR && + fix.visual != FB_VISUAL_DIRECTCOLOR) + disp[con].can_soft_blank = 0; + else + disp[con].can_soft_blank = 1; + disp[con].inverse = + (fix.visual == FB_VISUAL_MONO01 ? !inverse : inverse); +} + +static int +atari_fb_set_var(struct fb_var_screeninfo *var, int con) +{ + int err,oldxres,oldyres,oldbpp,oldxres_virtual,oldyoffset; + if ((err=do_fb_set_var(var, con==currcon))) + return err; + if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { + oldxres=disp[con].var.xres; + oldyres=disp[con].var.yres; + oldxres_virtual=disp[con].var.xres_virtual; + oldbpp=disp[con].var.bits_per_pixel; + oldyoffset=disp[con].var.yoffset; + disp[con].var=*var; + if (oldxres != var->xres || oldyres != var->yres + || oldxres_virtual != var->xres_virtual + || oldbpp != var->bits_per_pixel + || oldyoffset != var->yoffset) { + atari_fb_set_disp(con); + (*fb_info.changevar)(con); + alloc_cmap(&disp[con].cmap, 0, 0); + do_install_cmap(con); + } + } + var->activate=0; + return 0; +} + + + +static int +atari_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con) +{ + if (con == currcon) /* current console ? */ + return do_fb_get_cmap(cmap, &(disp[con].var), kspc); + else + if (disp[con].cmap.len) /* non default colormap ? */ + copy_cmap(&disp[con].cmap, cmap, kspc ? 0 : 2); + else + copy_cmap(get_default_colormap( + disp[con].var.bits_per_pixel), cmap, kspc ? 0 : 2); + return 0; +} + +static int +atari_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con) +{ + int err; + if (! disp[con].cmap.len) { /* no colormap allocated ? */ + if ((err = alloc_cmap(&disp[con].cmap, + 1 << disp[con].var.bits_per_pixel, 0))) + return err; + } + if (con == currcon) /* current console ? */ + return do_fb_set_cmap(cmap, &(disp[con].var), kspc); + else + copy_cmap(cmap, &disp[con].cmap, kspc ? 0 : 1); + return 0; +} + +static int +atari_fb_pan_display(struct fb_var_screeninfo *var, int con) +{ + int xoffset = var->xoffset; + int yoffset = var->yoffset; + int err; + + if ( xoffset < 0 || xoffset + disp[con].var.xres > disp[con].var.xres_virtual + || yoffset < 0 || yoffset + disp[con].var.yres > disp[con].var.yres_virtual) + return -EINVAL; + + if (con == currcon) { + if (fbhw->pan_display) { + if ((err = fbhw->pan_display(var, ¤t_par))) + return err; + } + else + return -EINVAL; + } + disp[con].var.xoffset = var->xoffset; + disp[con].var.yoffset = var->yoffset; + return 0; +} + +static int +atari_fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg, int con) +{ + int i; + + switch (cmd) { +#ifdef FBCMD_GET_CURRENTPAR + case FBCMD_GET_CURRENTPAR: + if ((i = verify_area(VERIFY_WRITE, (void *)arg, + sizeof(struct atari_fb_par)))) + return i; + memcpy_tofs((void *)arg, (void *)¤t_par, + sizeof(struct atari_fb_par)); + return 0; +#endif +#ifdef FBCMD_SET_CURRENTPAR + case FBCMD_SET_CURRENTPAR: + if ((i = verify_area(VERIFY_READ, (void *)arg, + sizeof(struct atari_fb_par)))) + return i; + memcpy_fromfs((void *)¤t_par, (void *)arg, + sizeof(struct atari_fb_par)); + atari_fb_set_par(¤t_par); + return 0; +#endif + } + return -EINVAL; +} + +static struct fb_ops atari_fb_ops = { + atari_fb_get_fix, atari_fb_get_var, atari_fb_set_var, atari_fb_get_cmap, + atari_fb_set_cmap, atari_fb_pan_display, atari_fb_ioctl +}; + +static void +check_default_par( int detected_mode ) +{ + char default_name[10]; + int i; + struct fb_var_screeninfo var; + unsigned long min_mem; + + /* First try the user supplied mode */ + if (default_par) { + var=atari_fb_predefined[default_par-1]; + var.activate = FB_ACTIVATE_TEST; + if (do_fb_set_var(&var,1)) + default_par=0; /* failed */ + } + /* Next is the autodetected one */ + if (! default_par) { + var=atari_fb_predefined[detected_mode-1]; /* autodetect */ + var.activate = FB_ACTIVATE_TEST; + if (!do_fb_set_var(&var,1)) + default_par=detected_mode; + } + /* If that also failed, try some default modes... */ + if (! default_par) { + /* try default1, default2... */ + for (i=1 ; i < 10 ; i++) { + sprintf(default_name,"default%d",i); + default_par=get_video_mode(default_name); + if (! default_par) + panic("can't set default video mode\n"); + var=atari_fb_predefined[default_par-1]; + var.activate = FB_ACTIVATE_TEST; + if (! do_fb_set_var(&var,1)) + break; /* ok */ + } + } + min_mem=var.xres_virtual * var.yres_virtual * var.bits_per_pixel/8; + if (default_mem_req < min_mem) + default_mem_req=min_mem; +} + +static int +atafb_switch(int con) +{ + /* Do we have to save the colormap ? */ + if (disp[currcon].cmap.len) + do_fb_get_cmap(&disp[currcon].cmap, &(disp[currcon].var), 1); + do_fb_set_var(&disp[con].var,1); + currcon=con; + /* Install new colormap */ + do_install_cmap(con); + return 0; +} + +static void +atafb_blank(int blank) +{ + unsigned short black[16]; + struct fb_cmap cmap; + if (fbhw->blank && !fbhw->blank(blank)) + return; + if (blank) { + memset(black, 0, 16*sizeof(unsigned short)); + cmap.red=black; + cmap.green=black; + cmap.blue=black; + cmap.transp=NULL; + cmap.start=0; + cmap.len=16; + do_fb_set_cmap(&cmap, &(disp[currcon].var), 1); + } + else + do_install_cmap(currcon); +} + +struct fb_info * +atari_fb_init(long *mem_start) +{ + int err; + int pad; + int detected_mode; + unsigned long mem_req; + struct fb_var_screeninfo *var; + + err=register_framebuffer("Atari Builtin", &node, &atari_fb_ops, + num_atari_fb_predefined, atari_fb_predefined); + if (err < 0) + panic ("Cannot register frame buffer\n"); + do { +#ifdef ATAFB_EXT + if (external_addr) { + fbhw = &ext_switch; + break; + } +#endif +#ifdef ATAFB_TT + if (ATARIHW_PRESENT(TT_SHIFTER)) { + fbhw = &tt_switch; + break; + } +#endif +#ifdef ATAFB_FALCON + if (ATARIHW_PRESENT(VIDEL_SHIFTER)) { + fbhw = &falcon_switch; + add_isr(IRQ_AUTO_4, falcon_vbl_switcher, IRQ_TYPE_PRIO, NULL, + "framebuffer/modeswitch"); + break; + } +#endif +#ifdef ATAFB_STE + if (ATARIHW_PRESENT(STND_SHIFTER) || + ATARIHW_PRESENT(EXTD_SHIFTER)) { + fbhw = &st_switch; + break; + } + fbhw = &st_switch; + printk("Cannot determine video hardware; defaulting to ST(e)\n"); +#else /* ATAFB_STE */ + /* no default driver included */ + /* Nobody will ever see this message :-) */ + panic("Cannot initialize video hardware\n"); +#endif + } while (0); + detected_mode = fbhw->detect(); + check_default_par(detected_mode); +#ifdef ATAFB_EXT + if (!external_addr) { +#endif /* ATAFB_EXT */ + mem_req = default_mem_req + ovsc_offset + + ovsc_addlen; + mem_req = ((mem_req + PAGE_SIZE - 1) & PAGE_MASK) + PAGE_SIZE; + screen_base = (unsigned long) atari_stram_alloc(mem_req, mem_start); + memset((char *) screen_base, 0, mem_req); + pad = ((screen_base + PAGE_SIZE-1) & PAGE_MASK) - screen_base; + screen_base+=pad; + real_screen_base=screen_base+ovsc_offset; + screen_len = (mem_req - pad - ovsc_offset) & PAGE_MASK; + st_ovsc_switch(ovsc_switchmode); + if (m68k_is040or060) { + /* On a '040+, the cache mode of video RAM must be set to + * write-through also for internal video hardware! */ + cache_push( VTOP(screen_base), screen_len ); + kernel_set_cachemode( screen_base, screen_len, + KERNELMAP_NO_COPYBACK ); + } +#ifdef ATAFB_EXT + } + else { + /* Map the video memory (physical address given) to somewhere + * in the kernel address space. + */ + *mem_start = (*mem_start+PAGE_SIZE-1) & ~(PAGE_SIZE-1); + external_addr = kernel_map(external_addr, external_len, + KERNELMAP_NO_COPYBACK, mem_start); + if (external_vgaiobase) + external_vgaiobase = kernel_map(external_vgaiobase, + 0x10000, KERNELMAP_NOCACHE_SER, mem_start); + screen_base = + real_screen_base = external_addr; + screen_len = external_len & PAGE_MASK; + memset ((char *) screen_base, 0, external_len); + } +#endif /* ATAFB_EXT */ + + strcpy(fb_info.modename, "Atari Builtin "); + fb_info.disp=disp; + fb_info.switch_con=&atafb_switch; + fb_info.updatevar=&fb_update_var; + fb_info.blank=&atafb_blank; + var=atari_fb_predefined+default_par-1; + do_fb_set_var(var,1); + strcat(fb_info.modename,fb_var_names[default_par-1][0]); + + atari_fb_get_var(&disp[0].var, -1); + atari_fb_set_disp(-1); + printk("Determined %dx%d, depth %d\n", + disp[0].var.xres, disp[0].var.yres, disp[0].var.bits_per_pixel ); + do_install_cmap(0); + return &fb_info; +} + +/* a strtok which returns empty strings, too */ + +static char * strtoke(char * s,const char * ct) +{ + char *sbegin, *send; + static char *ssave = NULL; + + sbegin = s ? s : ssave; + if (!sbegin) { + return NULL; + } + if (*sbegin == '\0') { + ssave = NULL; + return NULL; + } + send = strpbrk(sbegin, ct); + if (send && *send != '\0') + *send++ = '\0'; + ssave = send; + return sbegin; +} + +void atari_video_setup( char *options, int *ints ) +{ + char *this_opt; + int temp; + char ext_str[80], int_str[100]; + char mcap_spec[80]; + char user_mode[80]; + + ext_str[0] = + int_str[0] = + mcap_spec[0] = + user_mode[0] = + fb_info.fontname[0] = '\0'; + + if (!options || !*options) + return; + + for(this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,",")) { + if (!*this_opt) continue; + if ((temp=get_video_mode(this_opt))) + default_par=temp; + else if (! strcmp(this_opt, "inverse")) + inverse=1; + else if (!strncmp(this_opt, "font:", 5)) + strcpy(fb_info.fontname, this_opt+5); + else if (! strncmp(this_opt, "hwscroll_",9)) { + hwscroll=simple_strtoul(this_opt+9, NULL, 10); + if (hwscroll < 0) + hwscroll = 0; + if (hwscroll > 200) + hwscroll = 200; + } + else if (! strncmp(this_opt, "sw_",3)) { + if (! strcmp(this_opt+3, "acia")) + ovsc_switchmode = SWITCH_ACIA; + else if (! strcmp(this_opt+3, "snd6")) + ovsc_switchmode = SWITCH_SND6; + else if (! strcmp(this_opt+3, "snd7")) + ovsc_switchmode = SWITCH_SND7; + else ovsc_switchmode = SWITCH_NONE; + } +#ifdef ATAFB_EXT + else if (!strcmp(this_opt,"mv300")) { + external_bitspercol = 8; + external_card_type = IS_MV300; + } + else if (!strncmp(this_opt,"external:",9)) + strcpy(ext_str, this_opt+9); +#endif + else if (!strncmp(this_opt,"internal:",9)) + strcpy(int_str, this_opt+9); +#ifdef ATAFB_FALCON + else if (!strcmp(this_opt, "pwrsave")) + pwrsave = 1; + else if (!strncmp(this_opt, "eclock:", 7)) { + fext.f = simple_strtoul(this_opt+7, NULL, 10); + /* external pixelclock in kHz --> ps */ + fext.t = (2000000000UL/fext.f+1)/2; + fext.f *= 1000; + } + else if (!strncmp(this_opt, "monitorcap:", 11)) + strcpy(mcap_spec, this_opt+11); +#endif + else if (!strcmp(this_opt, "keep")) + DontCalcRes = 1; + else if (!strncmp(this_opt, "R", 1)) + strcpy(user_mode, this_opt+1); + } + + if (*int_str) { + /* Format to config extendet internal video hardware like OverScan: + ",internal:;;;;" + Explanation: + type to switch on higher resolution + sw_acia : via keyboard ACIA + sw_snd6 : via bit 6 of the soundchip port + sw_snd7 : via bit 7 of the soundchip port + : x-resolution + : y-resolution + The following are only needed if you have an overscan which + needs a black border: + : max. length of a line in pixels your OverScan hardware would allow + : max. number of lines your OverScan hardware would allow + : Offset from physical beginning to visible beginning + of screen in bytes + */ + int xres; + char *p; + + if (!(p = strtoke(int_str, ";")) ||!*p) goto int_invalid; + xres = simple_strtoul(p, NULL, 10); + if (!(p = strtoke(NULL, ";")) || !*p) goto int_invalid; + sttt_xres=xres; + tt_yres=st_yres=simple_strtoul(p, NULL, 10); + if ((p=strtoke(NULL, ";")) && *p) { + sttt_xres_virtual=simple_strtoul(p, NULL, 10); + } + if ((p=strtoke(NULL, ";")) && *p) { + sttt_yres_virtual=simple_strtoul(p, NULL, 0); + } + if ((p=strtoke(NULL, ";")) && *p) { + ovsc_offset=simple_strtoul(p, NULL, 0); + } + + if (ovsc_offset || (sttt_yres_virtual != st_yres)) + use_hwscroll=0; + } + else + int_invalid: ovsc_switchmode = SWITCH_NONE; + +#ifdef ATAFB_EXT + if (*ext_str) { + int xres, yres, depth, planes; + unsigned long addr, len; + char *p; + + /* Format is: ;;;; + * + * [;[;[;]]] + */ + if (!(p = strtoke(ext_str, ";")) ||!*p) goto ext_invalid; + xres = simple_strtoul(p, NULL, 10); + if (xres <= 0) goto ext_invalid; + + if (!(p = strtoke(NULL, ";")) ||!*p) goto ext_invalid; + yres = simple_strtoul(p, NULL, 10); + if (yres <= 0) goto ext_invalid; + + if (!(p = strtoke(NULL, ";")) ||!*p) goto ext_invalid; + depth = simple_strtoul(p, NULL, 10); + if (depth != 1 && depth != 2 && depth != 4 && depth != 8 && + depth != 16 && depth != 24) goto ext_invalid; + + if (!(p = strtoke(NULL, ";")) ||!*p) goto ext_invalid; + if (*p == 'i') + planes = FB_TYPE_INTERLEAVED_PLANES; + else if (*p == 'p') + planes = FB_TYPE_PACKED_PIXELS; + else if (*p == 'n') + planes = FB_TYPE_PLANES; + else if (*p == 't') + planes = -1; /* true color */ + else + goto ext_invalid; + + + if (!(p = strtoke(NULL, ";")) ||!*p) goto ext_invalid; + addr = simple_strtoul(p, NULL, 0); + + if (!(p = strtoke(NULL, ";")) ||!*p) + len = xres*yres*depth/8; + else + len = simple_strtoul(p, NULL, 0); + + if ((p = strtoke(NULL, ";")) && *p) + external_vgaiobase=simple_strtoul(p, NULL, 0); + + if ((p = strtoke(NULL, ";")) && *p) { + external_bitspercol = simple_strtoul(p, NULL, 0); + if (external_bitspercol > 8) + external_bitspercol = 8; + else if (external_bitspercol < 1) + external_bitspercol = 1; + } + + if ((p = strtoke(NULL, ";")) && *p) { + if (!strcmp(this_opt, "vga")) + external_card_type = IS_VGA; + if (!strcmp(this_opt, "mv300")) + external_card_type = IS_MV300; + } + + external_xres = xres; + external_yres = yres; + external_depth = depth; + external_pmode = planes; + external_addr = addr; + external_len = len; + + if (external_card_type == IS_MV300) + switch (external_depth) { + case 1: + MV300_reg = MV300_reg_1bit; + break; + case 4: + MV300_reg = MV300_reg_4bit; + break; + case 8: + MV300_reg = MV300_reg_8bit; + break; + } + + ext_invalid: + ; + } +#endif /* ATAFB_EXT */ + +#ifdef ATAFB_FALCON + if (*mcap_spec) { + char *p; + int vmin, vmax, hmin, hmax; + + /* Format for monitor capabilities is: ;;; + * vertical freq. in Hz + * horizontal freq. in kHz + */ + if (!(p = strtoke(mcap_spec, ";")) || !*p) goto cap_invalid; + vmin = simple_strtoul(p, NULL, 10); + if (vmin <= 0) goto cap_invalid; + if (!(p = strtoke(NULL, ";")) || !*p) goto cap_invalid; + vmax = simple_strtoul(p, NULL, 10); + if (vmax <= 0 || vmax <= vmin) goto cap_invalid; + if (!(p = strtoke(NULL, ";")) || !*p) goto cap_invalid; + hmin = 1000 * simple_strtoul(p, NULL, 10); + if (hmin <= 0) goto cap_invalid; + if (!(p = strtoke(NULL, "")) || !*p) goto cap_invalid; + hmax = 1000 * simple_strtoul(p, NULL, 10); + if (hmax <= 0 || hmax <= hmin) goto cap_invalid; + + vfmin = vmin; + vfmax = vmax; + hfmin = hmin; + hfmax = hmax; + cap_invalid: + ; + } +#endif + + if (*user_mode) { + /* Format of user defined video mode is: ;; + */ + char *p; + int xres, yres, depth, temp; + + if (!(p = strtoke(user_mode, ";")) || !*p) goto user_invalid; + xres = simple_strtoul(p, NULL, 10); + if (!(p = strtoke(NULL, ";")) || !*p) goto user_invalid; + yres = simple_strtoul(p, NULL, 10); + if (!(p = strtoke(NULL, "")) || !*p) goto user_invalid; + depth = simple_strtoul(p, NULL, 10); + if ((temp=get_video_mode("user0"))) { + default_par=temp; + atari_fb_predefined[default_par-1].xres = xres; + atari_fb_predefined[default_par-1].yres = yres; + atari_fb_predefined[default_par-1].bits_per_pixel = depth; + } + + user_invalid: + ; + } +} diff -u --recursive --new-file v1.3.93/linux/arch/m68k/atari/atafb.h linux/arch/m68k/atari/atafb.h --- v1.3.93/linux/arch/m68k/atari/atafb.h Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/atari/atafb.h Wed Dec 27 22:43:49 1995 @@ -0,0 +1,48 @@ +#include +#include + + +struct display +{ + int bytes_per_row; /* offset to one line below */ + + int cursor_x; /* current cursor position */ + int cursor_y; + + int fgcol; /* text colors */ + int bgcol; + + struct fb_var_screeninfo var; /* variable infos */ + struct fb_cmap cmap; /* colormap */ + + /* the following three are copies from fb_fix_screeninfo */ + int visual; + int type; + int type_aux; + + u_char *bitplane; /* pointer to top of physical screen */ + + u_char *screen_base; /* pointer to top of virtual screen */ + + u_char *fontdata; /* Font associated to this display */ + int fontheight; + int fontwidth; + + int inverse; /* != 0 text black on white as default */ + struct vc_data *conp; /* pointer to console data */ + struct display_switch *dispsw; /* pointers to depth specific functions */ +}; + +struct fb_info +{ + char modename[40]; /* name of the at boottime detected video mode */ + struct display *disp; /* pointer to display variables */ + int (*changevar)(int); /* tell the console var has changed */ + int (*switch_con)(int); /* tell the framebuffer to switch consoles */ + int (*updatevar)(int); /* tell the framebuffer to update the vars */ + void (*blank)(int); /* tell the framebuffer to (un)blank the screen */ +}; + +struct fb_info *atafb_init(long *); + + diff -u --recursive --new-file v1.3.93/linux/arch/m68k/atari/ataints.c linux/arch/m68k/atari/ataints.c --- v1.3.93/linux/arch/m68k/atari/ataints.c Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/atari/ataints.c Sat Apr 13 14:31:00 1996 @@ -0,0 +1,634 @@ +/* + * arch/m68k/atari/ataints.c -- Atari Linux interrupt handling code + * + * 5/2/94 Roman Hodek: + * Added support for TT interrupts; setup for TT SCU (may someone has + * twiddled there and we won't get the right interrupts :-() + * + * Major change: The device-independant code in m68k/ints.c didn't know + * about non-autovec ints yet. It hardcoded the number of possible ints to + * 7 (IRQ1...IRQ7). But the Atari has lots of non-autovec ints! I made the + * number of possible ints a constant defined in interrupt.h, which is + * 47 for the Atari. So we can call add_isr() for all Atari interrupts just + * the normal way. Additionally, all vectors >= 48 are initialized to call + * trap() instead of inthandler(). This must be changed here, too. + * + * 1995-07-16 Lars Brinkhoff : + * Corrected a bug in atari_add_isr() which rejected all SCC + * interrupt sources if there were no TT MFP! + * + * 12/13/95: New interface functions atari_level_triggered_int() and + * atari_register_vme_int() as support for level triggered VME interrupts. + * + * 02/12/96: (Roman) + * Total rewrite of Atari interrupt handling, for new scheme see comments + * below. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file README.legal in the main directory of this archive + * for more details. + * + */ + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + + +/* + * Atari interrupt handling scheme: + * -------------------------------- + * + * All interrupt source have an internal number (defined in + * ): Autovector interrupts are 1..7, then follow ST-MFP, + * TT-MFP, SCC, and finally VME interrupts. Vector numbers for the latter can + * be allocated by atari_register_vme_int(). Currently, all int source numbers + * have the IRQ_MACHSPEC bit set, to keep the general int handling functions + * in kernel/ints.c from them. + * + * Each interrupt can be of three types: + * + * - SLOW: The handler runs with all interrupts enabled, except the one it + * was called by (to avoid reentering). This should be the usual method. + * But it is currently possible only for MFP ints, since only the MFP + * offers an easy way to mask interrupts. + * + * - FAST: The handler runs with all interrupts disabled. This should be used + * only for really fast handlers, that just do actions immediately + * necessary, and let the rest do a bottom half or task queue. + * + * - PRIORITIZED: The handler can be interrupted by higher-level ints + * (greater IPL, no MFP priorities!). This is the method of choice for ints + * which should be slow, but are not from a MFP. + * + * The feature of more than one handler for one int source is still there, but + * only applicable if all handers are of the same type. To not slow down + * processing of ints with only one handler by the chaining feature, the list + * calling function atari_call_isr_list() is only plugged in at the time the + * second handler is registered. + * + * Implementation notes: For fast-as-possible int handling, there are separate + * entry points for each type (slow/fast/prio). The assembler handler calls + * the isr directly in the usual case, no C wrapper is involved. In case of + * multiple handlers, atari_call_isr_list() is registered as handler and calls + * in turn the real isr's. To ease access from assembler level to the isr + * function pointer and accompanying data, these two are stored in a separate + * array, irq_handler[]. The rest of data (type, name) are put into a second + * array, irq_param, that is accessed from C only. For each slow interrupt (32 + * in all) there are separate handler functions, which makes it possible to + * hard-code the MFP register address and value, are necessary to mask the + * int. If there'd be only one generic function, lots of calculations would be + * needed to determine MFP register and int mask from the vector number :-( + * + * Furthermore, slow ints may not lower the IPL below its previous value + * (before the int happened). This is needed so that an int of class PRIO, on + * that this int may be stacked, cannot be reentered. This feature is + * implemented as follows: If the stack frame format is 1 (throwaway), the int + * is not stacked, and the IPL is anded with 0xfbff, resulting in a new level + * 2, which still blocks the HSYNC, but no interrupts of interest. If the + * frame format is 0, the int is nested, and the old IPL value can be found in + * the sr copy in the frame. + */ + + +#define NUM_INT_SOURCES (8 + NUM_ATARI_SOURCES) + +typedef void (*asm_irq_handler)(void); + +struct irqhandler { + isrfunc isr; + void *data; +}; + +struct irqparam { + int type; + char *name; +}; + +/* + * Array with isr's and their parameter data. This array is accessed from low + * level assembler code, so an element size of 8 allows usage of index scaling + * addressing mode. + */ +static struct irqhandler irq_handler[NUM_INT_SOURCES]; + +/* + * This array hold the rest of parameters of int handlers: type + * (slow,fast,prio) and the name of the handler. These values are only + * accessed from C + */ +static struct irqparam irq_param[NUM_INT_SOURCES]; + +/* + * Counter for next free interrupt vector number + * (new vectors starting from 0x70 can be allocated by + * atari_register_vme_int()) + */ +static int next_free_vme_vec = VME_SOURCE_BASE; + +/* check for valid int number (complex, sigh...) */ +#define IS_VALID_INTNO(n) \ + ((n) > 0 && \ + /* autovec and ST-MFP ok anyway */ \ + (((n) < TTMFP_SOURCE_BASE) || \ + /* TT-MFP ok if present */ \ + ((n) >= TTMFP_SOURCE_BASE && (n) < SCC_SOURCE_BASE && \ + ATARIHW_PRESENT(TT_MFP)) || \ + /* SCC ok if present and number even */ \ + ((n) >= SCC_SOURCE_BASE && (n) < VME_SOURCE_BASE && \ + !((n) & 1) && ATARIHW_PRESENT(SCC)) || \ + /* greater numbers ok if less than #registered VME vectors */ \ + ((n) >= VME_SOURCE_BASE && (n) < next_free_vme_vec))) + + +/* + * Here start the assembler entry points for interrupts + */ + +#define IRQ_NAME(nr) atari_slow_irq_##nr##_handler(void) + +#define MFP_MK_BASE "0xfa13" + +/* This must agree with head.S. */ +#define ORIG_DO "0x20" +#define FORMATVEC "0x2E" +#define SR "0x28" +#define SAVE_ALL \ + "clrl %%sp@-;" /* stk_adj */ \ + "clrl %%sp@-;" \ + "subql #1,%%sp@;" /* orig d0 = -1 */ \ + "movel %%d0,%%sp@-;" /* d0 */ \ + "moveml %%d1-%%d5/%%a0-%%a1,%%sp@-" + +#define BUILD_SLOW_IRQ(n) \ +asmlinkage void IRQ_NAME(n); \ +/* Dummy function to allow asm with operands. */ \ +void atari_slow_irq_##n##_dummy (void) { \ +__asm__ (ALIGN_STR "\n" \ +SYMBOL_NAME_STR(atari_slow_irq_) #n "_handler:\t" \ + SAVE_ALL "\n" \ +" addql #1,"SYMBOL_NAME_STR(intr_count)"\n" \ +" andb #~(1<<(" #n "&7))," /* mask this interrupt */ \ + "("MFP_MK_BASE"+(((" #n "&8)^8)>>2)+((" #n "&16)<<3)):w\n" \ +" movew %%sp@("SR"),%%d0\n" /* get old IPL from stack frame */ \ +" movew %%sr,%%d1\n" \ +" andw #0x0700,%%d0\n" \ +" andw #0xf8ff,%%d1\n" \ +" orw %%d0,%%d1\n" \ +" movew %%d1,%%sr\n" /* set IPL = previous value */ \ +" addql #1,%a0\n" \ +" lea "SYMBOL_NAME_STR(irq_handler)"+("#n"+8)*8,%%a0\n" \ +" movel %%a0@(4),%%sp@-\n" /* push handler data */ \ +" pea %%sp@(4)\n" /* push addr of frame */ \ +" pea (" #n "+8):w\n" /* push int number */ \ +" movel %%a0@,%%a0\n" \ +" jbsr %%a0@\n" /* call the handler */ \ +" addql #8,%%sp\n" \ +" addql #4,%%sp\n" \ +" orw #0x0600,%%sr\n" \ +" andw #0xfeff,%%sr\n" /* set IPL = 6 again */ \ +" orb #(1<<(" #n "&7))," /* now unmask the int again */ \ + "("MFP_MK_BASE"+(((" #n "&8)^8)>>2)+((" #n "&16)<<3)):w\n" \ +" jbra "SYMBOL_NAME_STR(ret_from_interrupt)"\n" \ + : : "i" (&kstat.interrupts[n+8]) \ +); \ +} + +BUILD_SLOW_IRQ(0); +BUILD_SLOW_IRQ(1); +BUILD_SLOW_IRQ(2); +BUILD_SLOW_IRQ(3); +BUILD_SLOW_IRQ(4); +BUILD_SLOW_IRQ(5); +BUILD_SLOW_IRQ(6); +BUILD_SLOW_IRQ(7); +BUILD_SLOW_IRQ(8); +BUILD_SLOW_IRQ(9); +BUILD_SLOW_IRQ(10); +BUILD_SLOW_IRQ(11); +BUILD_SLOW_IRQ(12); +BUILD_SLOW_IRQ(13); +BUILD_SLOW_IRQ(14); +BUILD_SLOW_IRQ(15); +BUILD_SLOW_IRQ(16); +BUILD_SLOW_IRQ(17); +BUILD_SLOW_IRQ(18); +BUILD_SLOW_IRQ(19); +BUILD_SLOW_IRQ(20); +BUILD_SLOW_IRQ(21); +BUILD_SLOW_IRQ(22); +BUILD_SLOW_IRQ(23); +BUILD_SLOW_IRQ(24); +BUILD_SLOW_IRQ(25); +BUILD_SLOW_IRQ(26); +BUILD_SLOW_IRQ(27); +BUILD_SLOW_IRQ(28); +BUILD_SLOW_IRQ(29); +BUILD_SLOW_IRQ(30); +BUILD_SLOW_IRQ(31); + +asm_irq_handler slow_handlers[32] = { + atari_slow_irq_0_handler, + atari_slow_irq_1_handler, + atari_slow_irq_2_handler, + atari_slow_irq_3_handler, + atari_slow_irq_4_handler, + atari_slow_irq_5_handler, + atari_slow_irq_6_handler, + atari_slow_irq_7_handler, + atari_slow_irq_8_handler, + atari_slow_irq_9_handler, + atari_slow_irq_10_handler, + atari_slow_irq_11_handler, + atari_slow_irq_12_handler, + atari_slow_irq_13_handler, + atari_slow_irq_14_handler, + atari_slow_irq_15_handler, + atari_slow_irq_16_handler, + atari_slow_irq_17_handler, + atari_slow_irq_18_handler, + atari_slow_irq_19_handler, + atari_slow_irq_20_handler, + atari_slow_irq_21_handler, + atari_slow_irq_22_handler, + atari_slow_irq_23_handler, + atari_slow_irq_24_handler, + atari_slow_irq_25_handler, + atari_slow_irq_26_handler, + atari_slow_irq_27_handler, + atari_slow_irq_28_handler, + atari_slow_irq_29_handler, + atari_slow_irq_30_handler, + atari_slow_irq_31_handler +}; + +asmlinkage void atari_fast_irq_handler( void ); +asmlinkage void atari_prio_irq_handler( void ); + +/* Dummy function to allow asm with operands. */ +void atari_fast_prio_irq_dummy (void) { +__asm__ (ALIGN_STR "\n" +SYMBOL_NAME_STR(atari_fast_irq_handler) ": + orw #0x700,%%sr /* disable all interrupts */ +"SYMBOL_NAME_STR(atari_prio_irq_handler) ":\t" + SAVE_ALL " + addql #1,"SYMBOL_NAME_STR(intr_count)" + movew %%sp@(" FORMATVEC "),%%d0 /* get vector number from stack frame */ + andil #0xfff,%%d0 /* mask off format nibble */ + lsrl #2,%%d0 /* convert vector to source */ + subl #(0x40-8),%%d0 + jpl 1f + addl #(0x40-8-0x18),%%d0 +1: lea %a0,%%a0 + addql #1,%%a0@(%%d0:l:4) + lea "SYMBOL_NAME_STR(irq_handler)",%%a0 + lea %%a0@(%%d0:l:8),%%a0 + movel %%a0@(4),%%sp@- /* push handler data */ + pea %%sp@(4) /* push frame address */ + movel %%d0,%%sp@- /* push int number */ + movel %%a0@,%%a0 + jsr %%a0@ /* and call the handler */ + addql #8,%%sp + addql #4,%%sp + jbra "SYMBOL_NAME_STR(ret_from_interrupt) + : : "i" (&kstat.interrupts) +); +} + +/* GK: + * HBL IRQ handler for Falcon. Nobody needs it :-) + * ++andreas: raise ipl to disable further HBLANK interrupts. + */ +asmlinkage void falcon_hblhandler(void); +asm(".text\n" +ALIGN_STR "\n" +SYMBOL_NAME_STR(falcon_hblhandler) ": + movel %d0,%sp@- + movew %sp@(4),%d0 + andw #0xf8ff,%d0 + orw #0x0200,%d0 /* set saved ipl to 2 */ + movew %d0,%sp@(4) + movel %sp@+,%d0 + rte"); + +/* Defined in entry.S; only increments 'num_suprious' */ +asmlinkage void bad_interrupt(void); + +extern void atari_microwire_cmd( int cmd ); + +/* + * void atari_init_INTS (void) + * + * Parameters: None + * + * Returns: Nothing + * + * This function should be called during kernel startup to initialize + * the atari IRQ handling routines. + */ + +void atari_init_INTS(void) +{ + int i; + + /* initialize the vector table */ + for (i = 0; i < NUM_INT_SOURCES; ++i) { + vectors[IRQ_SOURCE_TO_VECTOR(i)] = bad_interrupt; + } + + /* Initialize the MFP(s) */ + +#ifdef ATARI_USE_SOFTWARE_EOI + mfp.vec_adr = 0x48; /* Software EOI-Mode */ +#else + mfp.vec_adr = 0x40; /* Automatic EOI-Mode */ +#endif + mfp.int_en_a = /* turn off MFP-Ints */ + mfp.int_en_b = 0x00; + mfp.int_mk_a = /* no Masking */ + mfp.int_mk_b = 0xff; + + if (ATARIHW_PRESENT(TT_MFP)) { +#ifdef ATARI_USE_SOFTWARE_EOI + tt_mfp.vec_adr = 0x58; /* Software EOI-Mode */ +#else + tt_mfp.vec_adr = 0x50; /* Automatic EOI-Mode */ +#endif + tt_mfp.int_en_a = /* turn off MFP-Ints */ + tt_mfp.int_en_b = 0x00; + tt_mfp.int_mk_a = /* no Masking */ + tt_mfp.int_mk_b = 0xff; + } + + if (ATARIHW_PRESENT(SCC)) { + scc.cha_a_ctrl = 9; + MFPDELAY(); + scc.cha_a_ctrl = (char) 0xc0; /* hardware reset */ + } + + if (ATARIHW_PRESENT(SCU)) { + /* init the SCU if present */ + tt_scu.sys_mask = 0x10; /* enable VBL (for the cursor) and + * disable HSYNC interrupts (who + * needs them?) MFP and SCC are + * enabled in VME mask + */ + tt_scu.vme_mask = 0x60; /* enable MFP and SCC ints */ + } + else { + /* If no SCU, the HSYNC interrupt needs to be disabled this + * way. (Else _inthandler in kernel/sys_call.S gets overruns) + */ + vectors[VEC_INT2] = falcon_hblhandler; + } + + if (ATARIHW_PRESENT(PCM_8BIT) && ATARIHW_PRESENT(MICROWIRE)) { + /* Initialize the LM1992 Sound Controller to enable + the PSG sound. This is misplaced here, it should + be in a atasound_init(), that doesn't exist yet. */ + atari_microwire_cmd(MW_LM1992_PSG_HIGH); + } + + stdma_init(); + + /* Initialize the PSG: all sounds off, both ports output */ + sound_ym.rd_data_reg_sel = 7; + sound_ym.wd_data = 0xff; +} + + +static void atari_call_isr_list( int irq, struct pt_regs *fp, void *_p ) +{ + isr_node_t *p; + + for( p = (isr_node_t *)_p; p; p = p->next ) + p->isr( irq, fp, p->data ); +} + + +/* + * atari_add_isr : add an interrupt service routine for a particular + * machine specific interrupt source. + * If the addition was successful, it returns 1, otherwise + * it returns 0. It will fail if the interrupt is already + * occupied of another handler with different type + */ + +int atari_add_isr(unsigned long source, isrfunc isr, int type, void + *data, char *name) +{ + int vector; + + source &= ~IRQ_MACHSPEC; + if (type < IRQ_TYPE_SLOW || type > IRQ_TYPE_PRIO) { + printk ("atari_add_isr: Bad irq type %d requested from %s\n", + type, name ); + return( 0 ); + } + if (!IS_VALID_INTNO(source)) { + printk ("atari_add_isr: Unknown irq %ld requested from %s\n", + source, name ); + return( 0 ); + } + vector = IRQ_SOURCE_TO_VECTOR(source); + + /* + * Check type/source combination: slow ints are (currently) + * only possible for MFP-interrupts. + */ + if (type == IRQ_TYPE_SLOW && + (source < STMFP_SOURCE_BASE || source >= SCC_SOURCE_BASE)) { + printk ("atari_add_isr: Slow irq requested for non-MFP source %ld from %s\n", + source, name ); + return( 0 ); + } + + if (vectors[vector] == bad_interrupt) { + /* int has no handler yet */ + irq_handler[source].isr = isr; + irq_handler[source].data = data; + irq_param[source].type = type; + irq_param[source].name = name; + vectors[vector] = + (type == IRQ_TYPE_SLOW) ? slow_handlers[source-STMFP_SOURCE_BASE] : + (type == IRQ_TYPE_FAST) ? atari_fast_irq_handler : + atari_prio_irq_handler; + /* If MFP int, also enable and umask it */ + atari_turnon_irq(source); + atari_enable_irq(source); + + return 1; + } + else if (irq_param[source].type == type) { + /* old handler is of same type -> handlers can be chained */ + isr_node_t *p; + unsigned long flags; + + save_flags(flags); + cli(); + + if (irq_handler[source].isr != atari_call_isr_list) { + /* Only one handler yet, make a node for this first one */ + p = new_isr_node(); + if (p == NULL) return 0; + p->isr = irq_handler[source].isr; + p->data = irq_handler[source].data; + p->name = irq_param[source].name; + p->next = NULL; + + irq_handler[source].isr = atari_call_isr_list; + irq_handler[source].data = p; + irq_param[source].name = "chained"; + } + + p = new_isr_node(); + if (p == NULL) return 0; + p->isr = isr; + p->data = data; + p->name = name; + /* new handlers are put in front of the queue */ + p->next = irq_handler[source].data; + irq_handler[source].data = p; + + restore_flags(flags); + return 1; + } + else { + printk ("atari_add_isr: Irq %ld allocated by other type int (call from %s)\n", + source, name ); + return( 0 ); + } +} + + +int atari_remove_isr(unsigned long source, isrfunc isr) +{ + unsigned long flags; + int vector; + isr_node_t **p, *q; + + source &= ~IRQ_MACHSPEC; + + if (!IS_VALID_INTNO(source)) { + printk("atari_remove_isr: Unknown irq %ld\n", source); + return 0; + } + + vector = IRQ_SOURCE_TO_VECTOR(source); + if (vectors[vector] == bad_interrupt) + goto not_found; + + save_flags(flags); + cli(); + + if (irq_handler[source].isr != atari_call_isr_list) { + /* It's the only handler for the interrupt */ + if (irq_handler[source].isr != isr) { + restore_flags(flags); + goto not_found; + } + irq_handler[source].isr = NULL; + irq_handler[source].data = NULL; + irq_param[source].name = NULL; + vectors[vector] = bad_interrupt; + /* If MFP int, also disable it */ + atari_disable_irq(source); + atari_turnoff_irq(source); + + restore_flags(flags); + return 1; + } + + /* The interrupt is chained, find the isr on the list */ + for( p = (isr_node_t **)&irq_handler[source].data; *p; p = &(*p)->next ) { + if ((*p)->isr == isr) break; + } + if (!*p) { + restore_flags(flags); + goto not_found; + } + + (*p)->isr = NULL; /* Mark it as free for reallocation */ + *p = (*p)->next; + + /* If there's now only one handler, unchain the interrupt, i.e. plug in + * the handler directly again and omit atari_call_isr_list */ + q = (isr_node_t *)irq_handler[source].data; + if (q && !q->next) { + irq_handler[source].isr = q->isr; + irq_handler[source].data = q->data; + irq_param[source].name = q->name; + q->isr = NULL; /* Mark it as free for reallocation */ + } + + restore_flags(flags); + return 1; + + not_found: + printk("atari_remove_isr: isr %p not found on list!\n", isr); + return 0; +} + + +/* + * atari_register_vme_int() returns the number of a free interrupt vector for + * hardware with a programmable int vector (probably a VME board). + */ + +unsigned long atari_register_vme_int(void) +{ + unsigned long source; + + if (next_free_vme_vec == NUM_ATARI_SOURCES) + return 0; + + source = next_free_vme_vec | IRQ_MACHSPEC; + next_free_vme_vec++; + return source; +} + + +int atari_get_irq_list(char *buf, int len) +{ + int i; + + for (i = 0; i < NUM_INT_SOURCES; ++i) { + if (vectors[IRQ_SOURCE_TO_VECTOR(i)] == bad_interrupt) + continue; + if (i < STMFP_SOURCE_BASE) + len += sprintf(buf+len, "auto %2d: %8d ", + i, kstat.interrupts[i]); + else + len += sprintf(buf+len, "vec $%02x: %8d ", + IRQ_SOURCE_TO_VECTOR(i), + kstat.interrupts[i]); + + if (irq_handler[i].isr != atari_call_isr_list) { + len += sprintf(buf+len, "%s\n", irq_param[i].name); + } + else { + isr_node_t *p; + for( p = (isr_node_t *)irq_handler[i].data; p; p = p->next ) { + len += sprintf(buf+len, "%s\n", p->name); + if (p->next) + len += sprintf( buf+len, " " ); + } + } + } + if (num_spurious) + len += sprintf(buf+len, "spurio.: %8ld\n", num_spurious); + + return len; +} + + diff -u --recursive --new-file v1.3.93/linux/arch/m68k/atari/atakeyb.c linux/arch/m68k/atari/atakeyb.c --- v1.3.93/linux/arch/m68k/atari/atakeyb.c Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/atari/atakeyb.c Mon Apr 1 22:00:10 1996 @@ -0,0 +1,847 @@ +/* + * linux/atari/atakeyb.c + * + * Atari Keyboard driver for 680x0 Linux + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file README.legal in the main directory of this archive + * for more details. + */ + +/* + * Atari support by Robert de Vries + * enhanced by Bjoern Brauel and Roman Hodek + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +extern int do_poke_blanked_console; +extern void process_keycode (int); +extern int ovsc_switchmode; +unsigned char mach_keyboard_type; +static void atakeyb_rep( unsigned long ignore ); +extern unsigned int keymap_count; + +/* Hook for MIDI serial driver */ +void (*atari_MIDI_interrupt_hook) (void); +/* Hook for mouse driver */ +void (*atari_mouse_interrupt_hook) (char *); + +#define ATAKEY_CAPS (58) +#define BREAK_MASK (0x80) + +/* + * ++roman: The following changes were applied manually: + * + * - The Alt (= Meta) key works in combination with Shift and + * Control, e.g. Alt+Shift+a sends Meta-A (0xc1), Alt+Control+A sends + * Meta-Ctrl-A (0x81) ... + * + * - The parentheses on the keypad send '(' and ')' with all + * modifiers (as would do e.g. keypad '+'), but they cannot be used as + * application keys (i.e. sending Esc O c). + * + * - HELP and UNDO are mapped to be F21 and F24, resp, that send the + * codes "\E[M" and "\E[P". (This is better than the old mapping to + * F11 and F12, because these codes are on Shift+F1/2 anyway.) This + * way, applications that allow their own keyboard mappings + * (e.g. tcsh, X Windows) can be configured to use them in the way + * the label suggests (providing help or undoing). + * + * - Console switching is done with Alt+Fx (consoles 1..10) and + * Shift+Alt+Fx (consoles 11..20). + * + * - The misc. special function implemented in the kernel are mapped + * to the following key combinations: + * + * ClrHome -> Home/Find + * Shift + ClrHome -> End/Select + * Shift + Up -> Page Up + * Shift + Down -> Page Down + * Alt + Help -> show system status + * Shift + Help -> show memory info + * Ctrl + Help -> show registers + * Ctrl + Alt + Del -> Reboot + * Alt + Undo -> switch to last console + * Shift + Undo -> send interrupt + * Alt + Insert -> stop/start output (same as ^S/^Q) + * Alt + Up -> Scroll back console (if implemented) + * Alt + Down -> Scroll forward console (if implemented) + * Alt + CapsLock -> NumLock + * + */ + +static u_short ataplain_map[NR_KEYS] = { + 0xf200, 0xf01b, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, + 0xf037, 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf008, 0xf009, + 0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69, + 0xfb6f, 0xfb70, 0xf05b, 0xf05d, 0xf201, 0xf702, 0xfb61, 0xfb73, + 0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf03b, + 0xf027, 0xf060, 0xf700, 0xf05c, 0xfb7a, 0xfb78, 0xfb63, 0xfb76, + 0xfb62, 0xfb6e, 0xfb6d, 0xf02c, 0xf02e, 0xf02f, 0xf700, 0xf200, + 0xf703, 0xf020, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, + 0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf200, 0xf200, 0xf114, + 0xf603, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200, + 0xf600, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf121, 0xf11b, 0xf028, 0xf029, 0xf30d, 0xf30c, 0xf307, + 0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303, + 0xf300, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200 +}; + +static u_short atashift_map[NR_KEYS] = { + 0xf200, 0xf01b, 0xf021, 0xf040, 0xf023, 0xf024, 0xf025, 0xf05e, + 0xf026, 0xf02a, 0xf028, 0xf029, 0xf05f, 0xf02b, 0xf008, 0xf009, + 0xfb51, 0xfb57, 0xfb45, 0xfb52, 0xfb54, 0xfb59, 0xfb55, 0xfb49, + 0xfb4f, 0xfb50, 0xf07b, 0xf07d, 0xf201, 0xf702, 0xfb41, 0xfb53, + 0xfb44, 0xfb46, 0xfb47, 0xfb48, 0xfb4a, 0xfb4b, 0xfb4c, 0xf03a, + 0xf022, 0xf07e, 0xf700, 0xf07c, 0xfb5a, 0xfb58, 0xfb43, 0xfb56, + 0xfb42, 0xfb4e, 0xfb4d, 0xf03c, 0xf03e, 0xf03f, 0xf700, 0xf200, + 0xf703, 0xf020, 0xf207, 0xf10a, 0xf10b, 0xf10c, 0xf10d, 0xf10e, + 0xf10f, 0xf110, 0xf111, 0xf112, 0xf113, 0xf200, 0xf200, 0xf117, + 0xf118, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200, + 0xf119, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf205, 0xf203, 0xf028, 0xf029, 0xf30d, 0xf30c, 0xf307, + 0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303, + 0xf300, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200 +}; + +static u_short atactrl_map[NR_KEYS] = { + 0xf200, 0xf200, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01d, 0xf01e, + 0xf01f, 0xf07f, 0xf200, 0xf200, 0xf07f, 0xf200, 0xf008, 0xf200, + 0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009, + 0xf00f, 0xf010, 0xf01b, 0xf01d, 0xf201, 0xf702, 0xf001, 0xf013, + 0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, 0xf200, + 0xf007, 0xf000, 0xf700, 0xf01c, 0xf01a, 0xf018, 0xf003, 0xf016, + 0xf002, 0xf00e, 0xf00d, 0xf200, 0xf200, 0xf07f, 0xf700, 0xf200, + 0xf703, 0xf000, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, + 0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf200, 0xf200, 0xf114, + 0xf603, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200, + 0xf600, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf121, 0xf202, 0xf028, 0xf029, 0xf30d, 0xf30c, 0xf307, + 0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303, + 0xf300, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200 +}; + +static u_short atashift_ctrl_map[NR_KEYS] = { + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf008, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf201, 0xf702, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf700, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf700, 0xf200, + 0xf703, 0xf200, 0xf207, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf117, + 0xf603, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200, + 0xf600, 0xf200, 0xf115, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf028, 0xf029, 0xf30d, 0xf30c, 0xf307, + 0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303, + 0xf300, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200 +}; + +static u_short ataalt_map[NR_KEYS] = { + 0xf200, 0xf81b, 0xf831, 0xf832, 0xf833, 0xf834, 0xf835, 0xf836, + 0xf837, 0xf838, 0xf839, 0xf830, 0xf82d, 0xf83d, 0xf808, 0xf809, + 0xf871, 0xf877, 0xf865, 0xf872, 0xf874, 0xf879, 0xf875, 0xf869, + 0xf86f, 0xf870, 0xf85b, 0xf85d, 0xf80d, 0xf702, 0xf861, 0xf873, + 0xf864, 0xf866, 0xf867, 0xf868, 0xf86a, 0xf86b, 0xf86c, 0xf83b, + 0xf827, 0xf860, 0xf700, 0xf85c, 0xf87a, 0xf878, 0xf863, 0xf876, + 0xf862, 0xf86e, 0xf86d, 0xf82c, 0xf82e, 0xf82f, 0xf700, 0xf200, + 0xf703, 0xf820, 0xf208, 0xf500, 0xf501, 0xf502, 0xf503, 0xf504, + 0xf505, 0xf506, 0xf507, 0xf508, 0xf509, 0xf200, 0xf200, 0xf114, + 0xf20b, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200, + 0xf20a, 0xf200, 0xf209, 0xf87f, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf206, 0xf204, 0xf028, 0xf029, 0xf30d, 0xf30c, 0xf907, + 0xf908, 0xf909, 0xf904, 0xf905, 0xf906, 0xf901, 0xf902, 0xf903, + 0xf900, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200 +}; + +static u_short atashift_alt_map[NR_KEYS] = { + 0xf200, 0xf81b, 0xf821, 0xf840, 0xf823, 0xf824, 0xf825, 0xf85e, + 0xf826, 0xf82a, 0xf828, 0xf829, 0xf85f, 0xf82b, 0xf808, 0xf809, + 0xf851, 0xf857, 0xf845, 0xf852, 0xf854, 0xf859, 0xf855, 0xf849, + 0xf84f, 0xf850, 0xf87b, 0xf87d, 0xf201, 0xf702, 0xf841, 0xf853, + 0xf844, 0xf846, 0xf847, 0xf848, 0xf84a, 0xf84b, 0xf84c, 0xf83a, + 0xf822, 0xf87e, 0xf700, 0xf87c, 0xf85a, 0xf858, 0xf843, 0xf856, + 0xf842, 0xf84e, 0xf84d, 0xf83c, 0xf83e, 0xf83f, 0xf700, 0xf200, + 0xf703, 0xf820, 0xf207, 0xf50a, 0xf50b, 0xf50c, 0xf50d, 0xf50e, + 0xf50f, 0xf510, 0xf511, 0xf512, 0xf513, 0xf200, 0xf200, 0xf117, + 0xf118, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200, + 0xf119, 0xf200, 0xf115, 0xf87f, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf028, 0xf029, 0xf30d, 0xf30c, 0xf307, + 0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303, + 0xf300, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200 +}; + +static u_short atactrl_alt_map[NR_KEYS] = { + 0xf200, 0xf200, 0xf200, 0xf800, 0xf81b, 0xf81c, 0xf81d, 0xf81e, + 0xf81f, 0xf87f, 0xf200, 0xf200, 0xf87f, 0xf200, 0xf808, 0xf200, + 0xf811, 0xf817, 0xf805, 0xf812, 0xf814, 0xf819, 0xf815, 0xf809, + 0xf80f, 0xf810, 0xf81b, 0xf81d, 0xf201, 0xf702, 0xf801, 0xf813, + 0xf804, 0xf806, 0xf807, 0xf808, 0xf80a, 0xf80b, 0xf80c, 0xf200, + 0xf807, 0xf800, 0xf700, 0xf81c, 0xf81a, 0xf818, 0xf803, 0xf816, + 0xf802, 0xf80e, 0xf80d, 0xf200, 0xf200, 0xf87f, 0xf700, 0xf200, + 0xf703, 0xf800, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, + 0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf200, 0xf200, 0xf114, + 0xf603, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200, + 0xf600, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf121, 0xf202, 0xf028, 0xf029, 0xf30d, 0xf30c, 0xf307, + 0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303, + 0xf300, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200 +}; + +static u_short atashift_ctrl_alt_map[NR_KEYS] = { + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf808, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf201, 0xf702, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf700, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf700, 0xf200, + 0xf703, 0xf200, 0xf207, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf117, + 0xf603, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200, + 0xf600, 0xf200, 0xf115, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf028, 0xf029, 0xf30d, 0xf30c, 0xf307, + 0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303, + 0xf300, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200 +}; + +typedef enum kb_state_t +{ + KEYBOARD, AMOUSE, RMOUSE, JOYSTICK, CLOCK, RESYNC +} KB_STATE_T; + +#define IS_SYNC_CODE(sc) ((sc) >= 0x04 && (sc) <= 0xfb) + +typedef struct keyboard_state +{ + unsigned char buf[6]; + int len; + KB_STATE_T state; +} KEYBOARD_STATE; + +KEYBOARD_STATE kb_state; + +#define DEFAULT_KEYB_REP_DELAY (HZ/4) +#define DEFAULT_KEYB_REP_RATE (HZ/25) + +/* These could be settable by some ioctl() in future... */ +static unsigned int key_repeat_delay = DEFAULT_KEYB_REP_DELAY; +static unsigned int key_repeat_rate = DEFAULT_KEYB_REP_RATE; + +static unsigned char rep_scancode; +static struct timer_list atakeyb_rep_timer = { NULL, NULL, 0, 0, atakeyb_rep }; + +extern struct pt_regs *pt_regs; + +static void atakeyb_rep( unsigned long ignore ) + +{ + pt_regs = NULL; + + /* Disable keyboard it for the time we call process_keycode(), else a race + * in the keyboard tty queue may happen */ + atari_disable_irq( IRQ_MFP_ACIA ); + del_timer( &atakeyb_rep_timer ); + + /* A keyboard int may have come in before we disabled the irq, so + * double-check whether rep_scancode is still != 0 */ + if (rep_scancode) { + atakeyb_rep_timer.expires = jiffies + key_repeat_rate; + atakeyb_rep_timer.prev = atakeyb_rep_timer.next = NULL; + add_timer( &atakeyb_rep_timer ); + + process_keycode (rep_scancode); + } + + atari_enable_irq( IRQ_MFP_ACIA ); +} + + +/* ++roman: If a keyboard overrun happened, we can't tell in general how much + * bytes have been lost and in which state of the packet structure we are now. + * This usually causes keyboards bytes to be interpreted as mouse movements + * and vice versa, which is very annoying. It seems better to throw away some + * bytes (that are usually mouse bytes) than to misinterpret them. Therefor I + * introduced the RESYNC state for IKBD data. In this state, the bytes up to + * one that really looks like a key event (0x04..0xf2) or the start of a mouse + * packet (0xf8..0xfb) are thrown away, but at most 2 bytes. This at least + * speeds up the resynchronization of the event structure, even if maybe a + * mouse movement is lost. However, nothing is perfect. For bytes 0x01..0x03, + * it's really hard to decide whether they're mouse or keyboard bytes. Since + * overruns usually occur when moving the Atari mouse rapidly, they're seen as + * mouse bytes here. If this is wrong, only a make code of the keyboard gets + * lost, which isn't too bad. Loosing a break code would be desasterous, + * because then the keyboard repeat strikes... + */ + +static void keyboard_interrupt(int irq, struct pt_regs *fp, void *dummy) +{ + u_char acia_stat; + int scancode; + int break_flag; + + /* save frame for register dump */ + pt_regs = (struct pt_regs *)fp; + + repeat: + if (acia.mid_ctrl & ACIA_IRQ) + if (atari_MIDI_interrupt_hook) + atari_MIDI_interrupt_hook(); + acia_stat = acia.key_ctrl; + /* check out if the interrupt came from this ACIA */ + if (!((acia_stat | acia.mid_ctrl) & ACIA_IRQ)) + return; + + if (acia_stat & ACIA_OVRN) + { + /* a very fast typist or a slow system, give a warning */ + /* ...happens often if interrupts were disabled for too long */ + printk( "Keyboard overrun\n" ); + scancode = acia.key_data; + /* Turn off autorepeating in case a break code has been lost */ + del_timer( &atakeyb_rep_timer ); + rep_scancode = 0; + if (IS_SYNC_CODE(scancode)) { + /* This code seem already to be the start of a new packet or a + * single keycode */ + kb_state.state = KEYBOARD; + goto interpret_scancode; + } + else { + /* Go to RESYNC state and skip this byte */ + kb_state.state = RESYNC; + kb_state.len = 1; /* skip max. 1 another byte */ + goto repeat; + } + } + + if (acia_stat & ACIA_RDRF) /* received a character */ + { + scancode = acia.key_data; /* get it or reset the ACIA, I'll get it! */ + interpret_scancode: + switch (kb_state.state) + { + case KEYBOARD: + switch (scancode) + { + case 0xF7: + kb_state.state = AMOUSE; + kb_state.len = 0; + break; + + case 0xF8: + case 0xF9: + case 0xFA: + case 0xFB: + kb_state.state = RMOUSE; + kb_state.len = 1; + kb_state.buf[0] = scancode; + break; + + case 0xFC: + kb_state.state = CLOCK; + kb_state.len = 0; + break; + + case 0xFE: + case 0xFF: + kb_state.state = JOYSTICK; + kb_state.len = 1; + kb_state.buf[0] = scancode; + break; + + default: + break_flag = scancode & BREAK_MASK; + scancode &= ~BREAK_MASK; + + if (break_flag) { + del_timer( &atakeyb_rep_timer ); + rep_scancode = 0; + } + else { + del_timer( &atakeyb_rep_timer ); + rep_scancode = scancode; + atakeyb_rep_timer.expires = jiffies + key_repeat_delay; + atakeyb_rep_timer.prev = atakeyb_rep_timer.next = NULL; + add_timer( &atakeyb_rep_timer ); + } + + process_keycode( break_flag | scancode ); + do_poke_blanked_console = 1; + mark_bh(CONSOLE_BH); + add_keyboard_randomness(scancode); + + break; + } + break; + + case AMOUSE: + kb_state.buf[kb_state.len++] = scancode; + if (kb_state.len == 5) + { + kb_state.state = KEYBOARD; + /* not yet used */ + /* wake up someone waiting for this */ + } + break; + + case RMOUSE: + kb_state.buf[kb_state.len++] = scancode; + if (kb_state.len == 3) + { + kb_state.state = KEYBOARD; + if (atari_mouse_interrupt_hook) + atari_mouse_interrupt_hook(kb_state.buf); + } + break; + + case JOYSTICK: + kb_state.buf[1] = scancode; + kb_state.state = KEYBOARD; + atari_joystick_interrupt(kb_state.buf); + break; + + case CLOCK: + kb_state.buf[kb_state.len++] = scancode; + if (kb_state.len == 6) + { + kb_state.state = KEYBOARD; + /* wake up someone waiting for this. + But will this ever be used, as Linux keeps its own time. + Perhaps for synchronization purposes? */ + /* wake_up_interruptible(&clock_wait); */ + } + break; + + case RESYNC: + if (kb_state.len <= 0 || IS_SYNC_CODE(scancode)) { + kb_state.state = KEYBOARD; + goto interpret_scancode; + } + kb_state.len--; + break; + } + } + +#ifdef KEYB_WRITE_INTERRUPT + if (acia_stat & ACIA_TDRE) /* transmit of character is finished */ + { + if (kb_state.buf) + { + acia.key_data = *kb_state.buf++; + kb_state.len--; + if (kb_state.len == 0) + { + kb_state.buf = NULL; + if (!kb_state.kernel_mode) + /* unblock something */; + } + } + } +#endif + +#if 0 + if (acia_stat & ACIA_CTS) + /* cannot happen */; +#endif + + if (acia_stat & (ACIA_FE | ACIA_PE)) + { + printk("Error in keyboard communication\n"); + } + + /* process_keycode() can take a lot of time, so check again if + * some character arrived + */ + goto repeat; +} + +#ifdef KEYB_WRITE_INTERRUPT +void ikbd_write(const char *str, int len) +{ + u_char acia_stat; + + if (kb_stat.buf) + /* wait */; + acia_stat = acia.key_ctrl; + if (acia_stat & ACIA_TDRE) + { + if (len != 1) + { + kb_stat.buf = str + 1; + kb_stat.len = len - 1; + } + acia.key_data = *str; + /* poll */ + } +} +#else +/* + * I write to the keyboard without using interrupts, I poll instead. + * This takes for the maximum length string allowed (7) at 7812.5 baud + * 8 data 1 start 1 stop bit: 9.0 ms + * If this takes too long for normal operation, interrupt driven writing + * is the solution. (I made a feeble attempt in that direction but I + * kept it simple for now.) + */ +void ikbd_write(const char *str, int len) +{ + u_char acia_stat; + + if ((len < 1) || (len > 7)) + panic("ikbd: maximum string length exceeded"); + while (len) + { + acia_stat = acia.key_ctrl; + if (acia_stat & ACIA_TDRE) + { + acia.key_data = *str++; + len--; + } + } +} +#endif + +/* Reset (without touching the clock) */ +void ikbd_reset(void) +{ + static const char cmd[2] = { 0x80, 0x01 }; + + ikbd_write(cmd, 2); + + /* if allswell code 0xF1 is returned, else the break codes of + all keys making contact */ +} + +/* Set mouse button action */ +void ikbd_mouse_button_action(int mode) +{ + char cmd[2] = { 0x07, mode }; + + ikbd_write(cmd, 2); +} + +/* Set relative mouse position reporting */ +void ikbd_mouse_rel_pos(void) +{ + static const char cmd[1] = { 0x08 }; + + ikbd_write(cmd, 1); +} + +/* Set absolute mouse position reporting */ +void ikbd_mouse_abs_pos(int xmax, int ymax) +{ + char cmd[5] = { 0x09, xmax>>8, xmax&0xFF, ymax>>8, ymax&0xFF }; + + ikbd_write(cmd, 5); +} + +/* Set mouse keycode mode */ +void ikbd_mouse_kbd_mode(int dx, int dy) +{ + char cmd[3] = { 0x0A, dx, dy }; + + ikbd_write(cmd, 3); +} + +/* Set mouse threshold */ +void ikbd_mouse_thresh(int x, int y) +{ + char cmd[3] = { 0x0B, x, y }; + + ikbd_write(cmd, 3); +} + +/* Set mouse scale */ +void ikbd_mouse_scale(int x, int y) +{ + char cmd[3] = { 0x0C, x, y }; + + ikbd_write(cmd, 3); +} + +/* Interrogate mouse position */ +void ikbd_mouse_pos_get(int *x, int *y) +{ + static const char cmd[1] = { 0x0D }; + + ikbd_write(cmd, 1); + + /* wait for returning bytes */ +} + +/* Load mouse position */ +void ikbd_mouse_pos_set(int x, int y) +{ + char cmd[6] = { 0x0E, 0x00, x>>8, x&0xFF, y>>8, y&0xFF }; + + ikbd_write(cmd, 6); +} + +/* Set Y=0 at bottom */ +void ikbd_mouse_y0_bot(void) +{ + static const char cmd[1] = { 0x0F }; + + ikbd_write(cmd, 1); +} + +/* Set Y=0 at top */ +void ikbd_mouse_y0_top(void) +{ + static const char cmd[1] = { 0x10 }; + + ikbd_write(cmd, 1); +} + +/* Resume */ +void ikbd_resume(void) +{ + static const char cmd[1] = { 0x11 }; + + ikbd_write(cmd, 1); +} + +/* Disable mouse */ +void ikbd_mouse_disable(void) +{ + static const char cmd[1] = { 0x12 }; + + ikbd_write(cmd, 1); +} + +/* Pause output */ +void ikbd_pause(void) +{ + static const char cmd[1] = { 0x13 }; + + ikbd_write(cmd, 1); +} + +/* Set joystick event reporting */ +void ikbd_joystick_event_on(void) +{ + static const char cmd[1] = { 0x14 }; + + ikbd_write(cmd, 1); +} + +/* Set joystick interrogation mode */ +void ikbd_joystick_event_off(void) +{ + static const char cmd[1] = { 0x15 }; + + ikbd_write(cmd, 1); +} + +/* Joystick interrogation */ +void ikbd_joystick_get_state(void) +{ + static const char cmd[1] = { 0x16 }; + + ikbd_write(cmd, 1); +} + +#if 0 +/* This disables all other ikbd activities !!!! */ +/* Set joystick monitoring */ +void ikbd_joystick_monitor(int rate) +{ + static const char cmd[2] = { 0x17, rate }; + + ikbd_write(cmd, 2); + + kb_state.state = JOYSTICK_MONITOR; +} +#endif + +/* some joystick routines not in yet (0x18-0x19) */ + +/* Disable joysticks */ +void ikbd_joystick_disable(void) +{ + static const char cmd[1] = { 0x1A }; + + ikbd_write(cmd, 1); +} + +/* Time-of-day clock set */ +void ikbd_clock_set(int year, int month, int day, int hour, int minute, int second) +{ + char cmd[7] = { 0x1B, year, month, day, hour, minute, second }; + + ikbd_write(cmd, 7); +} + +/* Interrogate time-of-day clock */ +void ikbd_clock_get(int *year, int *month, int *day, int *hour, int *minute, int second) +{ + static const char cmd[1] = { 0x1C }; + + ikbd_write(cmd, 1); +} + +/* Memory load */ +void ikbd_mem_write(int address, int size, char *data) +{ + panic("Attempt to write data into keyboard memory"); +} + +/* Memory read */ +void ikbd_mem_read(int address, char data[6]) +{ + char cmd[3] = { 0x21, address>>8, address&0xFF }; + + ikbd_write(cmd, 3); + + /* receive data and put it in data */ +} + +/* Controller execute */ +void ikbd_exec(int address) +{ + char cmd[3] = { 0x22, address>>8, address&0xFF }; + + ikbd_write(cmd, 3); +} + +/* Status inquiries (0x87-0x9A) not yet implemented */ + +/* Set the state of the caps lock led. */ +void atari_kbd_leds (unsigned int leds) +{ + char cmd[6] = {32, 0, 4, 1, 254 + ((leds & 4) != 0), 0}; + ikbd_write(cmd, 6); +} + +/* + * The original code sometimes left the interrupt line of + * the ACIAs low forever. I hope, it is fixed now. + * + * Martin Rogge, 20 Aug 1995 + */ + +int atari_keyb_init(void) +{ + /* setup key map */ + key_maps[0] = ataplain_map; + key_maps[1] = atashift_map; + key_maps[2] = 0; /* ataaltgr_map */ + key_maps[4] = atactrl_map; + key_maps[5] = atashift_ctrl_map; + key_maps[8] = ataalt_map; + key_maps[9] = atashift_alt_map; + key_maps[12] = atactrl_alt_map; + key_maps[13] = atashift_ctrl_alt_map; + memcpy (plain_map, ataplain_map, sizeof(plain_map)); + keymap_count = 8; + + /* say that we don't have an AltGr key */ + mach_keyboard_type = KB_84; + + kb_state.state = KEYBOARD; + kb_state.len = 0; + + add_isr(IRQ_MFP_ACIA, keyboard_interrupt, IRQ_TYPE_SLOW, NULL, + "keyboard/mouse/MIDI"); + + atari_turnoff_irq(IRQ_MFP_ACIA); + do { + acia.key_ctrl = ACIA_RESET; /* reset ACIA */ + (void)acia.key_ctrl; + (void)acia.key_data; + + acia.mid_ctrl = ACIA_RESET; /* reset other ACIA */ + (void)acia.mid_ctrl; + (void)acia.mid_data; + + /* divide 500kHz by 64 gives 7812.5 baud */ + /* 8 data no parity 1 start 1 stop bit */ + /* receive interrupt enabled */ +#ifdef KEYB_WRITE_INTERRUPT + /* RTS low, transmit interrupt enabled */ + if (ovsc_switchmode == 1) + acia.key_ctrl = (ACIA_DIV64|ACIA_D8N1S|ACIA_RHTIE|ACIA_RIE); + /* switch on OverScan via keyboard ACIA */ + else + acia.key_ctrl = (ACIA_DIV64|ACIA_D8N1S|ACIA_RLTIE|ACIA_RIE); +#else + /* RTS low, transmit interrupt disabled */ + if (ovsc_switchmode == 1) + acia.key_ctrl = (ACIA_DIV64|ACIA_D8N1S|ACIA_RHTID|ACIA_RIE); + else + acia.key_ctrl = (ACIA_DIV64|ACIA_D8N1S|ACIA_RLTID|ACIA_RIE); +#endif + + acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S; + } + /* make sure the interrupt line is up */ + while ((mfp.par_dt_reg & 0x10) == 0); + + /* enable ACIA Interrupts */ + mfp.active_edge &= ~0x10; + atari_turnon_irq(IRQ_MFP_ACIA); + + ikbd_reset(); + ikbd_mouse_disable(); + ikbd_joystick_disable(); + + atari_joystick_init(); + + return 0; +} + + +int atari_kbdrate( struct kbd_repeat *k ) + +{ + if (k->delay > 0) { + /* convert from msec to jiffies */ + key_repeat_delay = (k->delay * HZ + 500) / 1000; + if (key_repeat_delay < 1) + key_repeat_delay = 1; + } + if (k->rate > 0) { + key_repeat_rate = (k->rate * HZ + 500) / 1000; + if (key_repeat_rate < 1) + key_repeat_rate = 1; + } + + k->delay = key_repeat_delay * 1000 / HZ; + k->rate = key_repeat_rate * 1000 / HZ; + + return( 0 ); +} diff -u --recursive --new-file v1.3.93/linux/arch/m68k/atari/atapart.c linux/arch/m68k/atari/atapart.c --- v1.3.93/linux/arch/m68k/atari/atapart.c Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/atari/atapart.c Sat Mar 30 14:11:04 1996 @@ -0,0 +1,158 @@ +/* + * linux/atari/atapart.c + * + * Atari partition checking driver for 680x0 Linux + * Written by Andreas Schwab (schwab@ls5.informatik.uni-dortmund.de) + * + * 5/3/94 Roman Hodek: + * Added some sanity checks + * Linux device names start from 1 not 0, so I changed the initial value + * for i to 1. + * + * 10/09/94 Guenther Kelleter: + * Added support for ICD/Supra partition info. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file README.legal in the main directory of this archive + * for more details. + */ + +#include +#include +#include + +#include + +/* ++guenther: this should be settable by the user ("make config")?. + */ +#define ICD_PARTS + +extern int current_minor; + +void +atari_check_partition (struct gendisk *hd, unsigned int dev) +{ + int i, minor = current_minor, m_lim = current_minor + hd->max_p; + struct buffer_head *bh; + struct rootsector *rs; + struct partition_info *pi; + ulong extensect; +#ifdef ICD_PARTS + int part_fmt = 0; /* 0:unknown, 1:AHDI, 2:ICD/Supra */ +#endif + + bh = bread (dev, 0, 1024); + if (!bh) + { + printk (" unable to read block 0\n"); + return; + } + + rs = (struct rootsector *) bh->b_data; + printk (" %s%c:", hd->major_name, 'a' + (minor >> hd->minor_shift)); + + pi = &rs->part[0]; + for (i = 1; pi < &rs->part[4] && minor < m_lim; i++, minor++, pi++) + { + if (pi->flg & 1) + /* active partition */ + { + if (memcmp (pi->id, "XGM", 3) == 0) + /* extension partition */ + { + struct rootsector *xrs; + struct buffer_head *xbh; + ulong partsect; + +#ifdef ICD_PARTS + part_fmt = 1; +#endif + partsect = extensect = pi->st; + while (1) + { + xbh = bread (dev, partsect / 2, 1024); + if (!xbh) + { + printk (" block %ld read failed\n", partsect); + return; + } + if (partsect & 1) + xrs = (struct rootsector *) &xbh->b_data[512]; + else + xrs = (struct rootsector *) &xbh->b_data[0]; + + /* ++roman: sanity check: bit 0 of flg field must be set */ + if (!(xrs->part[0].flg & 1)) { + printk( "\nFirst sub-partition in extended partition is not valid!\n" ); + break; + } + + hd->part[minor].start_sect = partsect + xrs->part[0].st; + hd->part[minor].nr_sects = xrs->part[0].siz; + printk (" %s%c%d", hd->major_name, + 'a' + (minor >> hd->minor_shift), i); + + if (!(xrs->part[1].flg & 1)) { + /* end of linked partition list */ + brelse( xbh ); + break; + } + if (memcmp( xrs->part[1].id, "XGM", 3 ) != 0) { + printk( "\nID of extended partion is not XGM!\n" ); + brelse( xbh ); + break; + } + + partsect = xrs->part[1].st + extensect; + brelse (xbh); + i++; + minor++; + if (minor >= m_lim) { + printk( "\nMaximum number of partitions reached!\n" ); + break; + } + } + } + else + { + /* we don't care about other id's */ + hd->part[minor].start_sect = pi->st; + hd->part[minor].nr_sects = pi->siz; + printk (" %s%c%d", hd->major_name, + 'a' + (minor >> hd->minor_shift), i); + + } + } + } +#ifdef ICD_PARTS + if ( part_fmt!=1 ) /* no extended partitions -> test ICD-format */ + { + pi = &rs->icdpart[0]; + /* sanity check: no ICD format if first partion invalid */ + if (memcmp (pi->id, "GEM", 3) == 0 || + memcmp (pi->id, "BGM", 3) == 0 || + memcmp (pi->id, "RAW", 3) == 0 ) + { + for (i = 1; pi < &rs->icdpart[8] && minor < m_lim; i++, minor++, pi++) + { + /* accept only GEM,BGM,RAW partitions */ + if (pi->flg & 1 && + (memcmp (pi->id, "GEM", 3) == 0 || + memcmp (pi->id, "BGM", 3) == 0 || + memcmp (pi->id, "RAW", 3) == 0) ) + { + part_fmt = 2; + hd->part[minor].start_sect = pi->st; + hd->part[minor].nr_sects = pi->siz; + printk (" %s%c%d", hd->major_name, + 'a' + (minor >> hd->minor_shift), i); + } + } + } + } +#endif + brelse (bh); + + printk ("\n"); +} + diff -u --recursive --new-file v1.3.93/linux/arch/m68k/atari/atari.mup linux/arch/m68k/atari/atari.mup --- v1.3.93/linux/arch/m68k/atari/atari.mup Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/atari/atari.mup Wed Dec 27 22:44:02 1995 @@ -0,0 +1,16 @@ +gcc -D__KERNEL__ -O2 -m68030 -c atacon.c -o atacon.o +gcc -D__KERNEL__ -O2 -m68030 -c atasound.c -o atasound.o +gcc -D__KERNEL__ -O2 -m68030 -c ataints.c -o ataints.o +gcc -D__KERNEL__ -O2 -m68030 -c atapart.c -o atapart.o +gcc -D__KERNEL__ -O2 -m68030 -c atakeyb.c -o atakeyb.o +gcc -D__KERNEL__ -O2 -m68030 -c joystick.c -o joystick.o +gcc -D__KERNEL__ -O2 -m68030 -c mouse.c -o mouse.o +gcc -D__KERNEL__ -O2 -m68030 -c config.c -o config.o +gcc -D__KERNEL__ -O2 -m68030 -c font_8x16.c -o font_8x16.o +gcc -D__KERNEL__ -O2 -m68030 -c font_8x8.c -o font_8x8.o +gcc -D__KERNEL__ -O2 -m68030 -c stdma.c -o stdma.o + + +lnx-ld -r -o atari.o atacon.o atasound.o ataints.o atapart.o atakeyb.o config.o font_8x8.o font_8x1.o joystick.o mouse.o stdma.o + +cp atari.o ..\makedir diff -u --recursive --new-file v1.3.93/linux/arch/m68k/atari/atasound.c linux/arch/m68k/atari/atasound.c --- v1.3.93/linux/arch/m68k/atari/atasound.c Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/atari/atasound.c Thu Apr 18 02:04:17 1996 @@ -0,0 +1,150 @@ +/* +linux/arch/m68k/atari/atasound.c + +++Geert: Moved almost all stuff to linux/drivers/sound/ + +The author of atari_nosound, atari_mksound and atari_microwire_cmd is +unknown. +(++roman: That's me... :-) + +This file is subject to the terms and conditions of the GNU General Public +License. See the file README.legal in the main directory of this archive +for more details. + +*/ + + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +/* + * stuff from the old atasound.c + */ + + +static void atari_nosound (unsigned long ignored) +{ + unsigned char tmp; + unsigned long flags; + + /* turn off generator A in mixer control */ + save_flags(flags); + cli(); + sound_ym.rd_data_reg_sel = 7; + tmp = sound_ym.rd_data_reg_sel; + sound_ym.wd_data = tmp | 0x39; + restore_flags(flags); +} + + +void atari_microwire_cmd (int cmd) +{ + tt_microwire.mask = 0x7ff; + tt_microwire.data = MW_LM1992_ADDR | cmd; + + /* Busy wait for data being completely sent :-( */ + while( tt_microwire.mask != 0x7ff) + ; +} + + +#define PC_FREQ 1192180 +#define PSG_FREQ 125000 + + +void atari_mksound (unsigned int count, unsigned int ticks) +{ + static struct timer_list sound_timer = { NULL, NULL, 0, 0, + atari_nosound }; + /* + * Generates sound of some count for some number of clock ticks + * [count = 1193180 / frequency] + */ + unsigned long flags; + unsigned char tmp; + + save_flags(flags); + cli(); + + if (count == 750 && ticks == HZ/8) { + /* Special case: These values are used by console.c to + * generate the console bell. They are catched here and the + * sound actually generated is somehow special: it uses the + * generator B and an envelope. No timer is needed therefore + * and the bell doesn't disturb an other ongoing sound. + */ + + /* set envelope duration to 492 ms */ + sound_ym.rd_data_reg_sel = 11; + sound_ym.wd_data = 0; + sound_ym.rd_data_reg_sel = 12; + sound_ym.wd_data = 15; + /* envelope form: max -> min single */ + sound_ym.rd_data_reg_sel = 13; + sound_ym.wd_data = 9; + /* set generator B frequency to 2400 Hz */ + sound_ym.rd_data_reg_sel = 2; + sound_ym.wd_data = 52; + sound_ym.rd_data_reg_sel = 3; + sound_ym.wd_data = 0; + /* set volume of generator B to envelope control */ + sound_ym.rd_data_reg_sel = 9; + sound_ym.wd_data = 0x10; + /* enable generator B in the mixer control */ + sound_ym.rd_data_reg_sel = 7; + tmp = sound_ym.rd_data_reg_sel; + sound_ym.wd_data = (tmp & ~0x02) | 0x38; + + restore_flags(flags); + return; + } + + del_timer( &sound_timer ); + + if (!count) { + atari_nosound( 0 ); + } + else { + + /* convert from PC counter value (base frequency 1.193 MHz) + * to PSG period value (base frequency 125 kHz). + */ + int period = (PSG_FREQ * count + PC_FREQ/2) / PC_FREQ; + + if (period > 0xfff) period = 0xfff; + + /* set generator A frequency to 0 */ + sound_ym.rd_data_reg_sel = 0; + sound_ym.wd_data = period & 0xff; + sound_ym.rd_data_reg_sel = 1; + sound_ym.wd_data = (period >> 8) & 0xf; + /* turn on generator A in mixer control (but not noise + * generator!) */ + sound_ym.rd_data_reg_sel = 7; + tmp = sound_ym.rd_data_reg_sel; + sound_ym.wd_data = (tmp & ~0x01) | 0x38; + /* set generator A level to maximum, no envelope */ + sound_ym.rd_data_reg_sel = 8; + sound_ym.wd_data = 15; + + if (ticks) { + sound_timer.expires = jiffies + ticks; + add_timer( &sound_timer ); + } + } + + restore_flags(flags); +} diff -u --recursive --new-file v1.3.93/linux/arch/m68k/atari/atasound.h linux/arch/m68k/atari/atasound.h --- v1.3.93/linux/arch/m68k/atari/atasound.h Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/atari/atasound.h Mon Mar 4 22:36:02 1996 @@ -0,0 +1,33 @@ +/* + * Minor numbers for the sound driver. + * + * Unfortunately Creative called the codec chip of SB as a DSP. For this + * reason the /dev/dsp is reserved for digitized audio use. There is a + * device for true DSP processors but it will be called something else. + * In v3.0 it's /dev/sndproc but this could be a temporary solution. + */ + +#define SND_NDEVS 256 /* Number of supported devices */ +#define SND_DEV_CTL 0 /* Control port /dev/mixer */ +#define SND_DEV_SEQ 1 /* Sequencer output /dev/sequencer (FM + synthesizer and MIDI output) */ +#define SND_DEV_MIDIN 2 /* Raw midi access */ +#define SND_DEV_DSP 3 /* Digitized voice /dev/dsp */ +#define SND_DEV_AUDIO 4 /* Sparc compatible /dev/audio */ +#define SND_DEV_DSP16 5 /* Like /dev/dsp but 16 bits/sample */ +#define SND_DEV_STATUS 6 /* /dev/sndstat */ +/* #7 not in use now. Was in 2.4. Free for use after v3.0. */ +#define SND_DEV_SEQ2 8 /* /dev/sequencer, level 2 interface */ +#define SND_DEV_SNDPROC 9 /* /dev/sndproc for programmable devices */ +#define SND_DEV_PSS SND_DEV_SNDPROC + +#define DSP_DEFAULT_SPEED 8000 + +#define ON 1 +#define OFF 0 + +#define MAX_AUDIO_DEV 5 +#define MAX_MIXER_DEV 2 +#define MAX_SYNTH_DEV 3 +#define MAX_MIDI_DEV 6 +#define MAX_TIMER_DEV 3 diff -u --recursive --new-file v1.3.93/linux/arch/m68k/atari/config.c linux/arch/m68k/atari/config.c --- v1.3.93/linux/arch/m68k/atari/config.c Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/atari/config.c Fri Apr 19 02:41:15 1996 @@ -0,0 +1,1155 @@ +/* + * linux/atari/config.c + * + * Copyright (C) 1994 Bj”rn Brauel + * + * 5/2/94 Roman Hodek: + * Added setting of time_adj to get a better clock. + * + * 5/14/94 Roman Hodek: + * gettod() for TT + * + * 5/15/94 Roman Hodek: + * hard_reset_now() for Atari (and others?) + * + * 94/12/30 Andreas Schwab: + * atari_sched_init fixed to get precise clock. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file README.legal in the main directory of this archive + * for more details. + */ + +/* + * Miscellaneous atari stuff + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +extern void atari_sched_init(isrfunc); +extern int atari_keyb_init(void); +extern int atari_kbdrate (struct kbd_repeat *); +extern void atari_kbd_leds (unsigned int); +extern void atari_init_INTS (void); +extern int atari_add_isr (unsigned long, isrfunc, int, void *, char *); +extern int atari_remove_isr (unsigned long, isrfunc); +extern void atari_enable_irq (unsigned); +extern void atari_disable_irq (unsigned); +extern int atari_get_irq_list (char *buf, int len); +extern unsigned long atari_gettimeoffset (void); +extern void atari_mste_gettod (int *, int *, int *, int *, int *, int *); +extern void atari_gettod (int *, int *, int *, int *, int *, int *); +extern int atari_mste_hwclk (int, struct hwclk_time *); +extern int atari_hwclk (int, struct hwclk_time *); +extern int atari_mste_set_clock_mmss (unsigned long); +extern int atari_set_clock_mmss (unsigned long); +extern void atari_check_partition (struct gendisk *hd, unsigned int dev); +extern void atari_mksound( unsigned int count, unsigned int ticks ); +extern void atari_reset( void ); +#ifdef CONFIG_BLK_DEV_FD +extern int atari_floppy_init (void); +extern void atari_floppy_setup(char *, int *); +#endif +extern void atari_waitbut (void); +extern struct consw fb_con; +extern struct fb_info *atari_fb_init(long *); +extern void atari_debug_init (void); +extern void atari_video_setup(char *, int *); + +extern void (*kd_mksound)(unsigned int, unsigned int); + +/* This function tests for the presence of an address, specially a + * hardware register address. It is called very early in the kernel + * initialization process, when the VBR register isn't set up yet. On + * an Atari, it still points to address 0, which is unmapped. So a bus + * error would cause another bus error while fetching the exception + * vector, and the CPU would do nothing at all. So we needed to set up + * a temporary VBR and a vector table for the duration of the test. + */ + +static int hwreg_present( volatile void *regp ) +{ + int ret = 0; + long save_sp, save_vbr; + long tmp_vectors[3]; + + __asm__ __volatile__ + ( "movec %/vbr,%2\n\t" + "movel #Lberr1,%4@(8)\n\t" + "movec %4,%/vbr\n\t" + "movel %/sp,%1\n\t" + "moveq #0,%0\n\t" + "tstb %3@\n\t" + "nop\n\t" + "moveq #1,%0\n" + "Lberr1:\n\t" + "movel %1,%/sp\n\t" + "movec %2,%/vbr" + : "=&d" (ret), "=&r" (save_sp), "=&r" (save_vbr) + : "a" (regp), "a" (tmp_vectors) + ); + + return( ret ); +} + +#if 0 +static int hwreg_present_bywrite( volatile void *regp, + unsigned char val ) + +{ + int ret; + long save_sp, save_vbr; + static long tmp_vectors[3] = { 0, 0, (long)&&after_test }; + + __asm__ __volatile__ + ( "movec %/vbr,%2\n\t" /* save vbr value */ + "movec %4,%/vbr\n\t" /* set up temporary vectors */ + "movel %/sp,%1\n\t" /* save sp */ + "moveq #0,%0\n\t" /* assume not present */ + "moveb %5,%3@\n\t" /* write the hardware reg */ + "cmpb %3@,%5\n\t" /* compare it */ + "seq %0" /* comes here only if reg */ + /* is present */ + : "=d&" (ret), "=r&" (save_sp), "=r&" (save_vbr) + : "a" (regp), "r" (tmp_vectors), "d" (val) + ); + after_test: + __asm__ __volatile__ + ( "movel %0,%/sp\n\t" /* restore sp */ + "movec %1,%/vbr" /* restore vbr */ + : : "r" (save_sp), "r" (save_vbr) : "sp" + ); + + return( ret ); +} +#endif + +/* Basically the same, but writes a value into a word register, protected + * by a bus error handler */ + +static int hwreg_write( volatile void *regp, unsigned short val ) +{ + int ret; + long save_sp, save_vbr; + long tmp_vectors[3]; + + __asm__ __volatile__ + ( "movec %/vbr,%2\n\t" + "movel #Lberr2,%4@(8)\n\t" + "movec %4,%/vbr\n\t" + "movel %/sp,%1\n\t" + "moveq #0,%0\n\t" + "movew %5,%3@\n\t" + "nop \n\t" /* If this nop isn't present, 'ret' may already be + * loaded with 1 at the time the bus error + * happens! */ + "moveq #1,%0\n" + "Lberr2:\n\t" + "movel %1,%/sp\n\t" + "movec %2,%/vbr" + : "=&d" (ret), "=&r" (save_sp), "=&r" (save_vbr) + : "a" (regp), "a" (tmp_vectors), "g" (val) + ); + + return( ret ); +} + +/* ++roman: This is a more elaborate test for an SCC chip, since the plain + * Medusa board generates DTACK at the SCC's standard addresses, but a SCC + * board in the Medusa is possible. Also, the addresses where the ST_ESCC + * resides generate DTACK without the chip, too. + * The method is to write values into the interrupt vector register, that + * should be readable without trouble (from channel A!). + */ + +static int scc_test( volatile char *ctla ) +{ + if (!hwreg_present( ctla )) + return( 0 ); + MFPDELAY(); + + *ctla = 2; MFPDELAY(); + *ctla = 0x40; MFPDELAY(); + + *ctla = 2; MFPDELAY(); + if (*ctla != 0x40) return( 0 ); + MFPDELAY(); + + *ctla = 2; MFPDELAY(); + *ctla = 0x60; MFPDELAY(); + + *ctla = 2; MFPDELAY(); + if (*ctla != 0x60) return( 0 ); + + return( 1 ); +} + +void config_atari(void) +{ + mach_sched_init = atari_sched_init; + mach_keyb_init = atari_keyb_init; + mach_kbdrate = atari_kbdrate; + mach_kbd_leds = atari_kbd_leds; + mach_init_INTS = atari_init_INTS; + mach_add_isr = atari_add_isr; + mach_remove_isr = atari_remove_isr; + mach_enable_irq = atari_enable_irq; + mach_disable_irq = atari_disable_irq; + mach_get_irq_list = atari_get_irq_list; + mach_gettimeoffset = atari_gettimeoffset; + mach_check_partition = atari_check_partition; + mach_mksound = atari_mksound; + mach_reset = atari_reset; +#ifdef CONFIG_BLK_DEV_FD + mach_floppy_init = atari_floppy_init; + mach_floppy_setup = atari_floppy_setup; +#endif + conswitchp = &fb_con; + waitbut = atari_waitbut; + mach_fb_init = atari_fb_init; + mach_max_dma_address = 0xffffff; + mach_debug_init = atari_debug_init; + mach_video_setup = atari_video_setup; + kd_mksound = atari_mksound; + + /* ++bjoern: + * Determine hardware present + */ + + printk( "Atari hardware found: " ); + if (is_medusa) { + /* There's no Atari video hardware on the Medusa, but all the + * addresses below generate a DTACK so no bus error occurs! */ + } + else if (hwreg_present( f030_xreg )) { + ATARIHW_SET(VIDEL_SHIFTER); + printk( "VIDEL " ); + /* This is a temporary hack: If there is Falcon video + * hardware, we assume that the ST-DMA serves SCSI instead of + * ACSI. In the future, there should be a better method for + * this... + */ + ATARIHW_SET(ST_SCSI); + printk( "STDMA-SCSI " ); + } + else if (hwreg_present( tt_palette )) { + ATARIHW_SET(TT_SHIFTER); + printk( "TT_SHIFTER " ); + } + else if (hwreg_present( &shifter.bas_hi )) { + if (hwreg_present( &shifter.bas_lo ) && + (shifter.bas_lo = 0x0aau, shifter.bas_lo == 0x0aau)) { + ATARIHW_SET(EXTD_SHIFTER); + printk( "EXTD_SHIFTER " ); + } + else { + ATARIHW_SET(STND_SHIFTER); + printk( "STND_SHIFTER " ); + } + } + if (hwreg_present( &mfp.par_dt_reg )) { + ATARIHW_SET(ST_MFP); + printk( "ST_MFP " ); + } + if (hwreg_present( &tt_mfp.par_dt_reg )) { + ATARIHW_SET(TT_MFP); + printk( "TT_MFP " ); + } + if (hwreg_present( &tt_scsi_dma.dma_addr_hi )) { + ATARIHW_SET(SCSI_DMA); + printk( "TT_SCSI_DMA " ); + } + if (hwreg_present( &st_dma.dma_hi )) { + ATARIHW_SET(STND_DMA); + printk( "STND_DMA " ); + } + if (is_medusa || /* The ST-DMA address registers aren't readable + * on all Medusas, so the test below may fail */ + (hwreg_present( &st_dma.dma_vhi ) && + (st_dma.dma_vhi = 0x55) && (st_dma.dma_hi = 0xaa) && + st_dma.dma_vhi == 0x55 && st_dma.dma_hi == 0xaa && + (st_dma.dma_vhi = 0xaa) && (st_dma.dma_hi = 0x55) && + st_dma.dma_vhi == 0xaa && st_dma.dma_hi == 0x55)) { + ATARIHW_SET(EXTD_DMA); + printk( "EXTD_DMA " ); + } + if (hwreg_present( &tt_scsi.scsi_data )) { + ATARIHW_SET(TT_SCSI); + printk( "TT_SCSI " ); + } + if (hwreg_present( &sound_ym.rd_data_reg_sel )) { + ATARIHW_SET(YM_2149); + printk( "YM2149 " ); + } + if (!is_medusa && hwreg_present( &tt_dmasnd.ctrl )) { + ATARIHW_SET(PCM_8BIT); + printk( "PCM " ); + } + if (hwreg_present( (void *)(0xffff8940) )) { + ATARIHW_SET(CODEC); + printk( "CODEC " ); + } + if (hwreg_present( &tt_scc_dma.dma_ctrl ) && +#if 0 + /* This test sucks! Who knows some better? */ + (tt_scc_dma.dma_ctrl = 0x01, (tt_scc_dma.dma_ctrl & 1) == 1) && + (tt_scc_dma.dma_ctrl = 0x00, (tt_scc_dma.dma_ctrl & 1) == 0) +#else + !is_medusa +#endif + ) { + ATARIHW_SET(SCC_DMA); + printk( "SCC_DMA " ); + } + if (scc_test( &scc.cha_a_ctrl )) { + ATARIHW_SET(SCC); + printk( "SCC " ); + } + if (scc_test( &st_escc.cha_b_ctrl )) { + ATARIHW_SET( ST_ESCC ); + printk( "ST_ESCC " ); + } + if (hwreg_present( &tt_scu.sys_mask )) { + ATARIHW_SET(SCU); + /* Assume a VME bus if there's a SCU */ + ATARIHW_SET( VME ); + printk( "VME SCU " ); + } + if (hwreg_present( (void *)(0xffff9210) )) { + ATARIHW_SET(ANALOG_JOY); + printk( "ANALOG_JOY " ); + } + if (hwreg_present( blitter.halftone )) { + ATARIHW_SET(BLITTER); + printk( "BLITTER " ); + } + if (hwreg_present( (void *)(ATA_HD_BASE+ATA_HD_CMD) )) { + ATARIHW_SET(IDE); + printk( "IDE " ); + } +#if 1 /* This maybe wrong */ + if (!is_medusa && + hwreg_present( &tt_microwire.data ) && + hwreg_present( &tt_microwire.mask ) && + (tt_microwire.mask = 0x7ff, + tt_microwire.data = MW_LM1992_PSG_HIGH | MW_LM1992_ADDR, + tt_microwire.data != 0)) { + ATARIHW_SET(MICROWIRE); + while (tt_microwire.mask != 0x7ff) ; + printk( "MICROWIRE " ); + } +#endif + if (hwreg_present( &tt_rtc.regsel )) { + ATARIHW_SET(TT_CLK); + printk( "TT_CLK " ); + mach_gettod = atari_gettod; + mach_hwclk = atari_hwclk; + mach_set_clock_mmss = atari_set_clock_mmss; + } + if (hwreg_present( &mste_rtc.sec_ones)) { + ATARIHW_SET(MSTE_CLK); + printk( "MSTE_CLK "); + mach_gettod = atari_mste_gettod; + mach_hwclk = atari_mste_hwclk; + mach_set_clock_mmss = atari_mste_set_clock_mmss; + } + if (!is_medusa && + hwreg_present( &dma_wd.fdc_speed ) && + hwreg_write( &dma_wd.fdc_speed, 0 )) { + ATARIHW_SET(FDCSPEED); + printk( "FDC_SPEED "); + } + if (!ATARIHW_PRESENT(ST_SCSI)) { + ATARIHW_SET(ACSI); + printk( "ACSI " ); + } + printk("\n"); + + if (m68k_is040or060) + /* Now it seems to be safe to turn of the tt0 transparent + * translation (the one that must not be turned off in + * head.S...) + */ + __asm__ volatile ("moveq #0,%/d0;" + ".long 0x4e7b0004;" /* movec d0,itt0 */ + ".long 0x4e7b0006;" /* movec d0,dtt0 */ + : /* no outputs */ + : /* no inputs */ + : "d0"); + + /* allocator for memory that must reside in st-ram */ + atari_stram_init (); + + /* Set up a mapping for the VMEbus address region: + * + * VME is either at phys. 0xfexxxxxx (TT) or 0xa00000..0xdfffff + * (MegaSTE) In both cases, the whole 16 MB chunk is mapped at + * 0xfe000000 virt., because this can be done with a single + * transparent translation. On the 68040, lots of often unused + * page tables would be needed otherwise. On a MegaSTE or similar, + * the highest byte is stripped off by hardware due to the 24 bit + * design of the bus. + */ + + if (!m68k_is040or060) { + unsigned long tt1_val; + tt1_val = 0xfe008543; /* Translate 0xfexxxxxx, enable, cache + * inhibit, read and write, FDC mask = 3, + * FDC val = 4 -> Supervisor only */ + __asm__ __volatile__ ( "pmove %0@,%/tt1" : : "a" (&tt1_val) ); + } + else { + __asm__ __volatile__ + ( "movel %0,%/d0\n\t" + ".long 0x4e7b0005\n\t" /* movec d0,itt1 */ + ".long 0x4e7b0007" /* movec d0,dtt1 */ + : + : "g" (0xfe00a040) /* Translate 0xfexxxxxx, enable, + * supervisor only, non-cacheable/ + * serialized, writable */ + : "d0" ); + + } +} + +void atari_sched_init (isrfunc timer_routine) +{ + /* set Timer C data Register */ + mfp.tim_dt_c = INT_TICKS; + /* start timer C, div = 1:100 */ + mfp.tim_ct_cd = (mfp.tim_ct_cd & 15) | 0x60; + /* install interrupt service routine for MFP Timer C */ + add_isr (IRQ_MFP_TIMC, timer_routine, IRQ_TYPE_SLOW, NULL, "timer"); +} + +/* ++andreas: gettimeoffset fixed to check for pending interrupt */ + +#define TICK_SIZE 10000 + +/* This is always executed with interrupts disabled. */ +unsigned long atari_gettimeoffset (void) +{ + unsigned long ticks, offset = 0; + + /* read MFP timer C current value */ + ticks = mfp.tim_dt_c; + /* The probability of underflow is less than 2% */ + if (ticks > INT_TICKS - INT_TICKS / 50) + /* Check for pending timer interrupt */ + if (mfp.int_pn_b & (1 << 5)) + offset = TICK_SIZE; + + ticks = INT_TICKS - ticks; + ticks = ticks * 10000L / INT_TICKS; + + return ticks + offset; +} + + +static void +mste_read(struct MSTE_RTC *val) +{ +#define COPY(v) val->v=(mste_rtc.v & 0xf) + do { + COPY(sec_ones) ; COPY(sec_tens) ; COPY(min_ones) ; + COPY(min_tens) ; COPY(hr_ones) ; COPY(hr_tens) ; + COPY(weekday) ; COPY(day_ones) ; COPY(day_tens) ; + COPY(mon_ones) ; COPY(mon_tens) ; COPY(year_ones) ; + COPY(year_tens) ; + /* prevent from reading the clock while it changed */ + } while (val->sec_ones != (mste_rtc.sec_ones & 0xf)); +#undef COPY +} + +static void +mste_write(struct MSTE_RTC *val) +{ +#define COPY(v) mste_rtc.v=val->v + do { + COPY(sec_ones) ; COPY(sec_tens) ; COPY(min_ones) ; + COPY(min_tens) ; COPY(hr_ones) ; COPY(hr_tens) ; + COPY(weekday) ; COPY(day_ones) ; COPY(day_tens) ; + COPY(mon_ones) ; COPY(mon_tens) ; COPY(year_ones) ; + COPY(year_tens) ; + /* prevent from writing the clock while it changed */ + } while (val->sec_ones != (mste_rtc.sec_ones & 0xf)); +#undef COPY +} + +#define RTC_READ(reg) \ + ({ unsigned char __val; \ + outb(reg,&tt_rtc.regsel); \ + __val = tt_rtc.data; \ + __val; \ + }) + +#define RTC_WRITE(reg,val) \ + do { \ + outb(reg,&tt_rtc.regsel); \ + tt_rtc.data = (val); \ + } while(0) + + +void atari_mste_gettod (int *yearp, int *monp, int *dayp, + int *hourp, int *minp, int *secp) +{ + int hr24=0; + struct MSTE_RTC val; + + mste_rtc.mode=(mste_rtc.mode | 1); + hr24=mste_rtc.mon_tens & 1; + mste_rtc.mode=(mste_rtc.mode & ~1); + + mste_read(&val); + *secp = val.sec_ones + val.sec_tens * 10; + *minp = val.min_ones + val.min_tens * 10; + if (hr24) + *hourp = val.hr_ones + val.hr_tens * 10; + else { + *hourp = val.hr_ones + (val.hr_tens & 1) * 10; + if (val.hr_tens & 2) + *hourp += 12; + } + *dayp = val.day_ones + val.day_tens * 10; + *monp = val.mon_ones + val.mon_tens * 10; + *yearp = val.year_ones + val.year_tens * 10 + 80; +} + + +void atari_gettod (int *yearp, int *monp, int *dayp, + int *hourp, int *minp, int *secp) +{ + unsigned char ctrl; + unsigned short tos_version; + + while (!(RTC_READ(RTC_FREQ_SELECT) & RTC_UIP)) ; + while (RTC_READ(RTC_FREQ_SELECT) & RTC_UIP) ; + + *secp = RTC_READ(RTC_SECONDS); + *minp = RTC_READ(RTC_MINUTES); + *hourp = RTC_READ(RTC_HOURS); + *dayp = RTC_READ(RTC_DAY_OF_MONTH); + *monp = RTC_READ(RTC_MONTH); + *yearp = RTC_READ(RTC_YEAR); + + ctrl = RTC_READ(RTC_CONTROL); + + if (!(ctrl & RTC_DM_BINARY)) { + BCD_TO_BIN(*secp); + BCD_TO_BIN(*minp); + BCD_TO_BIN(*hourp); + BCD_TO_BIN(*dayp); + BCD_TO_BIN(*monp); + BCD_TO_BIN(*yearp); + } + if (!(ctrl & RTC_24H)) { + if (*hourp & 0x80) { + *hourp &= ~0x80; + *hourp += 12; + } + } + /* Adjust values (let the setup valid) */ + + /* Fetch tos version at Physical 2 */ + /* We my not be able to access this address if the kernel is + loaded to st ram, since the first page is unmapped. On the + Medusa this is always the case and there is nothing we can do + about this, so we just assume the smaller offset. For the TT + we use the fact that in head.S we have set up a mapping + 0xFFxxxxxx -> 0x00xxxxxx, so that the first 16MB is accessible + in the last 16MB of the address space. */ + tos_version = is_medusa ? 0xfff : *(unsigned short *)0xFF000002; + *yearp += (tos_version < 0x306) ? 70 : 68; +} + +#define HWCLK_POLL_INTERVAL 5 + +int atari_mste_hwclk( int op, struct hwclk_time *t ) +{ + int hour, year; + int hr24=0; + struct MSTE_RTC val; + + mste_rtc.mode=(mste_rtc.mode | 1); + hr24=mste_rtc.mon_tens & 1; + mste_rtc.mode=(mste_rtc.mode & ~1); + + if (op) { + /* write: prepare values */ + + val.sec_ones = t->sec % 10; + val.sec_tens = t->sec / 10; + val.min_ones = t->min % 10; + val.min_tens = t->min / 10; + hour = t->hour; + val.hr_ones = hour % 10; + val.hr_tens = hour / 10; + if (!hr24 && hour > 11) { + hour -= 12; + val.hr_ones = hour % 10; + val.hr_tens = (hour / 10) | 2; + } + val.day_ones = t->day % 10; + val.day_tens = t->day / 10; + val.mon_ones = (t->mon+1) % 10; + val.mon_tens = (t->mon+1) / 10; + year = t->year - 80; + val.year_ones = year % 10; + val.year_tens = year / 10; + val.weekday = t->wday; + mste_write(&val); + mste_rtc.mode=(mste_rtc.mode | 1); + val.year_ones = (year % 4); /* leap year register */ + mste_rtc.mode=(mste_rtc.mode & ~1); + } + else { + mste_read(&val); + t->sec = val.sec_ones + val.sec_tens * 10; + t->min = val.min_ones + val.min_tens * 10; + if (hr24) + t->hour = val.hr_ones + val.hr_tens * 10; + else { + t->hour = val.hr_ones + (val.hr_tens & 1) * 10; + if (val.hr_tens & 2) + t->hour += 12; + } + t->day = val.day_ones + val.day_tens * 10; + t->mon = val.mon_ones + val.mon_tens * 10 - 1; + t->year = val.year_ones + val.year_tens * 10 + 80; + t->wday = val.weekday; + } + return 0; +} + +int atari_hwclk( int op, struct hwclk_time *t ) +{ + int sec=0, min=0, hour=0, day=0, mon=0, year=0, wday=0; + unsigned long flags; + unsigned short tos_version; + unsigned char ctrl; + + /* Tos version at Physical 2. See above for explanation why we + cannot use PTOV(2). */ + tos_version = is_medusa ? 0xfff : *(unsigned short *)0xff000002; + + ctrl = RTC_READ(RTC_CONTROL); /* control registers are + * independant from the UIP */ + + if (op) { + /* write: prepare values */ + + sec = t->sec; + min = t->min; + hour = t->hour; + day = t->day; + mon = t->mon + 1; + year = t->year - ((tos_version < 0x306) ? 70 : 68); + wday = t->wday + (t->wday >= 0); + + if (!(ctrl & RTC_24H) && hour > 11) { + hour -= 12; + hour |= 0x80; + } + + if (!(ctrl & RTC_DM_BINARY)) { + BIN_TO_BCD(sec); + BIN_TO_BCD(min); + BIN_TO_BCD(hour); + BIN_TO_BCD(day); + BIN_TO_BCD(mon); + BIN_TO_BCD(year); + if (wday >= 0) BIN_TO_BCD(wday); + } + } + + /* Reading/writing the clock registers is a bit critical due to + * the regular update cycle of the RTC. While an update is in + * progress, registers 0..9 shouldn't be touched. + * The problem is solved like that: If an update is currently in + * progress (the UIP bit is set), the process sleeps for a while + * (50ms). This really should be enough, since the update cycle + * normally needs 2 ms. + * If the UIP bit reads as 0, we have at least 244 usecs until the + * update starts. This should be enough... But to be sure, + * additionally the RTC_SET bit is set to prevent an update cycle. + */ + + while( RTC_READ(RTC_FREQ_SELECT) & RTC_UIP ) { + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + HWCLK_POLL_INTERVAL; + schedule(); + } + + save_flags(flags); + cli(); + RTC_WRITE( RTC_CONTROL, ctrl | RTC_SET ); + if (!op) { + sec = RTC_READ( RTC_SECONDS ); + min = RTC_READ( RTC_MINUTES ); + hour = RTC_READ( RTC_HOURS ); + day = RTC_READ( RTC_DAY_OF_MONTH ); + mon = RTC_READ( RTC_MONTH ); + year = RTC_READ( RTC_YEAR ); + wday = RTC_READ( RTC_DAY_OF_WEEK ); + } + else { + RTC_WRITE( RTC_SECONDS, sec ); + RTC_WRITE( RTC_MINUTES, min ); + RTC_WRITE( RTC_HOURS, hour ); + RTC_WRITE( RTC_DAY_OF_MONTH, day ); + RTC_WRITE( RTC_MONTH, mon ); + RTC_WRITE( RTC_YEAR, year ); + if (wday >= 0) RTC_WRITE( RTC_DAY_OF_WEEK, wday ); + } + RTC_WRITE( RTC_CONTROL, ctrl & ~RTC_SET ); + restore_flags(flags); + + if (!op) { + /* read: adjust values */ + + if (!(ctrl & RTC_DM_BINARY)) { + BCD_TO_BIN(sec); + BCD_TO_BIN(min); + BCD_TO_BIN(hour); + BCD_TO_BIN(day); + BCD_TO_BIN(mon); + BCD_TO_BIN(year); + BCD_TO_BIN(wday); + } + + if (!(ctrl & RTC_24H)) { + if (hour & 0x80) { + hour &= ~0x80; + hour += 12; + } + } + + t->sec = sec; + t->min = min; + t->hour = hour; + t->day = day; + t->mon = mon - 1; + t->year = year + ((tos_version < 0x306) ? 70 : 68); + t->wday = wday - 1; + } + + return( 0 ); +} + + +int atari_mste_set_clock_mmss (unsigned long nowtime) +{ + short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60; + struct MSTE_RTC val; + unsigned char rtc_minutes; + + mste_read(&val); + rtc_minutes= val.min_ones + val.min_tens * 10; + if ((rtc_minutes < real_minutes + ? real_minutes - rtc_minutes + : rtc_minutes - real_minutes) < 30) + { + val.sec_ones = real_seconds % 10; + val.sec_tens = real_seconds / 10; + val.min_ones = real_minutes % 10; + val.min_tens = real_minutes / 10; + mste_write(&val); + } + else + return -1; + return 0; +} + +int atari_set_clock_mmss (unsigned long nowtime) +{ + int retval = 0; + short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60; + unsigned char save_control, save_freq_select, rtc_minutes; + + save_control = RTC_READ (RTC_CONTROL); /* tell the clock it's being set */ + RTC_WRITE (RTC_CONTROL, save_control | RTC_SET); + + save_freq_select = RTC_READ (RTC_FREQ_SELECT); /* stop and reset prescaler */ + RTC_WRITE (RTC_FREQ_SELECT, save_freq_select | RTC_DIV_RESET2); + + rtc_minutes = RTC_READ (RTC_MINUTES); + if (!(save_control & RTC_DM_BINARY)) + BCD_TO_BIN (rtc_minutes); + + /* Since we're only adjusting minutes and seconds, don't interfere + with hour overflow. This avoids messing with unknown time zones + but requires your RTC not to be off by more than 30 minutes. */ + if ((rtc_minutes < real_minutes + ? real_minutes - rtc_minutes + : rtc_minutes - real_minutes) < 30) + { + if (!(save_control & RTC_DM_BINARY)) + { + BIN_TO_BCD (real_seconds); + BIN_TO_BCD (real_minutes); + } + RTC_WRITE (RTC_SECONDS, real_seconds); + RTC_WRITE (RTC_MINUTES, real_minutes); + } + else + retval = -1; + + RTC_WRITE (RTC_FREQ_SELECT, save_freq_select); + RTC_WRITE (RTC_CONTROL, save_control); + return retval; +} + + +void atari_waitbut (void) +{ + /* sorry, no-op */ +} + + +static inline void ata_mfp_out (char c) +{ + while (!(mfp.trn_stat & 0x80)) /* wait for tx buf empty */ + barrier (); + mfp.usart_dta = c; +} + +void ata_mfp_print (const char *str) +{ + for( ; *str; ++str ) { + if (*str == '\n') + ata_mfp_out( '\r' ); + ata_mfp_out( *str ); + } +} + +static inline void ata_scc_out (char c) +{ + do { + MFPDELAY(); + } while (!(scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */ + MFPDELAY(); + scc.cha_b_data = c; +} + +void ata_scc_print (const char *str) +{ + for( ; *str; ++str ) { + if (*str == '\n') + ata_scc_out( '\r' ); + ata_scc_out( *str ); + } +} + +static int ata_par_out (char c) +{ + extern unsigned long loops_per_sec; + unsigned char tmp; + /* This a some-seconds timeout in case no printer is connected */ + unsigned long i = loops_per_sec > 1 ? loops_per_sec : 10000000; + + while( (mfp.par_dt_reg & 1) && --i ) /* wait for BUSY == L */ + ; + if (!i) return( 0 ); + + sound_ym.rd_data_reg_sel = 15; /* select port B */ + sound_ym.wd_data = c; /* put char onto port */ + sound_ym.rd_data_reg_sel = 14; /* select port A */ + tmp = sound_ym.rd_data_reg_sel; + sound_ym.wd_data = tmp & ~0x20; /* set strobe L */ + MFPDELAY(); /* wait a bit */ + sound_ym.wd_data = tmp | 0x20; /* set strobe H */ + return( 1 ); +} + +void ata_par_print (const char *str) +{ + static int printer_present = 1; + + if (!printer_present) + return; + + for( ; *str; ++str ) { + if (*str == '\n') + if (!ata_par_out( '\r' )) { + printer_present = 0; + return; + } + if (!ata_par_out( *str )) { + printer_present = 0; + return; + } + } +} + + +void atari_debug_init( void ) +{ + extern void (*debug_print_proc)(const char *); + extern char m68k_debug_device[]; + + if (!strcmp( m68k_debug_device, "ser" )) { + /* defaults to ser2 for a Falcon and ser1 otherwise */ + strcpy( m68k_debug_device, + ((boot_info.bi_atari.mch_cookie >> 16) == ATARI_MCH_FALCON) ? + "ser2" : "ser1" ); + + } + + if (!strcmp( m68k_debug_device, "ser1" )) { + /* ST-MFP Modem1 serial port */ + mfp.trn_stat &= ~0x01; /* disable TX */ + mfp.usart_ctr = 0x88; /* clk 1:16, 8N1 */ + mfp.tim_ct_cd &= 0x70; /* stop timer D */ + mfp.tim_dt_d = 2; /* 9600 bps */ + mfp.tim_ct_cd |= 0x01; /* start timer D, 1:4 */ + mfp.trn_stat |= 0x01; /* enable TX */ + debug_print_proc = ata_mfp_print; + } + else if (!strcmp( m68k_debug_device, "ser2" )) { + /* SCC Modem2 serial port */ + static unsigned char *p, scc_table[] = { + 9, 12, /* Reset */ + 4, 0x44, /* x16, 1 stopbit, no parity */ + 3, 0xc0, /* receiver: 8 bpc */ + 5, 0xe2, /* transmitter: 8 bpc, assert dtr/rts */ + 9, 0, /* no interrupts */ + 10, 0, /* NRZ */ + 11, 0x50, /* use baud rate generator */ + 12, 24, 13, 0, /* 9600 baud */ + 14, 2, 14, 3, /* use master clock for BRG, enable */ + 3, 0xc1, /* enable receiver */ + 5, 0xea, /* enable transmitter */ + 0 + }; + + (void)scc.cha_b_ctrl; /* reset reg pointer */ + for( p = scc_table; *p != 0; ) { + scc.cha_b_ctrl = *p++; + MFPDELAY(); + scc.cha_b_ctrl = *p++; + MFPDELAY(); + } + debug_print_proc = ata_scc_print; + } + else if (!strcmp( m68k_debug_device, "par" )) { + /* parallel printer */ + atari_turnoff_irq( IRQ_MFP_BUSY ); /* avoid ints */ + sound_ym.rd_data_reg_sel = 7; /* select mixer control */ + sound_ym.wd_data = 0xff; /* sound off, ports are output */ + sound_ym.rd_data_reg_sel = 15; /* select port B */ + sound_ym.wd_data = 0; /* no char */ + sound_ym.rd_data_reg_sel = 14; /* select port A */ + sound_ym.wd_data = sound_ym.rd_data_reg_sel | 0x20; /* strobe H */ + debug_print_proc = ata_par_print; + } + else + debug_print_proc = NULL; +} + + +void ata_serial_print (const char *str) +{ + int c; + + while (c = *str++, c != 0) + { + if (c == '\n') + { + while (!(mfp.trn_stat & (1 << 7))) + barrier (); + mfp.usart_dta = '\r'; + } + while (!(mfp.trn_stat & (1 << 7))) + barrier (); + mfp.usart_dta = c; + } +} + +/* ++roman: + * + * This function does a reset on machines that lack the ability to + * assert the processor's _RESET signal somehow via hardware. It is + * based on the fact that you can find the initial SP and PC values + * after a reset at physical addresses 0 and 4. This works pretty well + * for Atari machines, since the lowest 8 bytes of physical memory are + * really ROM (mapped by hardware). For other 680x0 machines: don't + * know if it works... + * + * To get the values at addresses 0 and 4, the MMU better is turned + * off first. After that, we have to jump into physical address space + * (the PC before the pmove statement points to the virtual address of + * the code). Getting that physical address is not hard, but the code + * becomes a bit complex since I've tried to ensure that the jump + * statement after the pmove is in the cache already (otherwise the + * processor can't fetch it!). For that, the code first jumps to the + * jump statement with the (virtual) address of the pmove section in + * an address register . The jump statement is surely in the cache + * now. After that, that physical address of the reset code is loaded + * into the same address register, pmove is done and the same jump + * statements goes to the reset code. Since there are not many + * statements between the two jumps, I hope it stays in the cache. + * + * The C code makes heavy use of the GCC features that you can get the + * address of a C label. No hope to compile this with another compiler + * than GCC! + */ + +/* ++andreas: no need for complicated code, just depend on prefetch */ + +void atari_reset (void) +{ + long tc_val = 0; + long reset_addr; + + /* On the Medusa, phys. 0x4 may contain garbage because it's no + ROM. See above for explanation why we cannot use PTOV(4). */ + reset_addr = is_medusa ? 0xe00030 : *(unsigned long *) 0xff000004; + + acia.key_ctrl = ACIA_RESET; /* reset ACIA for switch off OverScan, if it's active */ + + /* processor independent: turn off interrupts and reset the VBR; + * the caches must be left enabled, else prefetching the final jump + * instruction doesn't work. */ + cli(); + __asm__ __volatile__ + ("moveq #0,%/d0\n\t" + "movec %/d0,%/vbr" + : : : "d0" ); + + if (m68k_is040or060) { + unsigned long jmp_addr040 = VTOP(&&jmp_addr_label040); + if (m68k_is040or060 == 6) { + /* 68060: clear PCR to turn off superscalar operation */ + __asm__ __volatile__ + ("moveq #0,%/d0\n\t" + ".long 0x4e7b0808" /* movec d0,pcr */ + : : : "d0" ); + } + + __asm__ __volatile__ + ("movel %0,%/d0\n\t" + "andl #0xff000000,%/d0\n\t" + "orw #0xe020,%/d0\n\t" /* map 16 MB, enable, cacheable */ + ".long 0x4e7b0004\n\t" /* movec d0,itt0 */ + ".long 0x4e7b0006\n\t" /* movec d0,dtt0 */ + "jmp %0@\n\t" + : /* no outputs */ + : "a" (jmp_addr040) + : "d0" ); + jmp_addr_label040: + __asm__ __volatile__ + ("moveq #0,%/d0\n\t" + ".word 0xf4d8\n\t" /* cinva i/d */ + ".word 0xf518\n\t" /* pflusha */ + ".long 0x4e7b0003\n\t" /* movec d0,tc */ + "jmp %0@" + : /* no outputs */ + : "a" (reset_addr) + : "d0"); + } + else + __asm__ __volatile__ + ("pmove %0@,%/tc\n\t" + "jmp %1@" + : /* no outputs */ + : "a" (&tc_val), "a" (reset_addr)); +} + + +void atari_get_model(char *model) +{ + strcpy(model, "Atari "); + switch (boot_info.bi_atari.mch_cookie >> 16) { + case ATARI_MCH_ST: + if (ATARIHW_PRESENT(MSTE_CLK)) + strcat (model, "Mega ST"); + else + strcat (model, "ST"); + break; + case ATARI_MCH_STE: + if ((boot_info.bi_atari.mch_cookie & 0xffff) == 0x10) + strcat (model, "Mega STE"); + else + strcat (model, "STE"); + break; + case ATARI_MCH_TT: + if (is_medusa) + /* Medusa has TT _MCH cookie */ + strcat (model, "Medusa"); + else + strcat (model, "TT"); + break; + case ATARI_MCH_FALCON: + strcat (model, "Falcon"); + break; + default: + sprintf (model + strlen (model), "(unknown mach cookie 0x%lx)", + boot_info.bi_atari.mch_cookie); + break; + } +} + + +int atari_get_hardware_list(char *buffer) +{ + int len = 0; + + for (i = 0; i < boot_info.num_memory; i++) + len += sprintf (buffer+len, "\t%3ld MB at 0x%08lx (%s)\n", + boot_info.memory[i].size >> 20, + boot_info.memory[i].addr, + (boot_info.memory[i].addr & 0xff000000 ? + "alternate RAM" : "ST-RAM")); + +#define ATARIHW_ANNOUNCE(name,str) \ + if (ATARIHW_PRESENT(name)) \ + len += sprintf (buffer + len, "\t%s\n", str) + + len += sprintf (buffer + len, "Detected hardware:\n"); + ATARIHW_ANNOUNCE(STND_SHIFTER, "ST Shifter"); + ATARIHW_ANNOUNCE(EXTD_SHIFTER, "STe Shifter"); + ATARIHW_ANNOUNCE(TT_SHIFTER, "TT Shifter"); + ATARIHW_ANNOUNCE(VIDEL_SHIFTER, "Falcon Shifter"); + ATARIHW_ANNOUNCE(YM_2149, "Programmable Sound Generator"); + ATARIHW_ANNOUNCE(PCM_8BIT, "PCM 8 Bit Sound"); + ATARIHW_ANNOUNCE(CODEC, "CODEC Sound"); + ATARIHW_ANNOUNCE(TT_SCSI, "SCSI Controller NCR5380 (TT style)"); + ATARIHW_ANNOUNCE(ST_SCSI, "SCSI Controller NCR5380 (Falcon style)"); + ATARIHW_ANNOUNCE(ACSI, "ACSI Interface"); + ATARIHW_ANNOUNCE(IDE, "IDE Interface"); + ATARIHW_ANNOUNCE(FDCSPEED, "8/16 Mhz Switch for FDC"); + ATARIHW_ANNOUNCE(ST_MFP, "Multi Function Peripheral MFP 68901"); + ATARIHW_ANNOUNCE(TT_MFP, "Second Multi Function Peripheral MFP 68901"); + ATARIHW_ANNOUNCE(SCC, "Serial Communications Controller SCC 8530"); + ATARIHW_ANNOUNCE(ST_ESCC, "Extended Serial Communications Controller SCC 85230"); + ATARIHW_ANNOUNCE(ANALOG_JOY, "Paddle Interface"); + ATARIHW_ANNOUNCE(MICROWIRE, "MICROWIRE(tm) Interface"); + ATARIHW_ANNOUNCE(STND_DMA, "DMA Controller (24 bit)"); + ATARIHW_ANNOUNCE(EXTD_DMA, "DMA Controller (32 bit)"); + ATARIHW_ANNOUNCE(SCSI_DMA, "DMA Controller for NCR5380"); + ATARIHW_ANNOUNCE(SCC_DMA, "DMA Controller for SCC"); + ATARIHW_ANNOUNCE(TT_CLK, "Clock Chip MC146818A"); + ATARIHW_ANNOUNCE(MSTE_CLK, "Clock Chip RP5C15"); + ATARIHW_ANNOUNCE(SCU, "System Control Unit"); + ATARIHW_ANNOUNCE(BLITTER, "Blitter"); + ATARIHW_ANNOUNCE(VME, "VME Bus"); + + return(len); +} diff -u --recursive --new-file v1.3.93/linux/arch/m68k/atari/joystick.c linux/arch/m68k/atari/joystick.c --- v1.3.93/linux/arch/m68k/atari/joystick.c Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/atari/joystick.c Sat Mar 30 14:11:04 1996 @@ -0,0 +1,141 @@ +/* + * Atari Joystick Driver for Linux + * by Robert de Vries (robert@and.nl) 19Jul93 + * + * 16 Nov 1994 Andreas Schwab + * Support for three button mouse (shamelessly stolen from MiNT) + * third button wired to one of the joystick directions on joystick 1 + */ + +#include +#include +#include + +#include +#include +#include +#include + +#define MAJOR_NR JOYSTICK_MAJOR + +#define ANALOG_JOY(n) (!(n & 0x80)) +#define DIGITAL_JOY(n) (n & 0x80) +#define DEVICE_NR(n) (MINOR(n) & 0x7f) + + +static struct joystick_status joystick[2]; +int atari_mouse_buttons; /* for three-button mouse */ + +void atari_joystick_interrupt(char *buf) +{ + int j; +/* ikbd_joystick_disable(); */ + + j = buf[0] & 0x1; + joystick[j].dir = buf[1] & 0xF; + joystick[j].fire = (buf[1] & 0x80) >> 7; + joystick[j].ready = 1; + wake_up_interruptible(&joystick[j].wait); + + /* For three-button mouse emulation fake a mouse packet */ + if (atari_mouse_interrupt_hook && + j == 1 && (buf[1] & 1) != ((atari_mouse_buttons & 2) >> 1)) + { + char faked_packet[3]; + + atari_mouse_buttons = (atari_mouse_buttons & 5) | ((buf[1] & 1) << 1); + faked_packet[0] = (atari_mouse_buttons & 1) | + (atari_mouse_buttons & 4 ? 2 : 0); + faked_packet[1] = 0; + faked_packet[2] = 0; + atari_mouse_interrupt_hook (faked_packet); + } + +/* ikbd_joystick_event_on(); */ +} + +static void release_joystick(struct inode *inode, struct file *file) +{ + int minor = DEVICE_NR(inode->i_rdev); + + joystick[minor].active = 0; + joystick[minor].ready = 0; + + if ((joystick[0].active == 0) && (joystick[1].active == 0)) + ikbd_joystick_disable(); +} + +static int open_joystick(struct inode *inode, struct file *file) +{ + int minor = DEVICE_NR(inode->i_rdev); + + if (!DIGITAL_JOY(inode->i_rdev) || minor > 1) + return -ENODEV; + if (joystick[minor].active) + return -EBUSY; + joystick[minor].active = 1; + joystick[minor].ready = 0; + ikbd_joystick_event_on(); + return 0; +} + +static int write_joystick(struct inode *inode, struct file *file, + const char *buffer, int count) +{ + return -EINVAL; +} + +static int read_joystick(struct inode *inode, struct file *file, + char *buffer, int count) +{ + int minor = DEVICE_NR(inode->i_rdev); + int i; + + if (count < 2) + return -EINVAL; + if (!joystick[minor].ready) + return -EAGAIN; + put_user(joystick[minor].fire, buffer++); + put_user(joystick[minor].dir, buffer++); + for (i = 0; i < count; i++) + put_user(0, buffer++); + joystick[minor].ready = 0; + + return i; +} + +static int joystick_select(struct inode *inode, struct file *file, int sel_type, select_table *wait) +{ + int minor = DEVICE_NR(inode->i_rdev); + + if (sel_type != SEL_IN) + return 0; + if (joystick[minor].ready) + return 1; + select_wait(&joystick[minor].wait, wait); + return 0; +} + +struct file_operations atari_joystick_fops = { + NULL, /* joystick_seek */ + read_joystick, + write_joystick, + NULL, /* joystick_readdir */ + joystick_select, + NULL, /* joystick_ioctl */ + NULL, /* joystick_mmap */ + open_joystick, + release_joystick +}; + +int atari_joystick_init(void) +{ + joystick[0].active = joystick[1].active = 0; + joystick[0].ready = joystick[1].ready = 0; + joystick[0].wait = joystick[1].wait = NULL; + + if (register_chrdev(MAJOR_NR, "joystick", &atari_joystick_fops)) + printk("unable to get major %d for joystick devices\n", MAJOR_NR); + + return 0; +} diff -u --recursive --new-file v1.3.93/linux/arch/m68k/atari/ksyms.c linux/arch/m68k/atari/ksyms.c --- v1.3.93/linux/arch/m68k/atari/ksyms.c Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/atari/ksyms.c Sat Apr 13 14:31:00 1996 @@ -0,0 +1,53 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if 0 +#include +#endif + +static struct symbol_table mach_atari_symbol_table = { +#include + + X(is_medusa), + X(atari_register_vme_int), + X(stdma_lock), + X(stdma_release), + X(stdma_others_waiting), + X(stdma_islocked), + + X(atari_mouse_buttons), + X(atari_mouse_interrupt_hook), + X(atari_MIDI_interrupt_hook), + X(ikbd_write), + X(ikbd_mouse_y0_top), + X(ikbd_mouse_thresh), + X(ikbd_mouse_rel_pos), + X(ikbd_mouse_disable), + +#if 0 +#ifdef CONFIG_ATARI_ACSI + X(acsi_wait_for_IRQ), + X(acsi_wait_for_noIRQ), + X(acsicmd_nodma), + X(acsi_getstatus), +#ifdef CONFIG_ATARI_SLM + X(acsi_extstatus), + X(acsi_end_extstatus), + X(acsi_extcmd), +#endif +#endif +#endif /* 0 */ + +#include +}; + +void mach_atari_syms_export(void) +{ + register_symtab(&mach_atari_symbol_table); +} diff -u --recursive --new-file v1.3.93/linux/arch/m68k/atari/stdma.c linux/arch/m68k/atari/stdma.c --- v1.3.93/linux/arch/m68k/atari/stdma.c Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/atari/stdma.c Fri Apr 19 02:35:24 1996 @@ -0,0 +1,194 @@ + +/* + * linux/atari/stmda.c + * + * Copyright (C) 1994 Roman Hodek + * + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file README.legal in the main directory of this archive + * for more details. + */ + + +/* This file contains some function for controlling the access to the */ +/* ST-DMA chip that may be shared between devices. Currently we have: */ +/* TT: Floppy and ACSI bus */ +/* Falcon: Floppy and SCSI */ +/* */ +/* The controlling functions set up a wait queue for access to the */ +/* ST-DMA chip. Callers to stdma_lock() that cannot granted access are */ +/* put onto a queue and waked up later if the owner calls */ +/* stdma_release(). Additionally, the caller gives his interrupt */ +/* service routine to stdma_lock(). */ +/* */ +/* On the Falcon, the IDE bus uses just the ACSI/Floppy interrupt, but */ +/* not the ST-DMA chip itself. So falhd.c needs not to lock the */ +/* chip. The interrupt is routed to falhd.c if IDE is configured, the */ +/* model is a Falcon and the interrupt was caused by the HD controller */ +/* (can be determined by looking at its status register). */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int stdma_locked = 0; /* the semaphore */ +static isrfunc stdma_isr = NULL; /* int func to be called */ +static void *stdma_isr_data = NULL; /* data passed to isr */ +static struct wait_queue *stdma_wait = NULL; /* wait queue for ST-DMA */ + + + + +/***************************** Prototypes *****************************/ + +static void stdma_int (int irq, struct pt_regs *fp, void *dummy); + +/************************* End of Prototypes **************************/ + + + +/* + * Function: void stdma_lock( isrfunc isr, void *data ) + * + * Purpose: Trys to get a lock on the ST-DMA chip that is used by more + * then one device driver. Waits on stdma_wait until lock is free. + * stdma_lock() may not be called from an interrupt! You have to + * get the lock in your main routine and release it when your + * request is finished. + * + * Inputs: A interupt function that is called until the lock is + * released. + * + * Returns: nothing + * + */ + +void stdma_lock(isrfunc isr, void *data) +{ + unsigned long oldflags; + + save_flags(oldflags); + cli(); /* protect lock */ + + while(stdma_locked) + /* Since the DMA is used for file system purposes, we + have to sleep uninterruptible (there may be locked + buffers) */ + sleep_on(&stdma_wait); + + stdma_locked = 1; + stdma_isr = isr; + stdma_isr_data = data; + restore_flags(oldflags); +} + + +/* + * Function: void stdma_release( void ) + * + * Purpose: Releases the lock on the ST-DMA chip. + * + * Inputs: none + * + * Returns: nothing + * + */ + +void stdma_release(void) +{ + unsigned long oldflags; + + save_flags(oldflags); + cli(); + + stdma_locked = 0; + stdma_isr = NULL; + stdma_isr_data = NULL; + wake_up(&stdma_wait); + + restore_flags(oldflags); +} + + +/* + * Function: int stdma_others_waiting( void ) + * + * Purpose: Check if someone waits for the ST-DMA lock. + * + * Inputs: none + * + * Returns: 0 if noone is waiting, != 0 otherwise + * + */ + +int stdma_others_waiting(void) +{ + return stdma_wait != NULL; +} + + +/* + * Function: int stdma_islocked( void ) + * + * Purpose: Check if the ST-DMA is currently locked. + * Note: Returned status is only valid if ints are disabled while calling and + * as long as they remain disabled. + * If called with ints enabled, status can change only from locked to + * unlocked, because ints may not lock the ST-DMA. + * + * Inputs: none + * + * Returns: != 0 if locked, 0 otherwise + * + */ + +int stdma_islocked(void) +{ + return stdma_locked; +} + + +/* + * Function: void stdma_init( void ) + * + * Purpose: Initialize the ST-DMA chip access controlling. + * It sets up the interrupt and its service routine. The int is registered + * as slow int, client devices have to live with that (no problem + * currently). + * + * Inputs: none + * + * Return: nothing + * + */ + +void stdma_init(void) +{ + stdma_isr = NULL; + add_isr(IRQ_MFP_FDC, stdma_int, IRQ_TYPE_SLOW, NULL, + "ST-DMA: floppy/ACSI/IDE/Falcon-SCSI"); +} + + +/* + * Function: void stdma_int() + * + * Purpose: The interupt routine for the ST-DMA. It calls the isr + * registered by stdma_lock(). + * + */ + +static void stdma_int(int irq, struct pt_regs *fp, void *dummy) +{ + if (stdma_isr) + (*stdma_isr)(irq, fp, stdma_isr_data); +} diff -u --recursive --new-file v1.3.93/linux/arch/m68k/atari/stram.c linux/arch/m68k/atari/stram.c --- v1.3.93/linux/arch/m68k/atari/stram.c Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/atari/stram.c Wed Dec 27 22:44:28 1995 @@ -0,0 +1,243 @@ + +#include +#include +#include +#include +#include +#include +#include + +#if 0 + +struct stram_desc + { + unsigned first:1; + unsigned last:1; + unsigned alloced:1; + unsigned length:24; + }; + +#define DP(ptr) ((struct stram_desc *) (ptr)) + +static unsigned long stramsize; +static unsigned long stramaddr; + +void +atari_stram_init (void) +{ + struct stram_desc *dp; + stramaddr = boot_info.bi_atari.stram_start; + stramsize = boot_info.bi_atari.stram_size; + + /* initialize start boundary */ + dp = DP (stramaddr); + dp->first = 1; + dp->alloced = 0; + dp->length = stramsize - 2 * sizeof (*dp); + + /* initialize end boundary */ + dp = DP (stramaddr + stramsize) - 1; + dp->last = 1; + dp->alloced = 0; + dp->length = stramsize - 2 * sizeof (*dp); + +#ifdef DEBUG + printk ("stram end boundary is %p, length is %d\n", dp, + dp->length); +#endif +} + +void * +atari_stram_alloc (long size) +{ + /* last chunk */ + struct stram_desc *dp; + void *ptr; + + /* round off */ + size = (size + 3) & ~3; + +#ifdef DEBUG + printk ("stram_alloc: allocate %ld bytes\n", size); +#endif + + /* + * get pointer to descriptor for last chunk by + * going backwards from end chunk + */ + dp = DP (stramaddr + stramsize) - 1; + dp = DP ((unsigned long) dp - dp->length) - 1; + + while ((dp->alloced || dp->length < size) && !dp->first) + dp = DP ((unsigned long) dp - dp[-1].length) - 2; + + if (dp->alloced || dp->length < size) + { + printk ("no stram available for %ld allocation\n", size); + return NULL; + } + + if (dp->length < size + 2 * sizeof (*dp)) + { + /* length too small to split; allocate the whole thing */ + dp->alloced = 1; + ptr = (void *) (dp + 1); + dp = DP ((unsigned long) ptr + dp->length); + dp->alloced = 1; +#ifdef DEBUG + printk ("stram_alloc: no split\n"); +#endif + } + else + { + /* split the extent; use the end part */ + long newsize = dp->length - (2 * sizeof (*dp) + size); + +#ifdef DEBUG + printk ("stram_alloc: splitting %d to %ld\n", dp->length, + newsize); +#endif + dp->length = newsize; + dp = DP ((unsigned long) (dp + 1) + newsize); + dp->first = dp->last = 0; + dp->alloced = 0; + dp->length = newsize; + dp++; + dp->first = dp->last = 0; + dp->alloced = 1; + dp->length = size; + ptr = (void *) (dp + 1); + dp = DP ((unsigned long) ptr + size); + dp->alloced = 1; + dp->length = size; + } + +#ifdef DEBUG + printk ("stram_alloc: returning %p\n", ptr); +#endif + return ptr; +} + +void +atari_stram_free (void *ptr) +{ + struct stram_desc *sdp = DP (ptr) - 1, *dp2; + struct stram_desc *edp = DP ((unsigned long) ptr + sdp->length); + + /* deallocate the chunk */ + sdp->alloced = edp->alloced = 0; + + /* check if we should merge with the previous chunk */ + if (!sdp->first && !sdp[-1].alloced) + { + dp2 = DP ((unsigned long) sdp - sdp[-1].length) - 2; + dp2->length += sdp->length + 2 * sizeof (*sdp); + edp->length = dp2->length; + sdp = dp2; + } + + /* check if we should merge with the following chunk */ + if (!edp->last && !edp[1].alloced) + { + dp2 = DP ((unsigned long) edp + edp[1].length) + 2; + dp2->length += edp->length + 2 * sizeof (*sdp); + sdp->length = dp2->length; + edp = dp2; + } +} + +#else + +#include + +/* ++roman: + * + * New version of ST-Ram buffer allocation. Instead of using the + * 1 MB - 4 KB that remain when the the ST-Ram chunk starts at $1000 + * (1 MB granularity!), such buffers are reserved like this: + * + * - If the kernel resides in ST-Ram anyway, we can take the buffer + * from behind the current kernel data space the normal way + * (incrementing start_mem). + * + * - If the kernel is in TT-Ram, stram_init() initializes start and + * end of the available region. Buffers are allocated from there + * and mem_init() later marks the such used pages as reserved. + * Since each TT-Ram chunk is at least 4 MB in size, I hope there + * won't be an overrun of the ST-Ram region by normal kernel data + * space. + * + * For that, ST-Ram may only be allocated while kernel initialization + * is going on, or exactly: before mem_init() is called. There is also + * no provision now for freeing ST-Ram buffers. It seems that isn't + * really needed. + * + * ToDo: + * Check the high level scsi code what is done when the + * UNCHECKED_ISA_DMA flag is set. It guess, it is just a test for adr + * < 16 Mega. There should be call to atari_stram_alloc() instead. + * + * Also ToDo: + * Go through head.S and delete parts no longer needed (transparent + * mapping of ST-Ram etc.) + * + */ + + +unsigned long rsvd_stram_beg, rsvd_stram_end; + /* Start and end of the reserved ST-Ram region */ +static unsigned long stram_end; + /* Overall end of ST-Ram */ + + +void atari_stram_init( void ) + +{ int i; + + for( i = 0; i < boot_info.num_memory; ++i ) { + if (boot_info.memory[i].addr == 0) { + rsvd_stram_beg = PTOV( 0x800 ); /* skip super-only first 2 KB! */ + rsvd_stram_end = rsvd_stram_beg; + stram_end = rsvd_stram_beg - 0x800 + boot_info.memory[i].size; + return; + } + } + /* Should never come here! (There is always ST-Ram!) */ +} + + +void *atari_stram_alloc( long size, unsigned long *start_mem ) + +{ + static int kernel_in_stram = -1; + + void *adr = 0; + + if (kernel_in_stram < 0) + kernel_in_stram = (PTOV( 0 ) == 0); + + if (kernel_in_stram) { + /* Get memory from kernel data space */ + adr = (void *) *start_mem; + *start_mem += size; + } + else { + /* Get memory from rsvd_stram_beg */ + if (rsvd_stram_end + size < stram_end) { + adr = (void *) rsvd_stram_end; + rsvd_stram_end += size; + } + } + + return( adr ); +} + +void atari_stram_free( void *ptr ) + +{ + /* Sorry, this is a dummy. It isn't needed anyway. */ +} + +#endif + + diff -u --recursive --new-file v1.3.93/linux/arch/m68k/boot/Makefile linux/arch/m68k/boot/Makefile --- v1.3.93/linux/arch/m68k/boot/Makefile Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/boot/Makefile Wed Dec 27 22:44:28 1995 @@ -0,0 +1,37 @@ +# +# linux/arch/m68k/boot/Makefile +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. + +ifdef CONFIG_AMIGA +AMIGA_BOOTOBJS := amiga/bootstrap.o +endif + +ifdef CONFIG_ATARI +ATARI_BOOTOBJS := atari/bootstrap.o +HOSTCC += -b m68k-mint +endif + +ifdef CONFIG_ATARI +atari_bootstrap: $(ATARI_BOOTOBJS) + $(HOSTCC) $(HOSTFLAGS) -o $@ $(ATARI_BOOTOBJS) + rm -f ../../../bootstrap + ln $@ ../../../bootstrap +endif + +ifdef CONFIG_AMIGA +amiga_bootstrap: $(AMIGA_BOOTOBJS) + $(HOSTCC) $(HOSTFLAGS) -o $@ $(AMIGA_BOOTOBJS) + rm -f ../../../bootstrap + ln $@ ../../../bootstrap +endif + +$(AMIGA_BOOTOBJS) $(ATARI_BOOTOBJS): %.o: %.c + $(HOSTCC) $(HOSTFLAGS) -c $< -o $@ + +clean: + rm -f *.o + +dep: diff -u --recursive --new-file v1.3.93/linux/arch/m68k/boot/amiga/bootstrap.c linux/arch/m68k/boot/amiga/bootstrap.c --- v1.3.93/linux/arch/m68k/boot/amiga/bootstrap.c Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/boot/amiga/bootstrap.c Wed Dec 27 22:44:29 1995 @@ -0,0 +1,782 @@ +/* +** bootstrap.c -- This program loads the Linux/68k kernel into an Amiga +** and and launches it. +** +** Copyright 1993,1994 by Hamish Macdonald, Greg Harp +** +** Modified 11-May-94 by Geert Uytterhoeven +** (Geert.Uytterhoeven@cs.kuleuven.ac.be) +** - A3640 MapROM check +** Modified 31-May-94 by Geert Uytterhoeven +** - Memory thrash problem solved +** Modified 07-March-95 by Geert Uytterhoeven +** - Memory block sizes are rounded to a multiple of 256K instead of 1M +** This _requires_ >0.9pl5 to work! +** (unless all block sizes are multiples of 1M :-) +** +** This file is subject to the terms and conditions of the GNU General Public +** License. See the file README.legal in the main directory of this archive +** for more details. +** +*/ + +#include +#include +#include +#include +#include +#include +#include + +/* Amiga bootstrap include file */ +#include "bootstrap.h" + +/* required Linux/68k include files */ +#include +#include + +/* temporary stack size */ +#define TEMP_STACKSIZE 256 + +/* Exec Base */ +extern struct ExecBase *SysBase; + +extern char *optarg; + +struct exec kexec; +char *memptr; +u_long start_mem; +u_long mem_size; +u_long rd_size; + +struct ExpansionBase *ExpansionBase; +struct GfxBase *GfxBase; + +struct bootinfo bi; +u_long bi_size = sizeof bi; + +caddr_t CustomBase = (caddr_t)CUSTOM_PHYSADDR; + +void usage(void) +{ + fprintf (stderr, "Usage:\n" + "\tbootstrap [-d] [-k kernel_executable] [-r ramdisk_file]" + " [option...]\n"); + exit (EXIT_FAILURE); +} + +/* + * This assembler code is copied to chip ram, and + * then executed. + * It copies the kernel (and ramdisk) to their + * final resting place. + */ +#ifndef __GNUC__ +#error GNU CC is required to compile the bootstrap program +#endif +asm(" +.text +.globl _copyall, _copyallend +_copyall: + | /* put variables in registers because they may */ + lea _kexec,a3 | /* be overwritten by kernel/ramdisk copy!! - G.U. */ + movel _memptr,a4 + movel _start_mem,a5 + movel _mem_size,d0 + movel _rd_size,d1 + movel _bi_size,d5 + movel a3@(4),d2 | kexec.a_text + movel a3@(8),d3 | kexec.a_data + movel a3@(12),d4 | kexec.a_bss + + | /* copy kernel text and data */ + movel a4,a0 | src = (u_long *)memptr; + movel a0,a2 | limit = (u_long *)(memptr + kexec.a_text + kexec.a_data); + addl d2,a2 + addl d3,a2 + movel a5,a1 | dest = (u_long *)start_mem; +1: cmpl a0,a2 + beqs 2f | while (src < limit) + moveb a0@+,a1@+ | *dest++ = *src++; + bras 1b +2: + + | /* clear kernel bss */ + movel a1,a0 | dest = (u_long *)(start_mem + kexec.a_text + kexec.a_data); + movel a1,a2 | limit = dest + kexec.a_bss / sizeof(u_long); + addl d4,a2 +1: cmpl a0,a2 + beqs 2f | while (dest < limit) + clrb a0@+ | *dest++ = 0; + bras 1b +2: + + | /* copy bootinfo to end of bss */ + movel a4,a1 | src = (u long *)memptr + kexec.a_text + kexec.a_data); + addl d2,a1 + addl d3,a1 | dest = end of bss (already in a0) + movel d5,d7 | count = sizeof bi + subql #1,d7 +1: moveb a1@+,a0@+ | while (--count > -1) + dbra d7,1b | *dest++ = *src++ + + + | /* copy the ramdisk to the top of memory (from back to front) */ + movel a5,a1 | dest = (u_long *)(start_mem + mem_size); + addl d0,a1 + movel a4,a2 | limit = (u_long *)(memptr + kexec.a_text + kexec.a_data + sizeof bi); + addl d2,a2 + addl d3,a2 + addl d5,a2 + movel a2,a0 | src = (u_long *)((u_long)limit + rd_size); + addl d1,a0 +1: cmpl a0,a2 + beqs 2f | while (src > limit) + moveb a0@-,a1@- | *--dest = *--src; + bras 1b +2: + | /* jump to start of kernel */ + movel a5,a0 | jump_to (START_MEM); + jsr a0@ +_copyallend: +"); + +asm(" +.text +.globl _maprommed +_maprommed: + oriw #0x0700,sr + moveml #0x3f20,sp@- +/* Save cache settings */ + .long 0x4e7a1002 /* movec cacr,d1 */ +/* Save MMU settings */ + .long 0x4e7a2003 /* movec tc,d2 */ + .long 0x4e7a3004 /* movec itt0,d3 */ + .long 0x4e7a4005 /* movec itt1,d4 */ + .long 0x4e7a5006 /* movec dtt0,d5 */ + .long 0x4e7a6007 /* movec dtt1,d6 */ + moveq #0,d0 + movel d0,a2 +/* Disable caches */ + .long 0x4e7b0002 /* movec d0,cacr */ +/* Disable MMU */ + .long 0x4e7b0003 /* movec d0,tc */ + .long 0x4e7b0004 /* movec d0,itt0 */ + .long 0x4e7b0005 /* movec d0,itt1 */ + .long 0x4e7b0006 /* movec d0,dtt0 */ + .long 0x4e7b0007 /* movec d0,dtt1 */ + lea 0x07f80000,a0 + lea 0x00f80000,a1 + movel a0@,d7 + cmpl a1@,d7 + jnes 1f + movel d7,d0 + notl d0 + movel d0,a0@ + nop + cmpl a1@,d0 + jnes 1f +/* MapROMmed A3640 present */ + moveq #-1,d0 + movel d0,a2 +1: movel d7,a0@ +/* Restore MMU settings */ + .long 0x4e7b2003 /* movec d2,tc */ + .long 0x4e7b3004 /* movec d3,itt0 */ + .long 0x4e7b4005 /* movec d4,itt1 */ + .long 0x4e7b5006 /* movec d5,dtt0 */ + .long 0x4e7b6007 /* movec d6,dtt1 */ +/* Restore cache settings */ + .long 0x4e7b1002 /* movec d1,cacr */ + movel a2,d0 + moveml sp@+,#0x04fc + rte +"); + +extern unsigned long maprommed(); + + +extern char copyall, copyallend; + +int main(int argc, char *argv[]) +{ + int ch, debugflag = 0, kfd, rfd = -1, i; + long fast_total = 0; /* total Fast RAM in system */ + struct MemHeader *mnp; + struct ConfigDev *cdp = NULL; + char *kernel_name = "vmlinux"; + char *ramdisk_name = NULL; + char *memfile = NULL; + u_long memreq; + void (*startfunc)(void); + long startcodesize; + u_long *stack, text_offset; + unsigned char *rb3_reg = NULL, *piccolo_reg = NULL, *sd64_reg = NULL; + + /* print the greet message */ + puts(" Linux/68k Amiga Bootstrap version 1.11"); + puts("Copyright 1993,1994 by Hamish Macdonald and Greg Harp\n"); + + /* machine is Amiga */ + bi.machtype = MACH_AMIGA; + + /* check arguments */ + while ((ch = getopt(argc, argv, "dk:r:m:")) != EOF) + switch (ch) { + case 'd': + debugflag = 1; + break; + case 'k': + kernel_name = optarg; + break; + case 'r': + ramdisk_name = optarg; + break; + case 'm': + memfile = optarg; + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + SysBase = *(struct ExecBase **)4; + + /* Memory & AutoConfig based on 'unix_boot.c' by C= */ + + /* open Expansion Library */ + ExpansionBase = (struct ExpansionBase *)OpenLibrary("expansion.library", 36); + if (!ExpansionBase) { + puts("Unable to open expansion.library V36 or greater! Aborting..."); + exit(EXIT_FAILURE); + } + + /* find all of the autoconfig boards in the system */ + cdp = (struct ConfigDev *)FindConfigDev(cdp, -1, -1); + for (i=0; (i < NUM_AUTO) && cdp; i++) { + /* copy the contents of each structure into our boot info */ + memcpy(&bi.bi_amiga.autocon[i], cdp, sizeof(struct ConfigDev)); + + /* count this device */ + bi.bi_amiga.num_autocon++; + + /* get next device */ + cdp = (struct ConfigDev *)FindConfigDev(cdp, -1, -1); + } + + /* find out the memory in the system */ + for (mnp = (struct MemHeader *)SysBase->MemList.l_head; + (bi.num_memory < NUM_MEMINFO) && mnp->mh_Node.ln_Succ; + mnp = (struct MemHeader *)mnp->mh_Node.ln_Succ) + { + struct MemHeader mh; + + /* copy the information */ + mh = *mnp; + + /* if we suspect that Kickstart is shadowed in an A3000, + modify the entry to show 512K more at the top of RAM + Check first for a MapROMmed A3640 board: overwriting the + Kickstart image causes an infinite lock-up on reboot! */ + + if (mh.mh_Upper == (void *)0x07f80000) + if ((SysBase->AttnFlags & AFF_68040) && Supervisor(maprommed)) + printf("A3640 MapROM detected.\n"); + else { + mh.mh_Upper = (void *)0x08000000; + printf("A3000 shadowed Kickstart detected.\n"); + } + + /* if we suspect that Kickstart is zkicked, + modify the entry to show 512K more at the botton of RAM */ + if (mh.mh_Lower == (void *)0x00280020) { + mh.mh_Lower = (void *)0x00200000; + printf("ZKick detected.\n"); + } + + /* + * If this machine has "LOCAL" memory between 0x07000000 + * and 0x080000000, then we'll call it an A3000. + */ + if (mh.mh_Lower >= (void *)0x07000000 && + mh.mh_Lower < (void *)0x08000000 && + (mh.mh_Attributes & MEMF_LOCAL)) + bi.bi_amiga.model = AMI_3000; + + /* mask the memory limit values */ + mh.mh_Upper = (void *)((u_long)mh.mh_Upper & 0xfffff000); + mh.mh_Lower = (void *)((u_long)mh.mh_Lower & 0xfffff000); + + /* if fast memory */ + if (mh.mh_Attributes & MEMF_FAST) { + unsigned long size; + + /* record the start */ + bi.memory[bi.num_memory].addr = (u_long)mh.mh_Lower; + + /* set the size value to the size of this block */ + size = (u_long)mh.mh_Upper - (u_long)mh.mh_Lower; + + /* mask off to a 256K increment */ + size &= 0xfffc0000; + + fast_total += size; + + if (size > 0) + /* count this block */ + bi.memory[bi.num_memory++].size = size; + + } else if (mh.mh_Attributes & MEMF_CHIP) { + /* if CHIP memory, record the size */ + bi.bi_amiga.chip_size = + (u_long)mh.mh_Upper; /* - (u_long)mh.mh_Lower; */ + } + } + + CloseLibrary((struct Library *)ExpansionBase); + + /* + * if we have a memory file, read the memory information from it + */ + if (memfile) { + FILE *fp; + int i; + + if ((fp = fopen (memfile, "r")) == NULL) { + perror ("open memory file"); + fprintf (stderr, "Cannot open memory file %s\n", memfile); + exit (EXIT_FAILURE); + } + + if (fscanf (fp, "%lu", &bi.bi_amiga.chip_size) != 1) { + fprintf (stderr, "memory file does not contain chip memory size\n"); + fclose (fp); + exit (EXIT_FAILURE); + } + + for (i = 0; i < NUM_MEMINFO; i++) { + if (fscanf (fp, "%lx %lu", &bi.memory[i].addr, + &bi.memory[i].size) != 2) + break; + } + + fclose (fp); + + if (i != bi.num_memory && i > 0) + bi.num_memory = i; + } + + /* get info from ExecBase */ + bi.bi_amiga.vblank = SysBase->VBlankFrequency; + bi.bi_amiga.psfreq = SysBase->PowerSupplyFrequency; + bi.bi_amiga.eclock = SysBase->EClockFrequency; + + /* open graphics library */ + GfxBase = (struct GfxBase *)OpenLibrary ("graphics.library", 0); + + /* determine chipset */ + bi.bi_amiga.chipset = CS_STONEAGE; + if(GfxBase) + { + if(GfxBase->ChipRevBits0 & GFXG_AGA) + { + bi.bi_amiga.chipset = CS_AGA; + /* + * we considered this machine to be an A3000 because of its + * local memory just beneath $8000000; now if it has AGA, it + * must be an A4000 + * except the case no RAM is installed on the motherboard but + * on an additional card like FastLane Z3 or on the processor + * board itself. Gotta check this out. + */ + bi.bi_amiga.model = + (bi.bi_amiga.model == AMI_3000) ? AMI_4000 : AMI_1200; + } + else if(GfxBase->ChipRevBits0 & GFXG_ECS) + bi.bi_amiga.chipset = CS_ECS; + else if(GfxBase->ChipRevBits0 & GFXG_OCS) + bi.bi_amiga.chipset = CS_OCS; + } + + /* Display amiga model */ + switch (bi.bi_amiga.model) { + case AMI_UNKNOWN: + break; + case AMI_500: + printf ("Amiga 500 "); + break; + case AMI_2000: + printf ("Amiga 2000 "); + break; + case AMI_3000: + printf ("Amiga 3000 "); + break; + case AMI_4000: + printf ("Amiga 4000 "); + break; + case AMI_1200: /* this implies an upgraded model */ + printf ("Amiga 1200 "); /* equipped with at least 68030 !!! */ + break; + } + + /* display and set the CPU AttnFlags & AFF_68040) { + printf("68040"); + bi.cputype = CPU_68040; + if (SysBase->AttnFlags & AFF_FPU40) { + printf(" with internal FPU"); + bi.cputype |= FPU_68040; + } else + printf(" without FPU"); + } else { + if (SysBase->AttnFlags & AFF_68030) { + printf("68030"); + bi.cputype = CPU_68030; + } else if (SysBase->AttnFlags & AFF_68020) { + printf("68020 (Do you have an MMU?)"); + bi.cputype = CPU_68020; + } else { + puts("Insufficient for Linux. Aborting..."); + printf("SysBase->AttnFlags = %#x\n", SysBase->AttnFlags); + exit (EXIT_FAILURE); + } + if (SysBase->AttnFlags & AFF_68882) { + printf(" with 68882 FPU"); + bi.cputype |= FPU_68882; + } else if (SysBase->AttnFlags & AFF_68881) { + printf(" with 68881 FPU"); + bi.cputype |= FPU_68881; + } else + printf(" without FPU"); + } + + switch(bi.bi_amiga.chipset) + { + case CS_STONEAGE: + printf(", old or unknown chipset"); + break; + case CS_OCS: + printf(", OCS"); + break; + case CS_ECS: + printf(", ECS"); + break; + case CS_AGA: + printf(", AGA chipset"); + break; + } + + putchar ('\n'); + putchar ('\n'); + + /* + * Copy command line options into the kernel command line. + */ + i = 0; + while (argc--) { + if ((i+strlen(*argv)+1) < CL_SIZE) { + i += strlen(*argv) + 1; + if (bi.command_line[0]) + strcat (bi.command_line, " "); + strcat (bi.command_line, *argv++); + } + } + printf ("Command line is '%s'\n", bi.command_line); + + /* display the clock statistics */ + printf("Vertical Blank Frequency: %dHz\nPower Supply Frequency: %dHz\n", + bi.bi_amiga.vblank, bi.bi_amiga.psfreq); + printf("EClock Frequency: %7.5fKHz\n\n", + (float)bi.bi_amiga.eclock / 1000); + + /* display autoconfig devices */ + if (bi.bi_amiga.num_autocon) { + printf("Found %d AutoConfig Device%s", bi.bi_amiga.num_autocon, + (bi.bi_amiga.num_autocon > 1)?"s\n":"\n"); + for (i=0; i 1)?"s ":" "); + for (i=0; i> 10); + } + } else { + puts("No memory found?! Aborting..."); + exit(10); + } + + /* display chip memory size */ + printf ("%ldK of CHIP memory\n", bi.bi_amiga.chip_size >> 10); + + start_mem = bi.memory[0].addr; + mem_size = bi.memory[0].size; + + /* tell us where the kernel will go */ + printf("\nThe kernel will be located at %08lx\n", start_mem); + + /* verify that there is enough Chip RAM */ + if (bi.bi_amiga.chip_size < 512*1024) { + puts("\nNot enough Chip RAM in this system. Aborting..."); + exit(10); + } + + /* verify that there is enough Fast RAM */ + if (fast_total < 2*1024*1024) { + puts("\nNot enough Fast RAM in this system. Aborting..."); + exit(10); + } + + /* open kernel executable and read exec header */ + if ((kfd = open (kernel_name, O_RDONLY)) == -1) { + fprintf (stderr, "Unable to open kernel file %s\n", kernel_name); + exit (EXIT_FAILURE); + } + + if (read (kfd, (void *)&kexec, sizeof(kexec)) != sizeof(kexec)) { + fprintf (stderr, "Unable to read exec header from %s\n", + kernel_name); + exit (EXIT_FAILURE); + } + + switch (N_MAGIC(kexec)) { + case ZMAGIC: + text_offset = N_TXTOFF(kexec); + break; + case QMAGIC: + text_offset = sizeof(kexec); + /* the text size includes the exec header; remove this */ + kexec.a_text -= sizeof(kexec); + break; + default: + fprintf (stderr, "Wrong magic number %lo in kernel header\n", + N_MAGIC(kexec)); + exit (EXIT_FAILURE); + } + + /* Load the kernel at one page after start of mem */ + start_mem += PAGE_SIZE; + mem_size -= PAGE_SIZE; + /* Align bss size to multiple of four */ + kexec.a_bss = (kexec.a_bss + 3) & ~3; + + if (ramdisk_name) { + if ((rfd = open (ramdisk_name, O_RDONLY)) == -1) { + fprintf (stderr, "Unable to open ramdisk file %s\n", + ramdisk_name); + exit (EXIT_FAILURE); + } + /* record ramdisk size */ + bi.ramdisk_size = (lseek (rfd, 0, L_XTND) + 1023) >> 10; + } else + bi.ramdisk_size = 0; + + rd_size = bi.ramdisk_size << 10; + bi.ramdisk_addr = (u_long)start_mem + mem_size - rd_size; + + memreq = kexec.a_text + kexec.a_data + sizeof(bi) + rd_size; + if (!(memptr = (char *)AllocMem (memreq, MEMF_FAST | MEMF_CLEAR))) { + fprintf (stderr, "Unable to allocate memory\n"); + exit (EXIT_FAILURE); + } + + if (lseek (kfd, text_offset, L_SET) == -1) { + fprintf (stderr, "Failed to seek to text\n"); + FreeMem ((void *)memptr, memreq); + exit (EXIT_FAILURE); + } + if (read (kfd, memptr, kexec.a_text) != kexec.a_text) { + fprintf (stderr, "Failed to read text\n"); + FreeMem ((void *)memptr, memreq); + exit (EXIT_FAILURE); + } + + /* data follows immediately after text */ + if (read (kfd, memptr + kexec.a_text, kexec.a_data) != kexec.a_data) { + fprintf (stderr, "Failed to read data\n"); + FreeMem ((void *)memptr, memreq); + exit (EXIT_FAILURE); + } + close (kfd); + + /* copy the boot_info struct to the end of the kernel image */ + memcpy ((void *)(memptr + kexec.a_text + kexec.a_data), &bi, + sizeof(bi)); + + if (rfd != -1) { + if (lseek (rfd, 0, L_SET) == -1) { + fprintf (stderr, "Failed to seek to beginning of ramdisk file\n"); + FreeMem ((void *)memptr, memreq); + exit (EXIT_FAILURE); + } + if (read (rfd, memptr + kexec.a_text + kexec.a_data + + sizeof(bi), rd_size) != rd_size) { + fprintf (stderr, "Failed to read ramdisk file\n"); + FreeMem ((void *)memptr, memreq); + exit (EXIT_FAILURE); + } + close (rfd); + } + + /* allocate temporary chip ram stack */ + stack = (u_long *)AllocMem( TEMP_STACKSIZE, MEMF_CHIP|MEMF_CLEAR); + if (!stack) { + fprintf (stderr, "Unable to allocate memory for stack\n"); + FreeMem ((void *)memptr, memreq); + exit (EXIT_FAILURE); + } + + /* allocate chip ram for copy of startup code */ + startcodesize = ©allend - ©all; + startfunc = (void (*)(void))AllocMem( startcodesize, MEMF_CHIP); + if (!startfunc) { + fprintf (stderr, "Unable to allocate memory for code\n"); + FreeMem ((void *)memptr, memreq); + FreeMem ((void *)stack, TEMP_STACKSIZE); + exit (EXIT_FAILURE); + } + + /* copy startup code to CHIP RAM */ + memcpy (startfunc, ©all, startcodesize); + + if (debugflag) { + if (bi.ramdisk_size) + printf ("RAM disk at %#lx, size is %ldK\n", + (u_long)memptr + kexec.a_text + kexec.a_data, + bi.ramdisk_size); + + printf ("\nKernel text at %#lx, code size %x\n", + start_mem, kexec.a_text); + printf ("Kernel data at %#lx, data size %x\n", + start_mem + kexec.a_text, kexec.a_data ); + printf ("Kernel bss at %#lx, bss size %x\n", + start_mem + kexec.a_text + kexec.a_data, + kexec.a_bss ); + printf ("boot info at %#lx\n", start_mem + kexec.a_text + + kexec.a_data + kexec.a_bss); + + printf ("\nKernel entry is %#x\n", kexec.a_entry ); + + printf ("ramdisk dest top is %#lx\n", start_mem + mem_size); + printf ("ramdisk lower limit is %#lx\n", + (u_long)(memptr + kexec.a_text + kexec.a_data)); + printf ("ramdisk src top is %#lx\n", + (u_long)(memptr + kexec.a_text + kexec.a_data) + + rd_size); + + printf ("Type a key to continue the Linux boot..."); + fflush (stdout); + getchar(); + } + + /* wait for things to settle down */ + sleep(2); + + /* FN: If a Rainbow III board is present, reset it to disable */ + /* its (possibly activated) vertical blank interrupts as the */ + /* kernel is not yet prepared to handle them (level 6). */ + if (rb3_reg != NULL) + { + /* set RESET bit in special function register */ + *rb3_reg = 0x01; + /* actually, only a few cycles delay are required... */ + sleep(1); + /* clear reset bit */ + *rb3_reg = 0x00; + } + + /* the same stuff as above, for the Piccolo board. */ + /* this also has the side effect of resetting the board's */ + /* output selection logic to use the Amiga's display in single */ + /* monitor systems - which is currently what we want. */ + if (piccolo_reg != NULL) + { + /* set RESET bit in special function register */ + *piccolo_reg = 0x01; + /* actually, only a few cycles delay are required... */ + sleep(1); + /* clear reset bit */ + *piccolo_reg = 0x51; + } + + /* the same stuff as above, for the SD64 board. */ + /* just as on the Piccolo, this also resets the monitor switch */ + if (sd64_reg != NULL) + { + /* set RESET bit in special function register */ + *sd64_reg = 0x1f; + /* actually, only a few cycles delay are required... */ + sleep(1); + /* clear reset bit AND switch monitor bit (0x20) */ + *sd64_reg = 0x4f; + } + + if (GfxBase) { + /* set graphics mode to a nice normal one */ + LoadView (NULL); + CloseLibrary ((struct Library *)GfxBase); + } + + Disable(); + + /* Turn off all DMA */ + custom.dmacon = DMAF_ALL | DMAF_MASTER; + + /* turn off caches */ + CacheControl (0L, ~0L); + + /* Go into supervisor state */ + SuperState (); + + /* setup stack */ + change_stack ((char *) stack + TEMP_STACKSIZE); + + /* turn off any mmu translation */ + disable_mmu (); + + /* execute the copy-and-go code (from CHIP RAM) */ + startfunc(); + + /* NOTREACHED */ +} diff -u --recursive --new-file v1.3.93/linux/arch/m68k/boot/amiga/bootstrap.h linux/arch/m68k/boot/amiga/bootstrap.h --- v1.3.93/linux/arch/m68k/boot/amiga/bootstrap.h Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/boot/amiga/bootstrap.h Wed Dec 27 22:44:39 1995 @@ -0,0 +1,329 @@ +/* +** bootstrap.h -- This file is a part of the Amiga bootloader. +** +** Copyright 1993, 1994 by Hamish Macdonald +** +** Some minor additions by Michael Rausch 1-11-94 +** Modified 11-May-94 by Geert Uytterhoeven +** (Geert.Uytterhoeven@cs.kuleuven.ac.be) +** - inline Supervisor() call +** +** This file is subject to the terms and conditions of the GNU General Public +** License. See the file README.legal in the main directory of this archive +** for more details. +** +*/ + +#ifndef BOOTSTRAP_H +#define BOOTSTRAP_H + +#include +#include + +struct List { + struct Node *l_head; + struct Node *l_tail; + struct Node *l_tailpred; + u_char l_type; + u_char l_pad; +}; + +struct MemChunk { + struct MemChunk *mc_Next; /* pointer to next chunk */ + u_long mc_Bytes; /* chunk byte size */ +}; + +#define MEMF_CHIP (1<<1) +#define MEMF_FAST (1<<2) +#define MEMF_LOCAL (1<<8) +#define MEMF_CLEAR (1<<16) + +struct MemHeader { + struct Node mh_Node; + u_short mh_Attributes; /* characteristics of this region */ + struct MemChunk *mh_First; /* first free region */ + void *mh_Lower; /* lower memory bound */ + void *mh_Upper; /* upper memory bound+1 */ + u_long mh_Free; /* total number of free bytes */ +}; + +struct ExecBase { + u_char fill1[296]; + u_short AttnFlags; + u_char fill2[24]; + struct List MemList; + u_char fill3[194]; + u_char VBlankFrequency; + u_char PowerSupplyFrequency; + u_char fill4[36]; + u_long EClockFrequency; +}; + +#ifndef AFF_68020 +#define AFB_68020 1 +#define AFF_68020 (1<AttnFlags & AFF_68040) + __asm__ volatile ("moveq #0,d0;" + ".long 0x4e7b0003;" /* movec d0,tc */ + ".long 0x4e7b0004;" /* movec d0,itt0 */ + ".long 0x4e7b0005;" /* movec d0,itt1 */ + ".long 0x4e7b0006;" /* movec d0,dtt0 */ + ".long 0x4e7b0007" /* movec d0,dtt1 */ + : /* no outputs */ + : /* no inputs */ + : "d0"); + else { + __asm__ volatile ("subl #4,sp;" + "pmove tc,sp@;" + "bclr #7,sp@;" + "pmove sp@,tc;" + "addl #4,sp"); + if (SysBase->AttnFlags & AFF_68030) + __asm__ volatile ("clrl sp@-;" + ".long 0xf0170800;" /* pmove sp@,tt0 */ + ".long 0xf0170c00;" /* pmove sp@,tt1 */ + "addql #4,sp"); + } +} + +static __inline void jump_to (unsigned long addr) +{ + __asm__ volatile ("jmp %0@" :: "a" (addr)); + /* NOTREACHED */ +} + +#endif /* BOOTSTRAP_H */ diff -u --recursive --new-file v1.3.93/linux/arch/m68k/boot/atari/Makefile linux/arch/m68k/boot/atari/Makefile --- v1.3.93/linux/arch/m68k/boot/atari/Makefile Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/boot/atari/Makefile Wed Dec 27 22:44:40 1995 @@ -0,0 +1,12 @@ + +CC := d:/gnu/bin/gcc.ttp +CFLAGS := -Wall -O2 -fno-defer-pop -mint -s +LD := d:/gnu/bin/gcc.ttp +LDFLAGS := -mint -D__GNUC__ + +bootstra.ttp: bootstra.o + $(LD) $(LDFLAGS) -o $@ $^ + prgflags 7 7 $@ + cp $@ d:/linux + +bootstra.o: bootstra.c bootinfo.h diff -u --recursive --new-file v1.3.93/linux/arch/m68k/boot/atari/bootstrap.c linux/arch/m68k/boot/atari/bootstrap.c --- v1.3.93/linux/arch/m68k/boot/atari/bootstrap.c Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/boot/atari/bootstrap.c Mon Mar 4 22:36:11 1996 @@ -0,0 +1,999 @@ +/* +** bootstrap.c -- Load and launch the Atari Linux kernel +** +** Copyright 1993 by Arjan Knor +** +** This file is subject to the terms and conditions of the GNU General Public +** License. See the file README.legal in the main directory of this archive +** for more details. +** +** History: +** 10 Dec 1995 BOOTP/TFTP support (Roman) +** 03 Oct 1995 Allow kernel to be loaded to TT ram again (Andreas) +** 11 Jul 1995 Add support for ELF format kernel (Andreas) +** 16 Jun 1995 Adapted to Linux 1.2: kernel always loaded into ST ram +** (Andreas) +** 14 Nov 1994 YANML (Yet Another New Memory Layout :-) kernel +** start address is KSTART_ADDR + PAGE_SIZE, this +** does not need the ugly klugde with +** -fwritable-strings (++andreas) +** 09 Sep 1994 Adapted to the new memory layout: All the boot_info entry +** mentions all ST-Ram and the mover is located somewhere +** in the middle of memory (roman) +** Added the default arguments file known from the other +** bootstrap version +** 19 Feb 1994 Changed everything so that it works? (rdv) +** 14 Mar 1994 New mini-copy routine used (rdv) +*/ + +#include +#include +#include +#include +#include +#include +#include "sysvars.h" +#include +#include +#include + +/* linux specific include files */ +#include +#include +#include + +#define _LINUX_TYPES_H /* Hack to prevent including */ +#include + +/* Atari bootstrap include file */ +#include "bootstrap.h" + +#define MIN_RAMSIZE (3) /* 3 MB */ +#define TEMP_STACKSIZE 256 + +extern char *optarg; +extern int optind; +static void get_default_args( int *argc, char ***argv ); +/* This is missing in */ +extern int sync (void); + +struct bootinfo bi; +u_long *cookiejar; +u_long userstk; + +/* getcookie -- function to get the value of the given cookie. */ +static int getcookie(char *cookie, u_long *value) +{ + int i = 0; + + while(cookiejar[i] != 0L) { + if(cookiejar[i] == *(u_long *)cookie) { + *value = cookiejar[i + 1]; + return 1; + } + i += 2; + } + return -1; +} + +static void usage(void) +{ + fprintf(stderr, "Usage:\n" + "\tbootstrap [-dst] [-k kernel_executable] [-r ramdisk_file]" + " [option...]\n"); + exit(EXIT_FAILURE); +} + +/* + * Copy the kernel and the ramdisk to their final resting places. + * + * I assume that the kernel data and the ramdisk reside somewhere + * in the middle of the memory. + * + * This program itself should be somewhere in the first 4096 bytes of memory + * where the kernel never will be. In this way it can never be overwritten + * by itself. + * + * At this point the registers have: + * a0: the start of the final kernel + * a1: the start of the current kernel + * a2: the end of the final ramdisk + * a3: the end of the current ramdisk + * d0: the kernel size + * d1: the ramdisk size + */ +asm (" +.text +.globl _copyall, _copyallend +_copyall: + + movel a0,a4 /* save the start of the kernel for booting */ + +1: movel a1@+,a0@+ /* copy the kernel starting at the beginning */ + subql #4,d0 + jcc 1b + + tstl d1 + beq 3f + +2: movel a3@-,a2@- /* copy the ramdisk starting at the end */ + subql #4,d1 + jcc 2b + +3: jmp a4@ /* jump to the start of the kernel */ +_copyallend: +"); + +extern char copyall, copyallend; + + +/* Test for a Medusa: This is the only machine on which address 0 is + * writeable! + * ...err! On the Afterburner040 (for the Falcon) it's the same... So we do + * another test with 0x00ff82fe, that gives a bus error on the Falcon, but is + * in the range where the Medusa always asserts DTACK. + */ + +int test_medusa( void ) + +{ int rv = 0; + + __asm__ __volatile__ + ( "movel 0x8,a0\n\t" + "movel sp,a1\n\t" + "moveb 0x0,d1\n\t" + "movel #Lberr,0x8\n\t" + "moveq #0,%0\n\t" + "clrb 0x0\n\t" + "nop \n\t" + "moveb d1,0x0\n\t" + "nop \n\t" + "tstb 0x00ff82fe\n\t" + "nop \n\t" + "moveq #1,%0\n" + "Lberr:\t" + "movel a1,sp\n\t" + "movel a0,0x8" + : "=d" (rv) + : /* no inputs */ + : "d1", "a0", "a1", "memory" ); + + return( rv ); +} + + +void get_medusa_bank_sizes( u_long *bank1, u_long *bank2 ) + +{ static u_long save_addr; + u_long test_base, saved_contents[16]; +#define TESTADDR(i) (*((u_long *)((char *)test_base + i*8*MB))) +#define TESTPAT 0x12345678 + unsigned short oldflags; + int i; + + /* This ensures at least that none of the test addresses conflicts + * with the test code itself */ + test_base = ((unsigned long)&save_addr & 0x007fffff) | 0x20000000; + *bank1 = *bank2 = 0; + + /* Interrupts must be disabled because arbitrary addresses may be + * temporarily overwritten, even code of an interrupt handler */ + __asm__ __volatile__ ( "movew sr,%0; oriw #0x700,sr" : "=g" (oldflags) : ); + disable_cache(); + + /* save contents of the test addresses */ + for( i = 0; i < 16; ++i ) + saved_contents[i] = TESTADDR(i); + + /* write 0s into all test addresses */ + for( i = 0; i < 16; ++i ) + TESTADDR(i) = 0; + + /* test for bank 1 */ +#if 0 + /* This is Freddi's original test, but it didn't work. */ + TESTADDR(0) = TESTADDR(1) = TESTPAT; + if (TESTADDR(1) == TESTPAT) { + if (TESTADDR(2) == TESTPAT) + *bank1 = 8*MB; + else if (TESTADDR(3) == TESTPAT) + *bank1 = 16*MB; + else + *bank1 = 32*MB; + } + else { + if (TESTADDR(2) == TESTPAT) + *bank1 = 0; + else + *bank1 = 16*MB; + } +#else + TESTADDR(0) = TESTPAT; + if (TESTADDR(1) == TESTPAT) + *bank1 = 8*MB; + else if (TESTADDR(2) == TESTPAT) + *bank1 = 16*MB; + else if (TESTADDR(4) == TESTPAT) + *bank1 = 32*MB; + else + *bank1 = 64*MB; +#endif + + /* test for bank2 */ + if (TESTADDR(8) != 0) + *bank2 = 0; + else { + TESTADDR(8) = TESTPAT; + if (TESTADDR(9) != 0) { + if (TESTADDR(10) == TESTPAT) + *bank2 = 8*MB; + else + *bank2 = 32*MB; + } + else { + TESTADDR(9) = TESTPAT; + if (TESTADDR(10) == TESTPAT) + *bank2 = 16*MB; + else + *bank2 = 64*MB; + } + } + + /* restore contents of the test addresses and restore interrupt mask */ + for( i = 0; i < 16; ++i ) + TESTADDR(i) = saved_contents[i]; + __asm__ __volatile__ ( "movew %0,sr" : : "g" (oldflags) ); +} + +#undef TESTADDR +#undef TESTPAT + +#ifdef USE_BOOTP +# include "bootp.h" +#else +# define kread read +# define klseek lseek +# define kclose close +#endif + + +/* ++andreas: this must be inline due to Super */ +static inline void boot_exit (int) __attribute__ ((noreturn)); +static inline void boot_exit(int status) +{ + /* first go back to user mode */ + (void)Super(userstk); + getchar(); + exit(status); +} + +int main(int argc, char *argv[]) +{ + int debugflag = 0, ch, kfd, rfd = -1, i, ignore_ttram = 0; + int load_to_stram = 0; + char *ramdisk_name, *kernel_name, *memptr; + u_long ST_ramsize, TT_ramsize, memreq; + u_long cpu_type, fpu_type, mch_type, mint; + struct exec kexec; + int elf_kernel = 0; + Elf32_Ehdr kexec_elf; + Elf32_Phdr *kernel_phdrs = NULL; + u_long start_mem, mem_size, rd_size, text_offset = 0, kernel_size; +#ifdef USE_BOOTP + int prefer_bootp = 1, kname_set = 0; +#endif + + ramdisk_name = NULL; + kernel_name = "vmlinux"; + + /* print the startup message */ + puts("\fLinux/68k Atari Bootstrap version 1.6" +#ifdef USE_BOOTP + " (with BOOTP)" +#endif + ); + puts("Copyright 1993,1994 by Arjan Knor, Robert de Vries, Roman Hodek, Andreas Schwab\n"); + + /* ++roman: If no arguments on the command line, read them from + * file */ + if (argc == 1) + get_default_args( &argc, &argv ); + + /* machine is Atari */ + bi.machtype = MACH_ATARI; + + /* check arguments */ +#ifdef USE_BOOTP + while ((ch = getopt(argc, argv, "bdtsk:r:")) != EOF) +#else + while ((ch = getopt(argc, argv, "dtsk:r:")) != EOF) +#endif + switch (ch) { + case 'd': + debugflag = 1; + break; + case 't': + ignore_ttram = 1; + break; + case 's': + load_to_stram = 1; + break; + case 'k': + kernel_name = optarg; +#ifdef USE_BOOTP + kname_set = 1; +#endif + break; + case 'r': + ramdisk_name = optarg; + break; +#ifdef USE_BOOTP + case 'b': + prefer_bootp = 1; + break; +#endif + case '?': + default: + usage(); + } + + argc -= optind; + argv += optind; + + /* We have to access some system variables to get + * the information we need, so we must switch to + * supervisor mode first. + */ + userstk = Super(0L); + + /* get the info we need from the cookie-jar */ + cookiejar = *_p_cookies; + if(cookiejar == 0L) { + /* if we find no cookies, it's probably an ST */ + fprintf(stderr, "Error: No cookiejar found. Is this an ST?\n"); + boot_exit(EXIT_FAILURE); + } + + /* Exit if MiNT/MultiTOS is running. */ + if(getcookie("MiNT", &mint) != -1) + { + puts("Warning: MiNT is running\n"); +#if 0 + puts("Linux cannot be started when MiNT is running. Aborting...\n"); + boot_exit(EXIT_FAILURE); +#endif + } + + /* get _CPU, _FPU and _MCH */ + getcookie("_CPU", &cpu_type); + getcookie("_FPU", &fpu_type); + getcookie("_MCH", &mch_type); + + /* check if we are on a 68030/40 with FPU */ + if ((cpu_type != 30 && cpu_type != 40 && cpu_type != 60) || + (fpu_type >> 16) < 2) + { + puts("Machine type currently not supported. Aborting..."); + boot_exit(EXIT_FAILURE); + } + + switch(cpu_type) { + case 0: + case 10: break; + case 20: bi.cputype = CPU_68020; break; + case 30: bi.cputype = CPU_68030; break; + case 40: bi.cputype = CPU_68040; break; + case 60: bi.cputype = CPU_68060; break; + default: + fprintf(stderr, "Error: Unknown CPU type. Aborting...\n"); + boot_exit(EXIT_FAILURE); + break; + } + + printf("CPU: %ld; ", cpu_type + 68000); + printf("FPU: "); + + /* check for FPU; in case of a '040 or '060, don't look at _FPU itself, + * some software may set it to wrong values (68882 or the like) */ + if (cpu_type == 40) { + bi.cputype |= FPU_68040; + puts( "68040\n" ); + } + else if (cpu_type == 60) { + bi.cputype |= FPU_68060; + puts( "68060\n" ); + } + else { + switch ((fpu_type >> 16) & 6) { + case 0: + puts("not present\n"); + break; + case 2: + /* try to determine real type */ + if (fpu_idle_frame_size () != 0x18) + goto m68882; + /* fall through */ + case 4: + bi.cputype |= FPU_68881; + puts("68881\n"); + break; + case 6: + m68882: + bi.cputype |= FPU_68882; + puts("68882\n"); + break; + default: + puts("Unknown FPU type. Assuming no FPU."); + break; + } + } + + memset(&bi.bi_atari.hw_present, 0, sizeof(bi.bi_atari.hw_present)); + + /* Get the amounts of ST- and TT-RAM. */ + /* The size must be a multiple of 1MB. */ + i = 0; + + if (!test_medusa()) { + struct { + unsigned short version; /* version - currently 1 */ + unsigned long fr_start; /* start addr FastRAM */ + unsigned long fr_len; /* length FastRAM */ + } *magn_cookie; + struct { + unsigned long version; + unsigned long fr_start; /* start addr */ + unsigned long fr_len; /* length */ + } *fx_cookie; + + TT_ramsize = 0; + if (!ignore_ttram) { + /* "Original" or properly emulated TT-Ram */ + if (*ramtop) { + /* the 'ramtop' variable at 0x05a4 is not + * officially documented. We use it anyway + * because it is the only way to get the TTram size. + * (It is zero if there is no TTram.) + */ + bi.memory[i].addr = TT_RAM_BASE; + bi.memory[i].size = (*ramtop - TT_RAM_BASE) & ~(MB - 1); + TT_ramsize = bi.memory[i].size / MB; + i++; + printf("TT-RAM: %ld Mb; ", TT_ramsize); + } + + /* test for MAGNUM alternate RAM + * added 26.9.1995 M. Schwingen, rincewind@discworld.oche.de + */ + if (getcookie("MAGN", (u_long *)&magn_cookie) != -1) { + bi.memory[i].addr = magn_cookie->fr_start; + bi.memory[i].size = magn_cookie->fr_len & ~(MB - 1); + TT_ramsize += bi.memory[i].size / MB; + printf("MAGNUM alternate RAM: %ld Mb; ", bi.memory[i].size/MB); + i++; + } + + /* BlowUps FX */ + if (getcookie("BPFX", (u_long *)&fx_cookie) != -1 && fx_cookie) { + /* if fx is set (cookie call above), + * we assume that BlowUps FX-card + * is installed. (Nat!) + */ + bi.memory[i].addr = fx_cookie->fr_start; + bi.memory[i].size = fx_cookie->fr_len & ~(MB - 1); + printf("FX alternate RAM: %ld Mb; ", bi.memory[i].size/MB); + i++; + } + } + + bi.memory[i].addr = 0; + bi.memory[i].size = *phystop & ~(MB - 1); + ST_ramsize = bi.memory[i].size / MB; + i++; + printf("ST-RAM: %ld Mb\n", ST_ramsize ); + + bi.num_memory = i; + + if (load_to_stram && i > 1) { + /* Put ST-RAM first in the list of mem blocks */ + struct mem_info temp = bi.memory[i - 1]; + bi.memory[i - 1] = bi.memory[0]; + bi.memory[0] = temp; + } + } + else { + u_long bank1, bank2, medusa_st_ram; + + get_medusa_bank_sizes( &bank1, &bank2 ); + medusa_st_ram = *phystop & ~(MB - 1); + bank1 -= medusa_st_ram; + TT_ramsize = 0; + + bi.memory[i].addr = 0; + bi.memory[i].size = medusa_st_ram; + ST_ramsize = bi.memory[i].size / MB; + i++; + printf("Medusa pseudo ST-RAM from bank 1: %ld Mb; ", ST_ramsize ); + + if (!ignore_ttram && bank1 > 0) { + bi.memory[i].addr = 0x20000000 + medusa_st_ram; + bi.memory[i].size = bank1; + TT_ramsize += bank1; + i++; + printf("TT-RAM bank 1: %ld Mb; ", bank1/MB ); + } + + if (!ignore_ttram && bank2 > 0) { + bi.memory[i].addr = 0x24000000; + bi.memory[i].size = bank2; + TT_ramsize += bank2; + i++; + printf("TT-RAM bank 2: %ld Mb; ", bank2/MB ); + } + + bi.num_memory = i; + printf("\n"); + } + + /* verify that there is enough RAM; ST- and TT-RAM combined */ + if (ST_ramsize + TT_ramsize < MIN_RAMSIZE) { + puts("Not enough RAM. Aborting..."); + boot_exit(10); + } + +#if 0 + /* Get language/keyboard info */ + /* TODO: do we need this ? */ + /* Could be used to auto-select keyboard map later on. (rdv) */ + if (getcookie("_AKP",&language) == -1) + { + /* Get the language info from the OS-header */ + os_header = *_sysbase; + os_header = os_header->os_beg; + lang = (os_header->os_conf) >> 1; + printf("Language: "); + switch(lang) { + case HOL: puts("Dutch"); break; /* Own country first :-) */ + case USA: puts("American"); break; + case SWG: puts("Switzerland (German)"); break; + case FRG: puts("German"); break; + case FRA: puts("French"); break; + case SWF: puts("Switzerland (French)"); break; + case UK: puts("English"); break; + case SPA: puts("Spanish"); break; + case ITA: puts("Italian"); break; + case SWE: puts("Swedish"); break; + case TUR: puts("Turkey"); break; + case FIN: puts("Finnish"); break; + case NOR: puts("Norwegian"); break; + case DEN: puts("Danish"); break; + case SAU: puts("Saudi-Arabian"); break; + default: puts("Unknown"); break; + } + } + else + { + printf("Language: "); + switch(language & 0x0F) + { + case 1: printf("German "); break; + case 2: printf("French "); break; + case 4: printf("Spanish "); break; + case 5: printf("Italian "); break; + case 7: printf("Swiss French "); break; + case 8: printf("Swiss German "); break; + default: printf("English "); + } + printf("Keyboard type :"); + switch(language >> 8) + { + case 1: printf("German "); break; + case 2: printf("French "); break; + case 4: printf("Spanish "); break; + case 5: printf("Italian "); break; + case 7: printf("Swiss French "); break; + case 8: printf("Swiss German "); break; + default: printf("English "); + } + printf("\n"); + } +#endif + + /* Pass contents of the _MCH cookie to the kernel */ + bi.bi_atari.mch_cookie = mch_type; + + /* + * Copy command line options into the kernel command line. + */ + i = 0; + while (argc--) { + if ((i+strlen(*argv)+1) < CL_SIZE) { + i += strlen(*argv) + 1; + if (bi.command_line[0]) + strcat (bi.command_line, " "); + strcat (bi.command_line, *argv++); + } + } + printf ("Command line is '%s'\n", bi.command_line); + + start_mem = bi.memory[0].addr; + mem_size = bi.memory[0].size; + + /* tell us where the kernel will go */ + printf("\nThe kernel will be located at 0x%08lx\n", start_mem); + +#ifdef TEST + /* + ** Temporary exit point for testing + */ + boot_exit(-1); +#endif /* TEST */ + +#ifdef USE_BOOTP + kfd = -1; + if (prefer_bootp) { + /* First try to get a remote kernel, then use a local kernel (if + * present) */ + if (get_remote_kernel( kname_set ? kernel_name : NULL ) < 0) { + printf( "\nremote boot failed; trying local kernel\n" ); + if ((kfd = open (kernel_name, O_RDONLY)) == -1) { + fprintf (stderr, "Unable to open kernel file %s\n", + kernel_name); + boot_exit (EXIT_FAILURE); + } + } + } + else { + /* Try BOOTP if local kernel cannot be opened */ + if ((kfd = open (kernel_name, O_RDONLY)) == -1) { + printf( "\nlocal kernel failed; trying remote boot\n" ); + if (get_remote_kernel( kname_set ? kernel_name : NULL ) < 0) { + fprintf (stderr, "Unable to remote boot and " + "to open kernel file %s\n", kernel_name); + boot_exit (EXIT_FAILURE); + } + } + } +#else + /* open kernel executable and read exec header */ + if ((kfd = open (kernel_name, O_RDONLY)) == -1) { + fprintf (stderr, "Unable to open kernel file %s\n", kernel_name); + boot_exit (EXIT_FAILURE); + } +#endif + + if (kread (kfd, (void *)&kexec, sizeof(kexec)) != sizeof(kexec)) + { + fprintf (stderr, "Unable to read exec header from %s\n", kernel_name); + boot_exit (EXIT_FAILURE); + } + + switch (N_MAGIC(kexec)) { + case ZMAGIC: + text_offset = N_TXTOFF(kexec); + break; + case QMAGIC: + text_offset = sizeof(kexec); + /* the text size includes the exec header; remove this */ + kexec.a_text -= sizeof(kexec); + break; + default: + /* Try to parse it as an ELF header */ + klseek (kfd, 0, SEEK_SET); + if (kread (kfd, (void *)&kexec_elf, sizeof (kexec_elf)) == sizeof (kexec_elf) + && memcmp (&kexec_elf.e_ident[EI_MAG0], ELFMAG, SELFMAG) == 0) + { + elf_kernel = 1; + /* A few plausability checks */ + if (kexec_elf.e_type != ET_EXEC || kexec_elf.e_machine != EM_68K + || kexec_elf.e_version != EV_CURRENT) + { + fprintf (stderr, "Invalid ELF header contents in kernel\n"); + boot_exit (EXIT_FAILURE); + } + /* Load the program headers */ + kernel_phdrs = (Elf32_Phdr *) Malloc (kexec_elf.e_phnum * sizeof (Elf32_Phdr)); + if (kernel_phdrs == NULL) + { + fprintf (stderr, "Unable to allocate memory for program headers\n"); + boot_exit (EXIT_FAILURE); + } + klseek (kfd, kexec_elf.e_phoff, SEEK_SET); + if (kread (kfd, (void *) kernel_phdrs, + kexec_elf.e_phnum * sizeof (*kernel_phdrs)) + != kexec_elf.e_phnum * sizeof (*kernel_phdrs)) + { + fprintf (stderr, "Unable to read programm headers from %s\n", + kernel_name); + boot_exit (EXIT_FAILURE); + } + break; + } + fprintf (stderr, "Wrong magic number %lo in kernel header\n", + N_MAGIC(kexec)); + boot_exit (EXIT_FAILURE); + } + + /* Load the kernel one page after start of mem */ + start_mem += PAGE_SIZE; + mem_size -= PAGE_SIZE; + /* Align bss size to multiple of four */ + if (!elf_kernel) + kexec.a_bss = (kexec.a_bss + 3) & ~3; + + /* init ramdisk */ + if(ramdisk_name) { + if((rfd = open(ramdisk_name, O_RDONLY)) == -1) { + fprintf(stderr, "Unable to open ramdisk file %s\n", + ramdisk_name); + boot_exit(EXIT_FAILURE); + } + bi.ramdisk_size = (lseek(rfd, 0, SEEK_END) + 1023) / 1024; + } + else + bi.ramdisk_size = 0; + + rd_size = bi.ramdisk_size << 10; + if (mem_size - rd_size < MB && bi.num_memory > 1) + /* If running low on ST ram load ramdisk into alternate ram. */ + bi.ramdisk_addr = (u_long) bi.memory[1].addr + bi.memory[1].size - rd_size; + else + /* Else hopefully there is enough ST ram. */ + bi.ramdisk_addr = (u_long)start_mem + mem_size - rd_size; + + /* calculate the total required amount of memory */ + if (elf_kernel) + { + u_long min_addr = 0xffffffff, max_addr = 0; + for (i = 0; i < kexec_elf.e_phnum; i++) + { + if (min_addr > kernel_phdrs[i].p_vaddr) + min_addr = kernel_phdrs[i].p_vaddr; + if (max_addr < kernel_phdrs[i].p_vaddr + kernel_phdrs[i].p_memsz) + max_addr = kernel_phdrs[i].p_vaddr + kernel_phdrs[i].p_memsz; + } + /* This is needed for newer linkers that include the header in + the first segment. */ + if (min_addr == 0) + { + min_addr = PAGE_SIZE; + kernel_phdrs[0].p_vaddr += PAGE_SIZE; + kernel_phdrs[0].p_offset += PAGE_SIZE; + kernel_phdrs[0].p_filesz -= PAGE_SIZE; + kernel_phdrs[0].p_memsz -= PAGE_SIZE; + } + kernel_size = max_addr - min_addr; + } + else + kernel_size = kexec.a_text + kexec.a_data + kexec.a_bss; + memreq = kernel_size + sizeof (bi) + rd_size; + + /* allocate RAM for the kernel */ + if (!(memptr = (char *)Malloc (memreq))) + { + fprintf (stderr, "Unable to allocate memory for kernel and ramdisk\n"); + boot_exit (EXIT_FAILURE); + } + else + fprintf(stderr, "kernel at address %lx\n", (u_long) memptr); + + (void)memset(memptr, 0, memreq); + + /* read the text and data segments from the kernel image */ + if (elf_kernel) + { + for (i = 0; i < kexec_elf.e_phnum; i++) + { + if (klseek (kfd, kernel_phdrs[i].p_offset, SEEK_SET) == -1) + { + fprintf (stderr, "Failed to seek to segment %d\n", i); + boot_exit (EXIT_FAILURE); + } + if (kread (kfd, memptr + kernel_phdrs[i].p_vaddr - PAGE_SIZE, + kernel_phdrs[i].p_filesz) + != kernel_phdrs[i].p_filesz) + { + fprintf (stderr, "Failed to read segment %d\n", i); + boot_exit (EXIT_FAILURE); + } + } + } + else + { + if (klseek (kfd, text_offset, SEEK_SET) == -1) + { + fprintf (stderr, "Failed to seek to text\n"); + Mfree ((void *)memptr); + boot_exit (EXIT_FAILURE); + } + + if (kread (kfd, memptr, kexec.a_text) != kexec.a_text) + { + fprintf (stderr, "Failed to read text\n"); + Mfree ((void *)memptr); + boot_exit (EXIT_FAILURE); + } + + /* data follows immediately after text */ + if (kread (kfd, memptr + kexec.a_text, kexec.a_data) != kexec.a_data) + { + fprintf (stderr, "Failed to read data\n"); + Mfree ((void *)memptr); + boot_exit (EXIT_FAILURE); + } + } + kclose (kfd); + + /* copy the boot_info struct to the end of the kernel image */ + memcpy ((void *)(memptr + kernel_size), + &bi, sizeof(bi)); + + /* read the ramdisk image */ + if (rfd != -1) + { + if (lseek (rfd, 0, SEEK_SET) == -1) + { + fprintf (stderr, "Failed to seek to beginning of ramdisk file\n"); + Mfree ((void *)memptr); + boot_exit (EXIT_FAILURE); + } + if (read (rfd, memptr + kernel_size + sizeof (bi), + rd_size) != rd_size) + { + fprintf (stderr, "Failed to read ramdisk file\n"); + Mfree ((void *)memptr); + boot_exit (EXIT_FAILURE); + } + close (rfd); + } + + /* for those who want to debug */ + if (debugflag) + { + if (bi.ramdisk_size) + printf ("RAM disk at %#lx, size is %ldK\n", + (u_long)memptr + kernel_size, + bi.ramdisk_size); + + if (elf_kernel) + { + for (i = 0; i < kexec_elf.e_phnum; i++) + { + printf ("Kernel segment %d at %#lx, size %ld\n", i, + start_mem + kernel_phdrs[i].p_vaddr - PAGE_SIZE, + kernel_phdrs[i].p_memsz); + } + } + else + { + printf ("\nKernel text at %#lx, code size %d\n", + start_mem, kexec.a_text); + printf ("Kernel data at %#lx, data size %d\n", + start_mem + kexec.a_text, kexec.a_data ); + printf ("Kernel bss at %#lx, bss size %d\n", + start_mem + kexec.a_text + kexec.a_data, kexec.a_bss ); + } + printf ("\nboot_info is at %#lx\n", + start_mem + kernel_size); + printf ("\nKernel entry is %#lx\n", + elf_kernel ? kexec_elf.e_entry : kexec.a_entry); + printf ("ramdisk dest top is %#lx\n", bi.ramdisk_addr + rd_size); + printf ("ramdisk lower limit is %#lx\n", + (u_long)(memptr + kernel_size)); + printf ("ramdisk src top is %#lx\n", + (u_long)(memptr + kernel_size) + + rd_size); + + printf ("Type a key to continue the Linux boot..."); + fflush (stdout); + getchar(); + } + + printf("Booting Linux...\n"); + + sync (); + + /* turn off interrupts... */ + disable_interrupts(); + + /* turn off caches... */ + disable_cache(); + + /* ..and any MMU translation */ + disable_mmu(); + + /* ++guenther: allow reset if launched with MiNT */ + *(long*)0x426 = 0; + + /* copy mover code to a safe place if needed */ + memcpy ((void *) 0x400, ©all, ©allend - ©all); + + /* setup stack */ + change_stack ((void *) PAGE_SIZE); + + /* + * On the Atari you can have two situations: + * 1. One piece of contiguous RAM (Falcon) + * 2. Two pieces of contiguous RAM (TT) + * In case 2 you can load your program into ST-ram and load your data in + * any old RAM you have left. + * In case 1 you could overwrite your own program when copying the + * kernel and ramdisk to their final positions. + * To solve this the mover code is copied to a safe place first. + * Then this program jumps to the mover code. After the mover code + * has finished it jumps to the start of the kernel in its new position. + * I thought the memory just after the interrupt vector table was a safe + * place because it is used by TOS to store some system variables. + * This range goes from 0x400 to approx. 0x5B0. + * This is more than enough for the miniscule mover routine (16 bytes). + */ + + jump_to_mover((char *) start_mem, memptr, + (char *) bi.ramdisk_addr + rd_size, memptr + memreq, + kernel_size + sizeof (bi), + rd_size, + (void *) 0x400); + + for (;;); + /* NOTREACHED */ +} + + + +#define MAXARGS 30 + +static void get_default_args( int *argc, char ***argv ) + +{ FILE *f; + static char *nargv[MAXARGS]; + char arg[256], *p; + int c, quote, state; + + if (!(f = fopen( "bootargs", "r" ))) + return; + + *argc = 1; + if (***argv) + nargv[0] = **argv; + else + nargv[0] = "bootstrap"; + *argv = nargv; + + quote = state = 0; + p = arg; + while( (c = fgetc(f)) != EOF ) { + + if (state == 0) { + /* outside args, skip whitespace */ + if (!isspace(c)) { + state = 1; + p = arg; + } + } + + if (state) { + /* inside an arg: copy it into 'arg', obeying quoting */ + if (!quote && (c == '\'' || c == '"')) + quote = c; + else if (quote && c == quote) + quote = 0; + else if (!quote && isspace(c)) { + /* end of this arg */ + *p = 0; + nargv[(*argc)++] = strdup(arg); + state = 0; + } + else + *p++ = c; + } + } + if (state) { + /* last arg finished by EOF! */ + *p = 0; + nargv[(*argc)++] = strdup(arg); + } + fclose( f ); + + nargv[*argc] = 0; +} + diff -u --recursive --new-file v1.3.93/linux/arch/m68k/boot/atari/bootstrap.h linux/arch/m68k/boot/atari/bootstrap.h --- v1.3.93/linux/arch/m68k/boot/atari/bootstrap.h Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/boot/atari/bootstrap.h Mon Mar 4 22:36:11 1996 @@ -0,0 +1,147 @@ +/* +** bootstrap.h -- This file is a part of the Atari bootloader. +** +** Copyright 1993 by Arjan Knor +** +** Modified by Andreas Schwab +** - clear transparent translation registers +** +** This file is subject to the terms and conditions of the GNU General Public +** License. See the file README.legal in the main directory of this archive +** for more details. +** +*/ + +#ifndef BOOTSTRAP_H +#define BOOTSTRAP_H + +/* _MCH cookie values */ +#define MACH_ST 0 +#define MACH_STE 1 +#define MACH_TT 2 +#define MACH_FALCON 3 + +/* some constants for memory handling */ +#define ST_RAM 0 +#define TT_RAM 1 +#define TT_RAM_BASE (u_long)(0x01000000) +#define MB (1024 * 1024) +#define START_MEM (bi.memory[0].addr) +#define MEM_SIZE (bi.memory[0].size) + +/* the various CPU- and FPU-types */ +#define AFF_68000 (1) +#define AFF_68020 (2) +#define AFF_68030 (4) +#define AFF_68040 (8) +#define AFF_68881 (16) +#define AFF_68882 (32) + +/* the possible OS-languages */ +#define USA 0 +#define FRG 1 +#define FRA 2 +#define UK 3 +#define SPA 4 +#define ITA 5 +#define SWE 6 +#define SWF 7 +#define SWG 8 +#define TUR 9 +#define FIN 10 +#define NOR 11 +#define DEN 12 +#define SAU 13 +#define HOL 14 + +/* some inline functions */ + +static __inline int fpu_idle_frame_size (void) +{ + char fpu_frame[216]; + __asm__ __volatile__ ("fnop"::); + __asm__ __volatile__ ("fsave %0@" : : "a" (fpu_frame)); + return fpu_frame[1]; +} + +static __inline void change_stack (u_long *stackp) +{ + __asm__ volatile ("movel %0,sp\n\t" :: "g" (stackp) : "sp"); +} + +static __inline void disable_interrupts (void) +{ + __asm__ volatile ("orw #0x700,sr":); +} + +extern struct bootinfo bi; +static __inline void disable_cache (void) +{ + __asm__ volatile ("movec %0,cacr" :: "d" (0)); + if (bi.cputype & CPU_68060) { + /* '060: clear branch cache after disabling it; + * disable superscalar operation (and enable FPU) */ + __asm__ volatile ("movec %0,cacr" :: "d" (0x00400000)); + __asm__ volatile ("moveq #0,d0;" + ".long 0x4e7b0808" /* movec d0,pcr */ + : /* no outputs */ + : /* no inputs */ + : "d0"); + } +} + +static __inline void disable_mmu (void) +{ + if (bi.cputype & (CPU_68040|CPU_68060)) { + __asm__ volatile ("moveq #0,d0;" + ".long 0x4e7b0003;" /* movec d0,tc */ + ".long 0x4e7b0004;" /* movec d0,itt0 */ + ".long 0x4e7b0005;" /* movec d0,itt1 */ + ".long 0x4e7b0006;" /* movec d0,dtt0 */ + ".long 0x4e7b0007" /* movec d0,dtt1 */ + : /* no outputs */ + : /* no inputs */ + : "d0"); + } + else { + __asm__ volatile ("subl #4,sp\n\t" + "pmove tc,sp@\n\t" + "bclr #7,sp@\n\t" + "pmove sp@,tc\n\t" + "addl #4,sp"); + if (bi.cputype & CPU_68030) { + __asm__ volatile ("clrl sp@-\n\t" + ".long 0xf0170800\n\t" /* pmove sp@,tt0 */ + ".long 0xf0170c00\n\t" /* pmove sp@,tt1 */ + "addl #4,sp\n"); + } + } +} + +static __inline void jump_to_mover (void *, void *, void *, void *, int, int, + void *) __attribute__ ((noreturn)); +static __inline void jump_to_mover (void *kernel_start, void *mem_start, + void *ramdisk_end, void *mem_end, + int kernel_size, int ramdisk_size, + void *mover_addr) +{ + asm volatile ("movel %0,a0\n\t" + "movel %1,a1\n\t" + "movel %2,a2\n\t" + "movel %3,a3\n\t" + "movel %4,d0\n\t" + "movel %5,d1\n\t" + "jmp %6@\n" + : /* no outputs */ + : "g" (kernel_start), "g" (mem_start), + "g" (ramdisk_end), "g" (mem_end), + "g" (kernel_size), "g" (ramdisk_size), + "a" (mover_addr) + : "a0", "a1", "a2", "a3", "d0", "d1"); + + /* Avoid warning that function may return */ + for (;;) ; +} + +#endif /* BOOTSTRAP_H */ + diff -u --recursive --new-file v1.3.93/linux/arch/m68k/boot/atari/sysvars.h linux/arch/m68k/boot/atari/sysvars.h --- v1.3.93/linux/arch/m68k/boot/atari/sysvars.h Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/boot/atari/sysvars.h Wed Dec 27 22:44:47 1995 @@ -0,0 +1,22 @@ +typedef struct _osheader +{ + unsigned short os_entry; + unsigned short os_version; + void *reseth; + struct _osheader *os_beg; + void *os_end; + long os_rsv1; + void *os_magic; + long os_date; + unsigned short os_conf; + unsigned short os_dosdate; + char **p_root; + unsigned char **pkbshift; + void **p_run; + char *p_rsv2; +} OSHEADER; + +#define phystop ((unsigned long *)0x42e) +#define _sysbase ((OSHEADER **)0x4f2) +#define _p_cookies ((unsigned long **)0x5a0) +#define ramtop ((unsigned long *)0x5a4) diff -u --recursive --new-file v1.3.93/linux/arch/m68k/config.in linux/arch/m68k/config.in --- v1.3.93/linux/arch/m68k/config.in Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/config.in Thu Apr 18 02:01:36 1996 @@ -0,0 +1,171 @@ +# +# For a description of the syntax of this configuration file, +# see the Configure script. +# +mainmenu_name "Linux/68k Kernel Configuration" + +mainmenu_option next_comment +comment 'Loadable module support' +bool 'Enable loadable module support' CONFIG_MODULES +if [ "$CONFIG_MODULES" = "y" ]; then + bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS + bool 'Kernel daemon support (e.g. autoload of modules)' CONFIG_KERNELD +fi +endmenu + +mainmenu_option next_comment +comment 'General setup' + +bool 'Amiga support' CONFIG_AMIGA +bool 'Atari support' CONFIG_ATARI +bool 'Macintosh support' CONFIG_MAC +bool '68040 floating point software package' CONFIG_FPSP_040 +bool '68060 integer/floating point software package' CONFIG_IFPSP_060 +bool 'Networking support' CONFIG_NET +bool 'System V IPC' CONFIG_SYSVIPC +tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT +tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF +if [ "$CONFIG_BINFMT_ELF" = "y" ]; then + bool 'Compile kernel as ELF - if your GCC is ELF-GCC' CONFIG_KERNEL_ELF +fi +if [ "$CONFIG_AMIGA" = "y" ]; then + bool 'Amiga AutoConfig Identification' CONFIG_ZORRO +fi +endmenu + +# +# Block device driver configuration +# +mainmenu_option next_comment +comment 'Floppy, IDE, and other block devices' + +tristate 'Normal floppy disk support' CONFIG_BLK_DEV_FD +bool 'IDE harddisk support' CONFIG_BLK_DEV_IDE +if [ "$CONFIG_AMIGA" = "y" ]; then +bool 'Amiga Cybervision support' CONFIG_FB_CYBER +bool 'Amiga Zorro II ramdisk support' CONFIG_AMIGA_Z2RAM +fi +if [ "$CONFIG_ATARI" = "y" ]; then +bool 'Atari ACSI support' CONFIG_ATARI_ACSI +fi + +tristate 'RAM disk support' CONFIG_BLK_DEV_RAM +if [ "$CONFIG_BLK_DEV_RAM" = "y" ]; then + bool ' Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD +fi + +tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP +endmenu + +if [ "$CONFIG_NET" = "y" ]; then + source net/Config.in +fi + +mainmenu_option next_comment +comment 'SCSI support' + +tristate 'SCSI support' CONFIG_SCSI + +if [ "$CONFIG_SCSI" != "n" ]; then + +comment 'SCSI support type (disk, tape, CDrom)' + +dep_tristate 'SCSI disk support' CONFIG_BLK_DEV_SD $CONFIG_SCSI +dep_tristate 'SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI +dep_tristate 'SCSI CDROM support' CONFIG_BLK_DEV_SR $CONFIG_SCSI +dep_tristate 'SCSI generic support' CONFIG_CHR_DEV_SG $CONFIG_SCSI + +comment 'Some SCSI devices (e.g. CD jukebox) support multiple LUNs' + +bool 'Probe all LUNs on each SCSI device' CONFIG_SCSI_MULTI_LUN + +bool 'Verbose SCSI error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS + +mainmenu_option next_comment +comment 'SCSI low-level drivers' + +if [ "$CONFIG_AMIGA" = "y" ]; then +bool 'A3000 WD33C93A support' CONFIG_A3000_SCSI +bool 'A2091 WD33C93A support' CONFIG_A2091_SCSI +bool 'GVP Series II WD33C93A support' CONFIG_GVP11_SCSI +fi +if [ "$CONFIG_ATARI" = "y" ]; then +dep_tristate 'Atari native SCSI support' CONFIG_ATARI_SCSI $CONFIG_SCSI +fi +#dep_tristate 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG $CONFIG_SCSI +endmenu + +fi +endmenu + +if [ "$CONFIG_NET" = "y" ]; then + +mainmenu_option next_comment +comment 'Network device support' + +bool 'Network device support' CONFIG_NETDEVICES +if [ "$CONFIG_NETDEVICES" = "y" ]; then +# +# Network device configuration +# +tristate 'Dummy net driver support' CONFIG_DUMMY +tristate 'SLIP (serial line) support' CONFIG_SLIP +if [ "$CONFIG_SLIP" != "n" ]; then + bool ' CSLIP compressed headers' CONFIG_SLIP_COMPRESSED +fi +tristate 'PPP (point-to-point) support' CONFIG_PPP +if [ ! "$CONFIG_PPP" = "n" ]; then + comment 'CCP compressors for PPP are only built as modules.' +fi +tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER +if [ "$CONFIG_AMIGA" = "y" ]; then + bool 'Ariadne support' CONFIG_ARIADNE + bool 'A2065 support' CONFIG_A2065 + bool 'Hydra support' CONFIG_HYDRA +fi +if [ "$CONFIG_ATARI" = "y" ]; then + bool 'Atari Lance support' CONFIG_ATARILANCE +fi +fi +endmenu + +fi + +source fs/Config.in + +mainmenu_option next_comment +comment 'Character devices' + +bool 'Parallel printer support' CONFIG_PRINTER +if [ "$CONFIG_AMIGA" = "y" ]; then + tristate 'Amiga mouse support' CONFIG_AMIGAMOUSE +fi +if [ "$CONFIG_ATARI" = "y" ]; then + tristate 'Atari mouse support' CONFIG_ATARIMOUSE +fi +bool 'Watchdog Timer Support' CONFIG_WATCHDOG +if [ "$CONFIG_WATCHDOG" != "n" ]; then + bool ' Disable watchdog shutdown on close' CONFIG_WATCHDOG_NOWAYOUT + bool ' Software Watchdog' CONFIG_SOFT_WATCHDOG +fi +bool 'Support for user misc device modules' CONFIG_UMISC +endmenu + +mainmenu_option next_comment +comment 'Sound support' + +bool 'Sound support' CONFIG_SOUND y +if [ "$CONFIG_SOUND" != "n" ]; then + bool 'Amiga or Atari DMA sound support' CONFIG_DMASOUND y +fi +endmenu + +mainmenu_option next_comment +comment 'Kernel hacking' + +#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC +bool 'Kernel profiling support' CONFIG_PROFILE +if [ "$CONFIG_PROFILE" = "y" ]; then + int ' Profile shift count' CONFIG_PROFILE_SHIFT 2 +fi +endmenu diff -u --recursive --new-file v1.3.93/linux/arch/m68k/console/Makefile linux/arch/m68k/console/Makefile --- v1.3.93/linux/arch/m68k/console/Makefile Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/console/Makefile Sat Mar 23 16:36:12 1996 @@ -0,0 +1,15 @@ +# +# Makefile for Linux arch/m68k/console source directory +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# + +EXTRA_CFLAGS := -Wa,-m68030 + +L_TARGET = console.a +L_OBJS = fbcon.o fonts.o font_8x16.o font_8x8.o +M_OBJS = + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.93/linux/arch/m68k/console/fbcon.c linux/arch/m68k/console/fbcon.c --- v1.3.93/linux/arch/m68k/console/fbcon.c Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/console/fbcon.c Sun Mar 17 18:10:37 1996 @@ -0,0 +1,3618 @@ +/* + * linux/arch/m68k/console/fbcon.c -- Low level frame buffer based console + * driver + * + * Copyright (C) 1995 Geert Uytterhoeven + * + * + * This file is based on the original Amiga console driver (amicon.c): + * + * Copyright (C) 1993 Hamish Macdonald + * Greg Harp + * Copyright (C) 1994 David Carter [carter@compsci.bristol.ac.uk] + * + * with work by William Rucklidge (wjr@cs.cornell.edu) + * Geert Uytterhoeven + * Jes Sorensen (jds@kom.auc.dk) + * Martin Apel + * + * and on the original Atari console driver (atacon.c): + * + * Copyright (C) 1993 Bjoern Brauel + * Roman Hodek + * + * with work by Guenther Kelleter + * Martin Schaller + * Andreas Schwab + * + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file README.legal in the main directory of this archive + * for more details. + */ + +/* + * To do: + * - Implement 16 plane mode. + * - Add support for 16/24/32 bit packed pixels + * - Hardware cursor + */ + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#ifdef CONFIG_AMIGA +#include +#include +#endif /* CONFIG_AMIGA */ +#ifdef CONFIG_ATARI +#include +#endif +#ifdef CONFIG_FB_CYBER +#include "../amiga/s3blit.h" +#endif /* CONFIG_FB_CYBER */ +#include +#include +#include + +#include + +#include "../../../drivers/char/vt_kern.h" /* vt_cons and vc_resize_con() */ + + +/* Import console_blanked from console.c */ + +extern int console_blanked; + + + /* + * The following symbols select what modes are supported. They should + * be settable by the user ("make config") later. + */ + +/* Clear all definitions */ + +#undef CONFIG_FBCON_MONO +#undef CONFIG_FBCON_ILBM +#undef CONFIG_FBCON_PLANES +#undef CONFIG_FBCON_2PLANE +#undef CONFIG_FBCON_4PLANE +#undef CONFIG_FBCON_8PLANE +#undef CONFIG_FBCON_8PACKED +#undef CONFIG_FBCON_16PACKED +#undef CONFIG_FBCON_24PACKED +#undef CONFIG_FBCON_32PACKED +#undef CONFIG_FBCON_CYBER + + +/* Monochrome is default */ + +#define CONFIG_FBCON_MONO + +/* Amiga support */ + +#ifdef CONFIG_AMIGA +#ifndef CONFIG_FBCON_ILBM +#define CONFIG_FBCON_ILBM +#endif +#ifndef CONFIG_FBCON_PLANES +#define CONFIG_FBCON_PLANES +#endif + +/* Cybervision Graphics Board */ + +#ifdef CONFIG_FB_CYBER +#ifndef CONFIG_FBCON_CYBER +#define CONFIG_FBCON_CYBER +#endif +#endif /* CONFIG_FB_CYBER */ + +#endif /* CONFIG_AMIGA */ + +/* Atari support */ + +#ifdef CONFIG_ATARI +#ifndef CONFIG_FBCON_2PLANE +#define CONFIG_FBCON_2PLANE +#endif +#ifndef CONFIG_FBCON_4PLANE +#define CONFIG_FBCON_4PLANE +#endif +#ifndef CONFIG_FBCON_8PLANE +#define CONFIG_FBCON_8PLANE +#endif +#ifndef CONFIG_FBCON_8PACKED +#define CONFIG_FBCON_8PACKED +#endif +#ifndef CONFIG_FBCON_16PACKED +#define CONFIG_FBCON_16PACKED +#endif +#endif /* CONFIG_ATARI */ + + +/* Extra definitions to make the code more readable */ + +#if defined(CONFIG_FBCON_2PLANE) || defined(CONFIG_FBCON_4PLANE) || \ + defined(CONFIG_FBCON_8PLANE) +#define CONFIG_FBCON_IPLAN2 +#else +#undef CONFIG_FBCON_IPLAN2 +#endif + +#if defined(CONFIG_FBCON_CYBER) || defined(CONFIG_FBCON_8PACKED) || \ + defined(CONFIG_FBCON_16PACKED) || defined(CONFIG_FBCON_24PACKED) || \ + defined(CONFIG_FBCON_32PACKED) +#define CONFIG_FBCON_PACKED +#else +#undef CONFIG_FBCON_PACKED +#endif + + +struct fb_info *fb_info; +struct display *disp; + + +/* ++Geert: Sorry, no hardware cursor support at the moment; + use Atari alike software cursor */ + +static int cursor_drawn = 0; + +#define CURSOR_DRAW_DELAY (2) + +/* # VBL ints between cursor state changes */ +#define AMIGA_CURSOR_BLINK_RATE (20) +#define ATARI_CURSOR_BLINK_RATE (42) + +static int vbl_cursor_cnt = 0; +static int cursor_on = 0; +static int cursor_blink_rate; + +static __inline__ int CURSOR_UNDRAWN(void) +{ + int cursor_was_drawn; + vbl_cursor_cnt = 0; + cursor_was_drawn = cursor_drawn; + cursor_drawn = 0; + return(cursor_was_drawn); +} + + /* + * Attribute Decoding + */ + +/* Color */ +#define attr_fgcol(p,conp) \ + (((conp)->vc_attr >> ((p)->inverse ? 4 : 0)) & 0x0f) +#define attr_bgcol(p,conp) \ + (((conp)->vc_attr >> ((p)->inverse ? 0 : 4)) & 0x0f) +#define attr_bgcol_ec(p,conp) \ + (((conp)->vc_video_erase_char >> ((p)->inverse ? 8 : 12)) & 0x0f) + +/* Monochrome */ +#define attr_bold(p,conp) \ + (((conp)->vc_attr & 3) == 2) +#define attr_reverse(p,conp) \ + (((conp)->vc_attr & 8) ^ ((p)->inverse ? 8 : 0)) +#define attr_underline(p,conp) \ + (((conp)->vc_attr) & 4) + + + /* + * Scroll Method + */ + +#define SCROLL_YWRAP (0) +#define SCROLL_YPAN (1) +#define SCROLL_YMOVE (2) + +#define divides(a, b) ((!(a) || (b)%(a)) ? 0 : 1) + + + /* + * Interface used by the world + */ + +static u_long fbcon_startup(u_long kmem_start, char **display_desc); +static void fbcon_init(struct vc_data *conp); +static int fbcon_deinit(struct vc_data *conp); +static int fbcon_changevar(int con); +static int fbcon_clear(struct vc_data *conp, int sy, int sx, int height, + int width); +static int fbcon_putc(struct vc_data *conp, int c, int y, int x); +static int fbcon_putcs(struct vc_data *conp, const char *s, int count, int y, + int x); +static int fbcon_cursor(struct vc_data *conp, int mode); +static int fbcon_scroll(struct vc_data *conp, int t, int b, int dir, int count); +static int fbcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx, + int height, int width); +static int fbcon_switch(struct vc_data *conp); +static int fbcon_blank(int blank); + + + /* + * Internal routines + */ + +static void fbcon_setup(int con, int setcol, int cls); +static __inline__ void *mymemclear_small(void *s, size_t count); +static __inline__ void *mymemclear(void *s, size_t count); +static __inline__ void *mymemset(void *s, size_t count); +static __inline__ void *mymemmove(void *d, void *s, size_t count); +static __inline__ void fast_memmove(char *dst, char *src, size_t size); +static __inline__ void memclear_4p_col(void *d, size_t h, u_long val, int bpr); +static __inline__ void memset_even_4p(void *d, size_t count, u_long val1, + u_long val2); +static __inline__ void memmove_4p_col(void *d, void *s, int h, int bpr); +static __inline__ u_long expand4l(u_char c); +static __inline__ void expand4dl(u_char c, u_long *ret1, u_long *ret2); +static __inline__ u_long dup4l(u_char c); +static __inline__ void memclear_8p_col(void *d, size_t h, u_long val1, + u_long val2, int bpr); +static __inline__ void memset_even_8p(void *d, size_t count, u_long val1, + u_long val2, u_long val3, u_long val4); +static __inline__ void memmove_8p_col(void *d, void *s, int h, int bpr); +static __inline__ void expand8dl(u_char c, u_long *ret1, u_long *ret2); +static __inline__ void memclear_2p_col(void *d, size_t h, u_short val, int bpr); +static __inline__ void memset_even_2p(void *d, size_t count, u_long val); +static __inline__ void memmove_2p_col(void *d, void *s, int h, int bpr); +static __inline__ u_short expand2w(u_char c); +static __inline__ u_long expand2l(u_char c); +static __inline__ u_short dup2w(u_char c); +static __inline__ int real_y(struct display *p, int y); +static void fbcon_vbl_handler(int irq, struct pt_regs *fp, void *dummy); +static void fbcon_bmove_rec(struct display *p, int sy, int sx, int dy, int dx, + int height, int width, u_int y_break); + + + /* + * Monochrome + */ + +#ifdef CONFIG_FBCON_MONO +static void bmove_mono(struct display *p, int sy, int sx, int dy, int dx, + int height, int width); +static void clear_mono(struct vc_data *conp, struct display *p, int sy, int sx, + int height, int width); +static void putc_mono(struct vc_data *conp, struct display *p, int c, int y, + int x); +static void putcs_mono(struct vc_data *conp, struct display *p, const char *s, + int count, int y, int x); +static void rev_char_mono(struct display *p, int x, int y); +#endif /* CONFIG_FBCON_MONO */ + + + /* + * Color Interleaved Planes + */ + +#ifdef CONFIG_FBCON_ILBM +static void bmove_ilbm(struct display *p, int sy, int sx, int dy, int dx, + int height, int width); +static void clear_ilbm(struct vc_data *conp, struct display *p, int sy, int sx, + int height, int width); +static void putc_ilbm(struct vc_data *conp, struct display *p, int c, int y, + int x); +static void putcs_ilbm(struct vc_data *conp, struct display *p, const char *s, + int count, int y, int x); +static void rev_char_ilbm(struct display *p, int x, int y); +#endif /* CONFIG_FBCON_ILBM */ + + + /* + * Color Planes + */ + +#ifdef CONFIG_FBCON_PLANES +static void bmove_plan(struct display *p, int sy, int sx, int dy, int dx, + int height, int width); +static void clear_plan(struct vc_data *conp, struct display *p, int sy, int sx, + int height, int width); +static void putc_plan(struct vc_data *conp, struct display *p, int c, int y, + int x); +static void putcs_plan(struct vc_data *conp, struct display *p, const char *s, + int count, int y, int x); +static void rev_char_plan(struct display *p, int x, int y); +#endif /* CONFIG_FBCON_PLANES */ + + + /* + * 2 Planes (2-bytes interleave) + */ + +#ifdef CONFIG_FBCON_2PLANE +static void bmove_2_plane(struct display *p, int sy, int sx, int dy, int dx, + int height, int width); +static void clear_2_plane(struct vc_data *conp, struct display *p, int sy, + int sx, int height, int width); +static void putc_2_plane(struct vc_data *conp, struct display *p, int c, int y, + int x); +static void putcs_2_plane(struct vc_data *conp, struct display *p, + const char *s, int count, int y, int x); +static void rev_char_2_plane(struct display *display, int x, int y); +#endif /* CONFIG_FBCON_2PLANE */ + + + /* + * 4 Planes (2-bytes interleave) + */ + +#ifdef CONFIG_FBCON_4PLANE +static void bmove_4_plane(struct display *p, int sy, int sx, int dy, int dx, + int height, int width); +static void clear_4_plane(struct vc_data *conp, struct display *p, int sy, + int sx, int height, int width); +static void putc_4_plane(struct vc_data *conp, struct display *p, int c, int y, + int x); +static void putcs_4_plane(struct vc_data *conp, struct display *p, + const char *s, int count, int y, int x); +static void rev_char_4_plane(struct display *p, int x, int y); +#endif /* CONFIG_FBCON_4PLANE */ + + + /* + * 8 Planes (2-bytes interleave) + */ + +#ifdef CONFIG_FBCON_8PLANE +static void bmove_8_plane(struct display *p, int sy, int sx, int dy, int dx, + int height, int width); +static void clear_8_plane(struct vc_data *conp, struct display *p, int sy, + int sx, int height, int width); +static void putc_8_plane(struct vc_data *conp, struct display *p, int c, int y, + int x); +static void putcs_8_plane(struct vc_data *conp, struct display *p, + const char *s, int count, int y, int x); +static void rev_char_8_plane(struct display *display, int x, int y); +#endif /* CONFIG_FBCON_8PLANE */ + + + /* + * 8 bpp Packed Pixels + */ + +#ifdef CONFIG_FBCON_8PACKED +static void bmove_8_packed(struct display *p, int sy, int sx, int dy, int dx, + int height, int width); +static void clear_8_packed(struct vc_data *conp, struct display *p, int sy, + int sx, int height, int width); +static void putc_8_packed(struct vc_data *conp, struct display *p, int c, int y, + int x); +static void putcs_8_packed(struct vc_data *conp, struct display *p, + const char *s, int count, int y, int x); +static void rev_char_8_packed(struct display *p, int x, int y); +#endif /* CONFIG_FBCON_8PACKED */ + + + /* + * 16 bpp Packed Pixels + */ + +#ifdef CONFIG_FBCON_16PACKED +static void bmove_16_packed(struct display *p, int sy, int sx, int dy, int dx, + int height, int width); +static void clear_16_packed(struct vc_data *conp, struct display *p, int sy, + int sx, int height, int width); +static void putc_16_packed(struct vc_data *conp, struct display *p, int c, + int y, int x); +static void putcs_16_packed(struct vc_data *conp, struct display *p, + const char *s, int count, int y, int x); +static void rev_char_16_packed(struct display *p, int x, int y); +#endif */ CONFIG_FBCON_8PACKED */ + + + /* + * Cybervision (accelerated) + */ + +#ifdef CONFIG_FBCON_CYBER +static void bmove_cyber(struct display *p, int sy, int sx, int dy, int dx, + int height, int width); +static void clear_cyber(struct vc_data *conp, struct display *p, int sy, int sx, + int height, int width); +static void putc_cyber(struct vc_data *conp, struct display *p, int c, int y, + int x); +static void putcs_cyber(struct vc_data *conp, struct display *p, const char *s, + int count, int y, int x); +static void rev_char_cyber(struct display *p, int x, int y); + +extern void Cyber_WaitQueue(u_short fifo); +extern void Cyber_WaitBlit(void); +extern void Cyber_BitBLT(u_short curx, u_short cury, u_short destx, + u_short desty, u_short width, u_short height, + u_short mode); +extern void Cyber_RectFill(u_short x, u_short y, u_short width, u_short height, + u_short mode, u_short color); +extern void Cyber_MoveCursor(u_short x, u_short y); +#endif /* CONFIG_FBCON_CYBER */ + + + /* + * `switch' for the Low Level Operations + */ + +struct display_switch { + void (*bmove)(struct display *p, int sy, int sx, int dy, int dx, int height, + int width); + void (*clear)(struct vc_data *conp, struct display *p, int sy, int sx, + int height, int width); + void (*putc)(struct vc_data *conp, struct display *p, int c, int y, int x); + void (*putcs)(struct vc_data *conp, struct display *p, const char *s, + int count, int y, int x); + void (*rev_char)(struct display *p, int x, int y); +}; + + +#ifdef CONFIG_FBCON_MONO +struct display_switch dispsw_mono = { + bmove_mono, clear_mono, putc_mono, putcs_mono, rev_char_mono +}; +#endif /* CONFIG_FBCON_MONO */ + +#ifdef CONFIG_FBCON_ILBM +struct display_switch dispsw_ilbm = { + bmove_ilbm, clear_ilbm, putc_ilbm, putcs_ilbm, rev_char_ilbm +}; +#endif /* CONFIG_FBCON_ILBM */ + +#ifdef CONFIG_FBCON_PLANES +struct display_switch dispsw_plan = { + bmove_plan, clear_plan, putc_plan, putcs_plan, rev_char_plan +}; +#endif /* CONFIG_FBCON_PLANES */ + +#ifdef CONFIG_FBCON_2PLANE +struct display_switch dispsw_2_plane = { + bmove_2_plane, clear_2_plane, putc_2_plane, putcs_2_plane, rev_char_2_plane +}; +#endif /* CONFIG_FBCON_2PLANE */ + +#ifdef CONFIG_FBCON_4PLANE +struct display_switch dispsw_4_plane = { + bmove_4_plane, clear_4_plane, putc_4_plane, putcs_4_plane, rev_char_4_plane +}; +#endif /* CONFIG_FBCON_4PLANE */ + +#ifdef CONFIG_FBCON_8PLANE +struct display_switch dispsw_8_plane = { + bmove_8_plane, clear_8_plane, putc_8_plane, putcs_8_plane, rev_char_8_plane +}; +#endif /* CONFIG_FBCON_8PLANE */ + +#ifdef CONFIG_FBCON_8PACKED +struct display_switch dispsw_8_packed = { + bmove_8_packed, clear_8_packed, putc_8_packed, putcs_8_packed, rev_char_8_packed +}; +#endif /* CONFIG_FBCON_8PACKED */ + +#ifdef CONFIG_FBCON_16PACKED +struct display_switch dispsw_16_packed = { + bmove_16_packed, clear_16_packed, putc_16_packed, putcs_16_packed, + rev_char_16_packed +}; +#endif /* CONFIG_FBCON_16PACKED */ + +#ifdef CONFIG_FBCON_CYBER +struct display_switch dispsw_cyber = { + bmove_cyber, clear_cyber, putc_cyber, putcs_cyber, rev_char_cyber +}; +#endif /* CONFIG_FBCON_CYBER */ + + +static u_long fbcon_startup(u_long kmem_start, char **display_desc) +{ + int irqres = 0; + + fb_info = mach_fb_init(&kmem_start); + disp = fb_info->disp; + *display_desc = fb_info->modename; + fb_info->changevar = &fbcon_changevar; + +#ifdef CONFIG_AMIGA + if (MACH_IS_AMIGA) { + cursor_blink_rate = AMIGA_CURSOR_BLINK_RATE; + irqres = add_isr(IRQ_AMIGA_VERTB, fbcon_vbl_handler, 0, NULL, + "console/cursor"); + } +#endif /* CONFIG_AMIGA */ +#ifdef CONFIG_ATARI + if (MACH_IS_ATARI) { + cursor_blink_rate = ATARI_CURSOR_BLINK_RATE; + irqres = add_isr(IRQ_AUTO_4, fbcon_vbl_handler, IRQ_TYPE_PRIO, NULL, + "console/cursor"); + } +#endif /* CONFIG_ATARI */ + + if (!irqres) + panic("fbcon_startup: Couldn't add vblank interrupt"); + + return(kmem_start); +} + + +static void fbcon_init(struct vc_data *conp) +{ + int unit = conp->vc_num; + + if (unit) + disp[unit] = disp[0]; + disp[unit].conp = conp; + fbcon_setup(unit, 1, 0); +} + + +static int fbcon_deinit(struct vc_data *conp) +{ + disp[conp->vc_num].conp = 0; + return(0); +} + + +static int fbcon_changevar(int con) +{ + fbcon_setup(con, 1, 1); + return(0); +} + + +static void fbcon_setup(int con, int setcol, int cls) +{ + struct display *p = &disp[con]; + struct vc_data *conp = p->conp; + + p->var.xoffset = p->var.yoffset = p->yscroll = 0; /* reset wrap/pan */ + + if (!fb_info->fontname[0] || + !findsoftfont(fb_info->fontname, &p->fontwidth, &p->fontheight, + &p->fontdata) || p->fontwidth != 8) + getdefaultfont(p->var.xres, p->var.yres, NULL, &p->fontwidth, + &p->fontheight, &p->fontdata); + if (p->fontwidth != 8) + panic("fbcon_setup: No support for fontwidth != 8"); + + if (divides(p->ywrapstep, p->fontheight)) + p->scrollmode = SCROLL_YWRAP; + else if (divides(p->ypanstep, p->fontheight) && + p->var.yres_virtual >= p->var.yres+p->fontheight) + p->scrollmode = SCROLL_YPAN; + else + p->scrollmode = SCROLL_YMOVE; + + conp->vc_cols = p->var.xres/p->fontwidth; + conp->vc_rows = p->var.yres/p->fontheight; + conp->vc_can_do_color = p->var.bits_per_pixel != 1; + +#ifdef CONFIG_FBCON_MONO + if (p->var.bits_per_pixel == 1) { + p->next_line = p->var.xres_virtual>>3; + p->next_plane = 0; + p->dispsw = &dispsw_mono; + } else +#endif /* CONFIG_FBCON_MONO */ +#ifdef CONFIG_FBCON_IPLAN2 + if (p->type == FB_TYPE_INTERLEAVED_PLANES && p->type_aux == 2) { + p->next_line = p->var.xres_virtual*p->var.bits_per_pixel>>3; + p->next_plane = 0; +#ifdef CONFIG_FBCON_2PLANE + if (p->var.bits_per_pixel == 2) + p->dispsw = &dispsw_2_plane; + else +#endif /* CONFIG_FBCON_2PLANE */ +#ifdef CONFIG_FBCON_4PLANE + if (p->var.bits_per_pixel == 4) + p->dispsw = &dispsw_4_plane; + else +#endif /* CONFIG_FBCON_4PLANE */ +#ifdef CONFIG_FBCON_8PLANE + if (p->var.bits_per_pixel == 8) + p->dispsw = &dispsw_8_plane; + else +#endif /* CONFIG_FBCON_8PLANE */ + goto fail; + } else +#endif /* CONFIG_FBCON_IPLAN2 */ +#ifdef CONFIG_FBCON_ILBM + if (p->type == FB_TYPE_INTERLEAVED_PLANES && p->type_aux != 2) { + p->next_line = p->type_aux; + p->next_plane = p->type_aux/p->var.bits_per_pixel; + p->dispsw = &dispsw_ilbm; + } else +#endif /* CONFIG_FBCON_ILBM */ +#ifdef CONFIG_FBCON_PLANES + if (p->type == FB_TYPE_PLANES) { + p->next_line = p->var.xres_virtual>>3; + p->next_plane = p->var.yres_virtual*p->next_line; + p->dispsw = &dispsw_plan; + } else +#endif /* CONFIG_FBCON_PLANES */ +#ifdef CONFIG_FBCON_PACKED + if (p->type == FB_TYPE_PACKED_PIXELS) { + p->next_line = p->var.xres_virtual*p->var.bits_per_pixel>>3; + p->next_plane = 0; +#ifdef CONFIG_FBCON_CYBER + if (p->var.accel == FB_ACCEL_CYBERVISION) + p->dispsw = &dispsw_cyber; + else +#endif /* CONFIG_FBCON_CYBER */ +#ifdef CONFIG_FBCON_8PACKED + if (p->var.bits_per_pixel == 8) + p->dispsw = &dispsw_8_packed; + else +#endif /* CONFIG_FBCON_8PACKED */ +#ifdef CONFIG_FBCON_16PACKED + if (p->var.bits_per_pixel == 16) + p->dispsw = &dispsw_16_packed; + else +#endif /* CONFIG_FBCON_16PACKED */ +#ifdef CONFIG_FBCON_24PACKED + if (p->var.bits_per_pixel == 24) + p->dispsw = &dispsw_24_packed; + else +#endif /* CONFIG_FBCON_24PACKED */ +#ifdef CONFIG_FBCON_32PACKED + if (p->var.bits_per_pixel == 32) + p->dispsw = &dispsw_32_packed; + else +#endif /* CONFIG_FBCON_32PACKED */ + goto fail; + } else +#endif /* CONFIG_FBCON_PACKED */ + { +fail: +#ifdef CONFIG_FBCON_MONO + printk("fbcon_setup: type %d (aux %d) not supported, trying mono\n", + p->type, p->type_aux); + p->next_line = (p->var.xres_virtual)>>3; + p->next_plane = 0; + p->var.bits_per_pixel = 1; + p->dispsw = &dispsw_mono; +#else /* CONFIG_FBCON_MONO */ + panic("fbcon_setup: no default driver"); +#endif /* CONFIG_FBCON_MONO */ + } + + if (setcol) { + p->fgcol = p->var.bits_per_pixel > 2 ? 7 : (1<var.bits_per_pixel)-1; + p->bgcol = 0; + } + + if (cls) + vc_resize_con(conp->vc_rows, conp->vc_cols, con); +} + + +/* ================================================================= */ +/* Utility Assembler Functions */ +/* ================================================================= */ + + +/* ====================================================================== */ + +/* Those of a delicate disposition might like to skip the next couple of + * pages. + * + * These functions are drop in replacements for memmove and + * memset(_, 0, _). However their five instances add at least a kilobyte + * to the object file. You have been warned. + * + * Not a great fan of assembler for the sake of it, but I think + * that these routines are at least 10 times faster than their C + * equivalents for large blits, and thats important to the lowest level of + * a graphics driver. Question is whether some scheme with the blitter + * would be faster. I suspect not for simple text system - not much + * asynchronisity. + * + * Code is very simple, just gruesome expansion. Basic strategy is to + * increase data moved/cleared at each step to 16 bytes to reduce + * instruction per data move overhead. movem might be faster still + * For more than 15 bytes, we try to align the write direction on a + * longword boundary to get maximum speed. This is even more gruesome. + * Unaligned read/write used requires 68020+ - think this is a problem? + * + * Sorry! + */ + + +/* ++roman: I've optimized Robert's original versions in some minor + * aspects, e.g. moveq instead of movel, let gcc choose the registers, + * use movem in some places... + * For other modes than 1 plane, lots of more such assembler functions + * were needed (e.g. the ones using movep or expanding color values). + */ + +/* ++andreas: more optimizations: + subl #65536,d0 replaced by clrw d0; subql #1,d0 for dbcc + addal is faster than addaw + movep is rather expensive compared to ordinary move's + some functions rewritten in C for clearity, no speed loss */ + +static __inline__ void *mymemclear_small(void *s, size_t count) +{ + if (!count) + return(0); + + __asm__ __volatile__( + "lsrl #1,%1 ; jcc 1f ; moveb %2,%0@-\n\t" + "1: lsrl #1,%1 ; jcc 1f ; movew %2,%0@-\n\t" + "1: lsrl #1,%1 ; jcc 1f ; movel %2,%0@-\n\t" + "1: lsrl #1,%1 ; jcc 1f ; movel %2,%0@- ; movel %2,%0@-\n\t" + "1: subql #1,%1 ; jcs 3f\n\t" + "2: moveml %2/%3/%4/%5,%0@-\n\t" + "dbra %1,2b\n\t" + "3:" + : "=a" (s), "=d" (count) + : "d" (0), "d" (0), "d" (0), "d" (0), + "0" ((char *)s+count), "1" (count) + ); + + return(0); +} + + +static __inline__ void *mymemclear(void *s, size_t count) +{ + if (!count) + return(0); + + if (count < 16) { + __asm__ __volatile__( + "lsrl #1,%1 ; jcc 1f ; clrb %0@+\n\t" + "1: lsrl #1,%1 ; jcc 1f ; clrw %0@+\n\t" + "1: lsrl #1,%1 ; jcc 1f ; clrl %0@+\n\t" + "1: lsrl #1,%1 ; jcc 1f ; clrl %0@+ ; clrl %0@+\n\t" + "1:" + : "=a" (s), "=d" (count) + : "0" (s), "1" (count) + ); + } else { + long tmp; + __asm__ __volatile__( + "movel %1,%2\n\t" + "lsrl #1,%2 ; jcc 1f ; clrb %0@+ ; subqw #1,%1\n\t" + "lsrl #1,%2 ; jcs 2f\n\t" /* %0 increased=>bit 2 switched*/ + "clrw %0@+ ; subqw #2,%1 ; jra 2f\n\t" + "1: lsrl #1,%2 ; jcc 2f\n\t" + "clrw %0@+ ; subqw #2,%1\n\t" + "2: movew %1,%2; lsrl #2,%1 ; jeq 6f\n\t" + "lsrl #1,%1 ; jcc 3f ; clrl %0@+\n\t" + "3: lsrl #1,%1 ; jcc 4f ; clrl %0@+ ; clrl %0@+\n\t" + "4: subql #1,%1 ; jcs 6f\n\t" + "5: clrl %0@+; clrl %0@+ ; clrl %0@+ ; clrl %0@+\n\t" + "dbra %1,5b ; clrw %1; subql #1,%1; jcc 5b\n\t" + "6: movew %2,%1; btst #1,%1 ; jeq 7f ; clrw %0@+\n\t" + "7: ; btst #0,%1 ; jeq 8f ; clrb %0@+\n\t" + "8:" + : "=a" (s), "=d" (count), "=d" (tmp) + : "0" (s), "1" (count) + ); + } + + return(0); +} + + +static __inline__ void *mymemset(void *s, size_t count) +{ + if (!count) + return(0); + + __asm__ __volatile__( + "lsrl #1,%1 ; jcc 1f ; moveb %2,%0@-\n\t" + "1: lsrl #1,%1 ; jcc 1f ; movew %2,%0@-\n\t" + "1: lsrl #1,%1 ; jcc 1f ; movel %2,%0@-\n\t" + "1: lsrl #1,%1 ; jcc 1f ; movel %2,%0@- ; movel %2,%0@-\n\t" + "1: subql #1,%1 ; jcs 3f\n\t" + "2: moveml %2/%3/%4/%5,%0@-\n\t" + "dbra %1,2b\n\t" + "3:" + : "=a" (s), "=d" (count) + : "d" (-1), "d" (-1), "d" (-1), "d" (-1), + "0" ((char *) s + count), "1" (count) + ); + + return(0); +} + + +static __inline__ void *mymemmove(void *d, void *s, size_t count) +{ + if (d < s) { + if (count < 16) { + __asm__ __volatile__( + "lsrl #1,%2 ; jcc 1f ; moveb %1@+,%0@+\n\t" + "1: lsrl #1,%2 ; jcc 1f ; movew %1@+,%0@+\n\t" + "1: lsrl #1,%2 ; jcc 1f ; movel %1@+,%0@+\n\t" + "1: lsrl #1,%2 ; jcc 1f ; movel %1@+,%0@+ ; movel %1@+,%0@+\n\t" + "1:" + : "=a" (d), "=a" (s), "=d" (count) + : "0" (d), "1" (s), "2" (count) + ); + } else { + long tmp; + __asm__ __volatile__( + "movel %0,%3\n\t" + "lsrl #1,%3 ; jcc 1f ; moveb %1@+,%0@+ ; subqw #1,%2\n\t" + "lsrl #1,%3 ; jcs 2f\n\t" /* %0 increased=>bit 2 switched*/ + "movew %1@+,%0@+ ; subqw #2,%2 ; jra 2f\n\t" + "1: lsrl #1,%3 ; jcc 2f\n\t" + "movew %1@+,%0@+ ; subqw #2,%2\n\t" + "2: movew %2,%-; lsrl #2,%2 ; jeq 6f\n\t" + "lsrl #1,%2 ; jcc 3f ; movel %1@+,%0@+\n\t" + "3: lsrl #1,%2 ; jcc 4f ; movel %1@+,%0@+ ; movel %1@+,%0@+\n\t" + "4: subql #1,%2 ; jcs 6f\n\t" + "5: movel %1@+,%0@+;movel %1@+,%0@+\n\t" + "movel %1@+,%0@+;movel %1@+,%0@+\n\t" + "dbra %2,5b ; clrw %2; subql #1,%2; jcc 5b\n\t" + "6: movew %+,%2; btst #1,%2 ; jeq 7f ; movew %1@+,%0@+\n\t" + "7: ; btst #0,%2 ; jeq 8f ; moveb %1@+,%0@+\n\t" + "8:" + : "=a" (d), "=a" (s), "=d" (count), "=d" (tmp) + : "0" (d), "1" (s), "2" (count) + ); + } + } else { + if (count < 16) { + __asm__ __volatile__( + "lsrl #1,%2 ; jcc 1f ; moveb %1@-,%0@-\n\t" + "1: lsrl #1,%2 ; jcc 1f ; movew %1@-,%0@-\n\t" + "1: lsrl #1,%2 ; jcc 1f ; movel %1@-,%0@-\n\t" + "1: lsrl #1,%2 ; jcc 1f ; movel %1@-,%0@- ; movel %1@-,%0@-\n\t" + "1:" + : "=a" (d), "=a" (s), "=d" (count) + : "0" ((char *) d + count), "1" ((char *) s + count), "2" (count) + ); + } else { + long tmp; + __asm__ __volatile__( + "movel %0,%3\n\t" + "lsrl #1,%3 ; jcc 1f ; moveb %1@-,%0@- ; subqw #1,%2\n\t" + "lsrl #1,%3 ; jcs 2f\n\t" /* %0 increased=>bit 2 switched*/ + "movew %1@-,%0@- ; subqw #2,%2 ; jra 2f\n\t" + "1: lsrl #1,%3 ; jcc 2f\n\t" + "movew %1@-,%0@- ; subqw #2,%2\n\t" + "2: movew %2,%-; lsrl #2,%2 ; jeq 6f\n\t" + "lsrl #1,%2 ; jcc 3f ; movel %1@-,%0@-\n\t" + "3: lsrl #1,%2 ; jcc 4f ; movel %1@-,%0@- ; movel %1@-,%0@-\n\t" + "4: subql #1,%2 ; jcs 6f\n\t" + "5: movel %1@-,%0@-;movel %1@-,%0@-\n\t" + "movel %1@-,%0@-;movel %1@-,%0@-\n\t" + "dbra %2,5b ; clrw %2; subql #1,%2; jcc 5b\n\t" + "6: movew %+,%2; btst #1,%2 ; jeq 7f ; movew %1@-,%0@-\n\t" + "7: ; btst #0,%2 ; jeq 8f ; moveb %1@-,%0@-\n\t" + "8:" + : "=a" (d), "=a" (s), "=d" (count), "=d" (tmp) + : "0" ((char *) d + count), "1" ((char *) s + count), "2" (count) + ); + } + } + + return(0); +} + + +/* ++andreas: Simple and fast version of memmove, assumes size is + divisible by 16, suitable for moving the whole screen bitplane */ +static __inline__ void fast_memmove(char *dst, char *src, size_t size) +{ + if (!size) + return; + if (dst < src) + __asm__ __volatile__ + ("1:" + " moveml %0@+,%/d0/%/d1/%/a0/%/a1\n" + " moveml %/d0/%/d1/%/a0/%/a1,%1@\n" + " addql #8,%1; addql #8,%1\n" + " dbra %2,1b\n" + " clrw %2; subql #1,%2\n" + " jcc 1b" + : "=a" (src), "=a" (dst), "=d" (size) + : "0" (src), "1" (dst), "2" (size / 16 - 1) + : "d0", "d1", "a0", "a1", "memory"); + else + __asm__ __volatile__ + ("1:" + " subql #8,%0; subql #8,%0\n" + " moveml %0@,%/d0/%/d1/%/a0/%/a1\n" + " moveml %/d0/%/d1/%/a0/%/a1,%1@-\n" + " dbra %2,1b\n" + " clrw %2; subql #1,%2\n" + " jcc 1b" + : "=a" (src), "=a" (dst), "=d" (size) + : "0" (src + size), "1" (dst + size), "2" (size / 16 - 1) + : "d0", "d1", "a0", "a1", "memory"); +} + + +/* Sets the bytes in the visible column at d, height h, to the value + * val for a 4 plane screen. The the bis of the color in 'color' are + * moved (8 times) to the respective bytes. This means: + * + * for(h times; d += bpr) + * *d = (color & 1) ? 0xff : 0; + * *(d+2) = (color & 2) ? 0xff : 0; + * *(d+4) = (color & 4) ? 0xff : 0; + * *(d+6) = (color & 8) ? 0xff : 0; + */ + +static __inline__ void memclear_4p_col(void *d, size_t h, u_long val, int bpr) +{ + __asm__ __volatile__ + ("1: movepl %4,%0@(0)\n\t" + "addal %5,%0\n\t" + "dbra %1,1b" + : "=a" (d), "=d" (h) + : "0" (d), "1" (h - 1), "d" (val), "r" (bpr) + ); +} + +/* Sets a 4 plane region from 'd', length 'count' bytes, to the color + * in val1/val2. 'd' has to be an even address and count must be divisible + * by 8, because only whole words and all planes are accessed. I.e.: + * + * for(count/8 times) + * *d = *(d+1) = (color & 1) ? 0xff : 0; + * *(d+2) = *(d+3) = (color & 2) ? 0xff : 0; + * *(d+4) = *(d+5) = (color & 4) ? 0xff : 0; + * *(d+6) = *(d+7) = (color & 8) ? 0xff : 0; + */ + +static __inline__ void memset_even_4p(void *d, size_t count, u_long val1, + u_long val2) +{ + u_long *dd = d; + + count /= 8; + while (count--) + { + *dd++ = val1; + *dd++ = val2; + } +} + +/* Copies a 4 plane column from 's', height 'h', to 'd'. */ + +static __inline__ void memmove_4p_col (void *d, void *s, int h, int bpr) +{ + u_char *dd = d, *ss = s; + + while (h--) + { + dd[0] = ss[0]; + dd[2] = ss[2]; + dd[4] = ss[4]; + dd[6] = ss[6]; + dd += bpr; + ss += bpr; + } +} + + +/* This expands a 4 bit color into a long for movepl (4 plane) operations. */ + +static __inline__ u_long expand4l(u_char c) +{ + u_long rv; + + __asm__ __volatile__ + ("lsrb #1,%2\n\t" + "scs %0\n\t" + "lsll #8,%0\n\t" + "lsrb #1,%2\n\t" + "scs %0\n\t" + "lsll #8,%0\n\t" + "lsrb #1,%2\n\t" + "scs %0\n\t" + "lsll #8,%0\n\t" + "lsrb #1,%2\n\t" + "scs %0\n\t" + : "=&d" (rv), "=d" (c) + : "1" (c) + ); + return(rv); +} + +/* This expands a 4 bit color into two longs for two movel operations + * (4 planes). + */ + +static __inline__ void expand4dl(u_char c, u_long *ret1, u_long *ret2) +{ + u_long rv1, rv2; + + __asm__ __volatile__ + ("lsrb #1,%3\n\t" + "scs %0\n\t" + "extw %0\n\t" + "swap %0\n\t" + "lsrb #1,%3\n\t" + "scs %0\n\t" + "extw %0\n\t" + "lsrb #1,%3\n\t" + "scs %1\n\t" + "extw %1\n\t" + "swap %1\n\t" + "lsrb #1,%3\n\t" + "scs %1\n\t" + "extw %1" + : "=&d" (rv1), "=&d" (rv2), "=d" (c) + : "2" (c) + ); + *ret1 = rv1; + *ret2 = rv2; +} + + +/* This duplicates a byte 4 times into a long. */ + +static __inline__ u_long dup4l(u_char c) +{ + ushort tmp; + ulong rv; + + __asm__ __volatile__ + ("moveb %2,%0\n\t" + "lslw #8,%0\n\t" + "moveb %2,%0\n\t" + "movew %0,%1\n\t" + "swap %0\n\t" + "movew %1,%0" + : "=&d" (rv), "=d" (tmp) + : "d" (c) + ); + + return(rv); +} + + +/* Sets the bytes in the visible column at d, height h, to the value + * val1,val2 for a 8 plane screen. The the bis of the color in 'color' are + * moved (8 times) to the respective bytes. This means: + * + * for(h times; d += bpr) + * *d = (color & 1) ? 0xff : 0; + * *(d+2) = (color & 2) ? 0xff : 0; + * *(d+4) = (color & 4) ? 0xff : 0; + * *(d+6) = (color & 8) ? 0xff : 0; + * *(d+8) = (color & 16) ? 0xff : 0; + * *(d+10) = (color & 32) ? 0xff : 0; + * *(d+12) = (color & 64) ? 0xff : 0; + * *(d+14) = (color & 128) ? 0xff : 0; + */ + +static __inline__ void memclear_8p_col(void *d, size_t h, u_long val1, + u_long val2, int bpr) +{ + __asm__ __volatile__ + ("1: movepl %4,%0@(0)\n\t" + "movepl %5,%0@(8)\n\t" + "addal %6,%0\n\t" + "dbra %1,1b" + : "=a" (d), "=d" (h) + : "0" (d), "1" (h - 1), "d" (val1), "d" (val2), "r" (bpr) + ); +} + +/* Sets a 8 plane region from 'd', length 'count' bytes, to the color + * val1..val4. 'd' has to be an even address and count must be divisible + * by 16, because only whole words and all planes are accessed. I.e.: + * + * for(count/16 times) + * *d = *(d+1) = (color & 1) ? 0xff : 0; + * *(d+2) = *(d+3) = (color & 2) ? 0xff : 0; + * *(d+4) = *(d+5) = (color & 4) ? 0xff : 0; + * *(d+6) = *(d+7) = (color & 8) ? 0xff : 0; + * *(d+8) = *(d+9) = (color & 16) ? 0xff : 0; + * *(d+10) = *(d+11) = (color & 32) ? 0xff : 0; + * *(d+12) = *(d+13) = (color & 64) ? 0xff : 0; + * *(d+14) = *(d+15) = (color & 128) ? 0xff : 0; + */ + +static __inline__ void memset_even_8p(void *d, size_t count, u_long val1, + u_long val2, u_long val3, u_long val4) +{ + u_long *dd = d; + + count /= 16; + while (count--) + { + *dd++ = val1; + *dd++ = val2; + *dd++ = val3; + *dd++ = val4; + } +} + +/* Copies a 8 plane column from 's', height 'h', to 'd'. */ + +static __inline__ void memmove_8p_col (void *d, void *s, int h, int bpr) +{ + u_char *dd = d, *ss = s; + + while (h--) + { + dd[0] = ss[0]; + dd[2] = ss[2]; + dd[4] = ss[4]; + dd[6] = ss[6]; + dd[8] = ss[8]; + dd[10] = ss[10]; + dd[12] = ss[12]; + dd[14] = ss[14]; + dd += bpr; + ss += bpr; + } +} + + +/* This expands a 8 bit color into two longs for two movepl (8 plane) + * operations. + */ + +static __inline__ void expand8dl(u_char c, u_long *ret1, u_long *ret2) +{ + u_long rv1, rv2; + + __asm__ __volatile__ + ("lsrb #1,%3\n\t" + "scs %0\n\t" + "lsll #8,%0\n\t" + "lsrb #1,%3\n\t" + "scs %0\n\t" + "lsll #8,%0\n\t" + "lsrb #1,%3\n\t" + "scs %0\n\t" + "lsll #8,%0\n\t" + "lsrb #1,%3\n\t" + "scs %0\n\t" + "lsrb #1,%3\n\t" + "scs %1\n\t" + "lsll #8,%1\n\t" + "lsrb #1,%3\n\t" + "scs %1\n\t" + "lsll #8,%1\n\t" + "lsrb #1,%3\n\t" + "scs %1\n\t" + "lsll #8,%1\n\t" + "lsrb #1,%3\n\t" + "scs %1" + : "=&d" (rv1), "=&d" (rv2),"=d" (c) + : "2" (c) + ); + + *ret1 = rv1; + *ret2 = rv2; +} + +/* This expands a 8 bit color into four longs for four movel operations + * (8 planes). + */ + +/* ++andreas: use macro to avoid taking address of return values */ +#define expand8ql(c, rv1, rv2, rv3, rv4) \ +do { u_char tmp = c; \ + __asm__ __volatile__ \ + ("lsrb #1,%5\n\t" \ + "scs %0\n\t" \ + "extw %0\n\t" \ + "swap %0\n\t" \ + "lsrb #1,%5\n\t" \ + "scs %0\n\t" \ + "extw %0\n\t" \ + "lsrb #1,%5\n\t" \ + "scs %1\n\t" \ + "extw %1\n\t" \ + "swap %1\n\t" \ + "lsrb #1,%5\n\t" \ + "scs %1\n\t" \ + "extw %1\n\t" \ + "lsrb #1,%5\n\t" \ + "scs %2\n\t" \ + "extw %2\n\t" \ + "swap %2\n\t" \ + "lsrb #1,%5\n\t" \ + "scs %2\n\t" \ + "extw %2\n\t" \ + "lsrb #1,%5\n\t" \ + "scs %3\n\t" \ + "extw %3\n\t" \ + "swap %3\n\t" \ + "lsrb #1,%5\n\t" \ + "scs %3\n\t" \ + "extw %3" \ + : "=&d" (rv1), "=&d" (rv2), "=&d" (rv3), \ + "=&d" (rv4), "=d" (tmp) \ + : "4" (tmp) \ + ); \ +} while (0) + + +/* Sets the bytes in the visible column at d, height h, to the value + * val for a 2 plane screen. The the bis of the color in 'color' are + * moved (8 times) to the respective bytes. This means: + * + * for(h times; d += bpr) + * *d = (color & 1) ? 0xff : 0; + * *(d+2) = (color & 2) ? 0xff : 0; + */ + +static __inline__ void memclear_2p_col(void *d, size_t h, u_short val, int bpr) +{ + __asm__ __volatile__ + ("1: movepw %4,%0@(0)\n\t" + "addal %5,%0\n\t" + "dbra %1,1b" + : "=a" (d), "=d" (h) + : "0" (d), "1" (h - 1), "d" (val), "r" (bpr) + ); +} + +/* Sets a 2 plane region from 'd', length 'count' bytes, to the color + * in val1. 'd' has to be an even address and count must be divisible + * by 8, because only whole words and all planes are accessed. I.e.: + * + * for(count/4 times) + * *d = *(d+1) = (color & 1) ? 0xff : 0; + * *(d+2) = *(d+3) = (color & 2) ? 0xff : 0; + */ + +static __inline__ void memset_even_2p(void *d, size_t count, u_long val) +{ + u_long *dd = d; + + count /= 4; + while (count--) + *dd++ = val; +} + +/* Copies a 2 plane column from 's', height 'h', to 'd'. */ + +static __inline__ void memmove_2p_col (void *d, void *s, int h, int bpr) +{ + u_char *dd = d, *ss = s; + + while (h--) + { + dd[0] = ss[0]; + dd[2] = ss[2]; + dd += bpr; + ss += bpr; + } +} + + +/* This expands a 2 bit color into a short for movepw (2 plane) operations. */ + +static __inline__ u_short expand2w(u_char c) +{ + u_short rv; + + __asm__ __volatile__ + ("lsrb #1,%2\n\t" + "scs %0\n\t" + "lsll #8,%0\n\t" + "lsrb #1,%2\n\t" + "scs %0\n\t" + : "=&d" (rv), "=d" (c) + : "1" (c) + ); + return(rv); +} + +/* This expands a 2 bit color into one long for a movel operation + * (2 planes). + */ + +static __inline__ u_long expand2l(u_char c) +{ + u_long rv; + + __asm__ __volatile__ + ("lsrb #1,%2\n\t" + "scs %0\n\t" + "extw %0\n\t" + "swap %0\n\t" + "lsrb #1,%2\n\t" + "scs %0\n\t" + "extw %0\n\t" + : "=&d" (rv), "=d" (c) + : "1" (c) + ); + + return rv; +} + + +/* This duplicates a byte 2 times into a short. */ + +static __inline__ u_short dup2w(u_char c) +{ + ushort rv; + + __asm__ __volatile__ + ( "moveb %1,%0\n\t" + "lslw #8,%0\n\t" + "moveb %1,%0\n\t" + : "=&d" (rv) + : "d" (c) + ); + + return( rv ); +} + + +/* ====================================================================== */ + +/* fbcon_XXX routines - interface used by the world + * + * This system is now divided into two levels because of complications + * caused by hardware scrolling. Top level functions: + * + * fbcon_bmove(), fbcon_clear(), fbcon_putc() + * + * handles y values in range [0, scr_height-1] that correspond to real + * screen positions. y_wrap shift means that first line of bitmap may be + * anywhere on this display. These functions convert lineoffsets to + * bitmap offsets and deal with the wrap-around case by splitting blits. + * + * fbcon_bmove_physical_8() -- These functions fast implementations + * fbcon_clear_physical_8() -- of original fbcon_XXX fns. + * fbcon_putc_physical_8() -- (fontwidth != 8) may be added later + * + * WARNING: + * + * At the moment fbcon_putc() cannot blit across vertical wrap boundary + * Implies should only really hardware scroll in rows. Only reason for + * restriction is simplicity & efficiency at the moment. + */ + +static __inline__ int real_y(struct display *p, int y) +{ + int rows = p->conp->vc_rows; + + y += p->yscroll; + return(y < rows || p->scrollmode != SCROLL_YWRAP ? y : y-rows); +} + + +static int fbcon_clear(struct vc_data *conp, int sy, int sx, int height, + int width) +{ + int unit = conp->vc_num; + struct display *p = &disp[unit]; + u_int y_break; + + if (!p->can_soft_blank && console_blanked) + return(0); + + if ((sy <= p->cursor_y) && (p->cursor_y < sy+height) && + (sx <= p->cursor_x) && (p->cursor_x < sx+width)) + CURSOR_UNDRAWN(); + + /* Split blits that cross physical y_wrap boundary */ + + y_break = conp->vc_rows-p->yscroll; + if (sy < y_break && sy+height-1 >= y_break) { + u_int b = y_break-sy; + p->dispsw->clear(conp, p, real_y(p, sy), sx, b, width); + p->dispsw->clear(conp, p, real_y(p, sy+b), sx, height-b, width); + } else + p->dispsw->clear(conp, p, real_y(p, sy), sx, height, width); + + return(0); +} + + +static int fbcon_putc(struct vc_data *conp, int c, int y, int x) +{ + int unit = conp->vc_num; + struct display *p = &disp[unit]; + + if (!p->can_soft_blank && console_blanked) + return(0); + + if ((p->cursor_x == x) && (p->cursor_y == y)) + CURSOR_UNDRAWN(); + + p->dispsw->putc(conp, p, c, real_y(p, y), x); + + return(0); +} + + +static int fbcon_putcs(struct vc_data *conp, const char *s, int count, int y, + int x) +{ + int unit = conp->vc_num; + struct display *p = &disp[unit]; + + if (!p->can_soft_blank && console_blanked) + return(0); + + if ((p->cursor_y == y) && (x <= p->cursor_x) && (p->cursor_x < x+count)) + CURSOR_UNDRAWN(); + + p->dispsw->putcs(conp, p, s, count, real_y(p, y), x); + + return(0); +} + + +static int fbcon_cursor(struct vc_data *conp, int mode) +{ + int unit = conp->vc_num; + struct display *p = &disp[unit]; + + if (CURSOR_UNDRAWN ()) + p->dispsw->rev_char(p, p->cursor_x, real_y(p, p->cursor_y)); + p->cursor_x = conp->vc_x; + p->cursor_y = conp->vc_y; + + switch (mode) { + case CM_ERASE: + cursor_on = 0; + break; + + case CM_MOVE: + case CM_DRAW: + vbl_cursor_cnt = CURSOR_DRAW_DELAY; + cursor_on = 1; + break; + } + + return(0); +} + + +static void fbcon_vbl_handler(int irq, struct pt_regs *fp, void *dummy) +{ + struct display *p; + + if (!cursor_on) + return; + + if (vbl_cursor_cnt && --vbl_cursor_cnt == 0) { + /* Here no check is possible for console changing. The console + * switching code should set vbl_cursor_cnt to an appropriate value. + */ + p = &disp[fg_console]; + p->dispsw->rev_char(p, p->cursor_x, real_y(p, p->cursor_y)); + cursor_drawn ^= 1; + vbl_cursor_cnt = cursor_blink_rate; + } +} + + +static int fbcon_scroll(struct vc_data *conp, int t, int b, int dir, int count) +{ + int unit = conp->vc_num; + struct display *p = &disp[unit]; + + if (!p->can_soft_blank && console_blanked) + return(0); + + fbcon_cursor(conp, CM_ERASE); + + /* + * ++Geert: Only use ywrap/ypan if the console is in text mode + */ + + switch (dir) { + case SM_UP: + if (t == 0 && b == conp->vc_rows && + vt_cons[unit]->vc_mode == KD_TEXT) { + if (count > conp->vc_rows) /* Maximum realistic size */ + count = conp->vc_rows; + switch (p->scrollmode) { + case SCROLL_YWRAP: + p->yscroll += count; + if (p->yscroll >= conp->vc_rows) /* Deal with wrap */ + p->yscroll -= conp->vc_rows; + p->var.xoffset = 0; + p->var.yoffset = p->yscroll*p->fontheight; + p->var.vmode |= FB_VMODE_YWRAP; + fb_info->updatevar(unit); + break; + + case SCROLL_YPAN: + p->yscroll += count; + if (p->yscroll*p->fontheight+p->var.yres > + p->var.yres_virtual) { + p->dispsw->bmove(p, p->yscroll, 0, 0, 0, b-count, + conp->vc_cols); + p->yscroll = 0; + } + p->var.xoffset = 0; + p->var.yoffset = p->yscroll*p->fontheight; + p->var.vmode &= ~FB_VMODE_YWRAP; + fb_info->updatevar(unit); + break; + + case SCROLL_YMOVE: + p->dispsw->bmove(p, count, 0, 0, 0, b-count, conp->vc_cols); + break; + } + } else + fbcon_bmove(conp, t+count, 0, t, 0, b-t-count, conp->vc_cols); + fbcon_clear(conp, b-count, 0, count, conp->vc_cols); + break; + + case SM_DOWN: + if (t == 0 && b == conp->vc_rows && + vt_cons[unit]->vc_mode == KD_TEXT) { + if (count > conp->vc_rows) /* Maximum realistic size */ + count = conp->vc_rows; + switch (p->scrollmode) { + case SCROLL_YWRAP: + p->yscroll -= count; + if (p->yscroll < 0) /* Deal with wrap */ + p->yscroll += conp->vc_rows; + p->var.xoffset = 0; + p->var.yoffset = p->yscroll*p->fontheight; + p->var.vmode |= FB_VMODE_YWRAP; + fb_info->updatevar(unit); + break; + + case SCROLL_YPAN: + p->yscroll -= count; + if (p->yscroll < 0) { + p->yscroll = (p->var.yres_virtual-p->var.yres)/ + p->fontheight; + p->dispsw->bmove(p, 0, 0, p->yscroll+count, 0, b-count, + conp->vc_cols); + } + p->var.xoffset = 0; + p->var.yoffset = p->yscroll*p->fontheight; + p->var.vmode &= ~FB_VMODE_YWRAP; + fb_info->updatevar(unit); + break; + + case SCROLL_YMOVE: + p->dispsw->bmove(p, 0, 0, count, 0, b-count, conp->vc_cols); + break; + } + } else + fbcon_bmove(conp, t, 0, t+count, 0, b-t-count, conp->vc_cols); + + /* Fixed bmove() should end Arno's frustration with copying? + * Confusius says: + * Man who copies in wrong direction, end up with trashed data + */ + fbcon_clear(conp, t, 0, count, conp->vc_cols); + break; + + case SM_LEFT: + fbcon_bmove(conp, 0, t+count, 0, t, conp->vc_rows, b-t-count); + fbcon_clear(conp, 0, b-count, conp->vc_rows, count); + break; + + case SM_RIGHT: + fbcon_bmove(conp, 0, t, 0, t+count, conp->vc_rows, b-t-count); + fbcon_clear(conp, 0, t, conp->vc_rows, count); + break; + } + + return(0); +} + + +static int fbcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx, + int height, int width) +{ + int unit = conp->vc_num; + struct display *p = &disp[unit]; + + if (!p->can_soft_blank && console_blanked) + return(0); + + if (((sy <= p->cursor_y) && (p->cursor_y < sy+height) && + (sx <= p->cursor_x) && (p->cursor_x < sx+width)) || + ((dy <= p->cursor_y) && (p->cursor_y < dy+height) && + (dx <= p->cursor_x) && (p->cursor_x < dx+width))) + fbcon_cursor(conp, CM_ERASE); + + /* Split blits that cross physical y_wrap case. + * Pathological case involves 4 blits, better to use recursive + * code rather than unrolled case + * + * Recursive invocations don't need to erase the cursor over and + * over again, so we use fbcon_bmove_rec() + */ + fbcon_bmove_rec(p, sy, sx, dy, dx, height, width, conp->vc_rows-p->yscroll); + + return(0); +} + + +static void fbcon_bmove_rec(struct display *p, int sy, int sx, int dy, int dx, + int height, int width, u_int y_break) +{ + u_int b; + + if (sy < y_break && sy+height > y_break) { + b = y_break-sy; + if (dy < sy) { /* Avoid trashing self */ + fbcon_bmove_rec(p, sy, sx, dy, dx, b, width, y_break); + fbcon_bmove_rec(p, sy+b, sx, dy+b, dx, height-b, width, y_break); + } else { + fbcon_bmove_rec(p, sy+b, sx, dy+b, dx, height-b, width, y_break); + fbcon_bmove_rec(p, sy, sx, dy, dx, b, width, y_break); + } + return; + } + + if (dy < y_break && dy+height > y_break) { + b = y_break-dy; + if (dy < sy) { /* Avoid trashing self */ + fbcon_bmove_rec(p, sy, sx, dy, dx, b, width, y_break); + fbcon_bmove_rec(p, sy+b, sx, dy+b, dx, height-b, width, y_break); + } else { + fbcon_bmove_rec(p, sy+b, sx, dy+b, dx, height-b, width, y_break); + fbcon_bmove_rec(p, sy, sx, dy, dx, b, width, y_break); + } + return; + } + p->dispsw->bmove(p, real_y(p, sy), sx, real_y(p, dy), dx, height, width); +} + + +static int fbcon_switch(struct vc_data *conp) +{ + if (fb_info && fb_info->switch_con) + (*fb_info->switch_con)(conp->vc_num); + return(0); +} + + +static int fbcon_blank(int blank) +{ + struct display *p = &disp[fg_console]; + + fbcon_cursor(p->conp, blank ? CM_ERASE : CM_DRAW); + + if (!p->can_soft_blank) + if (blank) { + if (p->visual == FB_VISUAL_MONO01) + mymemset(p->screen_base, p->var.xres_virtual*p->var.yres_virtual* + p->var.bits_per_pixel>>3); + else + mymemclear(p->screen_base, p->var.xres_virtual*p->var.yres_virtual* + p->var.bits_per_pixel>>3); + return(0); + } else { + /* Tell console.c that it has to restore the screen itself */ + return(1); + } + (*fb_info->blank)(blank); + return(0); +} + + +/* ====================================================================== */ + +/* + * Low Level Operations for the various display memory organizations. + * + * Currently only the following organizations are supported here: + * + * - Monochrome + * - Color Interleaved Planes à la Amiga + * - Color Normal Planes + * - Color Interleaved Planes à la Atari (2, 4 and 8 planes) + * - Color Packed Pixels (8 and 16 bpp) + * - Cybervision Color Packed Pixels (accelerated) + */ + +#ifdef CONFIG_FBCON_MONO + + /* + * Monochrome + */ + +static void bmove_mono(struct display *p, int sy, int sx, int dy, int dx, + int height, int width) +{ + u_char *src, *dest; + u_int rows; + + if (sx == 0 && sy == 0 && width == p->next_line) { + src = p->screen_base; + dest = p->screen_base+dy*p->fontheight*width; + mymemmove(dest, src, height*p->fontheight*width); + } else if (dy <= sy) { + src = p->screen_base+sy*p->fontheight*p->next_line+sx; + dest = p->screen_base+dy*p->fontheight*p->next_line+dx; + for (rows = height*p->fontheight; rows--;) { + mymemmove(dest, src, width); + src += p->next_line; + dest += p->next_line; + } + } else { + src = p->screen_base+((sy+height)*p->fontheight-1)*p->next_line+sx; + dest = p->screen_base+((dy+height)*p->fontheight-1)*p->next_line+dx; + for (rows = height*p->fontheight; rows--;) { + mymemmove(dest, src, width); + src -= p->next_line; + dest -= p->next_line; + } + } +} + + +static void clear_mono(struct vc_data *conp, struct display *p, int sy, int sx, + int height, int width) +{ + u_char *dest; + u_int rows; + + dest = p->screen_base+sy*p->fontheight*p->next_line+sx; + + if (sx == 0 && width == p->next_line) + if (attr_reverse(p,conp)) + mymemset(dest, height*p->fontheight*width); + else + mymemclear(dest, height*p->fontheight*width); + else + for (rows = height*p->fontheight; rows--; dest += p->next_line) + if (attr_reverse(p,conp)) + mymemset(dest, width); + else + mymemclear_small(dest, width); +} + + +static void putc_mono(struct vc_data *conp, struct display *p, int c, int y, + int x) +{ + u_char *dest, *cdat; + u_int rows, bold, reverse, underline; + u_char d; + + c &= 0xff; + + dest = p->screen_base+y*p->fontheight*p->next_line+x; + cdat = p->fontdata+c*p->fontheight; + bold = attr_bold(p,conp); + reverse = attr_reverse(p,conp); + underline = attr_underline(p,conp); + + for (rows = p->fontheight; rows--; dest += p->next_line) { + d = *cdat++; + if (underline && !rows) + d = 0xff; + else if (bold) + d |= d>>1; + if (reverse) + d = ~d; + *dest = d; + } +} + + +static void putcs_mono(struct vc_data *conp, struct display *p, const char *s, + int count, int y, int x) +{ + u_char *dest, *dest0, *cdat; + u_int rows, bold, reverse, underline; + u_char c, d; + + dest0 = p->screen_base+y*p->fontheight*p->next_line+x; + bold = attr_bold(p,conp); + reverse = attr_reverse(p,conp); + underline = attr_underline(p,conp); + + while (count--) { + c = *s++; + dest = dest0++; + cdat = p->fontdata+c*p->fontheight; + for (rows = p->fontheight; rows--; dest += p->next_line) { + d = *cdat++; + if (underline && !rows) + d = 0xff; + else if (bold) + d |= d>>1; + if (reverse) + d = ~d; + *dest = d; + } + } +} + + +static void rev_char_mono(struct display *p, int x, int y) +{ + u_char *dest; + u_int rows; + + dest = p->screen_base+y*p->fontheight*p->next_line+x; + for (rows = p->fontheight; rows--; dest += p->next_line) + *dest = ~*dest; +} + +#endif /* CONFIG_FBCON_MONO */ + + +/* ====================================================================== */ + +#ifdef CONFIG_FBCON_ILBM + + /* + * Color Interleaved Planes + * + * This code heavily relies on the fact that + * + * next_line == interleave == next_plane*bits_per_pixel + * + * But maybe it can be merged with the code for normal bitplanes without + * much performance loss? + */ + +static void bmove_ilbm(struct display *p, int sy, int sx, int dy, int dx, + int height, int width) +{ + if (sx == 0 && sy == 0 && width == p->next_plane) + mymemmove(p->screen_base+dy*p->fontheight*p->next_line, p->screen_base, + height*p->fontheight*p->next_line); + else { + u_char *src, *dest; + u_int i; + + if (dy <= sy) { + src = p->screen_base+sy*p->fontheight*p->next_line+sx; + dest = p->screen_base+dy*p->fontheight*p->next_line+dx; + for (i = p->var.bits_per_pixel*height*p->fontheight; i--;) { + mymemmove(dest, src, width); + src += p->next_plane; + dest += p->next_plane; + } + } else { + src = p->screen_base+(sy+height)*p->fontheight*p->next_line+sx; + dest = p->screen_base+(dy+height)*p->fontheight*p->next_line+dx; + for (i = p->var.bits_per_pixel*height*p->fontheight; i--;) { + src -= p->next_plane; + dest -= p->next_plane; + mymemmove(dest, src, width); + } + } + } +} + + +static void clear_ilbm(struct vc_data *conp, struct display *p, int sy, int sx, + int height, int width) +{ + u_char *dest; + u_int i, rows; + int bg, bg0; + + dest = p->screen_base+sy*p->fontheight*p->next_line+sx; + + bg0 = attr_bgcol_ec(p,conp); + for (rows = height*p->fontheight; rows--;) { + bg = bg0; + for (i = p->var.bits_per_pixel; i--; dest += p->next_plane) { + if (bg & 1) + mymemset(dest, width); + else + mymemclear(dest, width); + bg >>= 1; + } + } +} + + +static void putc_ilbm(struct vc_data *conp, struct display *p, int c, int y, + int x) +{ + u_char *dest, *cdat; + u_int rows, i; + u_char d; + int fg0, bg0, fg, bg; + + c &= 0xff; + + dest = p->screen_base+y*p->fontheight*p->next_line+x; + cdat = p->fontdata+c*p->fontheight; + fg0 = attr_fgcol(p,conp); + bg0 = attr_bgcol(p,conp); + + for (rows = p->fontheight; rows--;) { + d = *cdat++; + fg = fg0; + bg = bg0; + for (i = p->var.bits_per_pixel; i--; dest += p->next_plane) { + if (bg & 1) + if (fg & 1) + *dest = 0xff; + else + *dest = ~d; + else + if (fg & 1) + *dest = d; + else + *dest = 0x00; + bg >>= 1; + fg >>= 1; + } + } +} + + +/* + * I splitted the console character loop in two parts: + * + * - slow version: this blits one character at a time + * + * - fast version: this blits 4 characters at a time at a longword aligned + * address, to reduce the number of expensive Chip RAM + * accesses. + * + * Experiments on my A4000/040 revealed that this makes a console switch on a + * 640x400 screen with 256 colors about 3 times faster. + * + * Geert + */ + +static void putcs_ilbm(struct vc_data *conp, struct display *p, const char *s, + int count, int y, int x) +{ + u_char *dest0, *dest, *cdat1, *cdat2, *cdat3, *cdat4; + u_int rows, i; + u_char c1, c2, c3, c4; + u_long d; + int fg0, bg0, fg, bg; + + dest0 = p->screen_base+y*p->fontheight*p->next_line+x; + fg0 = attr_fgcol(p,conp); + bg0 = attr_bgcol(p,conp); + + while (count--) + if (x&3 || count < 3) { /* Slow version */ + c1 = *s++; + dest = dest0++; + x++; + + cdat1 = p->fontdata+c1*p->fontheight; + for (rows = p->fontheight; rows--;) { + d = *cdat1++; + fg = fg0; + bg = bg0; + for (i = p->var.bits_per_pixel; i--; dest += p->next_plane) { + if (bg & 1) + if (fg & 1) + *dest = 0xff; + else + *dest = ~d; + else + if (fg & 1) + *dest = d; + else + *dest = 0x00; + bg >>= 1; + fg >>= 1; + } + } + } else { /* Fast version */ + c1 = s[0]; + c2 = s[1]; + c3 = s[2]; + c4 = s[3]; + + dest = dest0; + cdat1 = p->fontdata+c1*p->fontheight; + cdat2 = p->fontdata+c2*p->fontheight; + cdat3 = p->fontdata+c3*p->fontheight; + cdat4 = p->fontdata+c4*p->fontheight; + for (rows = p->fontheight; rows--;) { + d = *cdat1++<<24 | *cdat2++<<16 | *cdat3++<<8 | *cdat4++; + fg = fg0; + bg = bg0; + for (i = p->var.bits_per_pixel; i--; dest += p->next_plane) { + if (bg & 1) + if (fg & 1) + *(u_long *)dest = 0xffffffff; + else + *(u_long *)dest = ~d; + else + if (fg & 1) + *(u_long *)dest = d; + else + *(u_long *)dest = 0x00000000; + bg >>= 1; + fg >>= 1; + } + } + s += 4; + dest0 += 4; + x += 4; + count -= 3; + } +} + + +static void rev_char_ilbm(struct display *p, int x, int y) +{ + u_char *dest, *dest0; + u_int rows, i; + int mask; + + dest0 = p->screen_base+y*p->fontheight*p->next_line+x; + mask = p->fgcol ^ p->bgcol; + + /* + * This should really obey the individual character's + * background and foreground colors instead of simply + * inverting. + */ + + for (i = p->var.bits_per_pixel; i--; dest0 += p->next_plane) { + if (mask & 1) { + dest = dest0; + for (rows = p->fontheight; rows--; dest += p->next_line) + *dest = ~*dest; + } + mask >>= 1; + } +} + +#endif /* CONFIG_FBCON_ILBM */ + + +/* ====================================================================== */ + +#ifdef CONFIG_FBCON_PLANES + + /* + * Color Planes + */ + +static void bmove_plan(struct display *p, int sy, int sx, int dy, int dx, + int height, int width) +{ + u_char *src, *dest, *src0, *dest0; + u_int i, rows; + + if (sx == 0 && sy == 0 && width == p->next_line) { + src = p->screen_base; + dest = p->screen_base+dy*p->fontheight*width; + for (i = p->var.bits_per_pixel; i--;) { + mymemmove(dest, src, height*p->fontheight*width); + src += p->next_plane; + dest += p->next_plane; + } + } else if (dy <= sy) { + src0 = p->screen_base+sy*p->fontheight*p->next_line+sx; + dest0 = p->screen_base+dy*p->fontheight*p->next_line+dx; + for (i = p->var.bits_per_pixel; i--;) { + src = src0; + dest = dest0; + for (rows = height*p->fontheight; rows--;) { + mymemmove(dest, src, width); + src += p->next_line; + dest += p->next_line; + } + src0 += p->next_plane; + dest0 += p->next_plane; + } + } else { + src0 = p->screen_base+(sy+height)*p->fontheight*p->next_line+sx; + dest0 = p->screen_base+(dy+height)*p->fontheight*p->next_line+dx; + for (i = p->var.bits_per_pixel; i--;) { + src = src0; + dest = dest0; + for (rows = height*p->fontheight; rows--;) { + src -= p->next_line; + dest -= p->next_line; + mymemmove(dest, src, width); + } + src0 += p->next_plane; + dest0 += p->next_plane; + } + } +} + + +static void clear_plan(struct vc_data *conp, struct display *p, int sy, int sx, + int height, int width) +{ + u_char *dest, *dest0; + u_int i, rows; + int bg; + + dest0 = p->screen_base+sy*p->fontheight*p->next_line+sx; + + bg = attr_bgcol_ec(p,conp); + for (i = p->var.bits_per_pixel; i--; dest0 += p->next_plane) { + dest = dest0; + for (rows = height*p->fontheight; rows--; dest += p->next_line) + if (bg & 1) + mymemset(dest, width); + else + mymemclear(dest, width); + bg >>= 1; + } +} + + +static void putc_plan(struct vc_data *conp, struct display *p, int c, int y, + int x) +{ + u_char *dest, *dest0, *cdat, *cdat0; + u_int rows, i; + u_char d; + int fg, bg; + + c &= 0xff; + + dest0 = p->screen_base+y*p->fontheight*p->next_line+x; + cdat0 = p->fontdata+c*p->fontheight; + fg = attr_fgcol(p,conp); + bg = attr_bgcol(p,conp); + + for (i = p->var.bits_per_pixel; i--; dest0 += p->next_plane) { + dest = dest0; + cdat = cdat0; + for (rows = p->fontheight; rows--; dest += p->next_line) { + d = *cdat++; + if (bg & 1) + if (fg & 1) + *dest = 0xff; + else + *dest = ~d; + else + if (fg & 1) + *dest = d; + else + *dest = 0x00; + } + bg >>= 1; + fg >>= 1; + } +} + + +/* + * I splitted the console character loop in two parts + * (cfr. fbcon_putcs_ilbm()) + */ + +static void putcs_plan(struct vc_data *conp, struct display *p, const char *s, + int count, int y, int x) +{ + u_char *dest, *dest0, *dest1; + u_char *cdat1, *cdat2, *cdat3, *cdat4, *cdat10, *cdat20, *cdat30, *cdat40; + u_int rows, i; + u_char c1, c2, c3, c4; + u_long d; + int fg0, bg0, fg, bg; + + dest0 = p->screen_base+y*p->fontheight*p->next_line+x; + fg0 = attr_fgcol(p,conp); + bg0 = attr_bgcol(p,conp); + + while (count--) + if (x&3 || count < 3) { /* Slow version */ + c1 = *s++; + dest1 = dest0++; + x++; + + cdat10 = p->fontdata+c1*p->fontheight; + fg = fg0; + bg = bg0; + + for (i = p->var.bits_per_pixel; i--; dest1 += p->next_plane) { + dest = dest1; + cdat1 = cdat10; + for (rows = p->fontheight; rows--; dest += p->next_line) { + d = *cdat1++; + if (bg & 1) + if (fg & 1) + *dest = 0xff; + else + *dest = ~d; + else + if (fg & 1) + *dest = d; + else + *dest = 0x00; + } + bg >>= 1; + fg >>= 1; + } + } else { /* Fast version */ + c1 = s[0]; + c2 = s[1]; + c3 = s[2]; + c4 = s[3]; + + dest1 = dest0; + cdat10 = p->fontdata+c1*p->fontheight; + cdat20 = p->fontdata+c2*p->fontheight; + cdat30 = p->fontdata+c3*p->fontheight; + cdat40 = p->fontdata+c4*p->fontheight; + fg = fg0; + bg = bg0; + + for (i = p->var.bits_per_pixel; i--; dest1 += p->next_plane) { + dest = dest1; + cdat1 = cdat10; + cdat2 = cdat20; + cdat3 = cdat30; + cdat4 = cdat40; + for (rows = p->fontheight; rows--; dest += p->next_line) { + d = *cdat1++<<24 | *cdat2++<<16 | *cdat3++<<8 | *cdat4++; + if (bg & 1) + if (fg & 1) + *(u_long *)dest = 0xffffffff; + else + *(u_long *)dest = ~d; + else + if (fg & 1) + *(u_long *)dest = d; + else + *(u_long *)dest = 0x00000000; + } + bg >>= 1; + fg >>= 1; + } + s += 4; + dest0 += 4; + x += 4; + count -= 3; + } +} + + +static void rev_char_plan(struct display *p, int x, int y) +{ + u_char *dest, *dest0; + u_int rows, i; + int mask; + + dest0 = p->screen_base+y*p->fontheight*p->next_line+x; + mask = p->fgcol ^ p->bgcol; + + /* + * This should really obey the individual character's + * background and foreground colors instead of simply + * inverting. + */ + + for (i = p->var.bits_per_pixel; i--; dest0 += p->next_plane) { + if (mask & 1) { + dest = dest0; + for (rows = p->fontheight; rows--; dest += p->next_line) + *dest = ~*dest; + } + mask >>= 1; + } +} + +#endif /* CONFIG_FBCON_PLANES */ + + +/* ====================================================================== */ + +#ifdef CONFIG_FBCON_2PLANE + + /* + * 2 Planes (2-bytes interleave) + */ + +/* Increment/decrement 2 plane addresses */ + +#define INC_2P(p) do { if (!((long)(++(p)) & 1)) (p) += 2; } while(0) +#define DEC_2P(p) do { if ((long)(--(p)) & 1) (p) -= 2; } while(0) + +/* Convert a standard 4 bit color to our 2 bit color assignment: + * If at least two RGB channels are active, the low bit is turned on; + * The intensity bit (b3) is shifted into b1. + */ + +#define COLOR_2P(c) (((c & 7) >= 3 && (c & 7) != 4) | (c & 8) >> 2) + + +static void bmove_2_plane(struct display *p, int sy, int sx, int dy, int dx, + int height, int width) +{ + /* bmove() has to distinguish two major cases: If both, source and + * destination, start at even addresses or both are at odd + * addresses, just the first odd and last even column (if present) + * require special treatment (memmove_col()). The rest between + * then can be copied by normal operations, because all adjancent + * bytes are affected and are to be stored in the same order. + * The pathological case is when the move should go from an odd + * address to an even or vice versa. Since the bytes in the plane + * words must be assembled in new order, it seems wisest to make + * all movements by memmove_col(). + */ + + if (sx == 0 && dx == 0 && width == p->next_line/2) { + /* Special (but often used) case: Moving whole lines can be + * done with memmove() + */ + mymemmove(p->screen_base + dy * p->next_line * p->fontheight, + p->screen_base + sy * p->next_line * p->fontheight, + p->next_line * height * p->fontheight); + } else { + int rows, cols; + u_char *src; + u_char *dst; + int bytes = p->next_line; + int linesize = bytes * p->fontheight; + u_int colsize = height * p->fontheight; + u_int upwards = (dy < sy) || (dy == sy && dx < sx); + + if ((sx & 1) == (dx & 1)) { + /* odd->odd or even->even */ + + if (upwards) { + + src = p->screen_base + sy * linesize + (sx>>1)*4 + (sx & 1); + dst = p->screen_base + dy * linesize + (dx>>1)*4 + (dx & 1); + + if (sx & 1) { + memmove_2p_col(dst, src, colsize, bytes); + src += 3; + dst += 3; + --width; + } + + if (width > 1) { + for(rows = colsize; rows > 0; --rows) { + mymemmove(dst, src, (width>>1)*4); + src += bytes; + dst += bytes; + } + } + + if (width & 1) { + src -= colsize * bytes; + dst -= colsize * bytes; + memmove_2p_col(dst + (width>>1)*4, src + (width>>1)*4, + colsize, bytes); + } + } + else { + + if (!((sx+width-1) & 1)) { + src = p->screen_base + sy * linesize + ((sx+width-1)>>1)*4; + dst = p->screen_base + dy * linesize + ((dx+width-1)>>1)*4; + memmove_2p_col(dst, src, colsize, bytes); + --width; + } + + src = p->screen_base + sy * linesize + (sx>>1)*4 + (sx & 1); + dst = p->screen_base + dy * linesize + (dx>>1)*4 + (dx & 1); + + if (width > 1) { + src += colsize * bytes + (sx & 1)*3; + dst += colsize * bytes + (sx & 1)*3; + for(rows = colsize; rows > 0; --rows) { + src -= bytes; + dst -= bytes; + mymemmove(dst, src, (width>>1)*4); + } + } + + if (width & 1) { + memmove_2p_col(dst-3, src-3, colsize, bytes); + } + + } + } + else { + /* odd->even or even->odd */ + + if (upwards) { + src = p->screen_base + sy * linesize + (sx>>1)*4 + (sx & 1); + dst = p->screen_base + dy * linesize + (dx>>1)*4 + (dx & 1); + for(cols = width; cols > 0; --cols) { + memmove_2p_col(dst, src, colsize, bytes); + INC_2P(src); + INC_2P(dst); + } + } + else { + sx += width-1; + dx += width-1; + src = p->screen_base + sy * linesize + (sx>>1)*4 + (sx & 1); + dst = p->screen_base + dy * linesize + (dx>>1)*4 + (dx & 1); + for(cols = width; cols > 0; --cols) { + memmove_2p_col(dst, src, colsize, bytes); + DEC_2P(src); + DEC_2P(dst); + } + } + } + + + } +} + + +static void clear_2_plane(struct vc_data *conp, struct display *p, int sy, + int sx, int height, int width) +{ + ulong offset; + u_char *start; + int rows; + int bytes = p->next_line; + int lines = height * p->fontheight; + ulong size; + u_long cval; + u_short pcval; + + cval = expand2l (COLOR_2P (attr_bgcol_ec(p,conp))); + + if (sx == 0 && width == bytes/2) { + + offset = sy * bytes * p->fontheight; + size = lines * bytes; + memset_even_2p(p->screen_base+offset, size, cval); + + } else { + + offset = (sy * bytes * p->fontheight) + (sx>>1)*4 + (sx & 1); + start = p->screen_base + offset; + pcval = expand2w(COLOR_2P(attr_bgcol_ec(p,conp))); + + /* Clears are split if the region starts at an odd column or + * end at an even column. These extra columns are spread + * across the interleaved planes. All in between can be + * cleared by normal mymemclear_small(), because both bytes of + * the single plane words are affected. + */ + + if (sx & 1) { + memclear_2p_col(start, lines, pcval, bytes); + start += 3; + width--; + } + + if (width & 1) { + memclear_2p_col(start + (width>>1)*4, lines, pcval, bytes); + width--; + } + + if (width) { + for(rows = lines; rows-- ; start += bytes) + memset_even_2p(start, width*2, cval); + } + } +} + + +static void putc_2_plane(struct vc_data *conp, struct display *p, int c, int y, + int x) +{ + u_char *dest; + u_char *cdat; + int rows; + int bytes = p->next_line; + ulong eorx, fgx, bgx, fdx; + + c &= 0xff; + + dest = p->screen_base + y * p->fontheight * bytes + (x>>1)*4 + (x & 1); + cdat = p->fontdata + (c * p->fontheight); + + fgx = expand2w(COLOR_2P(attr_fgcol(p,conp))); + bgx = expand2w(COLOR_2P(attr_bgcol(p,conp))); + eorx = fgx ^ bgx; + + for(rows = p->fontheight ; rows-- ; dest += bytes) { + fdx = dup2w(*cdat++); + __asm__ __volatile__ ("movepw %1,%0@(0)" : /* no outputs */ + : "a" (dest), "d" ((fdx & eorx) ^ bgx)); + } +} + + +static void putcs_2_plane(struct vc_data *conp, struct display *p, + const char *s, int count, int y, int x) +{ + u_char *dest, *dest0; + u_char *cdat, c; + int rows; + int bytes; + ulong eorx, fgx, bgx, fdx; + + bytes = p->next_line; + dest0 = p->screen_base + y * p->fontheight * bytes + (x>>1)*4 + (x & 1); + fgx = expand2w(COLOR_2P(attr_fgcol(p,conp))); + bgx = expand2w(COLOR_2P(attr_bgcol(p,conp))); + eorx = fgx ^ bgx; + + while (count--) { + + c = *s++; + cdat = p->fontdata + (c * p->fontheight); + + for(rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) { + fdx = dup2w(*cdat++); + __asm__ __volatile__ ("movepw %1,%0@(0)" : /* no outputs */ + : "a" (dest), "d" ((fdx & eorx) ^ bgx)); + } + INC_2P(dest0); + } +} + + +static void rev_char_2_plane(struct display *p, int x, int y) +{ + u_char *dest; + int j; + int bytes; + + dest = p->screen_base + y * p->fontheight * p->next_line + (x>>1)*4 + (x & 1); + j = p->fontheight; + bytes = p->next_line; + while (j--) + { + /* This should really obey the individual character's + * background and foreground colors instead of simply + * inverting. + */ + dest[0] = ~dest[0]; + dest[2] = ~dest[2]; + dest += bytes; + } +} +#endif /* CONFIG_FBCON_2PLANE */ + + +/* ====================================================================== */ + +#ifdef CONFIG_FBCON_4PLANE + + /* + * 4 Planes (2-bytes interleave) + */ + +/* Increment/decrement 4 plane addresses */ + +#define INC_4P(p) do { if (!((long)(++(p)) & 1)) (p) += 6; } while(0) +#define DEC_4P(p) do { if ((long)(--(p)) & 1) (p) -= 6; } while(0) + + +static void bmove_4_plane(struct display *p, int sy, int sx, int dy, int dx, + int height, int width) +{ + /* bmove() has to distinguish two major cases: If both, source and + * destination, start at even addresses or both are at odd + * addresses, just the first odd and last even column (if present) + * require special treatment (memmove_col()). The rest between + * then can be copied by normal operations, because all adjancent + * bytes are affected and are to be stored in the same order. + * The pathological case is when the move should go from an odd + * address to an even or vice versa. Since the bytes in the plane + * words must be assembled in new order, it seems wisest to make + * all movements by memmove_col(). + */ + + if (sx == 0 && dx == 0 && width == p->next_line/4) { + /* Special (but often used) case: Moving whole lines can be + * done with memmove() + */ + mymemmove(p->screen_base + dy * p->next_line * p->fontheight, + p->screen_base + sy * p->next_line * p->fontheight, + p->next_line * height * p->fontheight); + } else { + int rows, cols; + u_char *src; + u_char *dst; + int bytes = p->next_line; + int linesize = bytes * p->fontheight; + u_int colsize = height * p->fontheight; + u_int upwards = (dy < sy) || (dy == sy && dx < sx); + + if ((sx & 1) == (dx & 1)) { + /* odd->odd or even->even */ + + if (upwards) { + + src = p->screen_base + sy * linesize + (sx>>1)*8 + (sx & 1); + dst = p->screen_base + dy * linesize + (dx>>1)*8 + (dx & 1); + + if (sx & 1) { + memmove_4p_col(dst, src, colsize, bytes); + src += 7; + dst += 7; + --width; + } + + if (width > 1) { + for(rows = colsize; rows > 0; --rows) { + mymemmove(dst, src, (width>>1)*8); + src += bytes; + dst += bytes; + } + } + + if (width & 1) { + src -= colsize * bytes; + dst -= colsize * bytes; + memmove_4p_col(dst + (width>>1)*8, src + (width>>1)*8, + colsize, bytes); + } + } + else { + + if (!((sx+width-1) & 1)) { + src = p->screen_base + sy * linesize + ((sx+width-1)>>1)*8; + dst = p->screen_base + dy * linesize + ((dx+width-1)>>1)*8; + memmove_4p_col(dst, src, colsize, bytes); + --width; + } + + src = p->screen_base + sy * linesize + (sx>>1)*8 + (sx & 1); + dst = p->screen_base + dy * linesize + (dx>>1)*8 + (dx & 1); + + if (width > 1) { + src += colsize * bytes + (sx & 1)*7; + dst += colsize * bytes + (sx & 1)*7; + for(rows = colsize; rows > 0; --rows) { + src -= bytes; + dst -= bytes; + mymemmove(dst, src, (width>>1)*8); + } + } + + if (width & 1) { + memmove_4p_col(dst-7, src-7, colsize, bytes); + } + + } + } + else { + /* odd->even or even->odd */ + + if (upwards) { + src = p->screen_base + sy * linesize + (sx>>1)*8 + (sx & 1); + dst = p->screen_base + dy * linesize + (dx>>1)*8 + (dx & 1); + for(cols = width; cols > 0; --cols) { + memmove_4p_col(dst, src, colsize, bytes); + INC_4P(src); + INC_4P(dst); + } + } + else { + sx += width-1; + dx += width-1; + src = p->screen_base + sy * linesize + (sx>>1)*8 + (sx & 1); + dst = p->screen_base + dy * linesize + (dx>>1)*8 + (dx & 1); + for(cols = width; cols > 0; --cols) { + memmove_4p_col(dst, src, colsize, bytes); + DEC_4P(src); + DEC_4P(dst); + } + } + } + + + } +} + + +static void clear_4_plane(struct vc_data *conp, struct display *p, int sy, + int sx, int height, int width) +{ + ulong offset; + u_char *start; + int rows; + int bytes = p->next_line; + int lines = height * p->fontheight; + ulong size; + u_long cval1, cval2, pcval; + + expand4dl(attr_bgcol_ec(p,conp), &cval1, &cval2); + + if (sx == 0 && width == bytes/4) { + + offset = sy * bytes * p->fontheight; + size = lines * bytes; + memset_even_4p(p->screen_base+offset, size, cval1, cval2); + + } else { + + offset = (sy * bytes * p->fontheight) + (sx>>1)*8 + (sx & 1); + start = p->screen_base + offset; + pcval = expand4l(attr_bgcol_ec(p,conp)); + + /* Clears are split if the region starts at an odd column or + * end at an even column. These extra columns are spread + * across the interleaved planes. All in between can be + * cleared by normal mymemclear_small(), because both bytes of + * the single plane words are affected. + */ + + if (sx & 1) { + memclear_4p_col(start, lines, pcval, bytes); + start += 7; + width--; + } + + if (width & 1) { + memclear_4p_col(start + (width>>1)*8, lines, pcval, bytes); + width--; + } + + if (width) { + for(rows = lines; rows-- ; start += bytes) + memset_even_4p(start, width*4, cval1, cval2); + } + } +} + + +static void putc_4_plane(struct vc_data *conp, struct display *p, int c, int y, + int x) +{ + u_char *dest; + u_char *cdat; + int rows; + int bytes = p->next_line; + ulong eorx, fgx, bgx, fdx; + + c &= 0xff; + + dest = p->screen_base + y * p->fontheight * bytes + (x>>1)*8 + (x & 1); + cdat = p->fontdata + (c * p->fontheight); + + fgx = expand4l(attr_fgcol(p,conp)); + bgx = expand4l(attr_bgcol(p,conp)); + eorx = fgx ^ bgx; + + for(rows = p->fontheight ; rows-- ; dest += bytes) { + fdx = dup4l(*cdat++); + __asm__ __volatile__ ("movepl %1,%0@(0)" : /* no outputs */ + : "a" (dest), "d" ((fdx & eorx) ^ bgx)); + } +} + + +static void putcs_4_plane(struct vc_data *conp, struct display *p, + const char *s, int count, int y, int x) +{ + u_char *dest, *dest0; + u_char *cdat, c; + int rows; + int bytes; + ulong eorx, fgx, bgx, fdx; + + bytes = p->next_line; + dest0 = p->screen_base + y * p->fontheight * bytes + (x>>1)*8 + (x & 1); + fgx = expand4l(attr_fgcol(p,conp)); + bgx = expand4l(attr_bgcol(p,conp)); + eorx = fgx ^ bgx; + + while (count--) { + + /* I think, unrolling the loops like in the 1 plane case isn't + * practicable here, because the body is much longer for 4 + * planes (mostly the dup4l()). I guess, unrolling this would + * need more than 256 bytes and so exceed the instruction + * cache :-( + */ + + c = *s++; + cdat = p->fontdata + (c * p->fontheight); + + for(rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) { + fdx = dup4l(*cdat++); + __asm__ __volatile__ ("movepl %1,%0@(0)" : /* no outputs */ + : "a" (dest), "d" ((fdx & eorx) ^ bgx)); + } + INC_4P(dest0); + } +} + + +static void rev_char_4_plane(struct display *p, int x, int y) +{ + u_char *dest; + int j; + int bytes; + + dest = p->screen_base + y * p->fontheight * p->next_line + (x>>1)*8 + (x & 1); + j = p->fontheight; + bytes = p->next_line; + + while (j--) + { + /* This should really obey the individual character's + * background and foreground colors instead of simply + * inverting. + */ + dest[0] = ~dest[0]; + dest[2] = ~dest[2]; + dest[4] = ~dest[4]; + dest[6] = ~dest[6]; + dest += bytes; + } +} +#endif /* CONFIG_FBCON_4PLANE */ + + +/* ====================================================================== */ + +#ifdef CONFIG_FBCON_8PLANE + + /* + * 8 Planes (2-bytes interleave) + */ + +/* In 8 plane mode, 256 colors would be possible, but only the first + * 16 are used by the console code (the upper 4 bits are + * background/unused). For that, the following functions mask off the + * higher 4 bits of each color. + */ + +/* Increment/decrement 8 plane addresses */ + +#define INC_8P(p) do { if (!((long)(++(p)) & 1)) (p) += 14; } while(0) +#define DEC_8P(p) do { if ((long)(--(p)) & 1) (p) -= 14; } while(0) + + +static void bmove_8_plane(struct display *p, int sy, int sx, int dy, int dx, + int height, int width) +{ + /* bmove() has to distinguish two major cases: If both, source and + * destination, start at even addresses or both are at odd + * addresses, just the first odd and last even column (if present) + * require special treatment (memmove_col()). The rest between + * then can be copied by normal operations, because all adjacent + * bytes are affected and are to be stored in the same order. + * The pathological case is when the move should go from an odd + * address to an even or vice versa. Since the bytes in the plane + * words must be assembled in new order, it seems wisest to make + * all movements by memmove_col(). + */ + + if (sx == 0 && dx == 0 && width == p->next_line/8) { + /* Special (but often used) case: Moving whole lines can be + * done with memmove() + */ + fast_memmove (p->screen_base + dy * p->next_line * p->fontheight, + p->screen_base + sy * p->next_line * p->fontheight, + p->next_line * height * p->fontheight); + } else { + int rows, cols; + u_char *src; + u_char *dst; + int bytes = p->next_line; + int linesize = bytes * p->fontheight; + u_int colsize = height * p->fontheight; + u_int upwards = (dy < sy) || (dy == sy && dx < sx); + + if ((sx & 1) == (dx & 1)) { + /* odd->odd or even->even */ + + if (upwards) { + + src = p->screen_base + sy * linesize + (sx>>1)*16 + (sx & 1); + dst = p->screen_base + dy * linesize + (dx>>1)*16 + (dx & 1); + + if (sx & 1) { + memmove_8p_col(dst, src, colsize, bytes); + src += 15; + dst += 15; + --width; + } + + if (width > 1) { + for(rows = colsize; rows > 0; --rows) { + fast_memmove (dst, src, (width >> 1) * 16); + src += bytes; + dst += bytes; + } + } + + if (width & 1) { + src -= colsize * bytes; + dst -= colsize * bytes; + memmove_8p_col(dst + (width>>1)*16, src + (width>>1)*16, + colsize, bytes); + } + } + else { + + if (!((sx+width-1) & 1)) { + src = p->screen_base + sy * linesize + ((sx+width-1)>>1)*16; + dst = p->screen_base + dy * linesize + ((dx+width-1)>>1)*16; + memmove_8p_col(dst, src, colsize, bytes); + --width; + } + + src = p->screen_base + sy * linesize + (sx>>1)*16 + (sx & 1); + dst = p->screen_base + dy * linesize + (dx>>1)*16 + (dx & 1); + + if (width > 1) { + src += colsize * bytes + (sx & 1)*15; + dst += colsize * bytes + (sx & 1)*15; + for(rows = colsize; rows > 0; --rows) { + src -= bytes; + dst -= bytes; + fast_memmove (dst, src, (width>>1)*16); + } + } + + if (width & 1) { + memmove_8p_col(dst-15, src-15, colsize, bytes); + } + + } + } + else { + /* odd->even or even->odd */ + + if (upwards) { + src = p->screen_base + sy * linesize + (sx>>1)*16 + (sx & 1); + dst = p->screen_base + dy * linesize + (dx>>1)*16 + (dx & 1); + for(cols = width; cols > 0; --cols) { + memmove_8p_col(dst, src, colsize, bytes); + INC_8P(src); + INC_8P(dst); + } + } + else { + sx += width-1; + dx += width-1; + src = p->screen_base + sy * linesize + (sx>>1)*16 + (sx & 1); + dst = p->screen_base + dy * linesize + (dx>>1)*16 + (dx & 1); + for(cols = width; cols > 0; --cols) { + memmove_8p_col(dst, src, colsize, bytes); + DEC_8P(src); + DEC_8P(dst); + } + } + } + + + } +} + + +static void clear_8_plane(struct vc_data *conp, struct display *p, int sy, + int sx, int height, int width) +{ + ulong offset; + u_char *start; + int rows; + int bytes = p->next_line; + int lines = height * p->fontheight; + ulong size; + u_long cval1, cval2, cval3, cval4, pcval1, pcval2; + + expand8ql(attr_bgcol_ec(p,conp), cval1, cval2, cval3, cval4); + + if (sx == 0 && width == bytes/8) { + + offset = sy * bytes * p->fontheight; + size = lines * bytes; + memset_even_8p(p->screen_base+offset, size, cval1, cval2, cval3, cval4); + + } else { + + offset = (sy * bytes * p->fontheight) + (sx>>1)*16 + (sx & 1); + start = p->screen_base + offset; + expand8dl(attr_bgcol_ec(p,conp), &pcval1, &pcval2); + + /* Clears are split if the region starts at an odd column or + * end at an even column. These extra columns are spread + * across the interleaved planes. All in between can be + * cleared by normal mymemclear_small(), because both bytes of + * the single plane words are affected. + */ + + if (sx & 1) { + memclear_8p_col(start, lines, pcval1, pcval2, bytes); + start += 7; + width--; + } + + if (width & 1) { + memclear_8p_col(start + (width>>1)*16, lines, pcval1, + pcval2, bytes); + width--; + } + + if (width) { + for(rows = lines; rows-- ; start += bytes) + memset_even_8p(start, width*8, cval1, cval2, cval3, cval4); + } + } +} + + +static void putc_8_plane(struct vc_data *conp, struct display *p, int c, int y, + int x) +{ + u_char *dest; + u_char *cdat; + int rows; + int bytes = p->next_line; + ulong eorx1, eorx2, fgx1, fgx2, bgx1, bgx2, fdx; + + c &= 0xff; + + dest = p->screen_base + y * p->fontheight * bytes + (x>>1)*16 + (x & 1); + cdat = p->fontdata + (c * p->fontheight); + + expand8dl(attr_fgcol(p,conp), &fgx1, &fgx2); + expand8dl(attr_bgcol(p,conp), &bgx1, &bgx2); + eorx1 = fgx1 ^ bgx1; eorx2 = fgx2 ^ bgx2; + + for(rows = p->fontheight ; rows-- ; dest += bytes) { + fdx = dup4l(*cdat++); + __asm__ __volatile__ + ("movepl %1,%0@(0)\n\t" + "movepl %2,%0@(8)" + : /* no outputs */ + : "a" (dest), "d" ((fdx & eorx1) ^ bgx1), + "d" ((fdx & eorx2) ^ bgx2) + ); + } +} + + +static void putcs_8_plane(struct vc_data *conp, struct display *p, + const char *s, int count, int y, int x) +{ + u_char *dest, *dest0; + u_char *cdat, c; + int rows; + int bytes; + ulong eorx1, eorx2, fgx1, fgx2, bgx1, bgx2, fdx; + + bytes = p->next_line; + dest0 = p->screen_base + y * p->fontheight * bytes + (x>>1)*16 + (x & 1); + + expand8dl(attr_fgcol(p,conp), &fgx1, &fgx2); + expand8dl(attr_bgcol(p,conp), &bgx1, &bgx2); + eorx1 = fgx1 ^ bgx1; eorx2 = fgx2 ^ bgx2; + + while (count--) { + + /* I think, unrolling the loops like in the 1 plane case isn't + * practicable here, because the body is much longer for 4 + * planes (mostly the dup4l()). I guess, unrolling this would + * need more than 256 bytes and so exceed the instruction + * cache :-( + */ + + c = *s++; + cdat = p->fontdata + (c * p->fontheight); + + for(rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) { + fdx = dup4l(*cdat++); + __asm__ __volatile__ + ("movepl %1,%0@(0)\n\t" + "movepl %2,%0@(8)" + : /* no outputs */ + : "a" (dest), "d" ((fdx & eorx1) ^ bgx1), + "d" ((fdx & eorx2) ^ bgx2) + ); + } + INC_8P(dest0); + } +} + + +static void rev_char_8_plane(struct display *p, int x, int y) +{ + u_char *dest; + int j; + int bytes; + + dest = p->screen_base + y * p->fontheight * p->next_line + (x>>1)*16 + (x & 1); + j = p->fontheight; + bytes = p->next_line; + + while (j--) + { + /* This should really obey the individual character's + * background and foreground colors instead of simply + * inverting. For 8 plane mode, only the lower 4 bits of the + * color are inverted, because only that color registers have + * been set up. + */ + dest[0] = ~dest[0]; + dest[2] = ~dest[2]; + dest[4] = ~dest[4]; + dest[6] = ~dest[6]; + dest += bytes; + } +} +#endif /* CONFIG_FBCON_8PLANE */ + + +/* ====================================================================== */ + +#ifdef CONFIG_FBCON_8PACKED + + /* + * 8 bpp Packed Pixels + */ + +static u_long nibbletab_8_packed[]={ +0x00000000,0x000000ff,0x0000ff00,0x0000ffff, +0x00ff0000,0x00ff00ff,0x00ffff00,0x00ffffff, +0xff000000,0xff0000ff,0xff00ff00,0xff00ffff, +0xffff0000,0xffff00ff,0xffffff00,0xffffffff}; + +static void bmove_8_packed(struct display *p, int sy, int sx, int dy, int dx, + int height, int width) +{ + int bytes = p->next_line, linesize = bytes * p->fontheight, rows; + u_char *src,*dst; + + if (sx == 0 && dx == 0 && width * 8 == bytes) { + mymemmove(p->screen_base + dy * linesize, + p->screen_base + sy * linesize, + height * linesize); + } + else { + if (dy < sy || (dy == sy && dx < sx)) { + src = p->screen_base + sy * linesize + sx * 8; + dst = p->screen_base + dy * linesize + dx * 8; + for (rows = height * p->fontheight ; rows-- ;) { + mymemmove(dst, src, width * 8); + src += bytes; + dst += bytes; + } + } + else { + src = p->screen_base + (sy+height) * linesize + sx * 8 + - bytes; + dst = p->screen_base + (dy+height) * linesize + dx * 8 + - bytes; + for (rows = height * p->fontheight ; rows-- ;) { + mymemmove(dst, src, width * 8); + src -= bytes; + dst -= bytes; + } + } + } +} + + +static void clear_8_packed(struct vc_data *conp, struct display *p, int sy, + int sx, int height, int width) +{ + u_char *dest0,*dest; + int bytes=p->next_line,lines=height * p->fontheight, rows, i; + u_long bgx; + + dest = p->screen_base + sy * p->fontheight * bytes + sx * 8; + + bgx=attr_bgcol_ec(p,conp); + bgx |= (bgx << 8); + bgx |= (bgx << 16); + + if (sx == 0 && width * 8 == bytes) { + for (i = 0 ; i < lines * width ; i++) { + ((u_long *)dest)[0]=bgx; + ((u_long *)dest)[1]=bgx; + dest+=8; + } + } else { + dest0=dest; + for (rows = lines; rows-- ; dest0 += bytes) { + dest=dest0; + for (i = 0 ; i < width ; i++) { + ((u_long *)dest)[0]=bgx; + ((u_long *)dest)[1]=bgx; + dest+=8; + } + } + } +} + + +static void putc_8_packed(struct vc_data *conp, struct display *p, int c, int y, + int x) +{ + u_char *dest,*cdat; + int bytes=p->next_line,rows; + ulong eorx,fgx,bgx; + + c &= 0xff; + + dest = p->screen_base + y * p->fontheight * bytes + x * 8; + cdat = p->fontdata + c * p->fontheight; + + fgx=attr_fgcol(p,conp); + bgx=attr_bgcol(p,conp); + fgx |= (fgx << 8); + fgx |= (fgx << 16); + bgx |= (bgx << 8); + bgx |= (bgx << 16); + eorx = fgx ^ bgx; + + for (rows = p->fontheight ; rows-- ; dest += bytes) { + ((u_long *)dest)[0]= + (nibbletab_8_packed[*cdat >> 4] & eorx) ^ bgx; + ((u_long *)dest)[1]= + (nibbletab_8_packed[*cdat++ & 0xf] & eorx) ^ bgx; + } +} + + +static void putcs_8_packed(struct vc_data *conp, struct display *p, + const char *s, int count, int y, int x) +{ + u_char *cdat, c, *dest, *dest0; + int rows,bytes=p->next_line; + u_long eorx, fgx, bgx; + + dest0 = p->screen_base + y * p->fontheight * bytes + x * 8; + fgx=attr_fgcol(p,conp); + bgx=attr_bgcol(p,conp); + fgx |= (fgx << 8); + fgx |= (fgx << 16); + bgx |= (bgx << 8); + bgx |= (bgx << 16); + eorx = fgx ^ bgx; + while (count--) { + c = *s++; + cdat = p->fontdata + c * p->fontheight; + + for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) { + ((u_long *)dest)[0]= + (nibbletab_8_packed[*cdat >> 4] & eorx) ^ bgx; + ((u_long *)dest)[1]= + (nibbletab_8_packed[*cdat++ & 0xf] & eorx) ^ bgx; + } + dest0+=8; + } +} + + +static void rev_char_8_packed(struct display *p, int x, int y) +{ + u_char *dest; + int bytes=p->next_line, rows; + + dest = p->screen_base + y * p->fontheight * bytes + x * 8; + for (rows = p->fontheight ; rows-- ; dest += bytes) { + ((u_long *)dest)[0] ^= 0x0f0f0f0f; + ((u_long *)dest)[1] ^= 0x0f0f0f0f; + } +} + +#endif /* CONFIG_FBCON_8PACKED */ + + +/* ====================================================================== */ + +#ifdef CONFIG_FBCON_16PACKED + + /* + * 16 bpp Packed Pixels + */ + +u_short packed16_cmap[16]; + +static u_long tab_16_packed[]={ +0x00000000,0x0000ffff,0xffff0000,0xffffffff}; + +static void bmove_16_packed(struct display *p, int sy, int sx, int dy, int dx, + int height, int width) +{ + int bytes = p->next_line, linesize = bytes * p->fontheight, rows; + u_char *src,*dst; + + if (sx == 0 && dx == 0 && width * 16 == bytes) { + mymemmove(p->screen_base + dy * linesize, + p->screen_base + sy * linesize, + height * linesize); + } + else { + if (dy < sy || (dy == sy && dx < sx)) { + src = p->screen_base + sy * linesize + sx * 16; + dst = p->screen_base + dy * linesize + dx * 16; + for (rows = height * p->fontheight ; rows-- ;) { + mymemmove(dst, src, width * 16); + src += bytes; + dst += bytes; + } + } + else { + src = p->screen_base + (sy+height) * linesize + sx * 16 + - bytes; + dst = p->screen_base + (dy+height) * linesize + dx * 16 + - bytes; + for (rows = height * p->fontheight ; rows-- ;) { + mymemmove(dst, src, width * 16); + src -= bytes; + dst -= bytes; + } + } + } +} + + +static void clear_16_packed(struct vc_data *conp, struct display *p, int sy, + int sx, int height, int width) +{ + u_char *dest0,*dest; + int bytes=p->next_line,lines=height * p->fontheight, rows, i; + u_long bgx; + + dest = p->screen_base + sy * p->fontheight * bytes + sx * 16; + + bgx = attr_bgcol_ec(p,conp); + bgx = packed16_cmap[bgx]; + bgx |= (bgx << 16); + + if (sx == 0 && width * 16 == bytes) { + for (i = 0 ; i < lines * width ; i++) { + ((u_long *)dest)[0]=bgx; + ((u_long *)dest)[1]=bgx; + ((u_long *)dest)[2]=bgx; + ((u_long *)dest)[3]=bgx; + dest+=16; + } + } else { + dest0=dest; + for (rows = lines; rows-- ; dest0 += bytes) { + dest=dest0; + for (i = 0 ; i < width ; i++) { + ((u_long *)dest)[0]=bgx; + ((u_long *)dest)[1]=bgx; + ((u_long *)dest)[2]=bgx; + ((u_long *)dest)[3]=bgx; + dest+=16; + } + } + } +} + + +static void putc_16_packed(struct vc_data *conp, struct display *p, int c, + int y, int x) +{ + u_char *dest,*cdat; + int bytes=p->next_line,rows; + ulong eorx,fgx,bgx; + + c &= 0xff; + + dest = p->screen_base + y * p->fontheight * bytes + x * 16; + cdat = p->fontdata + c * p->fontheight; + + fgx = attr_fgcol(p,conp); + fgx = packed16_cmap[fgx]; + bgx = attr_bgcol(p,conp); + bgx = packed16_cmap[bgx]; + fgx |= (fgx << 16); + bgx |= (bgx << 16); + eorx = fgx ^ bgx; + + for (rows = p->fontheight ; rows-- ; dest += bytes) { + ((u_long *)dest)[0]= + (tab_16_packed[*cdat >> 6] & eorx) ^ bgx; + ((u_long *)dest)[1]= + (tab_16_packed[*cdat >> 4 & 0x3] & eorx) ^ bgx; + ((u_long *)dest)[2]= + (tab_16_packed[*cdat >> 2 & 0x3] & eorx) ^ bgx; + ((u_long *)dest)[3]= + (tab_16_packed[*cdat++ & 0x3] & eorx) ^ bgx; + } +} + + +/* TODO */ +static void putcs_16_packed(struct vc_data *conp, struct display *p, + const char *s, int count, int y, int x) +{ + u_char *cdat, c, *dest, *dest0; + int rows,bytes=p->next_line; + u_long eorx, fgx, bgx; + + dest0 = p->screen_base + y * p->fontheight * bytes + x * 16; + fgx = attr_fgcol(p,conp); + fgx = packed16_cmap[fgx]; + bgx = attr_bgcol(p,conp); + bgx = packed16_cmap[bgx]; + fgx |= (fgx << 16); + bgx |= (bgx << 16); + eorx = fgx ^ bgx; + while (count--) { + c = *s++; + cdat = p->fontdata + c * p->fontheight; + + for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) { + ((u_long *)dest)[0]= + (tab_16_packed[*cdat >> 6] & eorx) ^ bgx; + ((u_long *)dest)[1]= + (tab_16_packed[*cdat >> 4 & 0x3] & eorx) ^ bgx; + ((u_long *)dest)[2]= + (tab_16_packed[*cdat >> 2 & 0x3] & eorx) ^ bgx; + ((u_long *)dest)[3]= + (tab_16_packed[*cdat++ & 0x3] & eorx) ^ bgx; + } + dest0+=16; + } +} + + +static void rev_char_16_packed(struct display *p, int x, int y) +{ + u_char *dest; + int bytes=p->next_line, rows; + + dest = p->screen_base + y * p->fontheight * bytes + x * 16; + for (rows = p->fontheight ; rows-- ; dest += bytes) { + ((u_long *)dest)[0] ^= 0xffffffff; + ((u_long *)dest)[1] ^= 0xffffffff; + ((u_long *)dest)[2] ^= 0xffffffff; + ((u_long *)dest)[3] ^= 0xffffffff; + } +} + +#endif /* CONFIG_FBCON_16PACKED */ + + +/* ====================================================================== */ + +#ifdef CONFIG_FBCON_CYBER + + /* + * Cybervision (accelerated) + */ + +static void bmove_cyber(struct display *p, int sy, int sx, int dy, int dx, + int height, int width) +{ + sx *= 8; dx *= 8; width *= 8; + Cyber_BitBLT((u_short)sx, (u_short)(sy*p->fontheight), (u_short)dx, + (u_short)(dy*p->fontheight), (u_short)width, + (u_short)(height*p->fontheight), (u_short)S3_NEW); +} + + +static void clear_cyber(struct vc_data *conp, struct display *p, int sy, int sx, + int height, int width) +{ + u_char bg; + + sx *= 8; width *= 8; + bg = attr_bgcol_ec(p,conp); + Cyber_RectFill((u_short)sx, (u_short)(sy*p->fontheight), (u_short)width, + (u_short)(height*p->fontheight), (u_short)S3_NEW, + (u_short)bg); +} + + +static void putc_cyber(struct vc_data *conp, struct display *p, int c, int y, + int x) +{ + u_char *dest, *cdat; + u_long tmp; + u_int rows, reverse, underline; + u_char d; + u_char fg, bg; + + c &= 0xff; + + dest = p->screen_base+y*p->fontheight*p->next_line+8*x; + cdat = p->fontdata+(c*p->fontheight); + fg = disp->fgcol; + bg = disp->bgcol; + reverse = conp->vc_reverse; + underline = conp->vc_underline; + + Cyber_WaitBlit(); + for (rows = p->fontheight; rows--; dest += p->next_line) { + d = *cdat++; + + if (underline && !rows) + d = 0xff; + if (reverse) + d = ~d; + + tmp = ((d & 0x80) ? fg : bg) << 24; + tmp |= ((d & 0x40) ? fg : bg) << 16; + tmp |= ((d & 0x20) ? fg : bg) << 8; + tmp |= ((d & 0x10) ? fg : bg); + *((u_long*) dest) = tmp; + tmp = ((d & 0x8) ? fg : bg) << 24; + tmp |= ((d & 0x4) ? fg : bg) << 16; + tmp |= ((d & 0x2) ? fg : bg) << 8; + tmp |= ((d & 0x1) ? fg : bg); + *((u_long*) dest + 1) = tmp; + } +} + + +static void putcs_cyber(struct vc_data *conp, struct display *p, const char *s, + int count, int y, int x) +{ + u_char *dest, *dest0, *cdat; + u_long tmp; + u_int rows, reverse, underline; + u_char c, d; + u_char fg, bg; + + dest0 = p->screen_base+y*p->fontheight*p->next_line+8*x; + fg = disp->fgcol; + bg = disp->bgcol; + reverse = conp->vc_reverse; + underline = conp->vc_underline; + + Cyber_WaitBlit(); + while (count--) { + c = *s++; + dest = dest0; + dest0 += 8; + cdat = p->fontdata+(c*p->fontheight); + for (rows = p->fontheight; rows--; dest += p->next_line) { + d = *cdat++; + + if (underline && !rows) + d = 0xff; + if (reverse) + d = ~d; + + tmp = ((d & 0x80) ? fg : bg) << 24; + tmp |= ((d & 0x40) ? fg : bg) << 16; + tmp |= ((d & 0x20) ? fg : bg) << 8; + tmp |= ((d & 0x10) ? fg : bg); + *((u_long*) dest) = tmp; + tmp = ((d & 0x8) ? fg : bg) << 24; + tmp |= ((d & 0x4) ? fg : bg) << 16; + tmp |= ((d & 0x2) ? fg : bg) << 8; + tmp |= ((d & 0x1) ? fg : bg); + *((u_long*) dest + 1) = tmp; + } + } +} + + +static void rev_char_cyber(struct display *p, int x, int y) +{ + u_char *dest; + u_int rows; + u_char fg, bg; + + fg = disp->fgcol; + bg = disp->bgcol; + + dest = p->screen_base+y*p->fontheight*p->next_line+8*x; + Cyber_WaitBlit(); + for (rows = p->fontheight; rows--; dest += p->next_line) { + *dest = (*dest == fg) ? bg : fg; + *(dest+1) = (*(dest + 1) == fg) ? bg : fg; + *(dest+2) = (*(dest + 2) == fg) ? bg : fg; + *(dest+3) = (*(dest + 3) == fg) ? bg : fg; + *(dest+4) = (*(dest + 4) == fg) ? bg : fg; + *(dest+5) = (*(dest + 5) == fg) ? bg : fg; + *(dest+6) = (*(dest + 6) == fg) ? bg : fg; + *(dest+7) = (*(dest + 7) == fg) ? bg : fg; + } +} + +#endif /* CONFIG_FBCON_CYBER */ + + +/* ====================================================================== */ + + /* + * The console `switch' structure for the frame buffer based console + */ + +struct consw fb_con = { + fbcon_startup, fbcon_init, fbcon_deinit, fbcon_clear, fbcon_putc, + fbcon_putcs, fbcon_cursor, fbcon_scroll, fbcon_bmove, fbcon_switch, + fbcon_blank +}; diff -u --recursive --new-file v1.3.93/linux/arch/m68k/console/font_8x16.c linux/arch/m68k/console/font_8x16.c --- v1.3.93/linux/arch/m68k/console/font_8x16.c Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/console/font_8x16.c Mon Mar 4 22:38:11 1996 @@ -0,0 +1,4625 @@ +/**********************************************/ +/* */ +/* Font file generated by cpi2fnt */ +/* */ +/**********************************************/ + +#define FONTDATAMAX 4096 + +char fontname_8x16[] = "VGA8x16"; + +int fontheight_8x16 = 16; +int fontwidth_8x16 = 8; + +unsigned char fontdata_8x16[FONTDATAMAX] = { + + /* 0 0x00 '^@' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 1 0x01 '^A' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x81, /* 10000001 */ + 0xa5, /* 10100101 */ + 0x81, /* 10000001 */ + 0x81, /* 10000001 */ + 0xbd, /* 10111101 */ + 0x99, /* 10011001 */ + 0x81, /* 10000001 */ + 0x81, /* 10000001 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 2 0x02 '^B' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xff, /* 11111111 */ + 0xdb, /* 11011011 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xc3, /* 11000011 */ + 0xe7, /* 11100111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 3 0x03 '^C' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 4 0x04 '^D' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 5 0x05 '^E' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0xe7, /* 11100111 */ + 0xe7, /* 11100111 */ + 0xe7, /* 11100111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 6 0x06 '^F' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 7 0x07 '^G' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 8 0x08 '^H' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xe7, /* 11100111 */ + 0xc3, /* 11000011 */ + 0xc3, /* 11000011 */ + 0xe7, /* 11100111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 9 0x09 '^I' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x42, /* 01000010 */ + 0x42, /* 01000010 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 10 0x0a '^J' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xc3, /* 11000011 */ + 0x99, /* 10011001 */ + 0xbd, /* 10111101 */ + 0xbd, /* 10111101 */ + 0x99, /* 10011001 */ + 0xc3, /* 11000011 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 11 0x0b '^K' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1e, /* 00011110 */ + 0x0e, /* 00001110 */ + 0x1a, /* 00011010 */ + 0x32, /* 00110010 */ + 0x78, /* 01111000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 12 0x0c '^L' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 13 0x0d '^M' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3f, /* 00111111 */ + 0x33, /* 00110011 */ + 0x3f, /* 00111111 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x70, /* 01110000 */ + 0xf0, /* 11110000 */ + 0xe0, /* 11100000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 14 0x0e '^N' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7f, /* 01111111 */ + 0x63, /* 01100011 */ + 0x7f, /* 01111111 */ + 0x63, /* 01100011 */ + 0x63, /* 01100011 */ + 0x63, /* 01100011 */ + 0x63, /* 01100011 */ + 0x67, /* 01100111 */ + 0xe7, /* 11100111 */ + 0xe6, /* 11100110 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 15 0x0f '^O' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xdb, /* 11011011 */ + 0x3c, /* 00111100 */ + 0xe7, /* 11100111 */ + 0x3c, /* 00111100 */ + 0xdb, /* 11011011 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 16 0x10 '^P' */ + 0x00, /* 00000000 */ + 0x80, /* 10000000 */ + 0xc0, /* 11000000 */ + 0xe0, /* 11100000 */ + 0xf0, /* 11110000 */ + 0xf8, /* 11111000 */ + 0xfe, /* 11111110 */ + 0xf8, /* 11111000 */ + 0xf0, /* 11110000 */ + 0xe0, /* 11100000 */ + 0xc0, /* 11000000 */ + 0x80, /* 10000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 17 0x11 '^Q' */ + 0x00, /* 00000000 */ + 0x02, /* 00000010 */ + 0x06, /* 00000110 */ + 0x0e, /* 00001110 */ + 0x1e, /* 00011110 */ + 0x3e, /* 00111110 */ + 0xfe, /* 11111110 */ + 0x3e, /* 00111110 */ + 0x1e, /* 00011110 */ + 0x0e, /* 00001110 */ + 0x06, /* 00000110 */ + 0x02, /* 00000010 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 18 0x12 '^R' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 19 0x13 '^S' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 20 0x14 '^T' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7f, /* 01111111 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0x7b, /* 01111011 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 21 0x15 '^U' */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x60, /* 01100000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x0c, /* 00001100 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 22 0x16 '^V' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 23 0x17 '^W' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 24 0x18 '^X' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 25 0x19 '^Y' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 26 0x1a '^Z' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0xfe, /* 11111110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 27 0x1b '^[' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xfe, /* 11111110 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 28 0x1c '^\' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 29 0x1d '^]' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x28, /* 00101000 */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x28, /* 00101000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 30 0x1e '^^' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0x7c, /* 01111100 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 31 0x1f '^_' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 32 0x20 ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 33 0x21 '!' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 34 0x22 '"' */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x24, /* 00100100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 35 0x23 '#' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 36 0x24 '$' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc2, /* 11000010 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x86, /* 10000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 37 0x25 '%' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc2, /* 11000010 */ + 0xc6, /* 11000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc6, /* 11000110 */ + 0x86, /* 10000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 38 0x26 '&' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 39 0x27 ''' */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 40 0x28 '(' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 41 0x29 ')' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 42 0x2a '*' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0xff, /* 11111111 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 43 0x2b '+' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 44 0x2c ',' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 45 0x2d '-' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 46 0x2e '.' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 47 0x2f '/' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x02, /* 00000010 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0x80, /* 10000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 48 0x30 '0' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 49 0x31 '1' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x38, /* 00111000 */ + 0x78, /* 01111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 50 0x32 '2' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 51 0x33 '3' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x3c, /* 00111100 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 52 0x34 '4' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x0c, /* 00001100 */ + 0x1c, /* 00011100 */ + 0x3c, /* 00111100 */ + 0x6c, /* 01101100 */ + 0xcc, /* 11001100 */ + 0xfe, /* 11111110 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x1e, /* 00011110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 53 0x35 '5' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xfc, /* 11111100 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 54 0x36 '6' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xfc, /* 11111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 55 0x37 '7' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 56 0x38 '8' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 57 0x39 '9' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 58 0x3a ':' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 59 0x3b ';' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 60 0x3c '<' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x06, /* 00000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 61 0x3d '=' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 62 0x3e '>' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 63 0x3f '?' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 64 0x40 '@' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xde, /* 11011110 */ + 0xde, /* 11011110 */ + 0xde, /* 11011110 */ + 0xdc, /* 11011100 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 65 0x41 'A' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 66 0x42 'B' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfc, /* 11111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0xfc, /* 11111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 67 0x43 'C' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0xc2, /* 11000010 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc2, /* 11000010 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 68 0x44 'D' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xf8, /* 11111000 */ + 0x6c, /* 01101100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x6c, /* 01101100 */ + 0xf8, /* 11111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 69 0x45 'E' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x66, /* 01100110 */ + 0x62, /* 01100010 */ + 0x68, /* 01101000 */ + 0x78, /* 01111000 */ + 0x68, /* 01101000 */ + 0x60, /* 01100000 */ + 0x62, /* 01100010 */ + 0x66, /* 01100110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 70 0x46 'F' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x66, /* 01100110 */ + 0x62, /* 01100010 */ + 0x68, /* 01101000 */ + 0x78, /* 01111000 */ + 0x68, /* 01101000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 71 0x47 'G' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0xc2, /* 11000010 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xde, /* 11011110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x66, /* 01100110 */ + 0x3a, /* 00111010 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 72 0x48 'H' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 73 0x49 'I' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 74 0x4a 'J' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1e, /* 00011110 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 75 0x4b 'K' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xe6, /* 11100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x6c, /* 01101100 */ + 0x78, /* 01111000 */ + 0x78, /* 01111000 */ + 0x6c, /* 01101100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0xe6, /* 11100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 76 0x4c 'L' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xf0, /* 11110000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x62, /* 01100010 */ + 0x66, /* 01100110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 77 0x4d 'M' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xee, /* 11101110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xd6, /* 11010110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 78 0x4e 'N' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xe6, /* 11100110 */ + 0xf6, /* 11110110 */ + 0xfe, /* 11111110 */ + 0xde, /* 11011110 */ + 0xce, /* 11001110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 79 0x4f 'O' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 80 0x50 'P' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfc, /* 11111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 81 0x51 'Q' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xd6, /* 11010110 */ + 0xde, /* 11011110 */ + 0x7c, /* 01111100 */ + 0x0c, /* 00001100 */ + 0x0e, /* 00001110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 82 0x52 'R' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfc, /* 11111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x6c, /* 01101100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0xe6, /* 11100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 83 0x53 'S' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x60, /* 01100000 */ + 0x38, /* 00111000 */ + 0x0c, /* 00001100 */ + 0x06, /* 00000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 84 0x54 'T' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x5a, /* 01011010 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 85 0x55 'U' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 86 0x56 'V' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 87 0x57 'W' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xfe, /* 11111110 */ + 0xee, /* 11101110 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 88 0x58 'X' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 89 0x59 'Y' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 90 0x5a 'Z' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0x86, /* 10000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc2, /* 11000010 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 91 0x5b '[' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 92 0x5c '\' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x80, /* 10000000 */ + 0xc0, /* 11000000 */ + 0xe0, /* 11100000 */ + 0x70, /* 01110000 */ + 0x38, /* 00111000 */ + 0x1c, /* 00011100 */ + 0x0e, /* 00001110 */ + 0x06, /* 00000110 */ + 0x02, /* 00000010 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 93 0x5d ']' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 94 0x5e '^' */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 95 0x5f '_' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 96 0x60 '`' */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 97 0x61 'a' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 98 0x62 'b' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xe0, /* 11100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x78, /* 01111000 */ + 0x6c, /* 01101100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 99 0x63 'c' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 100 0x64 'd' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1c, /* 00011100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x3c, /* 00111100 */ + 0x6c, /* 01101100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 101 0x65 'e' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 102 0x66 'f' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1c, /* 00011100 */ + 0x36, /* 00110110 */ + 0x32, /* 00110010 */ + 0x30, /* 00110000 */ + 0x78, /* 01111000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 103 0x67 'g' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x7c, /* 01111100 */ + 0x0c, /* 00001100 */ + 0xcc, /* 11001100 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + + /* 104 0x68 'h' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xe0, /* 11100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x6c, /* 01101100 */ + 0x76, /* 01110110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0xe6, /* 11100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 105 0x69 'i' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 106 0x6a 'j' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x00, /* 00000000 */ + 0x0e, /* 00001110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 107 0x6b 'k' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xe0, /* 11100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x66, /* 01100110 */ + 0x6c, /* 01101100 */ + 0x78, /* 01111000 */ + 0x78, /* 01111000 */ + 0x6c, /* 01101100 */ + 0x66, /* 01100110 */ + 0xe6, /* 11100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 108 0x6c 'l' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 109 0x6d 'm' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xec, /* 11101100 */ + 0xfe, /* 11111110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 110 0x6e 'n' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 111 0x6f 'o' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 112 0x70 'p' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x00, /* 00000000 */ + + /* 113 0x71 'q' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x7c, /* 01111100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x1e, /* 00011110 */ + 0x00, /* 00000000 */ + + /* 114 0x72 'r' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x76, /* 01110110 */ + 0x66, /* 01100110 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 115 0x73 's' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x60, /* 01100000 */ + 0x38, /* 00111000 */ + 0x0c, /* 00001100 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 116 0x74 't' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0xfc, /* 11111100 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x36, /* 00110110 */ + 0x1c, /* 00011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 117 0x75 'u' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 118 0x76 'v' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 119 0x77 'w' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 120 0x78 'x' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x38, /* 00111000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 121 0x79 'y' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0xf8, /* 11111000 */ + 0x00, /* 00000000 */ + + /* 122 0x7a 'z' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xcc, /* 11001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 123 0x7b '{' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x0e, /* 00001110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x70, /* 01110000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x0e, /* 00001110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 124 0x7c '|' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 125 0x7d '}' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x70, /* 01110000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x0e, /* 00001110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 126 0x7e '~' */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 127 0x7f '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 128 0x80 '€' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0xc2, /* 11000010 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc2, /* 11000010 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 129 0x81 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 130 0x82 '‚' */ + 0x00, /* 00000000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 131 0x83 'ƒ' */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 132 0x84 '„' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 133 0x85 '…' */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 134 0x86 '†' */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 135 0x87 '‡' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x18, /* 00011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 136 0x88 'ˆ' */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 137 0x89 '‰' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 138 0x8a 'Š' */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 139 0x8b '‹' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 140 0x8c 'Œ' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 141 0x8d '' */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 142 0x8e 'Ž' */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 143 0x8f '' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 144 0x90 '' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x66, /* 01100110 */ + 0x62, /* 01100010 */ + 0x68, /* 01101000 */ + 0x78, /* 01111000 */ + 0x68, /* 01101000 */ + 0x62, /* 01100010 */ + 0x66, /* 01100110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 145 0x91 '‘' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xec, /* 11101100 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x7e, /* 01111110 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0x6e, /* 01101110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 146 0x92 '’' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3e, /* 00111110 */ + 0x6c, /* 01101100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xfe, /* 11111110 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xce, /* 11001110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 147 0x93 '“' */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 148 0x94 '”' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 149 0x95 '•' */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 150 0x96 '–' */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x78, /* 01111000 */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 151 0x97 '—' */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 152 0x98 '˜' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + + /* 153 0x99 '™' */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 154 0x9a 'š' */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 155 0x9b '›' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 156 0x9c 'œ' */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x64, /* 01100100 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xe6, /* 11100110 */ + 0xfc, /* 11111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 157 0x9d '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 158 0x9e 'ž' */ + 0x00, /* 00000000 */ + 0xf8, /* 11111000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xf8, /* 11111000 */ + 0xc4, /* 11000100 */ + 0xcc, /* 11001100 */ + 0xde, /* 11011110 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 159 0x9f 'Ÿ' */ + 0x00, /* 00000000 */ + 0x0e, /* 00001110 */ + 0x1b, /* 00011011 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xd8, /* 11011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 160 0xa0 ' ' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 161 0xa1 '¡' */ + 0x00, /* 00000000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 162 0xa2 '¢' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 163 0xa3 '£' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 164 0xa4 '¤' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 165 0xa5 '¥' */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xe6, /* 11100110 */ + 0xf6, /* 11110110 */ + 0xfe, /* 11111110 */ + 0xde, /* 11011110 */ + 0xce, /* 11001110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 166 0xa6 '¦' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x3e, /* 00111110 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 167 0xa7 '§' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 168 0xa8 '¨' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 169 0xa9 '©' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 170 0xaa 'ª' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 171 0xab '«' */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0xe0, /* 11100000 */ + 0x62, /* 01100010 */ + 0x66, /* 01100110 */ + 0x6c, /* 01101100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xdc, /* 11011100 */ + 0x86, /* 10000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x3e, /* 00111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 172 0xac '¬' */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0xe0, /* 11100000 */ + 0x62, /* 01100010 */ + 0x66, /* 01100110 */ + 0x6c, /* 01101100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x66, /* 01100110 */ + 0xce, /* 11001110 */ + 0x9a, /* 10011010 */ + 0x3f, /* 00111111 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 173 0xad '­' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 174 0xae '®' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x36, /* 00110110 */ + 0x6c, /* 01101100 */ + 0xd8, /* 11011000 */ + 0x6c, /* 01101100 */ + 0x36, /* 00110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 175 0xaf '¯' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xd8, /* 11011000 */ + 0x6c, /* 01101100 */ + 0x36, /* 00110110 */ + 0x6c, /* 01101100 */ + 0xd8, /* 11011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 176 0xb0 '°' */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + + /* 177 0xb1 '±' */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + + /* 178 0xb2 '²' */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + + /* 179 0xb3 '³' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 180 0xb4 '´' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 181 0xb5 'µ' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 182 0xb6 '¶' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf6, /* 11110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 183 0xb7 '·' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 184 0xb8 '¸' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 185 0xb9 '¹' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf6, /* 11110110 */ + 0x06, /* 00000110 */ + 0xf6, /* 11110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 186 0xba 'º' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 187 0xbb '»' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x06, /* 00000110 */ + 0xf6, /* 11110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 188 0xbc '¼' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf6, /* 11110110 */ + 0x06, /* 00000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 189 0xbd '½' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 190 0xbe '¾' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 191 0xbf '¿' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 192 0xc0 'À' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 193 0xc1 'Á' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 194 0xc2 'Â' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 195 0xc3 'Ã' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 196 0xc4 'Ä' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 197 0xc5 'Å' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 198 0xc6 'Æ' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 199 0xc7 'Ç' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x37, /* 00110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 200 0xc8 'È' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x37, /* 00110111 */ + 0x30, /* 00110000 */ + 0x3f, /* 00111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 201 0xc9 'É' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3f, /* 00111111 */ + 0x30, /* 00110000 */ + 0x37, /* 00110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 202 0xca 'Ê' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf7, /* 11110111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 203 0xcb 'Ë' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xf7, /* 11110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 204 0xcc 'Ì' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x37, /* 00110111 */ + 0x30, /* 00110000 */ + 0x37, /* 00110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 205 0xcd 'Í' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 206 0xce 'Î' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf7, /* 11110111 */ + 0x00, /* 00000000 */ + 0xf7, /* 11110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 207 0xcf 'Ï' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 208 0xd0 'Ð' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 209 0xd1 'Ñ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 210 0xd2 'Ò' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 211 0xd3 'Ó' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x3f, /* 00111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 212 0xd4 'Ô' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 213 0xd5 'Õ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 214 0xd6 'Ö' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3f, /* 00111111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 215 0xd7 '×' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xff, /* 11111111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 216 0xd8 'Ø' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 217 0xd9 'Ù' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 218 0xda 'Ú' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 219 0xdb 'Û' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 220 0xdc 'Ü' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 221 0xdd 'Ý' */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + + /* 222 0xde 'Þ' */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + + /* 223 0xdf 'ß' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 224 0xe0 'à' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0xdc, /* 11011100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 225 0xe1 'á' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xd8, /* 11011000 */ + 0xcc, /* 11001100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 226 0xe2 'â' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 227 0xe3 'ã' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 228 0xe4 'ä' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 229 0xe5 'å' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 230 0xe6 'æ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + + /* 231 0xe7 'ç' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 232 0xe8 'è' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 233 0xe9 'é' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 234 0xea 'ê' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0xee, /* 11101110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 235 0xeb 'ë' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1e, /* 00011110 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x3e, /* 00111110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 236 0xec 'ì' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 237 0xed 'í' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x03, /* 00000011 */ + 0x06, /* 00000110 */ + 0x7e, /* 01111110 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0xf3, /* 11110011 */ + 0x7e, /* 01111110 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 238 0xee 'î' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1c, /* 00011100 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x7c, /* 01111100 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x1c, /* 00011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 239 0xef 'ï' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 240 0xf0 'ð' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 241 0xf1 'ñ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 242 0xf2 'ò' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 243 0xf3 'ó' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 244 0xf4 'ô' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x0e, /* 00001110 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 245 0xf5 'õ' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 246 0xf6 'ö' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 247 0xf7 '÷' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 248 0xf8 'ø' */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 249 0xf9 'ù' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 250 0xfa 'ú' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 251 0xfb 'û' */ + 0x00, /* 00000000 */ + 0x0f, /* 00001111 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0xec, /* 11101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x3c, /* 00111100 */ + 0x1c, /* 00011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 252 0xfc 'ü' */ + 0x00, /* 00000000 */ + 0x6c, /* 01101100 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 253 0xfd 'ý' */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x32, /* 00110010 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 254 0xfe 'þ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 255 0xff 'ÿ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + +}; + diff -u --recursive --new-file v1.3.93/linux/arch/m68k/console/font_8x8.c linux/arch/m68k/console/font_8x8.c --- v1.3.93/linux/arch/m68k/console/font_8x8.c Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/console/font_8x8.c Mon Mar 4 22:38:11 1996 @@ -0,0 +1,2577 @@ +/**********************************************/ +/* */ +/* Font file generated by cpi2fnt */ +/* */ +/**********************************************/ + +#define FONTDATAMAX 2048 + +char fontname_8x8[] = "VGA8x8"; + +int fontheight_8x8 = 8; +int fontwidth_8x8 = 8; + +unsigned char fontdata_8x8[FONTDATAMAX] = { + + /* 0 0x00 '^@' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 1 0x01 '^A' */ + 0x7e, /* 01111110 */ + 0x81, /* 10000001 */ + 0xa5, /* 10100101 */ + 0x81, /* 10000001 */ + 0xbd, /* 10111101 */ + 0x99, /* 10011001 */ + 0x81, /* 10000001 */ + 0x7e, /* 01111110 */ + + /* 2 0x02 '^B' */ + 0x7e, /* 01111110 */ + 0xff, /* 11111111 */ + 0xdb, /* 11011011 */ + 0xff, /* 11111111 */ + 0xc3, /* 11000011 */ + 0xe7, /* 11100111 */ + 0xff, /* 11111111 */ + 0x7e, /* 01111110 */ + + /* 3 0x03 '^C' */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + + /* 4 0x04 '^D' */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + + /* 5 0x05 '^E' */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xd6, /* 11010110 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + + /* 6 0x06 '^F' */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + + /* 7 0x07 '^G' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 8 0x08 '^H' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xe7, /* 11100111 */ + 0xc3, /* 11000011 */ + 0xc3, /* 11000011 */ + 0xe7, /* 11100111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 9 0x09 '^I' */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x42, /* 01000010 */ + 0x42, /* 01000010 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 10 0x0a '^J' */ + 0xff, /* 11111111 */ + 0xc3, /* 11000011 */ + 0x99, /* 10011001 */ + 0xbd, /* 10111101 */ + 0xbd, /* 10111101 */ + 0x99, /* 10011001 */ + 0xc3, /* 11000011 */ + 0xff, /* 11111111 */ + + /* 11 0x0b '^K' */ + 0x0f, /* 00001111 */ + 0x07, /* 00000111 */ + 0x0f, /* 00001111 */ + 0x7d, /* 01111101 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x78, /* 01111000 */ + + /* 12 0x0c '^L' */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + + /* 13 0x0d '^M' */ + 0x3f, /* 00111111 */ + 0x33, /* 00110011 */ + 0x3f, /* 00111111 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x70, /* 01110000 */ + 0xf0, /* 11110000 */ + 0xe0, /* 11100000 */ + + /* 14 0x0e '^N' */ + 0x7f, /* 01111111 */ + 0x63, /* 01100011 */ + 0x7f, /* 01111111 */ + 0x63, /* 01100011 */ + 0x63, /* 01100011 */ + 0x67, /* 01100111 */ + 0xe6, /* 11100110 */ + 0xc0, /* 11000000 */ + + /* 15 0x0f '^O' */ + 0x18, /* 00011000 */ + 0xdb, /* 11011011 */ + 0x3c, /* 00111100 */ + 0xe7, /* 11100111 */ + 0xe7, /* 11100111 */ + 0x3c, /* 00111100 */ + 0xdb, /* 11011011 */ + 0x18, /* 00011000 */ + + /* 16 0x10 '^P' */ + 0x80, /* 10000000 */ + 0xe0, /* 11100000 */ + 0xf8, /* 11111000 */ + 0xfe, /* 11111110 */ + 0xf8, /* 11111000 */ + 0xe0, /* 11100000 */ + 0x80, /* 10000000 */ + 0x00, /* 00000000 */ + + /* 17 0x11 '^Q' */ + 0x02, /* 00000010 */ + 0x0e, /* 00001110 */ + 0x3e, /* 00111110 */ + 0xfe, /* 11111110 */ + 0x3e, /* 00111110 */ + 0x0e, /* 00001110 */ + 0x02, /* 00000010 */ + 0x00, /* 00000000 */ + + /* 18 0x12 '^R' */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + + /* 19 0x13 '^S' */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + + /* 20 0x14 '^T' */ + 0x7f, /* 01111111 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0x7b, /* 01111011 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x00, /* 00000000 */ + + /* 21 0x15 '^U' */ + 0x3e, /* 00111110 */ + 0x61, /* 01100001 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x86, /* 10000110 */ + 0x7c, /* 01111100 */ + + /* 22 0x16 '^V' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 23 0x17 '^W' */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + + /* 24 0x18 '^X' */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 25 0x19 '^Y' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 26 0x1a '^Z' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0xfe, /* 11111110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 27 0x1b '^[' */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xfe, /* 11111110 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 28 0x1c '^\' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 29 0x1d '^]' */ + 0x00, /* 00000000 */ + 0x24, /* 00100100 */ + 0x66, /* 01100110 */ + 0xff, /* 11111111 */ + 0x66, /* 01100110 */ + 0x24, /* 00100100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 30 0x1e '^^' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 31 0x1f '^_' */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 32 0x20 ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 33 0x21 '!' */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 34 0x22 '"' */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x24, /* 00100100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 35 0x23 '#' */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + + /* 36 0x24 '$' */ + 0x18, /* 00011000 */ + 0x3e, /* 00111110 */ + 0x60, /* 01100000 */ + 0x3c, /* 00111100 */ + 0x06, /* 00000110 */ + 0x7c, /* 01111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 37 0x25 '%' */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xcc, /* 11001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x66, /* 01100110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 38 0x26 '&' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 39 0x27 ''' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 40 0x28 '(' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + + /* 41 0x29 ')' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + + /* 42 0x2a '*' */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0xff, /* 11111111 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 43 0x2b '+' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 44 0x2c ',' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + + /* 45 0x2d '-' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 46 0x2e '.' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 47 0x2f '/' */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0x80, /* 10000000 */ + 0x00, /* 00000000 */ + + /* 48 0x30 '0' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xd6, /* 11010110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + + /* 49 0x31 '1' */ + 0x18, /* 00011000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 50 0x32 '2' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x06, /* 00000110 */ + 0x1c, /* 00011100 */ + 0x30, /* 00110000 */ + 0x66, /* 01100110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 51 0x33 '3' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x06, /* 00000110 */ + 0x3c, /* 00111100 */ + 0x06, /* 00000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 52 0x34 '4' */ + 0x1c, /* 00011100 */ + 0x3c, /* 00111100 */ + 0x6c, /* 01101100 */ + 0xcc, /* 11001100 */ + 0xfe, /* 11111110 */ + 0x0c, /* 00001100 */ + 0x1e, /* 00011110 */ + 0x00, /* 00000000 */ + + /* 53 0x35 '5' */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xfc, /* 11111100 */ + 0x06, /* 00000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 54 0x36 '6' */ + 0x38, /* 00111000 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0xfc, /* 11111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 55 0x37 '7' */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + + /* 56 0x38 '8' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 57 0x39 '9' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + + /* 58 0x3a ':' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 59 0x3b ';' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + + /* 60 0x3c '<' */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x06, /* 00000110 */ + 0x00, /* 00000000 */ + + /* 61 0x3d '=' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 62 0x3e '>' */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x00, /* 00000000 */ + + /* 63 0x3f '?' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 64 0x40 '@' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xde, /* 11011110 */ + 0xde, /* 11011110 */ + 0xde, /* 11011110 */ + 0xc0, /* 11000000 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + + /* 65 0x41 'A' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 66 0x42 'B' */ + 0xfc, /* 11111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0xfc, /* 11111100 */ + 0x00, /* 00000000 */ + + /* 67 0x43 'C' */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 68 0x44 'D' */ + 0xf8, /* 11111000 */ + 0x6c, /* 01101100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x6c, /* 01101100 */ + 0xf8, /* 11111000 */ + 0x00, /* 00000000 */ + + /* 69 0x45 'E' */ + 0xfe, /* 11111110 */ + 0x62, /* 01100010 */ + 0x68, /* 01101000 */ + 0x78, /* 01111000 */ + 0x68, /* 01101000 */ + 0x62, /* 01100010 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 70 0x46 'F' */ + 0xfe, /* 11111110 */ + 0x62, /* 01100010 */ + 0x68, /* 01101000 */ + 0x78, /* 01111000 */ + 0x68, /* 01101000 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x00, /* 00000000 */ + + /* 71 0x47 'G' */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xce, /* 11001110 */ + 0x66, /* 01100110 */ + 0x3a, /* 00111010 */ + 0x00, /* 00000000 */ + + /* 72 0x48 'H' */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 73 0x49 'I' */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 74 0x4a 'J' */ + 0x1e, /* 00011110 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + + /* 75 0x4b 'K' */ + 0xe6, /* 11100110 */ + 0x66, /* 01100110 */ + 0x6c, /* 01101100 */ + 0x78, /* 01111000 */ + 0x6c, /* 01101100 */ + 0x66, /* 01100110 */ + 0xe6, /* 11100110 */ + 0x00, /* 00000000 */ + + /* 76 0x4c 'L' */ + 0xf0, /* 11110000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x62, /* 01100010 */ + 0x66, /* 01100110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 77 0x4d 'M' */ + 0xc6, /* 11000110 */ + 0xee, /* 11101110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xd6, /* 11010110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 78 0x4e 'N' */ + 0xc6, /* 11000110 */ + 0xe6, /* 11100110 */ + 0xf6, /* 11110110 */ + 0xde, /* 11011110 */ + 0xce, /* 11001110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 79 0x4f 'O' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 80 0x50 'P' */ + 0xfc, /* 11111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x00, /* 00000000 */ + + /* 81 0x51 'Q' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xce, /* 11001110 */ + 0x7c, /* 01111100 */ + 0x0e, /* 00001110 */ + + /* 82 0x52 'R' */ + 0xfc, /* 11111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x6c, /* 01101100 */ + 0x66, /* 01100110 */ + 0xe6, /* 11100110 */ + 0x00, /* 00000000 */ + + /* 83 0x53 'S' */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 84 0x54 'T' */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x5a, /* 01011010 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 85 0x55 'U' */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 86 0x56 'V' */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + + /* 87 0x57 'W' */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + + /* 88 0x58 'X' */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 89 0x59 'Y' */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 90 0x5a 'Z' */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0x8c, /* 10001100 */ + 0x18, /* 00011000 */ + 0x32, /* 00110010 */ + 0x66, /* 01100110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 91 0x5b '[' */ + 0x3c, /* 00111100 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 92 0x5c '\' */ + 0xc0, /* 11000000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x06, /* 00000110 */ + 0x02, /* 00000010 */ + 0x00, /* 00000000 */ + + /* 93 0x5d ']' */ + 0x3c, /* 00111100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 94 0x5e '^' */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 95 0x5f '_' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + + /* 96 0x60 '`' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 97 0x61 'a' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 98 0x62 'b' */ + 0xe0, /* 11100000 */ + 0x60, /* 01100000 */ + 0x7c, /* 01111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + + /* 99 0x63 'c' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 100 0x64 'd' */ + 0x1c, /* 00011100 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 101 0x65 'e' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 102 0x66 'f' */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x60, /* 01100000 */ + 0xf8, /* 11111000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x00, /* 00000000 */ + + /* 103 0x67 'g' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x7c, /* 01111100 */ + 0x0c, /* 00001100 */ + 0xf8, /* 11111000 */ + + /* 104 0x68 'h' */ + 0xe0, /* 11100000 */ + 0x60, /* 01100000 */ + 0x6c, /* 01101100 */ + 0x76, /* 01110110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0xe6, /* 11100110 */ + 0x00, /* 00000000 */ + + /* 105 0x69 'i' */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 106 0x6a 'j' */ + 0x06, /* 00000110 */ + 0x00, /* 00000000 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + + /* 107 0x6b 'k' */ + 0xe0, /* 11100000 */ + 0x60, /* 01100000 */ + 0x66, /* 01100110 */ + 0x6c, /* 01101100 */ + 0x78, /* 01111000 */ + 0x6c, /* 01101100 */ + 0xe6, /* 11100110 */ + 0x00, /* 00000000 */ + + /* 108 0x6c 'l' */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 109 0x6d 'm' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xec, /* 11101100 */ + 0xfe, /* 11111110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0x00, /* 00000000 */ + + /* 110 0x6e 'n' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + + /* 111 0x6f 'o' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 112 0x70 'p' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + + /* 113 0x71 'q' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x7c, /* 01111100 */ + 0x0c, /* 00001100 */ + 0x1e, /* 00011110 */ + + /* 114 0x72 'r' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x76, /* 01110110 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x00, /* 00000000 */ + + /* 115 0x73 's' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x06, /* 00000110 */ + 0xfc, /* 11111100 */ + 0x00, /* 00000000 */ + + /* 116 0x74 't' */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0xfc, /* 11111100 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x36, /* 00110110 */ + 0x1c, /* 00011100 */ + 0x00, /* 00000000 */ + + /* 117 0x75 'u' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 118 0x76 'v' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + + /* 119 0x77 'w' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + + /* 120 0x78 'x' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 121 0x79 'y' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x06, /* 00000110 */ + 0xfc, /* 11111100 */ + + /* 122 0x7a 'z' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x4c, /* 01001100 */ + 0x18, /* 00011000 */ + 0x32, /* 00110010 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 123 0x7b '{' */ + 0x0e, /* 00001110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x70, /* 01110000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x0e, /* 00001110 */ + 0x00, /* 00000000 */ + + /* 124 0x7c '|' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 125 0x7d '}' */ + 0x70, /* 01110000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x0e, /* 00001110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + + /* 126 0x7e '~' */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 127 0x7f '' */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 128 0x80 '€' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x0c, /* 00001100 */ + 0x78, /* 01111000 */ + + /* 129 0x81 '' */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 130 0x82 '‚' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 131 0x83 'ƒ' */ + 0x7c, /* 01111100 */ + 0x82, /* 10000010 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 132 0x84 '„' */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 133 0x85 '…' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 134 0x86 '†' */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 135 0x87 '‡' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x7e, /* 01111110 */ + 0x0c, /* 00001100 */ + 0x38, /* 00111000 */ + + /* 136 0x88 'ˆ' */ + 0x7c, /* 01111100 */ + 0x82, /* 10000010 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 137 0x89 '‰' */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 138 0x8a 'Š' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 139 0x8b '‹' */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 140 0x8c 'Œ' */ + 0x7c, /* 01111100 */ + 0x82, /* 10000010 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 141 0x8d '' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 142 0x8e 'Ž' */ + 0xc6, /* 11000110 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 143 0x8f '' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 144 0x90 '' */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xf8, /* 11111000 */ + 0xc0, /* 11000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 145 0x91 '‘' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0xd8, /* 11011000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 146 0x92 '’' */ + 0x3e, /* 00111110 */ + 0x6c, /* 01101100 */ + 0xcc, /* 11001100 */ + 0xfe, /* 11111110 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xce, /* 11001110 */ + 0x00, /* 00000000 */ + + /* 147 0x93 '“' */ + 0x7c, /* 01111100 */ + 0x82, /* 10000010 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 148 0x94 '”' */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 149 0x95 '•' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 150 0x96 '–' */ + 0x78, /* 01111000 */ + 0x84, /* 10000100 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 151 0x97 '—' */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 152 0x98 '˜' */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x06, /* 00000110 */ + 0xfc, /* 11111100 */ + + /* 153 0x99 '™' */ + 0xc6, /* 11000110 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + + /* 154 0x9a 'š' */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 155 0x9b '›' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 156 0x9c 'œ' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x64, /* 01100100 */ + 0xf0, /* 11110000 */ + 0x60, /* 01100000 */ + 0x66, /* 01100110 */ + 0xfc, /* 11111100 */ + 0x00, /* 00000000 */ + + /* 157 0x9d '' */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 158 0x9e 'ž' */ + 0xf8, /* 11111000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xfa, /* 11111010 */ + 0xc6, /* 11000110 */ + 0xcf, /* 11001111 */ + 0xc6, /* 11000110 */ + 0xc7, /* 11000111 */ + + /* 159 0x9f 'Ÿ' */ + 0x0e, /* 00001110 */ + 0x1b, /* 00011011 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0xd8, /* 11011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + + /* 160 0xa0 ' ' */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 161 0xa1 '¡' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 162 0xa2 '¢' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 163 0xa3 '£' */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 164 0xa4 '¤' */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + + /* 165 0xa5 '¥' */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0xe6, /* 11100110 */ + 0xf6, /* 11110110 */ + 0xde, /* 11011110 */ + 0xce, /* 11001110 */ + 0x00, /* 00000000 */ + + /* 166 0xa6 '¦' */ + 0x3c, /* 00111100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x3e, /* 00111110 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 167 0xa7 '§' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 168 0xa8 '¨' */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x63, /* 01100011 */ + 0x3e, /* 00111110 */ + 0x00, /* 00000000 */ + + /* 169 0xa9 '©' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 170 0xaa 'ª' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 171 0xab '«' */ + 0x63, /* 01100011 */ + 0xe6, /* 11100110 */ + 0x6c, /* 01101100 */ + 0x7e, /* 01111110 */ + 0x33, /* 00110011 */ + 0x66, /* 01100110 */ + 0xcc, /* 11001100 */ + 0x0f, /* 00001111 */ + + /* 172 0xac '¬' */ + 0x63, /* 01100011 */ + 0xe6, /* 11100110 */ + 0x6c, /* 01101100 */ + 0x7a, /* 01111010 */ + 0x36, /* 00110110 */ + 0x6a, /* 01101010 */ + 0xdf, /* 11011111 */ + 0x06, /* 00000110 */ + + /* 173 0xad '­' */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 174 0xae '®' */ + 0x00, /* 00000000 */ + 0x33, /* 00110011 */ + 0x66, /* 01100110 */ + 0xcc, /* 11001100 */ + 0x66, /* 01100110 */ + 0x33, /* 00110011 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 175 0xaf '¯' */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0x66, /* 01100110 */ + 0x33, /* 00110011 */ + 0x66, /* 01100110 */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 176 0xb0 '°' */ + 0x22, /* 00100010 */ + 0x88, /* 10001000 */ + 0x22, /* 00100010 */ + 0x88, /* 10001000 */ + 0x22, /* 00100010 */ + 0x88, /* 10001000 */ + 0x22, /* 00100010 */ + 0x88, /* 10001000 */ + + /* 177 0xb1 '±' */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + + /* 178 0xb2 '²' */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + + /* 179 0xb3 '³' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 180 0xb4 '´' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 181 0xb5 'µ' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 182 0xb6 '¶' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf6, /* 11110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 183 0xb7 '·' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 184 0xb8 '¸' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 185 0xb9 '¹' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf6, /* 11110110 */ + 0x06, /* 00000110 */ + 0xf6, /* 11110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 186 0xba 'º' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 187 0xbb '»' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x06, /* 00000110 */ + 0xf6, /* 11110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 188 0xbc '¼' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf6, /* 11110110 */ + 0x06, /* 00000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 189 0xbd '½' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 190 0xbe '¾' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 191 0xbf '¿' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 192 0xc0 'À' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 193 0xc1 'Á' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 194 0xc2 'Â' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 195 0xc3 'Ã' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 196 0xc4 'Ä' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 197 0xc5 'Å' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 198 0xc6 'Æ' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 199 0xc7 'Ç' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x37, /* 00110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 200 0xc8 'È' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x37, /* 00110111 */ + 0x30, /* 00110000 */ + 0x3f, /* 00111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 201 0xc9 'É' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3f, /* 00111111 */ + 0x30, /* 00110000 */ + 0x37, /* 00110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 202 0xca 'Ê' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf7, /* 11110111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 203 0xcb 'Ë' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xf7, /* 11110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 204 0xcc 'Ì' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x37, /* 00110111 */ + 0x30, /* 00110000 */ + 0x37, /* 00110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 205 0xcd 'Í' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 206 0xce 'Î' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf7, /* 11110111 */ + 0x00, /* 00000000 */ + 0xf7, /* 11110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 207 0xcf 'Ï' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 208 0xd0 'Ð' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 209 0xd1 'Ñ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 210 0xd2 'Ò' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 211 0xd3 'Ó' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x3f, /* 00111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 212 0xd4 'Ô' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 213 0xd5 'Õ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 214 0xd6 'Ö' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3f, /* 00111111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 215 0xd7 '×' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xff, /* 11111111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 216 0xd8 'Ø' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 217 0xd9 'Ù' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 218 0xda 'Ú' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 219 0xdb 'Û' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 220 0xdc 'Ü' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 221 0xdd 'Ý' */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + + /* 222 0xde 'Þ' */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + + /* 223 0xdf 'ß' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 224 0xe0 'à' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0xc8, /* 11001000 */ + 0xdc, /* 11011100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 225 0xe1 'á' */ + 0x78, /* 01111000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xd8, /* 11011000 */ + 0xcc, /* 11001100 */ + 0xc6, /* 11000110 */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + + /* 226 0xe2 'â' */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + + /* 227 0xe3 'ã' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + + /* 228 0xe4 'ä' */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 229 0xe5 'å' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + + /* 230 0xe6 'æ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0xc0, /* 11000000 */ + + /* 231 0xe7 'ç' */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 232 0xe8 'è' */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + + /* 233 0xe9 'é' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + + /* 234 0xea 'ê' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0xee, /* 11101110 */ + 0x00, /* 00000000 */ + + /* 235 0xeb 'ë' */ + 0x0e, /* 00001110 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x3e, /* 00111110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 236 0xec 'ì' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 237 0xed 'í' */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x7e, /* 01111110 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0x7e, /* 01111110 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + + /* 238 0xee 'î' */ + 0x1e, /* 00011110 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x7e, /* 01111110 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x1e, /* 00011110 */ + 0x00, /* 00000000 */ + + /* 239 0xef 'ï' */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 240 0xf0 'ð' */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 241 0xf1 'ñ' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 242 0xf2 'ò' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 243 0xf3 'ó' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 244 0xf4 'ô' */ + 0x0e, /* 00001110 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 245 0xf5 'õ' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0x70, /* 01110000 */ + + /* 246 0xf6 'ö' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 247 0xf7 '÷' */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 248 0xf8 'ø' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 249 0xf9 'ù' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 250 0xfa 'ú' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 251 0xfb 'û' */ + 0x0f, /* 00001111 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0xec, /* 11101100 */ + 0x6c, /* 01101100 */ + 0x3c, /* 00111100 */ + 0x1c, /* 00011100 */ + + /* 252 0xfc 'ü' */ + 0x6c, /* 01101100 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 253 0xfd 'ý' */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 254 0xfe 'þ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 255 0xff 'ÿ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + +}; + diff -u --recursive --new-file v1.3.93/linux/arch/m68k/console/fonts.c linux/arch/m68k/console/fonts.c --- v1.3.93/linux/arch/m68k/console/fonts.c Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/console/fonts.c Mon Mar 4 22:38:11 1996 @@ -0,0 +1,100 @@ + +/* + * arch/m68k/console/fonts.c -- `Soft' font definitions + * + * Created 1995 by Geert Uytterhoeven + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file README.legal in the main directory of this archive + * for more details. + */ + + +#include +#include +#include + + + /* + * External Font Definitions + */ + +/* VGA8x8 */ +extern char fontname_8x8[]; +extern int fontwidth_8x8, fontheight_8x8; +extern u_char fontdata_8x8[]; + +/* VGA8x16 */ +extern char fontname_8x16[]; +extern int fontwidth_8x16, fontheight_8x16; +extern u_char fontdata_8x16[]; + + + /* + * Font Descriptor Array + */ + +struct softfontdesc { + char *name; + int *width; + int *height; + u_char *data; +}; + +static struct softfontdesc softfonts[] = { + { fontname_8x8, &fontwidth_8x8, &fontheight_8x8, fontdata_8x8 }, + { fontname_8x16, &fontwidth_8x16, &fontheight_8x16, fontdata_8x16 } +}; + +static u_long numsoftfonts = sizeof(softfonts)/sizeof(*softfonts); + + + /* + * Find a font with a specific name + */ + +int findsoftfont(char *name, int *width, int *height, u_char *data[]) +{ + int i; + + for (i = 0; i < numsoftfonts; i++) + if (!strcmp(softfonts[i].name, name)) { + if (width) + *width = *softfonts[i].width; + if (height) + *height = *softfonts[i].height; + if (data) + *data = softfonts[i].data; + return(1); + } + return(0); +} + + + /* + * Get the default font for a specific screen size + */ + +void getdefaultfont(int xres, int yres, char *name[], int *width, int *height, + u_char *data[]) +{ + if (yres < 400) { + if (name) + *name = fontname_8x8; + if (width) + *width = fontwidth_8x8; + if (height) + *height = fontheight_8x8; + if (data) + *data = fontdata_8x8; + } else { + if (name) + *name = fontname_8x16; + if (width) + *width = fontwidth_8x16; + if (height) + *height = fontheight_8x16; + if (data) + *data = fontdata_8x16; + } +} diff -u --recursive --new-file v1.3.93/linux/arch/m68k/console/txtcon.c linux/arch/m68k/console/txtcon.c --- v1.3.93/linux/arch/m68k/console/txtcon.c Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/console/txtcon.c Mon Mar 4 22:38:11 1996 @@ -0,0 +1,127 @@ +/* + * linux/arch/m68k/console/txtcon.c -- Low level text mode based console driver + * + * Copyright (C) 1995 Geert Uytterhoeven + * + * + * This file is currently only a skeleton, since all Amigas and Ataris have + * bitmapped graphics. + * + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file README.legal in the main directory of this archive + * for more details. + */ + + +#include +#include + + + /* + * Interface used by the world + */ + +static u_long txtcon_startup(u_long kmem_start, char **display_desc); +static void txtcon_init(struct vc_data *conp); +static int txtcon_deinit(struct vc_data *conp); +static int txtcon_clear(struct vc_data *conp, int sy, int sx, int height, + int width); +static int txtcon_putc(struct vc_data *conp, int c, int y, int x); +static int txtcon_putcs(struct vc_data *conp, const char *s, int count, int y, + int x); +static int txtcon_cursor(struct vc_data *conp, int mode); +static int txtcon_scroll(struct vc_data *conp, int t, int b, int dir, int count); +static int txtcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx, + int height, int width); +static int txtcon_switch(struct vc_data *conp); +static int txtcon_blank(int blank); + + + +static u_long txtcon_startup(u_long kmem_start, char **display_desc) +{ + *display_desc = "Not yet implemented"; + return(kmem_start); +} + + +static void txtcon_init(struct vc_data *conp) +{ +} + + +static int txtcon_deinit(struct vc_data *conp) +{ + return(0); +} + + +/* ====================================================================== */ + +/* txtcon_XXX routines - interface used by the world */ + + +static int txtcon_clear(struct vc_data *conp, int sy, int sx, int height, + int width) +{ + return(0); +} + + +static int txtcon_putc(struct vc_data *conp, int c, int y, int x) +{ + return(0); +} + + +static int txtcon_putcs(struct vc_data *conp, const char *s, int count, int y, + int x) +{ + return(0); +} + + +static int txtcon_cursor(struct vc_data *conp, int mode) +{ + return(0); +} + + +static int txtcon_scroll(struct vc_data *conp, int t, int b, int dir, int count) +{ + return(0); +} + + +static int txtcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx, + int height, int width) +{ + return(0); +} + + +static int txtcon_switch(struct vc_data *conp) +{ + return(0); +} + + +static int txtcon_blank(int blank) +{ + return(0); +} + + +/* ====================================================================== */ + + /* + * The console `switch' structure for the text mode based console + */ + +struct consw txt_con = { + txtcon_startup, txtcon_init, txtcon_deinit, txtcon_clear, txtcon_putc, + txtcon_putcs, txtcon_cursor, txtcon_scroll, txtcon_bmove, txtcon_switch, + txtcon_blank +}; + diff -u --recursive --new-file v1.3.93/linux/arch/m68k/defconfig linux/arch/m68k/defconfig --- v1.3.93/linux/arch/m68k/defconfig Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/defconfig Thu Apr 18 02:01:36 1996 @@ -0,0 +1,145 @@ +# +# Automatically generated make config: don't edit +# + +# +# Loadable module support +# +# CONFIG_MODULES is not set +# CONFIG_MODVERSIONS is not set +# CONFIG_KERNELD is not set + +# +# General setup +# +CONFIG_AMIGA=y +# CONFIG_ATARI is not set +# CONFIG_MAC is not set +CONFIG_FPSP_040=y +# CONFIG_IFPSP_060 is not set +# CONFIG_NET is not set +CONFIG_SYSVIPC=y +CONFIG_BINFMT_AOUT=y +CONFIG_BINFMT_ELF=y +CONFIG_KERNEL_ELF=y +# CONFIG_ZORRO is not set + +# +# Block device driver configuration +# +CONFIG_BLK_DEV_FD=y +CONFIG_BLK_DEV_RAM=y +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_IDE is not set +# CONFIG_FB_CYBER is not set +# CONFIG_AMIGA_Z2RAM is not set +# CONFIG_ATARI_ACSI is not set + +# +# Networking options +# +# CONFIG_FIREWALL is not set +# CONFIG_NET_ALIAS is not set +CONFIG_INET=y +# CONFIG_IP_FORWARD is not set +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_FIREWALL is not set +# CONFIG_IP_ACCT is not set + +# +# (it is safe to leave these untouched) +# +# CONFIG_INET_PCTCP is not set +# CONFIG_INET_RARP is not set +# CONFIG_NO_PATH_MTU_DISCOVERY is not set +# CONFIG_TCP_NAGLE_OFF is not set +CONFIG_IP_NOSR=y +# CONFIG_SKB_LARGE is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_AX25 is not set +# CONFIG_BRIDGE is not set +# CONFIG_NETLINK is not set + +# +# SCSI support +# +CONFIG_SCSI=y + +# +# SCSI support type (disk, tape, CDrom) +# +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_ST=y +CONFIG_BLK_DEV_SR=y +# CONFIG_CHR_DEV_SG is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN is not set + +# +# SCSI low-level drivers +# +CONFIG_A3000_SCSI=y +# CONFIG_A2091_SCSI is not set +# CONFIG_GVP11_SCSI is not set +# CONFIG_ATARI_SCSI is not set + +# +# Network device support +# +# CONFIG_NETDEVICES is not set +# CONFIG_DUMMY is not set +# CONFIG_SLIP is not set +# CONFIG_PPP is not set +# CONFIG_ARIADNE is not set +# CONFIG_A2065 is not set +# CONFIG_HYDRA is not set +# CONFIG_ATARILANCE is not set + +# +# Filesystems +# +# CONFIG_QUOTA is not set +CONFIG_MINIX_FS=y +# CONFIG_EXT_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_XIA_FS is not set +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +# CONFIG_VFAT_FS is not set +# CONFIG_UMSDOS_FS is not set +CONFIG_PROC_FS=y +CONFIG_NFS_FS=y +# CONFIG_ROOT_NFS is not set +# CONFIG_SMB_FS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_AFFS_FS is not set + +# +# Character devices +# +# CONFIG_PRINTER is not set +CONFIG_AMIGAMOUSE=y +# CONFIG_ATARIMOUSE is not set +# CONFIG_UMISC is not set + +# +# Sound +# +# CONFIG_SOUND is not set +# CONFIG_DMASOUND is not set + +# +# Kernel hacking +# +# CONFIG_PROFILE is not set +CONFIG_SCSI_CONSTANTS=y diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/Makefile linux/arch/m68k/fpsp040/Makefile --- v1.3.93/linux/arch/m68k/fpsp040/Makefile Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/fpsp040/Makefile Thu Dec 28 01:15:11 1995 @@ -0,0 +1,31 @@ +# +# Makefile for Linux arch/m68k/fpsp040 source directory +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now in the main makefile... + +.S.o: + $(CC) -D__ASSEMBLY__ -traditional -c -o $*.o $< +# $(AS) -o $*.o $< + +OS_TARGET := fpsp.o + +OS_OBJS := bindec.o binstr.o decbin.o do_func.o gen_except.o get_op.o \ + kernel_ex.o res_func.o round.o sacos.o sasin.o satan.o satanh.o \ + scosh.o setox.o sgetem.o sint.o slog2.o slogn.o \ + smovecr.o srem_mod.o scale.o \ + ssin.o ssinh.o stan.o stanh.o sto_res.o stwotox.o tbldo.o util.o \ + x_bsun.o x_fline.o x_operr.o x_ovfl.o x_snan.o x_store.o \ + x_unfl.o x_unimp.o x_unsupp.o bugfix.o skeleton.o + +all: $(OS_TARGET) + +include $(TOPDIR)/Rules.make + +$(OS_OBJS): fpsp.h + +$(OS_TARGET): $(OS_OBJS) fpsp.h + $(LD) -x -r -o $(OS_TARGET) $(OS_OBJS) diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/bindec.S linux/arch/m68k/fpsp040/bindec.S --- v1.3.93/linux/arch/m68k/fpsp040/bindec.S Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/fpsp040/bindec.S Sat Feb 24 22:58:42 1996 @@ -0,0 +1,920 @@ +| +| bindec.sa 3.4 1/3/91 +| +| bindec +| +| Description: +| Converts an input in extended precision format +| to bcd format. +| +| Input: +| a0 points to the input extended precision value +| value in memory; d0 contains the k-factor sign-extended +| to 32-bits. The input may be either normalized, +| unnormalized, or denormalized. +| +| Output: result in the FP_SCR1 space on the stack. +| +| Saves and Modifies: D2-D7,A2,FP2 +| +| Algorithm: +| +| A1. Set RM and size ext; Set SIGMA = sign of input. +| The k-factor is saved for use in d7. Clear the +| BINDEC_FLG for separating normalized/denormalized +| input. If input is unnormalized or denormalized, +| normalize it. +| +| A2. Set X = abs(input). +| +| A3. Compute ILOG. +| ILOG is the log base 10 of the input value. It is +| approximated by adding e + 0.f when the original +| value is viewed as 2^^e * 1.f in extended precision. +| This value is stored in d6. +| +| A4. Clr INEX bit. +| The operation in A3 above may have set INEX2. +| +| A5. Set ICTR = 0; +| ICTR is a flag used in A13. It must be set before the +| loop entry A6. +| +| A6. Calculate LEN. +| LEN is the number of digits to be displayed. The +| k-factor can dictate either the total number of digits, +| if it is a positive number, or the number of digits +| after the decimal point which are to be included as +| significant. See the 68882 manual for examples. +| If LEN is computed to be greater than 17, set OPERR in +| USER_FPSR. LEN is stored in d4. +| +| A7. Calculate SCALE. +| SCALE is equal to 10^ISCALE, where ISCALE is the number +| of decimal places needed to insure LEN integer digits +| in the output before conversion to bcd. LAMBDA is the +| sign of ISCALE, used in A9. Fp1 contains +| 10^^(abs(ISCALE)) using a rounding mode which is a +| function of the original rounding mode and the signs +| of ISCALE and X. A table is given in the code. +| +| A8. Clr INEX; Force RZ. +| The operation in A3 above may have set INEX2. +| RZ mode is forced for the scaling operation to insure +| only one rounding error. The grs bits are collected in +| the INEX flag for use in A10. +| +| A9. Scale X -> Y. +| The mantissa is scaled to the desired number of +| significant digits. The excess digits are collected +| in INEX2. +| +| A10. Or in INEX. +| If INEX is set, round error occured. This is +| compensated for by 'or-ing' in the INEX2 flag to +| the lsb of Y. +| +| A11. Restore original FPCR; set size ext. +| Perform FINT operation in the user's rounding mode. +| Keep the size to extended. +| +| A12. Calculate YINT = FINT(Y) according to user's rounding +| mode. The FPSP routine sintd0 is used. The output +| is in fp0. +| +| A13. Check for LEN digits. +| If the int operation results in more than LEN digits, +| or less than LEN -1 digits, adjust ILOG and repeat from +| A6. This test occurs only on the first pass. If the +| result is exactly 10^LEN, decrement ILOG and divide +| the mantissa by 10. +| +| A14. Convert the mantissa to bcd. +| The binstr routine is used to convert the LEN digit +| mantissa to bcd in memory. The input to binstr is +| to be a fraction; i.e. (mantissa)/10^LEN and adjusted +| such that the decimal point is to the left of bit 63. +| The bcd digits are stored in the correct position in +| the final string area in memory. +| +| A15. Convert the exponent to bcd. +| As in A14 above, the exp is converted to bcd and the +| digits are stored in the final string. +| Test the length of the final exponent string. If the +| length is 4, set operr. +| +| A16. Write sign bits to final string. +| +| Implementation Notes: +| +| The registers are used as follows: +| +| d0: scratch; LEN input to binstr +| d1: scratch +| d2: upper 32-bits of mantissa for binstr +| d3: scratch;lower 32-bits of mantissa for binstr +| d4: LEN +| d5: LAMBDA/ICTR +| d6: ILOG +| d7: k-factor +| a0: ptr for original operand/final result +| a1: scratch pointer +| a2: pointer to FP_X; abs(original value) in ext +| fp0: scratch +| fp1: scratch +| fp2: scratch +| F_SCR1: +| F_SCR2: +| L_SCR1: +| L_SCR2: + +| Copyright (C) Motorola, Inc. 1990 +| All Rights Reserved +| +| THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA +| The copyright notice above does not evidence any +| actual or intended publication of such source code. + +|BINDEC idnt 2,1 | Motorola 040 Floating Point Software Package + + .include "fpsp.h" + + |section 8 + +| Constants in extended precision +LOG2: .long 0x3FFD0000,0x9A209A84,0xFBCFF798,0x00000000 +LOG2UP1: .long 0x3FFD0000,0x9A209A84,0xFBCFF799,0x00000000 + +| Constants in single precision +FONE: .long 0x3F800000,0x00000000,0x00000000,0x00000000 +FTWO: .long 0x40000000,0x00000000,0x00000000,0x00000000 +FTEN: .long 0x41200000,0x00000000,0x00000000,0x00000000 +F4933: .long 0x459A2800,0x00000000,0x00000000,0x00000000 + +RBDTBL: .byte 0,0,0,0 + .byte 3,3,2,2 + .byte 3,2,2,3 + .byte 2,3,3,2 + + |xref binstr + |xref sintdo + |xref ptenrn,ptenrm,ptenrp + + .global bindec + .global sc_mul +bindec: + moveml %d2-%d7/%a2,-(%a7) + fmovemx %fp0-%fp2,-(%a7) + +| A1. Set RM and size ext. Set SIGMA = sign input; +| The k-factor is saved for use in d7. Clear BINDEC_FLG for +| separating normalized/denormalized input. If the input +| is a denormalized number, set the BINDEC_FLG memory word +| to signal denorm. If the input is unnormalized, normalize +| the input and test for denormalized result. +| + fmovel #rm_mode,%FPCR |set RM and ext + movel (%a0),L_SCR2(%a6) |save exponent for sign check + movel %d0,%d7 |move k-factor to d7 + clrb BINDEC_FLG(%a6) |clr norm/denorm flag + movew STAG(%a6),%d0 |get stag + andiw #0xe000,%d0 |isolate stag bits + beq A2_str |if zero, input is norm +| +| Normalize the denorm +| +un_de_norm: + movew (%a0),%d0 + andiw #0x7fff,%d0 |strip sign of normalized exp + movel 4(%a0),%d1 + movel 8(%a0),%d2 +norm_loop: + subw #1,%d0 + lsll #1,%d2 + roxll #1,%d1 + tstl %d1 + bges norm_loop +| +| Test if the normalized input is denormalized +| + tstw %d0 + bgts pos_exp |if greater than zero, it is a norm + st BINDEC_FLG(%a6) |set flag for denorm +pos_exp: + andiw #0x7fff,%d0 |strip sign of normalized exp + movew %d0,(%a0) + movel %d1,4(%a0) + movel %d2,8(%a0) + +| A2. Set X = abs(input). +| +A2_str: + movel (%a0),FP_SCR2(%a6) | move input to work space + movel 4(%a0),FP_SCR2+4(%a6) | move input to work space + movel 8(%a0),FP_SCR2+8(%a6) | move input to work space + andil #0x7fffffff,FP_SCR2(%a6) |create abs(X) + +| A3. Compute ILOG. +| ILOG is the log base 10 of the input value. It is approx- +| imated by adding e + 0.f when the original value is viewed +| as 2^^e * 1.f in extended precision. This value is stored +| in d6. +| +| Register usage: +| Input/Output +| d0: k-factor/exponent +| d2: x/x +| d3: x/x +| d4: x/x +| d5: x/x +| d6: x/ILOG +| d7: k-factor/Unchanged +| a0: ptr for original operand/final result +| a1: x/x +| a2: x/x +| fp0: x/float(ILOG) +| fp1: x/x +| fp2: x/x +| F_SCR1:x/x +| F_SCR2:Abs(X)/Abs(X) with $3fff exponent +| L_SCR1:x/x +| L_SCR2:first word of X packed/Unchanged + + tstb BINDEC_FLG(%a6) |check for denorm + beqs A3_cont |if clr, continue with norm + movel #-4933,%d6 |force ILOG = -4933 + bras A4_str +A3_cont: + movew FP_SCR2(%a6),%d0 |move exp to d0 + movew #0x3fff,FP_SCR2(%a6) |replace exponent with 0x3fff + fmovex FP_SCR2(%a6),%fp0 |now fp0 has 1.f + subw #0x3fff,%d0 |strip off bias + faddw %d0,%fp0 |add in exp + fsubs FONE,%fp0 |subtract off 1.0 + fbge pos_res |if pos, branch + fmulx LOG2UP1,%fp0 |if neg, mul by LOG2UP1 + fmovel %fp0,%d6 |put ILOG in d6 as a lword + bras A4_str |go move out ILOG +pos_res: + fmulx LOG2,%fp0 |if pos, mul by LOG2 + fmovel %fp0,%d6 |put ILOG in d6 as a lword + + +| A4. Clr INEX bit. +| The operation in A3 above may have set INEX2. + +A4_str: + fmovel #0,%FPSR |zero all of fpsr - nothing needed + + +| A5. Set ICTR = 0; +| ICTR is a flag used in A13. It must be set before the +| loop entry A6. The lower word of d5 is used for ICTR. + + clrw %d5 |clear ICTR + + +| A6. Calculate LEN. +| LEN is the number of digits to be displayed. The k-factor +| can dictate either the total number of digits, if it is +| a positive number, or the number of digits after the +| original decimal point which are to be included as +| significant. See the 68882 manual for examples. +| If LEN is computed to be greater than 17, set OPERR in +| USER_FPSR. LEN is stored in d4. +| +| Register usage: +| Input/Output +| d0: exponent/Unchanged +| d2: x/x/scratch +| d3: x/x +| d4: exc picture/LEN +| d5: ICTR/Unchanged +| d6: ILOG/Unchanged +| d7: k-factor/Unchanged +| a0: ptr for original operand/final result +| a1: x/x +| a2: x/x +| fp0: float(ILOG)/Unchanged +| fp1: x/x +| fp2: x/x +| F_SCR1:x/x +| F_SCR2:Abs(X) with $3fff exponent/Unchanged +| L_SCR1:x/x +| L_SCR2:first word of X packed/Unchanged + +A6_str: + tstl %d7 |branch on sign of k + bles k_neg |if k <= 0, LEN = ILOG + 1 - k + movel %d7,%d4 |if k > 0, LEN = k + bras len_ck |skip to LEN check +k_neg: + movel %d6,%d4 |first load ILOG to d4 + subl %d7,%d4 |subtract off k + addql #1,%d4 |add in the 1 +len_ck: + tstl %d4 |LEN check: branch on sign of LEN + bles LEN_ng |if neg, set LEN = 1 + cmpl #17,%d4 |test if LEN > 17 + bles A7_str |if not, forget it + movel #17,%d4 |set max LEN = 17 + tstl %d7 |if negative, never set OPERR + bles A7_str |if positive, continue + orl #opaop_mask,USER_FPSR(%a6) |set OPERR & AIOP in USER_FPSR + bras A7_str |finished here +LEN_ng: + moveql #1,%d4 |min LEN is 1 + + +| A7. Calculate SCALE. +| SCALE is equal to 10^ISCALE, where ISCALE is the number +| of decimal places needed to insure LEN integer digits +| in the output before conversion to bcd. LAMBDA is the sign +| of ISCALE, used in A9. Fp1 contains 10^^(abs(ISCALE)) using +| the rounding mode as given in the following table (see +| Coonen, p. 7.23 as ref.; however, the SCALE variable is +| of opposite sign in bindec.sa from Coonen). +| +| Initial USE +| FPCR[6:5] LAMBDA SIGN(X) FPCR[6:5] +| ---------------------------------------------- +| RN 00 0 0 00/0 RN +| RN 00 0 1 00/0 RN +| RN 00 1 0 00/0 RN +| RN 00 1 1 00/0 RN +| RZ 01 0 0 11/3 RP +| RZ 01 0 1 11/3 RP +| RZ 01 1 0 10/2 RM +| RZ 01 1 1 10/2 RM +| RM 10 0 0 11/3 RP +| RM 10 0 1 10/2 RM +| RM 10 1 0 10/2 RM +| RM 10 1 1 11/3 RP +| RP 11 0 0 10/2 RM +| RP 11 0 1 11/3 RP +| RP 11 1 0 11/3 RP +| RP 11 1 1 10/2 RM +| +| Register usage: +| Input/Output +| d0: exponent/scratch - final is 0 +| d2: x/0 or 24 for A9 +| d3: x/scratch - offset ptr into PTENRM array +| d4: LEN/Unchanged +| d5: 0/ICTR:LAMBDA +| d6: ILOG/ILOG or k if ((k<=0)&(ILOG 0, skip this + cmpl %d6,%d7 |test k - ILOG + blts k_pos |if ILOG >= k, skip this + movel %d7,%d6 |if ((k<0) & (ILOG < k)) ILOG = k +k_pos: + movel %d6,%d0 |calc ILOG + 1 - LEN in d0 + addql #1,%d0 |add the 1 + subl %d4,%d0 |sub off LEN + swap %d5 |use upper word of d5 for LAMBDA + clrw %d5 |set it zero initially + clrw %d2 |set up d2 for very small case + tstl %d0 |test sign of ISCALE + bges iscale |if pos, skip next inst + addqw #1,%d5 |if neg, set LAMBDA true + cmpl #0xffffecd4,%d0 |test iscale <= -4908 + bgts no_inf |if false, skip rest + addil #24,%d0 |add in 24 to iscale + movel #24,%d2 |put 24 in d2 for A9 +no_inf: + negl %d0 |and take abs of ISCALE +iscale: + fmoves FONE,%fp1 |init fp1 to 1 + bfextu USER_FPCR(%a6){#26:#2},%d1 |get initial rmode bits + lslw #1,%d1 |put them in bits 2:1 + addw %d5,%d1 |add in LAMBDA + lslw #1,%d1 |put them in bits 3:1 + tstl L_SCR2(%a6) |test sign of original x + bges x_pos |if pos, don't set bit 0 + addql #1,%d1 |if neg, set bit 0 +x_pos: + leal RBDTBL,%a2 |load rbdtbl base + moveb (%a2,%d1),%d3 |load d3 with new rmode + lsll #4,%d3 |put bits in proper position + fmovel %d3,%fpcr |load bits into fpu + lsrl #4,%d3 |put bits in proper position + tstb %d3 |decode new rmode for pten table + bnes not_rn |if zero, it is RN + leal PTENRN,%a1 |load a1 with RN table base + bras rmode |exit decode +not_rn: + lsrb #1,%d3 |get lsb in carry + bccs not_rp |if carry clear, it is RM + leal PTENRP,%a1 |load a1 with RP table base + bras rmode |exit decode +not_rp: + leal PTENRM,%a1 |load a1 with RM table base +rmode: + clrl %d3 |clr table index +e_loop: + lsrl #1,%d0 |shift next bit into carry + bccs e_next |if zero, skip the mul + fmulx (%a1,%d3),%fp1 |mul by 10**(d3_bit_no) +e_next: + addl #12,%d3 |inc d3 to next pwrten table entry + tstl %d0 |test if ISCALE is zero + bnes e_loop |if not, loop + + +| A8. Clr INEX; Force RZ. +| The operation in A3 above may have set INEX2. +| RZ mode is forced for the scaling operation to insure +| only one rounding error. The grs bits are collected in +| the INEX flag for use in A10. +| +| Register usage: +| Input/Output + + fmovel #0,%FPSR |clr INEX + fmovel #rz_mode,%FPCR |set RZ rounding mode + + +| A9. Scale X -> Y. +| The mantissa is scaled to the desired number of significant +| digits. The excess digits are collected in INEX2. If mul, +| Check d2 for excess 10 exponential value. If not zero, +| the iscale value would have caused the pwrten calculation +| to overflow. Only a negative iscale can cause this, so +| multiply by 10^(d2), which is now only allowed to be 24, +| with a multiply by 10^8 and 10^16, which is exact since +| 10^24 is exact. If the input was denormalized, we must +| create a busy stack frame with the mul command and the +| two operands, and allow the fpu to complete the multiply. +| +| Register usage: +| Input/Output +| d0: FPCR with RZ mode/Unchanged +| d2: 0 or 24/unchanged +| d3: x/x +| d4: LEN/Unchanged +| d5: ICTR:LAMBDA +| d6: ILOG/Unchanged +| d7: k-factor/Unchanged +| a0: ptr for original operand/final result +| a1: ptr to PTENRM array/Unchanged +| a2: x/x +| fp0: float(ILOG)/X adjusted for SCALE (Y) +| fp1: 10^ISCALE/Unchanged +| fp2: x/x +| F_SCR1:x/x +| F_SCR2:Abs(X) with $3fff exponent/Unchanged +| L_SCR1:x/x +| L_SCR2:first word of X packed/Unchanged + +A9_str: + fmovex (%a0),%fp0 |load X from memory + fabsx %fp0 |use abs(X) + tstw %d5 |LAMBDA is in lower word of d5 + bnes sc_mul |if neg (LAMBDA = 1), scale by mul + fdivx %fp1,%fp0 |calculate X / SCALE -> Y to fp0 + bras A10_st |branch to A10 + +sc_mul: + tstb BINDEC_FLG(%a6) |check for denorm + beqs A9_norm |if norm, continue with mul + fmovemx %fp1-%fp1,-(%a7) |load ETEMP with 10^ISCALE + movel 8(%a0),-(%a7) |load FPTEMP with input arg + movel 4(%a0),-(%a7) + movel (%a0),-(%a7) + movel #18,%d3 |load count for busy stack +A9_loop: + clrl -(%a7) |clear lword on stack + dbf %d3,A9_loop + moveb VER_TMP(%a6),(%a7) |write current version number + moveb #BUSY_SIZE-4,1(%a7) |write current busy size + moveb #0x10,0x44(%a7) |set fcefpte[15] bit + movew #0x0023,0x40(%a7) |load cmdreg1b with mul command + moveb #0xfe,0x8(%a7) |load all 1s to cu savepc + frestore (%a7)+ |restore frame to fpu for completion + fmulx 36(%a1),%fp0 |multiply fp0 by 10^8 + fmulx 48(%a1),%fp0 |multiply fp0 by 10^16 + bras A10_st +A9_norm: + tstw %d2 |test for small exp case + beqs A9_con |if zero, continue as normal + fmulx 36(%a1),%fp0 |multiply fp0 by 10^8 + fmulx 48(%a1),%fp0 |multiply fp0 by 10^16 +A9_con: + fmulx %fp1,%fp0 |calculate X * SCALE -> Y to fp0 + + +| A10. Or in INEX. +| If INEX is set, round error occured. This is compensated +| for by 'or-ing' in the INEX2 flag to the lsb of Y. +| +| Register usage: +| Input/Output +| d0: FPCR with RZ mode/FPSR with INEX2 isolated +| d2: x/x +| d3: x/x +| d4: LEN/Unchanged +| d5: ICTR:LAMBDA +| d6: ILOG/Unchanged +| d7: k-factor/Unchanged +| a0: ptr for original operand/final result +| a1: ptr to PTENxx array/Unchanged +| a2: x/ptr to FP_SCR2(a6) +| fp0: Y/Y with lsb adjusted +| fp1: 10^ISCALE/Unchanged +| fp2: x/x + +A10_st: + fmovel %FPSR,%d0 |get FPSR + fmovex %fp0,FP_SCR2(%a6) |move Y to memory + leal FP_SCR2(%a6),%a2 |load a2 with ptr to FP_SCR2 + btstl #9,%d0 |check if INEX2 set + beqs A11_st |if clear, skip rest + oril #1,8(%a2) |or in 1 to lsb of mantissa + fmovex FP_SCR2(%a6),%fp0 |write adjusted Y back to fpu + + +| A11. Restore original FPCR; set size ext. +| Perform FINT operation in the user's rounding mode. Keep +| the size to extended. The sintdo entry point in the sint +| routine expects the FPCR value to be in USER_FPCR for +| mode and precision. The original FPCR is saved in L_SCR1. + +A11_st: + movel USER_FPCR(%a6),L_SCR1(%a6) |save it for later + andil #0x00000030,USER_FPCR(%a6) |set size to ext, +| ;block exceptions + + +| A12. Calculate YINT = FINT(Y) according to user's rounding mode. +| The FPSP routine sintd0 is used. The output is in fp0. +| +| Register usage: +| Input/Output +| d0: FPSR with AINEX cleared/FPCR with size set to ext +| d2: x/x/scratch +| d3: x/x +| d4: LEN/Unchanged +| d5: ICTR:LAMBDA/Unchanged +| d6: ILOG/Unchanged +| d7: k-factor/Unchanged +| a0: ptr for original operand/src ptr for sintdo +| a1: ptr to PTENxx array/Unchanged +| a2: ptr to FP_SCR2(a6)/Unchanged +| a6: temp pointer to FP_SCR2(a6) - orig value saved and restored +| fp0: Y/YINT +| fp1: 10^ISCALE/Unchanged +| fp2: x/x +| F_SCR1:x/x +| F_SCR2:Y adjusted for inex/Y with original exponent +| L_SCR1:x/original USER_FPCR +| L_SCR2:first word of X packed/Unchanged + +A12_st: + moveml %d0-%d1/%a0-%a1,-(%a7) |save regs used by sintd0 + movel L_SCR1(%a6),-(%a7) + movel L_SCR2(%a6),-(%a7) + leal FP_SCR2(%a6),%a0 |a0 is ptr to F_SCR2(a6) + fmovex %fp0,(%a0) |move Y to memory at FP_SCR2(a6) + tstl L_SCR2(%a6) |test sign of original operand + bges do_fint |if pos, use Y + orl #0x80000000,(%a0) |if neg, use -Y +do_fint: + movel USER_FPSR(%a6),-(%a7) + bsr sintdo |sint routine returns int in fp0 + moveb (%a7),USER_FPSR(%a6) + addl #4,%a7 + movel (%a7)+,L_SCR2(%a6) + movel (%a7)+,L_SCR1(%a6) + moveml (%a7)+,%d0-%d1/%a0-%a1 |restore regs used by sint + movel L_SCR2(%a6),FP_SCR2(%a6) |restore original exponent + movel L_SCR1(%a6),USER_FPCR(%a6) |restore user's FPCR + + +| A13. Check for LEN digits. +| If the int operation results in more than LEN digits, +| or less than LEN -1 digits, adjust ILOG and repeat from +| A6. This test occurs only on the first pass. If the +| result is exactly 10^LEN, decrement ILOG and divide +| the mantissa by 10. The calculation of 10^LEN cannot +| be inexact, since all powers of ten upto 10^27 are exact +| in extended precision, so the use of a previous power-of-ten +| table will introduce no error. +| +| +| Register usage: +| Input/Output +| d0: FPCR with size set to ext/scratch final = 0 +| d2: x/x +| d3: x/scratch final = x +| d4: LEN/LEN adjusted +| d5: ICTR:LAMBDA/LAMBDA:ICTR +| d6: ILOG/ILOG adjusted +| d7: k-factor/Unchanged +| a0: pointer into memory for packed bcd string formation +| a1: ptr to PTENxx array/Unchanged +| a2: ptr to FP_SCR2(a6)/Unchanged +| fp0: int portion of Y/abs(YINT) adjusted +| fp1: 10^ISCALE/Unchanged +| fp2: x/10^LEN +| F_SCR1:x/x +| F_SCR2:Y with original exponent/Unchanged +| L_SCR1:original USER_FPCR/Unchanged +| L_SCR2:first word of X packed/Unchanged + +A13_st: + swap %d5 |put ICTR in lower word of d5 + tstw %d5 |check if ICTR = 0 + bne not_zr |if non-zero, go to second test +| +| Compute 10^(LEN-1) +| + fmoves FONE,%fp2 |init fp2 to 1.0 + movel %d4,%d0 |put LEN in d0 + subql #1,%d0 |d0 = LEN -1 + clrl %d3 |clr table index +l_loop: + lsrl #1,%d0 |shift next bit into carry + bccs l_next |if zero, skip the mul + fmulx (%a1,%d3),%fp2 |mul by 10**(d3_bit_no) +l_next: + addl #12,%d3 |inc d3 to next pwrten table entry + tstl %d0 |test if LEN is zero + bnes l_loop |if not, loop +| +| 10^LEN-1 is computed for this test and A14. If the input was +| denormalized, check only the case in which YINT > 10^LEN. +| + tstb BINDEC_FLG(%a6) |check if input was norm + beqs A13_con |if norm, continue with checking + fabsx %fp0 |take abs of YINT + bra test_2 +| +| Compare abs(YINT) to 10^(LEN-1) and 10^LEN +| +A13_con: + fabsx %fp0 |take abs of YINT + fcmpx %fp2,%fp0 |compare abs(YINT) with 10^(LEN-1) + fbge test_2 |if greater, do next test + subql #1,%d6 |subtract 1 from ILOG + movew #1,%d5 |set ICTR + fmovel #rm_mode,%FPCR |set rmode to RM + fmuls FTEN,%fp2 |compute 10^LEN + bra A6_str |return to A6 and recompute YINT +test_2: + fmuls FTEN,%fp2 |compute 10^LEN + fcmpx %fp2,%fp0 |compare abs(YINT) with 10^LEN + fblt A14_st |if less, all is ok, go to A14 + fbgt fix_ex |if greater, fix and redo + fdivs FTEN,%fp0 |if equal, divide by 10 + addql #1,%d6 | and inc ILOG + bras A14_st | and continue elsewhere +fix_ex: + addql #1,%d6 |increment ILOG by 1 + movew #1,%d5 |set ICTR + fmovel #rm_mode,%FPCR |set rmode to RM + bra A6_str |return to A6 and recompute YINT +| +| Since ICTR <> 0, we have already been through one adjustment, +| and shouldn't have another; this is to check if abs(YINT) = 10^LEN +| 10^LEN is again computed using whatever table is in a1 since the +| value calculated cannot be inexact. +| +not_zr: + fmoves FONE,%fp2 |init fp2 to 1.0 + movel %d4,%d0 |put LEN in d0 + clrl %d3 |clr table index +z_loop: + lsrl #1,%d0 |shift next bit into carry + bccs z_next |if zero, skip the mul + fmulx (%a1,%d3),%fp2 |mul by 10**(d3_bit_no) +z_next: + addl #12,%d3 |inc d3 to next pwrten table entry + tstl %d0 |test if LEN is zero + bnes z_loop |if not, loop + fabsx %fp0 |get abs(YINT) + fcmpx %fp2,%fp0 |check if abs(YINT) = 10^LEN + fbne A14_st |if not, skip this + fdivs FTEN,%fp0 |divide abs(YINT) by 10 + addql #1,%d6 |and inc ILOG by 1 + addql #1,%d4 | and inc LEN + fmuls FTEN,%fp2 | if LEN++, the get 10^^LEN + + +| A14. Convert the mantissa to bcd. +| The binstr routine is used to convert the LEN digit +| mantissa to bcd in memory. The input to binstr is +| to be a fraction; i.e. (mantissa)/10^LEN and adjusted +| such that the decimal point is to the left of bit 63. +| The bcd digits are stored in the correct position in +| the final string area in memory. +| +| +| Register usage: +| Input/Output +| d0: x/LEN call to binstr - final is 0 +| d1: x/0 +| d2: x/ms 32-bits of mant of abs(YINT) +| d3: x/ls 32-bits of mant of abs(YINT) +| d4: LEN/Unchanged +| d5: ICTR:LAMBDA/LAMBDA:ICTR +| d6: ILOG +| d7: k-factor/Unchanged +| a0: pointer into memory for packed bcd string formation +| /ptr to first mantissa byte in result string +| a1: ptr to PTENxx array/Unchanged +| a2: ptr to FP_SCR2(a6)/Unchanged +| fp0: int portion of Y/abs(YINT) adjusted +| fp1: 10^ISCALE/Unchanged +| fp2: 10^LEN/Unchanged +| F_SCR1:x/Work area for final result +| F_SCR2:Y with original exponent/Unchanged +| L_SCR1:original USER_FPCR/Unchanged +| L_SCR2:first word of X packed/Unchanged + +A14_st: + fmovel #rz_mode,%FPCR |force rz for conversion + fdivx %fp2,%fp0 |divide abs(YINT) by 10^LEN + leal FP_SCR1(%a6),%a0 + fmovex %fp0,(%a0) |move abs(YINT)/10^LEN to memory + movel 4(%a0),%d2 |move 2nd word of FP_RES to d2 + movel 8(%a0),%d3 |move 3rd word of FP_RES to d3 + clrl 4(%a0) |zero word 2 of FP_RES + clrl 8(%a0) |zero word 3 of FP_RES + movel (%a0),%d0 |move exponent to d0 + swap %d0 |put exponent in lower word + beqs no_sft |if zero, don't shift + subil #0x3ffd,%d0 |sub bias less 2 to make fract + tstl %d0 |check if > 1 + bgts no_sft |if so, don't shift + negl %d0 |make exp positive +m_loop: + lsrl #1,%d2 |shift d2:d3 right, add 0s + roxrl #1,%d3 |the number of places + dbf %d0,m_loop |given in d0 +no_sft: + tstl %d2 |check for mantissa of zero + bnes no_zr |if not, go on + tstl %d3 |continue zero check + beqs zer_m |if zero, go directly to binstr +no_zr: + clrl %d1 |put zero in d1 for addx + addil #0x00000080,%d3 |inc at bit 7 + addxl %d1,%d2 |continue inc + andil #0xffffff80,%d3 |strip off lsb not used by 882 +zer_m: + movel %d4,%d0 |put LEN in d0 for binstr call + addql #3,%a0 |a0 points to M16 byte in result + bsr binstr |call binstr to convert mant + + +| A15. Convert the exponent to bcd. +| As in A14 above, the exp is converted to bcd and the +| digits are stored in the final string. +| +| Digits are stored in L_SCR1(a6) on return from BINDEC as: +| +| 32 16 15 0 +| ----------------------------------------- +| | 0 | e3 | e2 | e1 | e4 | X | X | X | +| ----------------------------------------- +| +| And are moved into their proper places in FP_SCR1. If digit e4 +| is non-zero, OPERR is signaled. In all cases, all 4 digits are +| written as specified in the 881/882 manual for packed decimal. +| +| Register usage: +| Input/Output +| d0: x/LEN call to binstr - final is 0 +| d1: x/scratch (0);shift count for final exponent packing +| d2: x/ms 32-bits of exp fraction/scratch +| d3: x/ls 32-bits of exp fraction +| d4: LEN/Unchanged +| d5: ICTR:LAMBDA/LAMBDA:ICTR +| d6: ILOG +| d7: k-factor/Unchanged +| a0: ptr to result string/ptr to L_SCR1(a6) +| a1: ptr to PTENxx array/Unchanged +| a2: ptr to FP_SCR2(a6)/Unchanged +| fp0: abs(YINT) adjusted/float(ILOG) +| fp1: 10^ISCALE/Unchanged +| fp2: 10^LEN/Unchanged +| F_SCR1:Work area for final result/BCD result +| F_SCR2:Y with original exponent/ILOG/10^4 +| L_SCR1:original USER_FPCR/Exponent digits on return from binstr +| L_SCR2:first word of X packed/Unchanged + +A15_st: + tstb BINDEC_FLG(%a6) |check for denorm + beqs not_denorm + ftstx %fp0 |test for zero + fbeq den_zero |if zero, use k-factor or 4933 + fmovel %d6,%fp0 |float ILOG + fabsx %fp0 |get abs of ILOG + bras convrt +den_zero: + tstl %d7 |check sign of the k-factor + blts use_ilog |if negative, use ILOG + fmoves F4933,%fp0 |force exponent to 4933 + bras convrt |do it +use_ilog: + fmovel %d6,%fp0 |float ILOG + fabsx %fp0 |get abs of ILOG + bras convrt +not_denorm: + ftstx %fp0 |test for zero + fbne not_zero |if zero, force exponent + fmoves FONE,%fp0 |force exponent to 1 + bras convrt |do it +not_zero: + fmovel %d6,%fp0 |float ILOG + fabsx %fp0 |get abs of ILOG +convrt: + fdivx 24(%a1),%fp0 |compute ILOG/10^4 + fmovex %fp0,FP_SCR2(%a6) |store fp0 in memory + movel 4(%a2),%d2 |move word 2 to d2 + movel 8(%a2),%d3 |move word 3 to d3 + movew (%a2),%d0 |move exp to d0 + beqs x_loop_fin |if zero, skip the shift + subiw #0x3ffd,%d0 |subtract off bias + negw %d0 |make exp positive +x_loop: + lsrl #1,%d2 |shift d2:d3 right + roxrl #1,%d3 |the number of places + dbf %d0,x_loop |given in d0 +x_loop_fin: + clrl %d1 |put zero in d1 for addx + addil #0x00000080,%d3 |inc at bit 6 + addxl %d1,%d2 |continue inc + andil #0xffffff80,%d3 |strip off lsb not used by 882 + movel #4,%d0 |put 4 in d0 for binstr call + leal L_SCR1(%a6),%a0 |a0 is ptr to L_SCR1 for exp digits + bsr binstr |call binstr to convert exp + movel L_SCR1(%a6),%d0 |load L_SCR1 lword to d0 + movel #12,%d1 |use d1 for shift count + lsrl %d1,%d0 |shift d0 right by 12 + bfins %d0,FP_SCR1(%a6){#4:#12} |put e3:e2:e1 in FP_SCR1 + lsrl %d1,%d0 |shift d0 right by 12 + bfins %d0,FP_SCR1(%a6){#16:#4} |put e4 in FP_SCR1 + tstb %d0 |check if e4 is zero + beqs A16_st |if zero, skip rest + orl #opaop_mask,USER_FPSR(%a6) |set OPERR & AIOP in USER_FPSR + + +| A16. Write sign bits to final string. +| Sigma is bit 31 of initial value; RHO is bit 31 of d6 (ILOG). +| +| Register usage: +| Input/Output +| d0: x/scratch - final is x +| d2: x/x +| d3: x/x +| d4: LEN/Unchanged +| d5: ICTR:LAMBDA/LAMBDA:ICTR +| d6: ILOG/ILOG adjusted +| d7: k-factor/Unchanged +| a0: ptr to L_SCR1(a6)/Unchanged +| a1: ptr to PTENxx array/Unchanged +| a2: ptr to FP_SCR2(a6)/Unchanged +| fp0: float(ILOG)/Unchanged +| fp1: 10^ISCALE/Unchanged +| fp2: 10^LEN/Unchanged +| F_SCR1:BCD result with correct signs +| F_SCR2:ILOG/10^4 +| L_SCR1:Exponent digits on return from binstr +| L_SCR2:first word of X packed/Unchanged + +A16_st: + clrl %d0 |clr d0 for collection of signs + andib #0x0f,FP_SCR1(%a6) |clear first nibble of FP_SCR1 + tstl L_SCR2(%a6) |check sign of original mantissa + bges mant_p |if pos, don't set SM + moveql #2,%d0 |move 2 in to d0 for SM +mant_p: + tstl %d6 |check sign of ILOG + bges wr_sgn |if pos, don't set SE + addql #1,%d0 |set bit 0 in d0 for SE +wr_sgn: + bfins %d0,FP_SCR1(%a6){#0:#2} |insert SM and SE into FP_SCR1 + +| Clean up and restore all registers used. + + fmovel #0,%FPSR |clear possible inex2/ainex bits + fmovemx (%a7)+,%fp0-%fp2 + moveml (%a7)+,%d2-%d7/%a2 + rts + + |end diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/binstr.S linux/arch/m68k/fpsp040/binstr.S --- v1.3.93/linux/arch/m68k/fpsp040/binstr.S Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/fpsp040/binstr.S Sat Feb 24 22:58:42 1996 @@ -0,0 +1,140 @@ +| +| binstr.sa 3.3 12/19/90 +| +| +| Description: Converts a 64-bit binary integer to bcd. +| +| Input: 64-bit binary integer in d2:d3, desired length (LEN) in +| d0, and a pointer to start in memory for bcd characters +| in d0. (This pointer must point to byte 4 of the first +| lword of the packed decimal memory string.) +| +| Output: LEN bcd digits representing the 64-bit integer. +| +| Algorithm: +| The 64-bit binary is assumed to have a decimal point before +| bit 63. The fraction is multiplied by 10 using a mul by 2 +| shift and a mul by 8 shift. The bits shifted out of the +| msb form a decimal digit. This process is iterated until +| LEN digits are formed. +| +| A1. Init d7 to 1. D7 is the byte digit counter, and if 1, the +| digit formed will be assumed the least significant. This is +| to force the first byte formed to have a 0 in the upper 4 bits. +| +| A2. Beginning of the loop: +| Copy the fraction in d2:d3 to d4:d5. +| +| A3. Multiply the fraction in d2:d3 by 8 using bit-field +| extracts and shifts. The three msbs from d2 will go into +| d1. +| +| A4. Multiply the fraction in d4:d5 by 2 using shifts. The msb +| will be collected by the carry. +| +| A5. Add using the carry the 64-bit quantities in d2:d3 and d4:d5 +| into d2:d3. D1 will contain the bcd digit formed. +| +| A6. Test d7. If zero, the digit formed is the ms digit. If non- +| zero, it is the ls digit. Put the digit in its place in the +| upper word of d0. If it is the ls digit, write the word +| from d0 to memory. +| +| A7. Decrement d6 (LEN counter) and repeat the loop until zero. +| +| Implementation Notes: +| +| The registers are used as follows: +| +| d0: LEN counter +| d1: temp used to form the digit +| d2: upper 32-bits of fraction for mul by 8 +| d3: lower 32-bits of fraction for mul by 8 +| d4: upper 32-bits of fraction for mul by 2 +| d5: lower 32-bits of fraction for mul by 2 +| d6: temp for bit-field extracts +| d7: byte digit formation word;digit count {0,1} +| a0: pointer into memory for packed bcd string formation +| + +| Copyright (C) Motorola, Inc. 1990 +| All Rights Reserved +| +| THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA +| The copyright notice above does not evidence any +| actual or intended publication of such source code. + +|BINSTR idnt 2,1 | Motorola 040 Floating Point Software Package + + |section 8 + + .include "fpsp.h" + + .global binstr +binstr: + moveml %d0-%d7,-(%a7) +| +| A1: Init d7 +| + moveql #1,%d7 |init d7 for second digit + subql #1,%d0 |for dbf d0 would have LEN+1 passes +| +| A2. Copy d2:d3 to d4:d5. Start loop. +| +loop: + movel %d2,%d4 |copy the fraction before muls + movel %d3,%d5 |to d4:d5 +| +| A3. Multiply d2:d3 by 8; extract msbs into d1. +| + bfextu %d2{#0:#3},%d1 |copy 3 msbs of d2 into d1 + asll #3,%d2 |shift d2 left by 3 places + bfextu %d3{#0:#3},%d6 |copy 3 msbs of d3 into d6 + asll #3,%d3 |shift d3 left by 3 places + orl %d6,%d2 |or in msbs from d3 into d2 +| +| A4. Multiply d4:d5 by 2; add carry out to d1. +| + asll #1,%d5 |mul d5 by 2 + roxll #1,%d4 |mul d4 by 2 + swap %d6 |put 0 in d6 lower word + addxw %d6,%d1 |add in extend from mul by 2 +| +| A5. Add mul by 8 to mul by 2. D1 contains the digit formed. +| + addl %d5,%d3 |add lower 32 bits + nop |ERRATA ; FIX #13 (Rev. 1.2 6/6/90) + addxl %d4,%d2 |add with extend upper 32 bits + nop |ERRATA ; FIX #13 (Rev. 1.2 6/6/90) + addxw %d6,%d1 |add in extend from add to d1 + swap %d6 |with d6 = 0; put 0 in upper word +| +| A6. Test d7 and branch. +| + tstw %d7 |if zero, store digit & to loop + beqs first_d |if non-zero, form byte & write +sec_d: + swap %d7 |bring first digit to word d7b + aslw #4,%d7 |first digit in upper 4 bits d7b + addw %d1,%d7 |add in ls digit to d7b + moveb %d7,(%a0)+ |store d7b byte in memory + swap %d7 |put LEN counter in word d7a + clrw %d7 |set d7a to signal no digits done + dbf %d0,loop |do loop some more! + bras end_bstr |finished, so exit +first_d: + swap %d7 |put digit word in d7b + movew %d1,%d7 |put new digit in d7b + swap %d7 |put LEN counter in word d7a + addqw #1,%d7 |set d7a to signal first digit done + dbf %d0,loop |do loop some more! + swap %d7 |put last digit in string + lslw #4,%d7 |move it to upper 4 bits + moveb %d7,(%a0)+ |store it in memory string +| +| Clean up and return with result in fp0. +| +end_bstr: + moveml (%a7)+,%d0-%d7 + rts + |end diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/bugfix.S linux/arch/m68k/fpsp040/bugfix.S --- v1.3.93/linux/arch/m68k/fpsp040/bugfix.S Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/fpsp040/bugfix.S Sat Feb 24 22:58:42 1996 @@ -0,0 +1,496 @@ +| +| bugfix.sa 3.2 1/31/91 +| +| +| This file contains workarounds for bugs in the 040 +| relating to the Floating-Point Software Package (FPSP) +| +| Fixes for bugs: 1238 +| +| Bug: 1238 +| +| +| /* The following dirty_bit clear should be left in +| * the handler permanently to improve throughput. +| * The dirty_bits are located at bits [23:16] in +| * longword $08 in the busy frame $4x60. Bit 16 +| * corresponds to FP0, bit 17 corresponds to FP1, +| * and so on. +| */ +| if (E3_exception_just_serviced) { +| dirty_bit[cmdreg3b[9:7]] = 0; +| } +| +| if (fsave_format_version != $40) {goto NOFIX} +| +| if !(E3_exception_just_serviced) {goto NOFIX} +| if (cupc == 0000000) {goto NOFIX} +| if ((cmdreg1b[15:13] != 000) && +| (cmdreg1b[15:10] != 010001)) {goto NOFIX} +| if (((cmdreg1b[15:13] != 000) || ((cmdreg1b[12:10] != cmdreg2b[9:7]) && +| (cmdreg1b[12:10] != cmdreg3b[9:7])) ) && +| ((cmdreg1b[ 9: 7] != cmdreg2b[9:7]) && +| (cmdreg1b[ 9: 7] != cmdreg3b[9:7])) ) {goto NOFIX} +| +| /* Note: for 6d43b or 8d43b, you may want to add the following code +| * to get better coverage. (If you do not insert this code, the part +| * won't lock up; it will simply get the wrong answer.) +| * Do NOT insert this code for 10d43b or later parts. +| * +| * if (fpiarcu == integer stack return address) { +| * cupc = 0000000; +| * goto NOFIX; +| * } +| */ +| +| if (cmdreg1b[15:13] != 000) {goto FIX_OPCLASS2} +| FIX_OPCLASS0: +| if (((cmdreg1b[12:10] == cmdreg2b[9:7]) || +| (cmdreg1b[ 9: 7] == cmdreg2b[9:7])) && +| (cmdreg1b[12:10] != cmdreg3b[9:7]) && +| (cmdreg1b[ 9: 7] != cmdreg3b[9:7])) { /* xu conflict only */ +| /* We execute the following code if there is an +| xu conflict and NOT an nu conflict */ +| +| /* first save some values on the fsave frame */ +| stag_temp = STAG[fsave_frame]; +| cmdreg1b_temp = CMDREG1B[fsave_frame]; +| dtag_temp = DTAG[fsave_frame]; +| ete15_temp = ETE15[fsave_frame]; +| +| CUPC[fsave_frame] = 0000000; +| FRESTORE +| FSAVE +| +| /* If the xu instruction is exceptional, we punt. +| * Otherwise, we would have to include OVFL/UNFL handler +| * code here to get the correct answer. +| */ +| if (fsave_frame_format == $4060) {goto KILL_PROCESS} +| +| fsave_frame = /* build a long frame of all zeros */ +| fsave_frame_format = $4060; /* label it as long frame */ +| +| /* load it with the temps we saved */ +| STAG[fsave_frame] = stag_temp; +| CMDREG1B[fsave_frame] = cmdreg1b_temp; +| DTAG[fsave_frame] = dtag_temp; +| ETE15[fsave_frame] = ete15_temp; +| +| /* Make sure that the cmdreg3b dest reg is not going to +| * be destroyed by a FMOVEM at the end of all this code. +| * If it is, you should move the current value of the reg +| * onto the stack so that the reg will loaded with that value. +| */ +| +| /* All done. Proceed with the code below */ +| } +| +| etemp = FP_reg_[cmdreg1b[12:10]]; +| ete15 = ~ete14; +| cmdreg1b[15:10] = 010010; +| clear(bug_flag_procIDxxxx); +| FRESTORE and return; +| +| +| FIX_OPCLASS2: +| if ((cmdreg1b[9:7] == cmdreg2b[9:7]) && +| (cmdreg1b[9:7] != cmdreg3b[9:7])) { /* xu conflict only */ +| /* We execute the following code if there is an +| xu conflict and NOT an nu conflict */ +| +| /* first save some values on the fsave frame */ +| stag_temp = STAG[fsave_frame]; +| cmdreg1b_temp = CMDREG1B[fsave_frame]; +| dtag_temp = DTAG[fsave_frame]; +| ete15_temp = ETE15[fsave_frame]; +| etemp_temp = ETEMP[fsave_frame]; +| +| CUPC[fsave_frame] = 0000000; +| FRESTORE +| FSAVE +| +| +| /* If the xu instruction is exceptional, we punt. +| * Otherwise, we would have to include OVFL/UNFL handler +| * code here to get the correct answer. +| */ +| if (fsave_frame_format == $4060) {goto KILL_PROCESS} +| +| fsave_frame = /* build a long frame of all zeros */ +| fsave_frame_format = $4060; /* label it as long frame */ +| +| /* load it with the temps we saved */ +| STAG[fsave_frame] = stag_temp; +| CMDREG1B[fsave_frame] = cmdreg1b_temp; +| DTAG[fsave_frame] = dtag_temp; +| ETE15[fsave_frame] = ete15_temp; +| ETEMP[fsave_frame] = etemp_temp; +| +| /* Make sure that the cmdreg3b dest reg is not going to +| * be destroyed by a FMOVEM at the end of all this code. +| * If it is, you should move the current value of the reg +| * onto the stack so that the reg will loaded with that value. +| */ +| +| /* All done. Proceed with the code below */ +| } +| +| if (etemp_exponent == min_sgl) etemp_exponent = min_dbl; +| if (etemp_exponent == max_sgl) etemp_exponent = max_dbl; +| cmdreg1b[15:10] = 010101; +| clear(bug_flag_procIDxxxx); +| FRESTORE and return; +| +| +| NOFIX: +| clear(bug_flag_procIDxxxx); +| FRESTORE and return; +| + + +| Copyright (C) Motorola, Inc. 1990 +| All Rights Reserved +| +| THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA +| The copyright notice above does not evidence any +| actual or intended publication of such source code. + +|BUGFIX idnt 2,1 | Motorola 040 Floating Point Software Package + + |section 8 + + .include "fpsp.h" + + |xref fpsp_fmt_error + + .global b1238_fix +b1238_fix: +| +| This code is entered only on completion of the handling of an +| nu-generated ovfl, unfl, or inex exception. If the version +| number of the fsave is not $40, this handler is not necessary. +| Simply branch to fix_done and exit normally. +| + cmpib #VER_40,4(%a7) + bne fix_done +| +| Test for cu_savepc equal to zero. If not, this is not a bug +| #1238 case. +| + moveb CU_SAVEPC(%a6),%d0 + andib #0xFE,%d0 + beq fix_done |if zero, this is not bug #1238 + +| +| Test the register conflict aspect. If opclass0, check for +| cu src equal to xu dest or equal to nu dest. If so, go to +| op0. Else, or if opclass2, check for cu dest equal to +| xu dest or equal to nu dest. If so, go to tst_opcl. Else, +| exit, it is not the bug case. +| +| Check for opclass 0. If not, go and check for opclass 2 and sgl. +| + movew CMDREG1B(%a6),%d0 + andiw #0xE000,%d0 |strip all but opclass + bne op2sgl |not opclass 0, check op2 +| +| Check for cu and nu register conflict. If one exists, this takes +| priority over a cu and xu conflict. +| + bfextu CMDREG1B(%a6){#3:#3},%d0 |get 1st src + bfextu CMDREG3B(%a6){#6:#3},%d1 |get 3rd dest + cmpb %d0,%d1 + beqs op0 |if equal, continue bugfix +| +| Check for cu dest equal to nu dest. If so, go and fix the +| bug condition. Otherwise, exit. +| + bfextu CMDREG1B(%a6){#6:#3},%d0 |get 1st dest + cmpb %d0,%d1 |cmp 1st dest with 3rd dest + beqs op0 |if equal, continue bugfix +| +| Check for cu and xu register conflict. +| + bfextu CMDREG2B(%a6){#6:#3},%d1 |get 2nd dest + cmpb %d0,%d1 |cmp 1st dest with 2nd dest + beqs op0_xu |if equal, continue bugfix + bfextu CMDREG1B(%a6){#3:#3},%d0 |get 1st src + cmpb %d0,%d1 |cmp 1st src with 2nd dest + beq op0_xu + bne fix_done |if the reg checks fail, exit +| +| We have the opclass 0 situation. +| +op0: + bfextu CMDREG1B(%a6){#3:#3},%d0 |get source register no + movel #7,%d1 + subl %d0,%d1 + clrl %d0 + bsetl %d1,%d0 + fmovemx %d0,ETEMP(%a6) |load source to ETEMP + + moveb #0x12,%d0 + bfins %d0,CMDREG1B(%a6){#0:#6} |opclass 2, extended +| +| Set ETEMP exponent bit 15 as the opposite of ete14 +| + btst #6,ETEMP_EX(%a6) |check etemp exponent bit 14 + beq setete15 + bclr #etemp15_bit,STAG(%a6) + bra finish +setete15: + bset #etemp15_bit,STAG(%a6) + bra finish + +| +| We have the case in which a conflict exists between the cu src or +| dest and the dest of the xu. We must clear the instruction in +| the cu and restore the state, allowing the instruction in the +| xu to complete. Remember, the instruction in the nu +| was exceptional, and was completed by the appropriate handler. +| If the result of the xu instruction is not exceptional, we can +| restore the instruction from the cu to the frame and continue +| processing the original exception. If the result is also +| exceptional, we choose to kill the process. +| +| Items saved from the stack: +| +| $3c stag - L_SCR1 +| $40 cmdreg1b - L_SCR2 +| $44 dtag - L_SCR3 +| +| The cu savepc is set to zero, and the frame is restored to the +| fpu. +| +op0_xu: + movel STAG(%a6),L_SCR1(%a6) + movel CMDREG1B(%a6),L_SCR2(%a6) + movel DTAG(%a6),L_SCR3(%a6) + andil #0xe0000000,L_SCR3(%a6) + moveb #0,CU_SAVEPC(%a6) + movel (%a7)+,%d1 |save return address from bsr + frestore (%a7)+ + fsave -(%a7) +| +| Check if the instruction which just completed was exceptional. +| + cmpw #0x4060,(%a7) + beq op0_xb +| +| It is necessary to isolate the result of the instruction in the +| xu if it is to fp0 - fp3 and write that value to the USER_FPn +| locations on the stack. The correct destination register is in +| cmdreg2b. +| + bfextu CMDREG2B(%a6){#6:#3},%d0 |get dest register no + cmpil #3,%d0 + bgts op0_xi + beqs op0_fp3 + cmpil #1,%d0 + blts op0_fp0 + beqs op0_fp1 +op0_fp2: + fmovemx %fp2-%fp2,USER_FP2(%a6) + bras op0_xi +op0_fp1: + fmovemx %fp1-%fp1,USER_FP1(%a6) + bras op0_xi +op0_fp0: + fmovemx %fp0-%fp0,USER_FP0(%a6) + bras op0_xi +op0_fp3: + fmovemx %fp3-%fp3,USER_FP3(%a6) +| +| The frame returned is idle. We must build a busy frame to hold +| the cu state information and setup etemp. +| +op0_xi: + movel #22,%d0 |clear 23 lwords + clrl (%a7) +op0_loop: + clrl -(%a7) + dbf %d0,op0_loop + movel #0x40600000,-(%a7) + movel L_SCR1(%a6),STAG(%a6) + movel L_SCR2(%a6),CMDREG1B(%a6) + movel L_SCR3(%a6),DTAG(%a6) + moveb #0x6,CU_SAVEPC(%a6) + movel %d1,-(%a7) |return bsr return address + bfextu CMDREG1B(%a6){#3:#3},%d0 |get source register no + movel #7,%d1 + subl %d0,%d1 + clrl %d0 + bsetl %d1,%d0 + fmovemx %d0,ETEMP(%a6) |load source to ETEMP + + moveb #0x12,%d0 + bfins %d0,CMDREG1B(%a6){#0:#6} |opclass 2, extended +| +| Set ETEMP exponent bit 15 as the opposite of ete14 +| + btst #6,ETEMP_EX(%a6) |check etemp exponent bit 14 + beq op0_sete15 + bclr #etemp15_bit,STAG(%a6) + bra finish +op0_sete15: + bset #etemp15_bit,STAG(%a6) + bra finish + +| +| The frame returned is busy. It is not possible to reconstruct +| the code sequence to allow completion. We will jump to +| fpsp_fmt_error and allow the kernel to kill the process. +| +op0_xb: + jmp fpsp_fmt_error + +| +| Check for opclass 2 and single size. If not both, exit. +| +op2sgl: + movew CMDREG1B(%a6),%d0 + andiw #0xFC00,%d0 |strip all but opclass and size + cmpiw #0x4400,%d0 |test for opclass 2 and size=sgl + bne fix_done |if not, it is not bug 1238 +| +| Check for cu dest equal to nu dest or equal to xu dest, with +| a cu and nu conflict taking priority an nu conflict. If either, +| go and fix the bug condition. Otherwise, exit. +| + bfextu CMDREG1B(%a6){#6:#3},%d0 |get 1st dest + bfextu CMDREG3B(%a6){#6:#3},%d1 |get 3rd dest + cmpb %d0,%d1 |cmp 1st dest with 3rd dest + beq op2_com |if equal, continue bugfix + bfextu CMDREG2B(%a6){#6:#3},%d1 |get 2nd dest + cmpb %d0,%d1 |cmp 1st dest with 2nd dest + bne fix_done |if the reg checks fail, exit +| +| We have the case in which a conflict exists between the cu src or +| dest and the dest of the xu. We must clear the instruction in +| the cu and restore the state, allowing the instruction in the +| xu to complete. Remember, the instruction in the nu +| was exceptional, and was completed by the appropriate handler. +| If the result of the xu instruction is not exceptional, we can +| restore the instruction from the cu to the frame and continue +| processing the original exception. If the result is also +| exceptional, we choose to kill the process. +| +| Items saved from the stack: +| +| $3c stag - L_SCR1 +| $40 cmdreg1b - L_SCR2 +| $44 dtag - L_SCR3 +| etemp - FP_SCR2 +| +| The cu savepc is set to zero, and the frame is restored to the +| fpu. +| +op2_xu: + movel STAG(%a6),L_SCR1(%a6) + movel CMDREG1B(%a6),L_SCR2(%a6) + movel DTAG(%a6),L_SCR3(%a6) + andil #0xe0000000,L_SCR3(%a6) + moveb #0,CU_SAVEPC(%a6) + movel ETEMP(%a6),FP_SCR2(%a6) + movel ETEMP_HI(%a6),FP_SCR2+4(%a6) + movel ETEMP_LO(%a6),FP_SCR2+8(%a6) + movel (%a7)+,%d1 |save return address from bsr + frestore (%a7)+ + fsave -(%a7) +| +| Check if the instruction which just completed was exceptional. +| + cmpw #0x4060,(%a7) + beq op2_xb +| +| It is necessary to isolate the result of the instruction in the +| xu if it is to fp0 - fp3 and write that value to the USER_FPn +| locations on the stack. The correct destination register is in +| cmdreg2b. +| + bfextu CMDREG2B(%a6){#6:#3},%d0 |get dest register no + cmpil #3,%d0 + bgts op2_xi + beqs op2_fp3 + cmpil #1,%d0 + blts op2_fp0 + beqs op2_fp1 +op2_fp2: + fmovemx %fp2-%fp2,USER_FP2(%a6) + bras op2_xi +op2_fp1: + fmovemx %fp1-%fp1,USER_FP1(%a6) + bras op2_xi +op2_fp0: + fmovemx %fp0-%fp0,USER_FP0(%a6) + bras op2_xi +op2_fp3: + fmovemx %fp3-%fp3,USER_FP3(%a6) +| +| The frame returned is idle. We must build a busy frame to hold +| the cu state information and fix up etemp. +| +op2_xi: + movel #22,%d0 |clear 23 lwords + clrl (%a7) +op2_loop: + clrl -(%a7) + dbf %d0,op2_loop + movel #0x40600000,-(%a7) + movel L_SCR1(%a6),STAG(%a6) + movel L_SCR2(%a6),CMDREG1B(%a6) + movel L_SCR3(%a6),DTAG(%a6) + moveb #0x6,CU_SAVEPC(%a6) + movel FP_SCR2(%a6),ETEMP(%a6) + movel FP_SCR2+4(%a6),ETEMP_HI(%a6) + movel FP_SCR2+8(%a6),ETEMP_LO(%a6) + movel %d1,-(%a7) + bra op2_com + +| +| We have the opclass 2 single source situation. +| +op2_com: + moveb #0x15,%d0 + bfins %d0,CMDREG1B(%a6){#0:#6} |opclass 2, double + + cmpw #0x407F,ETEMP_EX(%a6) |single +max + bnes case2 + movew #0x43FF,ETEMP_EX(%a6) |to double +max + bra finish +case2: + cmpw #0xC07F,ETEMP_EX(%a6) |single -max + bnes case3 + movew #0xC3FF,ETEMP_EX(%a6) |to double -max + bra finish +case3: + cmpw #0x3F80,ETEMP_EX(%a6) |single +min + bnes case4 + movew #0x3C00,ETEMP_EX(%a6) |to double +min + bra finish +case4: + cmpw #0xBF80,ETEMP_EX(%a6) |single -min + bne fix_done + movew #0xBC00,ETEMP_EX(%a6) |to double -min + bra finish +| +| The frame returned is busy. It is not possible to reconstruct +| the code sequence to allow completion. fpsp_fmt_error causes +| an fline illegal instruction to be executed. +| +| You should replace the jump to fpsp_fmt_error with a jump +| to the entry point used to kill a process. +| +op2_xb: + jmp fpsp_fmt_error + +| +| Enter here if the case is not of the situations affected by +| bug #1238, or if the fix is completed, and exit. +| +finish: +fix_done: + rts + + |end diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/decbin.S linux/arch/m68k/fpsp040/decbin.S --- v1.3.93/linux/arch/m68k/fpsp040/decbin.S Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/fpsp040/decbin.S Sat Feb 24 22:58:42 1996 @@ -0,0 +1,506 @@ +| +| decbin.sa 3.3 12/19/90 +| +| Description: Converts normalized packed bcd value pointed to by +| register A6 to extended-precision value in FP0. +| +| Input: Normalized packed bcd value in ETEMP(a6). +| +| Output: Exact floating-point representation of the packed bcd value. +| +| Saves and Modifies: D2-D5 +| +| Speed: The program decbin takes ??? cycles to execute. +| +| Object Size: +| +| External Reference(s): None. +| +| Algorithm: +| Expected is a normal bcd (i.e. non-exceptional; all inf, zero, +| and NaN operands are dispatched without entering this routine) +| value in 68881/882 format at location ETEMP(A6). +| +| A1. Convert the bcd exponent to binary by successive adds and muls. +| Set the sign according to SE. Subtract 16 to compensate +| for the mantissa which is to be interpreted as 17 integer +| digits, rather than 1 integer and 16 fraction digits. +| Note: this operation can never overflow. +| +| A2. Convert the bcd mantissa to binary by successive +| adds and muls in FP0. Set the sign according to SM. +| The mantissa digits will be converted with the decimal point +| assumed following the least-significant digit. +| Note: this operation can never overflow. +| +| A3. Count the number of leading/trailing zeros in the +| bcd string. If SE is positive, count the leading zeros; +| if negative, count the trailing zeros. Set the adjusted +| exponent equal to the exponent from A1 and the zero count +| added if SM = 1 and subtracted if SM = 0. Scale the +| mantissa the equivalent of forcing in the bcd value: +| +| SM = 0 a non-zero digit in the integer position +| SM = 1 a non-zero digit in Mant0, lsd of the fraction +| +| this will insure that any value, regardless of its +| representation (ex. 0.1E2, 1E1, 10E0, 100E-1), is converted +| consistently. +| +| A4. Calculate the factor 10^exp in FP1 using a table of +| 10^(2^n) values. To reduce the error in forming factors +| greater than 10^27, a directed rounding scheme is used with +| tables rounded to RN, RM, and RP, according to the table +| in the comments of the pwrten section. +| +| A5. Form the final binary number by scaling the mantissa by +| the exponent factor. This is done by multiplying the +| mantissa in FP0 by the factor in FP1 if the adjusted +| exponent sign is positive, and dividing FP0 by FP1 if +| it is negative. +| +| Clean up and return. Check if the final mul or div resulted +| in an inex2 exception. If so, set inex1 in the fpsr and +| check if the inex1 exception is enabled. If so, set d7 upper +| word to $0100. This will signal unimp.sa that an enabled inex1 +| exception occured. Unimp will fix the stack. +| + +| Copyright (C) Motorola, Inc. 1990 +| All Rights Reserved +| +| THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA +| The copyright notice above does not evidence any +| actual or intended publication of such source code. + +|DECBIN idnt 2,1 | Motorola 040 Floating Point Software Package + + |section 8 + + .include "fpsp.h" + +| +| PTENRN, PTENRM, and PTENRP are arrays of powers of 10 rounded +| to nearest, minus, and plus, respectively. The tables include +| 10**{1,2,4,8,16,32,64,128,256,512,1024,2048,4096}. No rounding +| is required until the power is greater than 27, however, all +| tables include the first 5 for ease of indexing. +| + |xref PTENRN + |xref PTENRM + |xref PTENRP + +RTABLE: .byte 0,0,0,0 + .byte 2,3,2,3 + .byte 2,3,3,2 + .byte 3,2,2,3 + + .global decbin + .global calc_e + .global pwrten + .global calc_m + .global norm + .global ap_st_z + .global ap_st_n +| + .set FNIBS,7 + .set FSTRT,0 +| + .set ESTRT,4 + .set EDIGITS,2 | +| +| Constants in single precision +FZERO: .long 0x00000000 +FONE: .long 0x3F800000 +FTEN: .long 0x41200000 + + .set TEN,10 + +| +decbin: + | fmovel #0,FPCR ;clr real fpcr + moveml %d2-%d5,-(%a7) +| +| Calculate exponent: +| 1. Copy bcd value in memory for use as a working copy. +| 2. Calculate absolute value of exponent in d1 by mul and add. +| 3. Correct for exponent sign. +| 4. Subtract 16 to compensate for interpreting the mant as all integer digits. +| (i.e., all digits assumed left of the decimal point.) +| +| Register usage: +| +| calc_e: +| (*) d0: temp digit storage +| (*) d1: accumulator for binary exponent +| (*) d2: digit count +| (*) d3: offset pointer +| ( ) d4: first word of bcd +| ( ) a0: pointer to working bcd value +| ( ) a6: pointer to original bcd value +| (*) FP_SCR1: working copy of original bcd value +| (*) L_SCR1: copy of original exponent word +| +calc_e: + movel #EDIGITS,%d2 |# of nibbles (digits) in fraction part + moveql #ESTRT,%d3 |counter to pick up digits + leal FP_SCR1(%a6),%a0 |load tmp bcd storage address + movel ETEMP(%a6),(%a0) |save input bcd value + movel ETEMP_HI(%a6),4(%a0) |save words 2 and 3 + movel ETEMP_LO(%a6),8(%a0) |and work with these + movel (%a0),%d4 |get first word of bcd + clrl %d1 |zero d1 for accumulator +e_gd: + mulul #TEN,%d1 |mul partial product by one digit place + bfextu %d4{%d3:#4},%d0 |get the digit and zero extend into d0 + addl %d0,%d1 |d1 = d1 + d0 + addqb #4,%d3 |advance d3 to the next digit + dbf %d2,e_gd |if we have used all 3 digits, exit loop + btst #30,%d4 |get SE + beqs e_pos |don't negate if pos + negl %d1 |negate before subtracting +e_pos: + subl #16,%d1 |sub to compensate for shift of mant + bges e_save |if still pos, do not neg + negl %d1 |now negative, make pos and set SE + orl #0x40000000,%d4 |set SE in d4, + orl #0x40000000,(%a0) |and in working bcd +e_save: + movel %d1,L_SCR1(%a6) |save exp in memory +| +| +| Calculate mantissa: +| 1. Calculate absolute value of mantissa in fp0 by mul and add. +| 2. Correct for mantissa sign. +| (i.e., all digits assumed left of the decimal point.) +| +| Register usage: +| +| calc_m: +| (*) d0: temp digit storage +| (*) d1: lword counter +| (*) d2: digit count +| (*) d3: offset pointer +| ( ) d4: words 2 and 3 of bcd +| ( ) a0: pointer to working bcd value +| ( ) a6: pointer to original bcd value +| (*) fp0: mantissa accumulator +| ( ) FP_SCR1: working copy of original bcd value +| ( ) L_SCR1: copy of original exponent word +| +calc_m: + moveql #1,%d1 |word counter, init to 1 + fmoves FZERO,%fp0 |accumulator +| +| +| Since the packed number has a long word between the first & second parts, +| get the integer digit then skip down & get the rest of the +| mantissa. We will unroll the loop once. +| + bfextu (%a0){#28:#4},%d0 |integer part is ls digit in long word + faddb %d0,%fp0 |add digit to sum in fp0 +| +| +| Get the rest of the mantissa. +| +loadlw: + movel (%a0,%d1.L*4),%d4 |load mantissa lonqword into d4 + moveql #FSTRT,%d3 |counter to pick up digits + moveql #FNIBS,%d2 |reset number of digits per a0 ptr +md2b: + fmuls FTEN,%fp0 |fp0 = fp0 * 10 + bfextu %d4{%d3:#4},%d0 |get the digit and zero extend + faddb %d0,%fp0 |fp0 = fp0 + digit +| +| +| If all the digits (8) in that long word have been converted (d2=0), +| then inc d1 (=2) to point to the next long word and reset d3 to 0 +| to initialize the digit offset, and set d2 to 7 for the digit count; +| else continue with this long word. +| + addqb #4,%d3 |advance d3 to the next digit + dbf %d2,md2b |check for last digit in this lw +nextlw: + addql #1,%d1 |inc lw pointer in mantissa + cmpl #2,%d1 |test for last lw + ble loadlw |if not, get last one + +| +| Check the sign of the mant and make the value in fp0 the same sign. +| +m_sign: + btst #31,(%a0) |test sign of the mantissa + beqs ap_st_z |if clear, go to append/strip zeros + fnegx %fp0 |if set, negate fp0 + +| +| Append/strip zeros: +| +| For adjusted exponents which have an absolute value greater than 27*, +| this routine calculates the amount needed to normalize the mantissa +| for the adjusted exponent. That number is subtracted from the exp +| if the exp was positive, and added if it was negative. The purpose +| of this is to reduce the value of the exponent and the possibility +| of error in calculation of pwrten. +| +| 1. Branch on the sign of the adjusted exponent. +| 2p.(positive exp) +| 2. Check M16 and the digits in lwords 2 and 3 in decending order. +| 3. Add one for each zero encountered until a non-zero digit. +| 4. Subtract the count from the exp. +| 5. Check if the exp has crossed zero in #3 above; make the exp abs +| and set SE. +| 6. Multiply the mantissa by 10**count. +| 2n.(negative exp) +| 2. Check the digits in lwords 3 and 2 in decending order. +| 3. Add one for each zero encountered until a non-zero digit. +| 4. Add the count to the exp. +| 5. Check if the exp has crossed zero in #3 above; clear SE. +| 6. Divide the mantissa by 10**count. +| +| *Why 27? If the adjusted exponent is within -28 < expA < 28, than +| any adjustment due to append/strip zeros will drive the resultane +| exponent towards zero. Since all pwrten constants with a power +| of 27 or less are exact, there is no need to use this routine to +| attempt to lessen the resultant exponent. +| +| Register usage: +| +| ap_st_z: +| (*) d0: temp digit storage +| (*) d1: zero count +| (*) d2: digit count +| (*) d3: offset pointer +| ( ) d4: first word of bcd +| (*) d5: lword counter +| ( ) a0: pointer to working bcd value +| ( ) FP_SCR1: working copy of original bcd value +| ( ) L_SCR1: copy of original exponent word +| +| +| First check the absolute value of the exponent to see if this +| routine is necessary. If so, then check the sign of the exponent +| and do append (+) or strip (-) zeros accordingly. +| This section handles a positive adjusted exponent. +| +ap_st_z: + movel L_SCR1(%a6),%d1 |load expA for range test + cmpl #27,%d1 |test is with 27 + ble pwrten |if abs(expA) <28, skip ap/st zeros + btst #30,(%a0) |check sign of exp + bnes ap_st_n |if neg, go to neg side + clrl %d1 |zero count reg + movel (%a0),%d4 |load lword 1 to d4 + bfextu %d4{#28:#4},%d0 |get M16 in d0 + bnes ap_p_fx |if M16 is non-zero, go fix exp + addql #1,%d1 |inc zero count + moveql #1,%d5 |init lword counter + movel (%a0,%d5.L*4),%d4 |get lword 2 to d4 + bnes ap_p_cl |if lw 2 is zero, skip it + addql #8,%d1 |and inc count by 8 + addql #1,%d5 |inc lword counter + movel (%a0,%d5.L*4),%d4 |get lword 3 to d4 +ap_p_cl: + clrl %d3 |init offset reg + moveql #7,%d2 |init digit counter +ap_p_gd: + bfextu %d4{%d3:#4},%d0 |get digit + bnes ap_p_fx |if non-zero, go to fix exp + addql #4,%d3 |point to next digit + addql #1,%d1 |inc digit counter + dbf %d2,ap_p_gd |get next digit +ap_p_fx: + movel %d1,%d0 |copy counter to d2 + movel L_SCR1(%a6),%d1 |get adjusted exp from memory + subl %d0,%d1 |subtract count from exp + bges ap_p_fm |if still pos, go to pwrten + negl %d1 |now its neg; get abs + movel (%a0),%d4 |load lword 1 to d4 + orl #0x40000000,%d4 | and set SE in d4 + orl #0x40000000,(%a0) | and in memory +| +| Calculate the mantissa multiplier to compensate for the striping of +| zeros from the mantissa. +| +ap_p_fm: + movel #PTENRN,%a1 |get address of power-of-ten table + clrl %d3 |init table index + fmoves FONE,%fp1 |init fp1 to 1 + moveql #3,%d2 |init d2 to count bits in counter +ap_p_el: + asrl #1,%d0 |shift lsb into carry + bccs ap_p_en |if 1, mul fp1 by pwrten factor + fmulx (%a1,%d3),%fp1 |mul by 10**(d3_bit_no) +ap_p_en: + addl #12,%d3 |inc d3 to next rtable entry + tstl %d0 |check if d0 is zero + bnes ap_p_el |if not, get next bit + fmulx %fp1,%fp0 |mul mantissa by 10**(no_bits_shifted) + bras pwrten |go calc pwrten +| +| This section handles a negative adjusted exponent. +| +ap_st_n: + clrl %d1 |clr counter + moveql #2,%d5 |set up d5 to point to lword 3 + movel (%a0,%d5.L*4),%d4 |get lword 3 + bnes ap_n_cl |if not zero, check digits + subl #1,%d5 |dec d5 to point to lword 2 + addql #8,%d1 |inc counter by 8 + movel (%a0,%d5.L*4),%d4 |get lword 2 +ap_n_cl: + movel #28,%d3 |point to last digit + moveql #7,%d2 |init digit counter +ap_n_gd: + bfextu %d4{%d3:#4},%d0 |get digit + bnes ap_n_fx |if non-zero, go to exp fix + subql #4,%d3 |point to previous digit + addql #1,%d1 |inc digit counter + dbf %d2,ap_n_gd |get next digit +ap_n_fx: + movel %d1,%d0 |copy counter to d0 + movel L_SCR1(%a6),%d1 |get adjusted exp from memory + subl %d0,%d1 |subtract count from exp + bgts ap_n_fm |if still pos, go fix mantissa + negl %d1 |take abs of exp and clr SE + movel (%a0),%d4 |load lword 1 to d4 + andl #0xbfffffff,%d4 | and clr SE in d4 + andl #0xbfffffff,(%a0) | and in memory +| +| Calculate the mantissa multiplier to compensate for the appending of +| zeros to the mantissa. +| +ap_n_fm: + movel #PTENRN,%a1 |get address of power-of-ten table + clrl %d3 |init table index + fmoves FONE,%fp1 |init fp1 to 1 + moveql #3,%d2 |init d2 to count bits in counter +ap_n_el: + asrl #1,%d0 |shift lsb into carry + bccs ap_n_en |if 1, mul fp1 by pwrten factor + fmulx (%a1,%d3),%fp1 |mul by 10**(d3_bit_no) +ap_n_en: + addl #12,%d3 |inc d3 to next rtable entry + tstl %d0 |check if d0 is zero + bnes ap_n_el |if not, get next bit + fdivx %fp1,%fp0 |div mantissa by 10**(no_bits_shifted) +| +| +| Calculate power-of-ten factor from adjusted and shifted exponent. +| +| Register usage: +| +| pwrten: +| (*) d0: temp +| ( ) d1: exponent +| (*) d2: {FPCR[6:5],SM,SE} as index in RTABLE; temp +| (*) d3: FPCR work copy +| ( ) d4: first word of bcd +| (*) a1: RTABLE pointer +| calc_p: +| (*) d0: temp +| ( ) d1: exponent +| (*) d3: PWRTxx table index +| ( ) a0: pointer to working copy of bcd +| (*) a1: PWRTxx pointer +| (*) fp1: power-of-ten accumulator +| +| Pwrten calculates the exponent factor in the selected rounding mode +| according to the following table: +| +| Sign of Mant Sign of Exp Rounding Mode PWRTEN Rounding Mode +| +| ANY ANY RN RN +| +| + + RP RP +| - + RP RM +| + - RP RM +| - - RP RP +| +| + + RM RM +| - + RM RP +| + - RM RP +| - - RM RM +| +| + + RZ RM +| - + RZ RM +| + - RZ RP +| - - RZ RP +| +| +pwrten: + movel USER_FPCR(%a6),%d3 |get user's FPCR + bfextu %d3{#26:#2},%d2 |isolate rounding mode bits + movel (%a0),%d4 |reload 1st bcd word to d4 + asll #2,%d2 |format d2 to be + bfextu %d4{#0:#2},%d0 | {FPCR[6],FPCR[5],SM,SE} + addl %d0,%d2 |in d2 as index into RTABLE + leal RTABLE,%a1 |load rtable base + moveb (%a1,%d2),%d0 |load new rounding bits from table + clrl %d3 |clear d3 to force no exc and extended + bfins %d0,%d3{#26:#2} |stuff new rounding bits in FPCR + fmovel %d3,%FPCR |write new FPCR + asrl #1,%d0 |write correct PTENxx table + bccs not_rp |to a1 + leal PTENRP,%a1 |it is RP + bras calc_p |go to init section +not_rp: + asrl #1,%d0 |keep checking + bccs not_rm + leal PTENRM,%a1 |it is RM + bras calc_p |go to init section +not_rm: + leal PTENRN,%a1 |it is RN +calc_p: + movel %d1,%d0 |copy exp to d0;use d0 + bpls no_neg |if exp is negative, + negl %d0 |invert it + orl #0x40000000,(%a0) |and set SE bit +no_neg: + clrl %d3 |table index + fmoves FONE,%fp1 |init fp1 to 1 +e_loop: + asrl #1,%d0 |shift next bit into carry + bccs e_next |if zero, skip the mul + fmulx (%a1,%d3),%fp1 |mul by 10**(d3_bit_no) +e_next: + addl #12,%d3 |inc d3 to next rtable entry + tstl %d0 |check if d0 is zero + bnes e_loop |not zero, continue shifting +| +| +| Check the sign of the adjusted exp and make the value in fp0 the +| same sign. If the exp was pos then multiply fp1*fp0; +| else divide fp0/fp1. +| +| Register Usage: +| norm: +| ( ) a0: pointer to working bcd value +| (*) fp0: mantissa accumulator +| ( ) fp1: scaling factor - 10**(abs(exp)) +| +norm: + btst #30,(%a0) |test the sign of the exponent + beqs mul |if clear, go to multiply +div: + fdivx %fp1,%fp0 |exp is negative, so divide mant by exp + bras end_dec +mul: + fmulx %fp1,%fp0 |exp is positive, so multiply by exp +| +| +| Clean up and return with result in fp0. +| +| If the final mul/div in decbin incurred an inex exception, +| it will be inex2, but will be reported as inex1 by get_op. +| +end_dec: + fmovel %FPSR,%d0 |get status register + bclrl #inex2_bit+8,%d0 |test for inex2 and clear it + fmovel %d0,%FPSR |return status reg w/o inex2 + beqs no_exc |skip this if no exc + orl #inx1a_mask,USER_FPSR(%a6) |set inex1/ainex +no_exc: + moveml (%a7)+,%d2-%d5 + rts + |end diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/do_func.S linux/arch/m68k/fpsp040/do_func.S --- v1.3.93/linux/arch/m68k/fpsp040/do_func.S Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/fpsp040/do_func.S Sat Feb 24 22:58:42 1996 @@ -0,0 +1,559 @@ +| +| do_func.sa 3.4 2/18/91 +| +| Do_func performs the unimplemented operation. The operation +| to be performed is determined from the lower 7 bits of the +| extension word (except in the case of fmovecr and fsincos). +| The opcode and tag bits form an index into a jump table in +| tbldo.sa. Cases of zero, infinity and NaN are handled in +| do_func by forcing the default result. Normalized and +| denormalized (there are no unnormalized numbers at this +| point) are passed onto the emulation code. +| +| CMDREG1B and STAG are extracted from the fsave frame +| and combined to form the table index. The function called +| will start with a0 pointing to the ETEMP operand. Dyadic +| functions can find FPTEMP at -12(a0). +| +| Called functions return their result in fp0. Sincos returns +| sin(x) in fp0 and cos(x) in fp1. +| + +| Copyright (C) Motorola, Inc. 1990 +| All Rights Reserved +| +| THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA +| The copyright notice above does not evidence any +| actual or intended publication of such source code. + +DO_FUNC: |idnt 2,1 | Motorola 040 Floating Point Software Package + + |section 8 + + .include "fpsp.h" + + |xref t_dz2 + |xref t_operr + |xref t_inx2 + |xref t_resdnrm + |xref dst_nan + |xref src_nan + |xref nrm_set + |xref sto_cos + + |xref tblpre + |xref slognp1,slogn,slog10,slog2 + |xref slognd,slog10d,slog2d + |xref smod,srem + |xref sscale + |xref smovcr + +PONE: .long 0x3fff0000,0x80000000,0x00000000 |+1 +MONE: .long 0xbfff0000,0x80000000,0x00000000 |-1 +PZERO: .long 0x00000000,0x00000000,0x00000000 |+0 +MZERO: .long 0x80000000,0x00000000,0x00000000 |-0 +PINF: .long 0x7fff0000,0x00000000,0x00000000 |+inf +MINF: .long 0xffff0000,0x00000000,0x00000000 |-inf +QNAN: .long 0x7fff0000,0xffffffff,0xffffffff |non-signaling nan +PPIBY2: .long 0x3FFF0000,0xC90FDAA2,0x2168C235 |+PI/2 +MPIBY2: .long 0xbFFF0000,0xC90FDAA2,0x2168C235 |-PI/2 + + .global do_func +do_func: + clrb CU_ONLY(%a6) +| +| Check for fmovecr. It does not follow the format of fp gen +| unimplemented instructions. The test is on the upper 6 bits; +| if they are $17, the inst is fmovecr. Call entry smovcr +| directly. +| + bfextu CMDREG1B(%a6){#0:#6},%d0 |get opclass and src fields + cmpil #0x17,%d0 |if op class and size fields are $17, +| ;it is FMOVECR; if not, continue + bnes not_fmovecr + jmp smovcr |fmovecr; jmp directly to emulation + +not_fmovecr: + movew CMDREG1B(%a6),%d0 + andl #0x7F,%d0 + cmpil #0x38,%d0 |if the extension is >= $38, + bges serror |it is illegal + bfextu STAG(%a6){#0:#3},%d1 + lsll #3,%d0 |make room for STAG + addl %d1,%d0 |combine for final index into table + leal tblpre,%a1 |start of monster jump table + movel (%a1,%d0.w*4),%a1 |real target address + leal ETEMP(%a6),%a0 |a0 is pointer to src op + movel USER_FPCR(%a6),%d1 + andl #0xFF,%d1 | discard all but rounding mode/prec + fmovel #0,%fpcr + jmp (%a1) +| +| ERROR +| + .global serror +serror: + st STORE_FLG(%a6) + rts +| +| These routines load forced values into fp0. They are called +| by index into tbldo. +| +| Load a signed zero to fp0 and set inex2/ainex +| + .global snzrinx +snzrinx: + btstb #sign_bit,LOCAL_EX(%a0) |get sign of source operand + bnes ld_mzinx |if negative, branch + bsr ld_pzero |bsr so we can return and set inx + bra t_inx2 |now, set the inx for the next inst +ld_mzinx: + bsr ld_mzero |if neg, load neg zero, return here + bra t_inx2 |now, set the inx for the next inst +| +| Load a signed zero to fp0; do not set inex2/ainex +| + .global szero +szero: + btstb #sign_bit,LOCAL_EX(%a0) |get sign of source operand + bne ld_mzero |if neg, load neg zero + bra ld_pzero |load positive zero +| +| Load a signed infinity to fp0; do not set inex2/ainex +| + .global sinf +sinf: + btstb #sign_bit,LOCAL_EX(%a0) |get sign of source operand + bne ld_minf |if negative branch + bra ld_pinf +| +| Load a signed one to fp0; do not set inex2/ainex +| + .global sone +sone: + btstb #sign_bit,LOCAL_EX(%a0) |check sign of source + bne ld_mone + bra ld_pone +| +| Load a signed pi/2 to fp0; do not set inex2/ainex +| + .global spi_2 +spi_2: + btstb #sign_bit,LOCAL_EX(%a0) |check sign of source + bne ld_mpi2 + bra ld_ppi2 +| +| Load either a +0 or +inf for plus/minus operand +| + .global szr_inf +szr_inf: + btstb #sign_bit,LOCAL_EX(%a0) |check sign of source + bne ld_pzero + bra ld_pinf +| +| Result is either an operr or +inf for plus/minus operand +| [Used by slogn, slognp1, slog10, and slog2] +| + .global sopr_inf +sopr_inf: + btstb #sign_bit,LOCAL_EX(%a0) |check sign of source + bne t_operr + bra ld_pinf +| +| FLOGNP1 +| + .global sslognp1 +sslognp1: + fmovemx (%a0),%fp0-%fp0 + fcmpb #-1,%fp0 + fbgt slognp1 + fbeq t_dz2 |if = -1, divide by zero exception + fmovel #0,%FPSR |clr N flag + bra t_operr |take care of operands < -1 +| +| FETOXM1 +| + .global setoxm1i +setoxm1i: + btstb #sign_bit,LOCAL_EX(%a0) |check sign of source + bne ld_mone + bra ld_pinf +| +| FLOGN +| +| Test for 1.0 as an input argument, returning +zero. Also check +| the sign and return operr if negative. +| + .global sslogn +sslogn: + btstb #sign_bit,LOCAL_EX(%a0) + bne t_operr |take care of operands < 0 + cmpiw #0x3fff,LOCAL_EX(%a0) |test for 1.0 input + bne slogn + cmpil #0x80000000,LOCAL_HI(%a0) + bne slogn + tstl LOCAL_LO(%a0) + bne slogn + fmovex PZERO,%fp0 + rts + + .global sslognd +sslognd: + btstb #sign_bit,LOCAL_EX(%a0) + beq slognd + bra t_operr |take care of operands < 0 + +| +| FLOG10 +| + .global sslog10 +sslog10: + btstb #sign_bit,LOCAL_EX(%a0) + bne t_operr |take care of operands < 0 + cmpiw #0x3fff,LOCAL_EX(%a0) |test for 1.0 input + bne slog10 + cmpil #0x80000000,LOCAL_HI(%a0) + bne slog10 + tstl LOCAL_LO(%a0) + bne slog10 + fmovex PZERO,%fp0 + rts + + .global sslog10d +sslog10d: + btstb #sign_bit,LOCAL_EX(%a0) + beq slog10d + bra t_operr |take care of operands < 0 + +| +| FLOG2 +| + .global sslog2 +sslog2: + btstb #sign_bit,LOCAL_EX(%a0) + bne t_operr |take care of operands < 0 + cmpiw #0x3fff,LOCAL_EX(%a0) |test for 1.0 input + bne slog2 + cmpil #0x80000000,LOCAL_HI(%a0) + bne slog2 + tstl LOCAL_LO(%a0) + bne slog2 + fmovex PZERO,%fp0 + rts + + .global sslog2d +sslog2d: + btstb #sign_bit,LOCAL_EX(%a0) + beq slog2d + bra t_operr |take care of operands < 0 + +| +| FMOD +| +pmodt: +| ;$21 fmod +| ;dtag,stag + .long smod | 00,00 norm,norm = normal + .long smod_oper | 00,01 norm,zero = nan with operr + .long smod_fpn | 00,10 norm,inf = fpn + .long smod_snan | 00,11 norm,nan = nan + .long smod_zro | 01,00 zero,norm = +-zero + .long smod_oper | 01,01 zero,zero = nan with operr + .long smod_zro | 01,10 zero,inf = +-zero + .long smod_snan | 01,11 zero,nan = nan + .long smod_oper | 10,00 inf,norm = nan with operr + .long smod_oper | 10,01 inf,zero = nan with operr + .long smod_oper | 10,10 inf,inf = nan with operr + .long smod_snan | 10,11 inf,nan = nan + .long smod_dnan | 11,00 nan,norm = nan + .long smod_dnan | 11,01 nan,zero = nan + .long smod_dnan | 11,10 nan,inf = nan + .long smod_dnan | 11,11 nan,nan = nan + + .global pmod +pmod: + clrb FPSR_QBYTE(%a6) | clear quotient field + bfextu STAG(%a6){#0:#3},%d0 |stag = d0 + bfextu DTAG(%a6){#0:#3},%d1 |dtag = d1 + +| +| Alias extended denorms to norms for the jump table. +| + bclrl #2,%d0 + bclrl #2,%d1 + + lslb #2,%d1 + orb %d0,%d1 |d1{3:2} = dtag, d1{1:0} = stag +| ;Tag values: +| ;00 = norm or denorm +| ;01 = zero +| ;10 = inf +| ;11 = nan + lea pmodt,%a1 + movel (%a1,%d1.w*4),%a1 + jmp (%a1) + +smod_snan: + bra src_nan +smod_dnan: + bra dst_nan +smod_oper: + bra t_operr +smod_zro: + moveb ETEMP(%a6),%d1 |get sign of src op + moveb FPTEMP(%a6),%d0 |get sign of dst op + eorb %d0,%d1 |get exor of sign bits + btstl #7,%d1 |test for sign + beqs smod_zsn |if clr, do not set sign big + bsetb #q_sn_bit,FPSR_QBYTE(%a6) |set q-byte sign bit +smod_zsn: + btstl #7,%d0 |test if + or - + beq ld_pzero |if pos then load +0 + bra ld_mzero |else neg load -0 + +smod_fpn: + moveb ETEMP(%a6),%d1 |get sign of src op + moveb FPTEMP(%a6),%d0 |get sign of dst op + eorb %d0,%d1 |get exor of sign bits + btstl #7,%d1 |test for sign + beqs smod_fsn |if clr, do not set sign big + bsetb #q_sn_bit,FPSR_QBYTE(%a6) |set q-byte sign bit +smod_fsn: + tstb DTAG(%a6) |filter out denormal destination case + bpls smod_nrm | + leal FPTEMP(%a6),%a0 |a0<- addr(FPTEMP) + bra t_resdnrm |force UNFL(but exact) result +smod_nrm: + fmovel USER_FPCR(%a6),%fpcr |use user's rmode and precision + fmovex FPTEMP(%a6),%fp0 |return dest to fp0 + rts + +| +| FREM +| +premt: +| ;$25 frem +| ;dtag,stag + .long srem | 00,00 norm,norm = normal + .long srem_oper | 00,01 norm,zero = nan with operr + .long srem_fpn | 00,10 norm,inf = fpn + .long srem_snan | 00,11 norm,nan = nan + .long srem_zro | 01,00 zero,norm = +-zero + .long srem_oper | 01,01 zero,zero = nan with operr + .long srem_zro | 01,10 zero,inf = +-zero + .long srem_snan | 01,11 zero,nan = nan + .long srem_oper | 10,00 inf,norm = nan with operr + .long srem_oper | 10,01 inf,zero = nan with operr + .long srem_oper | 10,10 inf,inf = nan with operr + .long srem_snan | 10,11 inf,nan = nan + .long srem_dnan | 11,00 nan,norm = nan + .long srem_dnan | 11,01 nan,zero = nan + .long srem_dnan | 11,10 nan,inf = nan + .long srem_dnan | 11,11 nan,nan = nan + + .global prem +prem: + clrb FPSR_QBYTE(%a6) |clear quotient field + bfextu STAG(%a6){#0:#3},%d0 |stag = d0 + bfextu DTAG(%a6){#0:#3},%d1 |dtag = d1 +| +| Alias extended denorms to norms for the jump table. +| + bclr #2,%d0 + bclr #2,%d1 + + lslb #2,%d1 + orb %d0,%d1 |d1{3:2} = dtag, d1{1:0} = stag +| ;Tag values: +| ;00 = norm or denorm +| ;01 = zero +| ;10 = inf +| ;11 = nan + lea premt,%a1 + movel (%a1,%d1.w*4),%a1 + jmp (%a1) + +srem_snan: + bra src_nan +srem_dnan: + bra dst_nan +srem_oper: + bra t_operr +srem_zro: + moveb ETEMP(%a6),%d1 |get sign of src op + moveb FPTEMP(%a6),%d0 |get sign of dst op + eorb %d0,%d1 |get exor of sign bits + btstl #7,%d1 |test for sign + beqs srem_zsn |if clr, do not set sign big + bsetb #q_sn_bit,FPSR_QBYTE(%a6) |set q-byte sign bit +srem_zsn: + btstl #7,%d0 |test if + or - + beq ld_pzero |if pos then load +0 + bra ld_mzero |else neg load -0 + +srem_fpn: + moveb ETEMP(%a6),%d1 |get sign of src op + moveb FPTEMP(%a6),%d0 |get sign of dst op + eorb %d0,%d1 |get exor of sign bits + btstl #7,%d1 |test for sign + beqs srem_fsn |if clr, do not set sign big + bsetb #q_sn_bit,FPSR_QBYTE(%a6) |set q-byte sign bit +srem_fsn: + tstb DTAG(%a6) |filter out denormal destination case + bpls srem_nrm | + leal FPTEMP(%a6),%a0 |a0<- addr(FPTEMP) + bra t_resdnrm |force UNFL(but exact) result +srem_nrm: + fmovel USER_FPCR(%a6),%fpcr |use user's rmode and precision + fmovex FPTEMP(%a6),%fp0 |return dest to fp0 + rts +| +| FSCALE +| +pscalet: +| ;$26 fscale +| ;dtag,stag + .long sscale | 00,00 norm,norm = result + .long sscale | 00,01 norm,zero = fpn + .long scl_opr | 00,10 norm,inf = nan with operr + .long scl_snan | 00,11 norm,nan = nan + .long scl_zro | 01,00 zero,norm = +-zero + .long scl_zro | 01,01 zero,zero = +-zero + .long scl_opr | 01,10 zero,inf = nan with operr + .long scl_snan | 01,11 zero,nan = nan + .long scl_inf | 10,00 inf,norm = +-inf + .long scl_inf | 10,01 inf,zero = +-inf + .long scl_opr | 10,10 inf,inf = nan with operr + .long scl_snan | 10,11 inf,nan = nan + .long scl_dnan | 11,00 nan,norm = nan + .long scl_dnan | 11,01 nan,zero = nan + .long scl_dnan | 11,10 nan,inf = nan + .long scl_dnan | 11,11 nan,nan = nan + + .global pscale +pscale: + bfextu STAG(%a6){#0:#3},%d0 |stag in d0 + bfextu DTAG(%a6){#0:#3},%d1 |dtag in d1 + bclrl #2,%d0 |alias denorm into norm + bclrl #2,%d1 |alias denorm into norm + lslb #2,%d1 + orb %d0,%d1 |d1{4:2} = dtag, d1{1:0} = stag +| ;dtag values stag values: +| ;000 = norm 00 = norm +| ;001 = zero 01 = zero +| ;010 = inf 10 = inf +| ;011 = nan 11 = nan +| ;100 = dnrm +| +| + leal pscalet,%a1 |load start of jump table + movel (%a1,%d1.w*4),%a1 |load a1 with label depending on tag + jmp (%a1) |go to the routine + +scl_opr: + bra t_operr + +scl_dnan: + bra dst_nan + +scl_zro: + btstb #sign_bit,FPTEMP_EX(%a6) |test if + or - + beq ld_pzero |if pos then load +0 + bra ld_mzero |if neg then load -0 +scl_inf: + btstb #sign_bit,FPTEMP_EX(%a6) |test if + or - + beq ld_pinf |if pos then load +inf + bra ld_minf |else neg load -inf +scl_snan: + bra src_nan +| +| FSINCOS +| + .global ssincosz +ssincosz: + btstb #sign_bit,ETEMP(%a6) |get sign + beqs sincosp + fmovex MZERO,%fp0 + bras sincoscom +sincosp: + fmovex PZERO,%fp0 +sincoscom: + fmovemx PONE,%fp1-%fp1 |do not allow FPSR to be affected + bra sto_cos |store cosine result + + .global ssincosi +ssincosi: + fmovex QNAN,%fp1 |load NAN + bsr sto_cos |store cosine result + fmovex QNAN,%fp0 |load NAN + bra t_operr + + .global ssincosnan +ssincosnan: + movel ETEMP_EX(%a6),FP_SCR1(%a6) + movel ETEMP_HI(%a6),FP_SCR1+4(%a6) + movel ETEMP_LO(%a6),FP_SCR1+8(%a6) + bsetb #signan_bit,FP_SCR1+4(%a6) + fmovemx FP_SCR1(%a6),%fp1-%fp1 + bsr sto_cos + bra src_nan +| +| This code forces default values for the zero, inf, and nan cases +| in the transcendentals code. The CC bits must be set in the +| stacked FPSR to be correctly reported. +| +|**Returns +PI/2 + .global ld_ppi2 +ld_ppi2: + fmovex PPIBY2,%fp0 |load +pi/2 + bra t_inx2 |set inex2 exc + +|**Returns -PI/2 + .global ld_mpi2 +ld_mpi2: + fmovex MPIBY2,%fp0 |load -pi/2 + orl #neg_mask,USER_FPSR(%a6) |set N bit + bra t_inx2 |set inex2 exc + +|**Returns +inf + .global ld_pinf +ld_pinf: + fmovex PINF,%fp0 |load +inf + orl #inf_mask,USER_FPSR(%a6) |set I bit + rts + +|**Returns -inf + .global ld_minf +ld_minf: + fmovex MINF,%fp0 |load -inf + orl #neg_mask+inf_mask,USER_FPSR(%a6) |set N and I bits + rts + +|**Returns +1 + .global ld_pone +ld_pone: + fmovex PONE,%fp0 |load +1 + rts + +|**Returns -1 + .global ld_mone +ld_mone: + fmovex MONE,%fp0 |load -1 + orl #neg_mask,USER_FPSR(%a6) |set N bit + rts + +|**Returns +0 + .global ld_pzero +ld_pzero: + fmovex PZERO,%fp0 |load +0 + orl #z_mask,USER_FPSR(%a6) |set Z bit + rts + +|**Returns -0 + .global ld_mzero +ld_mzero: + fmovex MZERO,%fp0 |load -0 + orl #neg_mask+z_mask,USER_FPSR(%a6) |set N and Z bits + rts + + |end diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/fpsp.h linux/arch/m68k/fpsp040/fpsp.h --- v1.3.93/linux/arch/m68k/fpsp040/fpsp.h Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/fpsp040/fpsp.h Wed Dec 27 22:44:57 1995 @@ -0,0 +1,348 @@ +| +| fpsp.h 3.3 3.3 +| + +| Copyright (C) Motorola, Inc. 1990 +| All Rights Reserved +| +| THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA +| The copyright notice above does not evidence any +| actual or intended publication of such source code. + +| fpsp.h --- stack frame offsets during FPSP exception handling +| +| These equates are used to access the exception frame, the fsave +| frame and any local variables needed by the FPSP package. +| +| All FPSP handlers begin by executing: +| +| link a6,#-LOCAL_SIZE +| fsave -(a7) +| movem.l d0-d1/a0-a1,USER_DA(a6) +| fmovem.x fp0-fp3,USER_FP0(a6) +| fmove.l fpsr/fpcr/fpiar,USER_FPSR(a6) +| +| After initialization, the stack looks like this: +| +| A7 ---> +-------------------------------+ +| | | +| | FPU fsave area | +| | | +| +-------------------------------+ +| | | +| | FPSP Local Variables | +| | including | +| | saved registers | +| | | +| +-------------------------------+ +| A6 ---> | Saved A6 | +| +-------------------------------+ +| | | +| | Exception Frame | +| | | +| | | +| +| Positive offsets from A6 refer to the exception frame. Negative +| offsets refer to the Local Variable area and the fsave area. +| The fsave frame is also accessible from the top via A7. +| +| On exit, the handlers execute: +| +| movem.l USER_DA(a6),d0-d1/a0-a1 +| fmovem.x USER_FP0(a6),fp0-fp3 +| fmove.l USER_FPSR(a6),fpsr/fpcr/fpiar +| frestore (a7)+ +| unlk a6 +| +| and then either "bra fpsp_done" if the exception was completely +| handled by the package, or "bra real_xxxx" which is an external +| label to a routine that will process a real exception of the +| type that was generated. Some handlers may omit the "frestore" +| if the FPU state after the exception is idle. +| +| Sometimes the exception handler will transform the fsave area +| because it needs to report an exception back to the user. This +| can happen if the package is entered for an unimplemented float +| instruction that generates (say) an underflow. Alternatively, +| a second fsave frame can be pushed onto the stack and the +| handler exit code will reload the new frame and discard the old. +| +| The registers d0, d1, a0, a1 and fp0-fp3 are always saved and +| restored from the "local variable" area and can be used as +| temporaries. If a routine needs to change any +| of these registers, it should modify the saved copy and let +| the handler exit code restore the value. +| +|---------------------------------------------------------------------- +| +| Local Variables on the stack +| + .set LOCAL_SIZE,192 | bytes needed for local variables + .set LV,-LOCAL_SIZE | convenient base value +| + .set USER_DA,LV+0 | save space for D0-D1,A0-A1 + .set USER_D0,LV+0 | saved user D0 + .set USER_D1,LV+4 | saved user D1 + .set USER_A0,LV+8 | saved user A0 + .set USER_A1,LV+12 | saved user A1 + .set USER_FP0,LV+16 | saved user FP0 + .set USER_FP1,LV+28 | saved user FP1 + .set USER_FP2,LV+40 | saved user FP2 + .set USER_FP3,LV+52 | saved user FP3 + .set USER_FPCR,LV+64 | saved user FPCR + .set FPCR_ENABLE,USER_FPCR+2 | FPCR exception enable + .set FPCR_MODE,USER_FPCR+3 | FPCR rounding mode control + .set USER_FPSR,LV+68 | saved user FPSR + .set FPSR_CC,USER_FPSR+0 | FPSR condition code + .set FPSR_QBYTE,USER_FPSR+1 | FPSR quotient + .set FPSR_EXCEPT,USER_FPSR+2 | FPSR exception + .set FPSR_AEXCEPT,USER_FPSR+3 | FPSR accrued exception + .set USER_FPIAR,LV+72 | saved user FPIAR + .set FP_SCR1,LV+76 | room for a temporary float value + .set FP_SCR2,LV+92 | room for a temporary float value + .set L_SCR1,LV+108 | room for a temporary long value + .set L_SCR2,LV+112 | room for a temporary long value + .set STORE_FLG,LV+116 + .set BINDEC_FLG,LV+117 | used in bindec + .set DNRM_FLG,LV+118 | used in res_func + .set RES_FLG,LV+119 | used in res_func + .set DY_MO_FLG,LV+120 | dyadic/monadic flag + .set UFLG_TMP,LV+121 | temporary for uflag errata + .set CU_ONLY,LV+122 | cu-only flag + .set VER_TMP,LV+123 | temp holding for version number + .set L_SCR3,LV+124 | room for a temporary long value + .set FP_SCR3,LV+128 | room for a temporary float value + .set FP_SCR4,LV+144 | room for a temporary float value + .set FP_SCR5,LV+160 | room for a temporary float value + .set FP_SCR6,LV+176 +| +|NEXT equ LV+192 ;need to increase LOCAL_SIZE +| +|-------------------------------------------------------------------------- +| +| fsave offsets and bit definitions +| +| Offsets are defined from the end of an fsave because the last 10 +| words of a busy frame are the same as the unimplemented frame. +| + .set CU_SAVEPC,LV-92 | micro-pc for CU (1 byte) + .set FPR_DIRTY_BITS,LV-91 | fpr dirty bits +| + .set WBTEMP,LV-76 | write back temp (12 bytes) + .set WBTEMP_EX,WBTEMP | wbtemp sign and exponent (2 bytes) + .set WBTEMP_HI,WBTEMP+4 | wbtemp mantissa [63:32] (4 bytes) + .set WBTEMP_LO,WBTEMP+8 | wbtemp mantissa [31:00] (4 bytes) +| + .set WBTEMP_SGN,WBTEMP+2 | used to store sign +| + .set FPSR_SHADOW,LV-64 | fpsr shadow reg +| + .set FPIARCU,LV-60 | Instr. addr. reg. for CU (4 bytes) +| + .set CMDREG2B,LV-52 | cmd reg for machine 2 + .set CMDREG3B,LV-48 | cmd reg for E3 exceptions (2 bytes) +| + .set NMNEXC,LV-44 | NMNEXC (unsup,snan bits only) + .set nmn_unsup_bit,1 | + .set nmn_snan_bit,0 | +| + .set NMCEXC,LV-43 | NMNEXC & NMCEXC + .set nmn_operr_bit,7 + .set nmn_ovfl_bit,6 + .set nmn_unfl_bit,5 + .set nmc_unsup_bit,4 + .set nmc_snan_bit,3 + .set nmc_operr_bit,2 + .set nmc_ovfl_bit,1 + .set nmc_unfl_bit,0 +| + .set STAG,LV-40 | source tag (1 byte) + .set WBTEMP_GRS,LV-40 | alias wbtemp guard, round, sticky + .set guard_bit,1 | guard bit is bit number 1 + .set round_bit,0 | round bit is bit number 0 + .set stag_mask,0xE0 | upper 3 bits are source tag type + .set denorm_bit,7 | bit determins if denorm or unnorm + .set etemp15_bit,4 | etemp exponent bit #15 + .set wbtemp66_bit,2 | wbtemp mantissa bit #66 + .set wbtemp1_bit,1 | wbtemp mantissa bit #1 + .set wbtemp0_bit,0 | wbtemp mantissa bit #0 +| + .set STICKY,LV-39 | holds sticky bit + .set sticky_bit,7 +| + .set CMDREG1B,LV-36 | cmd reg for E1 exceptions (2 bytes) + .set kfact_bit,12 | distinguishes static/dynamic k-factor +| ;on packed move outs. NOTE: this +| ;equate only works when CMDREG1B is in +| ;a register. +| + .set CMDWORD,LV-35 | command word in cmd1b + .set direction_bit,5 | bit 0 in opclass + .set size_bit2,12 | bit 2 in size field +| + .set DTAG,LV-32 | dest tag (1 byte) + .set dtag_mask,0xE0 | upper 3 bits are dest type tag + .set fptemp15_bit,4 | fptemp exponent bit #15 +| + .set WB_BYTE,LV-31 | holds WBTE15 bit (1 byte) + .set wbtemp15_bit,4 | wbtemp exponent bit #15 +| + .set E_BYTE,LV-28 | holds E1 and E3 bits (1 byte) + .set E1,2 | which bit is E1 flag + .set E3,1 | which bit is E3 flag + .set SFLAG,0 | which bit is S flag +| + .set T_BYTE,LV-27 | holds T and U bits (1 byte) + .set XFLAG,7 | which bit is X flag + .set UFLAG,5 | which bit is U flag + .set TFLAG,4 | which bit is T flag +| + .set FPTEMP,LV-24 | fptemp (12 bytes) + .set FPTEMP_EX,FPTEMP | fptemp sign and exponent (2 bytes) + .set FPTEMP_HI,FPTEMP+4 | fptemp mantissa [63:32] (4 bytes) + .set FPTEMP_LO,FPTEMP+8 | fptemp mantissa [31:00] (4 bytes) +| + .set FPTEMP_SGN,FPTEMP+2 | used to store sign +| + .set ETEMP,LV-12 | etemp (12 bytes) + .set ETEMP_EX,ETEMP | etemp sign and exponent (2 bytes) + .set ETEMP_HI,ETEMP+4 | etemp mantissa [63:32] (4 bytes) + .set ETEMP_LO,ETEMP+8 | etemp mantissa [31:00] (4 bytes) +| + .set ETEMP_SGN,ETEMP+2 | used to store sign +| + .set EXC_SR,4 | exception frame status register + .set EXC_PC,6 | exception frame program counter + .set EXC_VEC,10 | exception frame vector (format+vector#) + .set EXC_EA,12 | exception frame effective address +| +|-------------------------------------------------------------------------- +| +| FPSR/FPCR bits +| + .set neg_bit,3 | negative result + .set z_bit,2 | zero result + .set inf_bit,1 | infinity result + .set nan_bit,0 | not-a-number result +| + .set q_sn_bit,7 | sign bit of quotient byte +| + .set bsun_bit,7 | branch on unordered + .set snan_bit,6 | signalling nan + .set operr_bit,5 | operand error + .set ovfl_bit,4 | overflow + .set unfl_bit,3 | underflow + .set dz_bit,2 | divide by zero + .set inex2_bit,1 | inexact result 2 + .set inex1_bit,0 | inexact result 1 +| + .set aiop_bit,7 | accrued illegal operation + .set aovfl_bit,6 | accrued overflow + .set aunfl_bit,5 | accrued underflow + .set adz_bit,4 | accrued divide by zero + .set ainex_bit,3 | accrued inexact +| +| FPSR individual bit masks +| + .set neg_mask,0x08000000 + .set z_mask,0x04000000 + .set inf_mask,0x02000000 + .set nan_mask,0x01000000 +| + .set bsun_mask,0x00008000 | + .set snan_mask,0x00004000 + .set operr_mask,0x00002000 + .set ovfl_mask,0x00001000 + .set unfl_mask,0x00000800 + .set dz_mask,0x00000400 + .set inex2_mask,0x00000200 + .set inex1_mask,0x00000100 +| + .set aiop_mask,0x00000080 | accrued illegal operation + .set aovfl_mask,0x00000040 | accrued overflow + .set aunfl_mask,0x00000020 | accrued underflow + .set adz_mask,0x00000010 | accrued divide by zero + .set ainex_mask,0x00000008 | accrued inexact +| +| FPSR combinations used in the FPSP +| + .set dzinf_mask,inf_mask+dz_mask+adz_mask + .set opnan_mask,nan_mask+operr_mask+aiop_mask + .set nzi_mask,0x01ffffff | clears N, Z, and I + .set unfinx_mask,unfl_mask+inex2_mask+aunfl_mask+ainex_mask + .set unf2inx_mask,unfl_mask+inex2_mask+ainex_mask + .set ovfinx_mask,ovfl_mask+inex2_mask+aovfl_mask+ainex_mask + .set inx1a_mask,inex1_mask+ainex_mask + .set inx2a_mask,inex2_mask+ainex_mask + .set snaniop_mask,nan_mask+snan_mask+aiop_mask + .set naniop_mask,nan_mask+aiop_mask + .set neginf_mask,neg_mask+inf_mask + .set infaiop_mask,inf_mask+aiop_mask + .set negz_mask,neg_mask+z_mask + .set opaop_mask,operr_mask+aiop_mask + .set unfl_inx_mask,unfl_mask+aunfl_mask+ainex_mask + .set ovfl_inx_mask,ovfl_mask+aovfl_mask+ainex_mask +| +|-------------------------------------------------------------------------- +| +| FPCR rounding modes +| + .set x_mode,0x00 | round to extended + .set s_mode,0x40 | round to single + .set d_mode,0x80 | round to double +| + .set rn_mode,0x00 | round nearest + .set rz_mode,0x10 | round to zero + .set rm_mode,0x20 | round to minus infinity + .set rp_mode,0x30 | round to plus infinity +| +|-------------------------------------------------------------------------- +| +| Miscellaneous equates +| + .set signan_bit,6 | signalling nan bit in mantissa + .set sign_bit,7 +| + .set rnd_stky_bit,29 | round/sticky bit of mantissa +| this can only be used if in a data register + .set sx_mask,0x01800000 | set s and x bits in word $48 +| + .set LOCAL_EX,0 + .set LOCAL_SGN,2 + .set LOCAL_HI,4 + .set LOCAL_LO,8 + .set LOCAL_GRS,12 | valid ONLY for FP_SCR1, FP_SCR2 +| +| + .set norm_tag,0x00 | tag bits in {7:5} position + .set zero_tag,0x20 + .set inf_tag,0x40 + .set nan_tag,0x60 + .set dnrm_tag,0x80 +| +| fsave sizes and formats +| + .set VER_4,0x40 | fpsp compatible version numbers +| are in the $40s {$40-$4f} + .set VER_40,0x40 | original version number + .set VER_41,0x41 | revision version number +| + .set BUSY_SIZE,100 | size of busy frame + .set BUSY_FRAME,LV-BUSY_SIZE | start of busy frame +| + .set UNIMP_40_SIZE,44 | size of orig unimp frame + .set UNIMP_41_SIZE,52 | size of rev unimp frame +| + .set IDLE_SIZE,4 | size of idle frame + .set IDLE_FRAME,LV-IDLE_SIZE | start of idle frame +| +| exception vectors +| + .set TRACE_VEC,0x2024 | trace trap + .set FLINE_VEC,0x002C | real F-line + .set UNIMP_VEC,0x202C | unimplemented + .set INEX_VEC,0x00C4 +| + .set dbl_thresh,0x3C01 + .set sgl_thresh,0x3F81 +| diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/gen_except.S linux/arch/m68k/fpsp040/gen_except.S --- v1.3.93/linux/arch/m68k/fpsp040/gen_except.S Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/fpsp040/gen_except.S Sat Feb 24 22:58:43 1996 @@ -0,0 +1,468 @@ +| +| gen_except.sa 3.7 1/16/92 +| +| gen_except --- FPSP routine to detect reportable exceptions +| +| This routine compares the exception enable byte of the +| user_fpcr on the stack with the exception status byte +| of the user_fpsr. +| +| Any routine which may report an exceptions must load +| the stack frame in memory with the exceptional operand(s). +| +| Priority for exceptions is: +| +| Highest: bsun +| snan +| operr +| ovfl +| unfl +| dz +| inex2 +| Lowest: inex1 +| +| Note: The IEEE standard specifies that inex2 is to be +| reported if ovfl occurs and the ovfl enable bit is not +| set but the inex2 enable bit is. +| +| +| Copyright (C) Motorola, Inc. 1990 +| All Rights Reserved +| +| THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA +| The copyright notice above does not evidence any +| actual or intended publication of such source code. + +GEN_EXCEPT: |idnt 2,1 | Motorola 040 Floating Point Software Package + + |section 8 + + .include "fpsp.h" + + |xref real_trace + |xref fpsp_done + |xref fpsp_fmt_error + +exc_tbl: + .long bsun_exc + .long commonE1 + .long commonE1 + .long ovfl_unfl + .long ovfl_unfl + .long commonE1 + .long commonE3 + .long commonE3 + .long no_match + + .global gen_except +gen_except: + cmpib #IDLE_SIZE-4,1(%a7) |test for idle frame + beq do_check |go handle idle frame + cmpib #UNIMP_40_SIZE-4,1(%a7) |test for orig unimp frame + beqs unimp_x |go handle unimp frame + cmpib #UNIMP_41_SIZE-4,1(%a7) |test for rev unimp frame + beqs unimp_x |go handle unimp frame + cmpib #BUSY_SIZE-4,1(%a7) |if size <> $60, fmt error + bnel fpsp_fmt_error + leal BUSY_SIZE+LOCAL_SIZE(%a7),%a1 |init a1 so fpsp.h +| ;equates will work +| Fix up the new busy frame with entries from the unimp frame +| + movel ETEMP_EX(%a6),ETEMP_EX(%a1) |copy etemp from unimp + movel ETEMP_HI(%a6),ETEMP_HI(%a1) |frame to busy frame + movel ETEMP_LO(%a6),ETEMP_LO(%a1) + movel CMDREG1B(%a6),CMDREG1B(%a1) |set inst in frame to unimp + movel CMDREG1B(%a6),%d0 |fix cmd1b to make it + andl #0x03c30000,%d0 |work for cmd3b + bfextu CMDREG1B(%a6){#13:#1},%d1 |extract bit 2 + lsll #5,%d1 + swap %d1 + orl %d1,%d0 |put it in the right place + bfextu CMDREG1B(%a6){#10:#3},%d1 |extract bit 3,4,5 + lsll #2,%d1 + swap %d1 + orl %d1,%d0 |put them in the right place + movel %d0,CMDREG3B(%a1) |in the busy frame +| +| Or in the FPSR from the emulation with the USER_FPSR on the stack. +| + fmovel %FPSR,%d0 + orl %d0,USER_FPSR(%a6) + movel USER_FPSR(%a6),FPSR_SHADOW(%a1) |set exc bits + orl #sx_mask,E_BYTE(%a1) + bra do_clean + +| +| Frame is an unimp frame possible resulting from an fmove ,fp0 +| that caused an exception +| +| a1 is modified to point into the new frame allowing fpsp equates +| to be valid. +| +unimp_x: + cmpib #UNIMP_40_SIZE-4,1(%a7) |test for orig unimp frame + bnes test_rev + leal UNIMP_40_SIZE+LOCAL_SIZE(%a7),%a1 + bras unimp_con +test_rev: + cmpib #UNIMP_41_SIZE-4,1(%a7) |test for rev unimp frame + bnel fpsp_fmt_error |if not $28 or $30 + leal UNIMP_41_SIZE+LOCAL_SIZE(%a7),%a1 + +unimp_con: +| +| Fix up the new unimp frame with entries from the old unimp frame +| + movel CMDREG1B(%a6),CMDREG1B(%a1) |set inst in frame to unimp +| +| Or in the FPSR from the emulation with the USER_FPSR on the stack. +| + fmovel %FPSR,%d0 + orl %d0,USER_FPSR(%a6) + bra do_clean + +| +| Frame is idle, so check for exceptions reported through +| USER_FPSR and set the unimp frame accordingly. +| A7 must be incremented to the point before the +| idle fsave vector to the unimp vector. +| + +do_check: + addl #4,%a7 |point A7 back to unimp frame +| +| Or in the FPSR from the emulation with the USER_FPSR on the stack. +| + fmovel %FPSR,%d0 + orl %d0,USER_FPSR(%a6) +| +| On a busy frame, we must clear the nmnexc bits. +| + cmpib #BUSY_SIZE-4,1(%a7) |check frame type + bnes check_fr |if busy, clr nmnexc + clrw NMNEXC(%a6) |clr nmnexc & nmcexc + btstb #5,CMDREG1B(%a6) |test for fmove out + bnes frame_com + movel USER_FPSR(%a6),FPSR_SHADOW(%a6) |set exc bits + orl #sx_mask,E_BYTE(%a6) + bras frame_com +check_fr: + cmpb #UNIMP_40_SIZE-4,1(%a7) + beqs frame_com + clrw NMNEXC(%a6) +frame_com: + moveb FPCR_ENABLE(%a6),%d0 |get fpcr enable byte + andb FPSR_EXCEPT(%a6),%d0 |and in the fpsr exc byte + bfffo %d0{#24:#8},%d1 |test for first set bit + leal exc_tbl,%a0 |load jmp table address + subib #24,%d1 |normalize bit offset to 0-8 + movel (%a0,%d1.w*4),%a0 |load routine address based +| ;based on first enabled exc + jmp (%a0) |jump to routine +| +| Bsun is not possible in unimp or unsupp +| +bsun_exc: + bra do_clean +| +| The typical work to be done to the unimp frame to report an +| exception is to set the E1/E3 byte and clr the U flag. +| commonE1 does this for E1 exceptions, which are snan, +| operr, and dz. commonE3 does this for E3 exceptions, which +| are inex2 and inex1, and also clears the E1 exception bit +| left over from the unimp exception. +| +commonE1: + bsetb #E1,E_BYTE(%a6) |set E1 flag + bra commonE |go clean and exit + +commonE3: + tstb UFLG_TMP(%a6) |test flag for unsup/unimp state + bnes unsE3 +uniE3: + bsetb #E3,E_BYTE(%a6) |set E3 flag + bclrb #E1,E_BYTE(%a6) |clr E1 from unimp + bra commonE + +unsE3: + tstb RES_FLG(%a6) + bnes unsE3_0 +unsE3_1: + bsetb #E3,E_BYTE(%a6) |set E3 flag +unsE3_0: + bclrb #E1,E_BYTE(%a6) |clr E1 flag + movel CMDREG1B(%a6),%d0 + andl #0x03c30000,%d0 |work for cmd3b + bfextu CMDREG1B(%a6){#13:#1},%d1 |extract bit 2 + lsll #5,%d1 + swap %d1 + orl %d1,%d0 |put it in the right place + bfextu CMDREG1B(%a6){#10:#3},%d1 |extract bit 3,4,5 + lsll #2,%d1 + swap %d1 + orl %d1,%d0 |put them in the right place + movel %d0,CMDREG3B(%a6) |in the busy frame + +commonE: + bclrb #UFLAG,T_BYTE(%a6) |clr U flag from unimp + bra do_clean |go clean and exit +| +| No bits in the enable byte match existing exceptions. Check for +| the case of the ovfl exc without the ovfl enabled, but with +| inex2 enabled. +| +no_match: + btstb #inex2_bit,FPCR_ENABLE(%a6) |check for ovfl/inex2 case + beqs no_exc |if clear, exit + btstb #ovfl_bit,FPSR_EXCEPT(%a6) |now check ovfl + beqs no_exc |if clear, exit + bras ovfl_unfl |go to unfl_ovfl to determine if +| ;it is an unsupp or unimp exc + +| No exceptions are to be reported. If the instruction was +| unimplemented, no FPU restore is necessary. If it was +| unsupported, we must perform the restore. +no_exc: + tstb UFLG_TMP(%a6) |test flag for unsupp/unimp state + beqs uni_no_exc +uns_no_exc: + tstb RES_FLG(%a6) |check if frestore is needed + bne do_clean |if clear, no frestore needed +uni_no_exc: + moveml USER_DA(%a6),%d0-%d1/%a0-%a1 + fmovemx USER_FP0(%a6),%fp0-%fp3 + fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar + unlk %a6 + bra finish_up +| +| Unsupported Data Type Handler: +| Ovfl: +| An fmoveout that results in an overflow is reported this way. +| Unfl: +| An fmoveout that results in an underflow is reported this way. +| +| Unimplemented Instruction Handler: +| Ovfl: +| Only scosh, setox, ssinh, stwotox, and scale can set overflow in +| this manner. +| Unfl: +| Stwotox, setox, and scale can set underflow in this manner. +| Any of the other Library Routines such that f(x)=x in which +| x is an extended denorm can report an underflow exception. +| It is the responsibility of the exception-causing exception +| to make sure that WBTEMP is correct. +| +| The exceptional operand is in FP_SCR1. +| +ovfl_unfl: + tstb UFLG_TMP(%a6) |test flag for unsupp/unimp state + beqs ofuf_con +| +| The caller was from an unsupported data type trap. Test if the +| caller set CU_ONLY. If so, the exceptional operand is expected in +| FPTEMP, rather than WBTEMP. +| + tstb CU_ONLY(%a6) |test if inst is cu-only + beq unsE3 +| move.w #$fe,CU_SAVEPC(%a6) + clrb CU_SAVEPC(%a6) + bsetb #E1,E_BYTE(%a6) |set E1 exception flag + movew ETEMP_EX(%a6),FPTEMP_EX(%a6) + movel ETEMP_HI(%a6),FPTEMP_HI(%a6) + movel ETEMP_LO(%a6),FPTEMP_LO(%a6) + bsetb #fptemp15_bit,DTAG(%a6) |set fpte15 + bclrb #UFLAG,T_BYTE(%a6) |clr U flag from unimp + bra do_clean |go clean and exit + +ofuf_con: + moveb (%a7),VER_TMP(%a6) |save version number + cmpib #BUSY_SIZE-4,1(%a7) |check for busy frame + beqs busy_fr |if unimp, grow to busy + cmpib #VER_40,(%a7) |test for orig unimp frame + bnes try_41 |if not, test for rev frame + moveql #13,%d0 |need to zero 14 lwords + bras ofuf_fin +try_41: + cmpib #VER_41,(%a7) |test for rev unimp frame + bnel fpsp_fmt_error |if neither, exit with error + moveql #11,%d0 |need to zero 12 lwords + +ofuf_fin: + clrl (%a7) +loop1: + clrl -(%a7) |clear and dec a7 + dbra %d0,loop1 + moveb VER_TMP(%a6),(%a7) + moveb #BUSY_SIZE-4,1(%a7) |write busy fmt word. +busy_fr: + movel FP_SCR1(%a6),WBTEMP_EX(%a6) |write + movel FP_SCR1+4(%a6),WBTEMP_HI(%a6) |execptional op to + movel FP_SCR1+8(%a6),WBTEMP_LO(%a6) |wbtemp + bsetb #E3,E_BYTE(%a6) |set E3 flag + bclrb #E1,E_BYTE(%a6) |make sure E1 is clear + bclrb #UFLAG,T_BYTE(%a6) |clr U flag + movel USER_FPSR(%a6),FPSR_SHADOW(%a6) + orl #sx_mask,E_BYTE(%a6) + movel CMDREG1B(%a6),%d0 |fix cmd1b to make it + andl #0x03c30000,%d0 |work for cmd3b + bfextu CMDREG1B(%a6){#13:#1},%d1 |extract bit 2 + lsll #5,%d1 + swap %d1 + orl %d1,%d0 |put it in the right place + bfextu CMDREG1B(%a6){#10:#3},%d1 |extract bit 3,4,5 + lsll #2,%d1 + swap %d1 + orl %d1,%d0 |put them in the right place + movel %d0,CMDREG3B(%a6) |in the busy frame + +| +| Check if the frame to be restored is busy or unimp. +|** NOTE *** Bug fix for errata (0d43b #3) +| If the frame is unimp, we must create a busy frame to +| fix the bug with the nmnexc bits in cases in which they +| are set by a previous instruction and not cleared by +| the save. The frame will be unimp only if the final +| instruction in an emulation routine caused the exception +| by doing an fmove ,fp0. The exception operand, in +| internal format, is in fptemp. +| +do_clean: + cmpib #UNIMP_40_SIZE-4,1(%a7) + bnes do_con + moveql #13,%d0 |in orig, need to zero 14 lwords + bras do_build +do_con: + cmpib #UNIMP_41_SIZE-4,1(%a7) + bnes do_restore |frame must be busy + moveql #11,%d0 |in rev, need to zero 12 lwords + +do_build: + moveb (%a7),VER_TMP(%a6) + clrl (%a7) +loop2: + clrl -(%a7) |clear and dec a7 + dbra %d0,loop2 +| +| Use a1 as pointer into new frame. a6 is not correct if an unimp or +| busy frame was created as the result of an exception on the final +| instruction of an emulation routine. +| +| We need to set the nmcexc bits if the exception is E1. Otherwise, +| the exc taken will be inex2. +| + leal BUSY_SIZE+LOCAL_SIZE(%a7),%a1 |init a1 for new frame + moveb VER_TMP(%a6),(%a7) |write busy fmt word + moveb #BUSY_SIZE-4,1(%a7) + movel FP_SCR1(%a6),WBTEMP_EX(%a1) |write + movel FP_SCR1+4(%a6),WBTEMP_HI(%a1) |exceptional op to + movel FP_SCR1+8(%a6),WBTEMP_LO(%a1) |wbtemp +| btst.b #E1,E_BYTE(%a1) +| beq.b do_restore + bfextu USER_FPSR(%a6){#17:#4},%d0 |get snan/operr/ovfl/unfl bits + bfins %d0,NMCEXC(%a1){#4:#4} |and insert them in nmcexc + movel USER_FPSR(%a6),FPSR_SHADOW(%a1) |set exc bits + orl #sx_mask,E_BYTE(%a1) + +do_restore: + moveml USER_DA(%a6),%d0-%d1/%a0-%a1 + fmovemx USER_FP0(%a6),%fp0-%fp3 + fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar + frestore (%a7)+ + tstb RES_FLG(%a6) |RES_FLG indicates a "continuation" frame + beq cont + bsr bug1384 +cont: + unlk %a6 +| +| If trace mode enabled, then go to trace handler. This handler +| cannot have any fp instructions. If there are fp inst's and an +| exception has been restored into the machine then the exception +| will occur upon execution of the fp inst. This is not desirable +| in the kernel (supervisor mode). See MC68040 manual Section 9.3.8. +| +finish_up: + btstb #7,(%a7) |test T1 in SR + bnes g_trace + btstb #6,(%a7) |test T0 in SR + bnes g_trace + bral fpsp_done +| +| Change integer stack to look like trace stack +| The address of the instruction that caused the +| exception is already in the integer stack (is +| the same as the saved friar) +| +| If the current frame is already a 6-word stack then all +| that needs to be done is to change the vector# to TRACE. +| If the frame is only a 4-word stack (meaning we got here +| on an Unsupported data type exception), then we need to grow +| the stack an extra 2 words and get the FPIAR from the FPU. +| +g_trace: + bftst EXC_VEC-4(%sp){#0:#4} + bne g_easy + + subw #4,%sp | make room + movel 4(%sp),(%sp) + movel 8(%sp),4(%sp) + subw #BUSY_SIZE,%sp + fsave (%sp) + fmovel %fpiar,BUSY_SIZE+EXC_EA-4(%sp) + frestore (%sp) + addw #BUSY_SIZE,%sp + +g_easy: + movew #TRACE_VEC,EXC_VEC-4(%a7) + bral real_trace +| +| This is a work-around for hardware bug 1384. +| +bug1384: + link %a5,#0 + fsave -(%sp) + cmpib #0x41,(%sp) | check for correct frame + beq frame_41 + bgt nofix | if more advanced mask, do nada + +frame_40: + tstb 1(%sp) | check to see if idle + bne notidle +idle40: + clrl (%sp) | get rid of old fsave frame + movel %d1,USER_D1(%a6) | save d1 + movew #8,%d1 | place unimp frame instead +loop40: clrl -(%sp) + dbra %d1,loop40 + movel USER_D1(%a6),%d1 | restore d1 + movel #0x40280000,-(%sp) + frestore (%sp)+ + unlk %a5 + rts + +frame_41: + tstb 1(%sp) | check to see if idle + bne notidle +idle41: + clrl (%sp) | get rid of old fsave frame + movel %d1,USER_D1(%a6) | save d1 + movew #10,%d1 | place unimp frame instead +loop41: clrl -(%sp) + dbra %d1,loop41 + movel USER_D1(%a6),%d1 | restore d1 + movel #0x41300000,-(%sp) + frestore (%sp)+ + unlk %a5 + rts + +notidle: + bclrb #etemp15_bit,-40(%a5) + frestore (%sp)+ + unlk %a5 + rts + +nofix: + frestore (%sp)+ + unlk %a5 + rts + + |end diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/get_op.S linux/arch/m68k/fpsp040/get_op.S --- v1.3.93/linux/arch/m68k/fpsp040/get_op.S Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/fpsp040/get_op.S Sat Feb 24 22:58:43 1996 @@ -0,0 +1,676 @@ +| +| get_op.sa 3.6 5/19/92 +| +| get_op.sa 3.5 4/26/91 +| +| Description: This routine is called by the unsupported format/data +| type exception handler ('unsupp' - vector 55) and the unimplemented +| instruction exception handler ('unimp' - vector 11). 'get_op' +| determines the opclass (0, 2, or 3) and branches to the +| opclass handler routine. See 68881/2 User's Manual table 4-11 +| for a description of the opclasses. +| +| For UNSUPPORTED data/format (exception vector 55) and for +| UNIMPLEMENTED instructions (exception vector 11) the following +| applies: +| +| - For unnormormalized numbers (opclass 0, 2, or 3) the +| number(s) is normalized and the operand type tag is updated. +| +| - For a packed number (opclass 2) the number is unpacked and the +| operand type tag is updated. +| +| - For denormalized numbers (opclass 0 or 2) the number(s) is not +| changed but passed to the next module. The next module for +| unimp is do_func, the next module for unsupp is res_func. +| +| For UNSUPPORTED data/format (exception vector 55) only the +| following applies: +| +| - If there is a move out with a packed number (opclass 3) the +| number is packed and written to user memory. For the other +| opclasses the number(s) are written back to the fsave stack +| and the instruction is then restored back into the '040. The +| '040 is then able to complete the instruction. +| +| For example: +| fadd.x fpm,fpn where the fpm contains an unnormalized number. +| The '040 takes an unsupported data trap and gets to this +| routine. The number is normalized, put back on the stack and +| then an frestore is done to restore the instruction back into +| the '040. The '040 then re-executes the fadd.x fpm,fpn with +| a normalized number in the source and the instruction is +| successful. +| +| Next consider if in the process of normalizing the un- +| normalized number it becomes a denormalized number. The +| routine which converts the unnorm to a norm (called mk_norm) +| detects this and tags the number as a denorm. The routine +| res_func sees the denorm tag and converts the denorm to a +| norm. The instruction is then restored back into the '040 +| which re_executess the instruction. +| +| +| Copyright (C) Motorola, Inc. 1990 +| All Rights Reserved +| +| THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA +| The copyright notice above does not evidence any +| actual or intended publication of such source code. + +GET_OP: |idnt 2,1 | Motorola 040 Floating Point Software Package + + |section 8 + + .include "fpsp.h" + + .global PIRN,PIRZRM,PIRP + .global SMALRN,SMALRZRM,SMALRP + .global BIGRN,BIGRZRM,BIGRP + +PIRN: + .long 0x40000000,0xc90fdaa2,0x2168c235 |pi +PIRZRM: + .long 0x40000000,0xc90fdaa2,0x2168c234 |pi +PIRP: + .long 0x40000000,0xc90fdaa2,0x2168c235 |pi + +|round to nearest +SMALRN: + .long 0x3ffd0000,0x9a209a84,0xfbcff798 |log10(2) + .long 0x40000000,0xadf85458,0xa2bb4a9a |e + .long 0x3fff0000,0xb8aa3b29,0x5c17f0bc |log2(e) + .long 0x3ffd0000,0xde5bd8a9,0x37287195 |log10(e) + .long 0x00000000,0x00000000,0x00000000 |0.0 +| round to zero;round to negative infinity +SMALRZRM: + .long 0x3ffd0000,0x9a209a84,0xfbcff798 |log10(2) + .long 0x40000000,0xadf85458,0xa2bb4a9a |e + .long 0x3fff0000,0xb8aa3b29,0x5c17f0bb |log2(e) + .long 0x3ffd0000,0xde5bd8a9,0x37287195 |log10(e) + .long 0x00000000,0x00000000,0x00000000 |0.0 +| round to positive infinity +SMALRP: + .long 0x3ffd0000,0x9a209a84,0xfbcff799 |log10(2) + .long 0x40000000,0xadf85458,0xa2bb4a9b |e + .long 0x3fff0000,0xb8aa3b29,0x5c17f0bc |log2(e) + .long 0x3ffd0000,0xde5bd8a9,0x37287195 |log10(e) + .long 0x00000000,0x00000000,0x00000000 |0.0 + +|round to nearest +BIGRN: + .long 0x3ffe0000,0xb17217f7,0xd1cf79ac |ln(2) + .long 0x40000000,0x935d8ddd,0xaaa8ac17 |ln(10) + .long 0x3fff0000,0x80000000,0x00000000 |10 ^ 0 + + .global PTENRN +PTENRN: + .long 0x40020000,0xA0000000,0x00000000 |10 ^ 1 + .long 0x40050000,0xC8000000,0x00000000 |10 ^ 2 + .long 0x400C0000,0x9C400000,0x00000000 |10 ^ 4 + .long 0x40190000,0xBEBC2000,0x00000000 |10 ^ 8 + .long 0x40340000,0x8E1BC9BF,0x04000000 |10 ^ 16 + .long 0x40690000,0x9DC5ADA8,0x2B70B59E |10 ^ 32 + .long 0x40D30000,0xC2781F49,0xFFCFA6D5 |10 ^ 64 + .long 0x41A80000,0x93BA47C9,0x80E98CE0 |10 ^ 128 + .long 0x43510000,0xAA7EEBFB,0x9DF9DE8E |10 ^ 256 + .long 0x46A30000,0xE319A0AE,0xA60E91C7 |10 ^ 512 + .long 0x4D480000,0xC9767586,0x81750C17 |10 ^ 1024 + .long 0x5A920000,0x9E8B3B5D,0xC53D5DE5 |10 ^ 2048 + .long 0x75250000,0xC4605202,0x8A20979B |10 ^ 4096 +|round to minus infinity +BIGRZRM: + .long 0x3ffe0000,0xb17217f7,0xd1cf79ab |ln(2) + .long 0x40000000,0x935d8ddd,0xaaa8ac16 |ln(10) + .long 0x3fff0000,0x80000000,0x00000000 |10 ^ 0 + + .global PTENRM +PTENRM: + .long 0x40020000,0xA0000000,0x00000000 |10 ^ 1 + .long 0x40050000,0xC8000000,0x00000000 |10 ^ 2 + .long 0x400C0000,0x9C400000,0x00000000 |10 ^ 4 + .long 0x40190000,0xBEBC2000,0x00000000 |10 ^ 8 + .long 0x40340000,0x8E1BC9BF,0x04000000 |10 ^ 16 + .long 0x40690000,0x9DC5ADA8,0x2B70B59D |10 ^ 32 + .long 0x40D30000,0xC2781F49,0xFFCFA6D5 |10 ^ 64 + .long 0x41A80000,0x93BA47C9,0x80E98CDF |10 ^ 128 + .long 0x43510000,0xAA7EEBFB,0x9DF9DE8D |10 ^ 256 + .long 0x46A30000,0xE319A0AE,0xA60E91C6 |10 ^ 512 + .long 0x4D480000,0xC9767586,0x81750C17 |10 ^ 1024 + .long 0x5A920000,0x9E8B3B5D,0xC53D5DE5 |10 ^ 2048 + .long 0x75250000,0xC4605202,0x8A20979A |10 ^ 4096 +|round to positive infinity +BIGRP: + .long 0x3ffe0000,0xb17217f7,0xd1cf79ac |ln(2) + .long 0x40000000,0x935d8ddd,0xaaa8ac17 |ln(10) + .long 0x3fff0000,0x80000000,0x00000000 |10 ^ 0 + + .global PTENRP +PTENRP: + .long 0x40020000,0xA0000000,0x00000000 |10 ^ 1 + .long 0x40050000,0xC8000000,0x00000000 |10 ^ 2 + .long 0x400C0000,0x9C400000,0x00000000 |10 ^ 4 + .long 0x40190000,0xBEBC2000,0x00000000 |10 ^ 8 + .long 0x40340000,0x8E1BC9BF,0x04000000 |10 ^ 16 + .long 0x40690000,0x9DC5ADA8,0x2B70B59E |10 ^ 32 + .long 0x40D30000,0xC2781F49,0xFFCFA6D6 |10 ^ 64 + .long 0x41A80000,0x93BA47C9,0x80E98CE0 |10 ^ 128 + .long 0x43510000,0xAA7EEBFB,0x9DF9DE8E |10 ^ 256 + .long 0x46A30000,0xE319A0AE,0xA60E91C7 |10 ^ 512 + .long 0x4D480000,0xC9767586,0x81750C18 |10 ^ 1024 + .long 0x5A920000,0x9E8B3B5D,0xC53D5DE6 |10 ^ 2048 + .long 0x75250000,0xC4605202,0x8A20979B |10 ^ 4096 + + |xref nrm_zero + |xref decbin + |xref round + + .global get_op + .global uns_getop + .global uni_getop +get_op: + clrb DY_MO_FLG(%a6) + tstb UFLG_TMP(%a6) |test flag for unsupp/unimp state + beqs uni_getop + +uns_getop: + btstb #direction_bit,CMDREG1B(%a6) + bne opclass3 |branch if a fmove out (any kind) + btstb #6,CMDREG1B(%a6) + beqs uns_notpacked + + bfextu CMDREG1B(%a6){#3:#3},%d0 + cmpb #3,%d0 + beq pack_source |check for a packed src op, branch if so +uns_notpacked: + bsr chk_dy_mo |set the dyadic/monadic flag + tstb DY_MO_FLG(%a6) + beqs src_op_ck |if monadic, go check src op +| ;else, check dst op (fall through) + + btstb #7,DTAG(%a6) + beqs src_op_ck |if dst op is norm, check src op + bras dst_ex_dnrm |else, handle destination unnorm/dnrm + +uni_getop: + bfextu CMDREG1B(%a6){#0:#6},%d0 |get opclass and src fields + cmpil #0x17,%d0 |if op class and size fields are $17, +| ;it is FMOVECR; if not, continue +| +| If the instruction is fmovecr, exit get_op. It is handled +| in do_func and smovecr.sa. +| + bne not_fmovecr |handle fmovecr as an unimplemented inst + rts + +not_fmovecr: + btstb #E1,E_BYTE(%a6) |if set, there is a packed operand + bne pack_source |check for packed src op, branch if so + +| The following lines of are coded to optimize on normalized operands + moveb STAG(%a6),%d0 + orb DTAG(%a6),%d0 |check if either of STAG/DTAG msb set + bmis dest_op_ck |if so, some op needs to be fixed + rts + +dest_op_ck: + btstb #7,DTAG(%a6) |check for unsupported data types in + beqs src_op_ck |the destination, if not, check src op + bsr chk_dy_mo |set dyadic/monadic flag + tstb DY_MO_FLG(%a6) | + beqs src_op_ck |if monadic, check src op +| +| At this point, destination has an extended denorm or unnorm. +| +dst_ex_dnrm: + movew FPTEMP_EX(%a6),%d0 |get destination exponent + andiw #0x7fff,%d0 |mask sign, check if exp = 0000 + beqs src_op_ck |if denorm then check source op. +| ;denorms are taken care of in res_func +| ;(unsupp) or do_func (unimp) +| ;else unnorm fall through + leal FPTEMP(%a6),%a0 |point a0 to dop - used in mk_norm + bsr mk_norm |go normalize - mk_norm returns: +| ;L_SCR1{7:5} = operand tag +| ; (000 = norm, 100 = denorm) +| ;L_SCR1{4} = fpte15 or ete15 +| ; 0 = exp > $3fff +| ; 1 = exp <= $3fff +| ;and puts the normalized num back +| ;on the fsave stack +| + moveb L_SCR1(%a6),DTAG(%a6) |write the new tag & fpte15 +| ;to the fsave stack and fall +| ;through to check source operand +| +src_op_ck: + btstb #7,STAG(%a6) + beq end_getop |check for unsupported data types on the +| ;source operand + btstb #5,STAG(%a6) + bnes src_sd_dnrm |if bit 5 set, handle sgl/dbl denorms +| +| At this point only unnorms or extended denorms are possible. +| +src_ex_dnrm: + movew ETEMP_EX(%a6),%d0 |get source exponent + andiw #0x7fff,%d0 |mask sign, check if exp = 0000 + beq end_getop |if denorm then exit, denorms are +| ;handled in do_func + leal ETEMP(%a6),%a0 |point a0 to sop - used in mk_norm + bsr mk_norm |go normalize - mk_norm returns: +| ;L_SCR1{7:5} = operand tag +| ; (000 = norm, 100 = denorm) +| ;L_SCR1{4} = fpte15 or ete15 +| ; 0 = exp > $3fff +| ; 1 = exp <= $3fff +| ;and puts the normalized num back +| ;on the fsave stack +| + moveb L_SCR1(%a6),STAG(%a6) |write the new tag & ete15 + rts |end_getop + +| +| At this point, only single or double denorms are possible. +| If the inst is not fmove, normalize the source. If it is, +| do nothing to the input. +| +src_sd_dnrm: + btstb #4,CMDREG1B(%a6) |differentiate between sgl/dbl denorm + bnes is_double +is_single: + movew #0x3f81,%d1 |write bias for sgl denorm + bras common |goto the common code +is_double: + movew #0x3c01,%d1 |write the bias for a dbl denorm +common: + btstb #sign_bit,ETEMP_EX(%a6) |grab sign bit of mantissa + beqs pos + bset #15,%d1 |set sign bit because it is negative +pos: + movew %d1,ETEMP_EX(%a6) +| ;put exponent on stack + + movew CMDREG1B(%a6),%d1 + andw #0xe3ff,%d1 |clear out source specifier + orw #0x0800,%d1 |set source specifier to extended prec + movew %d1,CMDREG1B(%a6) |write back to the command word in stack +| ;this is needed to fix unsupp data stack + leal ETEMP(%a6),%a0 |point a0 to sop + + bsr mk_norm |convert sgl/dbl denorm to norm + moveb L_SCR1(%a6),STAG(%a6) |put tag into source tag reg - d0 + rts |end_getop +| +| At this point, the source is definitely packed, whether +| instruction is dyadic or monadic is still unknown +| +pack_source: + movel FPTEMP_LO(%a6),ETEMP(%a6) |write ms part of packed +| ;number to etemp slot + bsr chk_dy_mo |set dyadic/monadic flag + bsr unpack + + tstb DY_MO_FLG(%a6) + beqs end_getop |if monadic, exit +| ;else, fix FPTEMP +pack_dya: + bfextu CMDREG1B(%a6){#6:#3},%d0 |extract dest fp reg + movel #7,%d1 + subl %d0,%d1 + clrl %d0 + bsetl %d1,%d0 |set up d0 as a dynamic register mask + fmovemx %d0,FPTEMP(%a6) |write to FPTEMP + + btstb #7,DTAG(%a6) |check dest tag for unnorm or denorm + bne dst_ex_dnrm |else, handle the unnorm or ext denorm +| +| Dest is not denormalized. Check for norm, and set fpte15 +| accordingly. +| + moveb DTAG(%a6),%d0 + andib #0xf0,%d0 |strip to only dtag:fpte15 + tstb %d0 |check for normalized value + bnes end_getop |if inf/nan/zero leave get_op + movew FPTEMP_EX(%a6),%d0 + andiw #0x7fff,%d0 + cmpiw #0x3fff,%d0 |check if fpte15 needs setting + bges end_getop |if >= $3fff, leave fpte15=0 + orb #0x10,DTAG(%a6) + bras end_getop + +| +| At this point, it is either an fmoveout packed, unnorm or denorm +| +opclass3: + clrb DY_MO_FLG(%a6) |set dyadic/monadic flag to monadic + bfextu CMDREG1B(%a6){#4:#2},%d0 + cmpib #3,%d0 + bne src_ex_dnrm |if not equal, must be unnorm or denorm +| ;else it is a packed move out +| ;exit +end_getop: + rts + +| +| Sets the DY_MO_FLG correctly. This is used only on if it is an +| unuspported data type exception. Set if dyadic. +| +chk_dy_mo: + movew CMDREG1B(%a6),%d0 + btstl #5,%d0 |testing extension command word + beqs set_mon |if bit 5 = 0 then monadic + btstl #4,%d0 |know that bit 5 = 1 + beqs set_dya |if bit 4 = 0 then dyadic + andiw #0x007f,%d0 |get rid of all but extension bits {6:0} + cmpiw #0x0038,%d0 |if extension = $38 then fcmp (dyadic) + bnes set_mon +set_dya: + st DY_MO_FLG(%a6) |set the inst flag type to dyadic + rts +set_mon: + clrb DY_MO_FLG(%a6) |set the inst flag type to monadic + rts +| +| MK_NORM +| +| Normalizes unnormalized numbers, sets tag to norm or denorm, sets unfl +| exception if denorm. +| +| CASE opclass 0x0 unsupp +| mk_norm till msb set +| set tag = norm +| +| CASE opclass 0x0 unimp +| mk_norm till msb set or exp = 0 +| if integer bit = 0 +| tag = denorm +| else +| tag = norm +| +| CASE opclass 011 unsupp +| mk_norm till msb set or exp = 0 +| if integer bit = 0 +| tag = denorm +| set unfl_nmcexe = 1 +| else +| tag = norm +| +| if exp <= $3fff +| set ete15 or fpte15 = 1 +| else set ete15 or fpte15 = 0 + +| input: +| a0 = points to operand to be normalized +| output: +| L_SCR1{7:5} = operand tag (000 = norm, 100 = denorm) +| L_SCR1{4} = fpte15 or ete15 (0 = exp > $3fff, 1 = exp <=$3fff) +| the normalized operand is placed back on the fsave stack +mk_norm: + clrl L_SCR1(%a6) + bclrb #sign_bit,LOCAL_EX(%a0) + sne LOCAL_SGN(%a0) |transform into internal extended format + + cmpib #0x2c,1+EXC_VEC(%a6) |check if unimp + bnes uns_data |branch if unsupp + bsr uni_inst |call if unimp (opclass 0x0) + bras reload +uns_data: + btstb #direction_bit,CMDREG1B(%a6) |check transfer direction + bnes bit_set |branch if set (opclass 011) + bsr uns_opx |call if opclass 0x0 + bras reload +bit_set: + bsr uns_op3 |opclass 011 +reload: + cmpw #0x3fff,LOCAL_EX(%a0) |if exp > $3fff + bgts end_mk | fpte15/ete15 already set to 0 + bsetb #4,L_SCR1(%a6) |else set fpte15/ete15 to 1 +| ;calling routine actually sets the +| ;value on the stack (along with the +| ;tag), since this routine doesn't +| ;know if it should set ete15 or fpte15 +| ;ie, it doesn't know if this is the +| ;src op or dest op. +end_mk: + bfclr LOCAL_SGN(%a0){#0:#8} + beqs end_mk_pos + bsetb #sign_bit,LOCAL_EX(%a0) |convert back to IEEE format +end_mk_pos: + rts +| +| CASE opclass 011 unsupp +| +uns_op3: + bsr nrm_zero |normalize till msb = 1 or exp = zero + btstb #7,LOCAL_HI(%a0) |if msb = 1 + bnes no_unfl |then branch +set_unfl: + orw #dnrm_tag,L_SCR1(%a6) |set denorm tag + bsetb #unfl_bit,FPSR_EXCEPT(%a6) |set unfl exception bit +no_unfl: + rts +| +| CASE opclass 0x0 unsupp +| +uns_opx: + bsr nrm_zero |normalize the number + btstb #7,LOCAL_HI(%a0) |check if integer bit (j-bit) is set + beqs uns_den |if clear then now have a denorm +uns_nrm: + orb #norm_tag,L_SCR1(%a6) |set tag to norm + rts +uns_den: + orb #dnrm_tag,L_SCR1(%a6) |set tag to denorm + rts +| +| CASE opclass 0x0 unimp +| +uni_inst: + bsr nrm_zero + btstb #7,LOCAL_HI(%a0) |check if integer bit (j-bit) is set + beqs uni_den |if clear then now have a denorm +uni_nrm: + orb #norm_tag,L_SCR1(%a6) |set tag to norm + rts +uni_den: + orb #dnrm_tag,L_SCR1(%a6) |set tag to denorm + rts + +| +| Decimal to binary conversion +| +| Special cases of inf and NaNs are completed outside of decbin. +| If the input is an snan, the snan bit is not set. +| +| input: +| ETEMP(a6) - points to packed decimal string in memory +| output: +| fp0 - contains packed string converted to extended precision +| ETEMP - same as fp0 +unpack: + movew CMDREG1B(%a6),%d0 |examine command word, looking for fmove's + andw #0x3b,%d0 + beq move_unpack |special handling for fmove: must set FPSR_CC + + movew ETEMP(%a6),%d0 |get word with inf information + bfextu %d0{#20:#12},%d1 |get exponent into d1 + cmpiw #0x0fff,%d1 |test for inf or NaN + bnes try_zero |if not equal, it is not special + bfextu %d0{#17:#3},%d1 |get SE and y bits into d1 + cmpiw #7,%d1 |SE and y bits must be on for special + bnes try_zero |if not on, it is not special +|input is of the special cases of inf and NaN + tstl ETEMP_HI(%a6) |check ms mantissa + bnes fix_nan |if non-zero, it is a NaN + tstl ETEMP_LO(%a6) |check ls mantissa + bnes fix_nan |if non-zero, it is a NaN + bra finish |special already on stack +fix_nan: + btstb #signan_bit,ETEMP_HI(%a6) |test for snan + bne finish + orl #snaniop_mask,USER_FPSR(%a6) |always set snan if it is so + bra finish +try_zero: + movew ETEMP_EX+2(%a6),%d0 |get word 4 + andiw #0x000f,%d0 |clear all but last ni(y)bble + tstw %d0 |check for zero. + bne not_spec + tstl ETEMP_HI(%a6) |check words 3 and 2 + bne not_spec + tstl ETEMP_LO(%a6) |check words 1 and 0 + bne not_spec + tstl ETEMP(%a6) |test sign of the zero + bges pos_zero + movel #0x80000000,ETEMP(%a6) |write neg zero to etemp + clrl ETEMP_HI(%a6) + clrl ETEMP_LO(%a6) + bra finish +pos_zero: + clrl ETEMP(%a6) + clrl ETEMP_HI(%a6) + clrl ETEMP_LO(%a6) + bra finish + +not_spec: + fmovemx %fp0-%fp1,-(%a7) |save fp0 - decbin returns in it + bsr decbin + fmovex %fp0,ETEMP(%a6) |put the unpacked sop in the fsave stack + fmovemx (%a7)+,%fp0-%fp1 + fmovel #0,%FPSR |clr fpsr from decbin + bra finish + +| +| Special handling for packed move in: Same results as all other +| packed cases, but we must set the FPSR condition codes properly. +| +move_unpack: + movew ETEMP(%a6),%d0 |get word with inf information + bfextu %d0{#20:#12},%d1 |get exponent into d1 + cmpiw #0x0fff,%d1 |test for inf or NaN + bnes mtry_zero |if not equal, it is not special + bfextu %d0{#17:#3},%d1 |get SE and y bits into d1 + cmpiw #7,%d1 |SE and y bits must be on for special + bnes mtry_zero |if not on, it is not special +|input is of the special cases of inf and NaN + tstl ETEMP_HI(%a6) |check ms mantissa + bnes mfix_nan |if non-zero, it is a NaN + tstl ETEMP_LO(%a6) |check ls mantissa + bnes mfix_nan |if non-zero, it is a NaN +|input is inf + orl #inf_mask,USER_FPSR(%a6) |set I bit + tstl ETEMP(%a6) |check sign + bge finish + orl #neg_mask,USER_FPSR(%a6) |set N bit + bra finish |special already on stack +mfix_nan: + orl #nan_mask,USER_FPSR(%a6) |set NaN bit + moveb #nan_tag,STAG(%a6) |set stag to NaN + btstb #signan_bit,ETEMP_HI(%a6) |test for snan + bnes mn_snan + orl #snaniop_mask,USER_FPSR(%a6) |set snan bit + btstb #snan_bit,FPCR_ENABLE(%a6) |test for snan enabled + bnes mn_snan + bsetb #signan_bit,ETEMP_HI(%a6) |force snans to qnans +mn_snan: + tstl ETEMP(%a6) |check for sign + bge finish |if clr, go on + orl #neg_mask,USER_FPSR(%a6) |set N bit + bra finish + +mtry_zero: + movew ETEMP_EX+2(%a6),%d0 |get word 4 + andiw #0x000f,%d0 |clear all but last ni(y)bble + tstw %d0 |check for zero. + bnes mnot_spec + tstl ETEMP_HI(%a6) |check words 3 and 2 + bnes mnot_spec + tstl ETEMP_LO(%a6) |check words 1 and 0 + bnes mnot_spec + tstl ETEMP(%a6) |test sign of the zero + bges mpos_zero + orl #neg_mask+z_mask,USER_FPSR(%a6) |set N and Z + movel #0x80000000,ETEMP(%a6) |write neg zero to etemp + clrl ETEMP_HI(%a6) + clrl ETEMP_LO(%a6) + bras finish +mpos_zero: + orl #z_mask,USER_FPSR(%a6) |set Z + clrl ETEMP(%a6) + clrl ETEMP_HI(%a6) + clrl ETEMP_LO(%a6) + bras finish + +mnot_spec: + fmovemx %fp0-%fp1,-(%a7) |save fp0 ,fp1 - decbin returns in fp0 + bsr decbin + fmovex %fp0,ETEMP(%a6) +| ;put the unpacked sop in the fsave stack + fmovemx (%a7)+,%fp0-%fp1 + +finish: + movew CMDREG1B(%a6),%d0 |get the command word + andw #0xfbff,%d0 |change the source specifier field to +| ;extended (was packed). + movew %d0,CMDREG1B(%a6) |write command word back to fsave stack +| ;we need to do this so the 040 will +| ;re-execute the inst. without taking +| ;another packed trap. + +fix_stag: +|Converted result is now in etemp on fsave stack, now set the source +|tag (stag) +| if (ete =$7fff) then INF or NAN +| if (etemp = $x.0----0) then +| stag = INF +| else +| stag = NAN +| else +| if (ete = $0000) then +| stag = ZERO +| else +| stag = NORM +| +| Note also that the etemp_15 bit (just right of the stag) must +| be set accordingly. +| + movew ETEMP_EX(%a6),%d1 + andiw #0x7fff,%d1 |strip sign + cmpw #0x7fff,%d1 + bnes z_or_nrm + movel ETEMP_HI(%a6),%d1 + bnes is_nan + movel ETEMP_LO(%a6),%d1 + bnes is_nan +is_inf: + moveb #0x40,STAG(%a6) + movel #0x40,%d0 + rts +is_nan: + moveb #0x60,STAG(%a6) + movel #0x60,%d0 + rts +z_or_nrm: + tstw %d1 + bnes is_nrm +is_zro: +| For a zero, set etemp_15 + moveb #0x30,STAG(%a6) + movel #0x20,%d0 + rts +is_nrm: +| For a norm, check if the exp <= $3fff; if so, set etemp_15 + cmpiw #0x3fff,%d1 + bles set_bit15 + moveb #0,STAG(%a6) + bras end_is_nrm +set_bit15: + moveb #0x10,STAG(%a6) +end_is_nrm: + movel #0,%d0 +end_fix: + rts + +end_get: + rts + |end diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/kernel_ex.S linux/arch/m68k/fpsp040/kernel_ex.S --- v1.3.93/linux/arch/m68k/fpsp040/kernel_ex.S Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/fpsp040/kernel_ex.S Sat Feb 24 22:58:43 1996 @@ -0,0 +1,494 @@ +| +| kernel_ex.sa 3.3 12/19/90 +| +| This file contains routines to force exception status in the +| fpu for exceptional cases detected or reported within the +| transcendental functions. Typically, the t_xx routine will +| set the appropriate bits in the USER_FPSR word on the stack. +| The bits are tested in gen_except.sa to determine if an exceptional +| situation needs to be created on return from the FPSP. +| + +| Copyright (C) Motorola, Inc. 1990 +| All Rights Reserved +| +| THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA +| The copyright notice above does not evidence any +| actual or intended publication of such source code. + +KERNEL_EX: |idnt 2,1 | Motorola 040 Floating Point Software Package + + |section 8 + + .include "fpsp.h" + +mns_inf: .long 0xffff0000,0x00000000,0x00000000 +pls_inf: .long 0x7fff0000,0x00000000,0x00000000 +nan: .long 0x7fff0000,0xffffffff,0xffffffff +huge: .long 0x7ffe0000,0xffffffff,0xffffffff + + |xref ovf_r_k + |xref unf_sub + |xref nrm_set + + .global t_dz + .global t_dz2 + .global t_operr + .global t_unfl + .global t_ovfl + .global t_ovfl2 + .global t_inx2 + .global t_frcinx + .global t_extdnrm + .global t_resdnrm + .global dst_nan + .global src_nan +| +| DZ exception +| +| +| if dz trap disabled +| store properly signed inf (use sign of etemp) into fp0 +| set FPSR exception status dz bit, condition code +| inf bit, and accrued dz bit +| return +| frestore the frame into the machine (done by unimp_hd) +| +| else dz trap enabled +| set exception status bit & accrued bits in FPSR +| set flag to disable sto_res from corrupting fp register +| return +| frestore the frame into the machine (done by unimp_hd) +| +| t_dz2 is used by monadic functions such as flogn (from do_func). +| t_dz is used by monadic functions such as satanh (from the +| transcendental function). +| +t_dz2: + bsetb #neg_bit,FPSR_CC(%a6) |set neg bit in FPSR + fmovel #0,%FPSR |clr status bits (Z set) + btstb #dz_bit,FPCR_ENABLE(%a6) |test FPCR for dz exc enabled + bnes dz_ena_end + bras m_inf |flogx always returns -inf +t_dz: + fmovel #0,%FPSR |clr status bits (Z set) + btstb #dz_bit,FPCR_ENABLE(%a6) |test FPCR for dz exc enabled + bnes dz_ena +| +| dz disabled +| + btstb #sign_bit,ETEMP_EX(%a6) |check sign for neg or pos + beqs p_inf |branch if pos sign + +m_inf: + fmovemx mns_inf,%fp0-%fp0 |load -inf + bsetb #neg_bit,FPSR_CC(%a6) |set neg bit in FPSR + bras set_fpsr +p_inf: + fmovemx pls_inf,%fp0-%fp0 |load +inf +set_fpsr: + orl #dzinf_mask,USER_FPSR(%a6) |set I,DZ,ADZ + rts +| +| dz enabled +| +dz_ena: + btstb #sign_bit,ETEMP_EX(%a6) |check sign for neg or pos + beqs dz_ena_end + bsetb #neg_bit,FPSR_CC(%a6) |set neg bit in FPSR +dz_ena_end: + orl #dzinf_mask,USER_FPSR(%a6) |set I,DZ,ADZ + st STORE_FLG(%a6) + rts +| +| OPERR exception +| +| if (operr trap disabled) +| set FPSR exception status operr bit, condition code +| nan bit; Store default NAN into fp0 +| frestore the frame into the machine (done by unimp_hd) +| +| else (operr trap enabled) +| set FPSR exception status operr bit, accrued operr bit +| set flag to disable sto_res from corrupting fp register +| frestore the frame into the machine (done by unimp_hd) +| +t_operr: + orl #opnan_mask,USER_FPSR(%a6) |set NaN, OPERR, AIOP + + btstb #operr_bit,FPCR_ENABLE(%a6) |test FPCR for operr enabled + bnes op_ena + + fmovemx nan,%fp0-%fp0 |load default nan + rts +op_ena: + st STORE_FLG(%a6) |do not corrupt destination + rts + +| +| t_unfl --- UNFL exception +| +| This entry point is used by all routines requiring unfl, inex2, +| aunfl, and ainex to be set on exit. +| +| On entry, a0 points to the exceptional operand. The final exceptional +| operand is built in FP_SCR1 and only the sign from the original operand +| is used. +| +t_unfl: + clrl FP_SCR1(%a6) |set exceptional operand to zero + clrl FP_SCR1+4(%a6) + clrl FP_SCR1+8(%a6) + tstb (%a0) |extract sign from caller's exop + bpls unfl_signok + bset #sign_bit,FP_SCR1(%a6) +unfl_signok: + leal FP_SCR1(%a6),%a0 + orl #unfinx_mask,USER_FPSR(%a6) +| ;set UNFL, INEX2, AUNFL, AINEX +unfl_con: + btstb #unfl_bit,FPCR_ENABLE(%a6) + beqs unfl_dis + +unfl_ena: + bfclr STAG(%a6){#5:#3} |clear wbtm66,wbtm1,wbtm0 + bsetb #wbtemp15_bit,WB_BYTE(%a6) |set wbtemp15 + bsetb #sticky_bit,STICKY(%a6) |set sticky bit + + bclrb #E1,E_BYTE(%a6) + +unfl_dis: + bfextu FPCR_MODE(%a6){#0:#2},%d0 |get round precision + + bclrb #sign_bit,LOCAL_EX(%a0) + sne LOCAL_SGN(%a0) |convert to internal ext format + + bsr unf_sub |returns IEEE result at a0 +| ;and sets FPSR_CC accordingly + + bfclr LOCAL_SGN(%a0){#0:#8} |convert back to IEEE ext format + beqs unfl_fin + + bsetb #sign_bit,LOCAL_EX(%a0) + bsetb #sign_bit,FP_SCR1(%a6) |set sign bit of exc operand + +unfl_fin: + fmovemx (%a0),%fp0-%fp0 |store result in fp0 + rts + + +| +| t_ovfl2 --- OVFL exception (without inex2 returned) +| +| This entry is used by scale to force catastrophic overflow. The +| ovfl, aovfl, and ainex bits are set, but not the inex2 bit. +| +t_ovfl2: + orl #ovfl_inx_mask,USER_FPSR(%a6) + movel ETEMP(%a6),FP_SCR1(%a6) + movel ETEMP_HI(%a6),FP_SCR1+4(%a6) + movel ETEMP_LO(%a6),FP_SCR1+8(%a6) +| +| Check for single or double round precision. If single, check if +| the lower 40 bits of ETEMP are zero; if not, set inex2. If double, +| check if the lower 21 bits are zero; if not, set inex2. +| + moveb FPCR_MODE(%a6),%d0 + andib #0xc0,%d0 + beq t_work |if extended, finish ovfl processing + cmpib #0x40,%d0 |test for single + bnes t_dbl +t_sgl: + tstb ETEMP_LO(%a6) + bnes t_setinx2 + movel ETEMP_HI(%a6),%d0 + andil #0xff,%d0 |look at only lower 8 bits + bnes t_setinx2 + bra t_work +t_dbl: + movel ETEMP_LO(%a6),%d0 + andil #0x7ff,%d0 |look at only lower 11 bits + beq t_work +t_setinx2: + orl #inex2_mask,USER_FPSR(%a6) + bras t_work +| +| t_ovfl --- OVFL exception +| +|** Note: the exc operand is returned in ETEMP. +| +t_ovfl: + orl #ovfinx_mask,USER_FPSR(%a6) +t_work: + btstb #ovfl_bit,FPCR_ENABLE(%a6) |test FPCR for ovfl enabled + beqs ovf_dis + +ovf_ena: + clrl FP_SCR1(%a6) |set exceptional operand + clrl FP_SCR1+4(%a6) + clrl FP_SCR1+8(%a6) + + bfclr STAG(%a6){#5:#3} |clear wbtm66,wbtm1,wbtm0 + bclrb #wbtemp15_bit,WB_BYTE(%a6) |clear wbtemp15 + bsetb #sticky_bit,STICKY(%a6) |set sticky bit + + bclrb #E1,E_BYTE(%a6) +| ;fall through to disabled case + +| For disabled overflow call 'ovf_r_k'. This routine loads the +| correct result based on the rounding precision, destination +| format, rounding mode and sign. +| +ovf_dis: + bsr ovf_r_k |returns unsigned ETEMP_EX +| ;and sets FPSR_CC accordingly. + bfclr ETEMP_SGN(%a6){#0:#8} |fix sign + beqs ovf_pos + bsetb #sign_bit,ETEMP_EX(%a6) + bsetb #sign_bit,FP_SCR1(%a6) |set exceptional operand sign +ovf_pos: + fmovemx ETEMP(%a6),%fp0-%fp0 |move the result to fp0 + rts + + +| +| INEX2 exception +| +| The inex2 and ainex bits are set. +| +t_inx2: + orl #inx2a_mask,USER_FPSR(%a6) |set INEX2, AINEX + rts + +| +| Force Inex2 +| +| This routine is called by the transcendental routines to force +| the inex2 exception bits set in the FPSR. If the underflow bit +| is set, but the underflow trap was not taken, the aunfl bit in +| the FPSR must be set. +| +t_frcinx: + orl #inx2a_mask,USER_FPSR(%a6) |set INEX2, AINEX + btstb #unfl_bit,FPSR_EXCEPT(%a6) |test for unfl bit set + beqs no_uacc1 |if clear, do not set aunfl + bsetb #aunfl_bit,FPSR_AEXCEPT(%a6) +no_uacc1: + rts + +| +| DST_NAN +| +| Determine if the destination nan is signalling or non-signalling, +| and set the FPSR bits accordingly. See the MC68040 User's Manual +| section 3.2.2.5 NOT-A-NUMBERS. +| +dst_nan: + btstb #sign_bit,FPTEMP_EX(%a6) |test sign of nan + beqs dst_pos |if clr, it was positive + bsetb #neg_bit,FPSR_CC(%a6) |set N bit +dst_pos: + btstb #signan_bit,FPTEMP_HI(%a6) |check if signalling + beqs dst_snan |branch if signalling + + fmovel %d1,%fpcr |restore user's rmode/prec + fmovex FPTEMP(%a6),%fp0 |return the non-signalling nan +| +| Check the source nan. If it is signalling, snan will be reported. +| + moveb STAG(%a6),%d0 + andib #0xe0,%d0 + cmpib #0x60,%d0 + bnes no_snan + btstb #signan_bit,ETEMP_HI(%a6) |check if signalling + bnes no_snan + orl #snaniop_mask,USER_FPSR(%a6) |set NAN, SNAN, AIOP +no_snan: + rts + +dst_snan: + btstb #snan_bit,FPCR_ENABLE(%a6) |check if trap enabled + beqs dst_dis |branch if disabled + + orb #nan_tag,DTAG(%a6) |set up dtag for nan + st STORE_FLG(%a6) |do not store a result + orl #snaniop_mask,USER_FPSR(%a6) |set NAN, SNAN, AIOP + rts + +dst_dis: + bsetb #signan_bit,FPTEMP_HI(%a6) |set SNAN bit in sop + fmovel %d1,%fpcr |restore user's rmode/prec + fmovex FPTEMP(%a6),%fp0 |load non-sign. nan + orl #snaniop_mask,USER_FPSR(%a6) |set NAN, SNAN, AIOP + rts + +| +| SRC_NAN +| +| Determine if the source nan is signalling or non-signalling, +| and set the FPSR bits accordingly. See the MC68040 User's Manual +| section 3.2.2.5 NOT-A-NUMBERS. +| +src_nan: + btstb #sign_bit,ETEMP_EX(%a6) |test sign of nan + beqs src_pos |if clr, it was positive + bsetb #neg_bit,FPSR_CC(%a6) |set N bit +src_pos: + btstb #signan_bit,ETEMP_HI(%a6) |check if signalling + beqs src_snan |branch if signalling + fmovel %d1,%fpcr |restore user's rmode/prec + fmovex ETEMP(%a6),%fp0 |return the non-signalling nan + rts + +src_snan: + btstb #snan_bit,FPCR_ENABLE(%a6) |check if trap enabled + beqs src_dis |branch if disabled + bsetb #signan_bit,ETEMP_HI(%a6) |set SNAN bit in sop + orb #norm_tag,DTAG(%a6) |set up dtag for norm + orb #nan_tag,STAG(%a6) |set up stag for nan + st STORE_FLG(%a6) |do not store a result + orl #snaniop_mask,USER_FPSR(%a6) |set NAN, SNAN, AIOP + rts + +src_dis: + bsetb #signan_bit,ETEMP_HI(%a6) |set SNAN bit in sop + fmovel %d1,%fpcr |restore user's rmode/prec + fmovex ETEMP(%a6),%fp0 |load non-sign. nan + orl #snaniop_mask,USER_FPSR(%a6) |set NAN, SNAN, AIOP + rts + +| +| For all functions that have a denormalized input and that f(x)=x, +| this is the entry point +| +t_extdnrm: + orl #unfinx_mask,USER_FPSR(%a6) +| ;set UNFL, INEX2, AUNFL, AINEX + bras xdnrm_con +| +| Entry point for scale with extended denorm. The function does +| not set inex2, aunfl, or ainex. +| +t_resdnrm: + orl #unfl_mask,USER_FPSR(%a6) + +xdnrm_con: + btstb #unfl_bit,FPCR_ENABLE(%a6) + beqs xdnrm_dis + +| +| If exceptions are enabled, the additional task of setting up WBTEMP +| is needed so that when the underflow exception handler is entered, +| the user perceives no difference between what the 040 provides vs. +| what the FPSP provides. +| +xdnrm_ena: + movel %a0,-(%a7) + + movel LOCAL_EX(%a0),FP_SCR1(%a6) + movel LOCAL_HI(%a0),FP_SCR1+4(%a6) + movel LOCAL_LO(%a0),FP_SCR1+8(%a6) + + lea FP_SCR1(%a6),%a0 + + bclrb #sign_bit,LOCAL_EX(%a0) + sne LOCAL_SGN(%a0) |convert to internal ext format + tstw LOCAL_EX(%a0) |check if input is denorm + beqs xdnrm_dn |if so, skip nrm_set + bsr nrm_set |normalize the result (exponent +| ;will be negative +xdnrm_dn: + bclrb #sign_bit,LOCAL_EX(%a0) |take off false sign + bfclr LOCAL_SGN(%a0){#0:#8} |change back to IEEE ext format + beqs xdep + bsetb #sign_bit,LOCAL_EX(%a0) +xdep: + bfclr STAG(%a6){#5:#3} |clear wbtm66,wbtm1,wbtm0 + bsetb #wbtemp15_bit,WB_BYTE(%a6) |set wbtemp15 + bclrb #sticky_bit,STICKY(%a6) |clear sticky bit + bclrb #E1,E_BYTE(%a6) + movel (%a7)+,%a0 +xdnrm_dis: + bfextu FPCR_MODE(%a6){#0:#2},%d0 |get round precision + bnes not_ext |if not round extended, store +| ;IEEE defaults +is_ext: + btstb #sign_bit,LOCAL_EX(%a0) + beqs xdnrm_store + + bsetb #neg_bit,FPSR_CC(%a6) |set N bit in FPSR_CC + + bras xdnrm_store + +not_ext: + bclrb #sign_bit,LOCAL_EX(%a0) + sne LOCAL_SGN(%a0) |convert to internal ext format + bsr unf_sub |returns IEEE result pointed by +| ;a0; sets FPSR_CC accordingly + bfclr LOCAL_SGN(%a0){#0:#8} |convert back to IEEE ext format + beqs xdnrm_store + bsetb #sign_bit,LOCAL_EX(%a0) +xdnrm_store: + fmovemx (%a0),%fp0-%fp0 |store result in fp0 + rts + +| +| This subroutine is used for dyadic operations that use an extended +| denorm within the kernel. The approach used is to capture the frame, +| fix/restore. +| + .global t_avoid_unsupp +t_avoid_unsupp: + link %a2,#-LOCAL_SIZE |so that a2 fpsp.h negative +| ;offsets may be used + fsave -(%a7) + tstb 1(%a7) |check if idle, exit if so + beq idle_end + btstb #E1,E_BYTE(%a2) |check for an E1 exception if +| ;enabled, there is an unsupp + beq end_avun |else, exit + btstb #7,DTAG(%a2) |check for denorm destination + beqs src_den |else, must be a source denorm +| +| handle destination denorm +| + lea FPTEMP(%a2),%a0 + btstb #sign_bit,LOCAL_EX(%a0) + sne LOCAL_SGN(%a0) |convert to internal ext format + bclrb #7,DTAG(%a2) |set DTAG to norm + bsr nrm_set |normalize result, exponent +| ;will become negative + bclrb #sign_bit,LOCAL_EX(%a0) |get rid of fake sign + bfclr LOCAL_SGN(%a0){#0:#8} |convert back to IEEE ext format + beqs ck_src_den |check if source is also denorm + bsetb #sign_bit,LOCAL_EX(%a0) +ck_src_den: + btstb #7,STAG(%a2) + beqs end_avun +src_den: + lea ETEMP(%a2),%a0 + btstb #sign_bit,LOCAL_EX(%a0) + sne LOCAL_SGN(%a0) |convert to internal ext format + bclrb #7,STAG(%a2) |set STAG to norm + bsr nrm_set |normalize result, exponent +| ;will become negative + bclrb #sign_bit,LOCAL_EX(%a0) |get rid of fake sign + bfclr LOCAL_SGN(%a0){#0:#8} |convert back to IEEE ext format + beqs den_com + bsetb #sign_bit,LOCAL_EX(%a0) +den_com: + moveb #0xfe,CU_SAVEPC(%a2) |set continue frame + clrw NMNEXC(%a2) |clear NMNEXC + bclrb #E1,E_BYTE(%a2) +| fmove.l %FPSR,FPSR_SHADOW(%a2) +| bset.b #SFLAG,E_BYTE(%a2) +| bset.b #XFLAG,T_BYTE(%a2) +end_avun: + frestore (%a7)+ + unlk %a2 + rts +idle_end: + addl #4,%a7 + unlk %a2 + rts + |end diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/res_func.S linux/arch/m68k/fpsp040/res_func.S --- v1.3.93/linux/arch/m68k/fpsp040/res_func.S Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/fpsp040/res_func.S Sat Feb 24 22:58:43 1996 @@ -0,0 +1,2040 @@ +| +| res_func.sa 3.9 7/29/91 +| +| Normalizes denormalized numbers if necessary and updates the +| stack frame. The function is then restored back into the +| machine and the 040 completes the operation. This routine +| is only used by the unsupported data type/format handler. +| (Exception vector 55). +| +| For packed move out (fmove.p fpm,) the operation is +| completed here; data is packed and moved to user memory. +| The stack is restored to the 040 only in the case of a +| reportable exception in the conversion. +| +| +| Copyright (C) Motorola, Inc. 1990 +| All Rights Reserved +| +| THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA +| The copyright notice above does not evidence any +| actual or intended publication of such source code. + +RES_FUNC: |idnt 2,1 | Motorola 040 Floating Point Software Package + + |section 8 + + .include "fpsp.h" + +sp_bnds: .short 0x3f81,0x407e + .short 0x3f6a,0x0000 +dp_bnds: .short 0x3c01,0x43fe + .short 0x3bcd,0x0000 + + |xref mem_write + |xref bindec + |xref get_fline + |xref round + |xref denorm + |xref dest_ext + |xref dest_dbl + |xref dest_sgl + |xref unf_sub + |xref nrm_set + |xref dnrm_lp + |xref ovf_res + |xref reg_dest + |xref t_ovfl + |xref t_unfl + + .global res_func + .global p_move + +res_func: + clrb DNRM_FLG(%a6) + clrb RES_FLG(%a6) + clrb CU_ONLY(%a6) + tstb DY_MO_FLG(%a6) + beqs monadic +dyadic: + btstb #7,DTAG(%a6) |if dop = norm=000, zero=001, +| ;inf=010 or nan=011 + beqs monadic |then branch +| ;else denorm +| HANDLE DESTINATION DENORM HERE +| ;set dtag to norm +| ;write the tag & fpte15 to the fstack + leal FPTEMP(%a6),%a0 + + bclrb #sign_bit,LOCAL_EX(%a0) + sne LOCAL_SGN(%a0) + + bsr nrm_set |normalize number (exp will go negative) + bclrb #sign_bit,LOCAL_EX(%a0) |get rid of false sign + bfclr LOCAL_SGN(%a0){#0:#8} |change back to IEEE ext format + beqs dpos + bsetb #sign_bit,LOCAL_EX(%a0) +dpos: + bfclr DTAG(%a6){#0:#4} |set tag to normalized, FPTE15 = 0 + bsetb #4,DTAG(%a6) |set FPTE15 + orb #0x0f,DNRM_FLG(%a6) +monadic: + leal ETEMP(%a6),%a0 + btstb #direction_bit,CMDREG1B(%a6) |check direction + bne opclass3 |it is a mv out +| +| At this point, only oplcass 0 and 2 possible +| + btstb #7,STAG(%a6) |if sop = norm=000, zero=001, +| ;inf=010 or nan=011 + bne mon_dnrm |else denorm + tstb DY_MO_FLG(%a6) |all cases of dyadic instructions would + bne normal |require normalization of denorm + +| At this point: +| monadic instructions: fabs = $18 fneg = $1a ftst = $3a +| fmove = $00 fsmove = $40 fdmove = $44 +| fsqrt = $05* fssqrt = $41 fdsqrt = $45 +| (*fsqrt reencoded to $05) +| + movew CMDREG1B(%a6),%d0 |get command register + andil #0x7f,%d0 |strip to only command word +| +| At this point, fabs, fneg, fsmove, fdmove, ftst, fsqrt, fssqrt, and +| fdsqrt are possible. +| For cases fabs, fneg, fsmove, and fdmove goto spos (do not normalize) +| For cases fsqrt, fssqrt, and fdsqrt goto nrm_src (do normalize) +| + btstl #0,%d0 + bne normal |weed out fsqrt instructions +| +| cu_norm handles fmove in instructions with normalized inputs. +| The routine round is used to correctly round the input for the +| destination precision and mode. +| +cu_norm: + st CU_ONLY(%a6) |set cu-only inst flag + movew CMDREG1B(%a6),%d0 + andib #0x3b,%d0 |isolate bits to select inst + tstb %d0 + beql cu_nmove |if zero, it is an fmove + cmpib #0x18,%d0 + beql cu_nabs |if $18, it is fabs + cmpib #0x1a,%d0 + beql cu_nneg |if $1a, it is fneg +| +| Inst is ftst. Check the source operand and set the cc's accordingly. +| No write is done, so simply rts. +| +cu_ntst: + movew LOCAL_EX(%a0),%d0 + bclrl #15,%d0 + sne LOCAL_SGN(%a0) + beqs cu_ntpo + orl #neg_mask,USER_FPSR(%a6) |set N +cu_ntpo: + cmpiw #0x7fff,%d0 |test for inf/nan + bnes cu_ntcz + tstl LOCAL_HI(%a0) + bnes cu_ntn + tstl LOCAL_LO(%a0) + bnes cu_ntn + orl #inf_mask,USER_FPSR(%a6) + rts +cu_ntn: + orl #nan_mask,USER_FPSR(%a6) + movel ETEMP_EX(%a6),FPTEMP_EX(%a6) |set up fptemp sign for +| ;snan handler + + rts +cu_ntcz: + tstl LOCAL_HI(%a0) + bnel cu_ntsx + tstl LOCAL_LO(%a0) + bnel cu_ntsx + orl #z_mask,USER_FPSR(%a6) +cu_ntsx: + rts +| +| Inst is fabs. Execute the absolute value function on the input. +| Branch to the fmove code. If the operand is NaN, do nothing. +| +cu_nabs: + moveb STAG(%a6),%d0 + btstl #5,%d0 |test for NaN or zero + bne wr_etemp |if either, simply write it + bclrb #7,LOCAL_EX(%a0) |do abs + bras cu_nmove |fmove code will finish +| +| Inst is fneg. Execute the negate value function on the input. +| Fall though to the fmove code. If the operand is NaN, do nothing. +| +cu_nneg: + moveb STAG(%a6),%d0 + btstl #5,%d0 |test for NaN or zero + bne wr_etemp |if either, simply write it + bchgb #7,LOCAL_EX(%a0) |do neg +| +| Inst is fmove. This code also handles all result writes. +| If bit 2 is set, round is forced to double. If it is clear, +| and bit 6 is set, round is forced to single. If both are clear, +| the round precision is found in the fpcr. If the rounding precision +| is double or single, round the result before the write. +| +cu_nmove: + moveb STAG(%a6),%d0 + andib #0xe0,%d0 |isolate stag bits + bne wr_etemp |if not norm, simply write it + btstb #2,CMDREG1B+1(%a6) |check for rd + bne cu_nmrd + btstb #6,CMDREG1B+1(%a6) |check for rs + bne cu_nmrs +| +| The move or operation is not with forced precision. Test for +| nan or inf as the input; if so, simply write it to FPn. Use the +| FPCR_MODE byte to get rounding on norms and zeros. +| +cu_nmnr: + bfextu FPCR_MODE(%a6){#0:#2},%d0 + tstb %d0 |check for extended + beq cu_wrexn |if so, just write result + cmpib #1,%d0 |check for single + beq cu_nmrs |fall through to double +| +| The move is fdmove or round precision is double. +| +cu_nmrd: + movel #2,%d0 |set up the size for denorm + movew LOCAL_EX(%a0),%d1 |compare exponent to double threshold + andw #0x7fff,%d1 + cmpw #0x3c01,%d1 + bls cu_nunfl + bfextu FPCR_MODE(%a6){#2:#2},%d1 |get rmode + orl #0x00020000,%d1 |or in rprec (double) + clrl %d0 |clear g,r,s for round + bclrb #sign_bit,LOCAL_EX(%a0) |convert to internal format + sne LOCAL_SGN(%a0) + bsrl round + bfclr LOCAL_SGN(%a0){#0:#8} + beqs cu_nmrdc + bsetb #sign_bit,LOCAL_EX(%a0) +cu_nmrdc: + movew LOCAL_EX(%a0),%d1 |check for overflow + andw #0x7fff,%d1 + cmpw #0x43ff,%d1 + bge cu_novfl |take care of overflow case + bra cu_wrexn +| +| The move is fsmove or round precision is single. +| +cu_nmrs: + movel #1,%d0 + movew LOCAL_EX(%a0),%d1 + andw #0x7fff,%d1 + cmpw #0x3f81,%d1 + bls cu_nunfl + bfextu FPCR_MODE(%a6){#2:#2},%d1 + orl #0x00010000,%d1 + clrl %d0 + bclrb #sign_bit,LOCAL_EX(%a0) + sne LOCAL_SGN(%a0) + bsrl round + bfclr LOCAL_SGN(%a0){#0:#8} + beqs cu_nmrsc + bsetb #sign_bit,LOCAL_EX(%a0) +cu_nmrsc: + movew LOCAL_EX(%a0),%d1 + andw #0x7FFF,%d1 + cmpw #0x407f,%d1 + blt cu_wrexn +| +| The operand is above precision boundaries. Use t_ovfl to +| generate the correct value. +| +cu_novfl: + bsr t_ovfl + bra cu_wrexn +| +| The operand is below precision boundaries. Use denorm to +| generate the correct value. +| +cu_nunfl: + bclrb #sign_bit,LOCAL_EX(%a0) + sne LOCAL_SGN(%a0) + bsr denorm + bfclr LOCAL_SGN(%a0){#0:#8} |change back to IEEE ext format + beqs cu_nucont + bsetb #sign_bit,LOCAL_EX(%a0) +cu_nucont: + bfextu FPCR_MODE(%a6){#2:#2},%d1 + btstb #2,CMDREG1B+1(%a6) |check for rd + bne inst_d + btstb #6,CMDREG1B+1(%a6) |check for rs + bne inst_s + swap %d1 + moveb FPCR_MODE(%a6),%d1 + lsrb #6,%d1 + swap %d1 + bra inst_sd +inst_d: + orl #0x00020000,%d1 + bra inst_sd +inst_s: + orl #0x00010000,%d1 +inst_sd: + bclrb #sign_bit,LOCAL_EX(%a0) + sne LOCAL_SGN(%a0) + bsrl round + bfclr LOCAL_SGN(%a0){#0:#8} + beqs cu_nuflp + bsetb #sign_bit,LOCAL_EX(%a0) +cu_nuflp: + btstb #inex2_bit,FPSR_EXCEPT(%a6) + beqs cu_nuninx + orl #aunfl_mask,USER_FPSR(%a6) |if the round was inex, set AUNFL +cu_nuninx: + tstl LOCAL_HI(%a0) |test for zero + bnes cu_nunzro + tstl LOCAL_LO(%a0) + bnes cu_nunzro +| +| The mantissa is zero from the denorm loop. Check sign and rmode +| to see if rounding should have occured which would leave the lsb. +| + movel USER_FPCR(%a6),%d0 + andil #0x30,%d0 |isolate rmode + cmpil #0x20,%d0 + blts cu_nzro + bnes cu_nrp +cu_nrm: + tstw LOCAL_EX(%a0) |if positive, set lsb + bges cu_nzro + btstb #7,FPCR_MODE(%a6) |check for double + beqs cu_nincs + bras cu_nincd +cu_nrp: + tstw LOCAL_EX(%a0) |if positive, set lsb + blts cu_nzro + btstb #7,FPCR_MODE(%a6) |check for double + beqs cu_nincs +cu_nincd: + orl #0x800,LOCAL_LO(%a0) |inc for double + bra cu_nunzro +cu_nincs: + orl #0x100,LOCAL_HI(%a0) |inc for single + bra cu_nunzro +cu_nzro: + orl #z_mask,USER_FPSR(%a6) + moveb STAG(%a6),%d0 + andib #0xe0,%d0 + cmpib #0x40,%d0 |check if input was tagged zero + beqs cu_numv +cu_nunzro: + orl #unfl_mask,USER_FPSR(%a6) |set unfl +cu_numv: + movel (%a0),ETEMP(%a6) + movel 4(%a0),ETEMP_HI(%a6) + movel 8(%a0),ETEMP_LO(%a6) +| +| Write the result to memory, setting the fpsr cc bits. NaN and Inf +| bypass cu_wrexn. +| +cu_wrexn: + tstw LOCAL_EX(%a0) |test for zero + beqs cu_wrzero + cmpw #0x8000,LOCAL_EX(%a0) |test for zero + bnes cu_wreon +cu_wrzero: + orl #z_mask,USER_FPSR(%a6) |set Z bit +cu_wreon: + tstw LOCAL_EX(%a0) + bpl wr_etemp + orl #neg_mask,USER_FPSR(%a6) + bra wr_etemp + +| +| HANDLE SOURCE DENORM HERE +| +| ;clear denorm stag to norm +| ;write the new tag & ete15 to the fstack +mon_dnrm: +| +| At this point, check for the cases in which normalizing the +| denorm produces incorrect results. +| + tstb DY_MO_FLG(%a6) |all cases of dyadic instructions would + bnes nrm_src |require normalization of denorm + +| At this point: +| monadic instructions: fabs = $18 fneg = $1a ftst = $3a +| fmove = $00 fsmove = $40 fdmove = $44 +| fsqrt = $05* fssqrt = $41 fdsqrt = $45 +| (*fsqrt reencoded to $05) +| + movew CMDREG1B(%a6),%d0 |get command register + andil #0x7f,%d0 |strip to only command word +| +| At this point, fabs, fneg, fsmove, fdmove, ftst, fsqrt, fssqrt, and +| fdsqrt are possible. +| For cases fabs, fneg, fsmove, and fdmove goto spos (do not normalize) +| For cases fsqrt, fssqrt, and fdsqrt goto nrm_src (do normalize) +| + btstl #0,%d0 + bnes nrm_src |weed out fsqrt instructions + st CU_ONLY(%a6) |set cu-only inst flag + bra cu_dnrm |fmove, fabs, fneg, ftst +| ;cases go to cu_dnrm +nrm_src: + bclrb #sign_bit,LOCAL_EX(%a0) + sne LOCAL_SGN(%a0) + bsr nrm_set |normalize number (exponent will go +| ; negative) + bclrb #sign_bit,LOCAL_EX(%a0) |get rid of false sign + + bfclr LOCAL_SGN(%a0){#0:#8} |change back to IEEE ext format + beqs spos + bsetb #sign_bit,LOCAL_EX(%a0) +spos: + bfclr STAG(%a6){#0:#4} |set tag to normalized, FPTE15 = 0 + bsetb #4,STAG(%a6) |set ETE15 + orb #0xf0,DNRM_FLG(%a6) +normal: + tstb DNRM_FLG(%a6) |check if any of the ops were denorms + bne ck_wrap |if so, check if it is a potential +| ;wrap-around case +fix_stk: + moveb #0xfe,CU_SAVEPC(%a6) + bclrb #E1,E_BYTE(%a6) + + clrw NMNEXC(%a6) + + st RES_FLG(%a6) |indicate that a restore is needed + rts + +| +| cu_dnrm handles all cu-only instructions (fmove, fabs, fneg, and +| ftst) completly in software without an frestore to the 040. +| +cu_dnrm: + st CU_ONLY(%a6) + movew CMDREG1B(%a6),%d0 + andib #0x3b,%d0 |isolate bits to select inst + tstb %d0 + beql cu_dmove |if zero, it is an fmove + cmpib #0x18,%d0 + beql cu_dabs |if $18, it is fabs + cmpib #0x1a,%d0 + beql cu_dneg |if $1a, it is fneg +| +| Inst is ftst. Check the source operand and set the cc's accordingly. +| No write is done, so simply rts. +| +cu_dtst: + movew LOCAL_EX(%a0),%d0 + bclrl #15,%d0 + sne LOCAL_SGN(%a0) + beqs cu_dtpo + orl #neg_mask,USER_FPSR(%a6) |set N +cu_dtpo: + cmpiw #0x7fff,%d0 |test for inf/nan + bnes cu_dtcz + tstl LOCAL_HI(%a0) + bnes cu_dtn + tstl LOCAL_LO(%a0) + bnes cu_dtn + orl #inf_mask,USER_FPSR(%a6) + rts +cu_dtn: + orl #nan_mask,USER_FPSR(%a6) + movel ETEMP_EX(%a6),FPTEMP_EX(%a6) |set up fptemp sign for +| ;snan handler + rts +cu_dtcz: + tstl LOCAL_HI(%a0) + bnel cu_dtsx + tstl LOCAL_LO(%a0) + bnel cu_dtsx + orl #z_mask,USER_FPSR(%a6) +cu_dtsx: + rts +| +| Inst is fabs. Execute the absolute value function on the input. +| Branch to the fmove code. +| +cu_dabs: + bclrb #7,LOCAL_EX(%a0) |do abs + bras cu_dmove |fmove code will finish +| +| Inst is fneg. Execute the negate value function on the input. +| Fall though to the fmove code. +| +cu_dneg: + bchgb #7,LOCAL_EX(%a0) |do neg +| +| Inst is fmove. This code also handles all result writes. +| If bit 2 is set, round is forced to double. If it is clear, +| and bit 6 is set, round is forced to single. If both are clear, +| the round precision is found in the fpcr. If the rounding precision +| is double or single, the result is zero, and the mode is checked +| to determine if the lsb of the result should be set. +| +cu_dmove: + btstb #2,CMDREG1B+1(%a6) |check for rd + bne cu_dmrd + btstb #6,CMDREG1B+1(%a6) |check for rs + bne cu_dmrs +| +| The move or operation is not with forced precision. Use the +| FPCR_MODE byte to get rounding. +| +cu_dmnr: + bfextu FPCR_MODE(%a6){#0:#2},%d0 + tstb %d0 |check for extended + beq cu_wrexd |if so, just write result + cmpib #1,%d0 |check for single + beq cu_dmrs |fall through to double +| +| The move is fdmove or round precision is double. Result is zero. +| Check rmode for rp or rm and set lsb accordingly. +| +cu_dmrd: + bfextu FPCR_MODE(%a6){#2:#2},%d1 |get rmode + tstw LOCAL_EX(%a0) |check sign + blts cu_dmdn + cmpib #3,%d1 |check for rp + bne cu_dpd |load double pos zero + bra cu_dpdr |load double pos zero w/lsb +cu_dmdn: + cmpib #2,%d1 |check for rm + bne cu_dnd |load double neg zero + bra cu_dndr |load double neg zero w/lsb +| +| The move is fsmove or round precision is single. Result is zero. +| Check for rp or rm and set lsb accordingly. +| +cu_dmrs: + bfextu FPCR_MODE(%a6){#2:#2},%d1 |get rmode + tstw LOCAL_EX(%a0) |check sign + blts cu_dmsn + cmpib #3,%d1 |check for rp + bne cu_spd |load single pos zero + bra cu_spdr |load single pos zero w/lsb +cu_dmsn: + cmpib #2,%d1 |check for rm + bne cu_snd |load single neg zero + bra cu_sndr |load single neg zero w/lsb +| +| The precision is extended, so the result in etemp is correct. +| Simply set unfl (not inex2 or aunfl) and write the result to +| the correct fp register. +cu_wrexd: + orl #unfl_mask,USER_FPSR(%a6) + tstw LOCAL_EX(%a0) + beq wr_etemp + orl #neg_mask,USER_FPSR(%a6) + bra wr_etemp +| +| These routines write +/- zero in double format. The routines +| cu_dpdr and cu_dndr set the double lsb. +| +cu_dpd: + movel #0x3c010000,LOCAL_EX(%a0) |force pos double zero + clrl LOCAL_HI(%a0) + clrl LOCAL_LO(%a0) + orl #z_mask,USER_FPSR(%a6) + orl #unfinx_mask,USER_FPSR(%a6) + bra wr_etemp +cu_dpdr: + movel #0x3c010000,LOCAL_EX(%a0) |force pos double zero + clrl LOCAL_HI(%a0) + movel #0x800,LOCAL_LO(%a0) |with lsb set + orl #unfinx_mask,USER_FPSR(%a6) + bra wr_etemp +cu_dnd: + movel #0xbc010000,LOCAL_EX(%a0) |force pos double zero + clrl LOCAL_HI(%a0) + clrl LOCAL_LO(%a0) + orl #z_mask,USER_FPSR(%a6) + orl #neg_mask,USER_FPSR(%a6) + orl #unfinx_mask,USER_FPSR(%a6) + bra wr_etemp +cu_dndr: + movel #0xbc010000,LOCAL_EX(%a0) |force pos double zero + clrl LOCAL_HI(%a0) + movel #0x800,LOCAL_LO(%a0) |with lsb set + orl #neg_mask,USER_FPSR(%a6) + orl #unfinx_mask,USER_FPSR(%a6) + bra wr_etemp +| +| These routines write +/- zero in single format. The routines +| cu_dpdr and cu_dndr set the single lsb. +| +cu_spd: + movel #0x3f810000,LOCAL_EX(%a0) |force pos single zero + clrl LOCAL_HI(%a0) + clrl LOCAL_LO(%a0) + orl #z_mask,USER_FPSR(%a6) + orl #unfinx_mask,USER_FPSR(%a6) + bra wr_etemp +cu_spdr: + movel #0x3f810000,LOCAL_EX(%a0) |force pos single zero + movel #0x100,LOCAL_HI(%a0) |with lsb set + clrl LOCAL_LO(%a0) + orl #unfinx_mask,USER_FPSR(%a6) + bra wr_etemp +cu_snd: + movel #0xbf810000,LOCAL_EX(%a0) |force pos single zero + clrl LOCAL_HI(%a0) + clrl LOCAL_LO(%a0) + orl #z_mask,USER_FPSR(%a6) + orl #neg_mask,USER_FPSR(%a6) + orl #unfinx_mask,USER_FPSR(%a6) + bra wr_etemp +cu_sndr: + movel #0xbf810000,LOCAL_EX(%a0) |force pos single zero + movel #0x100,LOCAL_HI(%a0) |with lsb set + clrl LOCAL_LO(%a0) + orl #neg_mask,USER_FPSR(%a6) + orl #unfinx_mask,USER_FPSR(%a6) + bra wr_etemp + +| +| This code checks for 16-bit overflow conditions on dyadic +| operations which are not restorable into the floating-point +| unit and must be completed in software. Basically, this +| condition exists with a very large norm and a denorm. One +| of the operands must be denormalized to enter this code. +| +| Flags used: +| DY_MO_FLG contains 0 for monadic op, $ff for dyadic +| DNRM_FLG contains $00 for neither op denormalized +| $0f for the destination op denormalized +| $f0 for the source op denormalized +| $ff for both ops denormalzed +| +| The wrap-around condition occurs for add, sub, div, and cmp +| when +| +| abs(dest_exp - src_exp) >= $8000 +| +| and for mul when +| +| (dest_exp + src_exp) < $0 +| +| we must process the operation here if this case is true. +| +| The rts following the frcfpn routine is the exit from res_func +| for this condition. The restore flag (RES_FLG) is left clear. +| No frestore is done unless an exception is to be reported. +| +| For fadd: +| if(sign_of(dest) != sign_of(src)) +| replace exponent of src with $3fff (keep sign) +| use fpu to perform dest+new_src (user's rmode and X) +| clr sticky +| else +| set sticky +| call round with user's precision and mode +| move result to fpn and wbtemp +| +| For fsub: +| if(sign_of(dest) == sign_of(src)) +| replace exponent of src with $3fff (keep sign) +| use fpu to perform dest+new_src (user's rmode and X) +| clr sticky +| else +| set sticky +| call round with user's precision and mode +| move result to fpn and wbtemp +| +| For fdiv/fsgldiv: +| if(both operands are denorm) +| restore_to_fpu; +| if(dest is norm) +| force_ovf; +| else(dest is denorm) +| force_unf: +| +| For fcmp: +| if(dest is norm) +| N = sign_of(dest); +| else(dest is denorm) +| N = sign_of(src); +| +| For fmul: +| if(both operands are denorm) +| force_unf; +| if((dest_exp + src_exp) < 0) +| force_unf: +| else +| restore_to_fpu; +| +| local equates: + .set addcode,0x22 + .set subcode,0x28 + .set mulcode,0x23 + .set divcode,0x20 + .set cmpcode,0x38 +ck_wrap: + | tstb DY_MO_FLG(%a6) ;check for fsqrt + beq fix_stk |if zero, it is fsqrt + movew CMDREG1B(%a6),%d0 + andiw #0x3b,%d0 |strip to command bits + cmpiw #addcode,%d0 + beq wrap_add + cmpiw #subcode,%d0 + beq wrap_sub + cmpiw #mulcode,%d0 + beq wrap_mul + cmpiw #cmpcode,%d0 + beq wrap_cmp +| +| Inst is fdiv. +| +wrap_div: + cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm, + beq fix_stk |restore to fpu +| +| One of the ops is denormalized. Test for wrap condition +| and force the result. +| + cmpb #0x0f,DNRM_FLG(%a6) |check for dest denorm + bnes div_srcd +div_destd: + bsrl ckinf_ns + bne fix_stk + bfextu ETEMP_EX(%a6){#1:#15},%d0 |get src exp (always pos) + bfexts FPTEMP_EX(%a6){#1:#15},%d1 |get dest exp (always neg) + subl %d1,%d0 |subtract dest from src + cmpl #0x7fff,%d0 + blt fix_stk |if less, not wrap case + clrb WBTEMP_SGN(%a6) + movew ETEMP_EX(%a6),%d0 |find the sign of the result + movew FPTEMP_EX(%a6),%d1 + eorw %d1,%d0 + andiw #0x8000,%d0 + beq force_unf + st WBTEMP_SGN(%a6) + bra force_unf + +ckinf_ns: + moveb STAG(%a6),%d0 |check source tag for inf or nan + bra ck_in_com +ckinf_nd: + moveb DTAG(%a6),%d0 |check destination tag for inf or nan +ck_in_com: + andib #0x60,%d0 |isolate tag bits + cmpb #0x40,%d0 |is it inf? + beq nan_or_inf |not wrap case + cmpb #0x60,%d0 |is it nan? + beq nan_or_inf |yes, not wrap case? + cmpb #0x20,%d0 |is it a zero? + beq nan_or_inf |yes + clrl %d0 + rts |then ; it is either a zero of norm, +| ;check wrap case +nan_or_inf: + moveql #-1,%d0 + rts + + + +div_srcd: + bsrl ckinf_nd + bne fix_stk + bfextu FPTEMP_EX(%a6){#1:#15},%d0 |get dest exp (always pos) + bfexts ETEMP_EX(%a6){#1:#15},%d1 |get src exp (always neg) + subl %d1,%d0 |subtract src from dest + cmpl #0x8000,%d0 + blt fix_stk |if less, not wrap case + clrb WBTEMP_SGN(%a6) + movew ETEMP_EX(%a6),%d0 |find the sign of the result + movew FPTEMP_EX(%a6),%d1 + eorw %d1,%d0 + andiw #0x8000,%d0 + beqs force_ovf + st WBTEMP_SGN(%a6) +| +| This code handles the case of the instruction resulting in +| an overflow condition. +| +force_ovf: + bclrb #E1,E_BYTE(%a6) + orl #ovfl_inx_mask,USER_FPSR(%a6) + clrw NMNEXC(%a6) + leal WBTEMP(%a6),%a0 |point a0 to memory location + movew CMDREG1B(%a6),%d0 + btstl #6,%d0 |test for forced precision + beqs frcovf_fpcr + btstl #2,%d0 |check for double + bnes frcovf_dbl + movel #0x1,%d0 |inst is forced single + bras frcovf_rnd +frcovf_dbl: + movel #0x2,%d0 |inst is forced double + bras frcovf_rnd +frcovf_fpcr: + bfextu FPCR_MODE(%a6){#0:#2},%d0 |inst not forced - use fpcr prec +frcovf_rnd: + +| The 881/882 does not set inex2 for the following case, so the +| line is commented out to be compatible with 881/882 +| tst.b %d0 +| beq.b frcovf_x +| or.l #inex2_mask,USER_FPSR(%a6) ;if prec is s or d, set inex2 + +|frcovf_x: + bsrl ovf_res |get correct result based on +| ;round precision/mode. This +| ;sets FPSR_CC correctly +| ;returns in external format + bfclr WBTEMP_SGN(%a6){#0:#8} + beq frcfpn + bsetb #sign_bit,WBTEMP_EX(%a6) + bra frcfpn +| +| Inst is fadd. +| +wrap_add: + cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm, + beq fix_stk |restore to fpu +| +| One of the ops is denormalized. Test for wrap condition +| and complete the instruction. +| + cmpb #0x0f,DNRM_FLG(%a6) |check for dest denorm + bnes add_srcd +add_destd: + bsrl ckinf_ns + bne fix_stk + bfextu ETEMP_EX(%a6){#1:#15},%d0 |get src exp (always pos) + bfexts FPTEMP_EX(%a6){#1:#15},%d1 |get dest exp (always neg) + subl %d1,%d0 |subtract dest from src + cmpl #0x8000,%d0 + blt fix_stk |if less, not wrap case + bra add_wrap +add_srcd: + bsrl ckinf_nd + bne fix_stk + bfextu FPTEMP_EX(%a6){#1:#15},%d0 |get dest exp (always pos) + bfexts ETEMP_EX(%a6){#1:#15},%d1 |get src exp (always neg) + subl %d1,%d0 |subtract src from dest + cmpl #0x8000,%d0 + blt fix_stk |if less, not wrap case +| +| Check the signs of the operands. If they are unlike, the fpu +| can be used to add the norm and 1.0 with the sign of the +| denorm and it will correctly generate the result in extended +| precision. We can then call round with no sticky and the result +| will be correct for the user's rounding mode and precision. If +| the signs are the same, we call round with the sticky bit set +| and the result will be correctfor the user's rounding mode and +| precision. +| +add_wrap: + movew ETEMP_EX(%a6),%d0 + movew FPTEMP_EX(%a6),%d1 + eorw %d1,%d0 + andiw #0x8000,%d0 + beq add_same +| +| The signs are unlike. +| + cmpb #0x0f,DNRM_FLG(%a6) |is dest the denorm? + bnes add_u_srcd + movew FPTEMP_EX(%a6),%d0 + andiw #0x8000,%d0 + orw #0x3fff,%d0 |force the exponent to +/- 1 + movew %d0,FPTEMP_EX(%a6) |in the denorm + movel USER_FPCR(%a6),%d0 + andil #0x30,%d0 + fmovel %d0,%fpcr |set up users rmode and X + fmovex ETEMP(%a6),%fp0 + faddx FPTEMP(%a6),%fp0 + leal WBTEMP(%a6),%a0 |point a0 to wbtemp in frame + fmovel %fpsr,%d1 + orl %d1,USER_FPSR(%a6) |capture cc's and inex from fadd + fmovex %fp0,WBTEMP(%a6) |write result to memory + lsrl #4,%d0 |put rmode in lower 2 bits + movel USER_FPCR(%a6),%d1 + andil #0xc0,%d1 + lsrl #6,%d1 |put precision in upper word + swap %d1 + orl %d0,%d1 |set up for round call + clrl %d0 |force sticky to zero + bclrb #sign_bit,WBTEMP_EX(%a6) + sne WBTEMP_SGN(%a6) + bsrl round |round result to users rmode & prec + bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format + beq frcfpnr + bsetb #sign_bit,WBTEMP_EX(%a6) + bra frcfpnr +add_u_srcd: + movew ETEMP_EX(%a6),%d0 + andiw #0x8000,%d0 + orw #0x3fff,%d0 |force the exponent to +/- 1 + movew %d0,ETEMP_EX(%a6) |in the denorm + movel USER_FPCR(%a6),%d0 + andil #0x30,%d0 + fmovel %d0,%fpcr |set up users rmode and X + fmovex ETEMP(%a6),%fp0 + faddx FPTEMP(%a6),%fp0 + fmovel %fpsr,%d1 + orl %d1,USER_FPSR(%a6) |capture cc's and inex from fadd + leal WBTEMP(%a6),%a0 |point a0 to wbtemp in frame + fmovex %fp0,WBTEMP(%a6) |write result to memory + lsrl #4,%d0 |put rmode in lower 2 bits + movel USER_FPCR(%a6),%d1 + andil #0xc0,%d1 + lsrl #6,%d1 |put precision in upper word + swap %d1 + orl %d0,%d1 |set up for round call + clrl %d0 |force sticky to zero + bclrb #sign_bit,WBTEMP_EX(%a6) + sne WBTEMP_SGN(%a6) |use internal format for round + bsrl round |round result to users rmode & prec + bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format + beq frcfpnr + bsetb #sign_bit,WBTEMP_EX(%a6) + bra frcfpnr +| +| Signs are alike: +| +add_same: + cmpb #0x0f,DNRM_FLG(%a6) |is dest the denorm? + bnes add_s_srcd +add_s_destd: + leal ETEMP(%a6),%a0 + movel USER_FPCR(%a6),%d0 + andil #0x30,%d0 + lsrl #4,%d0 |put rmode in lower 2 bits + movel USER_FPCR(%a6),%d1 + andil #0xc0,%d1 + lsrl #6,%d1 |put precision in upper word + swap %d1 + orl %d0,%d1 |set up for round call + movel #0x20000000,%d0 |set sticky for round + bclrb #sign_bit,ETEMP_EX(%a6) + sne ETEMP_SGN(%a6) + bsrl round |round result to users rmode & prec + bfclr ETEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format + beqs add_s_dclr + bsetb #sign_bit,ETEMP_EX(%a6) +add_s_dclr: + leal WBTEMP(%a6),%a0 + movel ETEMP(%a6),(%a0) |write result to wbtemp + movel ETEMP_HI(%a6),4(%a0) + movel ETEMP_LO(%a6),8(%a0) + tstw ETEMP_EX(%a6) + bgt add_ckovf + orl #neg_mask,USER_FPSR(%a6) + bra add_ckovf +add_s_srcd: + leal FPTEMP(%a6),%a0 + movel USER_FPCR(%a6),%d0 + andil #0x30,%d0 + lsrl #4,%d0 |put rmode in lower 2 bits + movel USER_FPCR(%a6),%d1 + andil #0xc0,%d1 + lsrl #6,%d1 |put precision in upper word + swap %d1 + orl %d0,%d1 |set up for round call + movel #0x20000000,%d0 |set sticky for round + bclrb #sign_bit,FPTEMP_EX(%a6) + sne FPTEMP_SGN(%a6) + bsrl round |round result to users rmode & prec + bfclr FPTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format + beqs add_s_sclr + bsetb #sign_bit,FPTEMP_EX(%a6) +add_s_sclr: + leal WBTEMP(%a6),%a0 + movel FPTEMP(%a6),(%a0) |write result to wbtemp + movel FPTEMP_HI(%a6),4(%a0) + movel FPTEMP_LO(%a6),8(%a0) + tstw FPTEMP_EX(%a6) + bgt add_ckovf + orl #neg_mask,USER_FPSR(%a6) +add_ckovf: + movew WBTEMP_EX(%a6),%d0 + andiw #0x7fff,%d0 + cmpiw #0x7fff,%d0 + bne frcfpnr +| +| The result has overflowed to $7fff exponent. Set I, ovfl, +| and aovfl, and clr the mantissa (incorrectly set by the +| round routine.) +| + orl #inf_mask+ovfl_inx_mask,USER_FPSR(%a6) + clrl 4(%a0) + bra frcfpnr +| +| Inst is fsub. +| +wrap_sub: + cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm, + beq fix_stk |restore to fpu +| +| One of the ops is denormalized. Test for wrap condition +| and complete the instruction. +| + cmpb #0x0f,DNRM_FLG(%a6) |check for dest denorm + bnes sub_srcd +sub_destd: + bsrl ckinf_ns + bne fix_stk + bfextu ETEMP_EX(%a6){#1:#15},%d0 |get src exp (always pos) + bfexts FPTEMP_EX(%a6){#1:#15},%d1 |get dest exp (always neg) + subl %d1,%d0 |subtract src from dest + cmpl #0x8000,%d0 + blt fix_stk |if less, not wrap case + bra sub_wrap +sub_srcd: + bsrl ckinf_nd + bne fix_stk + bfextu FPTEMP_EX(%a6){#1:#15},%d0 |get dest exp (always pos) + bfexts ETEMP_EX(%a6){#1:#15},%d1 |get src exp (always neg) + subl %d1,%d0 |subtract dest from src + cmpl #0x8000,%d0 + blt fix_stk |if less, not wrap case +| +| Check the signs of the operands. If they are alike, the fpu +| can be used to subtract from the norm 1.0 with the sign of the +| denorm and it will correctly generate the result in extended +| precision. We can then call round with no sticky and the result +| will be correct for the user's rounding mode and precision. If +| the signs are unlike, we call round with the sticky bit set +| and the result will be correctfor the user's rounding mode and +| precision. +| +sub_wrap: + movew ETEMP_EX(%a6),%d0 + movew FPTEMP_EX(%a6),%d1 + eorw %d1,%d0 + andiw #0x8000,%d0 + bne sub_diff +| +| The signs are alike. +| + cmpb #0x0f,DNRM_FLG(%a6) |is dest the denorm? + bnes sub_u_srcd + movew FPTEMP_EX(%a6),%d0 + andiw #0x8000,%d0 + orw #0x3fff,%d0 |force the exponent to +/- 1 + movew %d0,FPTEMP_EX(%a6) |in the denorm + movel USER_FPCR(%a6),%d0 + andil #0x30,%d0 + fmovel %d0,%fpcr |set up users rmode and X + fmovex FPTEMP(%a6),%fp0 + fsubx ETEMP(%a6),%fp0 + fmovel %fpsr,%d1 + orl %d1,USER_FPSR(%a6) |capture cc's and inex from fadd + leal WBTEMP(%a6),%a0 |point a0 to wbtemp in frame + fmovex %fp0,WBTEMP(%a6) |write result to memory + lsrl #4,%d0 |put rmode in lower 2 bits + movel USER_FPCR(%a6),%d1 + andil #0xc0,%d1 + lsrl #6,%d1 |put precision in upper word + swap %d1 + orl %d0,%d1 |set up for round call + clrl %d0 |force sticky to zero + bclrb #sign_bit,WBTEMP_EX(%a6) + sne WBTEMP_SGN(%a6) + bsrl round |round result to users rmode & prec + bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format + beq frcfpnr + bsetb #sign_bit,WBTEMP_EX(%a6) + bra frcfpnr +sub_u_srcd: + movew ETEMP_EX(%a6),%d0 + andiw #0x8000,%d0 + orw #0x3fff,%d0 |force the exponent to +/- 1 + movew %d0,ETEMP_EX(%a6) |in the denorm + movel USER_FPCR(%a6),%d0 + andil #0x30,%d0 + fmovel %d0,%fpcr |set up users rmode and X + fmovex FPTEMP(%a6),%fp0 + fsubx ETEMP(%a6),%fp0 + fmovel %fpsr,%d1 + orl %d1,USER_FPSR(%a6) |capture cc's and inex from fadd + leal WBTEMP(%a6),%a0 |point a0 to wbtemp in frame + fmovex %fp0,WBTEMP(%a6) |write result to memory + lsrl #4,%d0 |put rmode in lower 2 bits + movel USER_FPCR(%a6),%d1 + andil #0xc0,%d1 + lsrl #6,%d1 |put precision in upper word + swap %d1 + orl %d0,%d1 |set up for round call + clrl %d0 |force sticky to zero + bclrb #sign_bit,WBTEMP_EX(%a6) + sne WBTEMP_SGN(%a6) + bsrl round |round result to users rmode & prec + bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format + beq frcfpnr + bsetb #sign_bit,WBTEMP_EX(%a6) + bra frcfpnr +| +| Signs are unlike: +| +sub_diff: + cmpb #0x0f,DNRM_FLG(%a6) |is dest the denorm? + bnes sub_s_srcd +sub_s_destd: + leal ETEMP(%a6),%a0 + movel USER_FPCR(%a6),%d0 + andil #0x30,%d0 + lsrl #4,%d0 |put rmode in lower 2 bits + movel USER_FPCR(%a6),%d1 + andil #0xc0,%d1 + lsrl #6,%d1 |put precision in upper word + swap %d1 + orl %d0,%d1 |set up for round call + movel #0x20000000,%d0 |set sticky for round +| +| Since the dest is the denorm, the sign is the opposite of the +| norm sign. +| + eoriw #0x8000,ETEMP_EX(%a6) |flip sign on result + tstw ETEMP_EX(%a6) + bgts sub_s_dwr + orl #neg_mask,USER_FPSR(%a6) +sub_s_dwr: + bclrb #sign_bit,ETEMP_EX(%a6) + sne ETEMP_SGN(%a6) + bsrl round |round result to users rmode & prec + bfclr ETEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format + beqs sub_s_dclr + bsetb #sign_bit,ETEMP_EX(%a6) +sub_s_dclr: + leal WBTEMP(%a6),%a0 + movel ETEMP(%a6),(%a0) |write result to wbtemp + movel ETEMP_HI(%a6),4(%a0) + movel ETEMP_LO(%a6),8(%a0) + bra sub_ckovf +sub_s_srcd: + leal FPTEMP(%a6),%a0 + movel USER_FPCR(%a6),%d0 + andil #0x30,%d0 + lsrl #4,%d0 |put rmode in lower 2 bits + movel USER_FPCR(%a6),%d1 + andil #0xc0,%d1 + lsrl #6,%d1 |put precision in upper word + swap %d1 + orl %d0,%d1 |set up for round call + movel #0x20000000,%d0 |set sticky for round + bclrb #sign_bit,FPTEMP_EX(%a6) + sne FPTEMP_SGN(%a6) + bsrl round |round result to users rmode & prec + bfclr FPTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format + beqs sub_s_sclr + bsetb #sign_bit,FPTEMP_EX(%a6) +sub_s_sclr: + leal WBTEMP(%a6),%a0 + movel FPTEMP(%a6),(%a0) |write result to wbtemp + movel FPTEMP_HI(%a6),4(%a0) + movel FPTEMP_LO(%a6),8(%a0) + tstw FPTEMP_EX(%a6) + bgt sub_ckovf + orl #neg_mask,USER_FPSR(%a6) +sub_ckovf: + movew WBTEMP_EX(%a6),%d0 + andiw #0x7fff,%d0 + cmpiw #0x7fff,%d0 + bne frcfpnr +| +| The result has overflowed to $7fff exponent. Set I, ovfl, +| and aovfl, and clr the mantissa (incorrectly set by the +| round routine.) +| + orl #inf_mask+ovfl_inx_mask,USER_FPSR(%a6) + clrl 4(%a0) + bra frcfpnr +| +| Inst is fcmp. +| +wrap_cmp: + cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm, + beq fix_stk |restore to fpu +| +| One of the ops is denormalized. Test for wrap condition +| and complete the instruction. +| + cmpb #0x0f,DNRM_FLG(%a6) |check for dest denorm + bnes cmp_srcd +cmp_destd: + bsrl ckinf_ns + bne fix_stk + bfextu ETEMP_EX(%a6){#1:#15},%d0 |get src exp (always pos) + bfexts FPTEMP_EX(%a6){#1:#15},%d1 |get dest exp (always neg) + subl %d1,%d0 |subtract dest from src + cmpl #0x8000,%d0 + blt fix_stk |if less, not wrap case + tstw ETEMP_EX(%a6) |set N to ~sign_of(src) + bge cmp_setn + rts +cmp_srcd: + bsrl ckinf_nd + bne fix_stk + bfextu FPTEMP_EX(%a6){#1:#15},%d0 |get dest exp (always pos) + bfexts ETEMP_EX(%a6){#1:#15},%d1 |get src exp (always neg) + subl %d1,%d0 |subtract src from dest + cmpl #0x8000,%d0 + blt fix_stk |if less, not wrap case + tstw FPTEMP_EX(%a6) |set N to sign_of(dest) + blt cmp_setn + rts +cmp_setn: + orl #neg_mask,USER_FPSR(%a6) + rts + +| +| Inst is fmul. +| +wrap_mul: + cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm, + beq force_unf |force an underflow (really!) +| +| One of the ops is denormalized. Test for wrap condition +| and complete the instruction. +| + cmpb #0x0f,DNRM_FLG(%a6) |check for dest denorm + bnes mul_srcd +mul_destd: + bsrl ckinf_ns + bne fix_stk + bfextu ETEMP_EX(%a6){#1:#15},%d0 |get src exp (always pos) + bfexts FPTEMP_EX(%a6){#1:#15},%d1 |get dest exp (always neg) + addl %d1,%d0 |subtract dest from src + bgt fix_stk + bra force_unf +mul_srcd: + bsrl ckinf_nd + bne fix_stk + bfextu FPTEMP_EX(%a6){#1:#15},%d0 |get dest exp (always pos) + bfexts ETEMP_EX(%a6){#1:#15},%d1 |get src exp (always neg) + addl %d1,%d0 |subtract src from dest + bgt fix_stk + +| +| This code handles the case of the instruction resulting in +| an underflow condition. +| +force_unf: + bclrb #E1,E_BYTE(%a6) + orl #unfinx_mask,USER_FPSR(%a6) + clrw NMNEXC(%a6) + clrb WBTEMP_SGN(%a6) + movew ETEMP_EX(%a6),%d0 |find the sign of the result + movew FPTEMP_EX(%a6),%d1 + eorw %d1,%d0 + andiw #0x8000,%d0 + beqs frcunfcont + st WBTEMP_SGN(%a6) +frcunfcont: + lea WBTEMP(%a6),%a0 |point a0 to memory location + movew CMDREG1B(%a6),%d0 + btstl #6,%d0 |test for forced precision + beqs frcunf_fpcr + btstl #2,%d0 |check for double + bnes frcunf_dbl + movel #0x1,%d0 |inst is forced single + bras frcunf_rnd +frcunf_dbl: + movel #0x2,%d0 |inst is forced double + bras frcunf_rnd +frcunf_fpcr: + bfextu FPCR_MODE(%a6){#0:#2},%d0 |inst not forced - use fpcr prec +frcunf_rnd: + bsrl unf_sub |get correct result based on +| ;round precision/mode. This +| ;sets FPSR_CC correctly + bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format + beqs frcfpn + bsetb #sign_bit,WBTEMP_EX(%a6) + bra frcfpn + +| +| Write the result to the user's fpn. All results must be HUGE to be +| written; otherwise the results would have overflowed or underflowed. +| If the rounding precision is single or double, the ovf_res routine +| is needed to correctly supply the max value. +| +frcfpnr: + movew CMDREG1B(%a6),%d0 + btstl #6,%d0 |test for forced precision + beqs frcfpn_fpcr + btstl #2,%d0 |check for double + bnes frcfpn_dbl + movel #0x1,%d0 |inst is forced single + bras frcfpn_rnd +frcfpn_dbl: + movel #0x2,%d0 |inst is forced double + bras frcfpn_rnd +frcfpn_fpcr: + bfextu FPCR_MODE(%a6){#0:#2},%d0 |inst not forced - use fpcr prec + tstb %d0 + beqs frcfpn |if extended, write what you got +frcfpn_rnd: + bclrb #sign_bit,WBTEMP_EX(%a6) + sne WBTEMP_SGN(%a6) + bsrl ovf_res |get correct result based on +| ;round precision/mode. This +| ;sets FPSR_CC correctly + bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format + beqs frcfpn_clr + bsetb #sign_bit,WBTEMP_EX(%a6) +frcfpn_clr: + orl #ovfinx_mask,USER_FPSR(%a6) +| +| Perform the write. +| +frcfpn: + bfextu CMDREG1B(%a6){#6:#3},%d0 |extract fp destination register + cmpib #3,%d0 + bles frc0123 |check if dest is fp0-fp3 + movel #7,%d1 + subl %d0,%d1 + clrl %d0 + bsetl %d1,%d0 + fmovemx WBTEMP(%a6),%d0 + rts +frc0123: + cmpib #0,%d0 + beqs frc0_dst + cmpib #1,%d0 + beqs frc1_dst + cmpib #2,%d0 + beqs frc2_dst +frc3_dst: + movel WBTEMP_EX(%a6),USER_FP3(%a6) + movel WBTEMP_HI(%a6),USER_FP3+4(%a6) + movel WBTEMP_LO(%a6),USER_FP3+8(%a6) + rts +frc2_dst: + movel WBTEMP_EX(%a6),USER_FP2(%a6) + movel WBTEMP_HI(%a6),USER_FP2+4(%a6) + movel WBTEMP_LO(%a6),USER_FP2+8(%a6) + rts +frc1_dst: + movel WBTEMP_EX(%a6),USER_FP1(%a6) + movel WBTEMP_HI(%a6),USER_FP1+4(%a6) + movel WBTEMP_LO(%a6),USER_FP1+8(%a6) + rts +frc0_dst: + movel WBTEMP_EX(%a6),USER_FP0(%a6) + movel WBTEMP_HI(%a6),USER_FP0+4(%a6) + movel WBTEMP_LO(%a6),USER_FP0+8(%a6) + rts + +| +| Write etemp to fpn. +| A check is made on enabled and signalled snan exceptions, +| and the destination is not overwritten if this condition exists. +| This code is designed to make fmoveins of unsupported data types +| faster. +| +wr_etemp: + btstb #snan_bit,FPSR_EXCEPT(%a6) |if snan is set, and + beqs fmoveinc |enabled, force restore + btstb #snan_bit,FPCR_ENABLE(%a6) |and don't overwrite + beqs fmoveinc |the dest + movel ETEMP_EX(%a6),FPTEMP_EX(%a6) |set up fptemp sign for +| ;snan handler + tstb ETEMP(%a6) |check for negative + blts snan_neg + rts +snan_neg: + orl #neg_bit,USER_FPSR(%a6) |snan is negative; set N + rts +fmoveinc: + clrw NMNEXC(%a6) + bclrb #E1,E_BYTE(%a6) + moveb STAG(%a6),%d0 |check if stag is inf + andib #0xe0,%d0 + cmpib #0x40,%d0 + bnes fminc_cnan + orl #inf_mask,USER_FPSR(%a6) |if inf, nothing yet has set I + tstw LOCAL_EX(%a0) |check sign + bges fminc_con + orl #neg_mask,USER_FPSR(%a6) + bra fminc_con +fminc_cnan: + cmpib #0x60,%d0 |check if stag is NaN + bnes fminc_czero + orl #nan_mask,USER_FPSR(%a6) |if nan, nothing yet has set NaN + movel ETEMP_EX(%a6),FPTEMP_EX(%a6) |set up fptemp sign for +| ;snan handler + tstw LOCAL_EX(%a0) |check sign + bges fminc_con + orl #neg_mask,USER_FPSR(%a6) + bra fminc_con +fminc_czero: + cmpib #0x20,%d0 |check if zero + bnes fminc_con + orl #z_mask,USER_FPSR(%a6) |if zero, set Z + tstw LOCAL_EX(%a0) |check sign + bges fminc_con + orl #neg_mask,USER_FPSR(%a6) +fminc_con: + bfextu CMDREG1B(%a6){#6:#3},%d0 |extract fp destination register + cmpib #3,%d0 + bles fp0123 |check if dest is fp0-fp3 + movel #7,%d1 + subl %d0,%d1 + clrl %d0 + bsetl %d1,%d0 + fmovemx ETEMP(%a6),%d0 + rts + +fp0123: + cmpib #0,%d0 + beqs fp0_dst + cmpib #1,%d0 + beqs fp1_dst + cmpib #2,%d0 + beqs fp2_dst +fp3_dst: + movel ETEMP_EX(%a6),USER_FP3(%a6) + movel ETEMP_HI(%a6),USER_FP3+4(%a6) + movel ETEMP_LO(%a6),USER_FP3+8(%a6) + rts +fp2_dst: + movel ETEMP_EX(%a6),USER_FP2(%a6) + movel ETEMP_HI(%a6),USER_FP2+4(%a6) + movel ETEMP_LO(%a6),USER_FP2+8(%a6) + rts +fp1_dst: + movel ETEMP_EX(%a6),USER_FP1(%a6) + movel ETEMP_HI(%a6),USER_FP1+4(%a6) + movel ETEMP_LO(%a6),USER_FP1+8(%a6) + rts +fp0_dst: + movel ETEMP_EX(%a6),USER_FP0(%a6) + movel ETEMP_HI(%a6),USER_FP0+4(%a6) + movel ETEMP_LO(%a6),USER_FP0+8(%a6) + rts + +opclass3: + st CU_ONLY(%a6) + movew CMDREG1B(%a6),%d0 |check if packed moveout + andiw #0x0c00,%d0 |isolate last 2 bits of size field + cmpiw #0x0c00,%d0 |if size is 011 or 111, it is packed + beq pack_out |else it is norm or denorm + bra mv_out + + +| +| MOVE OUT +| + +mv_tbl: + .long li + .long sgp + .long xp + .long mvout_end |should never be taken + .long wi + .long dp + .long bi + .long mvout_end |should never be taken +mv_out: + bfextu CMDREG1B(%a6){#3:#3},%d1 |put source specifier in d1 + leal mv_tbl,%a0 + movel %a0@(%d1:l:4),%a0 + jmp (%a0) + +| +| This exit is for move-out to memory. The aunfl bit is +| set if the result is inex and unfl is signalled. +| +mvout_end: + btstb #inex2_bit,FPSR_EXCEPT(%a6) + beqs no_aufl + btstb #unfl_bit,FPSR_EXCEPT(%a6) + beqs no_aufl + bsetb #aunfl_bit,FPSR_AEXCEPT(%a6) +no_aufl: + clrw NMNEXC(%a6) + bclrb #E1,E_BYTE(%a6) + fmovel #0,%FPSR |clear any cc bits from res_func +| +| Return ETEMP to extended format from internal extended format so +| that gen_except will have a correctly signed value for ovfl/unfl +| handlers. +| + bfclr ETEMP_SGN(%a6){#0:#8} + beqs mvout_con + bsetb #sign_bit,ETEMP_EX(%a6) +mvout_con: + rts +| +| This exit is for move-out to int register. The aunfl bit is +| not set in any case for this move. +| +mvouti_end: + clrw NMNEXC(%a6) + bclrb #E1,E_BYTE(%a6) + fmovel #0,%FPSR |clear any cc bits from res_func +| +| Return ETEMP to extended format from internal extended format so +| that gen_except will have a correctly signed value for ovfl/unfl +| handlers. +| + bfclr ETEMP_SGN(%a6){#0:#8} + beqs mvouti_con + bsetb #sign_bit,ETEMP_EX(%a6) +mvouti_con: + rts +| +| li is used to handle a long integer source specifier +| + +li: + moveql #4,%d0 |set byte count + + btstb #7,STAG(%a6) |check for extended denorm + bne int_dnrm |if so, branch + + fmovemx ETEMP(%a6),%fp0-%fp0 + fcmpd #0x41dfffffffc00000,%fp0 +| 41dfffffffc00000 in dbl prec = 401d0000fffffffe00000000 in ext prec + fbge lo_plrg + fcmpd #0xc1e0000000000000,%fp0 +| c1e0000000000000 in dbl prec = c01e00008000000000000000 in ext prec + fble lo_nlrg +| +| at this point, the answer is between the largest pos and neg values +| + movel USER_FPCR(%a6),%d1 |use user's rounding mode + andil #0x30,%d1 + fmovel %d1,%fpcr + fmovel %fp0,L_SCR1(%a6) |let the 040 perform conversion + fmovel %fpsr,%d1 + orl %d1,USER_FPSR(%a6) |capture inex2/ainex if set + bra int_wrt + + +lo_plrg: + movel #0x7fffffff,L_SCR1(%a6) |answer is largest positive int + fbeq int_wrt |exact answer + fcmpd #0x41dfffffffe00000,%fp0 +| 41dfffffffe00000 in dbl prec = 401d0000ffffffff00000000 in ext prec + fbge int_operr |set operr + bra int_inx |set inexact + +lo_nlrg: + movel #0x80000000,L_SCR1(%a6) + fbeq int_wrt |exact answer + fcmpd #0xc1e0000000100000,%fp0 +| c1e0000000100000 in dbl prec = c01e00008000000080000000 in ext prec + fblt int_operr |set operr + bra int_inx |set inexact + +| +| wi is used to handle a word integer source specifier +| + +wi: + moveql #2,%d0 |set byte count + + btstb #7,STAG(%a6) |check for extended denorm + bne int_dnrm |branch if so + + fmovemx ETEMP(%a6),%fp0-%fp0 + fcmps #0x46fffe00,%fp0 +| 46fffe00 in sgl prec = 400d0000fffe000000000000 in ext prec + fbge wo_plrg + fcmps #0xc7000000,%fp0 +| c7000000 in sgl prec = c00e00008000000000000000 in ext prec + fble wo_nlrg + +| +| at this point, the answer is between the largest pos and neg values +| + movel USER_FPCR(%a6),%d1 |use user's rounding mode + andil #0x30,%d1 + fmovel %d1,%fpcr + fmovew %fp0,L_SCR1(%a6) |let the 040 perform conversion + fmovel %fpsr,%d1 + orl %d1,USER_FPSR(%a6) |capture inex2/ainex if set + bra int_wrt + +wo_plrg: + movew #0x7fff,L_SCR1(%a6) |answer is largest positive int + fbeq int_wrt |exact answer + fcmps #0x46ffff00,%fp0 +| 46ffff00 in sgl prec = 400d0000ffff000000000000 in ext prec + fbge int_operr |set operr + bra int_inx |set inexact + +wo_nlrg: + movew #0x8000,L_SCR1(%a6) + fbeq int_wrt |exact answer + fcmps #0xc7000080,%fp0 +| c7000080 in sgl prec = c00e00008000800000000000 in ext prec + fblt int_operr |set operr + bra int_inx |set inexact + +| +| bi is used to handle a byte integer source specifier +| + +bi: + moveql #1,%d0 |set byte count + + btstb #7,STAG(%a6) |check for extended denorm + bne int_dnrm |branch if so + + fmovemx ETEMP(%a6),%fp0-%fp0 + fcmps #0x42fe0000,%fp0 +| 42fe0000 in sgl prec = 40050000fe00000000000000 in ext prec + fbge by_plrg + fcmps #0xc3000000,%fp0 +| c3000000 in sgl prec = c00600008000000000000000 in ext prec + fble by_nlrg + +| +| at this point, the answer is between the largest pos and neg values +| + movel USER_FPCR(%a6),%d1 |use user's rounding mode + andil #0x30,%d1 + fmovel %d1,%fpcr + fmoveb %fp0,L_SCR1(%a6) |let the 040 perform conversion + fmovel %fpsr,%d1 + orl %d1,USER_FPSR(%a6) |capture inex2/ainex if set + bra int_wrt + +by_plrg: + moveb #0x7f,L_SCR1(%a6) |answer is largest positive int + fbeq int_wrt |exact answer + fcmps #0x42ff0000,%fp0 +| 42ff0000 in sgl prec = 40050000ff00000000000000 in ext prec + fbge int_operr |set operr + bra int_inx |set inexact + +by_nlrg: + moveb #0x80,L_SCR1(%a6) + fbeq int_wrt |exact answer + fcmps #0xc3008000,%fp0 +| c3008000 in sgl prec = c00600008080000000000000 in ext prec + fblt int_operr |set operr + bra int_inx |set inexact + +| +| Common integer routines +| +| int_drnrm---account for possible nonzero result for round up with positive +| operand and round down for negative answer. In the first case (result = 1) +| byte-width (store in d0) of result must be honored. In the second case, +| -1 in L_SCR1(a6) will cover all contingencies (FMOVE.B/W/L out). + +int_dnrm: + movel #0,L_SCR1(%a6) | initialize result to 0 + bfextu FPCR_MODE(%a6){#2:#2},%d1 | d1 is the rounding mode + cmpb #2,%d1 + bmis int_inx | if RN or RZ, done + bnes int_rp | if RP, continue below + tstw ETEMP(%a6) | RM: store -1 in L_SCR1 if src is negative + bpls int_inx | otherwise result is 0 + movel #-1,L_SCR1(%a6) + bras int_inx +int_rp: + tstw ETEMP(%a6) | RP: store +1 of proper width in L_SCR1 if +| ; source is greater than 0 + bmis int_inx | otherwise, result is 0 + lea L_SCR1(%a6),%a1 | a1 is address of L_SCR1 + addal %d0,%a1 | offset by destination width -1 + subal #1,%a1 + bsetb #0,(%a1) | set low bit at a1 address +int_inx: + oril #inx2a_mask,USER_FPSR(%a6) + bras int_wrt +int_operr: + fmovemx %fp0-%fp0,FPTEMP(%a6) |FPTEMP must contain the extended +| ;precision source that needs to be +| ;converted to integer this is required +| ;if the operr exception is enabled. +| ;set operr/aiop (no inex2 on int ovfl) + + oril #opaop_mask,USER_FPSR(%a6) +| ;fall through to perform int_wrt +int_wrt: + movel EXC_EA(%a6),%a1 |load destination address + tstl %a1 |check to see if it is a dest register + beqs wrt_dn |write data register + lea L_SCR1(%a6),%a0 |point to supervisor source address + bsrl mem_write + bra mvouti_end + +wrt_dn: + movel %d0,-(%sp) |d0 currently contains the size to write + bsrl get_fline |get_fline returns Dn in d0 + andiw #0x7,%d0 |isolate register + movel (%sp)+,%d1 |get size + cmpil #4,%d1 |most frequent case + beqs sz_long + cmpil #2,%d1 + bnes sz_con + orl #8,%d0 |add 'word' size to register# + bras sz_con +sz_long: + orl #0x10,%d0 |add 'long' size to register# +sz_con: + movel %d0,%d1 |reg_dest expects size:reg in d1 + bsrl reg_dest |load proper data register + bra mvouti_end +xp: + lea ETEMP(%a6),%a0 + bclrb #sign_bit,LOCAL_EX(%a0) + sne LOCAL_SGN(%a0) + btstb #7,STAG(%a6) |check for extended denorm + bne xdnrm + clrl %d0 + bras do_fp |do normal case +sgp: + lea ETEMP(%a6),%a0 + bclrb #sign_bit,LOCAL_EX(%a0) + sne LOCAL_SGN(%a0) + btstb #7,STAG(%a6) |check for extended denorm + bne sp_catas |branch if so + movew LOCAL_EX(%a0),%d0 + lea sp_bnds,%a1 + cmpw (%a1),%d0 + blt sp_under + cmpw 2(%a1),%d0 + bgt sp_over + movel #1,%d0 |set destination format to single + bras do_fp |do normal case +dp: + lea ETEMP(%a6),%a0 + bclrb #sign_bit,LOCAL_EX(%a0) + sne LOCAL_SGN(%a0) + + btstb #7,STAG(%a6) |check for extended denorm + bne dp_catas |branch if so + + movew LOCAL_EX(%a0),%d0 + lea dp_bnds,%a1 + + cmpw (%a1),%d0 + blt dp_under + cmpw 2(%a1),%d0 + bgt dp_over + + movel #2,%d0 |set destination format to double +| ;fall through to do_fp +| +do_fp: + bfextu FPCR_MODE(%a6){#2:#2},%d1 |rnd mode in d1 + swap %d0 |rnd prec in upper word + addl %d0,%d1 |d1 has PREC/MODE info + + clrl %d0 |clear g,r,s + + bsrl round |round + + movel %a0,%a1 + movel EXC_EA(%a6),%a0 + + bfextu CMDREG1B(%a6){#3:#3},%d1 |extract destination format +| ;at this point only the dest +| ;formats sgl, dbl, ext are +| ;possible + cmpb #2,%d1 + bgts ddbl |double=5, extended=2, single=1 + bnes dsgl +| ;fall through to dext +dext: + bsrl dest_ext + bra mvout_end +dsgl: + bsrl dest_sgl + bra mvout_end +ddbl: + bsrl dest_dbl + bra mvout_end + +| +| Handle possible denorm or catastrophic underflow cases here +| +xdnrm: + bsr set_xop |initialize WBTEMP + bsetb #wbtemp15_bit,WB_BYTE(%a6) |set wbtemp15 + + movel %a0,%a1 + movel EXC_EA(%a6),%a0 |a0 has the destination pointer + bsrl dest_ext |store to memory + bsetb #unfl_bit,FPSR_EXCEPT(%a6) + bra mvout_end + +sp_under: + bsetb #etemp15_bit,STAG(%a6) + + cmpw 4(%a1),%d0 + blts sp_catas |catastrophic underflow case + + movel #1,%d0 |load in round precision + movel #sgl_thresh,%d1 |load in single denorm threshold + bsrl dpspdnrm |expects d1 to have the proper +| ;denorm threshold + bsrl dest_sgl |stores value to destination + bsetb #unfl_bit,FPSR_EXCEPT(%a6) + bra mvout_end |exit + +dp_under: + bsetb #etemp15_bit,STAG(%a6) + + cmpw 4(%a1),%d0 + blts dp_catas |catastrophic underflow case + + movel #dbl_thresh,%d1 |load in double precision threshold + movel #2,%d0 + bsrl dpspdnrm |expects d1 to have proper +| ;denorm threshold +| ;expects d0 to have round precision + bsrl dest_dbl |store value to destination + bsetb #unfl_bit,FPSR_EXCEPT(%a6) + bra mvout_end |exit + +| +| Handle catastrophic underflow cases here +| +sp_catas: +| Temp fix for z bit set in unf_sub + movel USER_FPSR(%a6),-(%a7) + + movel #1,%d0 |set round precision to sgl + + bsrl unf_sub |a0 points to result + + movel (%a7)+,USER_FPSR(%a6) + + movel #1,%d0 + subw %d0,LOCAL_EX(%a0) |account for difference between +| ;denorm/norm bias + + movel %a0,%a1 |a1 has the operand input + movel EXC_EA(%a6),%a0 |a0 has the destination pointer + + bsrl dest_sgl |store the result + oril #unfinx_mask,USER_FPSR(%a6) + bra mvout_end + +dp_catas: +| Temp fix for z bit set in unf_sub + movel USER_FPSR(%a6),-(%a7) + + movel #2,%d0 |set round precision to dbl + bsrl unf_sub |a0 points to result + + movel (%a7)+,USER_FPSR(%a6) + + movel #1,%d0 + subw %d0,LOCAL_EX(%a0) |account for difference between +| ;denorm/norm bias + + movel %a0,%a1 |a1 has the operand input + movel EXC_EA(%a6),%a0 |a0 has the destination pointer + + bsrl dest_dbl |store the result + oril #unfinx_mask,USER_FPSR(%a6) + bra mvout_end + +| +| Handle catastrophic overflow cases here +| +sp_over: +| Temp fix for z bit set in unf_sub + movel USER_FPSR(%a6),-(%a7) + + movel #1,%d0 + leal FP_SCR1(%a6),%a0 |use FP_SCR1 for creating result + movel ETEMP_EX(%a6),(%a0) + movel ETEMP_HI(%a6),4(%a0) + movel ETEMP_LO(%a6),8(%a0) + bsrl ovf_res + + movel (%a7)+,USER_FPSR(%a6) + + movel %a0,%a1 + movel EXC_EA(%a6),%a0 + bsrl dest_sgl + orl #ovfinx_mask,USER_FPSR(%a6) + bra mvout_end + +dp_over: +| Temp fix for z bit set in ovf_res + movel USER_FPSR(%a6),-(%a7) + + movel #2,%d0 + leal FP_SCR1(%a6),%a0 |use FP_SCR1 for creating result + movel ETEMP_EX(%a6),(%a0) + movel ETEMP_HI(%a6),4(%a0) + movel ETEMP_LO(%a6),8(%a0) + bsrl ovf_res + + movel (%a7)+,USER_FPSR(%a6) + + movel %a0,%a1 + movel EXC_EA(%a6),%a0 + bsrl dest_dbl + orl #ovfinx_mask,USER_FPSR(%a6) + bra mvout_end + +| +| DPSPDNRM +| +| This subroutine takes an extended normalized number and denormalizes +| it to the given round precision. This subroutine also decrements +| the input operand's exponent by 1 to account for the fact that +| dest_sgl or dest_dbl expects a normalized number's bias. +| +| Input: a0 points to a normalized number in internal extended format +| d0 is the round precision (=1 for sgl; =2 for dbl) +| d1 is the the single precision or double precision +| denorm threshold +| +| Output: (In the format for dest_sgl or dest_dbl) +| a0 points to the destination +| a1 points to the operand +| +| Exceptions: Reports inexact 2 exception by setting USER_FPSR bits +| +dpspdnrm: + movel %d0,-(%a7) |save round precision + clrl %d0 |clear initial g,r,s + bsrl dnrm_lp |careful with d0, it's needed by round + + bfextu FPCR_MODE(%a6){#2:#2},%d1 |get rounding mode + swap %d1 + movew 2(%a7),%d1 |set rounding precision + swap %d1 |at this point d1 has PREC/MODE info + bsrl round |round result, sets the inex bit in +| ;USER_FPSR if needed + + movew #1,%d0 + subw %d0,LOCAL_EX(%a0) |account for difference in denorm +| ;vs norm bias + + movel %a0,%a1 |a1 has the operand input + movel EXC_EA(%a6),%a0 |a0 has the destination pointer + addw #4,%a7 |pop stack + rts +| +| SET_XOP initialized WBTEMP with the value pointed to by a0 +| input: a0 points to input operand in the internal extended format +| +set_xop: + movel LOCAL_EX(%a0),WBTEMP_EX(%a6) + movel LOCAL_HI(%a0),WBTEMP_HI(%a6) + movel LOCAL_LO(%a0),WBTEMP_LO(%a6) + bfclr WBTEMP_SGN(%a6){#0:#8} + beqs sxop + bsetb #sign_bit,WBTEMP_EX(%a6) +sxop: + bfclr STAG(%a6){#5:#4} |clear wbtm66,wbtm1,wbtm0,sbit + rts +| +| P_MOVE +| +p_movet: + .long p_move + .long p_movez + .long p_movei + .long p_moven + .long p_move +p_regd: + .long p_dyd0 + .long p_dyd1 + .long p_dyd2 + .long p_dyd3 + .long p_dyd4 + .long p_dyd5 + .long p_dyd6 + .long p_dyd7 + +pack_out: + leal p_movet,%a0 |load jmp table address + movew STAG(%a6),%d0 |get source tag + bfextu %d0{#16:#3},%d0 |isolate source bits + movel (%a0,%d0.w*4),%a0 |load a0 with routine label for tag + jmp (%a0) |go to the routine + +p_write: + movel #0x0c,%d0 |get byte count + movel EXC_EA(%a6),%a1 |get the destination address + bsr mem_write |write the user's destination + moveb #0,CU_SAVEPC(%a6) |set the cu save pc to all 0's + +| +| Also note that the dtag must be set to norm here - this is because +| the 040 uses the dtag to execute the correct microcode. +| + bfclr DTAG(%a6){#0:#3} |set dtag to norm + + rts + +| Notes on handling of special case (zero, inf, and nan) inputs: +| 1. Operr is not signalled if the k-factor is greater than 18. +| 2. Per the manual, status bits are not set. +| + +p_move: + movew CMDREG1B(%a6),%d0 + btstl #kfact_bit,%d0 |test for dynamic k-factor + beqs statick |if clear, k-factor is static +dynamick: + bfextu %d0{#25:#3},%d0 |isolate register for dynamic k-factor + lea p_regd,%a0 + movel %a0@(%d0:l:4),%a0 + jmp (%a0) +statick: + andiw #0x007f,%d0 |get k-factor + bfexts %d0{#25:#7},%d0 |sign extend d0 for bindec + leal ETEMP(%a6),%a0 |a0 will point to the packed decimal + bsrl bindec |perform the convert; data at a6 + leal FP_SCR1(%a6),%a0 |load a0 with result address + bral p_write +p_movez: + leal ETEMP(%a6),%a0 |a0 will point to the packed decimal + clrw 2(%a0) |clear lower word of exp + clrl 4(%a0) |load second lword of ZERO + clrl 8(%a0) |load third lword of ZERO + bra p_write |go write results +p_movei: + fmovel #0,%FPSR |clear aiop + leal ETEMP(%a6),%a0 |a0 will point to the packed decimal + clrw 2(%a0) |clear lower word of exp + bra p_write |go write the result +p_moven: + leal ETEMP(%a6),%a0 |a0 will point to the packed decimal + clrw 2(%a0) |clear lower word of exp + bra p_write |go write the result + +| +| Routines to read the dynamic k-factor from Dn. +| +p_dyd0: + movel USER_D0(%a6),%d0 + bras statick +p_dyd1: + movel USER_D1(%a6),%d0 + bras statick +p_dyd2: + movel %d2,%d0 + bras statick +p_dyd3: + movel %d3,%d0 + bras statick +p_dyd4: + movel %d4,%d0 + bras statick +p_dyd5: + movel %d5,%d0 + bras statick +p_dyd6: + movel %d6,%d0 + bra statick +p_dyd7: + movel %d7,%d0 + bra statick + + |end diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/round.S linux/arch/m68k/fpsp040/round.S --- v1.3.93/linux/arch/m68k/fpsp040/round.S Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/fpsp040/round.S Sat Feb 24 22:58:43 1996 @@ -0,0 +1,649 @@ +| +| round.sa 3.4 7/29/91 +| +| handle rounding and normalization tasks +| +| +| +| Copyright (C) Motorola, Inc. 1990 +| All Rights Reserved +| +| THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA +| The copyright notice above does not evidence any +| actual or intended publication of such source code. + +|ROUND idnt 2,1 | Motorola 040 Floating Point Software Package + + |section 8 + + .include "fpsp.h" + +| +| round --- round result according to precision/mode +| +| a0 points to the input operand in the internal extended format +| d1(high word) contains rounding precision: +| ext = $0000xxxx +| sgl = $0001xxxx +| dbl = $0002xxxx +| d1(low word) contains rounding mode: +| RN = $xxxx0000 +| RZ = $xxxx0001 +| RM = $xxxx0010 +| RP = $xxxx0011 +| d0{31:29} contains the g,r,s bits (extended) +| +| On return the value pointed to by a0 is correctly rounded, +| a0 is preserved and the g-r-s bits in d0 are cleared. +| The result is not typed - the tag field is invalid. The +| result is still in the internal extended format. +| +| The INEX bit of USER_FPSR will be set if the rounded result was +| inexact (i.e. if any of the g-r-s bits were set). +| + + .global round +round: +| If g=r=s=0 then result is exact and round is done, else set +| the inex flag in status reg and continue. +| + bsrs ext_grs |this subroutine looks at the +| :rounding precision and sets +| ;the appropriate g-r-s bits. + tstl %d0 |if grs are zero, go force + bne rnd_cont |lower bits to zero for size + + swap %d1 |set up d1.w for round prec. + bra truncate + +rnd_cont: +| +| Use rounding mode as an index into a jump table for these modes. +| + orl #inx2a_mask,USER_FPSR(%a6) |set inex2/ainex + lea mode_tab,%a1 + movel (%a1,%d1.w*4),%a1 + jmp (%a1) +| +| Jump table indexed by rounding mode in d1.w. All following assumes +| grs != 0. +| +mode_tab: + .long rnd_near + .long rnd_zero + .long rnd_mnus + .long rnd_plus +| +| ROUND PLUS INFINITY +| +| If sign of fp number = 0 (positive), then add 1 to l. +| +rnd_plus: + swap %d1 |set up d1 for round prec. + tstb LOCAL_SGN(%a0) |check for sign + bmi truncate |if positive then truncate + movel #0xffffffff,%d0 |force g,r,s to be all f's + lea add_to_l,%a1 + movel (%a1,%d1.w*4),%a1 + jmp (%a1) +| +| ROUND MINUS INFINITY +| +| If sign of fp number = 1 (negative), then add 1 to l. +| +rnd_mnus: + swap %d1 |set up d1 for round prec. + tstb LOCAL_SGN(%a0) |check for sign + bpl truncate |if negative then truncate + movel #0xffffffff,%d0 |force g,r,s to be all f's + lea add_to_l,%a1 + movel (%a1,%d1.w*4),%a1 + jmp (%a1) +| +| ROUND ZERO +| +| Always truncate. +rnd_zero: + swap %d1 |set up d1 for round prec. + bra truncate +| +| +| ROUND NEAREST +| +| If (g=1), then add 1 to l and if (r=s=0), then clear l +| Note that this will round to even in case of a tie. +| +rnd_near: + swap %d1 |set up d1 for round prec. + asll #1,%d0 |shift g-bit to c-bit + bcc truncate |if (g=1) then + lea add_to_l,%a1 + movel (%a1,%d1.w*4),%a1 + jmp (%a1) + +| +| ext_grs --- extract guard, round and sticky bits +| +| Input: d1 = PREC:ROUND +| Output: d0{31:29}= guard, round, sticky +| +| The ext_grs extract the guard/round/sticky bits according to the +| selected rounding precision. It is called by the round subroutine +| only. All registers except d0 are kept intact. d0 becomes an +| updated guard,round,sticky in d0{31:29} +| +| Notes: the ext_grs uses the round PREC, and therefore has to swap d1 +| prior to usage, and needs to restore d1 to original. +| +ext_grs: + swap %d1 |have d1.w point to round precision + cmpiw #0,%d1 + bnes sgl_or_dbl + bras end_ext_grs + +sgl_or_dbl: + moveml %d2/%d3,-(%a7) |make some temp registers + cmpiw #1,%d1 + bnes grs_dbl +grs_sgl: + bfextu LOCAL_HI(%a0){#24:#2},%d3 |sgl prec. g-r are 2 bits right + movel #30,%d2 |of the sgl prec. limits + lsll %d2,%d3 |shift g-r bits to MSB of d3 + movel LOCAL_HI(%a0),%d2 |get word 2 for s-bit test + andil #0x0000003f,%d2 |s bit is the or of all other + bnes st_stky |bits to the right of g-r + tstl LOCAL_LO(%a0) |test lower mantissa + bnes st_stky |if any are set, set sticky + tstl %d0 |test original g,r,s + bnes st_stky |if any are set, set sticky + bras end_sd |if words 3 and 4 are clr, exit +grs_dbl: + bfextu LOCAL_LO(%a0){#21:#2},%d3 |dbl-prec. g-r are 2 bits right + movel #30,%d2 |of the dbl prec. limits + lsll %d2,%d3 |shift g-r bits to the MSB of d3 + movel LOCAL_LO(%a0),%d2 |get lower mantissa for s-bit test + andil #0x000001ff,%d2 |s bit is the or-ing of all + bnes st_stky |other bits to the right of g-r + tstl %d0 |test word original g,r,s + bnes st_stky |if any are set, set sticky + bras end_sd |if clear, exit +st_stky: + bset #rnd_stky_bit,%d3 +end_sd: + movel %d3,%d0 |return grs to d0 + moveml (%a7)+,%d2/%d3 |restore scratch registers +end_ext_grs: + swap %d1 |restore d1 to original + rts + +|******************* Local Equates + .set ad_1_sgl,0x00000100 | constant to add 1 to l-bit in sgl prec + .set ad_1_dbl,0x00000800 | constant to add 1 to l-bit in dbl prec + + +|Jump table for adding 1 to the l-bit indexed by rnd prec + +add_to_l: + .long add_ext + .long add_sgl + .long add_dbl + .long add_dbl +| +| ADD SINGLE +| +add_sgl: + addl #ad_1_sgl,LOCAL_HI(%a0) + bccs scc_clr |no mantissa overflow + roxrw LOCAL_HI(%a0) |shift v-bit back in + roxrw LOCAL_HI+2(%a0) |shift v-bit back in + addw #0x1,LOCAL_EX(%a0) |and incr exponent +scc_clr: + tstl %d0 |test for rs = 0 + bnes sgl_done + andiw #0xfe00,LOCAL_HI+2(%a0) |clear the l-bit +sgl_done: + andil #0xffffff00,LOCAL_HI(%a0) |truncate bits beyond sgl limit + clrl LOCAL_LO(%a0) |clear d2 + rts + +| +| ADD EXTENDED +| +add_ext: + addql #1,LOCAL_LO(%a0) |add 1 to l-bit + bccs xcc_clr |test for carry out + addql #1,LOCAL_HI(%a0) |propogate carry + bccs xcc_clr + roxrw LOCAL_HI(%a0) |mant is 0 so restore v-bit + roxrw LOCAL_HI+2(%a0) |mant is 0 so restore v-bit + roxrw LOCAL_LO(%a0) + roxrw LOCAL_LO+2(%a0) + addw #0x1,LOCAL_EX(%a0) |and inc exp +xcc_clr: + tstl %d0 |test rs = 0 + bnes add_ext_done + andib #0xfe,LOCAL_LO+3(%a0) |clear the l bit +add_ext_done: + rts +| +| ADD DOUBLE +| +add_dbl: + addl #ad_1_dbl,LOCAL_LO(%a0) + bccs dcc_clr + addql #1,LOCAL_HI(%a0) |propogate carry + bccs dcc_clr + roxrw LOCAL_HI(%a0) |mant is 0 so restore v-bit + roxrw LOCAL_HI+2(%a0) |mant is 0 so restore v-bit + roxrw LOCAL_LO(%a0) + roxrw LOCAL_LO+2(%a0) + addw #0x1,LOCAL_EX(%a0) |incr exponent +dcc_clr: + tstl %d0 |test for rs = 0 + bnes dbl_done + andiw #0xf000,LOCAL_LO+2(%a0) |clear the l-bit + +dbl_done: + andil #0xfffff800,LOCAL_LO(%a0) |truncate bits beyond dbl limit + rts + +error: + rts +| +| Truncate all other bits +| +trunct: + .long end_rnd + .long sgl_done + .long dbl_done + .long dbl_done + +truncate: + lea trunct,%a1 + movel (%a1,%d1.w*4),%a1 + jmp (%a1) + +end_rnd: + rts + +| +| NORMALIZE +| +| These routines (nrm_zero & nrm_set) normalize the unnorm. This +| is done by shifting the mantissa left while decrementing the +| exponent. +| +| NRM_SET shifts and decrements until there is a 1 set in the integer +| bit of the mantissa (msb in d1). +| +| NRM_ZERO shifts and decrements until there is a 1 set in the integer +| bit of the mantissa (msb in d1) unless this would mean the exponent +| would go less than 0. In that case the number becomes a denorm - the +| exponent (d0) is set to 0 and the mantissa (d1 & d2) is not +| normalized. +| +| Note that both routines have been optimized (for the worst case) and +| therefore do not have the easy to follow decrement/shift loop. +| +| NRM_ZERO +| +| Distance to first 1 bit in mantissa = X +| Distance to 0 from exponent = Y +| If X < Y +| Then +| nrm_set +| Else +| shift mantissa by Y +| set exponent = 0 +| +|input: +| FP_SCR1 = exponent, ms mantissa part, ls mantissa part +|output: +| L_SCR1{4} = fpte15 or ete15 bit +| + .global nrm_zero +nrm_zero: + movew LOCAL_EX(%a0),%d0 + cmpw #64,%d0 |see if exp > 64 + bmis d0_less + bsr nrm_set |exp > 64 so exp won't exceed 0 + rts +d0_less: + moveml %d2/%d3/%d5/%d6,-(%a7) + movel LOCAL_HI(%a0),%d1 + movel LOCAL_LO(%a0),%d2 + + bfffo %d1{#0:#32},%d3 |get the distance to the first 1 +| ;in ms mant + beqs ms_clr |branch if no bits were set + cmpw %d3,%d0 |of X>Y + bmis greater |then exp will go past 0 (neg) if +| ;it is just shifted + bsr nrm_set |else exp won't go past 0 + moveml (%a7)+,%d2/%d3/%d5/%d6 + rts +greater: + movel %d2,%d6 |save ls mant in d6 + lsll %d0,%d2 |shift ls mant by count + lsll %d0,%d1 |shift ms mant by count + movel #32,%d5 + subl %d0,%d5 |make op a denorm by shifting bits + lsrl %d5,%d6 |by the number in the exp, then +| ;set exp = 0. + orl %d6,%d1 |shift the ls mant bits into the ms mant + movel #0,%d0 |same as if decremented exp to 0 +| ;while shifting + movew %d0,LOCAL_EX(%a0) + movel %d1,LOCAL_HI(%a0) + movel %d2,LOCAL_LO(%a0) + moveml (%a7)+,%d2/%d3/%d5/%d6 + rts +ms_clr: + bfffo %d2{#0:#32},%d3 |check if any bits set in ls mant + beqs all_clr |branch if none set + addw #32,%d3 + cmpw %d3,%d0 |if X>Y + bmis greater |then branch + bsr nrm_set |else exp won't go past 0 + moveml (%a7)+,%d2/%d3/%d5/%d6 + rts +all_clr: + movew #0,LOCAL_EX(%a0) |no mantissa bits set. Set exp = 0. + moveml (%a7)+,%d2/%d3/%d5/%d6 + rts +| +| NRM_SET +| + .global nrm_set +nrm_set: + movel %d7,-(%a7) + bfffo LOCAL_HI(%a0){#0:#32},%d7 |find first 1 in ms mant to d7) + beqs lower |branch if ms mant is all 0's + + movel %d6,-(%a7) + + subw %d7,LOCAL_EX(%a0) |sub exponent by count + movel LOCAL_HI(%a0),%d0 |d0 has ms mant + movel LOCAL_LO(%a0),%d1 |d1 has ls mant + + lsll %d7,%d0 |shift first 1 to j bit position + movel %d1,%d6 |copy ls mant into d6 + lsll %d7,%d6 |shift ls mant by count + movel %d6,LOCAL_LO(%a0) |store ls mant into memory + moveql #32,%d6 + subl %d7,%d6 |continue shift + lsrl %d6,%d1 |shift off all bits but those that will +| ;be shifted into ms mant + orl %d1,%d0 |shift the ls mant bits into the ms mant + movel %d0,LOCAL_HI(%a0) |store ms mant into memory + moveml (%a7)+,%d7/%d6 |restore registers + rts + +| +| We get here if ms mant was = 0, and we assume ls mant has bits +| set (otherwise this would have been tagged a zero not a denorm). +| +lower: + movew LOCAL_EX(%a0),%d0 |d0 has exponent + movel LOCAL_LO(%a0),%d1 |d1 has ls mant + subw #32,%d0 |account for ms mant being all zeros + bfffo %d1{#0:#32},%d7 |find first 1 in ls mant to d7) + subw %d7,%d0 |subtract shift count from exp + lsll %d7,%d1 |shift first 1 to integer bit in ms mant + movew %d0,LOCAL_EX(%a0) |store ms mant + movel %d1,LOCAL_HI(%a0) |store exp + clrl LOCAL_LO(%a0) |clear ls mant + movel (%a7)+,%d7 + rts +| +| denorm --- denormalize an intermediate result +| +| Used by underflow. +| +| Input: +| a0 points to the operand to be denormalized +| (in the internal extended format) +| +| d0: rounding precision +| Output: +| a0 points to the denormalized result +| (in the internal extended format) +| +| d0 is guard,round,sticky +| +| d0 comes into this routine with the rounding precision. It +| is then loaded with the denormalized exponent threshold for the +| rounding precision. +| + + .global denorm +denorm: + btstb #6,LOCAL_EX(%a0) |check for exponents between $7fff-$4000 + beqs no_sgn_ext + bsetb #7,LOCAL_EX(%a0) |sign extend if it is so +no_sgn_ext: + + cmpib #0,%d0 |if 0 then extended precision + bnes not_ext |else branch + + clrl %d1 |load d1 with ext threshold + clrl %d0 |clear the sticky flag + bsr dnrm_lp |denormalize the number + tstb %d1 |check for inex + beq no_inex |if clr, no inex + bras dnrm_inex |if set, set inex + +not_ext: + cmpil #1,%d0 |if 1 then single precision + beqs load_sgl |else must be 2, double prec + +load_dbl: + movew #dbl_thresh,%d1 |put copy of threshold in d1 + movel %d1,%d0 |copy d1 into d0 + subw LOCAL_EX(%a0),%d0 |diff = threshold - exp + cmpw #67,%d0 |if diff > 67 (mant + grs bits) + bpls chk_stky |then branch (all bits would be +| ; shifted off in denorm routine) + clrl %d0 |else clear the sticky flag + bsr dnrm_lp |denormalize the number + tstb %d1 |check flag + beqs no_inex |if clr, no inex + bras dnrm_inex |if set, set inex + +load_sgl: + movew #sgl_thresh,%d1 |put copy of threshold in d1 + movel %d1,%d0 |copy d1 into d0 + subw LOCAL_EX(%a0),%d0 |diff = threshold - exp + cmpw #67,%d0 |if diff > 67 (mant + grs bits) + bpls chk_stky |then branch (all bits would be +| ; shifted off in denorm routine) + clrl %d0 |else clear the sticky flag + bsr dnrm_lp |denormalize the number + tstb %d1 |check flag + beqs no_inex |if clr, no inex + bras dnrm_inex |if set, set inex + +chk_stky: + tstl LOCAL_HI(%a0) |check for any bits set + bnes set_stky + tstl LOCAL_LO(%a0) |check for any bits set + bnes set_stky + bras clr_mant +set_stky: + orl #inx2a_mask,USER_FPSR(%a6) |set inex2/ainex + movel #0x20000000,%d0 |set sticky bit in return value +clr_mant: + movew %d1,LOCAL_EX(%a0) |load exp with threshold + movel #0,LOCAL_HI(%a0) |set d1 = 0 (ms mantissa) + movel #0,LOCAL_LO(%a0) |set d2 = 0 (ms mantissa) + rts +dnrm_inex: + orl #inx2a_mask,USER_FPSR(%a6) |set inex2/ainex +no_inex: + rts + +| +| dnrm_lp --- normalize exponent/mantissa to specified threshhold +| +| Input: +| a0 points to the operand to be denormalized +| d0{31:29} initial guard,round,sticky +| d1{15:0} denormalization threshold +| Output: +| a0 points to the denormalized operand +| d0{31:29} final guard,round,sticky +| d1.b inexact flag: all ones means inexact result +| +| The LOCAL_LO and LOCAL_GRS parts of the value are copied to FP_SCR2 +| so that bfext can be used to extract the new low part of the mantissa. +| Dnrm_lp can be called with a0 pointing to ETEMP or WBTEMP and there +| is no LOCAL_GRS scratch word following it on the fsave frame. +| + .global dnrm_lp +dnrm_lp: + movel %d2,-(%sp) |save d2 for temp use + btstb #E3,E_BYTE(%a6) |test for type E3 exception + beqs not_E3 |not type E3 exception + bfextu WBTEMP_GRS(%a6){#6:#3},%d2 |extract guard,round, sticky bit + movel #29,%d0 + lsll %d0,%d2 |shift g,r,s to their postions + movel %d2,%d0 +not_E3: + movel (%sp)+,%d2 |restore d2 + movel LOCAL_LO(%a0),FP_SCR2+LOCAL_LO(%a6) + movel %d0,FP_SCR2+LOCAL_GRS(%a6) + movel %d1,%d0 |copy the denorm threshold + subw LOCAL_EX(%a0),%d1 |d1 = threshold - uns exponent + bles no_lp |d1 <= 0 + cmpw #32,%d1 + blts case_1 |0 = d1 < 32 + cmpw #64,%d1 + blts case_2 |32 <= d1 < 64 + bra case_3 |d1 >= 64 +| +| No normalization necessary +| +no_lp: + clrb %d1 |set no inex2 reported + movel FP_SCR2+LOCAL_GRS(%a6),%d0 |restore original g,r,s + rts +| +| case (0= 64 Force the exponent to be the denorm threshold with the +| correct sign. +| +case_3: + movew %d0,LOCAL_EX(%a0) + tstw LOCAL_SGN(%a0) + bges c3con +c3neg: + orl #0x80000000,LOCAL_EX(%a0) +c3con: + cmpw #64,%d1 + beqs sixty_four + cmpw #65,%d1 + beqs sixty_five +| +| Shift value is out of range. Set d1 for inex2 flag and +| return a zero with the given threshold. +| + clrl LOCAL_HI(%a0) + clrl LOCAL_LO(%a0) + movel #0x20000000,%d0 + st %d1 + rts + +sixty_four: + movel LOCAL_HI(%a0),%d0 + bfextu %d0{#2:#30},%d1 + andil #0xc0000000,%d0 + bras c3com + +sixty_five: + movel LOCAL_HI(%a0),%d0 + bfextu %d0{#1:#31},%d1 + andil #0x80000000,%d0 + lsrl #1,%d0 |shift high bit into R bit + +c3com: + tstl %d1 + bnes c3ssticky + tstl LOCAL_LO(%a0) + bnes c3ssticky + tstb FP_SCR2+LOCAL_GRS(%a6) + bnes c3ssticky + clrb %d1 + bras c3end + +c3ssticky: + bsetl #rnd_stky_bit,%d0 + st %d1 +c3end: + clrl LOCAL_HI(%a0) + clrl LOCAL_LO(%a0) + rts + + |end diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/sacos.S linux/arch/m68k/fpsp040/sacos.S --- v1.3.93/linux/arch/m68k/fpsp040/sacos.S Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/fpsp040/sacos.S Sat Feb 24 22:58:43 1996 @@ -0,0 +1,115 @@ +| +| sacos.sa 3.3 12/19/90 +| +| Description: The entry point sAcos computes the inverse cosine of +| an input argument; sAcosd does the same except for denormalized +| input. +| +| Input: Double-extended number X in location pointed to +| by address register a0. +| +| Output: The value arccos(X) returned in floating-point register Fp0. +| +| Accuracy and Monotonicity: The returned result is within 3 ulps in +| 64 significant bit, i.e. within 0.5001 ulp to 53 bits if the +| result is subsequently rounded to double precision. The +| result is provably monotonic in double precision. +| +| Speed: The program sCOS takes approximately 310 cycles. +| +| Algorithm: +| +| ACOS +| 1. If |X| >= 1, go to 3. +| +| 2. (|X| < 1) Calculate acos(X) by +| z := (1-X) / (1+X) +| acos(X) = 2 * atan( sqrt(z) ). +| Exit. +| +| 3. If |X| > 1, go to 5. +| +| 4. (|X| = 1) If X > 0, return 0. Otherwise, return Pi. Exit. +| +| 5. (|X| > 1) Generate an invalid operation by 0 * infinity. +| Exit. +| + +| Copyright (C) Motorola, Inc. 1990 +| All Rights Reserved +| +| THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA +| The copyright notice above does not evidence any +| actual or intended publication of such source code. + +|SACOS idnt 2,1 | Motorola 040 Floating Point Software Package + + |section 8 + +PI: .long 0x40000000,0xC90FDAA2,0x2168C235,0x00000000 +PIBY2: .long 0x3FFF0000,0xC90FDAA2,0x2168C235,0x00000000 + + |xref t_operr + |xref t_frcinx + |xref satan + + .global sacosd +sacosd: +|--ACOS(X) = PI/2 FOR DENORMALIZED X + fmovel %d1,%fpcr | ...load user's rounding mode/precision + fmovex PIBY2,%fp0 + bra t_frcinx + + .global sacos +sacos: + fmovex (%a0),%fp0 | ...LOAD INPUT + + movel (%a0),%d0 | ...pack exponent with upper 16 fraction + movew 4(%a0),%d0 + andil #0x7FFFFFFF,%d0 + cmpil #0x3FFF8000,%d0 + bges ACOSBIG + +|--THIS IS THE USUAL CASE, |X| < 1 +|--ACOS(X) = 2 * ATAN( SQRT( (1-X)/(1+X) ) ) + + fmoves #0x3F800000,%fp1 + faddx %fp0,%fp1 | ...1+X + fnegx %fp0 | ... -X + fadds #0x3F800000,%fp0 | ...1-X + fdivx %fp1,%fp0 | ...(1-X)/(1+X) + fsqrtx %fp0 | ...SQRT((1-X)/(1+X)) + fmovemx %fp0-%fp0,(%a0) | ...overwrite input + movel %d1,-(%sp) |save original users fpcr + clrl %d1 + bsr satan | ...ATAN(SQRT([1-X]/[1+X])) + fmovel (%sp)+,%fpcr |restore users exceptions + faddx %fp0,%fp0 | ...2 * ATAN( STUFF ) + bra t_frcinx + +ACOSBIG: + fabsx %fp0 + fcmps #0x3F800000,%fp0 + fbgt t_operr |cause an operr exception + +|--|X| = 1, ACOS(X) = 0 OR PI + movel (%a0),%d0 | ...pack exponent with upper 16 fraction + movew 4(%a0),%d0 + cmpl #0,%d0 |D0 has original exponent+fraction + bgts ACOSP1 + +|--X = -1 +|Returns PI and inexact exception + fmovex PI,%fp0 + fmovel %d1,%FPCR + fadds #0x00800000,%fp0 |cause an inexact exception to be put +| ;into the 040 - will not trap until next +| ;fp inst. + bra t_frcinx + +ACOSP1: + fmovel %d1,%FPCR + fmoves #0x00000000,%fp0 + rts |Facos ; of +1 is exact + + |end diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/sasin.S linux/arch/m68k/fpsp040/sasin.S --- v1.3.93/linux/arch/m68k/fpsp040/sasin.S Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/fpsp040/sasin.S Sat Feb 24 22:58:43 1996 @@ -0,0 +1,104 @@ +| +| sasin.sa 3.3 12/19/90 +| +| Description: The entry point sAsin computes the inverse sine of +| an input argument; sAsind does the same except for denormalized +| input. +| +| Input: Double-extended number X in location pointed to +| by address register a0. +| +| Output: The value arcsin(X) returned in floating-point register Fp0. +| +| Accuracy and Monotonicity: The returned result is within 3 ulps in +| 64 significant bit, i.e. within 0.5001 ulp to 53 bits if the +| result is subsequently rounded to double precision. The +| result is provably monotonic in double precision. +| +| Speed: The program sASIN takes approximately 310 cycles. +| +| Algorithm: +| +| ASIN +| 1. If |X| >= 1, go to 3. +| +| 2. (|X| < 1) Calculate asin(X) by +| z := sqrt( [1-X][1+X] ) +| asin(X) = atan( x / z ). +| Exit. +| +| 3. If |X| > 1, go to 5. +| +| 4. (|X| = 1) sgn := sign(X), return asin(X) := sgn * Pi/2. Exit. +| +| 5. (|X| > 1) Generate an invalid operation by 0 * infinity. +| Exit. +| + +| Copyright (C) Motorola, Inc. 1990 +| All Rights Reserved +| +| THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA +| The copyright notice above does not evidence any +| actual or intended publication of such source code. + +|SASIN idnt 2,1 | Motorola 040 Floating Point Software Package + + |section 8 + +PIBY2: .long 0x3FFF0000,0xC90FDAA2,0x2168C235,0x00000000 + + |xref t_operr + |xref t_frcinx + |xref t_extdnrm + |xref satan + + .global sasind +sasind: +|--ASIN(X) = X FOR DENORMALIZED X + + bra t_extdnrm + + .global sasin +sasin: + fmovex (%a0),%fp0 | ...LOAD INPUT + + movel (%a0),%d0 + movew 4(%a0),%d0 + andil #0x7FFFFFFF,%d0 + cmpil #0x3FFF8000,%d0 + bges asinbig + +|--THIS IS THE USUAL CASE, |X| < 1 +|--ASIN(X) = ATAN( X / SQRT( (1-X)(1+X) ) ) + + fmoves #0x3F800000,%fp1 + fsubx %fp0,%fp1 | ...1-X + fmovemx %fp2-%fp2,-(%a7) + fmoves #0x3F800000,%fp2 + faddx %fp0,%fp2 | ...1+X + fmulx %fp2,%fp1 | ...(1+X)(1-X) + fmovemx (%a7)+,%fp2-%fp2 + fsqrtx %fp1 | ...SQRT([1-X][1+X]) + fdivx %fp1,%fp0 | ...X/SQRT([1-X][1+X]) + fmovemx %fp0-%fp0,(%a0) + bsr satan + bra t_frcinx + +asinbig: + fabsx %fp0 | ...|X| + fcmps #0x3F800000,%fp0 + fbgt t_operr |cause an operr exception + +|--|X| = 1, ASIN(X) = +- PI/2. + + fmovex PIBY2,%fp0 + movel (%a0),%d0 + andil #0x80000000,%d0 | ...SIGN BIT OF X + oril #0x3F800000,%d0 | ...+-1 IN SGL FORMAT + movel %d0,-(%sp) | ...push SIGN(X) IN SGL-FMT + fmovel %d1,%FPCR + fmuls (%sp)+,%fp0 + bra t_frcinx + + |end diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/satan.S linux/arch/m68k/fpsp040/satan.S --- v1.3.93/linux/arch/m68k/fpsp040/satan.S Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/fpsp040/satan.S Sat Feb 24 22:58:43 1996 @@ -0,0 +1,478 @@ +| +| satan.sa 3.3 12/19/90 +| +| The entry point satan computes the arctagent of an +| input value. satand does the same except the input value is a +| denormalized number. +| +| Input: Double-extended value in memory location pointed to by address +| register a0. +| +| Output: Arctan(X) returned in floating-point register Fp0. +| +| Accuracy and Monotonicity: The returned result is within 2 ulps in +| 64 significant bit, i.e. within 0.5001 ulp to 53 bits if the +| result is subsequently rounded to double precision. The +| result is provably monotonic in double precision. +| +| Speed: The program satan takes approximately 160 cycles for input +| argument X such that 1/16 < |X| < 16. For the other arguments, +| the program will run no worse than 10% slower. +| +| Algorithm: +| Step 1. If |X| >= 16 or |X| < 1/16, go to Step 5. +| +| Step 2. Let X = sgn * 2**k * 1.xxxxxxxx...x. Note that k = -4, -3,..., or 3. +| Define F = sgn * 2**k * 1.xxxx1, i.e. the first 5 significant bits +| of X with a bit-1 attached at the 6-th bit position. Define u +| to be u = (X-F) / (1 + X*F). +| +| Step 3. Approximate arctan(u) by a polynomial poly. +| +| Step 4. Return arctan(F) + poly, arctan(F) is fetched from a table of values +| calculated beforehand. Exit. +| +| Step 5. If |X| >= 16, go to Step 7. +| +| Step 6. Approximate arctan(X) by an odd polynomial in X. Exit. +| +| Step 7. Define X' = -1/X. Approximate arctan(X') by an odd polynomial in X'. +| Arctan(X) = sign(X)*Pi/2 + arctan(X'). Exit. +| + +| Copyright (C) Motorola, Inc. 1990 +| All Rights Reserved +| +| THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA +| The copyright notice above does not evidence any +| actual or intended publication of such source code. + +|satan idnt 2,1 | Motorola 040 Floating Point Software Package + + |section 8 + + .include "fpsp.h" + +BOUNDS1: .long 0x3FFB8000,0x4002FFFF + +ONE: .long 0x3F800000 + + .long 0x00000000 + +ATANA3: .long 0xBFF6687E,0x314987D8 +ATANA2: .long 0x4002AC69,0x34A26DB3 + +ATANA1: .long 0xBFC2476F,0x4E1DA28E +ATANB6: .long 0x3FB34444,0x7F876989 + +ATANB5: .long 0xBFB744EE,0x7FAF45DB +ATANB4: .long 0x3FBC71C6,0x46940220 + +ATANB3: .long 0xBFC24924,0x921872F9 +ATANB2: .long 0x3FC99999,0x99998FA9 + +ATANB1: .long 0xBFD55555,0x55555555 +ATANC5: .long 0xBFB70BF3,0x98539E6A + +ATANC4: .long 0x3FBC7187,0x962D1D7D +ATANC3: .long 0xBFC24924,0x827107B8 + +ATANC2: .long 0x3FC99999,0x9996263E +ATANC1: .long 0xBFD55555,0x55555536 + +PPIBY2: .long 0x3FFF0000,0xC90FDAA2,0x2168C235,0x00000000 +NPIBY2: .long 0xBFFF0000,0xC90FDAA2,0x2168C235,0x00000000 +PTINY: .long 0x00010000,0x80000000,0x00000000,0x00000000 +NTINY: .long 0x80010000,0x80000000,0x00000000,0x00000000 + +ATANTBL: + .long 0x3FFB0000,0x83D152C5,0x060B7A51,0x00000000 + .long 0x3FFB0000,0x8BC85445,0x65498B8B,0x00000000 + .long 0x3FFB0000,0x93BE4060,0x17626B0D,0x00000000 + .long 0x3FFB0000,0x9BB3078D,0x35AEC202,0x00000000 + .long 0x3FFB0000,0xA3A69A52,0x5DDCE7DE,0x00000000 + .long 0x3FFB0000,0xAB98E943,0x62765619,0x00000000 + .long 0x3FFB0000,0xB389E502,0xF9C59862,0x00000000 + .long 0x3FFB0000,0xBB797E43,0x6B09E6FB,0x00000000 + .long 0x3FFB0000,0xC367A5C7,0x39E5F446,0x00000000 + .long 0x3FFB0000,0xCB544C61,0xCFF7D5C6,0x00000000 + .long 0x3FFB0000,0xD33F62F8,0x2488533E,0x00000000 + .long 0x3FFB0000,0xDB28DA81,0x62404C77,0x00000000 + .long 0x3FFB0000,0xE310A407,0x8AD34F18,0x00000000 + .long 0x3FFB0000,0xEAF6B0A8,0x188EE1EB,0x00000000 + .long 0x3FFB0000,0xF2DAF194,0x9DBE79D5,0x00000000 + .long 0x3FFB0000,0xFABD5813,0x61D47E3E,0x00000000 + .long 0x3FFC0000,0x8346AC21,0x0959ECC4,0x00000000 + .long 0x3FFC0000,0x8B232A08,0x304282D8,0x00000000 + .long 0x3FFC0000,0x92FB70B8,0xD29AE2F9,0x00000000 + .long 0x3FFC0000,0x9ACF476F,0x5CCD1CB4,0x00000000 + .long 0x3FFC0000,0xA29E7630,0x4954F23F,0x00000000 + .long 0x3FFC0000,0xAA68C5D0,0x8AB85230,0x00000000 + .long 0x3FFC0000,0xB22DFFFD,0x9D539F83,0x00000000 + .long 0x3FFC0000,0xB9EDEF45,0x3E900EA5,0x00000000 + .long 0x3FFC0000,0xC1A85F1C,0xC75E3EA5,0x00000000 + .long 0x3FFC0000,0xC95D1BE8,0x28138DE6,0x00000000 + .long 0x3FFC0000,0xD10BF300,0x840D2DE4,0x00000000 + .long 0x3FFC0000,0xD8B4B2BA,0x6BC05E7A,0x00000000 + .long 0x3FFC0000,0xE0572A6B,0xB42335F6,0x00000000 + .long 0x3FFC0000,0xE7F32A70,0xEA9CAA8F,0x00000000 + .long 0x3FFC0000,0xEF888432,0x64ECEFAA,0x00000000 + .long 0x3FFC0000,0xF7170A28,0xECC06666,0x00000000 + .long 0x3FFD0000,0x812FD288,0x332DAD32,0x00000000 + .long 0x3FFD0000,0x88A8D1B1,0x218E4D64,0x00000000 + .long 0x3FFD0000,0x9012AB3F,0x23E4AEE8,0x00000000 + .long 0x3FFD0000,0x976CC3D4,0x11E7F1B9,0x00000000 + .long 0x3FFD0000,0x9EB68949,0x3889A227,0x00000000 + .long 0x3FFD0000,0xA5EF72C3,0x4487361B,0x00000000 + .long 0x3FFD0000,0xAD1700BA,0xF07A7227,0x00000000 + .long 0x3FFD0000,0xB42CBCFA,0xFD37EFB7,0x00000000 + .long 0x3FFD0000,0xBB303A94,0x0BA80F89,0x00000000 + .long 0x3FFD0000,0xC22115C6,0xFCAEBBAF,0x00000000 + .long 0x3FFD0000,0xC8FEF3E6,0x86331221,0x00000000 + .long 0x3FFD0000,0xCFC98330,0xB4000C70,0x00000000 + .long 0x3FFD0000,0xD6807AA1,0x102C5BF9,0x00000000 + .long 0x3FFD0000,0xDD2399BC,0x31252AA3,0x00000000 + .long 0x3FFD0000,0xE3B2A855,0x6B8FC517,0x00000000 + .long 0x3FFD0000,0xEA2D764F,0x64315989,0x00000000 + .long 0x3FFD0000,0xF3BF5BF8,0xBAD1A21D,0x00000000 + .long 0x3FFE0000,0x801CE39E,0x0D205C9A,0x00000000 + .long 0x3FFE0000,0x8630A2DA,0xDA1ED066,0x00000000 + .long 0x3FFE0000,0x8C1AD445,0xF3E09B8C,0x00000000 + .long 0x3FFE0000,0x91DB8F16,0x64F350E2,0x00000000 + .long 0x3FFE0000,0x97731420,0x365E538C,0x00000000 + .long 0x3FFE0000,0x9CE1C8E6,0xA0B8CDBA,0x00000000 + .long 0x3FFE0000,0xA22832DB,0xCADAAE09,0x00000000 + .long 0x3FFE0000,0xA746F2DD,0xB7602294,0x00000000 + .long 0x3FFE0000,0xAC3EC0FB,0x997DD6A2,0x00000000 + .long 0x3FFE0000,0xB110688A,0xEBDC6F6A,0x00000000 + .long 0x3FFE0000,0xB5BCC490,0x59ECC4B0,0x00000000 + .long 0x3FFE0000,0xBA44BC7D,0xD470782F,0x00000000 + .long 0x3FFE0000,0xBEA94144,0xFD049AAC,0x00000000 + .long 0x3FFE0000,0xC2EB4ABB,0x661628B6,0x00000000 + .long 0x3FFE0000,0xC70BD54C,0xE602EE14,0x00000000 + .long 0x3FFE0000,0xCD000549,0xADEC7159,0x00000000 + .long 0x3FFE0000,0xD48457D2,0xD8EA4EA3,0x00000000 + .long 0x3FFE0000,0xDB948DA7,0x12DECE3B,0x00000000 + .long 0x3FFE0000,0xE23855F9,0x69E8096A,0x00000000 + .long 0x3FFE0000,0xE8771129,0xC4353259,0x00000000 + .long 0x3FFE0000,0xEE57C16E,0x0D379C0D,0x00000000 + .long 0x3FFE0000,0xF3E10211,0xA87C3779,0x00000000 + .long 0x3FFE0000,0xF919039D,0x758B8D41,0x00000000 + .long 0x3FFE0000,0xFE058B8F,0x64935FB3,0x00000000 + .long 0x3FFF0000,0x8155FB49,0x7B685D04,0x00000000 + .long 0x3FFF0000,0x83889E35,0x49D108E1,0x00000000 + .long 0x3FFF0000,0x859CFA76,0x511D724B,0x00000000 + .long 0x3FFF0000,0x87952ECF,0xFF8131E7,0x00000000 + .long 0x3FFF0000,0x89732FD1,0x9557641B,0x00000000 + .long 0x3FFF0000,0x8B38CAD1,0x01932A35,0x00000000 + .long 0x3FFF0000,0x8CE7A8D8,0x301EE6B5,0x00000000 + .long 0x3FFF0000,0x8F46A39E,0x2EAE5281,0x00000000 + .long 0x3FFF0000,0x922DA7D7,0x91888487,0x00000000 + .long 0x3FFF0000,0x94D19FCB,0xDEDF5241,0x00000000 + .long 0x3FFF0000,0x973AB944,0x19D2A08B,0x00000000 + .long 0x3FFF0000,0x996FF00E,0x08E10B96,0x00000000 + .long 0x3FFF0000,0x9B773F95,0x12321DA7,0x00000000 + .long 0x3FFF0000,0x9D55CC32,0x0F935624,0x00000000 + .long 0x3FFF0000,0x9F100575,0x006CC571,0x00000000 + .long 0x3FFF0000,0xA0A9C290,0xD97CC06C,0x00000000 + .long 0x3FFF0000,0xA22659EB,0xEBC0630A,0x00000000 + .long 0x3FFF0000,0xA388B4AF,0xF6EF0EC9,0x00000000 + .long 0x3FFF0000,0xA4D35F10,0x61D292C4,0x00000000 + .long 0x3FFF0000,0xA60895DC,0xFBE3187E,0x00000000 + .long 0x3FFF0000,0xA72A51DC,0x7367BEAC,0x00000000 + .long 0x3FFF0000,0xA83A5153,0x0956168F,0x00000000 + .long 0x3FFF0000,0xA93A2007,0x7539546E,0x00000000 + .long 0x3FFF0000,0xAA9E7245,0x023B2605,0x00000000 + .long 0x3FFF0000,0xAC4C84BA,0x6FE4D58F,0x00000000 + .long 0x3FFF0000,0xADCE4A4A,0x606B9712,0x00000000 + .long 0x3FFF0000,0xAF2A2DCD,0x8D263C9C,0x00000000 + .long 0x3FFF0000,0xB0656F81,0xF22265C7,0x00000000 + .long 0x3FFF0000,0xB1846515,0x0F71496A,0x00000000 + .long 0x3FFF0000,0xB28AAA15,0x6F9ADA35,0x00000000 + .long 0x3FFF0000,0xB37B44FF,0x3766B895,0x00000000 + .long 0x3FFF0000,0xB458C3DC,0xE9630433,0x00000000 + .long 0x3FFF0000,0xB525529D,0x562246BD,0x00000000 + .long 0x3FFF0000,0xB5E2CCA9,0x5F9D88CC,0x00000000 + .long 0x3FFF0000,0xB692CADA,0x7ACA1ADA,0x00000000 + .long 0x3FFF0000,0xB736AEA7,0xA6925838,0x00000000 + .long 0x3FFF0000,0xB7CFAB28,0x7E9F7B36,0x00000000 + .long 0x3FFF0000,0xB85ECC66,0xCB219835,0x00000000 + .long 0x3FFF0000,0xB8E4FD5A,0x20A593DA,0x00000000 + .long 0x3FFF0000,0xB99F41F6,0x4AFF9BB5,0x00000000 + .long 0x3FFF0000,0xBA7F1E17,0x842BBE7B,0x00000000 + .long 0x3FFF0000,0xBB471285,0x7637E17D,0x00000000 + .long 0x3FFF0000,0xBBFABE8A,0x4788DF6F,0x00000000 + .long 0x3FFF0000,0xBC9D0FAD,0x2B689D79,0x00000000 + .long 0x3FFF0000,0xBD306A39,0x471ECD86,0x00000000 + .long 0x3FFF0000,0xBDB6C731,0x856AF18A,0x00000000 + .long 0x3FFF0000,0xBE31CAC5,0x02E80D70,0x00000000 + .long 0x3FFF0000,0xBEA2D55C,0xE33194E2,0x00000000 + .long 0x3FFF0000,0xBF0B10B7,0xC03128F0,0x00000000 + .long 0x3FFF0000,0xBF6B7A18,0xDACB778D,0x00000000 + .long 0x3FFF0000,0xBFC4EA46,0x63FA18F6,0x00000000 + .long 0x3FFF0000,0xC0181BDE,0x8B89A454,0x00000000 + .long 0x3FFF0000,0xC065B066,0xCFBF6439,0x00000000 + .long 0x3FFF0000,0xC0AE345F,0x56340AE6,0x00000000 + .long 0x3FFF0000,0xC0F22291,0x9CB9E6A7,0x00000000 + + .set X,FP_SCR1 + .set XDCARE,X+2 + .set XFRAC,X+4 + .set XFRACLO,X+8 + + .set ATANF,FP_SCR2 + .set ATANFHI,ATANF+4 + .set ATANFLO,ATANF+8 + + + | xref t_frcinx + |xref t_extdnrm + + .global satand +satand: +|--ENTRY POINT FOR ATAN(X) FOR DENORMALIZED ARGUMENT + + bra t_extdnrm + + .global satan +satan: +|--ENTRY POINT FOR ATAN(X), HERE X IS FINITE, NON-ZERO, AND NOT NAN'S + + fmovex (%a0),%fp0 | ...LOAD INPUT + + movel (%a0),%d0 + movew 4(%a0),%d0 + fmovex %fp0,X(%a6) + andil #0x7FFFFFFF,%d0 + + cmpil #0x3FFB8000,%d0 | ...|X| >= 1/16? + bges ATANOK1 + bra ATANSM + +ATANOK1: + cmpil #0x4002FFFF,%d0 | ...|X| < 16 ? + bles ATANMAIN + bra ATANBIG + + +|--THE MOST LIKELY CASE, |X| IN [1/16, 16). WE USE TABLE TECHNIQUE +|--THE IDEA IS ATAN(X) = ATAN(F) + ATAN( [X-F] / [1+XF] ). +|--SO IF F IS CHOSEN TO BE CLOSE TO X AND ATAN(F) IS STORED IN +|--A TABLE, ALL WE NEED IS TO APPROXIMATE ATAN(U) WHERE +|--U = (X-F)/(1+XF) IS SMALL (REMEMBER F IS CLOSE TO X). IT IS +|--TRUE THAT A DIVIDE IS NOW NEEDED, BUT THE APPROXIMATION FOR +|--ATAN(U) IS A VERY SHORT POLYNOMIAL AND THE INDEXING TO +|--FETCH F AND SAVING OF REGISTERS CAN BE ALL HIDED UNDER THE +|--DIVIDE. IN THE END THIS METHOD IS MUCH FASTER THAN A TRADITIONAL +|--ONE. NOTE ALSO THAT THE TRADITIONAL SCHEME THAT APPROXIMATE +|--ATAN(X) DIRECTLY WILL NEED TO USE A RATIONAL APPROXIMATION +|--(DIVISION NEEDED) ANYWAY BECAUSE A POLYNOMIAL APPROXIMATION +|--WILL INVOLVE A VERY LONG POLYNOMIAL. + +|--NOW WE SEE X AS +-2^K * 1.BBBBBBB....B <- 1. + 63 BITS +|--WE CHOSE F TO BE +-2^K * 1.BBBB1 +|--THAT IS IT MATCHES THE EXPONENT AND FIRST 5 BITS OF X, THE +|--SIXTH BITS IS SET TO BE 1. SINCE K = -4, -3, ..., 3, THERE +|--ARE ONLY 8 TIMES 16 = 2^7 = 128 |F|'S. SINCE ATAN(-|F|) IS +|-- -ATAN(|F|), WE NEED TO STORE ONLY ATAN(|F|). + +ATANMAIN: + + movew #0x0000,XDCARE(%a6) | ...CLEAN UP X JUST IN CASE + andil #0xF8000000,XFRAC(%a6) | ...FIRST 5 BITS + oril #0x04000000,XFRAC(%a6) | ...SET 6-TH BIT TO 1 + movel #0x00000000,XFRACLO(%a6) | ...LOCATION OF X IS NOW F + + fmovex %fp0,%fp1 | ...FP1 IS X + fmulx X(%a6),%fp1 | ...FP1 IS X*F, NOTE THAT X*F > 0 + fsubx X(%a6),%fp0 | ...FP0 IS X-F + fadds #0x3F800000,%fp1 | ...FP1 IS 1 + X*F + fdivx %fp1,%fp0 | ...FP0 IS U = (X-F)/(1+X*F) + +|--WHILE THE DIVISION IS TAKING ITS TIME, WE FETCH ATAN(|F|) +|--CREATE ATAN(F) AND STORE IT IN ATANF, AND +|--SAVE REGISTERS FP2. + + movel %d2,-(%a7) | ...SAVE d2 TEMPORARILY + movel %d0,%d2 | ...THE EXPO AND 16 BITS OF X + andil #0x00007800,%d0 | ...4 VARYING BITS OF F'S FRACTION + andil #0x7FFF0000,%d2 | ...EXPONENT OF F + subil #0x3FFB0000,%d2 | ...K+4 + asrl #1,%d2 + addl %d2,%d0 | ...THE 7 BITS IDENTIFYING F + asrl #7,%d0 | ...INDEX INTO TBL OF ATAN(|F|) + lea ATANTBL,%a1 + addal %d0,%a1 | ...ADDRESS OF ATAN(|F|) + movel (%a1)+,ATANF(%a6) + movel (%a1)+,ATANFHI(%a6) + movel (%a1)+,ATANFLO(%a6) | ...ATANF IS NOW ATAN(|F|) + movel X(%a6),%d0 | ...LOAD SIGN AND EXPO. AGAIN + andil #0x80000000,%d0 | ...SIGN(F) + orl %d0,ATANF(%a6) | ...ATANF IS NOW SIGN(F)*ATAN(|F|) + movel (%a7)+,%d2 | ...RESTORE d2 + +|--THAT'S ALL I HAVE TO DO FOR NOW, +|--BUT ALAS, THE DIVIDE IS STILL CRANKING! + +|--U IN FP0, WE ARE NOW READY TO COMPUTE ATAN(U) AS +|--U + A1*U*V*(A2 + V*(A3 + V)), V = U*U +|--THE POLYNOMIAL MAY LOOK STRANGE, BUT IS NEVERTHELESS CORRECT. +|--THE NATURAL FORM IS U + U*V*(A1 + V*(A2 + V*A3)) +|--WHAT WE HAVE HERE IS MERELY A1 = A3, A2 = A1/A3, A3 = A2/A3. +|--THE REASON FOR THIS REARRANGEMENT IS TO MAKE THE INDEPENDENT +|--PARTS A1*U*V AND (A2 + ... STUFF) MORE LOAD-BALANCED + + + fmovex %fp0,%fp1 + fmulx %fp1,%fp1 + fmoved ATANA3,%fp2 + faddx %fp1,%fp2 | ...A3+V + fmulx %fp1,%fp2 | ...V*(A3+V) + fmulx %fp0,%fp1 | ...U*V + faddd ATANA2,%fp2 | ...A2+V*(A3+V) + fmuld ATANA1,%fp1 | ...A1*U*V + fmulx %fp2,%fp1 | ...A1*U*V*(A2+V*(A3+V)) + + faddx %fp1,%fp0 | ...ATAN(U), FP1 RELEASED + fmovel %d1,%FPCR |restore users exceptions + faddx ATANF(%a6),%fp0 | ...ATAN(X) + bra t_frcinx + +ATANBORS: +|--|X| IS IN d0 IN COMPACT FORM. FP1, d0 SAVED. +|--FP0 IS X AND |X| <= 1/16 OR |X| >= 16. + cmpil #0x3FFF8000,%d0 + bgt ATANBIG | ...I.E. |X| >= 16 + +ATANSM: +|--|X| <= 1/16 +|--IF |X| < 2^(-40), RETURN X AS ANSWER. OTHERWISE, APPROXIMATE +|--ATAN(X) BY X + X*Y*(B1+Y*(B2+Y*(B3+Y*(B4+Y*(B5+Y*B6))))) +|--WHICH IS X + X*Y*( [B1+Z*(B3+Z*B5)] + [Y*(B2+Z*(B4+Z*B6)] ) +|--WHERE Y = X*X, AND Z = Y*Y. + + cmpil #0x3FD78000,%d0 + blt ATANTINY +|--COMPUTE POLYNOMIAL + fmulx %fp0,%fp0 | ...FP0 IS Y = X*X + + + movew #0x0000,XDCARE(%a6) + + fmovex %fp0,%fp1 + fmulx %fp1,%fp1 | ...FP1 IS Z = Y*Y + + fmoved ATANB6,%fp2 + fmoved ATANB5,%fp3 + + fmulx %fp1,%fp2 | ...Z*B6 + fmulx %fp1,%fp3 | ...Z*B5 + + faddd ATANB4,%fp2 | ...B4+Z*B6 + faddd ATANB3,%fp3 | ...B3+Z*B5 + + fmulx %fp1,%fp2 | ...Z*(B4+Z*B6) + fmulx %fp3,%fp1 | ...Z*(B3+Z*B5) + + faddd ATANB2,%fp2 | ...B2+Z*(B4+Z*B6) + faddd ATANB1,%fp1 | ...B1+Z*(B3+Z*B5) + + fmulx %fp0,%fp2 | ...Y*(B2+Z*(B4+Z*B6)) + fmulx X(%a6),%fp0 | ...X*Y + + faddx %fp2,%fp1 | ...[B1+Z*(B3+Z*B5)]+[Y*(B2+Z*(B4+Z*B6))] + + + fmulx %fp1,%fp0 | ...X*Y*([B1+Z*(B3+Z*B5)]+[Y*(B2+Z*(B4+Z*B6))]) + + fmovel %d1,%FPCR |restore users exceptions + faddx X(%a6),%fp0 + + bra t_frcinx + +ATANTINY: +|--|X| < 2^(-40), ATAN(X) = X + movew #0x0000,XDCARE(%a6) + + fmovel %d1,%FPCR |restore users exceptions + fmovex X(%a6),%fp0 |last inst - possible exception set + + bra t_frcinx + +ATANBIG: +|--IF |X| > 2^(100), RETURN SIGN(X)*(PI/2 - TINY). OTHERWISE, +|--RETURN SIGN(X)*PI/2 + ATAN(-1/X). + cmpil #0x40638000,%d0 + bgt ATANHUGE + +|--APPROXIMATE ATAN(-1/X) BY +|--X'+X'*Y*(C1+Y*(C2+Y*(C3+Y*(C4+Y*C5)))), X' = -1/X, Y = X'*X' +|--THIS CAN BE RE-WRITTEN AS +|--X'+X'*Y*( [C1+Z*(C3+Z*C5)] + [Y*(C2+Z*C4)] ), Z = Y*Y. + + fmoves #0xBF800000,%fp1 | ...LOAD -1 + fdivx %fp0,%fp1 | ...FP1 IS -1/X + + +|--DIVIDE IS STILL CRANKING + + fmovex %fp1,%fp0 | ...FP0 IS X' + fmulx %fp0,%fp0 | ...FP0 IS Y = X'*X' + fmovex %fp1,X(%a6) | ...X IS REALLY X' + + fmovex %fp0,%fp1 + fmulx %fp1,%fp1 | ...FP1 IS Z = Y*Y + + fmoved ATANC5,%fp3 + fmoved ATANC4,%fp2 + + fmulx %fp1,%fp3 | ...Z*C5 + fmulx %fp1,%fp2 | ...Z*B4 + + faddd ATANC3,%fp3 | ...C3+Z*C5 + faddd ATANC2,%fp2 | ...C2+Z*C4 + + fmulx %fp3,%fp1 | ...Z*(C3+Z*C5), FP3 RELEASED + fmulx %fp0,%fp2 | ...Y*(C2+Z*C4) + + faddd ATANC1,%fp1 | ...C1+Z*(C3+Z*C5) + fmulx X(%a6),%fp0 | ...X'*Y + + faddx %fp2,%fp1 | ...[Y*(C2+Z*C4)]+[C1+Z*(C3+Z*C5)] + + + fmulx %fp1,%fp0 | ...X'*Y*([B1+Z*(B3+Z*B5)] +| ... +[Y*(B2+Z*(B4+Z*B6))]) + faddx X(%a6),%fp0 + + fmovel %d1,%FPCR |restore users exceptions + + btstb #7,(%a0) + beqs pos_big + +neg_big: + faddx NPIBY2,%fp0 + bra t_frcinx + +pos_big: + faddx PPIBY2,%fp0 + bra t_frcinx + +ATANHUGE: +|--RETURN SIGN(X)*(PIBY2 - TINY) = SIGN(X)*PIBY2 - SIGN(X)*TINY + btstb #7,(%a0) + beqs pos_huge + +neg_huge: + fmovex NPIBY2,%fp0 + fmovel %d1,%fpcr + fsubx NTINY,%fp0 + bra t_frcinx + +pos_huge: + fmovex PPIBY2,%fp0 + fmovel %d1,%fpcr + fsubx PTINY,%fp0 + bra t_frcinx + + |end diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/satanh.S linux/arch/m68k/fpsp040/satanh.S --- v1.3.93/linux/arch/m68k/fpsp040/satanh.S Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/fpsp040/satanh.S Sat Feb 24 22:58:43 1996 @@ -0,0 +1,104 @@ +| +| satanh.sa 3.3 12/19/90 +| +| The entry point satanh computes the inverse +| hyperbolic tangent of +| an input argument; satanhd does the same except for denormalized +| input. +| +| Input: Double-extended number X in location pointed to +| by address register a0. +| +| Output: The value arctanh(X) returned in floating-point register Fp0. +| +| Accuracy and Monotonicity: The returned result is within 3 ulps in +| 64 significant bit, i.e. within 0.5001 ulp to 53 bits if the +| result is subsequently rounded to double precision. The +| result is provably monotonic in double precision. +| +| Speed: The program satanh takes approximately 270 cycles. +| +| Algorithm: +| +| ATANH +| 1. If |X| >= 1, go to 3. +| +| 2. (|X| < 1) Calculate atanh(X) by +| sgn := sign(X) +| y := |X| +| z := 2y/(1-y) +| atanh(X) := sgn * (1/2) * logp1(z) +| Exit. +| +| 3. If |X| > 1, go to 5. +| +| 4. (|X| = 1) Generate infinity with an appropriate sign and +| divide-by-zero by +| sgn := sign(X) +| atan(X) := sgn / (+0). +| Exit. +| +| 5. (|X| > 1) Generate an invalid operation by 0 * infinity. +| Exit. +| + +| Copyright (C) Motorola, Inc. 1990 +| All Rights Reserved +| +| THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA +| The copyright notice above does not evidence any +| actual or intended publication of such source code. + +|satanh idnt 2,1 | Motorola 040 Floating Point Software Package + + |section 8 + + |xref t_dz + |xref t_operr + |xref t_frcinx + |xref t_extdnrm + |xref slognp1 + + .global satanhd +satanhd: +|--ATANH(X) = X FOR DENORMALIZED X + + bra t_extdnrm + + .global satanh +satanh: + movel (%a0),%d0 + movew 4(%a0),%d0 + andil #0x7FFFFFFF,%d0 + cmpil #0x3FFF8000,%d0 + bges ATANHBIG + +|--THIS IS THE USUAL CASE, |X| < 1 +|--Y = |X|, Z = 2Y/(1-Y), ATANH(X) = SIGN(X) * (1/2) * LOG1P(Z). + + fabsx (%a0),%fp0 | ...Y = |X| + fmovex %fp0,%fp1 + fnegx %fp1 | ...-Y + faddx %fp0,%fp0 | ...2Y + fadds #0x3F800000,%fp1 | ...1-Y + fdivx %fp1,%fp0 | ...2Y/(1-Y) + movel (%a0),%d0 + andil #0x80000000,%d0 + oril #0x3F000000,%d0 | ...SIGN(X)*HALF + movel %d0,-(%sp) + + fmovemx %fp0-%fp0,(%a0) | ...overwrite input + movel %d1,-(%sp) + clrl %d1 + bsr slognp1 | ...LOG1P(Z) + fmovel (%sp)+,%fpcr + fmuls (%sp)+,%fp0 + bra t_frcinx + +ATANHBIG: + fabsx (%a0),%fp0 | ...|X| + fcmps #0x3F800000,%fp0 + fbgt t_operr + bra t_dz + + |end diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/scale.S linux/arch/m68k/fpsp040/scale.S --- v1.3.93/linux/arch/m68k/fpsp040/scale.S Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/fpsp040/scale.S Sat Feb 24 22:58:43 1996 @@ -0,0 +1,371 @@ +| +| scale.sa 3.3 7/30/91 +| +| The entry point sSCALE computes the destination operand +| scaled by the source operand. If the absoulute value of +| the source operand is (>= 2^14) an overflow or underflow +| is returned. +| +| The entry point sscale is called from do_func to emulate +| the fscale unimplemented instruction. +| +| Input: Double-extended destination operand in FPTEMP, +| double-extended source operand in ETEMP. +| +| Output: The function returns scale(X,Y) to fp0. +| +| Modifies: fp0. +| +| Algorithm: +| +| Copyright (C) Motorola, Inc. 1990 +| All Rights Reserved +| +| THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA +| The copyright notice above does not evidence any +| actual or intended publication of such source code. + +|SCALE idnt 2,1 | Motorola 040 Floating Point Software Package + + |section 8 + + .include "fpsp.h" + + |xref t_ovfl2 + |xref t_unfl + |xref round + |xref t_resdnrm + +SRC_BNDS: .short 0x3fff,0x400c + +| +| This entry point is used by the unimplemented instruction exception +| handler. +| +| +| +| FSCALE +| + .global sscale +sscale: + fmovel #0,%fpcr |clr user enabled exc + clrl %d1 + movew FPTEMP(%a6),%d1 |get dest exponent + smi L_SCR1(%a6) |use L_SCR1 to hold sign + andil #0x7fff,%d1 |strip sign + movew ETEMP(%a6),%d0 |check src bounds + andiw #0x7fff,%d0 |clr sign bit + cmp2w SRC_BNDS,%d0 + bccs src_in + cmpiw #0x400c,%d0 |test for too large + bge src_out +| +| The source input is below 1, so we check for denormalized numbers +| and set unfl. +| +src_small: + moveb DTAG(%a6),%d0 + andib #0xe0,%d0 + tstb %d0 + beqs no_denorm + st STORE_FLG(%a6) |dest already contains result + orl #unfl_mask,USER_FPSR(%a6) |set UNFL +den_done: + leal FPTEMP(%a6),%a0 + bra t_resdnrm +no_denorm: + fmovel USER_FPCR(%a6),%FPCR + fmovex FPTEMP(%a6),%fp0 |simply return dest + rts + + +| +| Source is within 2^14 range. To perform the int operation, +| move it to d0. +| +src_in: + fmovex ETEMP(%a6),%fp0 |move in src for int + fmovel #rz_mode,%fpcr |force rz for src conversion + fmovel %fp0,%d0 |int src to d0 + fmovel #0,%FPSR |clr status from above + tstw ETEMP(%a6) |check src sign + blt src_neg +| +| Source is positive. Add the src to the dest exponent. +| The result can be denormalized, if src = 0, or overflow, +| if the result of the add sets a bit in the upper word. +| +src_pos: + tstw %d1 |check for denorm + beq dst_dnrm + addl %d0,%d1 |add src to dest exp + beqs denorm |if zero, result is denorm + cmpil #0x7fff,%d1 |test for overflow + bges ovfl + tstb L_SCR1(%a6) + beqs spos_pos + orw #0x8000,%d1 +spos_pos: + movew %d1,FPTEMP(%a6) |result in FPTEMP + fmovel USER_FPCR(%a6),%FPCR + fmovex FPTEMP(%a6),%fp0 |write result to fp0 + rts +ovfl: + tstb L_SCR1(%a6) + beqs sovl_pos + orw #0x8000,%d1 +sovl_pos: + movew FPTEMP(%a6),ETEMP(%a6) |result in ETEMP + movel FPTEMP_HI(%a6),ETEMP_HI(%a6) + movel FPTEMP_LO(%a6),ETEMP_LO(%a6) + bra t_ovfl2 + +denorm: + tstb L_SCR1(%a6) + beqs den_pos + orw #0x8000,%d1 +den_pos: + tstl FPTEMP_HI(%a6) |check j bit + blts nden_exit |if set, not denorm + movew %d1,ETEMP(%a6) |input expected in ETEMP + movel FPTEMP_HI(%a6),ETEMP_HI(%a6) + movel FPTEMP_LO(%a6),ETEMP_LO(%a6) + orl #unfl_bit,USER_FPSR(%a6) |set unfl + leal ETEMP(%a6),%a0 + bra t_resdnrm +nden_exit: + movew %d1,FPTEMP(%a6) |result in FPTEMP + fmovel USER_FPCR(%a6),%FPCR + fmovex FPTEMP(%a6),%fp0 |write result to fp0 + rts + +| +| Source is negative. Add the src to the dest exponent. +| (The result exponent will be reduced). The result can be +| denormalized. +| +src_neg: + addl %d0,%d1 |add src to dest + beqs denorm |if zero, result is denorm + blts fix_dnrm |if negative, result is +| ;needing denormalization + tstb L_SCR1(%a6) + beqs sneg_pos + orw #0x8000,%d1 +sneg_pos: + movew %d1,FPTEMP(%a6) |result in FPTEMP + fmovel USER_FPCR(%a6),%FPCR + fmovex FPTEMP(%a6),%fp0 |write result to fp0 + rts + + +| +| The result exponent is below denorm value. Test for catastrophic +| underflow and force zero if true. If not, try to shift the +| mantissa right until a zero exponent exists. +| +fix_dnrm: + cmpiw #0xffc0,%d1 |lower bound for normalization + blt fix_unfl |if lower, catastrophic unfl + movew %d1,%d0 |use d0 for exp + movel %d2,-(%a7) |free d2 for norm + movel FPTEMP_HI(%a6),%d1 + movel FPTEMP_LO(%a6),%d2 + clrl L_SCR2(%a6) +fix_loop: + addw #1,%d0 |drive d0 to 0 + lsrl #1,%d1 |while shifting the + roxrl #1,%d2 |mantissa to the right + bccs no_carry + st L_SCR2(%a6) |use L_SCR2 to capture inex +no_carry: + tstw %d0 |it is finished when + blts fix_loop |d0 is zero or the mantissa + tstb L_SCR2(%a6) + beqs tst_zero + orl #unfl_inx_mask,USER_FPSR(%a6) +| ;set unfl, aunfl, ainex +| +| Test for zero. If zero, simply use fmove to return +/- zero +| to the fpu. +| +tst_zero: + clrw FPTEMP_EX(%a6) + tstb L_SCR1(%a6) |test for sign + beqs tst_con + orw #0x8000,FPTEMP_EX(%a6) |set sign bit +tst_con: + movel %d1,FPTEMP_HI(%a6) + movel %d2,FPTEMP_LO(%a6) + movel (%a7)+,%d2 + tstl %d1 + bnes not_zero + tstl FPTEMP_LO(%a6) + bnes not_zero +| +| Result is zero. Check for rounding mode to set lsb. If the +| mode is rp, and the zero is positive, return smallest denorm. +| If the mode is rm, and the zero is negative, return smallest +| negative denorm. +| + btstb #5,FPCR_MODE(%a6) |test if rm or rp + beqs no_dir + btstb #4,FPCR_MODE(%a6) |check which one + beqs zer_rm +zer_rp: + tstb L_SCR1(%a6) |check sign + bnes no_dir |if set, neg op, no inc + movel #1,FPTEMP_LO(%a6) |set lsb + bras sm_dnrm +zer_rm: + tstb L_SCR1(%a6) |check sign + beqs no_dir |if clr, neg op, no inc + movel #1,FPTEMP_LO(%a6) |set lsb + orl #neg_mask,USER_FPSR(%a6) |set N + bras sm_dnrm +no_dir: + fmovel USER_FPCR(%a6),%FPCR + fmovex FPTEMP(%a6),%fp0 |use fmove to set cc's + rts + +| +| The rounding mode changed the zero to a smallest denorm. Call +| t_resdnrm with exceptional operand in ETEMP. +| +sm_dnrm: + movel FPTEMP_EX(%a6),ETEMP_EX(%a6) + movel FPTEMP_HI(%a6),ETEMP_HI(%a6) + movel FPTEMP_LO(%a6),ETEMP_LO(%a6) + leal ETEMP(%a6),%a0 + bra t_resdnrm + +| +| Result is still denormalized. +| +not_zero: + orl #unfl_mask,USER_FPSR(%a6) |set unfl + tstb L_SCR1(%a6) |check for sign + beqs fix_exit + orl #neg_mask,USER_FPSR(%a6) |set N +fix_exit: + bras sm_dnrm + + +| +| The result has underflowed to zero. Return zero and set +| unfl, aunfl, and ainex. +| +fix_unfl: + orl #unfl_inx_mask,USER_FPSR(%a6) + btstb #5,FPCR_MODE(%a6) |test if rm or rp + beqs no_dir2 + btstb #4,FPCR_MODE(%a6) |check which one + beqs zer_rm2 +zer_rp2: + tstb L_SCR1(%a6) |check sign + bnes no_dir2 |if set, neg op, no inc + clrl FPTEMP_EX(%a6) + clrl FPTEMP_HI(%a6) + movel #1,FPTEMP_LO(%a6) |set lsb + bras sm_dnrm |return smallest denorm +zer_rm2: + tstb L_SCR1(%a6) |check sign + beqs no_dir2 |if clr, neg op, no inc + movew #0x8000,FPTEMP_EX(%a6) + clrl FPTEMP_HI(%a6) + movel #1,FPTEMP_LO(%a6) |set lsb + orl #neg_mask,USER_FPSR(%a6) |set N + bra sm_dnrm |return smallest denorm + +no_dir2: + tstb L_SCR1(%a6) + bges pos_zero +neg_zero: + clrl FP_SCR1(%a6) |clear the exceptional operand + clrl FP_SCR1+4(%a6) |for gen_except. + clrl FP_SCR1+8(%a6) + fmoves #0x80000000,%fp0 + rts +pos_zero: + clrl FP_SCR1(%a6) |clear the exceptional operand + clrl FP_SCR1+4(%a6) |for gen_except. + clrl FP_SCR1+8(%a6) + fmoves #0x00000000,%fp0 + rts + +| +| The destination is a denormalized number. It must be handled +| by first shifting the bits in the mantissa until it is normalized, +| then adding the remainder of the source to the exponent. +| +dst_dnrm: + moveml %d2/%d3,-(%a7) + movew FPTEMP_EX(%a6),%d1 + movel FPTEMP_HI(%a6),%d2 + movel FPTEMP_LO(%a6),%d3 +dst_loop: + tstl %d2 |test for normalized result + blts dst_norm |exit loop if so + tstl %d0 |otherwise, test shift count + beqs dst_fin |if zero, shifting is done + subil #1,%d0 |dec src + lsll #1,%d3 + roxll #1,%d2 + bras dst_loop +| +| Destination became normalized. Simply add the remaining +| portion of the src to the exponent. +| +dst_norm: + addw %d0,%d1 |dst is normalized; add src + tstb L_SCR1(%a6) + beqs dnrm_pos + orl #0x8000,%d1 +dnrm_pos: + movemw %d1,FPTEMP_EX(%a6) + moveml %d2,FPTEMP_HI(%a6) + moveml %d3,FPTEMP_LO(%a6) + fmovel USER_FPCR(%a6),%FPCR + fmovex FPTEMP(%a6),%fp0 + moveml (%a7)+,%d2/%d3 + rts + +| +| Destination remained denormalized. Call t_excdnrm with +| exceptional operand in ETEMP. +| +dst_fin: + tstb L_SCR1(%a6) |check for sign + beqs dst_exit + orl #neg_mask,USER_FPSR(%a6) |set N + orl #0x8000,%d1 +dst_exit: + movemw %d1,ETEMP_EX(%a6) + moveml %d2,ETEMP_HI(%a6) + moveml %d3,ETEMP_LO(%a6) + orl #unfl_mask,USER_FPSR(%a6) |set unfl + moveml (%a7)+,%d2/%d3 + leal ETEMP(%a6),%a0 + bra t_resdnrm + +| +| Source is outside of 2^14 range. Test the sign and branch +| to the appropriate exception handler. +| +src_out: + tstb L_SCR1(%a6) + beqs scro_pos + orl #0x8000,%d1 +scro_pos: + movel FPTEMP_HI(%a6),ETEMP_HI(%a6) + movel FPTEMP_LO(%a6),ETEMP_LO(%a6) + tstw ETEMP(%a6) + blts res_neg +res_pos: + movew %d1,ETEMP(%a6) |result in ETEMP + bra t_ovfl2 +res_neg: + movew %d1,ETEMP(%a6) |result in ETEMP + leal ETEMP(%a6),%a0 + bra t_unfl + |end diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/scosh.S linux/arch/m68k/fpsp040/scosh.S --- v1.3.93/linux/arch/m68k/fpsp040/scosh.S Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/fpsp040/scosh.S Sat Feb 24 22:58:43 1996 @@ -0,0 +1,132 @@ +| +| scosh.sa 3.1 12/10/90 +| +| The entry point sCosh computes the hyperbolic cosine of +| an input argument; sCoshd does the same except for denormalized +| input. +| +| Input: Double-extended number X in location pointed to +| by address register a0. +| +| Output: The value cosh(X) returned in floating-point register Fp0. +| +| Accuracy and Monotonicity: The returned result is within 3 ulps in +| 64 significant bit, i.e. within 0.5001 ulp to 53 bits if the +| result is subsequently rounded to double precision. The +| result is provably monotonic in double precision. +| +| Speed: The program sCOSH takes approximately 250 cycles. +| +| Algorithm: +| +| COSH +| 1. If |X| > 16380 log2, go to 3. +| +| 2. (|X| <= 16380 log2) Cosh(X) is obtained by the formulae +| y = |X|, z = exp(Y), and +| cosh(X) = (1/2)*( z + 1/z ). +| Exit. +| +| 3. (|X| > 16380 log2). If |X| > 16480 log2, go to 5. +| +| 4. (16380 log2 < |X| <= 16480 log2) +| cosh(X) = sign(X) * exp(|X|)/2. +| However, invoking exp(|X|) may cause premature overflow. +| Thus, we calculate sinh(X) as follows: +| Y := |X| +| Fact := 2**(16380) +| Y' := Y - 16381 log2 +| cosh(X) := Fact * exp(Y'). +| Exit. +| +| 5. (|X| > 16480 log2) sinh(X) must overflow. Return +| Huge*Huge to generate overflow and an infinity with +| the appropriate sign. Huge is the largest finite number in +| extended format. Exit. +| +| + +| Copyright (C) Motorola, Inc. 1990 +| All Rights Reserved +| +| THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA +| The copyright notice above does not evidence any +| actual or intended publication of such source code. + +|SCOSH idnt 2,1 | Motorola 040 Floating Point Software Package + + |section 8 + + |xref t_ovfl + |xref t_frcinx + |xref setox + +T1: .long 0x40C62D38,0xD3D64634 | ... 16381 LOG2 LEAD +T2: .long 0x3D6F90AE,0xB1E75CC7 | ... 16381 LOG2 TRAIL + +TWO16380: .long 0x7FFB0000,0x80000000,0x00000000,0x00000000 + + .global scoshd +scoshd: +|--COSH(X) = 1 FOR DENORMALIZED X + + fmoves #0x3F800000,%fp0 + + fmovel %d1,%FPCR + fadds #0x00800000,%fp0 + bra t_frcinx + + .global scosh +scosh: + fmovex (%a0),%fp0 | ...LOAD INPUT + + movel (%a0),%d0 + movew 4(%a0),%d0 + andil #0x7FFFFFFF,%d0 + cmpil #0x400CB167,%d0 + bgts COSHBIG + +|--THIS IS THE USUAL CASE, |X| < 16380 LOG2 +|--COSH(X) = (1/2) * ( EXP(X) + 1/EXP(X) ) + + fabsx %fp0 | ...|X| + + movel %d1,-(%sp) + clrl %d1 + fmovemx %fp0-%fp0,(%a0) |pass parameter to setox + bsr setox | ...FP0 IS EXP(|X|) + fmuls #0x3F000000,%fp0 | ...(1/2)EXP(|X|) + movel (%sp)+,%d1 + + fmoves #0x3E800000,%fp1 | ...(1/4) + fdivx %fp0,%fp1 | ...1/(2 EXP(|X|)) + + fmovel %d1,%FPCR + faddx %fp1,%fp0 + + bra t_frcinx + +COSHBIG: + cmpil #0x400CB2B3,%d0 + bgts COSHHUGE + + fabsx %fp0 + fsubd T1(%pc),%fp0 | ...(|X|-16381LOG2_LEAD) + fsubd T2(%pc),%fp0 | ...|X| - 16381 LOG2, ACCURATE + + movel %d1,-(%sp) + clrl %d1 + fmovemx %fp0-%fp0,(%a0) + bsr setox + fmovel (%sp)+,%fpcr + + fmulx TWO16380(%pc),%fp0 + bra t_frcinx + +COSHHUGE: + fmovel #0,%fpsr |clr N bit if set by source + bclrb #7,(%a0) |always return positive value + fmovemx (%a0),%fp0-%fp0 + bra t_ovfl + + |end diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/setox.S linux/arch/m68k/fpsp040/setox.S --- v1.3.93/linux/arch/m68k/fpsp040/setox.S Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/fpsp040/setox.S Sat Feb 24 22:58:44 1996 @@ -0,0 +1,865 @@ +| +| setox.sa 3.1 12/10/90 +| +| The entry point setox computes the exponential of a value. +| setoxd does the same except the input value is a denormalized +| number. setoxm1 computes exp(X)-1, and setoxm1d computes +| exp(X)-1 for denormalized X. +| +| INPUT +| ----- +| Double-extended value in memory location pointed to by address +| register a0. +| +| OUTPUT +| ------ +| exp(X) or exp(X)-1 returned in floating-point register fp0. +| +| ACCURACY and MONOTONICITY +| ------------------------- +| The returned result is within 0.85 ulps in 64 significant bit, i.e. +| within 0.5001 ulp to 53 bits if the result is subsequently rounded +| to double precision. The result is provably monotonic in double +| precision. +| +| SPEED +| ----- +| Two timings are measured, both in the copy-back mode. The +| first one is measured when the function is invoked the first time +| (so the instructions and data are not in cache), and the +| second one is measured when the function is reinvoked at the same +| input argument. +| +| The program setox takes approximately 210/190 cycles for input +| argument X whose magnitude is less than 16380 log2, which +| is the usual situation. For the less common arguments, +| depending on their values, the program may run faster or slower -- +| but no worse than 10% slower even in the extreme cases. +| +| The program setoxm1 takes approximately ???/??? cycles for input +| argument X, 0.25 <= |X| < 70log2. For |X| < 0.25, it takes +| approximately ???/??? cycles. For the less common arguments, +| depending on their values, the program may run faster or slower -- +| but no worse than 10% slower even in the extreme cases. +| +| ALGORITHM and IMPLEMENTATION NOTES +| ---------------------------------- +| +| setoxd +| ------ +| Step 1. Set ans := 1.0 +| +| Step 2. Return ans := ans + sign(X)*2^(-126). Exit. +| Notes: This will always generate one exception -- inexact. +| +| +| setox +| ----- +| +| Step 1. Filter out extreme cases of input argument. +| 1.1 If |X| >= 2^(-65), go to Step 1.3. +| 1.2 Go to Step 7. +| 1.3 If |X| < 16380 log(2), go to Step 2. +| 1.4 Go to Step 8. +| Notes: The usual case should take the branches 1.1 -> 1.3 -> 2. +| To avoid the use of floating-point comparisons, a +| compact representation of |X| is used. This format is a +| 32-bit integer, the upper (more significant) 16 bits are +| the sign and biased exponent field of |X|; the lower 16 +| bits are the 16 most significant fraction (including the +| explicit bit) bits of |X|. Consequently, the comparisons +| in Steps 1.1 and 1.3 can be performed by integer comparison. +| Note also that the constant 16380 log(2) used in Step 1.3 +| is also in the compact form. Thus taking the branch +| to Step 2 guarantees |X| < 16380 log(2). There is no harm +| to have a small number of cases where |X| is less than, +| but close to, 16380 log(2) and the branch to Step 9 is +| taken. +| +| Step 2. Calculate N = round-to-nearest-int( X * 64/log2 ). +| 2.1 Set AdjFlag := 0 (indicates the branch 1.3 -> 2 was taken) +| 2.2 N := round-to-nearest-integer( X * 64/log2 ). +| 2.3 Calculate J = N mod 64; so J = 0,1,2,..., or 63. +| 2.4 Calculate M = (N - J)/64; so N = 64M + J. +| 2.5 Calculate the address of the stored value of 2^(J/64). +| 2.6 Create the value Scale = 2^M. +| Notes: The calculation in 2.2 is really performed by +| +| Z := X * constant +| N := round-to-nearest-integer(Z) +| +| where +| +| constant := single-precision( 64/log 2 ). +| +| Using a single-precision constant avoids memory access. +| Another effect of using a single-precision "constant" is +| that the calculated value Z is +| +| Z = X*(64/log2)*(1+eps), |eps| <= 2^(-24). +| +| This error has to be considered later in Steps 3 and 4. +| +| Step 3. Calculate X - N*log2/64. +| 3.1 R := X + N*L1, where L1 := single-precision(-log2/64). +| 3.2 R := R + N*L2, L2 := extended-precision(-log2/64 - L1). +| Notes: a) The way L1 and L2 are chosen ensures L1+L2 approximate +| the value -log2/64 to 88 bits of accuracy. +| b) N*L1 is exact because N is no longer than 22 bits and +| L1 is no longer than 24 bits. +| c) The calculation X+N*L1 is also exact due to cancellation. +| Thus, R is practically X+N(L1+L2) to full 64 bits. +| d) It is important to estimate how large can |R| be after +| Step 3.2. +| +| N = rnd-to-int( X*64/log2 (1+eps) ), |eps|<=2^(-24) +| X*64/log2 (1+eps) = N + f, |f| <= 0.5 +| X*64/log2 - N = f - eps*X 64/log2 +| X - N*log2/64 = f*log2/64 - eps*X +| +| +| Now |X| <= 16446 log2, thus +| +| |X - N*log2/64| <= (0.5 + 16446/2^(18))*log2/64 +| <= 0.57 log2/64. +| This bound will be used in Step 4. +| +| Step 4. Approximate exp(R)-1 by a polynomial +| p = R + R*R*(A1 + R*(A2 + R*(A3 + R*(A4 + R*A5)))) +| Notes: a) In order to reduce memory access, the coefficients are +| made as "short" as possible: A1 (which is 1/2), A4 and A5 +| are single precision; A2 and A3 are double precision. +| b) Even with the restrictions above, +| |p - (exp(R)-1)| < 2^(-68.8) for all |R| <= 0.0062. +| Note that 0.0062 is slightly bigger than 0.57 log2/64. +| c) To fully utilize the pipeline, p is separated into +| two independent pieces of roughly equal complexities +| p = [ R + R*S*(A2 + S*A4) ] + +| [ S*(A1 + S*(A3 + S*A5)) ] +| where S = R*R. +| +| Step 5. Compute 2^(J/64)*exp(R) = 2^(J/64)*(1+p) by +| ans := T + ( T*p + t) +| where T and t are the stored values for 2^(J/64). +| Notes: 2^(J/64) is stored as T and t where T+t approximates +| 2^(J/64) to roughly 85 bits; T is in extended precision +| and t is in single precision. Note also that T is rounded +| to 62 bits so that the last two bits of T are zero. The +| reason for such a special form is that T-1, T-2, and T-8 +| will all be exact --- a property that will give much +| more accurate computation of the function EXPM1. +| +| Step 6. Reconstruction of exp(X) +| exp(X) = 2^M * 2^(J/64) * exp(R). +| 6.1 If AdjFlag = 0, go to 6.3 +| 6.2 ans := ans * AdjScale +| 6.3 Restore the user FPCR +| 6.4 Return ans := ans * Scale. Exit. +| Notes: If AdjFlag = 0, we have X = Mlog2 + Jlog2/64 + R, +| |M| <= 16380, and Scale = 2^M. Moreover, exp(X) will +| neither overflow nor underflow. If AdjFlag = 1, that +| means that +| X = (M1+M)log2 + Jlog2/64 + R, |M1+M| >= 16380. +| Hence, exp(X) may overflow or underflow or neither. +| When that is the case, AdjScale = 2^(M1) where M1 is +| approximately M. Thus 6.2 will never cause over/underflow. +| Possible exception in 6.4 is overflow or underflow. +| The inexact exception is not generated in 6.4. Although +| one can argue that the inexact flag should always be +| raised, to simulate that exception cost to much than the +| flag is worth in practical uses. +| +| Step 7. Return 1 + X. +| 7.1 ans := X +| 7.2 Restore user FPCR. +| 7.3 Return ans := 1 + ans. Exit +| Notes: For non-zero X, the inexact exception will always be +| raised by 7.3. That is the only exception raised by 7.3. +| Note also that we use the FMOVEM instruction to move X +| in Step 7.1 to avoid unnecessary trapping. (Although +| the FMOVEM may not seem relevant since X is normalized, +| the precaution will be useful in the library version of +| this code where the separate entry for denormalized inputs +| will be done away with.) +| +| Step 8. Handle exp(X) where |X| >= 16380log2. +| 8.1 If |X| > 16480 log2, go to Step 9. +| (mimic 2.2 - 2.6) +| 8.2 N := round-to-integer( X * 64/log2 ) +| 8.3 Calculate J = N mod 64, J = 0,1,...,63 +| 8.4 K := (N-J)/64, M1 := truncate(K/2), M = K-M1, AdjFlag := 1. +| 8.5 Calculate the address of the stored value 2^(J/64). +| 8.6 Create the values Scale = 2^M, AdjScale = 2^M1. +| 8.7 Go to Step 3. +| Notes: Refer to notes for 2.2 - 2.6. +| +| Step 9. Handle exp(X), |X| > 16480 log2. +| 9.1 If X < 0, go to 9.3 +| 9.2 ans := Huge, go to 9.4 +| 9.3 ans := Tiny. +| 9.4 Restore user FPCR. +| 9.5 Return ans := ans * ans. Exit. +| Notes: Exp(X) will surely overflow or underflow, depending on +| X's sign. "Huge" and "Tiny" are respectively large/tiny +| extended-precision numbers whose square over/underflow +| with an inexact result. Thus, 9.5 always raises the +| inexact together with either overflow or underflow. +| +| +| setoxm1d +| -------- +| +| Step 1. Set ans := 0 +| +| Step 2. Return ans := X + ans. Exit. +| Notes: This will return X with the appropriate rounding +| precision prescribed by the user FPCR. +| +| setoxm1 +| ------- +| +| Step 1. Check |X| +| 1.1 If |X| >= 1/4, go to Step 1.3. +| 1.2 Go to Step 7. +| 1.3 If |X| < 70 log(2), go to Step 2. +| 1.4 Go to Step 10. +| Notes: The usual case should take the branches 1.1 -> 1.3 -> 2. +| However, it is conceivable |X| can be small very often +| because EXPM1 is intended to evaluate exp(X)-1 accurately +| when |X| is small. For further details on the comparisons, +| see the notes on Step 1 of setox. +| +| Step 2. Calculate N = round-to-nearest-int( X * 64/log2 ). +| 2.1 N := round-to-nearest-integer( X * 64/log2 ). +| 2.2 Calculate J = N mod 64; so J = 0,1,2,..., or 63. +| 2.3 Calculate M = (N - J)/64; so N = 64M + J. +| 2.4 Calculate the address of the stored value of 2^(J/64). +| 2.5 Create the values Sc = 2^M and OnebySc := -2^(-M). +| Notes: See the notes on Step 2 of setox. +| +| Step 3. Calculate X - N*log2/64. +| 3.1 R := X + N*L1, where L1 := single-precision(-log2/64). +| 3.2 R := R + N*L2, L2 := extended-precision(-log2/64 - L1). +| Notes: Applying the analysis of Step 3 of setox in this case +| shows that |R| <= 0.0055 (note that |X| <= 70 log2 in +| this case). +| +| Step 4. Approximate exp(R)-1 by a polynomial +| p = R+R*R*(A1+R*(A2+R*(A3+R*(A4+R*(A5+R*A6))))) +| Notes: a) In order to reduce memory access, the coefficients are +| made as "short" as possible: A1 (which is 1/2), A5 and A6 +| are single precision; A2, A3 and A4 are double precision. +| b) Even with the restriction above, +| |p - (exp(R)-1)| < |R| * 2^(-72.7) +| for all |R| <= 0.0055. +| c) To fully utilize the pipeline, p is separated into +| two independent pieces of roughly equal complexity +| p = [ R*S*(A2 + S*(A4 + S*A6)) ] + +| [ R + S*(A1 + S*(A3 + S*A5)) ] +| where S = R*R. +| +| Step 5. Compute 2^(J/64)*p by +| p := T*p +| where T and t are the stored values for 2^(J/64). +| Notes: 2^(J/64) is stored as T and t where T+t approximates +| 2^(J/64) to roughly 85 bits; T is in extended precision +| and t is in single precision. Note also that T is rounded +| to 62 bits so that the last two bits of T are zero. The +| reason for such a special form is that T-1, T-2, and T-8 +| will all be exact --- a property that will be exploited +| in Step 6 below. The total relative error in p is no +| bigger than 2^(-67.7) compared to the final result. +| +| Step 6. Reconstruction of exp(X)-1 +| exp(X)-1 = 2^M * ( 2^(J/64) + p - 2^(-M) ). +| 6.1 If M <= 63, go to Step 6.3. +| 6.2 ans := T + (p + (t + OnebySc)). Go to 6.6 +| 6.3 If M >= -3, go to 6.5. +| 6.4 ans := (T + (p + t)) + OnebySc. Go to 6.6 +| 6.5 ans := (T + OnebySc) + (p + t). +| 6.6 Restore user FPCR. +| 6.7 Return ans := Sc * ans. Exit. +| Notes: The various arrangements of the expressions give accurate +| evaluations. +| +| Step 7. exp(X)-1 for |X| < 1/4. +| 7.1 If |X| >= 2^(-65), go to Step 9. +| 7.2 Go to Step 8. +| +| Step 8. Calculate exp(X)-1, |X| < 2^(-65). +| 8.1 If |X| < 2^(-16312), goto 8.3 +| 8.2 Restore FPCR; return ans := X - 2^(-16382). Exit. +| 8.3 X := X * 2^(140). +| 8.4 Restore FPCR; ans := ans - 2^(-16382). +| Return ans := ans*2^(140). Exit +| Notes: The idea is to return "X - tiny" under the user +| precision and rounding modes. To avoid unnecessary +| inefficiency, we stay away from denormalized numbers the +| best we can. For |X| >= 2^(-16312), the straightforward +| 8.2 generates the inexact exception as the case warrants. +| +| Step 9. Calculate exp(X)-1, |X| < 1/4, by a polynomial +| p = X + X*X*(B1 + X*(B2 + ... + X*B12)) +| Notes: a) In order to reduce memory access, the coefficients are +| made as "short" as possible: B1 (which is 1/2), B9 to B12 +| are single precision; B3 to B8 are double precision; and +| B2 is double extended. +| b) Even with the restriction above, +| |p - (exp(X)-1)| < |X| 2^(-70.6) +| for all |X| <= 0.251. +| Note that 0.251 is slightly bigger than 1/4. +| c) To fully preserve accuracy, the polynomial is computed +| as X + ( S*B1 + Q ) where S = X*X and +| Q = X*S*(B2 + X*(B3 + ... + X*B12)) +| d) To fully utilize the pipeline, Q is separated into +| two independent pieces of roughly equal complexity +| Q = [ X*S*(B2 + S*(B4 + ... + S*B12)) ] + +| [ S*S*(B3 + S*(B5 + ... + S*B11)) ] +| +| Step 10. Calculate exp(X)-1 for |X| >= 70 log 2. +| 10.1 If X >= 70log2 , exp(X) - 1 = exp(X) for all practical +| purposes. Therefore, go to Step 1 of setox. +| 10.2 If X <= -70log2, exp(X) - 1 = -1 for all practical purposes. +| ans := -1 +| Restore user FPCR +| Return ans := ans + 2^(-126). Exit. +| Notes: 10.2 will always create an inexact and return -1 + tiny +| in the user rounding precision and mode. +| +| + +| Copyright (C) Motorola, Inc. 1990 +| All Rights Reserved +| +| THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA +| The copyright notice above does not evidence any +| actual or intended publication of such source code. + +|setox idnt 2,1 | Motorola 040 Floating Point Software Package + + |section 8 + + .include "fpsp.h" + +L2: .long 0x3FDC0000,0x82E30865,0x4361C4C6,0x00000000 + +EXPA3: .long 0x3FA55555,0x55554431 +EXPA2: .long 0x3FC55555,0x55554018 + +HUGE: .long 0x7FFE0000,0xFFFFFFFF,0xFFFFFFFF,0x00000000 +TINY: .long 0x00010000,0xFFFFFFFF,0xFFFFFFFF,0x00000000 + +EM1A4: .long 0x3F811111,0x11174385 +EM1A3: .long 0x3FA55555,0x55554F5A + +EM1A2: .long 0x3FC55555,0x55555555,0x00000000,0x00000000 + +EM1B8: .long 0x3EC71DE3,0xA5774682 +EM1B7: .long 0x3EFA01A0,0x19D7CB68 + +EM1B6: .long 0x3F2A01A0,0x1A019DF3 +EM1B5: .long 0x3F56C16C,0x16C170E2 + +EM1B4: .long 0x3F811111,0x11111111 +EM1B3: .long 0x3FA55555,0x55555555 + +EM1B2: .long 0x3FFC0000,0xAAAAAAAA,0xAAAAAAAB + .long 0x00000000 + +TWO140: .long 0x48B00000,0x00000000 +TWON140: .long 0x37300000,0x00000000 + +EXPTBL: + .long 0x3FFF0000,0x80000000,0x00000000,0x00000000 + .long 0x3FFF0000,0x8164D1F3,0xBC030774,0x9F841A9B + .long 0x3FFF0000,0x82CD8698,0xAC2BA1D8,0x9FC1D5B9 + .long 0x3FFF0000,0x843A28C3,0xACDE4048,0xA0728369 + .long 0x3FFF0000,0x85AAC367,0xCC487B14,0x1FC5C95C + .long 0x3FFF0000,0x871F6196,0x9E8D1010,0x1EE85C9F + .long 0x3FFF0000,0x88980E80,0x92DA8528,0x9FA20729 + .long 0x3FFF0000,0x8A14D575,0x496EFD9C,0xA07BF9AF + .long 0x3FFF0000,0x8B95C1E3,0xEA8BD6E8,0xA0020DCF + .long 0x3FFF0000,0x8D1ADF5B,0x7E5BA9E4,0x205A63DA + .long 0x3FFF0000,0x8EA4398B,0x45CD53C0,0x1EB70051 + .long 0x3FFF0000,0x9031DC43,0x1466B1DC,0x1F6EB029 + .long 0x3FFF0000,0x91C3D373,0xAB11C338,0xA0781494 + .long 0x3FFF0000,0x935A2B2F,0x13E6E92C,0x9EB319B0 + .long 0x3FFF0000,0x94F4EFA8,0xFEF70960,0x2017457D + .long 0x3FFF0000,0x96942D37,0x20185A00,0x1F11D537 + .long 0x3FFF0000,0x9837F051,0x8DB8A970,0x9FB952DD + .long 0x3FFF0000,0x99E04593,0x20B7FA64,0x1FE43087 + .long 0x3FFF0000,0x9B8D39B9,0xD54E5538,0x1FA2A818 + .long 0x3FFF0000,0x9D3ED9A7,0x2CFFB750,0x1FDE494D + .long 0x3FFF0000,0x9EF53260,0x91A111AC,0x20504890 + .long 0x3FFF0000,0xA0B0510F,0xB9714FC4,0xA073691C + .long 0x3FFF0000,0xA2704303,0x0C496818,0x1F9B7A05 + .long 0x3FFF0000,0xA43515AE,0x09E680A0,0xA0797126 + .long 0x3FFF0000,0xA5FED6A9,0xB15138EC,0xA071A140 + .long 0x3FFF0000,0xA7CD93B4,0xE9653568,0x204F62DA + .long 0x3FFF0000,0xA9A15AB4,0xEA7C0EF8,0x1F283C4A + .long 0x3FFF0000,0xAB7A39B5,0xA93ED338,0x9F9A7FDC + .long 0x3FFF0000,0xAD583EEA,0x42A14AC8,0xA05B3FAC + .long 0x3FFF0000,0xAF3B78AD,0x690A4374,0x1FDF2610 + .long 0x3FFF0000,0xB123F581,0xD2AC2590,0x9F705F90 + .long 0x3FFF0000,0xB311C412,0xA9112488,0x201F678A + .long 0x3FFF0000,0xB504F333,0xF9DE6484,0x1F32FB13 + .long 0x3FFF0000,0xB6FD91E3,0x28D17790,0x20038B30 + .long 0x3FFF0000,0xB8FBAF47,0x62FB9EE8,0x200DC3CC + .long 0x3FFF0000,0xBAFF5AB2,0x133E45FC,0x9F8B2AE6 + .long 0x3FFF0000,0xBD08A39F,0x580C36C0,0xA02BBF70 + .long 0x3FFF0000,0xBF1799B6,0x7A731084,0xA00BF518 + .long 0x3FFF0000,0xC12C4CCA,0x66709458,0xA041DD41 + .long 0x3FFF0000,0xC346CCDA,0x24976408,0x9FDF137B + .long 0x3FFF0000,0xC5672A11,0x5506DADC,0x201F1568 + .long 0x3FFF0000,0xC78D74C8,0xABB9B15C,0x1FC13A2E + .long 0x3FFF0000,0xC9B9BD86,0x6E2F27A4,0xA03F8F03 + .long 0x3FFF0000,0xCBEC14FE,0xF2727C5C,0x1FF4907D + .long 0x3FFF0000,0xCE248C15,0x1F8480E4,0x9E6E53E4 + .long 0x3FFF0000,0xD06333DA,0xEF2B2594,0x1FD6D45C + .long 0x3FFF0000,0xD2A81D91,0xF12AE45C,0xA076EDB9 + .long 0x3FFF0000,0xD4F35AAB,0xCFEDFA20,0x9FA6DE21 + .long 0x3FFF0000,0xD744FCCA,0xD69D6AF4,0x1EE69A2F + .long 0x3FFF0000,0xD99D15C2,0x78AFD7B4,0x207F439F + .long 0x3FFF0000,0xDBFBB797,0xDAF23754,0x201EC207 + .long 0x3FFF0000,0xDE60F482,0x5E0E9124,0x9E8BE175 + .long 0x3FFF0000,0xE0CCDEEC,0x2A94E110,0x20032C4B + .long 0x3FFF0000,0xE33F8972,0xBE8A5A50,0x2004DFF5 + .long 0x3FFF0000,0xE5B906E7,0x7C8348A8,0x1E72F47A + .long 0x3FFF0000,0xE8396A50,0x3C4BDC68,0x1F722F22 + .long 0x3FFF0000,0xEAC0C6E7,0xDD243930,0xA017E945 + .long 0x3FFF0000,0xED4F301E,0xD9942B84,0x1F401A5B + .long 0x3FFF0000,0xEFE4B99B,0xDCDAF5CC,0x9FB9A9E3 + .long 0x3FFF0000,0xF281773C,0x59FFB138,0x20744C05 + .long 0x3FFF0000,0xF5257D15,0x2486CC2C,0x1F773A19 + .long 0x3FFF0000,0xF7D0DF73,0x0AD13BB8,0x1FFE90D5 + .long 0x3FFF0000,0xFA83B2DB,0x722A033C,0xA041ED22 + .long 0x3FFF0000,0xFD3E0C0C,0xF486C174,0x1F853F3A + + .set ADJFLAG,L_SCR2 + .set SCALE,FP_SCR1 + .set ADJSCALE,FP_SCR2 + .set SC,FP_SCR3 + .set ONEBYSC,FP_SCR4 + + | xref t_frcinx + |xref t_extdnrm + |xref t_unfl + |xref t_ovfl + + .global setoxd +setoxd: +|--entry point for EXP(X), X is denormalized + movel (%a0),%d0 + andil #0x80000000,%d0 + oril #0x00800000,%d0 | ...sign(X)*2^(-126) + movel %d0,-(%sp) + fmoves #0x3F800000,%fp0 + fmovel %d1,%fpcr + fadds (%sp)+,%fp0 + bra t_frcinx + + .global setox +setox: +|--entry point for EXP(X), here X is finite, non-zero, and not NaN's + +|--Step 1. + movel (%a0),%d0 | ...load part of input X + andil #0x7FFF0000,%d0 | ...biased expo. of X + cmpil #0x3FBE0000,%d0 | ...2^(-65) + bges EXPC1 | ...normal case + bra EXPSM + +EXPC1: +|--The case |X| >= 2^(-65) + movew 4(%a0),%d0 | ...expo. and partial sig. of |X| + cmpil #0x400CB167,%d0 | ...16380 log2 trunc. 16 bits + blts EXPMAIN | ...normal case + bra EXPBIG + +EXPMAIN: +|--Step 2. +|--This is the normal branch: 2^(-65) <= |X| < 16380 log2. + fmovex (%a0),%fp0 | ...load input from (a0) + + fmovex %fp0,%fp1 + fmuls #0x42B8AA3B,%fp0 | ...64/log2 * X + fmovemx %fp2-%fp2/%fp3,-(%a7) | ...save fp2 + movel #0,ADJFLAG(%a6) + fmovel %fp0,%d0 | ...N = int( X * 64/log2 ) + lea EXPTBL,%a1 + fmovel %d0,%fp0 | ...convert to floating-format + + movel %d0,L_SCR1(%a6) | ...save N temporarily + andil #0x3F,%d0 | ...D0 is J = N mod 64 + lsll #4,%d0 + addal %d0,%a1 | ...address of 2^(J/64) + movel L_SCR1(%a6),%d0 + asrl #6,%d0 | ...D0 is M + addiw #0x3FFF,%d0 | ...biased expo. of 2^(M) + movew L2,L_SCR1(%a6) | ...prefetch L2, no need in CB + +EXPCONT1: +|--Step 3. +|--fp1,fp2 saved on the stack. fp0 is N, fp1 is X, +|--a0 points to 2^(J/64), D0 is biased expo. of 2^(M) + fmovex %fp0,%fp2 + fmuls #0xBC317218,%fp0 | ...N * L1, L1 = lead(-log2/64) + fmulx L2,%fp2 | ...N * L2, L1+L2 = -log2/64 + faddx %fp1,%fp0 | ...X + N*L1 + faddx %fp2,%fp0 | ...fp0 is R, reduced arg. +| MOVE.W #$3FA5,EXPA3 ...load EXPA3 in cache + +|--Step 4. +|--WE NOW COMPUTE EXP(R)-1 BY A POLYNOMIAL +|-- R + R*R*(A1 + R*(A2 + R*(A3 + R*(A4 + R*A5)))) +|--TO FULLY UTILIZE THE PIPELINE, WE COMPUTE S = R*R +|--[R+R*S*(A2+S*A4)] + [S*(A1+S*(A3+S*A5))] + + fmovex %fp0,%fp1 + fmulx %fp1,%fp1 | ...fp1 IS S = R*R + + fmoves #0x3AB60B70,%fp2 | ...fp2 IS A5 +| MOVE.W #0,2(%a1) ...load 2^(J/64) in cache + + fmulx %fp1,%fp2 | ...fp2 IS S*A5 + fmovex %fp1,%fp3 + fmuls #0x3C088895,%fp3 | ...fp3 IS S*A4 + + faddd EXPA3,%fp2 | ...fp2 IS A3+S*A5 + faddd EXPA2,%fp3 | ...fp3 IS A2+S*A4 + + fmulx %fp1,%fp2 | ...fp2 IS S*(A3+S*A5) + movew %d0,SCALE(%a6) | ...SCALE is 2^(M) in extended + clrw SCALE+2(%a6) + movel #0x80000000,SCALE+4(%a6) + clrl SCALE+8(%a6) + + fmulx %fp1,%fp3 | ...fp3 IS S*(A2+S*A4) + + fadds #0x3F000000,%fp2 | ...fp2 IS A1+S*(A3+S*A5) + fmulx %fp0,%fp3 | ...fp3 IS R*S*(A2+S*A4) + + fmulx %fp1,%fp2 | ...fp2 IS S*(A1+S*(A3+S*A5)) + faddx %fp3,%fp0 | ...fp0 IS R+R*S*(A2+S*A4), +| ...fp3 released + + fmovex (%a1)+,%fp1 | ...fp1 is lead. pt. of 2^(J/64) + faddx %fp2,%fp0 | ...fp0 is EXP(R) - 1 +| ...fp2 released + +|--Step 5 +|--final reconstruction process +|--EXP(X) = 2^M * ( 2^(J/64) + 2^(J/64)*(EXP(R)-1) ) + + fmulx %fp1,%fp0 | ...2^(J/64)*(Exp(R)-1) + fmovemx (%a7)+,%fp2-%fp2/%fp3 | ...fp2 restored + fadds (%a1),%fp0 | ...accurate 2^(J/64) + + faddx %fp1,%fp0 | ...2^(J/64) + 2^(J/64)*... + movel ADJFLAG(%a6),%d0 + +|--Step 6 + tstl %d0 + beqs NORMAL +ADJUST: + fmulx ADJSCALE(%a6),%fp0 +NORMAL: + fmovel %d1,%FPCR | ...restore user FPCR + fmulx SCALE(%a6),%fp0 | ...multiply 2^(M) + bra t_frcinx + +EXPSM: +|--Step 7 + fmovemx (%a0),%fp0-%fp0 | ...in case X is denormalized + fmovel %d1,%FPCR + fadds #0x3F800000,%fp0 | ...1+X in user mode + bra t_frcinx + +EXPBIG: +|--Step 8 + cmpil #0x400CB27C,%d0 | ...16480 log2 + bgts EXP2BIG +|--Steps 8.2 -- 8.6 + fmovex (%a0),%fp0 | ...load input from (a0) + + fmovex %fp0,%fp1 + fmuls #0x42B8AA3B,%fp0 | ...64/log2 * X + fmovemx %fp2-%fp2/%fp3,-(%a7) | ...save fp2 + movel #1,ADJFLAG(%a6) + fmovel %fp0,%d0 | ...N = int( X * 64/log2 ) + lea EXPTBL,%a1 + fmovel %d0,%fp0 | ...convert to floating-format + movel %d0,L_SCR1(%a6) | ...save N temporarily + andil #0x3F,%d0 | ...D0 is J = N mod 64 + lsll #4,%d0 + addal %d0,%a1 | ...address of 2^(J/64) + movel L_SCR1(%a6),%d0 + asrl #6,%d0 | ...D0 is K + movel %d0,L_SCR1(%a6) | ...save K temporarily + asrl #1,%d0 | ...D0 is M1 + subl %d0,L_SCR1(%a6) | ...a1 is M + addiw #0x3FFF,%d0 | ...biased expo. of 2^(M1) + movew %d0,ADJSCALE(%a6) | ...ADJSCALE := 2^(M1) + clrw ADJSCALE+2(%a6) + movel #0x80000000,ADJSCALE+4(%a6) + clrl ADJSCALE+8(%a6) + movel L_SCR1(%a6),%d0 | ...D0 is M + addiw #0x3FFF,%d0 | ...biased expo. of 2^(M) + bra EXPCONT1 | ...go back to Step 3 + +EXP2BIG: +|--Step 9 + fmovel %d1,%FPCR + movel (%a0),%d0 + bclrb #sign_bit,(%a0) | ...setox always returns positive + cmpil #0,%d0 + blt t_unfl + bra t_ovfl + + .global setoxm1d +setoxm1d: +|--entry point for EXPM1(X), here X is denormalized +|--Step 0. + bra t_extdnrm + + + .global setoxm1 +setoxm1: +|--entry point for EXPM1(X), here X is finite, non-zero, non-NaN + +|--Step 1. +|--Step 1.1 + movel (%a0),%d0 | ...load part of input X + andil #0x7FFF0000,%d0 | ...biased expo. of X + cmpil #0x3FFD0000,%d0 | ...1/4 + bges EM1CON1 | ...|X| >= 1/4 + bra EM1SM + +EM1CON1: +|--Step 1.3 +|--The case |X| >= 1/4 + movew 4(%a0),%d0 | ...expo. and partial sig. of |X| + cmpil #0x4004C215,%d0 | ...70log2 rounded up to 16 bits + bles EM1MAIN | ...1/4 <= |X| <= 70log2 + bra EM1BIG + +EM1MAIN: +|--Step 2. +|--This is the case: 1/4 <= |X| <= 70 log2. + fmovex (%a0),%fp0 | ...load input from (a0) + + fmovex %fp0,%fp1 + fmuls #0x42B8AA3B,%fp0 | ...64/log2 * X + fmovemx %fp2-%fp2/%fp3,-(%a7) | ...save fp2 +| MOVE.W #$3F81,EM1A4 ...prefetch in CB mode + fmovel %fp0,%d0 | ...N = int( X * 64/log2 ) + lea EXPTBL,%a1 + fmovel %d0,%fp0 | ...convert to floating-format + + movel %d0,L_SCR1(%a6) | ...save N temporarily + andil #0x3F,%d0 | ...D0 is J = N mod 64 + lsll #4,%d0 + addal %d0,%a1 | ...address of 2^(J/64) + movel L_SCR1(%a6),%d0 + asrl #6,%d0 | ...D0 is M + movel %d0,L_SCR1(%a6) | ...save a copy of M +| MOVE.W #$3FDC,L2 ...prefetch L2 in CB mode + +|--Step 3. +|--fp1,fp2 saved on the stack. fp0 is N, fp1 is X, +|--a0 points to 2^(J/64), D0 and a1 both contain M + fmovex %fp0,%fp2 + fmuls #0xBC317218,%fp0 | ...N * L1, L1 = lead(-log2/64) + fmulx L2,%fp2 | ...N * L2, L1+L2 = -log2/64 + faddx %fp1,%fp0 | ...X + N*L1 + faddx %fp2,%fp0 | ...fp0 is R, reduced arg. +| MOVE.W #$3FC5,EM1A2 ...load EM1A2 in cache + addiw #0x3FFF,%d0 | ...D0 is biased expo. of 2^M + +|--Step 4. +|--WE NOW COMPUTE EXP(R)-1 BY A POLYNOMIAL +|-- R + R*R*(A1 + R*(A2 + R*(A3 + R*(A4 + R*(A5 + R*A6))))) +|--TO FULLY UTILIZE THE PIPELINE, WE COMPUTE S = R*R +|--[R*S*(A2+S*(A4+S*A6))] + [R+S*(A1+S*(A3+S*A5))] + + fmovex %fp0,%fp1 + fmulx %fp1,%fp1 | ...fp1 IS S = R*R + + fmoves #0x3950097B,%fp2 | ...fp2 IS a6 +| MOVE.W #0,2(%a1) ...load 2^(J/64) in cache + + fmulx %fp1,%fp2 | ...fp2 IS S*A6 + fmovex %fp1,%fp3 + fmuls #0x3AB60B6A,%fp3 | ...fp3 IS S*A5 + + faddd EM1A4,%fp2 | ...fp2 IS A4+S*A6 + faddd EM1A3,%fp3 | ...fp3 IS A3+S*A5 + movew %d0,SC(%a6) | ...SC is 2^(M) in extended + clrw SC+2(%a6) + movel #0x80000000,SC+4(%a6) + clrl SC+8(%a6) + + fmulx %fp1,%fp2 | ...fp2 IS S*(A4+S*A6) + movel L_SCR1(%a6),%d0 | ...D0 is M + negw %d0 | ...D0 is -M + fmulx %fp1,%fp3 | ...fp3 IS S*(A3+S*A5) + addiw #0x3FFF,%d0 | ...biased expo. of 2^(-M) + faddd EM1A2,%fp2 | ...fp2 IS A2+S*(A4+S*A6) + fadds #0x3F000000,%fp3 | ...fp3 IS A1+S*(A3+S*A5) + + fmulx %fp1,%fp2 | ...fp2 IS S*(A2+S*(A4+S*A6)) + oriw #0x8000,%d0 | ...signed/expo. of -2^(-M) + movew %d0,ONEBYSC(%a6) | ...OnebySc is -2^(-M) + clrw ONEBYSC+2(%a6) + movel #0x80000000,ONEBYSC+4(%a6) + clrl ONEBYSC+8(%a6) + fmulx %fp3,%fp1 | ...fp1 IS S*(A1+S*(A3+S*A5)) +| ...fp3 released + + fmulx %fp0,%fp2 | ...fp2 IS R*S*(A2+S*(A4+S*A6)) + faddx %fp1,%fp0 | ...fp0 IS R+S*(A1+S*(A3+S*A5)) +| ...fp1 released + + faddx %fp2,%fp0 | ...fp0 IS EXP(R)-1 +| ...fp2 released + fmovemx (%a7)+,%fp2-%fp2/%fp3 | ...fp2 restored + +|--Step 5 +|--Compute 2^(J/64)*p + + fmulx (%a1),%fp0 | ...2^(J/64)*(Exp(R)-1) + +|--Step 6 +|--Step 6.1 + movel L_SCR1(%a6),%d0 | ...retrieve M + cmpil #63,%d0 + bles MLE63 +|--Step 6.2 M >= 64 + fmoves 12(%a1),%fp1 | ...fp1 is t + faddx ONEBYSC(%a6),%fp1 | ...fp1 is t+OnebySc + faddx %fp1,%fp0 | ...p+(t+OnebySc), fp1 released + faddx (%a1),%fp0 | ...T+(p+(t+OnebySc)) + bras EM1SCALE +MLE63: +|--Step 6.3 M <= 63 + cmpil #-3,%d0 + bges MGEN3 +MLTN3: +|--Step 6.4 M <= -4 + fadds 12(%a1),%fp0 | ...p+t + faddx (%a1),%fp0 | ...T+(p+t) + faddx ONEBYSC(%a6),%fp0 | ...OnebySc + (T+(p+t)) + bras EM1SCALE +MGEN3: +|--Step 6.5 -3 <= M <= 63 + fmovex (%a1)+,%fp1 | ...fp1 is T + fadds (%a1),%fp0 | ...fp0 is p+t + faddx ONEBYSC(%a6),%fp1 | ...fp1 is T+OnebySc + faddx %fp1,%fp0 | ...(T+OnebySc)+(p+t) + +EM1SCALE: +|--Step 6.6 + fmovel %d1,%FPCR + fmulx SC(%a6),%fp0 + + bra t_frcinx + +EM1SM: +|--Step 7 |X| < 1/4. + cmpil #0x3FBE0000,%d0 | ...2^(-65) + bges EM1POLY + +EM1TINY: +|--Step 8 |X| < 2^(-65) + cmpil #0x00330000,%d0 | ...2^(-16312) + blts EM12TINY +|--Step 8.2 + movel #0x80010000,SC(%a6) | ...SC is -2^(-16382) + movel #0x80000000,SC+4(%a6) + clrl SC+8(%a6) + fmovex (%a0),%fp0 + fmovel %d1,%FPCR + faddx SC(%a6),%fp0 + + bra t_frcinx + +EM12TINY: +|--Step 8.3 + fmovex (%a0),%fp0 + fmuld TWO140,%fp0 + movel #0x80010000,SC(%a6) + movel #0x80000000,SC+4(%a6) + clrl SC+8(%a6) + faddx SC(%a6),%fp0 + fmovel %d1,%FPCR + fmuld TWON140,%fp0 + + bra t_frcinx + +EM1POLY: +|--Step 9 exp(X)-1 by a simple polynomial + fmovex (%a0),%fp0 | ...fp0 is X + fmulx %fp0,%fp0 | ...fp0 is S := X*X + fmovemx %fp2-%fp2/%fp3,-(%a7) | ...save fp2 + fmoves #0x2F30CAA8,%fp1 | ...fp1 is B12 + fmulx %fp0,%fp1 | ...fp1 is S*B12 + fmoves #0x310F8290,%fp2 | ...fp2 is B11 + fadds #0x32D73220,%fp1 | ...fp1 is B10+S*B12 + + fmulx %fp0,%fp2 | ...fp2 is S*B11 + fmulx %fp0,%fp1 | ...fp1 is S*(B10 + ... + + fadds #0x3493F281,%fp2 | ...fp2 is B9+S*... + faddd EM1B8,%fp1 | ...fp1 is B8+S*... + + fmulx %fp0,%fp2 | ...fp2 is S*(B9+... + fmulx %fp0,%fp1 | ...fp1 is S*(B8+... + + faddd EM1B7,%fp2 | ...fp2 is B7+S*... + faddd EM1B6,%fp1 | ...fp1 is B6+S*... + + fmulx %fp0,%fp2 | ...fp2 is S*(B7+... + fmulx %fp0,%fp1 | ...fp1 is S*(B6+... + + faddd EM1B5,%fp2 | ...fp2 is B5+S*... + faddd EM1B4,%fp1 | ...fp1 is B4+S*... + + fmulx %fp0,%fp2 | ...fp2 is S*(B5+... + fmulx %fp0,%fp1 | ...fp1 is S*(B4+... + + faddd EM1B3,%fp2 | ...fp2 is B3+S*... + faddx EM1B2,%fp1 | ...fp1 is B2+S*... + + fmulx %fp0,%fp2 | ...fp2 is S*(B3+... + fmulx %fp0,%fp1 | ...fp1 is S*(B2+... + + fmulx %fp0,%fp2 | ...fp2 is S*S*(B3+...) + fmulx (%a0),%fp1 | ...fp1 is X*S*(B2... + + fmuls #0x3F000000,%fp0 | ...fp0 is S*B1 + faddx %fp2,%fp1 | ...fp1 is Q +| ...fp2 released + + fmovemx (%a7)+,%fp2-%fp2/%fp3 | ...fp2 restored + + faddx %fp1,%fp0 | ...fp0 is S*B1+Q +| ...fp1 released + + fmovel %d1,%FPCR + faddx (%a0),%fp0 + + bra t_frcinx + +EM1BIG: +|--Step 10 |X| > 70 log2 + movel (%a0),%d0 + cmpil #0,%d0 + bgt EXPC1 +|--Step 10.2 + fmoves #0xBF800000,%fp0 | ...fp0 is -1 + fmovel %d1,%FPCR + fadds #0x00800000,%fp0 | ...-1 + 2^(-126) + + bra t_frcinx + + |end diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/sgetem.S linux/arch/m68k/fpsp040/sgetem.S --- v1.3.93/linux/arch/m68k/fpsp040/sgetem.S Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/fpsp040/sgetem.S Sat Feb 24 22:58:44 1996 @@ -0,0 +1,141 @@ +| +| sgetem.sa 3.1 12/10/90 +| +| The entry point sGETEXP returns the exponent portion +| of the input argument. The exponent bias is removed +| and the exponent value is returned as an extended +| precision number in fp0. sGETEXPD handles denormalized +| numbers. +| +| The entry point sGETMAN extracts the mantissa of the +| input argument. The mantissa is converted to an +| extended precision number and returned in fp0. The +| range of the result is [1.0 - 2.0). +| +| +| Input: Double-extended number X in the ETEMP space in +| the floating-point save stack. +| +| Output: The functions return exp(X) or man(X) in fp0. +| +| Modified: fp0. +| +| +| Copyright (C) Motorola, Inc. 1990 +| All Rights Reserved +| +| THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA +| The copyright notice above does not evidence any +| actual or intended publication of such source code. + +|SGETEM idnt 2,1 | Motorola 040 Floating Point Software Package + + |section 8 + + .include "fpsp.h" + + |xref nrm_set + +| +| This entry point is used by the unimplemented instruction exception +| handler. It points a0 to the input operand. +| +| +| +| SGETEXP +| + + .global sgetexp +sgetexp: + movew LOCAL_EX(%a0),%d0 |get the exponent + bclrl #15,%d0 |clear the sign bit + subw #0x3fff,%d0 |subtract off the bias + fmovew %d0,%fp0 |move the exp to fp0 + rts + + .global sgetexpd +sgetexpd: + bclrb #sign_bit,LOCAL_EX(%a0) + bsr nrm_set |normalize (exp will go negative) + movew LOCAL_EX(%a0),%d0 |load resulting exponent into d0 + subw #0x3fff,%d0 |subtract off the bias + fmovew %d0,%fp0 |move the exp to fp0 + rts +| +| +| This entry point is used by the unimplemented instruction exception +| handler. It points a0 to the input operand. +| +| +| +| SGETMAN +| +| +| For normalized numbers, leave the mantissa alone, simply load +| with an exponent of +/- $3fff. +| + .global sgetman +sgetman: + movel USER_FPCR(%a6),%d0 + andil #0xffffff00,%d0 |clear rounding precision and mode + fmovel %d0,%fpcr |this fpcr setting is used by the 882 + movew LOCAL_EX(%a0),%d0 |get the exp (really just want sign bit) + orw #0x7fff,%d0 |clear old exp + bclrl #14,%d0 |make it the new exp +-3fff + movew %d0,LOCAL_EX(%a0) |move the sign & exp back to fsave stack + fmovex (%a0),%fp0 |put new value back in fp0 + rts + +| +| For denormalized numbers, shift the mantissa until the j-bit = 1, +| then load the exponent with +/1 $3fff. +| + .global sgetmand +sgetmand: + movel LOCAL_HI(%a0),%d0 |load ms mant in d0 + movel LOCAL_LO(%a0),%d1 |load ls mant in d1 + bsr shft |shift mantissa bits till msbit is set + movel %d0,LOCAL_HI(%a0) |put ms mant back on stack + movel %d1,LOCAL_LO(%a0) |put ls mant back on stack + bras sgetman + +| +| SHFT +| +| Shifts the mantissa bits until msbit is set. +| input: +| ms mantissa part in d0 +| ls mantissa part in d1 +| output: +| shifted bits in d0 and d1 +shft: + tstl %d0 |if any bits set in ms mant + bnes upper |then branch +| ;else no bits set in ms mant + tstl %d1 |test if any bits set in ls mant + bnes cont |if set then continue + bras shft_end |else return +cont: + movel %d3,-(%a7) |save d3 + exg %d0,%d1 |shift ls mant to ms mant + bfffo %d0{#0:#32},%d3 |find first 1 in ls mant to d0 + lsll %d3,%d0 |shift first 1 to integer bit in ms mant + movel (%a7)+,%d3 |restore d3 + bras shft_end +upper: + + moveml %d3/%d5/%d6,-(%a7) |save registers + bfffo %d0{#0:#32},%d3 |find first 1 in ls mant to d0 + lsll %d3,%d0 |shift ms mant until j-bit is set + movel %d1,%d6 |save ls mant in d6 + lsll %d3,%d1 |shift ls mant by count + movel #32,%d5 + subl %d3,%d5 |sub 32 from shift for ls mant + lsrl %d5,%d6 |shift off all bits but those that will +| ;be shifted into ms mant + orl %d6,%d0 |shift the ls mant bits into the ms mant + moveml (%a7)+,%d3/%d5/%d6 |restore registers +shft_end: + rts + + |end diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/sint.S linux/arch/m68k/fpsp040/sint.S --- v1.3.93/linux/arch/m68k/fpsp040/sint.S Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/fpsp040/sint.S Sat Feb 24 22:58:44 1996 @@ -0,0 +1,247 @@ +| +| sint.sa 3.1 12/10/90 +| +| The entry point sINT computes the rounded integer +| equivalent of the input argument, sINTRZ computes +| the integer rounded to zero of the input argument. +| +| Entry points sint and sintrz are called from do_func +| to emulate the fint and fintrz unimplemented instructions, +| respectively. Entry point sintdo is used by bindec. +| +| Input: (Entry points sint and sintrz) Double-extended +| number X in the ETEMP space in the floating-point +| save stack. +| (Entry point sintdo) Double-extended number X in +| location pointed to by the address register a0. +| (Entry point sintd) Double-extended denormalized +| number X in the ETEMP space in the floating-point +| save stack. +| +| Output: The function returns int(X) or intrz(X) in fp0. +| +| Modifies: fp0. +| +| Algorithm: (sint and sintrz) +| +| 1. If exp(X) >= 63, return X. +| If exp(X) < 0, return +/- 0 or +/- 1, according to +| the rounding mode. +| +| 2. (X is in range) set rsc = 63 - exp(X). Unnormalize the +| result to the exponent $403e. +| +| 3. Round the result in the mode given in USER_FPCR. For +| sintrz, force round-to-zero mode. +| +| 4. Normalize the rounded result; store in fp0. +| +| For the denormalized cases, force the correct result +| for the given sign and rounding mode. +| +| Sign(X) +| RMODE + - +| ----- -------- +| RN +0 -0 +| RZ +0 -0 +| RM +0 -1 +| RP +1 -0 +| +| +| Copyright (C) Motorola, Inc. 1990 +| All Rights Reserved +| +| THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA +| The copyright notice above does not evidence any +| actual or intended publication of such source code. + +|SINT idnt 2,1 | Motorola 040 Floating Point Software Package + + |section 8 + + .include "fpsp.h" + + |xref dnrm_lp + |xref nrm_set + |xref round + |xref t_inx2 + |xref ld_pone + |xref ld_mone + |xref ld_pzero + |xref ld_mzero + |xref snzrinx + +| +| FINT +| + .global sint +sint: + bfextu FPCR_MODE(%a6){#2:#2},%d1 |use user's mode for rounding +| ;implicity has extend precision +| ;in upper word. + movel %d1,L_SCR1(%a6) |save mode bits + bras sintexc + +| +| FINT with extended denorm inputs. +| + .global sintd +sintd: + btstb #5,FPCR_MODE(%a6) + beq snzrinx |if round nearest or round zero, +/- 0 + btstb #4,FPCR_MODE(%a6) + beqs rnd_mns +rnd_pls: + btstb #sign_bit,LOCAL_EX(%a0) + bnes sintmz + bsr ld_pone |if round plus inf and pos, answer is +1 + bra t_inx2 +rnd_mns: + btstb #sign_bit,LOCAL_EX(%a0) + beqs sintpz + bsr ld_mone |if round mns inf and neg, answer is -1 + bra t_inx2 +sintpz: + bsr ld_pzero + bra t_inx2 +sintmz: + bsr ld_mzero + bra t_inx2 + +| +| FINTRZ +| + .global sintrz +sintrz: + movel #1,L_SCR1(%a6) |use rz mode for rounding +| ;implicity has extend precision +| ;in upper word. + bras sintexc +| +| SINTDO +| +| Input: a0 points to an IEEE extended format operand +| Output: fp0 has the result +| +| Exeptions: +| +| If the subroutine results in an inexact operation, the inx2 and +| ainx bits in the USER_FPSR are set. +| +| + .global sintdo +sintdo: + bfextu FPCR_MODE(%a6){#2:#2},%d1 |use user's mode for rounding +| ;implicitly has ext precision +| ;in upper word. + movel %d1,L_SCR1(%a6) |save mode bits +| +| Real work of sint is in sintexc +| +sintexc: + bclrb #sign_bit,LOCAL_EX(%a0) |convert to internal extended +| ;format + sne LOCAL_SGN(%a0) + cmpw #0x403e,LOCAL_EX(%a0) |check if (unbiased) exp > 63 + bgts out_rnge |branch if exp < 63 + cmpw #0x3ffd,LOCAL_EX(%a0) |check if (unbiased) exp < 0 + bgt in_rnge |if 63 >= exp > 0, do calc +| +| Input is less than zero. Restore sign, and check for directed +| rounding modes. L_SCR1 contains the rmode in the lower byte. +| +un_rnge: + btstb #1,L_SCR1+3(%a6) |check for rn and rz + beqs un_rnrz + tstb LOCAL_SGN(%a0) |check for sign + bnes un_rmrp_neg +| +| Sign is +. If rp, load +1.0, if rm, load +0.0 +| + cmpib #3,L_SCR1+3(%a6) |check for rp + beqs un_ldpone |if rp, load +1.0 + bsr ld_pzero |if rm, load +0.0 + bra t_inx2 +un_ldpone: + bsr ld_pone + bra t_inx2 +| +| Sign is -. If rm, load -1.0, if rp, load -0.0 +| +un_rmrp_neg: + cmpib #2,L_SCR1+3(%a6) |check for rm + beqs un_ldmone |if rm, load -1.0 + bsr ld_mzero |if rp, load -0.0 + bra t_inx2 +un_ldmone: + bsr ld_mone + bra t_inx2 +| +| Rmode is rn or rz; return signed zero +| +un_rnrz: + tstb LOCAL_SGN(%a0) |check for sign + bnes un_rnrz_neg + bsr ld_pzero + bra t_inx2 +un_rnrz_neg: + bsr ld_mzero + bra t_inx2 + +| +| Input is greater than 2^63. All bits are significant. Return +| the input. +| +out_rnge: + bfclr LOCAL_SGN(%a0){#0:#8} |change back to IEEE ext format + beqs intps + bsetb #sign_bit,LOCAL_EX(%a0) +intps: + fmovel %fpcr,-(%sp) + fmovel #0,%fpcr + fmovex LOCAL_EX(%a0),%fp0 |if exp > 63 +| ;then return X to the user +| ;there are no fraction bits + fmovel (%sp)+,%fpcr + rts + +in_rnge: +| ;shift off fraction bits + clrl %d0 |clear d0 - initial g,r,s for +| ;dnrm_lp + movel #0x403e,%d1 |set threshold for dnrm_lp +| ;assumes a0 points to operand + bsr dnrm_lp +| ;returns unnormalized number +| ;pointed by a0 +| ;output d0 supplies g,r,s +| ;used by round + movel L_SCR1(%a6),%d1 |use selected rounding mode +| +| + bsr round |round the unnorm based on users +| ;input a0 ptr to ext X +| ; d0 g,r,s bits +| ; d1 PREC/MODE info +| ;output a0 ptr to rounded result +| ;inexact flag set in USER_FPSR +| ;if initial grs set +| +| normalize the rounded result and store value in fp0 +| + bsr nrm_set |normalize the unnorm +| ;Input: a0 points to operand to +| ;be normalized +| ;Output: a0 points to normalized +| ;result + bfclr LOCAL_SGN(%a0){#0:#8} + beqs nrmrndp + bsetb #sign_bit,LOCAL_EX(%a0) |return to IEEE extended format +nrmrndp: + fmovel %fpcr,-(%sp) + fmovel #0,%fpcr + fmovex LOCAL_EX(%a0),%fp0 |move result to fp0 + fmovel (%sp)+,%fpcr + rts + + |end diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/skeleton.S linux/arch/m68k/fpsp040/skeleton.S --- v1.3.93/linux/arch/m68k/fpsp040/skeleton.S Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/fpsp040/skeleton.S Sat Apr 13 19:59:44 1996 @@ -0,0 +1,568 @@ +| +| skeleton.sa 3.2 4/26/91 +| +| This file contains code that is system dependent and will +| need to be modified to install the FPSP. +| +| Each entry point for exception 'xxxx' begins with a 'jmp fpsp_xxxx'. +| Put any target system specific handling that must be done immediately +| before the jump instruction. If there no handling necessary, then +| the 'fpsp_xxxx' handler entry point should be placed in the exception +| table so that the 'jmp' can be eliminated. If the FPSP determines that the +| exception is one that must be reported then there will be a +| return from the package by a 'jmp real_xxxx'. At that point +| the machine state will be identical to the state before +| the FPSP was entered. In particular, whatever condition +| that caused the exception will still be pending when the FPSP +| package returns. Thus, there will be system specific code +| to handle the exception. +| +| If the exception was completely handled by the package, then +| the return will be via a 'jmp fpsp_done'. Unless there is +| OS specific work to be done (such as handling a context switch or +| interrupt) the user program can be resumed via 'rte'. +| +| In the following skeleton code, some typical 'real_xxxx' handling +| code is shown. This code may need to be moved to an appropriate +| place in the target system, or rewritten. +| + +| Copyright (C) Motorola, Inc. 1990 +| All Rights Reserved +| +| THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA +| The copyright notice above does not evidence any +| actual or intended publication of such source code. + +| +| Modified for Linux-1.3.x by Jes Sorensen (jds@kom.auc.dk) +| + +#include + +|SKELETON idnt 2,1 | Motorola 040 Floating Point Software Package + + |section 15 +| +| The following counters are used for standalone testing +| +sigunimp: .long 0 +sigbsun: .long 0 +siginex: .long 0 +sigdz: .long 0 +sigunfl: .long 0 +sigovfl: .long 0 +sigoperr: .long 0 +sigsnan: .long 0 +sigunsupp: .long 0 + + |section 8 + + .include "fpsp.h" + +LOFF_ORIG_D0 = 0x20 + +#define SAVE_ALL \ + clrl %sp@-; /* stk_adj */ \ + movel %d0,%sp@-; /* orig d0 */ \ + movel %d0,%sp@-; /* d0 */ \ + moveml %d1-%d5/%a0-%a1,%sp@- + + |xref b1238_fix + +| +| Divide by Zero exception +| +| All dz exceptions are 'real', hence no fpsp_dz entry point. +| + .global dz + .global real_dz +dz: +real_dz: + link %a6,#-LOCAL_SIZE + fsave -(%sp) + bclrb #E1,E_BYTE(%a6) + frestore (%sp)+ + unlk %a6 + + addl #1,sigdz |for standalone testing + + SAVE_ALL + moveq #-1,%d0 + movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field + | signifies that the stack frame + | is NOT for syscall + movel %sp,%sp@- | stack frame pointer argument + bsrl SYMBOL_NAME(trap_c) + addql #4,%sp + bral SYMBOL_NAME(ret_from_exception) + +| +| Inexact exception +| +| All inexact exceptions are real, but the 'real' handler +| will probably want to clear the pending exception. +| The provided code will clear the E3 exception (if pending), +| otherwise clear the E1 exception. The frestore is not really +| necessary for E1 exceptions. +| +| Code following the 'inex' label is to handle bug #1232. In this +| bug, if an E1 snan, ovfl, or unfl occured, and the process was +| swapped out before taking the exception, the exception taken on +| return was inex, rather than the correct exception. The snan, ovfl, +| and unfl exception to be taken must not have been enabled. The +| fix is to check for E1, and the existence of one of snan, ovfl, +| or unfl bits set in the fpsr. If any of these are set, branch +| to the appropriate handler for the exception in the fpsr. Note +| that this fix is only for d43b parts, and is skipped if the +| version number is not $40. +| +| + .global real_inex + .global inex +inex: + link %a6,#-LOCAL_SIZE + fsave -(%sp) + cmpib #VER_40,(%sp) |test version number + bnes not_fmt40 + fmovel %fpsr,-(%sp) + btstb #E1,E_BYTE(%a6) |test for E1 set + beqs not_b1232 + btstb #snan_bit,2(%sp) |test for snan + beq inex_ckofl + addl #4,%sp + frestore (%sp)+ + unlk %a6 + bra snan +inex_ckofl: + btstb #ovfl_bit,2(%sp) |test for ovfl + beq inex_ckufl + addl #4,%sp + frestore (%sp)+ + unlk %a6 + bra ovfl +inex_ckufl: + btstb #unfl_bit,2(%sp) |test for unfl + beq not_b1232 + addl #4,%sp + frestore (%sp)+ + unlk %a6 + bra unfl + +| +| We do not have the bug 1232 case. Clean up the stack and call +| real_inex. +| +not_b1232: + addl #4,%sp + frestore (%sp)+ + unlk %a6 + +real_inex: + + addl #1,siginex |for standalone testing + + link %a6,#-LOCAL_SIZE + fsave -(%sp) +not_fmt40: + bclrb #E3,E_BYTE(%a6) |clear and test E3 flag + beqs inex_cke1 +| +| Clear dirty bit on dest resister in the frame before branching +| to b1238_fix. +| + moveml %d0/%d1,USER_DA(%a6) + bfextu CMDREG1B(%a6){#6:#3},%d0 |get dest reg no + bclrb %d0,FPR_DIRTY_BITS(%a6) |clr dest dirty bit + bsrl b1238_fix |test for bug1238 case + moveml USER_DA(%a6),%d0/%d1 + bras inex_done +inex_cke1: + bclrb #E1,E_BYTE(%a6) +inex_done: + frestore (%sp)+ + unlk %a6 + + SAVE_ALL + moveq #-1,%d0 + movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field + | signifies that the stack frame + | is NOT for syscall + movel %sp,%sp@- | stack frame pointer argument + bsrl SYMBOL_NAME(trap_c) + addql #4,%sp + bral SYMBOL_NAME(ret_from_exception) + +| +| Overflow exception +| + |xref fpsp_ovfl + .global real_ovfl + .global ovfl +ovfl: + jmp fpsp_ovfl +real_ovfl: + + addl #1,sigovfl |for standalone testing + + link %a6,#-LOCAL_SIZE + fsave -(%sp) + bclrb #E3,E_BYTE(%a6) |clear and test E3 flag + bnes ovfl_done + bclrb #E1,E_BYTE(%a6) +ovfl_done: + frestore (%sp)+ + unlk %a6 + + SAVE_ALL + moveq #-1,%d0 + movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field + | signifies that the stack frame + | is NOT for syscall + movel %sp,%sp@- | stack frame pointer argument + bsrl SYMBOL_NAME(trap_c) + addql #4,%sp + bral SYMBOL_NAME(ret_from_exception) + +| +| Underflow exception +| + |xref fpsp_unfl + .global real_unfl + .global unfl +unfl: + jmp fpsp_unfl +real_unfl: + + addl #1,sigunfl |for standalone testing + + link %a6,#-LOCAL_SIZE + fsave -(%sp) + bclrb #E3,E_BYTE(%a6) |clear and test E3 flag + bnes unfl_done + bclrb #E1,E_BYTE(%a6) +unfl_done: + frestore (%sp)+ + unlk %a6 + + SAVE_ALL + moveq #-1,%d0 + movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field + | signifies that the stack frame + | is NOT for syscall + movel %sp,%sp@- | stack frame pointer argument + bsrl SYMBOL_NAME(trap_c) + addql #4,%sp + bral SYMBOL_NAME(ret_from_exception) + +| +| Signalling NAN exception +| + |xref fpsp_snan + .global real_snan + .global snan +snan: + jmp fpsp_snan +real_snan: + link %a6,#-LOCAL_SIZE + fsave -(%sp) + bclrb #E1,E_BYTE(%a6) |snan is always an E1 exception + frestore (%sp)+ + unlk %a6 + + addl #1,sigsnan |for standalone testing + + SAVE_ALL + moveq #-1,%d0 + movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field + | signifies that the stack frame + | is NOT for syscall + movel %sp,%sp@- | stack frame pointer argument + bsrl SYMBOL_NAME(trap_c) + addql #4,%sp + bral SYMBOL_NAME(ret_from_exception) + +| +| Operand Error exception +| + |xref fpsp_operr + .global real_operr + .global operr +operr: + jmp fpsp_operr +real_operr: + link %a6,#-LOCAL_SIZE + fsave -(%sp) + bclrb #E1,E_BYTE(%a6) |operr is always an E1 exception + frestore (%sp)+ + unlk %a6 + + addl #1,sigoperr |for standalone testing + + + SAVE_ALL + moveq #-1,%d0 + movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field + | signifies that the stack frame + | is NOT for syscall + movel %sp,%sp@- | stack frame pointer argument + bsrl SYMBOL_NAME(trap_c) + addql #4,%sp + bral SYMBOL_NAME(ret_from_exception) + + +| +| BSUN exception +| +| This sample handler simply clears the nan bit in the FPSR. +| + |xref fpsp_bsun + .global real_bsun + .global bsun +bsun: + jmp fpsp_bsun +real_bsun: + link %a6,#-LOCAL_SIZE + fsave -(%sp) + bclrb #E1,E_BYTE(%a6) |bsun is always an E1 exception + fmovel %FPSR,-(%sp) + bclrb #nan_bit,(%sp) + fmovel (%sp)+,%FPSR + frestore (%sp)+ + unlk %a6 + + addl #1,sigbsun |for standalone testing + + + + SAVE_ALL + moveq #-1,%d0 + movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field + | signifies that the stack frame + | is NOT for syscall + movel %sp,%sp@- | stack frame pointer argument + bsrl SYMBOL_NAME(trap_c) + addql #4,%sp + bral SYMBOL_NAME(ret_from_exception) + +| +| F-line exception +| +| A 'real' F-line exception is one that the FPSP isn't supposed to +| handle. E.g. an instruction with a co-processor ID that is not 1. +| +| + |xref fpsp_fline + .global real_fline + .global fline +fline: + jmp fpsp_fline +real_fline: + + addl #1,sigunimp |for standalone testing + + + SAVE_ALL + moveq #-1,%d0 + movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field + | signifies that the stack frame + | is NOT for syscall + movel %sp,%sp@- | stack frame pointer argument + bsrl SYMBOL_NAME(trap_c) + addql #4,%sp + bral SYMBOL_NAME(ret_from_exception) + +| +| Unsupported data type exception +| + |xref fpsp_unsupp + .global real_unsupp + .global unsupp +unsupp: + jmp fpsp_unsupp +real_unsupp: + link %a6,#-LOCAL_SIZE + fsave -(%sp) + bclrb #E1,E_BYTE(%a6) |unsupp is always an E1 exception + frestore (%sp)+ + unlk %a6 + + addl #1,sigunsupp |for standalone testing + + + SAVE_ALL + moveq #-1,%d0 + movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field + | signifies that the stack frame + | is NOT for syscall + movel %sp,%sp@- | stack frame pointer argument + bsrl SYMBOL_NAME(trap_c) + addql #4,%sp + bral SYMBOL_NAME(ret_from_exception) + +| +| Trace exception +| + .global real_trace +real_trace: + | + bral SYMBOL_NAME(trap) + +| +| fpsp_fmt_error --- exit point for frame format error +| +| The fpu stack frame does not match the frames existing +| or planned at the time of this writing. The fpsp is +| unable to handle frame sizes not in the following +| version:size pairs: +| +| {4060, 4160} - busy frame +| {4028, 4130} - unimp frame +| {4000, 4100} - idle frame +| +| This entry point simply holds an f-line illegal value. +| Replace this with a call to your kernel panic code or +| code to handle future revisions of the fpu. +| + .global fpsp_fmt_error +fpsp_fmt_error: + + .long 0xf27f0000 |f-line illegal + +| +| fpsp_done --- FPSP exit point +| +| The exception has been handled by the package and we are ready +| to return to user mode, but there may be OS specific code +| to execute before we do. If there is, do it now. +| +| + + .global fpsp_done +fpsp_done: + btst #0x5,%sp@ | supervisor bit set in saved SR? + beq Lnotkern + rte +Lnotkern: + tstl SYMBOL_NAME(need_resched) + bne Lmustsched + rte +Lmustsched: + SAVE_ALL + moveq #-1,%d0 + movel %d0,%sp@(LOFF_ORIG_D0) | indicate stack frame not for syscall + bral SYMBOL_NAME(ret_from_exception) | deliver signals, reschedule etc.. + + +| +| mem_write --- write to user or supervisor address space +| +| Writes to memory while in supervisor mode. copyout accomplishes +| this via a 'moves' instruction. copyout is a UNIX SVR3 (and later) function. +| If you don't have copyout, use the local copy of the function below. +| +| a0 - supervisor source address +| a1 - user destination address +| d0 - number of bytes to write (maximum count is 12) +| +| The supervisor source address is guaranteed to point into the supervisor +| stack. The result is that a UNIX +| process is allowed to sleep as a consequence of a page fault during +| copyout. The probability of a page fault is exceedingly small because +| the 68040 always reads the destination address and thus the page +| faults should have already been handled. +| +| If the EXC_SR shows that the exception was from supervisor space, +| then just do a dumb (and slow) memory move. In a UNIX environment +| there shouldn't be any supervisor mode floating point exceptions. +| + .global mem_write +mem_write: + btstb #5,EXC_SR(%a6) |check for supervisor state + beqs user_write +super_write: + moveb (%a0)+,(%a1)+ + subql #1,%d0 + bnes super_write + rts +user_write: + movel %d1,-(%sp) |preserve d1 just in case + movel %d0,-(%sp) + movel %a1,-(%sp) + movel %a0,-(%sp) + jsr copyout + addw #12,%sp + movel (%sp)+,%d1 + rts +| +| mem_read --- read from user or supervisor address space +| +| Reads from memory while in supervisor mode. copyin accomplishes +| this via a 'moves' instruction. copyin is a UNIX SVR3 (and later) function. +| If you don't have copyin, use the local copy of the function below. +| +| The FPSP calls mem_read to read the original F-line instruction in order +| to extract the data register number when the 'Dn' addressing mode is +| used. +| +|Input: +| a0 - user source address +| a1 - supervisor destination address +| d0 - number of bytes to read (maximum count is 12) +| +| Like mem_write, mem_read always reads with a supervisor +| destination address on the supervisor stack. Also like mem_write, +| the EXC_SR is checked and a simple memory copy is done if reading +| from supervisor space is indicated. +| + .global mem_read +mem_read: + btstb #5,EXC_SR(%a6) |check for supervisor state + beqs user_read +super_read: + moveb (%a0)+,(%a1)+ + subql #1,%d0 + bnes super_read + rts +user_read: + movel %d1,-(%sp) |preserve d1 just in case + movel %d0,-(%sp) + movel %a1,-(%sp) + movel %a0,-(%sp) + jsr copyin + addw #12,%sp + movel (%sp)+,%d1 + rts + +| +| Use these routines if your kernel doesn't have copyout/copyin equivalents. +| Assumes that D0/D1/A0/A1 are scratch registers. copyout overwrites DFC, +| and copyin overwrites SFC. +| +copyout: + movel 4(%sp),%a0 | source + movel 8(%sp),%a1 | destination + movel 12(%sp),%d0 | count + subl #1,%d0 | dec count by 1 for dbra + movel #1,%d1 + movec %d1,%DFC | set dfc for user data space +moreout: + moveb (%a0)+,%d1 | fetch supervisor byte + movesb %d1,(%a1)+ | write user byte + dbf %d0,moreout + rts + +copyin: + movel 4(%sp),%a0 | source + movel 8(%sp),%a1 | destination + movel 12(%sp),%d0 | count + subl #1,%d0 | dec count by 1 for dbra + movel #1,%d1 + movec %d1,%SFC | set sfc for user space +morein: + movesb (%a0)+,%d1 | fetch user byte + moveb %d1,(%a1)+ | write supervisor byte + dbf %d0,morein + rts + + |end diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/slog2.S linux/arch/m68k/fpsp040/slog2.S --- v1.3.93/linux/arch/m68k/fpsp040/slog2.S Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/fpsp040/slog2.S Sat Feb 24 22:58:44 1996 @@ -0,0 +1,188 @@ +| +| slog2.sa 3.1 12/10/90 +| +| The entry point slog10 computes the base-10 +| logarithm of an input argument X. +| slog10d does the same except the input value is a +| denormalized number. +| sLog2 and sLog2d are the base-2 analogues. +| +| INPUT: Double-extended value in memory location pointed to +| by address register a0. +| +| OUTPUT: log_10(X) or log_2(X) returned in floating-point +| register fp0. +| +| ACCURACY and MONOTONICITY: The returned result is within 1.7 +| ulps in 64 significant bit, i.e. within 0.5003 ulp +| to 53 bits if the result is subsequently rounded +| to double precision. The result is provably monotonic +| in double precision. +| +| SPEED: Two timings are measured, both in the copy-back mode. +| The first one is measured when the function is invoked +| the first time (so the instructions and data are not +| in cache), and the second one is measured when the +| function is reinvoked at the same input argument. +| +| ALGORITHM and IMPLEMENTATION NOTES: +| +| slog10d: +| +| Step 0. If X < 0, create a NaN and raise the invalid operation +| flag. Otherwise, save FPCR in D1; set FpCR to default. +| Notes: Default means round-to-nearest mode, no floating-point +| traps, and precision control = double extended. +| +| Step 1. Call slognd to obtain Y = log(X), the natural log of X. +| Notes: Even if X is denormalized, log(X) is always normalized. +| +| Step 2. Compute log_10(X) = log(X) * (1/log(10)). +| 2.1 Restore the user FPCR +| 2.2 Return ans := Y * INV_L10. +| +| +| slog10: +| +| Step 0. If X < 0, create a NaN and raise the invalid operation +| flag. Otherwise, save FPCR in D1; set FpCR to default. +| Notes: Default means round-to-nearest mode, no floating-point +| traps, and precision control = double extended. +| +| Step 1. Call sLogN to obtain Y = log(X), the natural log of X. +| +| Step 2. Compute log_10(X) = log(X) * (1/log(10)). +| 2.1 Restore the user FPCR +| 2.2 Return ans := Y * INV_L10. +| +| +| sLog2d: +| +| Step 0. If X < 0, create a NaN and raise the invalid operation +| flag. Otherwise, save FPCR in D1; set FpCR to default. +| Notes: Default means round-to-nearest mode, no floating-point +| traps, and precision control = double extended. +| +| Step 1. Call slognd to obtain Y = log(X), the natural log of X. +| Notes: Even if X is denormalized, log(X) is always normalized. +| +| Step 2. Compute log_10(X) = log(X) * (1/log(2)). +| 2.1 Restore the user FPCR +| 2.2 Return ans := Y * INV_L2. +| +| +| sLog2: +| +| Step 0. If X < 0, create a NaN and raise the invalid operation +| flag. Otherwise, save FPCR in D1; set FpCR to default. +| Notes: Default means round-to-nearest mode, no floating-point +| traps, and precision control = double extended. +| +| Step 1. If X is not an integer power of two, i.e., X != 2^k, +| go to Step 3. +| +| Step 2. Return k. +| 2.1 Get integer k, X = 2^k. +| 2.2 Restore the user FPCR. +| 2.3 Return ans := convert-to-double-extended(k). +| +| Step 3. Call sLogN to obtain Y = log(X), the natural log of X. +| +| Step 4. Compute log_2(X) = log(X) * (1/log(2)). +| 4.1 Restore the user FPCR +| 4.2 Return ans := Y * INV_L2. +| + +| Copyright (C) Motorola, Inc. 1990 +| All Rights Reserved +| +| THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA +| The copyright notice above does not evidence any +| actual or intended publication of such source code. + +|SLOG2 idnt 2,1 | Motorola 040 Floating Point Software Package + + |section 8 + + |xref t_frcinx + |xref t_operr + |xref slogn + |xref slognd + +INV_L10: .long 0x3FFD0000,0xDE5BD8A9,0x37287195,0x00000000 + +INV_L2: .long 0x3FFF0000,0xB8AA3B29,0x5C17F0BC,0x00000000 + + .global slog10d +slog10d: +|--entry point for Log10(X), X is denormalized + movel (%a0),%d0 + blt invalid + movel %d1,-(%sp) + clrl %d1 + bsr slognd | ...log(X), X denorm. + fmovel (%sp)+,%fpcr + fmulx INV_L10,%fp0 + bra t_frcinx + + .global slog10 +slog10: +|--entry point for Log10(X), X is normalized + + movel (%a0),%d0 + blt invalid + movel %d1,-(%sp) + clrl %d1 + bsr slogn | ...log(X), X normal. + fmovel (%sp)+,%fpcr + fmulx INV_L10,%fp0 + bra t_frcinx + + + .global slog2d +slog2d: +|--entry point for Log2(X), X is denormalized + + movel (%a0),%d0 + blt invalid + movel %d1,-(%sp) + clrl %d1 + bsr slognd | ...log(X), X denorm. + fmovel (%sp)+,%fpcr + fmulx INV_L2,%fp0 + bra t_frcinx + + .global slog2 +slog2: +|--entry point for Log2(X), X is normalized + movel (%a0),%d0 + blt invalid + + movel 8(%a0),%d0 + bnes continue | ...X is not 2^k + + movel 4(%a0),%d0 + andl #0x7FFFFFFF,%d0 + tstl %d0 + bnes continue + +|--X = 2^k. + movew (%a0),%d0 + andl #0x00007FFF,%d0 + subl #0x3FFF,%d0 + fmovel %d1,%fpcr + fmovel %d0,%fp0 + bra t_frcinx + +continue: + movel %d1,-(%sp) + clrl %d1 + bsr slogn | ...log(X), X normal. + fmovel (%sp)+,%fpcr + fmulx INV_L2,%fp0 + bra t_frcinx + +invalid: + bra t_operr + + |end diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/slogn.S linux/arch/m68k/fpsp040/slogn.S --- v1.3.93/linux/arch/m68k/fpsp040/slogn.S Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/fpsp040/slogn.S Sat Feb 24 22:58:44 1996 @@ -0,0 +1,592 @@ +| +| slogn.sa 3.1 12/10/90 +| +| slogn computes the natural logarithm of an +| input value. slognd does the same except the input value is a +| denormalized number. slognp1 computes log(1+X), and slognp1d +| computes log(1+X) for denormalized X. +| +| Input: Double-extended value in memory location pointed to by address +| register a0. +| +| Output: log(X) or log(1+X) returned in floating-point register Fp0. +| +| Accuracy and Monotonicity: The returned result is within 2 ulps in +| 64 significant bit, i.e. within 0.5001 ulp to 53 bits if the +| result is subsequently rounded to double precision. The +| result is provably monotonic in double precision. +| +| Speed: The program slogn takes approximately 190 cycles for input +| argument X such that |X-1| >= 1/16, which is the the usual +| situation. For those arguments, slognp1 takes approximately +| 210 cycles. For the less common arguments, the program will +| run no worse than 10% slower. +| +| Algorithm: +| LOGN: +| Step 1. If |X-1| < 1/16, approximate log(X) by an odd polynomial in +| u, where u = 2(X-1)/(X+1). Otherwise, move on to Step 2. +| +| Step 2. X = 2**k * Y where 1 <= Y < 2. Define F to be the first seven +| significant bits of Y plus 2**(-7), i.e. F = 1.xxxxxx1 in base +| 2 where the six "x" match those of Y. Note that |Y-F| <= 2**(-7). +| +| Step 3. Define u = (Y-F)/F. Approximate log(1+u) by a polynomial in u, +| log(1+u) = poly. +| +| Step 4. Reconstruct log(X) = log( 2**k * Y ) = k*log(2) + log(F) + log(1+u) +| by k*log(2) + (log(F) + poly). The values of log(F) are calculated +| beforehand and stored in the program. +| +| lognp1: +| Step 1: If |X| < 1/16, approximate log(1+X) by an odd polynomial in +| u where u = 2X/(2+X). Otherwise, move on to Step 2. +| +| Step 2: Let 1+X = 2**k * Y, where 1 <= Y < 2. Define F as done in Step 2 +| of the algorithm for LOGN and compute log(1+X) as +| k*log(2) + log(F) + poly where poly approximates log(1+u), +| u = (Y-F)/F. +| +| Implementation Notes: +| Note 1. There are 64 different possible values for F, thus 64 log(F)'s +| need to be tabulated. Moreover, the values of 1/F are also +| tabulated so that the division in (Y-F)/F can be performed by a +| multiplication. +| +| Note 2. In Step 2 of lognp1, in order to preserved accuracy, the value +| Y-F has to be calculated carefully when 1/2 <= X < 3/2. +| +| Note 3. To fully exploit the pipeline, polynomials are usually separated +| into two parts evaluated independently before being added up. +| + +| Copyright (C) Motorola, Inc. 1990 +| All Rights Reserved +| +| THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA +| The copyright notice above does not evidence any +| actual or intended publication of such source code. + +|slogn idnt 2,1 | Motorola 040 Floating Point Software Package + + |section 8 + + .include "fpsp.h" + +BOUNDS1: .long 0x3FFEF07D,0x3FFF8841 +BOUNDS2: .long 0x3FFE8000,0x3FFFC000 + +LOGOF2: .long 0x3FFE0000,0xB17217F7,0xD1CF79AC,0x00000000 + +one: .long 0x3F800000 +zero: .long 0x00000000 +infty: .long 0x7F800000 +negone: .long 0xBF800000 + +LOGA6: .long 0x3FC2499A,0xB5E4040B +LOGA5: .long 0xBFC555B5,0x848CB7DB + +LOGA4: .long 0x3FC99999,0x987D8730 +LOGA3: .long 0xBFCFFFFF,0xFF6F7E97 + +LOGA2: .long 0x3FD55555,0x555555a4 +LOGA1: .long 0xBFE00000,0x00000008 + +LOGB5: .long 0x3F175496,0xADD7DAD6 +LOGB4: .long 0x3F3C71C2,0xFE80C7E0 + +LOGB3: .long 0x3F624924,0x928BCCFF +LOGB2: .long 0x3F899999,0x999995EC + +LOGB1: .long 0x3FB55555,0x55555555 +TWO: .long 0x40000000,0x00000000 + +LTHOLD: .long 0x3f990000,0x80000000,0x00000000,0x00000000 + +LOGTBL: + .long 0x3FFE0000,0xFE03F80F,0xE03F80FE,0x00000000 + .long 0x3FF70000,0xFF015358,0x833C47E2,0x00000000 + .long 0x3FFE0000,0xFA232CF2,0x52138AC0,0x00000000 + .long 0x3FF90000,0xBDC8D83E,0xAD88D549,0x00000000 + .long 0x3FFE0000,0xF6603D98,0x0F6603DA,0x00000000 + .long 0x3FFA0000,0x9CF43DCF,0xF5EAFD48,0x00000000 + .long 0x3FFE0000,0xF2B9D648,0x0F2B9D65,0x00000000 + .long 0x3FFA0000,0xDA16EB88,0xCB8DF614,0x00000000 + .long 0x3FFE0000,0xEF2EB71F,0xC4345238,0x00000000 + .long 0x3FFB0000,0x8B29B775,0x1BD70743,0x00000000 + .long 0x3FFE0000,0xEBBDB2A5,0xC1619C8C,0x00000000 + .long 0x3FFB0000,0xA8D839F8,0x30C1FB49,0x00000000 + .long 0x3FFE0000,0xE865AC7B,0x7603A197,0x00000000 + .long 0x3FFB0000,0xC61A2EB1,0x8CD907AD,0x00000000 + .long 0x3FFE0000,0xE525982A,0xF70C880E,0x00000000 + .long 0x3FFB0000,0xE2F2A47A,0xDE3A18AF,0x00000000 + .long 0x3FFE0000,0xE1FC780E,0x1FC780E2,0x00000000 + .long 0x3FFB0000,0xFF64898E,0xDF55D551,0x00000000 + .long 0x3FFE0000,0xDEE95C4C,0xA037BA57,0x00000000 + .long 0x3FFC0000,0x8DB956A9,0x7B3D0148,0x00000000 + .long 0x3FFE0000,0xDBEB61EE,0xD19C5958,0x00000000 + .long 0x3FFC0000,0x9B8FE100,0xF47BA1DE,0x00000000 + .long 0x3FFE0000,0xD901B203,0x6406C80E,0x00000000 + .long 0x3FFC0000,0xA9372F1D,0x0DA1BD17,0x00000000 + .long 0x3FFE0000,0xD62B80D6,0x2B80D62C,0x00000000 + .long 0x3FFC0000,0xB6B07F38,0xCE90E46B,0x00000000 + .long 0x3FFE0000,0xD3680D36,0x80D3680D,0x00000000 + .long 0x3FFC0000,0xC3FD0329,0x06488481,0x00000000 + .long 0x3FFE0000,0xD0B69FCB,0xD2580D0B,0x00000000 + .long 0x3FFC0000,0xD11DE0FF,0x15AB18CA,0x00000000 + .long 0x3FFE0000,0xCE168A77,0x25080CE1,0x00000000 + .long 0x3FFC0000,0xDE1433A1,0x6C66B150,0x00000000 + .long 0x3FFE0000,0xCB8727C0,0x65C393E0,0x00000000 + .long 0x3FFC0000,0xEAE10B5A,0x7DDC8ADD,0x00000000 + .long 0x3FFE0000,0xC907DA4E,0x871146AD,0x00000000 + .long 0x3FFC0000,0xF7856E5E,0xE2C9B291,0x00000000 + .long 0x3FFE0000,0xC6980C69,0x80C6980C,0x00000000 + .long 0x3FFD0000,0x82012CA5,0xA68206D7,0x00000000 + .long 0x3FFE0000,0xC4372F85,0x5D824CA6,0x00000000 + .long 0x3FFD0000,0x882C5FCD,0x7256A8C5,0x00000000 + .long 0x3FFE0000,0xC1E4BBD5,0x95F6E947,0x00000000 + .long 0x3FFD0000,0x8E44C60B,0x4CCFD7DE,0x00000000 + .long 0x3FFE0000,0xBFA02FE8,0x0BFA02FF,0x00000000 + .long 0x3FFD0000,0x944AD09E,0xF4351AF6,0x00000000 + .long 0x3FFE0000,0xBD691047,0x07661AA3,0x00000000 + .long 0x3FFD0000,0x9A3EECD4,0xC3EAA6B2,0x00000000 + .long 0x3FFE0000,0xBB3EE721,0xA54D880C,0x00000000 + .long 0x3FFD0000,0xA0218434,0x353F1DE8,0x00000000 + .long 0x3FFE0000,0xB92143FA,0x36F5E02E,0x00000000 + .long 0x3FFD0000,0xA5F2FCAB,0xBBC506DA,0x00000000 + .long 0x3FFE0000,0xB70FBB5A,0x19BE3659,0x00000000 + .long 0x3FFD0000,0xABB3B8BA,0x2AD362A5,0x00000000 + .long 0x3FFE0000,0xB509E68A,0x9B94821F,0x00000000 + .long 0x3FFD0000,0xB1641795,0xCE3CA97B,0x00000000 + .long 0x3FFE0000,0xB30F6352,0x8917C80B,0x00000000 + .long 0x3FFD0000,0xB7047551,0x5D0F1C61,0x00000000 + .long 0x3FFE0000,0xB11FD3B8,0x0B11FD3C,0x00000000 + .long 0x3FFD0000,0xBC952AFE,0xEA3D13E1,0x00000000 + .long 0x3FFE0000,0xAF3ADDC6,0x80AF3ADE,0x00000000 + .long 0x3FFD0000,0xC2168ED0,0xF458BA4A,0x00000000 + .long 0x3FFE0000,0xAD602B58,0x0AD602B6,0x00000000 + .long 0x3FFD0000,0xC788F439,0xB3163BF1,0x00000000 + .long 0x3FFE0000,0xAB8F69E2,0x8359CD11,0x00000000 + .long 0x3FFD0000,0xCCECAC08,0xBF04565D,0x00000000 + .long 0x3FFE0000,0xA9C84A47,0xA07F5638,0x00000000 + .long 0x3FFD0000,0xD2420487,0x2DD85160,0x00000000 + .long 0x3FFE0000,0xA80A80A8,0x0A80A80B,0x00000000 + .long 0x3FFD0000,0xD7894992,0x3BC3588A,0x00000000 + .long 0x3FFE0000,0xA655C439,0x2D7B73A8,0x00000000 + .long 0x3FFD0000,0xDCC2C4B4,0x9887DACC,0x00000000 + .long 0x3FFE0000,0xA4A9CF1D,0x96833751,0x00000000 + .long 0x3FFD0000,0xE1EEBD3E,0x6D6A6B9E,0x00000000 + .long 0x3FFE0000,0xA3065E3F,0xAE7CD0E0,0x00000000 + .long 0x3FFD0000,0xE70D785C,0x2F9F5BDC,0x00000000 + .long 0x3FFE0000,0xA16B312E,0xA8FC377D,0x00000000 + .long 0x3FFD0000,0xEC1F392C,0x5179F283,0x00000000 + .long 0x3FFE0000,0x9FD809FD,0x809FD80A,0x00000000 + .long 0x3FFD0000,0xF12440D3,0xE36130E6,0x00000000 + .long 0x3FFE0000,0x9E4CAD23,0xDD5F3A20,0x00000000 + .long 0x3FFD0000,0xF61CCE92,0x346600BB,0x00000000 + .long 0x3FFE0000,0x9CC8E160,0xC3FB19B9,0x00000000 + .long 0x3FFD0000,0xFB091FD3,0x8145630A,0x00000000 + .long 0x3FFE0000,0x9B4C6F9E,0xF03A3CAA,0x00000000 + .long 0x3FFD0000,0xFFE97042,0xBFA4C2AD,0x00000000 + .long 0x3FFE0000,0x99D722DA,0xBDE58F06,0x00000000 + .long 0x3FFE0000,0x825EFCED,0x49369330,0x00000000 + .long 0x3FFE0000,0x9868C809,0x868C8098,0x00000000 + .long 0x3FFE0000,0x84C37A7A,0xB9A905C9,0x00000000 + .long 0x3FFE0000,0x97012E02,0x5C04B809,0x00000000 + .long 0x3FFE0000,0x87224C2E,0x8E645FB7,0x00000000 + .long 0x3FFE0000,0x95A02568,0x095A0257,0x00000000 + .long 0x3FFE0000,0x897B8CAC,0x9F7DE298,0x00000000 + .long 0x3FFE0000,0x94458094,0x45809446,0x00000000 + .long 0x3FFE0000,0x8BCF55DE,0xC4CD05FE,0x00000000 + .long 0x3FFE0000,0x92F11384,0x0497889C,0x00000000 + .long 0x3FFE0000,0x8E1DC0FB,0x89E125E5,0x00000000 + .long 0x3FFE0000,0x91A2B3C4,0xD5E6F809,0x00000000 + .long 0x3FFE0000,0x9066E68C,0x955B6C9B,0x00000000 + .long 0x3FFE0000,0x905A3863,0x3E06C43B,0x00000000 + .long 0x3FFE0000,0x92AADE74,0xC7BE59E0,0x00000000 + .long 0x3FFE0000,0x8F1779D9,0xFDC3A219,0x00000000 + .long 0x3FFE0000,0x94E9BFF6,0x15845643,0x00000000 + .long 0x3FFE0000,0x8DDA5202,0x37694809,0x00000000 + .long 0x3FFE0000,0x9723A1B7,0x20134203,0x00000000 + .long 0x3FFE0000,0x8CA29C04,0x6514E023,0x00000000 + .long 0x3FFE0000,0x995899C8,0x90EB8990,0x00000000 + .long 0x3FFE0000,0x8B70344A,0x139BC75A,0x00000000 + .long 0x3FFE0000,0x9B88BDAA,0x3A3DAE2F,0x00000000 + .long 0x3FFE0000,0x8A42F870,0x5669DB46,0x00000000 + .long 0x3FFE0000,0x9DB4224F,0xFFE1157C,0x00000000 + .long 0x3FFE0000,0x891AC73A,0xE9819B50,0x00000000 + .long 0x3FFE0000,0x9FDADC26,0x8B7A12DA,0x00000000 + .long 0x3FFE0000,0x87F78087,0xF78087F8,0x00000000 + .long 0x3FFE0000,0xA1FCFF17,0xCE733BD4,0x00000000 + .long 0x3FFE0000,0x86D90544,0x7A34ACC6,0x00000000 + .long 0x3FFE0000,0xA41A9E8F,0x5446FB9F,0x00000000 + .long 0x3FFE0000,0x85BF3761,0x2CEE3C9B,0x00000000 + .long 0x3FFE0000,0xA633CD7E,0x6771CD8B,0x00000000 + .long 0x3FFE0000,0x84A9F9C8,0x084A9F9D,0x00000000 + .long 0x3FFE0000,0xA8489E60,0x0B435A5E,0x00000000 + .long 0x3FFE0000,0x83993052,0x3FBE3368,0x00000000 + .long 0x3FFE0000,0xAA59233C,0xCCA4BD49,0x00000000 + .long 0x3FFE0000,0x828CBFBE,0xB9A020A3,0x00000000 + .long 0x3FFE0000,0xAC656DAE,0x6BCC4985,0x00000000 + .long 0x3FFE0000,0x81848DA8,0xFAF0D277,0x00000000 + .long 0x3FFE0000,0xAE6D8EE3,0x60BB2468,0x00000000 + .long 0x3FFE0000,0x80808080,0x80808081,0x00000000 + .long 0x3FFE0000,0xB07197A2,0x3C46C654,0x00000000 + + .set ADJK,L_SCR1 + + .set X,FP_SCR1 + .set XDCARE,X+2 + .set XFRAC,X+4 + + .set F,FP_SCR2 + .set FFRAC,F+4 + + .set KLOG2,FP_SCR3 + + .set SAVEU,FP_SCR4 + + | xref t_frcinx + |xref t_extdnrm + |xref t_operr + |xref t_dz + + .global slognd +slognd: +|--ENTRY POINT FOR LOG(X) FOR DENORMALIZED INPUT + + movel #-100,ADJK(%a6) | ...INPUT = 2^(ADJK) * FP0 + +|----normalize the input value by left shifting k bits (k to be determined +|----below), adjusting exponent and storing -k to ADJK +|----the value TWOTO100 is no longer needed. +|----Note that this code assumes the denormalized input is NON-ZERO. + + moveml %d2-%d7,-(%a7) | ...save some registers + movel #0x00000000,%d3 | ...D3 is exponent of smallest norm. # + movel 4(%a0),%d4 + movel 8(%a0),%d5 | ...(D4,D5) is (Hi_X,Lo_X) + clrl %d2 | ...D2 used for holding K + + tstl %d4 + bnes HiX_not0 + +HiX_0: + movel %d5,%d4 + clrl %d5 + movel #32,%d2 + clrl %d6 + bfffo %d4{#0:#32},%d6 + lsll %d6,%d4 + addl %d6,%d2 | ...(D3,D4,D5) is normalized + + movel %d3,X(%a6) + movel %d4,XFRAC(%a6) + movel %d5,XFRAC+4(%a6) + negl %d2 + movel %d2,ADJK(%a6) + fmovex X(%a6),%fp0 + moveml (%a7)+,%d2-%d7 | ...restore registers + lea X(%a6),%a0 + bras LOGBGN | ...begin regular log(X) + + +HiX_not0: + clrl %d6 + bfffo %d4{#0:#32},%d6 | ...find first 1 + movel %d6,%d2 | ...get k + lsll %d6,%d4 + movel %d5,%d7 | ...a copy of D5 + lsll %d6,%d5 + negl %d6 + addil #32,%d6 + lsrl %d6,%d7 + orl %d7,%d4 | ...(D3,D4,D5) normalized + + movel %d3,X(%a6) + movel %d4,XFRAC(%a6) + movel %d5,XFRAC+4(%a6) + negl %d2 + movel %d2,ADJK(%a6) + fmovex X(%a6),%fp0 + moveml (%a7)+,%d2-%d7 | ...restore registers + lea X(%a6),%a0 + bras LOGBGN | ...begin regular log(X) + + + .global slogn +slogn: +|--ENTRY POINT FOR LOG(X) FOR X FINITE, NON-ZERO, NOT NAN'S + + fmovex (%a0),%fp0 | ...LOAD INPUT + movel #0x00000000,ADJK(%a6) + +LOGBGN: +|--FPCR SAVED AND CLEARED, INPUT IS 2^(ADJK)*FP0, FP0 CONTAINS +|--A FINITE, NON-ZERO, NORMALIZED NUMBER. + + movel (%a0),%d0 + movew 4(%a0),%d0 + + movel (%a0),X(%a6) + movel 4(%a0),X+4(%a6) + movel 8(%a0),X+8(%a6) + + cmpil #0,%d0 | ...CHECK IF X IS NEGATIVE + blt LOGNEG | ...LOG OF NEGATIVE ARGUMENT IS INVALID + cmp2l BOUNDS1,%d0 | ...X IS POSITIVE, CHECK IF X IS NEAR 1 + bcc LOGNEAR1 | ...BOUNDS IS ROUGHLY [15/16, 17/16] + +LOGMAIN: +|--THIS SHOULD BE THE USUAL CASE, X NOT VERY CLOSE TO 1 + +|--X = 2^(K) * Y, 1 <= Y < 2. THUS, Y = 1.XXXXXXXX....XX IN BINARY. +|--WE DEFINE F = 1.XXXXXX1, I.E. FIRST 7 BITS OF Y AND ATTACH A 1. +|--THE IDEA IS THAT LOG(X) = K*LOG2 + LOG(Y) +|-- = K*LOG2 + LOG(F) + LOG(1 + (Y-F)/F). +|--NOTE THAT U = (Y-F)/F IS VERY SMALL AND THUS APPROXIMATING +|--LOG(1+U) CAN BE VERY EFFICIENT. +|--ALSO NOTE THAT THE VALUE 1/F IS STORED IN A TABLE SO THAT NO +|--DIVISION IS NEEDED TO CALCULATE (Y-F)/F. + +|--GET K, Y, F, AND ADDRESS OF 1/F. + asrl #8,%d0 + asrl #8,%d0 | ...SHIFTED 16 BITS, BIASED EXPO. OF X + subil #0x3FFF,%d0 | ...THIS IS K + addl ADJK(%a6),%d0 | ...ADJUST K, ORIGINAL INPUT MAY BE DENORM. + lea LOGTBL,%a0 | ...BASE ADDRESS OF 1/F AND LOG(F) + fmovel %d0,%fp1 | ...CONVERT K TO FLOATING-POINT FORMAT + +|--WHILE THE CONVERSION IS GOING ON, WE GET F AND ADDRESS OF 1/F + movel #0x3FFF0000,X(%a6) | ...X IS NOW Y, I.E. 2^(-K)*X + movel XFRAC(%a6),FFRAC(%a6) + andil #0xFE000000,FFRAC(%a6) | ...FIRST 7 BITS OF Y + oril #0x01000000,FFRAC(%a6) | ...GET F: ATTACH A 1 AT THE EIGHTH BIT + movel FFRAC(%a6),%d0 | ...READY TO GET ADDRESS OF 1/F + andil #0x7E000000,%d0 + asrl #8,%d0 + asrl #8,%d0 + asrl #4,%d0 | ...SHIFTED 20, D0 IS THE DISPLACEMENT + addal %d0,%a0 | ...A0 IS THE ADDRESS FOR 1/F + + fmovex X(%a6),%fp0 + movel #0x3fff0000,F(%a6) + clrl F+8(%a6) + fsubx F(%a6),%fp0 | ...Y-F + fmovemx %fp2-%fp2/%fp3,-(%sp) | ...SAVE FP2 WHILE FP0 IS NOT READY +|--SUMMARY: FP0 IS Y-F, A0 IS ADDRESS OF 1/F, FP1 IS K +|--REGISTERS SAVED: FPCR, FP1, FP2 + +LP1CONT1: +|--AN RE-ENTRY POINT FOR LOGNP1 + fmulx (%a0),%fp0 | ...FP0 IS U = (Y-F)/F + fmulx LOGOF2,%fp1 | ...GET K*LOG2 WHILE FP0 IS NOT READY + fmovex %fp0,%fp2 + fmulx %fp2,%fp2 | ...FP2 IS V=U*U + fmovex %fp1,KLOG2(%a6) | ...PUT K*LOG2 IN MEMEORY, FREE FP1 + +|--LOG(1+U) IS APPROXIMATED BY +|--U + V*(A1+U*(A2+U*(A3+U*(A4+U*(A5+U*A6))))) WHICH IS +|--[U + V*(A1+V*(A3+V*A5))] + [U*V*(A2+V*(A4+V*A6))] + + fmovex %fp2,%fp3 + fmovex %fp2,%fp1 + + fmuld LOGA6,%fp1 | ...V*A6 + fmuld LOGA5,%fp2 | ...V*A5 + + faddd LOGA4,%fp1 | ...A4+V*A6 + faddd LOGA3,%fp2 | ...A3+V*A5 + + fmulx %fp3,%fp1 | ...V*(A4+V*A6) + fmulx %fp3,%fp2 | ...V*(A3+V*A5) + + faddd LOGA2,%fp1 | ...A2+V*(A4+V*A6) + faddd LOGA1,%fp2 | ...A1+V*(A3+V*A5) + + fmulx %fp3,%fp1 | ...V*(A2+V*(A4+V*A6)) + addal #16,%a0 | ...ADDRESS OF LOG(F) + fmulx %fp3,%fp2 | ...V*(A1+V*(A3+V*A5)), FP3 RELEASED + + fmulx %fp0,%fp1 | ...U*V*(A2+V*(A4+V*A6)) + faddx %fp2,%fp0 | ...U+V*(A1+V*(A3+V*A5)), FP2 RELEASED + + faddx (%a0),%fp1 | ...LOG(F)+U*V*(A2+V*(A4+V*A6)) + fmovemx (%sp)+,%fp2-%fp2/%fp3 | ...RESTORE FP2 + faddx %fp1,%fp0 | ...FP0 IS LOG(F) + LOG(1+U) + + fmovel %d1,%fpcr + faddx KLOG2(%a6),%fp0 | ...FINAL ADD + bra t_frcinx + + +LOGNEAR1: +|--REGISTERS SAVED: FPCR, FP1. FP0 CONTAINS THE INPUT. + fmovex %fp0,%fp1 + fsubs one,%fp1 | ...FP1 IS X-1 + fadds one,%fp0 | ...FP0 IS X+1 + faddx %fp1,%fp1 | ...FP1 IS 2(X-1) +|--LOG(X) = LOG(1+U/2)-LOG(1-U/2) WHICH IS AN ODD POLYNOMIAL +|--IN U, U = 2(X-1)/(X+1) = FP1/FP0 + +LP1CONT2: +|--THIS IS AN RE-ENTRY POINT FOR LOGNP1 + fdivx %fp0,%fp1 | ...FP1 IS U + fmovemx %fp2-%fp2/%fp3,-(%sp) | ...SAVE FP2 +|--REGISTERS SAVED ARE NOW FPCR,FP1,FP2,FP3 +|--LET V=U*U, W=V*V, CALCULATE +|--U + U*V*(B1 + V*(B2 + V*(B3 + V*(B4 + V*B5)))) BY +|--U + U*V*( [B1 + W*(B3 + W*B5)] + [V*(B2 + W*B4)] ) + fmovex %fp1,%fp0 + fmulx %fp0,%fp0 | ...FP0 IS V + fmovex %fp1,SAVEU(%a6) | ...STORE U IN MEMORY, FREE FP1 + fmovex %fp0,%fp1 + fmulx %fp1,%fp1 | ...FP1 IS W + + fmoved LOGB5,%fp3 + fmoved LOGB4,%fp2 + + fmulx %fp1,%fp3 | ...W*B5 + fmulx %fp1,%fp2 | ...W*B4 + + faddd LOGB3,%fp3 | ...B3+W*B5 + faddd LOGB2,%fp2 | ...B2+W*B4 + + fmulx %fp3,%fp1 | ...W*(B3+W*B5), FP3 RELEASED + + fmulx %fp0,%fp2 | ...V*(B2+W*B4) + + faddd LOGB1,%fp1 | ...B1+W*(B3+W*B5) + fmulx SAVEU(%a6),%fp0 | ...FP0 IS U*V + + faddx %fp2,%fp1 | ...B1+W*(B3+W*B5) + V*(B2+W*B4), FP2 RELEASED + fmovemx (%sp)+,%fp2-%fp2/%fp3 | ...FP2 RESTORED + + fmulx %fp1,%fp0 | ...U*V*( [B1+W*(B3+W*B5)] + [V*(B2+W*B4)] ) + + fmovel %d1,%fpcr + faddx SAVEU(%a6),%fp0 + bra t_frcinx + rts + +LOGNEG: +|--REGISTERS SAVED FPCR. LOG(-VE) IS INVALID + bra t_operr + + .global slognp1d +slognp1d: +|--ENTRY POINT FOR LOG(1+Z) FOR DENORMALIZED INPUT +| Simply return the denorm + + bra t_extdnrm + + .global slognp1 +slognp1: +|--ENTRY POINT FOR LOG(1+X) FOR X FINITE, NON-ZERO, NOT NAN'S + + fmovex (%a0),%fp0 | ...LOAD INPUT + fabsx %fp0 |test magnitude + fcmpx LTHOLD,%fp0 |compare with min threshold + fbgt LP1REAL |if greater, continue + fmovel #0,%fpsr |clr N flag from compare + fmovel %d1,%fpcr + fmovex (%a0),%fp0 |return signed argument + bra t_frcinx + +LP1REAL: + fmovex (%a0),%fp0 | ...LOAD INPUT + movel #0x00000000,ADJK(%a6) + fmovex %fp0,%fp1 | ...FP1 IS INPUT Z + fadds one,%fp0 | ...X := ROUND(1+Z) + fmovex %fp0,X(%a6) + movew XFRAC(%a6),XDCARE(%a6) + movel X(%a6),%d0 + cmpil #0,%d0 + ble LP1NEG0 | ...LOG OF ZERO OR -VE + cmp2l BOUNDS2,%d0 + bcs LOGMAIN | ...BOUNDS2 IS [1/2,3/2] +|--IF 1+Z > 3/2 OR 1+Z < 1/2, THEN X, WHICH IS ROUNDING 1+Z, +|--CONTAINS AT LEAST 63 BITS OF INFORMATION OF Z. IN THAT CASE, +|--SIMPLY INVOKE LOG(X) FOR LOG(1+Z). + +LP1NEAR1: +|--NEXT SEE IF EXP(-1/16) < X < EXP(1/16) + cmp2l BOUNDS1,%d0 + bcss LP1CARE + +LP1ONE16: +|--EXP(-1/16) < X < EXP(1/16). LOG(1+Z) = LOG(1+U/2) - LOG(1-U/2) +|--WHERE U = 2Z/(2+Z) = 2Z/(1+X). + faddx %fp1,%fp1 | ...FP1 IS 2Z + fadds one,%fp0 | ...FP0 IS 1+X +|--U = FP1/FP0 + bra LP1CONT2 + +LP1CARE: +|--HERE WE USE THE USUAL TABLE DRIVEN APPROACH. CARE HAS TO BE +|--TAKEN BECAUSE 1+Z CAN HAVE 67 BITS OF INFORMATION AND WE MUST +|--PRESERVE ALL THE INFORMATION. BECAUSE 1+Z IS IN [1/2,3/2], +|--THERE ARE ONLY TWO CASES. +|--CASE 1: 1+Z < 1, THEN K = -1 AND Y-F = (2-F) + 2Z +|--CASE 2: 1+Z > 1, THEN K = 0 AND Y-F = (1-F) + Z +|--ON RETURNING TO LP1CONT1, WE MUST HAVE K IN FP1, ADDRESS OF +|--(1/F) IN A0, Y-F IN FP0, AND FP2 SAVED. + + movel XFRAC(%a6),FFRAC(%a6) + andil #0xFE000000,FFRAC(%a6) + oril #0x01000000,FFRAC(%a6) | ...F OBTAINED + cmpil #0x3FFF8000,%d0 | ...SEE IF 1+Z > 1 + bges KISZERO + +KISNEG1: + fmoves TWO,%fp0 + movel #0x3fff0000,F(%a6) + clrl F+8(%a6) + fsubx F(%a6),%fp0 | ...2-F + movel FFRAC(%a6),%d0 + andil #0x7E000000,%d0 + asrl #8,%d0 + asrl #8,%d0 + asrl #4,%d0 | ...D0 CONTAINS DISPLACEMENT FOR 1/F + faddx %fp1,%fp1 | ...GET 2Z + fmovemx %fp2-%fp2/%fp3,-(%sp) | ...SAVE FP2 + faddx %fp1,%fp0 | ...FP0 IS Y-F = (2-F)+2Z + lea LOGTBL,%a0 | ...A0 IS ADDRESS OF 1/F + addal %d0,%a0 + fmoves negone,%fp1 | ...FP1 IS K = -1 + bra LP1CONT1 + +KISZERO: + fmoves one,%fp0 + movel #0x3fff0000,F(%a6) + clrl F+8(%a6) + fsubx F(%a6),%fp0 | ...1-F + movel FFRAC(%a6),%d0 + andil #0x7E000000,%d0 + asrl #8,%d0 + asrl #8,%d0 + asrl #4,%d0 + faddx %fp1,%fp0 | ...FP0 IS Y-F + fmovemx %fp2-%fp2/%fp3,-(%sp) | ...FP2 SAVED + lea LOGTBL,%a0 + addal %d0,%a0 | ...A0 IS ADDRESS OF 1/F + fmoves zero,%fp1 | ...FP1 IS K = 0 + bra LP1CONT1 + +LP1NEG0: +|--FPCR SAVED. D0 IS X IN COMPACT FORM. + cmpil #0,%d0 + blts LP1NEG +LP1ZERO: + fmoves negone,%fp0 + + fmovel %d1,%fpcr + bra t_dz + +LP1NEG: + fmoves zero,%fp0 + + fmovel %d1,%fpcr + bra t_operr + + |end diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/smovecr.S linux/arch/m68k/fpsp040/smovecr.S --- v1.3.93/linux/arch/m68k/fpsp040/smovecr.S Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/fpsp040/smovecr.S Sat Feb 24 22:58:44 1996 @@ -0,0 +1,162 @@ +| +| smovecr.sa 3.1 12/10/90 +| +| The entry point sMOVECR returns the constant at the +| offset given in the instruction field. +| +| Input: An offset in the instruction word. +| +| Output: The constant rounded to the user's rounding +| mode unchecked for overflow. +| +| Modified: fp0. +| +| +| Copyright (C) Motorola, Inc. 1990 +| All Rights Reserved +| +| THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA +| The copyright notice above does not evidence any +| actual or intended publication of such source code. + +|SMOVECR idnt 2,1 | Motorola 040 Floating Point Software Package + + |section 8 + + .include "fpsp.h" + + |xref nrm_set + |xref round + |xref PIRN + |xref PIRZRM + |xref PIRP + |xref SMALRN + |xref SMALRZRM + |xref SMALRP + |xref BIGRN + |xref BIGRZRM + |xref BIGRP + +FZERO: .long 00000000 +| +| FMOVECR +| + .global smovcr +smovcr: + bfextu CMDREG1B(%a6){#9:#7},%d0 |get offset + bfextu USER_FPCR(%a6){#26:#2},%d1 |get rmode +| +| check range of offset +| + tstb %d0 |if zero, offset is to pi + beqs PI_TBL |it is pi + cmpib #0x0a,%d0 |check range $01 - $0a + bles Z_VAL |if in this range, return zero + cmpib #0x0e,%d0 |check range $0b - $0e + bles SM_TBL |valid constants in this range + cmpib #0x2f,%d0 |check range $10 - $2f + bles Z_VAL |if in this range, return zero + cmpib #0x3f,%d0 |check range $30 - $3f + ble BG_TBL |valid constants in this range +Z_VAL: + fmoves FZERO,%fp0 + rts +PI_TBL: + tstb %d1 |offset is zero, check for rmode + beqs PI_RN |if zero, rn mode + cmpib #0x3,%d1 |check for rp + beqs PI_RP |if 3, rp mode +PI_RZRM: + leal PIRZRM,%a0 |rmode is rz or rm, load PIRZRM in a0 + bra set_finx +PI_RN: + leal PIRN,%a0 |rmode is rn, load PIRN in a0 + bra set_finx +PI_RP: + leal PIRP,%a0 |rmode is rp, load PIRP in a0 + bra set_finx +SM_TBL: + subil #0xb,%d0 |make offset in 0 - 4 range + tstb %d1 |check for rmode + beqs SM_RN |if zero, rn mode + cmpib #0x3,%d1 |check for rp + beqs SM_RP |if 3, rp mode +SM_RZRM: + leal SMALRZRM,%a0 |rmode is rz or rm, load SMRZRM in a0 + cmpib #0x2,%d0 |check if result is inex + ble set_finx |if 0 - 2, it is inexact + bra no_finx |if 3, it is exact +SM_RN: + leal SMALRN,%a0 |rmode is rn, load SMRN in a0 + cmpib #0x2,%d0 |check if result is inex + ble set_finx |if 0 - 2, it is inexact + bra no_finx |if 3, it is exact +SM_RP: + leal SMALRP,%a0 |rmode is rp, load SMRP in a0 + cmpib #0x2,%d0 |check if result is inex + ble set_finx |if 0 - 2, it is inexact + bra no_finx |if 3, it is exact +BG_TBL: + subil #0x30,%d0 |make offset in 0 - f range + tstb %d1 |check for rmode + beqs BG_RN |if zero, rn mode + cmpib #0x3,%d1 |check for rp + beqs BG_RP |if 3, rp mode +BG_RZRM: + leal BIGRZRM,%a0 |rmode is rz or rm, load BGRZRM in a0 + cmpib #0x1,%d0 |check if result is inex + ble set_finx |if 0 - 1, it is inexact + cmpib #0x7,%d0 |second check + ble no_finx |if 0 - 7, it is exact + bra set_finx |if 8 - f, it is inexact +BG_RN: + leal BIGRN,%a0 |rmode is rn, load BGRN in a0 + cmpib #0x1,%d0 |check if result is inex + ble set_finx |if 0 - 1, it is inexact + cmpib #0x7,%d0 |second check + ble no_finx |if 0 - 7, it is exact + bra set_finx |if 8 - f, it is inexact +BG_RP: + leal BIGRP,%a0 |rmode is rp, load SMRP in a0 + cmpib #0x1,%d0 |check if result is inex + ble set_finx |if 0 - 1, it is inexact + cmpib #0x7,%d0 |second check + ble no_finx |if 0 - 7, it is exact +| bra set_finx ;if 8 - f, it is inexact +set_finx: + orl #inx2a_mask,USER_FPSR(%a6) |set inex2/ainex +no_finx: + mulul #12,%d0 |use offset to point into tables + movel %d1,L_SCR1(%a6) |load mode for round call + bfextu USER_FPCR(%a6){#24:#2},%d1 |get precision + tstl %d1 |check if extended precision +| +| Precision is extended +| + bnes not_ext |if extended, do not call round + fmovemx (%a0,%d0),%fp0-%fp0 |return result in fp0 + rts +| +| Precision is single or double +| +not_ext: + swap %d1 |rnd prec in upper word of d1 + addl L_SCR1(%a6),%d1 |merge rmode in low word of d1 + movel (%a0,%d0),FP_SCR1(%a6) |load first word to temp storage + movel 4(%a0,%d0),FP_SCR1+4(%a6) |load second word + movel 8(%a0,%d0),FP_SCR1+8(%a6) |load third word + clrl %d0 |clear g,r,s + lea FP_SCR1(%a6),%a0 + btstb #sign_bit,LOCAL_EX(%a0) + sne LOCAL_SGN(%a0) |convert to internal ext. format + + bsr round |go round the mantissa + + bfclr LOCAL_SGN(%a0){#0:#8} |convert back to IEEE ext format + beqs fin_fcr + bsetb #sign_bit,LOCAL_EX(%a0) +fin_fcr: + fmovemx (%a0),%fp0-%fp0 + rts + + |end diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/srem_mod.S linux/arch/m68k/fpsp040/srem_mod.S --- v1.3.93/linux/arch/m68k/fpsp040/srem_mod.S Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/fpsp040/srem_mod.S Sat Feb 24 22:58:44 1996 @@ -0,0 +1,422 @@ +| +| srem_mod.sa 3.1 12/10/90 +| +| The entry point sMOD computes the floating point MOD of the +| input values X and Y. The entry point sREM computes the floating +| point (IEEE) REM of the input values X and Y. +| +| INPUT +| ----- +| Double-extended value Y is pointed to by address in register +| A0. Double-extended value X is located in -12(A0). The values +| of X and Y are both nonzero and finite; although either or both +| of them can be denormalized. The special cases of zeros, NaNs, +| and infinities are handled elsewhere. +| +| OUTPUT +| ------ +| FREM(X,Y) or FMOD(X,Y), depending on entry point. +| +| ALGORITHM +| --------- +| +| Step 1. Save and strip signs of X and Y: signX := sign(X), +| signY := sign(Y), X := |X|, Y := |Y|, +| signQ := signX EOR signY. Record whether MOD or REM +| is requested. +| +| Step 2. Set L := expo(X)-expo(Y), k := 0, Q := 0. +| If (L < 0) then +| R := X, go to Step 4. +| else +| R := 2^(-L)X, j := L. +| endif +| +| Step 3. Perform MOD(X,Y) +| 3.1 If R = Y, go to Step 9. +| 3.2 If R > Y, then { R := R - Y, Q := Q + 1} +| 3.3 If j = 0, go to Step 4. +| 3.4 k := k + 1, j := j - 1, Q := 2Q, R := 2R. Go to +| Step 3.1. +| +| Step 4. At this point, R = X - QY = MOD(X,Y). Set +| Last_Subtract := false (used in Step 7 below). If +| MOD is requested, go to Step 6. +| +| Step 5. R = MOD(X,Y), but REM(X,Y) is requested. +| 5.1 If R < Y/2, then R = MOD(X,Y) = REM(X,Y). Go to +| Step 6. +| 5.2 If R > Y/2, then { set Last_Subtract := true, +| Q := Q + 1, Y := signY*Y }. Go to Step 6. +| 5.3 This is the tricky case of R = Y/2. If Q is odd, +| then { Q := Q + 1, signX := -signX }. +| +| Step 6. R := signX*R. +| +| Step 7. If Last_Subtract = true, R := R - Y. +| +| Step 8. Return signQ, last 7 bits of Q, and R as required. +| +| Step 9. At this point, R = 2^(-j)*X - Q Y = Y. Thus, +| X = 2^(j)*(Q+1)Y. set Q := 2^(j)*(Q+1), +| R := 0. Return signQ, last 7 bits of Q, and R. +| +| + +| Copyright (C) Motorola, Inc. 1990 +| All Rights Reserved +| +| THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA +| The copyright notice above does not evidence any +| actual or intended publication of such source code. + +SREM_MOD: |idnt 2,1 | Motorola 040 Floating Point Software Package + + |section 8 + + .include "fpsp.h" + + .set Mod_Flag,L_SCR3 + .set SignY,FP_SCR3+4 + .set SignX,FP_SCR3+8 + .set SignQ,FP_SCR3+12 + .set Sc_Flag,FP_SCR4 + + .set Y,FP_SCR1 + .set Y_Hi,Y+4 + .set Y_Lo,Y+8 + + .set R,FP_SCR2 + .set R_Hi,R+4 + .set R_Lo,R+8 + + +Scale: .long 0x00010000,0x80000000,0x00000000,0x00000000 + + |xref t_avoid_unsupp + + .global smod +smod: + + movel #0,Mod_Flag(%a6) + bras Mod_Rem + + .global srem +srem: + + movel #1,Mod_Flag(%a6) + +Mod_Rem: +|..Save sign of X and Y + moveml %d2-%d7,-(%a7) | ...save data registers + movew (%a0),%d3 + movew %d3,SignY(%a6) + andil #0x00007FFF,%d3 | ...Y := |Y| + +| + movel 4(%a0),%d4 + movel 8(%a0),%d5 | ...(D3,D4,D5) is |Y| + + tstl %d3 + bnes Y_Normal + + movel #0x00003FFE,%d3 | ...$3FFD + 1 + tstl %d4 + bnes HiY_not0 + +HiY_0: + movel %d5,%d4 + clrl %d5 + subil #32,%d3 + clrl %d6 + bfffo %d4{#0:#32},%d6 + lsll %d6,%d4 + subl %d6,%d3 | ...(D3,D4,D5) is normalized +| ...with bias $7FFD + bras Chk_X + +HiY_not0: + clrl %d6 + bfffo %d4{#0:#32},%d6 + subl %d6,%d3 + lsll %d6,%d4 + movel %d5,%d7 | ...a copy of D5 + lsll %d6,%d5 + negl %d6 + addil #32,%d6 + lsrl %d6,%d7 + orl %d7,%d4 | ...(D3,D4,D5) normalized +| ...with bias $7FFD + bras Chk_X + +Y_Normal: + addil #0x00003FFE,%d3 | ...(D3,D4,D5) normalized +| ...with bias $7FFD + +Chk_X: + movew -12(%a0),%d0 + movew %d0,SignX(%a6) + movew SignY(%a6),%d1 + eorl %d0,%d1 + andil #0x00008000,%d1 + movew %d1,SignQ(%a6) | ...sign(Q) obtained + andil #0x00007FFF,%d0 + movel -8(%a0),%d1 + movel -4(%a0),%d2 | ...(D0,D1,D2) is |X| + tstl %d0 + bnes X_Normal + movel #0x00003FFE,%d0 + tstl %d1 + bnes HiX_not0 + +HiX_0: + movel %d2,%d1 + clrl %d2 + subil #32,%d0 + clrl %d6 + bfffo %d1{#0:#32},%d6 + lsll %d6,%d1 + subl %d6,%d0 | ...(D0,D1,D2) is normalized +| ...with bias $7FFD + bras Init + +HiX_not0: + clrl %d6 + bfffo %d1{#0:#32},%d6 + subl %d6,%d0 + lsll %d6,%d1 + movel %d2,%d7 | ...a copy of D2 + lsll %d6,%d2 + negl %d6 + addil #32,%d6 + lsrl %d6,%d7 + orl %d7,%d1 | ...(D0,D1,D2) normalized +| ...with bias $7FFD + bras Init + +X_Normal: + addil #0x00003FFE,%d0 | ...(D0,D1,D2) normalized +| ...with bias $7FFD + +Init: +| + movel %d3,L_SCR1(%a6) | ...save biased expo(Y) + movel %d0,L_SCR2(%a6) |save d0 + subl %d3,%d0 | ...L := expo(X)-expo(Y) +| Move.L D0,L ...D0 is j + clrl %d6 | ...D6 := carry <- 0 + clrl %d3 | ...D3 is Q + moveal #0,%a1 | ...A1 is k; j+k=L, Q=0 + +|..(Carry,D1,D2) is R + tstl %d0 + bges Mod_Loop + +|..expo(X) < expo(Y). Thus X = mod(X,Y) +| + movel L_SCR2(%a6),%d0 |restore d0 + bra Get_Mod + +|..At this point R = 2^(-L)X; Q = 0; k = 0; and k+j = L + + +Mod_Loop: + tstl %d6 | ...test carry bit + bgts R_GT_Y + +|..At this point carry = 0, R = (D1,D2), Y = (D4,D5) + cmpl %d4,%d1 | ...compare hi(R) and hi(Y) + bnes R_NE_Y + cmpl %d5,%d2 | ...compare lo(R) and lo(Y) + bnes R_NE_Y + +|..At this point, R = Y + bra Rem_is_0 + +R_NE_Y: +|..use the borrow of the previous compare + bcss R_LT_Y | ...borrow is set iff R < Y + +R_GT_Y: +|..If Carry is set, then Y < (Carry,D1,D2) < 2Y. Otherwise, Carry = 0 +|..and Y < (D1,D2) < 2Y. Either way, perform R - Y + subl %d5,%d2 | ...lo(R) - lo(Y) + subxl %d4,%d1 | ...hi(R) - hi(Y) + clrl %d6 | ...clear carry + addql #1,%d3 | ...Q := Q + 1 + +R_LT_Y: +|..At this point, Carry=0, R < Y. R = 2^(k-L)X - QY; k+j = L; j >= 0. + tstl %d0 | ...see if j = 0. + beqs PostLoop + + addl %d3,%d3 | ...Q := 2Q + addl %d2,%d2 | ...lo(R) = 2lo(R) + roxll #1,%d1 | ...hi(R) = 2hi(R) + carry + scs %d6 | ...set Carry if 2(R) overflows + addql #1,%a1 | ...k := k+1 + subql #1,%d0 | ...j := j - 1 +|..At this point, R=(Carry,D1,D2) = 2^(k-L)X - QY, j+k=L, j >= 0, R < 2Y. + + bras Mod_Loop + +PostLoop: +|..k = L, j = 0, Carry = 0, R = (D1,D2) = X - QY, R < Y. + +|..normalize R. + movel L_SCR1(%a6),%d0 | ...new biased expo of R + tstl %d1 + bnes HiR_not0 + +HiR_0: + movel %d2,%d1 + clrl %d2 + subil #32,%d0 + clrl %d6 + bfffo %d1{#0:#32},%d6 + lsll %d6,%d1 + subl %d6,%d0 | ...(D0,D1,D2) is normalized +| ...with bias $7FFD + bras Get_Mod + +HiR_not0: + clrl %d6 + bfffo %d1{#0:#32},%d6 + bmis Get_Mod | ...already normalized + subl %d6,%d0 + lsll %d6,%d1 + movel %d2,%d7 | ...a copy of D2 + lsll %d6,%d2 + negl %d6 + addil #32,%d6 + lsrl %d6,%d7 + orl %d7,%d1 | ...(D0,D1,D2) normalized + +| +Get_Mod: + cmpil #0x000041FE,%d0 + bges No_Scale +Do_Scale: + movew %d0,R(%a6) + clrw R+2(%a6) + movel %d1,R_Hi(%a6) + movel %d2,R_Lo(%a6) + movel L_SCR1(%a6),%d6 + movew %d6,Y(%a6) + clrw Y+2(%a6) + movel %d4,Y_Hi(%a6) + movel %d5,Y_Lo(%a6) + fmovex R(%a6),%fp0 | ...no exception + movel #1,Sc_Flag(%a6) + bras ModOrRem +No_Scale: + movel %d1,R_Hi(%a6) + movel %d2,R_Lo(%a6) + subil #0x3FFE,%d0 + movew %d0,R(%a6) + clrw R+2(%a6) + movel L_SCR1(%a6),%d6 + subil #0x3FFE,%d6 + movel %d6,L_SCR1(%a6) + fmovex R(%a6),%fp0 + movew %d6,Y(%a6) + movel %d4,Y_Hi(%a6) + movel %d5,Y_Lo(%a6) + movel #0,Sc_Flag(%a6) + +| + + +ModOrRem: + movel Mod_Flag(%a6),%d6 + beqs Fix_Sign + + movel L_SCR1(%a6),%d6 | ...new biased expo(Y) + subql #1,%d6 | ...biased expo(Y/2) + cmpl %d6,%d0 + blts Fix_Sign + bgts Last_Sub + + cmpl %d4,%d1 + bnes Not_EQ + cmpl %d5,%d2 + bnes Not_EQ + bra Tie_Case + +Not_EQ: + bcss Fix_Sign + +Last_Sub: +| + fsubx Y(%a6),%fp0 | ...no exceptions + addql #1,%d3 | ...Q := Q + 1 + +| + +Fix_Sign: +|..Get sign of X + movew SignX(%a6),%d6 + bges Get_Q + fnegx %fp0 + +|..Get Q +| +Get_Q: + clrl %d6 + movew SignQ(%a6),%d6 | ...D6 is sign(Q) + movel #8,%d7 + lsrl %d7,%d6 + andil #0x0000007F,%d3 | ...7 bits of Q + orl %d6,%d3 | ...sign and bits of Q + swap %d3 + fmovel %fpsr,%d6 + andil #0xFF00FFFF,%d6 + orl %d3,%d6 + fmovel %d6,%fpsr | ...put Q in fpsr + +| +Restore: + moveml (%a7)+,%d2-%d7 + fmovel USER_FPCR(%a6),%fpcr + movel Sc_Flag(%a6),%d0 + beqs Finish + fmulx Scale(%pc),%fp0 | ...may cause underflow + bra t_avoid_unsupp |check for denorm as a +| ;result of the scaling + +Finish: + fmovex %fp0,%fp0 |capture exceptions & round + rts + +Rem_is_0: +|..R = 2^(-j)X - Q Y = Y, thus R = 0 and quotient = 2^j (Q+1) + addql #1,%d3 + cmpil #8,%d0 | ...D0 is j + bges Q_Big + + lsll %d0,%d3 + bras Set_R_0 + +Q_Big: + clrl %d3 + +Set_R_0: + fmoves #0x00000000,%fp0 + movel #0,Sc_Flag(%a6) + bra Fix_Sign + +Tie_Case: +|..Check parity of Q + movel %d3,%d6 + andil #0x00000001,%d6 + tstl %d6 + beq Fix_Sign | ...Q is even + +|..Q is odd, Q := Q + 1, signX := -signX + addql #1,%d3 + movew SignX(%a6),%d6 + eoril #0x00008000,%d6 + movew %d6,SignX(%a6) + bra Fix_Sign + + |end diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/ssin.S linux/arch/m68k/fpsp040/ssin.S --- v1.3.93/linux/arch/m68k/fpsp040/ssin.S Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/fpsp040/ssin.S Sat Feb 24 22:58:44 1996 @@ -0,0 +1,746 @@ +| +| ssin.sa 3.3 7/29/91 +| +| The entry point sSIN computes the sine of an input argument +| sCOS computes the cosine, and sSINCOS computes both. The +| corresponding entry points with a "d" computes the same +| corresponding function values for denormalized inputs. +| +| Input: Double-extended number X in location pointed to +| by address register a0. +| +| Output: The funtion value sin(X) or cos(X) returned in Fp0 if SIN or +| COS is requested. Otherwise, for SINCOS, sin(X) is returned +| in Fp0, and cos(X) is returned in Fp1. +| +| Modifies: Fp0 for SIN or COS; both Fp0 and Fp1 for SINCOS. +| +| Accuracy and Monotonicity: The returned result is within 1 ulp in +| 64 significant bit, i.e. within 0.5001 ulp to 53 bits if the +| result is subsequently rounded to double precision. The +| result is provably monotonic in double precision. +| +| Speed: The programs sSIN and sCOS take approximately 150 cycles for +| input argument X such that |X| < 15Pi, which is the the usual +| situation. The speed for sSINCOS is approximately 190 cycles. +| +| Algorithm: +| +| SIN and COS: +| 1. If SIN is invoked, set AdjN := 0; otherwise, set AdjN := 1. +| +| 2. If |X| >= 15Pi or |X| < 2**(-40), go to 7. +| +| 3. Decompose X as X = N(Pi/2) + r where |r| <= Pi/4. Let +| k = N mod 4, so in particular, k = 0,1,2,or 3. Overwirte +| k by k := k + AdjN. +| +| 4. If k is even, go to 6. +| +| 5. (k is odd) Set j := (k-1)/2, sgn := (-1)**j. Return sgn*cos(r) +| where cos(r) is approximated by an even polynomial in r, +| 1 + r*r*(B1+s*(B2+ ... + s*B8)), s = r*r. +| Exit. +| +| 6. (k is even) Set j := k/2, sgn := (-1)**j. Return sgn*sin(r) +| where sin(r) is approximated by an odd polynomial in r +| r + r*s*(A1+s*(A2+ ... + s*A7)), s = r*r. +| Exit. +| +| 7. If |X| > 1, go to 9. +| +| 8. (|X|<2**(-40)) If SIN is invoked, return X; otherwise return 1. +| +| 9. Overwrite X by X := X rem 2Pi. Now that |X| <= Pi, go back to 3. +| +| SINCOS: +| 1. If |X| >= 15Pi or |X| < 2**(-40), go to 6. +| +| 2. Decompose X as X = N(Pi/2) + r where |r| <= Pi/4. Let +| k = N mod 4, so in particular, k = 0,1,2,or 3. +| +| 3. If k is even, go to 5. +| +| 4. (k is odd) Set j1 := (k-1)/2, j2 := j1 (EOR) (k mod 2), i.e. +| j1 exclusive or with the l.s.b. of k. +| sgn1 := (-1)**j1, sgn2 := (-1)**j2. +| SIN(X) = sgn1 * cos(r) and COS(X) = sgn2*sin(r) where +| sin(r) and cos(r) are computed as odd and even polynomials +| in r, respectively. Exit +| +| 5. (k is even) Set j1 := k/2, sgn1 := (-1)**j1. +| SIN(X) = sgn1 * sin(r) and COS(X) = sgn1*cos(r) where +| sin(r) and cos(r) are computed as odd and even polynomials +| in r, respectively. Exit +| +| 6. If |X| > 1, go to 8. +| +| 7. (|X|<2**(-40)) SIN(X) = X and COS(X) = 1. Exit. +| +| 8. Overwrite X by X := X rem 2Pi. Now that |X| <= Pi, go back to 2. +| + +| Copyright (C) Motorola, Inc. 1990 +| All Rights Reserved +| +| THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA +| The copyright notice above does not evidence any +| actual or intended publication of such source code. + +|SSIN idnt 2,1 | Motorola 040 Floating Point Software Package + + |section 8 + + .include "fpsp.h" + +BOUNDS1: .long 0x3FD78000,0x4004BC7E +TWOBYPI: .long 0x3FE45F30,0x6DC9C883 + +SINA7: .long 0xBD6AAA77,0xCCC994F5 +SINA6: .long 0x3DE61209,0x7AAE8DA1 + +SINA5: .long 0xBE5AE645,0x2A118AE4 +SINA4: .long 0x3EC71DE3,0xA5341531 + +SINA3: .long 0xBF2A01A0,0x1A018B59,0x00000000,0x00000000 + +SINA2: .long 0x3FF80000,0x88888888,0x888859AF,0x00000000 + +SINA1: .long 0xBFFC0000,0xAAAAAAAA,0xAAAAAA99,0x00000000 + +COSB8: .long 0x3D2AC4D0,0xD6011EE3 +COSB7: .long 0xBDA9396F,0x9F45AC19 + +COSB6: .long 0x3E21EED9,0x0612C972 +COSB5: .long 0xBE927E4F,0xB79D9FCF + +COSB4: .long 0x3EFA01A0,0x1A01D423,0x00000000,0x00000000 + +COSB3: .long 0xBFF50000,0xB60B60B6,0x0B61D438,0x00000000 + +COSB2: .long 0x3FFA0000,0xAAAAAAAA,0xAAAAAB5E +COSB1: .long 0xBF000000 + +INVTWOPI: .long 0x3FFC0000,0xA2F9836E,0x4E44152A + +TWOPI1: .long 0x40010000,0xC90FDAA2,0x00000000,0x00000000 +TWOPI2: .long 0x3FDF0000,0x85A308D4,0x00000000,0x00000000 + + |xref PITBL + + .set INARG,FP_SCR4 + + .set X,FP_SCR5 + .set XDCARE,X+2 + .set XFRAC,X+4 + + .set RPRIME,FP_SCR1 + .set SPRIME,FP_SCR2 + + .set POSNEG1,L_SCR1 + .set TWOTO63,L_SCR1 + + .set ENDFLAG,L_SCR2 + .set N,L_SCR2 + + .set ADJN,L_SCR3 + + | xref t_frcinx + |xref t_extdnrm + |xref sto_cos + + .global ssind +ssind: +|--SIN(X) = X FOR DENORMALIZED X + bra t_extdnrm + + .global scosd +scosd: +|--COS(X) = 1 FOR DENORMALIZED X + + fmoves #0x3F800000,%fp0 +| +| 9D25B Fix: Sometimes the previous fmove.s sets fpsr bits +| + fmovel #0,%fpsr +| + bra t_frcinx + + .global ssin +ssin: +|--SET ADJN TO 0 + movel #0,ADJN(%a6) + bras SINBGN + + .global scos +scos: +|--SET ADJN TO 1 + movel #1,ADJN(%a6) + +SINBGN: +|--SAVE FPCR, FP1. CHECK IF |X| IS TOO SMALL OR LARGE + + fmovex (%a0),%fp0 | ...LOAD INPUT + + movel (%a0),%d0 + movew 4(%a0),%d0 + fmovex %fp0,X(%a6) + andil #0x7FFFFFFF,%d0 | ...COMPACTIFY X + + cmpil #0x3FD78000,%d0 | ...|X| >= 2**(-40)? + bges SOK1 + bra SINSM + +SOK1: + cmpil #0x4004BC7E,%d0 | ...|X| < 15 PI? + blts SINMAIN + bra REDUCEX + +SINMAIN: +|--THIS IS THE USUAL CASE, |X| <= 15 PI. +|--THE ARGUMENT REDUCTION IS DONE BY TABLE LOOK UP. + fmovex %fp0,%fp1 + fmuld TWOBYPI,%fp1 | ...X*2/PI + +|--HIDE THE NEXT THREE INSTRUCTIONS + lea PITBL+0x200,%a1 | ...TABLE OF N*PI/2, N = -32,...,32 + + +|--FP1 IS NOW READY + fmovel %fp1,N(%a6) | ...CONVERT TO INTEGER + + movel N(%a6),%d0 + asll #4,%d0 + addal %d0,%a1 | ...A1 IS THE ADDRESS OF N*PIBY2 +| ...WHICH IS IN TWO PIECES Y1 & Y2 + + fsubx (%a1)+,%fp0 | ...X-Y1 +|--HIDE THE NEXT ONE + fsubs (%a1),%fp0 | ...FP0 IS R = (X-Y1)-Y2 + +SINCONT: +|--continuation from REDUCEX + +|--GET N+ADJN AND SEE IF SIN(R) OR COS(R) IS NEEDED + movel N(%a6),%d0 + addl ADJN(%a6),%d0 | ...SEE IF D0 IS ODD OR EVEN + rorl #1,%d0 | ...D0 WAS ODD IFF D0 IS NEGATIVE + cmpil #0,%d0 + blt COSPOLY + +SINPOLY: +|--LET J BE THE LEAST SIG. BIT OF D0, LET SGN := (-1)**J. +|--THEN WE RETURN SGN*SIN(R). SGN*SIN(R) IS COMPUTED BY +|--R' + R'*S*(A1 + S(A2 + S(A3 + S(A4 + ... + SA7)))), WHERE +|--R' = SGN*R, S=R*R. THIS CAN BE REWRITTEN AS +|--R' + R'*S*( [A1+T(A3+T(A5+TA7))] + [S(A2+T(A4+TA6))]) +|--WHERE T=S*S. +|--NOTE THAT A3 THROUGH A7 ARE STORED IN DOUBLE PRECISION +|--WHILE A1 AND A2 ARE IN DOUBLE-EXTENDED FORMAT. + fmovex %fp0,X(%a6) | ...X IS R + fmulx %fp0,%fp0 | ...FP0 IS S +|---HIDE THE NEXT TWO WHILE WAITING FOR FP0 + fmoved SINA7,%fp3 + fmoved SINA6,%fp2 +|--FP0 IS NOW READY + fmovex %fp0,%fp1 + fmulx %fp1,%fp1 | ...FP1 IS T +|--HIDE THE NEXT TWO WHILE WAITING FOR FP1 + + rorl #1,%d0 + andil #0x80000000,%d0 +| ...LEAST SIG. BIT OF D0 IN SIGN POSITION + eorl %d0,X(%a6) | ...X IS NOW R'= SGN*R + + fmulx %fp1,%fp3 | ...TA7 + fmulx %fp1,%fp2 | ...TA6 + + faddd SINA5,%fp3 | ...A5+TA7 + faddd SINA4,%fp2 | ...A4+TA6 + + fmulx %fp1,%fp3 | ...T(A5+TA7) + fmulx %fp1,%fp2 | ...T(A4+TA6) + + faddd SINA3,%fp3 | ...A3+T(A5+TA7) + faddx SINA2,%fp2 | ...A2+T(A4+TA6) + + fmulx %fp3,%fp1 | ...T(A3+T(A5+TA7)) + + fmulx %fp0,%fp2 | ...S(A2+T(A4+TA6)) + faddx SINA1,%fp1 | ...A1+T(A3+T(A5+TA7)) + fmulx X(%a6),%fp0 | ...R'*S + + faddx %fp2,%fp1 | ...[A1+T(A3+T(A5+TA7))]+[S(A2+T(A4+TA6))] +|--FP3 RELEASED, RESTORE NOW AND TAKE SOME ADVANTAGE OF HIDING +|--FP2 RELEASED, RESTORE NOW AND TAKE FULL ADVANTAGE OF HIDING + + + fmulx %fp1,%fp0 | ...SIN(R')-R' +|--FP1 RELEASED. + + fmovel %d1,%FPCR |restore users exceptions + faddx X(%a6),%fp0 |last inst - possible exception set + bra t_frcinx + + +COSPOLY: +|--LET J BE THE LEAST SIG. BIT OF D0, LET SGN := (-1)**J. +|--THEN WE RETURN SGN*COS(R). SGN*COS(R) IS COMPUTED BY +|--SGN + S'*(B1 + S(B2 + S(B3 + S(B4 + ... + SB8)))), WHERE +|--S=R*R AND S'=SGN*S. THIS CAN BE REWRITTEN AS +|--SGN + S'*([B1+T(B3+T(B5+TB7))] + [S(B2+T(B4+T(B6+TB8)))]) +|--WHERE T=S*S. +|--NOTE THAT B4 THROUGH B8 ARE STORED IN DOUBLE PRECISION +|--WHILE B2 AND B3 ARE IN DOUBLE-EXTENDED FORMAT, B1 IS -1/2 +|--AND IS THEREFORE STORED AS SINGLE PRECISION. + + fmulx %fp0,%fp0 | ...FP0 IS S +|---HIDE THE NEXT TWO WHILE WAITING FOR FP0 + fmoved COSB8,%fp2 + fmoved COSB7,%fp3 +|--FP0 IS NOW READY + fmovex %fp0,%fp1 + fmulx %fp1,%fp1 | ...FP1 IS T +|--HIDE THE NEXT TWO WHILE WAITING FOR FP1 + fmovex %fp0,X(%a6) | ...X IS S + rorl #1,%d0 + andil #0x80000000,%d0 +| ...LEAST SIG. BIT OF D0 IN SIGN POSITION + + fmulx %fp1,%fp2 | ...TB8 +|--HIDE THE NEXT TWO WHILE WAITING FOR THE XU + eorl %d0,X(%a6) | ...X IS NOW S'= SGN*S + andil #0x80000000,%d0 + + fmulx %fp1,%fp3 | ...TB7 +|--HIDE THE NEXT TWO WHILE WAITING FOR THE XU + oril #0x3F800000,%d0 | ...D0 IS SGN IN SINGLE + movel %d0,POSNEG1(%a6) + + faddd COSB6,%fp2 | ...B6+TB8 + faddd COSB5,%fp3 | ...B5+TB7 + + fmulx %fp1,%fp2 | ...T(B6+TB8) + fmulx %fp1,%fp3 | ...T(B5+TB7) + + faddd COSB4,%fp2 | ...B4+T(B6+TB8) + faddx COSB3,%fp3 | ...B3+T(B5+TB7) + + fmulx %fp1,%fp2 | ...T(B4+T(B6+TB8)) + fmulx %fp3,%fp1 | ...T(B3+T(B5+TB7)) + + faddx COSB2,%fp2 | ...B2+T(B4+T(B6+TB8)) + fadds COSB1,%fp1 | ...B1+T(B3+T(B5+TB7)) + + fmulx %fp2,%fp0 | ...S(B2+T(B4+T(B6+TB8))) +|--FP3 RELEASED, RESTORE NOW AND TAKE SOME ADVANTAGE OF HIDING +|--FP2 RELEASED. + + + faddx %fp1,%fp0 +|--FP1 RELEASED + + fmulx X(%a6),%fp0 + + fmovel %d1,%FPCR |restore users exceptions + fadds POSNEG1(%a6),%fp0 |last inst - possible exception set + bra t_frcinx + + +SINBORS: +|--IF |X| > 15PI, WE USE THE GENERAL ARGUMENT REDUCTION. +|--IF |X| < 2**(-40), RETURN X OR 1. + cmpil #0x3FFF8000,%d0 + bgts REDUCEX + + +SINSM: + movel ADJN(%a6),%d0 + cmpil #0,%d0 + bgts COSTINY + +SINTINY: + movew #0x0000,XDCARE(%a6) | ...JUST IN CASE + fmovel %d1,%FPCR |restore users exceptions + fmovex X(%a6),%fp0 |last inst - possible exception set + bra t_frcinx + + +COSTINY: + fmoves #0x3F800000,%fp0 + + fmovel %d1,%FPCR |restore users exceptions + fsubs #0x00800000,%fp0 |last inst - possible exception set + bra t_frcinx + + +REDUCEX: +|--WHEN REDUCEX IS USED, THE CODE WILL INEVITABLY BE SLOW. +|--THIS REDUCTION METHOD, HOWEVER, IS MUCH FASTER THAN USING +|--THE REMAINDER INSTRUCTION WHICH IS NOW IN SOFTWARE. + + fmovemx %fp2-%fp5,-(%a7) | ...save FP2 through FP5 + movel %d2,-(%a7) + fmoves #0x00000000,%fp1 +|--If compact form of abs(arg) in d0=$7ffeffff, argument is so large that +|--there is a danger of unwanted overflow in first LOOP iteration. In this +|--case, reduce argument by one remainder step to make subsequent reduction +|--safe. + cmpil #0x7ffeffff,%d0 |is argument dangerously large? + bnes LOOP + movel #0x7ffe0000,FP_SCR2(%a6) |yes +| ;create 2**16383*PI/2 + movel #0xc90fdaa2,FP_SCR2+4(%a6) + clrl FP_SCR2+8(%a6) + ftstx %fp0 |test sign of argument + movel #0x7fdc0000,FP_SCR3(%a6) |create low half of 2**16383* +| ;PI/2 at FP_SCR3 + movel #0x85a308d3,FP_SCR3+4(%a6) + clrl FP_SCR3+8(%a6) + fblt red_neg + orw #0x8000,FP_SCR2(%a6) |positive arg + orw #0x8000,FP_SCR3(%a6) +red_neg: + faddx FP_SCR2(%a6),%fp0 |high part of reduction is exact + fmovex %fp0,%fp1 |save high result in fp1 + faddx FP_SCR3(%a6),%fp0 |low part of reduction + fsubx %fp0,%fp1 |determine low component of result + faddx FP_SCR3(%a6),%fp1 |fp0/fp1 are reduced argument. + +|--ON ENTRY, FP0 IS X, ON RETURN, FP0 IS X REM PI/2, |X| <= PI/4. +|--integer quotient will be stored in N +|--Intermeditate remainder is 66-bit long; (R,r) in (FP0,FP1) + +LOOP: + fmovex %fp0,INARG(%a6) | ...+-2**K * F, 1 <= F < 2 + movew INARG(%a6),%d0 + movel %d0,%a1 | ...save a copy of D0 + andil #0x00007FFF,%d0 + subil #0x00003FFF,%d0 | ...D0 IS K + cmpil #28,%d0 + bles LASTLOOP +CONTLOOP: + subil #27,%d0 | ...D0 IS L := K-27 + movel #0,ENDFLAG(%a6) + bras WORK +LASTLOOP: + clrl %d0 | ...D0 IS L := 0 + movel #1,ENDFLAG(%a6) + +WORK: +|--FIND THE REMAINDER OF (R,r) W.R.T. 2**L * (PI/2). L IS SO CHOSEN +|--THAT INT( X * (2/PI) / 2**(L) ) < 2**29. + +|--CREATE 2**(-L) * (2/PI), SIGN(INARG)*2**(63), +|--2**L * (PIby2_1), 2**L * (PIby2_2) + + movel #0x00003FFE,%d2 | ...BIASED EXPO OF 2/PI + subl %d0,%d2 | ...BIASED EXPO OF 2**(-L)*(2/PI) + + movel #0xA2F9836E,FP_SCR1+4(%a6) + movel #0x4E44152A,FP_SCR1+8(%a6) + movew %d2,FP_SCR1(%a6) | ...FP_SCR1 is 2**(-L)*(2/PI) + + fmovex %fp0,%fp2 + fmulx FP_SCR1(%a6),%fp2 +|--WE MUST NOW FIND INT(FP2). SINCE WE NEED THIS VALUE IN +|--FLOATING POINT FORMAT, THE TWO FMOVE'S FMOVE.L FP <--> N +|--WILL BE TOO INEFFICIENT. THE WAY AROUND IT IS THAT +|--(SIGN(INARG)*2**63 + FP2) - SIGN(INARG)*2**63 WILL GIVE +|--US THE DESIRED VALUE IN FLOATING POINT. + +|--HIDE SIX CYCLES OF INSTRUCTION + movel %a1,%d2 + swap %d2 + andil #0x80000000,%d2 + oril #0x5F000000,%d2 | ...D2 IS SIGN(INARG)*2**63 IN SGL + movel %d2,TWOTO63(%a6) + + movel %d0,%d2 + addil #0x00003FFF,%d2 | ...BIASED EXPO OF 2**L * (PI/2) + +|--FP2 IS READY + fadds TWOTO63(%a6),%fp2 | ...THE FRACTIONAL PART OF FP1 IS ROUNDED + +|--HIDE 4 CYCLES OF INSTRUCTION; creating 2**(L)*Piby2_1 and 2**(L)*Piby2_2 + movew %d2,FP_SCR2(%a6) + clrw FP_SCR2+2(%a6) + movel #0xC90FDAA2,FP_SCR2+4(%a6) + clrl FP_SCR2+8(%a6) | ...FP_SCR2 is 2**(L) * Piby2_1 + +|--FP2 IS READY + fsubs TWOTO63(%a6),%fp2 | ...FP2 is N + + addil #0x00003FDD,%d0 + movew %d0,FP_SCR3(%a6) + clrw FP_SCR3+2(%a6) + movel #0x85A308D3,FP_SCR3+4(%a6) + clrl FP_SCR3+8(%a6) | ...FP_SCR3 is 2**(L) * Piby2_2 + + movel ENDFLAG(%a6),%d0 + +|--We are now ready to perform (R+r) - N*P1 - N*P2, P1 = 2**(L) * Piby2_1 and +|--P2 = 2**(L) * Piby2_2 + fmovex %fp2,%fp4 + fmulx FP_SCR2(%a6),%fp4 | ...W = N*P1 + fmovex %fp2,%fp5 + fmulx FP_SCR3(%a6),%fp5 | ...w = N*P2 + fmovex %fp4,%fp3 +|--we want P+p = W+w but |p| <= half ulp of P +|--Then, we need to compute A := R-P and a := r-p + faddx %fp5,%fp3 | ...FP3 is P + fsubx %fp3,%fp4 | ...W-P + + fsubx %fp3,%fp0 | ...FP0 is A := R - P + faddx %fp5,%fp4 | ...FP4 is p = (W-P)+w + + fmovex %fp0,%fp3 | ...FP3 A + fsubx %fp4,%fp1 | ...FP1 is a := r - p + +|--Now we need to normalize (A,a) to "new (R,r)" where R+r = A+a but +|--|r| <= half ulp of R. + faddx %fp1,%fp0 | ...FP0 is R := A+a +|--No need to calculate r if this is the last loop + cmpil #0,%d0 + bgt RESTORE + +|--Need to calculate r + fsubx %fp0,%fp3 | ...A-R + faddx %fp3,%fp1 | ...FP1 is r := (A-R)+a + bra LOOP + +RESTORE: + fmovel %fp2,N(%a6) + movel (%a7)+,%d2 + fmovemx (%a7)+,%fp2-%fp5 + + + movel ADJN(%a6),%d0 + cmpil #4,%d0 + + blt SINCONT + bras SCCONT + + .global ssincosd +ssincosd: +|--SIN AND COS OF X FOR DENORMALIZED X + + fmoves #0x3F800000,%fp1 + bsr sto_cos |store cosine result + bra t_extdnrm + + .global ssincos +ssincos: +|--SET ADJN TO 4 + movel #4,ADJN(%a6) + + fmovex (%a0),%fp0 | ...LOAD INPUT + + movel (%a0),%d0 + movew 4(%a0),%d0 + fmovex %fp0,X(%a6) + andil #0x7FFFFFFF,%d0 | ...COMPACTIFY X + + cmpil #0x3FD78000,%d0 | ...|X| >= 2**(-40)? + bges SCOK1 + bra SCSM + +SCOK1: + cmpil #0x4004BC7E,%d0 | ...|X| < 15 PI? + blts SCMAIN + bra REDUCEX + + +SCMAIN: +|--THIS IS THE USUAL CASE, |X| <= 15 PI. +|--THE ARGUMENT REDUCTION IS DONE BY TABLE LOOK UP. + fmovex %fp0,%fp1 + fmuld TWOBYPI,%fp1 | ...X*2/PI + +|--HIDE THE NEXT THREE INSTRUCTIONS + lea PITBL+0x200,%a1 | ...TABLE OF N*PI/2, N = -32,...,32 + + +|--FP1 IS NOW READY + fmovel %fp1,N(%a6) | ...CONVERT TO INTEGER + + movel N(%a6),%d0 + asll #4,%d0 + addal %d0,%a1 | ...ADDRESS OF N*PIBY2, IN Y1, Y2 + + fsubx (%a1)+,%fp0 | ...X-Y1 + fsubs (%a1),%fp0 | ...FP0 IS R = (X-Y1)-Y2 + +SCCONT: +|--continuation point from REDUCEX + +|--HIDE THE NEXT TWO + movel N(%a6),%d0 + rorl #1,%d0 + + cmpil #0,%d0 | ...D0 < 0 IFF N IS ODD + bge NEVEN + +NODD: +|--REGISTERS SAVED SO FAR: D0, A0, FP2. + + fmovex %fp0,RPRIME(%a6) + fmulx %fp0,%fp0 | ...FP0 IS S = R*R + fmoved SINA7,%fp1 | ...A7 + fmoved COSB8,%fp2 | ...B8 + fmulx %fp0,%fp1 | ...SA7 + movel %d2,-(%a7) + movel %d0,%d2 + fmulx %fp0,%fp2 | ...SB8 + rorl #1,%d2 + andil #0x80000000,%d2 + + faddd SINA6,%fp1 | ...A6+SA7 + eorl %d0,%d2 + andil #0x80000000,%d2 + faddd COSB7,%fp2 | ...B7+SB8 + + fmulx %fp0,%fp1 | ...S(A6+SA7) + eorl %d2,RPRIME(%a6) + movel (%a7)+,%d2 + fmulx %fp0,%fp2 | ...S(B7+SB8) + rorl #1,%d0 + andil #0x80000000,%d0 + + faddd SINA5,%fp1 | ...A5+S(A6+SA7) + movel #0x3F800000,POSNEG1(%a6) + eorl %d0,POSNEG1(%a6) + faddd COSB6,%fp2 | ...B6+S(B7+SB8) + + fmulx %fp0,%fp1 | ...S(A5+S(A6+SA7)) + fmulx %fp0,%fp2 | ...S(B6+S(B7+SB8)) + fmovex %fp0,SPRIME(%a6) + + faddd SINA4,%fp1 | ...A4+S(A5+S(A6+SA7)) + eorl %d0,SPRIME(%a6) + faddd COSB5,%fp2 | ...B5+S(B6+S(B7+SB8)) + + fmulx %fp0,%fp1 | ...S(A4+...) + fmulx %fp0,%fp2 | ...S(B5+...) + + faddd SINA3,%fp1 | ...A3+S(A4+...) + faddd COSB4,%fp2 | ...B4+S(B5+...) + + fmulx %fp0,%fp1 | ...S(A3+...) + fmulx %fp0,%fp2 | ...S(B4+...) + + faddx SINA2,%fp1 | ...A2+S(A3+...) + faddx COSB3,%fp2 | ...B3+S(B4+...) + + fmulx %fp0,%fp1 | ...S(A2+...) + fmulx %fp0,%fp2 | ...S(B3+...) + + faddx SINA1,%fp1 | ...A1+S(A2+...) + faddx COSB2,%fp2 | ...B2+S(B3+...) + + fmulx %fp0,%fp1 | ...S(A1+...) + fmulx %fp2,%fp0 | ...S(B2+...) + + + + fmulx RPRIME(%a6),%fp1 | ...R'S(A1+...) + fadds COSB1,%fp0 | ...B1+S(B2...) + fmulx SPRIME(%a6),%fp0 | ...S'(B1+S(B2+...)) + + movel %d1,-(%sp) |restore users mode & precision + andil #0xff,%d1 |mask off all exceptions + fmovel %d1,%FPCR + faddx RPRIME(%a6),%fp1 | ...COS(X) + bsr sto_cos |store cosine result + fmovel (%sp)+,%FPCR |restore users exceptions + fadds POSNEG1(%a6),%fp0 | ...SIN(X) + + bra t_frcinx + + +NEVEN: +|--REGISTERS SAVED SO FAR: FP2. + + fmovex %fp0,RPRIME(%a6) + fmulx %fp0,%fp0 | ...FP0 IS S = R*R + fmoved COSB8,%fp1 | ...B8 + fmoved SINA7,%fp2 | ...A7 + fmulx %fp0,%fp1 | ...SB8 + fmovex %fp0,SPRIME(%a6) + fmulx %fp0,%fp2 | ...SA7 + rorl #1,%d0 + andil #0x80000000,%d0 + faddd COSB7,%fp1 | ...B7+SB8 + faddd SINA6,%fp2 | ...A6+SA7 + eorl %d0,RPRIME(%a6) + eorl %d0,SPRIME(%a6) + fmulx %fp0,%fp1 | ...S(B7+SB8) + oril #0x3F800000,%d0 + movel %d0,POSNEG1(%a6) + fmulx %fp0,%fp2 | ...S(A6+SA7) + + faddd COSB6,%fp1 | ...B6+S(B7+SB8) + faddd SINA5,%fp2 | ...A5+S(A6+SA7) + + fmulx %fp0,%fp1 | ...S(B6+S(B7+SB8)) + fmulx %fp0,%fp2 | ...S(A5+S(A6+SA7)) + + faddd COSB5,%fp1 | ...B5+S(B6+S(B7+SB8)) + faddd SINA4,%fp2 | ...A4+S(A5+S(A6+SA7)) + + fmulx %fp0,%fp1 | ...S(B5+...) + fmulx %fp0,%fp2 | ...S(A4+...) + + faddd COSB4,%fp1 | ...B4+S(B5+...) + faddd SINA3,%fp2 | ...A3+S(A4+...) + + fmulx %fp0,%fp1 | ...S(B4+...) + fmulx %fp0,%fp2 | ...S(A3+...) + + faddx COSB3,%fp1 | ...B3+S(B4+...) + faddx SINA2,%fp2 | ...A2+S(A3+...) + + fmulx %fp0,%fp1 | ...S(B3+...) + fmulx %fp0,%fp2 | ...S(A2+...) + + faddx COSB2,%fp1 | ...B2+S(B3+...) + faddx SINA1,%fp2 | ...A1+S(A2+...) + + fmulx %fp0,%fp1 | ...S(B2+...) + fmulx %fp2,%fp0 | ...s(a1+...) + + + + fadds COSB1,%fp1 | ...B1+S(B2...) + fmulx RPRIME(%a6),%fp0 | ...R'S(A1+...) + fmulx SPRIME(%a6),%fp1 | ...S'(B1+S(B2+...)) + + movel %d1,-(%sp) |save users mode & precision + andil #0xff,%d1 |mask off all exceptions + fmovel %d1,%FPCR + fadds POSNEG1(%a6),%fp1 | ...COS(X) + bsr sto_cos |store cosine result + fmovel (%sp)+,%FPCR |restore users exceptions + faddx RPRIME(%a6),%fp0 | ...SIN(X) + + bra t_frcinx + +SCBORS: + cmpil #0x3FFF8000,%d0 + bgt REDUCEX + + +SCSM: + movew #0x0000,XDCARE(%a6) + fmoves #0x3F800000,%fp1 + + movel %d1,-(%sp) |save users mode & precision + andil #0xff,%d1 |mask off all exceptions + fmovel %d1,%FPCR + fsubs #0x00800000,%fp1 + bsr sto_cos |store cosine result + fmovel (%sp)+,%FPCR |restore users exceptions + fmovex X(%a6),%fp0 + bra t_frcinx + + |end diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/ssinh.S linux/arch/m68k/fpsp040/ssinh.S --- v1.3.93/linux/arch/m68k/fpsp040/ssinh.S Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/fpsp040/ssinh.S Sat Feb 24 22:58:44 1996 @@ -0,0 +1,135 @@ +| +| ssinh.sa 3.1 12/10/90 +| +| The entry point sSinh computes the hyperbolic sine of +| an input argument; sSinhd does the same except for denormalized +| input. +| +| Input: Double-extended number X in location pointed to +| by address register a0. +| +| Output: The value sinh(X) returned in floating-point register Fp0. +| +| Accuracy and Monotonicity: The returned result is within 3 ulps in +| 64 significant bit, i.e. within 0.5001 ulp to 53 bits if the +| result is subsequently rounded to double precision. The +| result is provably monotonic in double precision. +| +| Speed: The program sSINH takes approximately 280 cycles. +| +| Algorithm: +| +| SINH +| 1. If |X| > 16380 log2, go to 3. +| +| 2. (|X| <= 16380 log2) Sinh(X) is obtained by the formulae +| y = |X|, sgn = sign(X), and z = expm1(Y), +| sinh(X) = sgn*(1/2)*( z + z/(1+z) ). +| Exit. +| +| 3. If |X| > 16480 log2, go to 5. +| +| 4. (16380 log2 < |X| <= 16480 log2) +| sinh(X) = sign(X) * exp(|X|)/2. +| However, invoking exp(|X|) may cause premature overflow. +| Thus, we calculate sinh(X) as follows: +| Y := |X| +| sgn := sign(X) +| sgnFact := sgn * 2**(16380) +| Y' := Y - 16381 log2 +| sinh(X) := sgnFact * exp(Y'). +| Exit. +| +| 5. (|X| > 16480 log2) sinh(X) must overflow. Return +| sign(X)*Huge*Huge to generate overflow and an infinity with +| the appropriate sign. Huge is the largest finite number in +| extended format. Exit. +| + +| Copyright (C) Motorola, Inc. 1990 +| All Rights Reserved +| +| THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA +| The copyright notice above does not evidence any +| actual or intended publication of such source code. + +|SSINH idnt 2,1 | Motorola 040 Floating Point Software Package + + |section 8 + +T1: .long 0x40C62D38,0xD3D64634 | ... 16381 LOG2 LEAD +T2: .long 0x3D6F90AE,0xB1E75CC7 | ... 16381 LOG2 TRAIL + + |xref t_frcinx + |xref t_ovfl + |xref t_extdnrm + |xref setox + |xref setoxm1 + + .global ssinhd +ssinhd: +|--SINH(X) = X FOR DENORMALIZED X + + bra t_extdnrm + + .global ssinh +ssinh: + fmovex (%a0),%fp0 | ...LOAD INPUT + + movel (%a0),%d0 + movew 4(%a0),%d0 + movel %d0,%a1 | save a copy of original (compacted) operand + andl #0x7FFFFFFF,%d0 + cmpl #0x400CB167,%d0 + bgts SINHBIG + +|--THIS IS THE USUAL CASE, |X| < 16380 LOG2 +|--Y = |X|, Z = EXPM1(Y), SINH(X) = SIGN(X)*(1/2)*( Z + Z/(1+Z) ) + + fabsx %fp0 | ...Y = |X| + + moveml %a1/%d1,-(%sp) + fmovemx %fp0-%fp0,(%a0) + clrl %d1 + bsr setoxm1 | ...FP0 IS Z = EXPM1(Y) + fmovel #0,%fpcr + moveml (%sp)+,%a1/%d1 + + fmovex %fp0,%fp1 + fadds #0x3F800000,%fp1 | ...1+Z + fmovex %fp0,-(%sp) + fdivx %fp1,%fp0 | ...Z/(1+Z) + movel %a1,%d0 + andl #0x80000000,%d0 + orl #0x3F000000,%d0 + faddx (%sp)+,%fp0 + movel %d0,-(%sp) + + fmovel %d1,%fpcr + fmuls (%sp)+,%fp0 |last fp inst - possible exceptions set + + bra t_frcinx + +SINHBIG: + cmpl #0x400CB2B3,%d0 + bgt t_ovfl + fabsx %fp0 + fsubd T1(%pc),%fp0 | ...(|X|-16381LOG2_LEAD) + movel #0,-(%sp) + movel #0x80000000,-(%sp) + movel %a1,%d0 + andl #0x80000000,%d0 + orl #0x7FFB0000,%d0 + movel %d0,-(%sp) | ...EXTENDED FMT + fsubd T2(%pc),%fp0 | ...|X| - 16381 LOG2, ACCURATE + + movel %d1,-(%sp) + clrl %d1 + fmovemx %fp0-%fp0,(%a0) + bsr setox + fmovel (%sp)+,%fpcr + + fmulx (%sp)+,%fp0 |possible exception + bra t_frcinx + + |end diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/stan.S linux/arch/m68k/fpsp040/stan.S --- v1.3.93/linux/arch/m68k/fpsp040/stan.S Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/fpsp040/stan.S Sat Feb 24 22:58:44 1996 @@ -0,0 +1,455 @@ +| +| stan.sa 3.3 7/29/91 +| +| The entry point stan computes the tangent of +| an input argument; +| stand does the same except for denormalized input. +| +| Input: Double-extended number X in location pointed to +| by address register a0. +| +| Output: The value tan(X) returned in floating-point register Fp0. +| +| Accuracy and Monotonicity: The returned result is within 3 ulp in +| 64 significant bit, i.e. within 0.5001 ulp to 53 bits if the +| result is subsequently rounded to double precision. The +| result is provably monotonic in double precision. +| +| Speed: The program sTAN takes approximately 170 cycles for +| input argument X such that |X| < 15Pi, which is the the usual +| situation. +| +| Algorithm: +| +| 1. If |X| >= 15Pi or |X| < 2**(-40), go to 6. +| +| 2. Decompose X as X = N(Pi/2) + r where |r| <= Pi/4. Let +| k = N mod 2, so in particular, k = 0 or 1. +| +| 3. If k is odd, go to 5. +| +| 4. (k is even) Tan(X) = tan(r) and tan(r) is approximated by a +| rational function U/V where +| U = r + r*s*(P1 + s*(P2 + s*P3)), and +| V = 1 + s*(Q1 + s*(Q2 + s*(Q3 + s*Q4))), s = r*r. +| Exit. +| +| 4. (k is odd) Tan(X) = -cot(r). Since tan(r) is approximated by a +| rational function U/V where +| U = r + r*s*(P1 + s*(P2 + s*P3)), and +| V = 1 + s*(Q1 + s*(Q2 + s*(Q3 + s*Q4))), s = r*r, +| -Cot(r) = -V/U. Exit. +| +| 6. If |X| > 1, go to 8. +| +| 7. (|X|<2**(-40)) Tan(X) = X. Exit. +| +| 8. Overwrite X by X := X rem 2Pi. Now that |X| <= Pi, go back to 2. +| + +| Copyright (C) Motorola, Inc. 1990 +| All Rights Reserved +| +| THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA +| The copyright notice above does not evidence any +| actual or intended publication of such source code. + +|STAN idnt 2,1 | Motorola 040 Floating Point Software Package + + |section 8 + + .include "fpsp.h" + +BOUNDS1: .long 0x3FD78000,0x4004BC7E +TWOBYPI: .long 0x3FE45F30,0x6DC9C883 + +TANQ4: .long 0x3EA0B759,0xF50F8688 +TANP3: .long 0xBEF2BAA5,0xA8924F04 + +TANQ3: .long 0xBF346F59,0xB39BA65F,0x00000000,0x00000000 + +TANP2: .long 0x3FF60000,0xE073D3FC,0x199C4A00,0x00000000 + +TANQ2: .long 0x3FF90000,0xD23CD684,0x15D95FA1,0x00000000 + +TANP1: .long 0xBFFC0000,0x8895A6C5,0xFB423BCA,0x00000000 + +TANQ1: .long 0xBFFD0000,0xEEF57E0D,0xA84BC8CE,0x00000000 + +INVTWOPI: .long 0x3FFC0000,0xA2F9836E,0x4E44152A,0x00000000 + +TWOPI1: .long 0x40010000,0xC90FDAA2,0x00000000,0x00000000 +TWOPI2: .long 0x3FDF0000,0x85A308D4,0x00000000,0x00000000 + +|--N*PI/2, -32 <= N <= 32, IN A LEADING TERM IN EXT. AND TRAILING +|--TERM IN SGL. NOTE THAT PI IS 64-BIT LONG, THUS N*PI/2 IS AT +|--MOST 69 BITS LONG. + .global PITBL +PITBL: + .long 0xC0040000,0xC90FDAA2,0x2168C235,0x21800000 + .long 0xC0040000,0xC2C75BCD,0x105D7C23,0xA0D00000 + .long 0xC0040000,0xBC7EDCF7,0xFF523611,0xA1E80000 + .long 0xC0040000,0xB6365E22,0xEE46F000,0x21480000 + .long 0xC0040000,0xAFEDDF4D,0xDD3BA9EE,0xA1200000 + .long 0xC0040000,0xA9A56078,0xCC3063DD,0x21FC0000 + .long 0xC0040000,0xA35CE1A3,0xBB251DCB,0x21100000 + .long 0xC0040000,0x9D1462CE,0xAA19D7B9,0xA1580000 + .long 0xC0040000,0x96CBE3F9,0x990E91A8,0x21E00000 + .long 0xC0040000,0x90836524,0x88034B96,0x20B00000 + .long 0xC0040000,0x8A3AE64F,0x76F80584,0xA1880000 + .long 0xC0040000,0x83F2677A,0x65ECBF73,0x21C40000 + .long 0xC0030000,0xFB53D14A,0xA9C2F2C2,0x20000000 + .long 0xC0030000,0xEEC2D3A0,0x87AC669F,0x21380000 + .long 0xC0030000,0xE231D5F6,0x6595DA7B,0xA1300000 + .long 0xC0030000,0xD5A0D84C,0x437F4E58,0x9FC00000 + .long 0xC0030000,0xC90FDAA2,0x2168C235,0x21000000 + .long 0xC0030000,0xBC7EDCF7,0xFF523611,0xA1680000 + .long 0xC0030000,0xAFEDDF4D,0xDD3BA9EE,0xA0A00000 + .long 0xC0030000,0xA35CE1A3,0xBB251DCB,0x20900000 + .long 0xC0030000,0x96CBE3F9,0x990E91A8,0x21600000 + .long 0xC0030000,0x8A3AE64F,0x76F80584,0xA1080000 + .long 0xC0020000,0xFB53D14A,0xA9C2F2C2,0x1F800000 + .long 0xC0020000,0xE231D5F6,0x6595DA7B,0xA0B00000 + .long 0xC0020000,0xC90FDAA2,0x2168C235,0x20800000 + .long 0xC0020000,0xAFEDDF4D,0xDD3BA9EE,0xA0200000 + .long 0xC0020000,0x96CBE3F9,0x990E91A8,0x20E00000 + .long 0xC0010000,0xFB53D14A,0xA9C2F2C2,0x1F000000 + .long 0xC0010000,0xC90FDAA2,0x2168C235,0x20000000 + .long 0xC0010000,0x96CBE3F9,0x990E91A8,0x20600000 + .long 0xC0000000,0xC90FDAA2,0x2168C235,0x1F800000 + .long 0xBFFF0000,0xC90FDAA2,0x2168C235,0x1F000000 + .long 0x00000000,0x00000000,0x00000000,0x00000000 + .long 0x3FFF0000,0xC90FDAA2,0x2168C235,0x9F000000 + .long 0x40000000,0xC90FDAA2,0x2168C235,0x9F800000 + .long 0x40010000,0x96CBE3F9,0x990E91A8,0xA0600000 + .long 0x40010000,0xC90FDAA2,0x2168C235,0xA0000000 + .long 0x40010000,0xFB53D14A,0xA9C2F2C2,0x9F000000 + .long 0x40020000,0x96CBE3F9,0x990E91A8,0xA0E00000 + .long 0x40020000,0xAFEDDF4D,0xDD3BA9EE,0x20200000 + .long 0x40020000,0xC90FDAA2,0x2168C235,0xA0800000 + .long 0x40020000,0xE231D5F6,0x6595DA7B,0x20B00000 + .long 0x40020000,0xFB53D14A,0xA9C2F2C2,0x9F800000 + .long 0x40030000,0x8A3AE64F,0x76F80584,0x21080000 + .long 0x40030000,0x96CBE3F9,0x990E91A8,0xA1600000 + .long 0x40030000,0xA35CE1A3,0xBB251DCB,0xA0900000 + .long 0x40030000,0xAFEDDF4D,0xDD3BA9EE,0x20A00000 + .long 0x40030000,0xBC7EDCF7,0xFF523611,0x21680000 + .long 0x40030000,0xC90FDAA2,0x2168C235,0xA1000000 + .long 0x40030000,0xD5A0D84C,0x437F4E58,0x1FC00000 + .long 0x40030000,0xE231D5F6,0x6595DA7B,0x21300000 + .long 0x40030000,0xEEC2D3A0,0x87AC669F,0xA1380000 + .long 0x40030000,0xFB53D14A,0xA9C2F2C2,0xA0000000 + .long 0x40040000,0x83F2677A,0x65ECBF73,0xA1C40000 + .long 0x40040000,0x8A3AE64F,0x76F80584,0x21880000 + .long 0x40040000,0x90836524,0x88034B96,0xA0B00000 + .long 0x40040000,0x96CBE3F9,0x990E91A8,0xA1E00000 + .long 0x40040000,0x9D1462CE,0xAA19D7B9,0x21580000 + .long 0x40040000,0xA35CE1A3,0xBB251DCB,0xA1100000 + .long 0x40040000,0xA9A56078,0xCC3063DD,0xA1FC0000 + .long 0x40040000,0xAFEDDF4D,0xDD3BA9EE,0x21200000 + .long 0x40040000,0xB6365E22,0xEE46F000,0xA1480000 + .long 0x40040000,0xBC7EDCF7,0xFF523611,0x21E80000 + .long 0x40040000,0xC2C75BCD,0x105D7C23,0x20D00000 + .long 0x40040000,0xC90FDAA2,0x2168C235,0xA1800000 + + .set INARG,FP_SCR4 + + .set TWOTO63,L_SCR1 + .set ENDFLAG,L_SCR2 + .set N,L_SCR3 + + | xref t_frcinx + |xref t_extdnrm + + .global stand +stand: +|--TAN(X) = X FOR DENORMALIZED X + + bra t_extdnrm + + .global stan +stan: + fmovex (%a0),%fp0 | ...LOAD INPUT + + movel (%a0),%d0 + movew 4(%a0),%d0 + andil #0x7FFFFFFF,%d0 + + cmpil #0x3FD78000,%d0 | ...|X| >= 2**(-40)? + bges TANOK1 + bra TANSM +TANOK1: + cmpil #0x4004BC7E,%d0 | ...|X| < 15 PI? + blts TANMAIN + bra REDUCEX + + +TANMAIN: +|--THIS IS THE USUAL CASE, |X| <= 15 PI. +|--THE ARGUMENT REDUCTION IS DONE BY TABLE LOOK UP. + fmovex %fp0,%fp1 + fmuld TWOBYPI,%fp1 | ...X*2/PI + +|--HIDE THE NEXT TWO INSTRUCTIONS + leal PITBL+0x200,%a1 | ...TABLE OF N*PI/2, N = -32,...,32 + +|--FP1 IS NOW READY + fmovel %fp1,%d0 | ...CONVERT TO INTEGER + + asll #4,%d0 + addal %d0,%a1 | ...ADDRESS N*PIBY2 IN Y1, Y2 + + fsubx (%a1)+,%fp0 | ...X-Y1 +|--HIDE THE NEXT ONE + + fsubs (%a1),%fp0 | ...FP0 IS R = (X-Y1)-Y2 + + rorl #5,%d0 + andil #0x80000000,%d0 | ...D0 WAS ODD IFF D0 < 0 + +TANCONT: + + cmpil #0,%d0 + blt NODD + + fmovex %fp0,%fp1 + fmulx %fp1,%fp1 | ...S = R*R + + fmoved TANQ4,%fp3 + fmoved TANP3,%fp2 + + fmulx %fp1,%fp3 | ...SQ4 + fmulx %fp1,%fp2 | ...SP3 + + faddd TANQ3,%fp3 | ...Q3+SQ4 + faddx TANP2,%fp2 | ...P2+SP3 + + fmulx %fp1,%fp3 | ...S(Q3+SQ4) + fmulx %fp1,%fp2 | ...S(P2+SP3) + + faddx TANQ2,%fp3 | ...Q2+S(Q3+SQ4) + faddx TANP1,%fp2 | ...P1+S(P2+SP3) + + fmulx %fp1,%fp3 | ...S(Q2+S(Q3+SQ4)) + fmulx %fp1,%fp2 | ...S(P1+S(P2+SP3)) + + faddx TANQ1,%fp3 | ...Q1+S(Q2+S(Q3+SQ4)) + fmulx %fp0,%fp2 | ...RS(P1+S(P2+SP3)) + + fmulx %fp3,%fp1 | ...S(Q1+S(Q2+S(Q3+SQ4))) + + + faddx %fp2,%fp0 | ...R+RS(P1+S(P2+SP3)) + + + fadds #0x3F800000,%fp1 | ...1+S(Q1+...) + + fmovel %d1,%fpcr |restore users exceptions + fdivx %fp1,%fp0 |last inst - possible exception set + + bra t_frcinx + +NODD: + fmovex %fp0,%fp1 + fmulx %fp0,%fp0 | ...S = R*R + + fmoved TANQ4,%fp3 + fmoved TANP3,%fp2 + + fmulx %fp0,%fp3 | ...SQ4 + fmulx %fp0,%fp2 | ...SP3 + + faddd TANQ3,%fp3 | ...Q3+SQ4 + faddx TANP2,%fp2 | ...P2+SP3 + + fmulx %fp0,%fp3 | ...S(Q3+SQ4) + fmulx %fp0,%fp2 | ...S(P2+SP3) + + faddx TANQ2,%fp3 | ...Q2+S(Q3+SQ4) + faddx TANP1,%fp2 | ...P1+S(P2+SP3) + + fmulx %fp0,%fp3 | ...S(Q2+S(Q3+SQ4)) + fmulx %fp0,%fp2 | ...S(P1+S(P2+SP3)) + + faddx TANQ1,%fp3 | ...Q1+S(Q2+S(Q3+SQ4)) + fmulx %fp1,%fp2 | ...RS(P1+S(P2+SP3)) + + fmulx %fp3,%fp0 | ...S(Q1+S(Q2+S(Q3+SQ4))) + + + faddx %fp2,%fp1 | ...R+RS(P1+S(P2+SP3)) + fadds #0x3F800000,%fp0 | ...1+S(Q1+...) + + + fmovex %fp1,-(%sp) + eoril #0x80000000,(%sp) + + fmovel %d1,%fpcr |restore users exceptions + fdivx (%sp)+,%fp0 |last inst - possible exception set + + bra t_frcinx + +TANBORS: +|--IF |X| > 15PI, WE USE THE GENERAL ARGUMENT REDUCTION. +|--IF |X| < 2**(-40), RETURN X OR 1. + cmpil #0x3FFF8000,%d0 + bgts REDUCEX + +TANSM: + + fmovex %fp0,-(%sp) + fmovel %d1,%fpcr |restore users exceptions + fmovex (%sp)+,%fp0 |last inst - posibble exception set + + bra t_frcinx + + +REDUCEX: +|--WHEN REDUCEX IS USED, THE CODE WILL INEVITABLY BE SLOW. +|--THIS REDUCTION METHOD, HOWEVER, IS MUCH FASTER THAN USING +|--THE REMAINDER INSTRUCTION WHICH IS NOW IN SOFTWARE. + + fmovemx %fp2-%fp5,-(%a7) | ...save FP2 through FP5 + movel %d2,-(%a7) + fmoves #0x00000000,%fp1 + +|--If compact form of abs(arg) in d0=$7ffeffff, argument is so large that +|--there is a danger of unwanted overflow in first LOOP iteration. In this +|--case, reduce argument by one remainder step to make subsequent reduction +|--safe. + cmpil #0x7ffeffff,%d0 |is argument dangerously large? + bnes LOOP + movel #0x7ffe0000,FP_SCR2(%a6) |yes +| ;create 2**16383*PI/2 + movel #0xc90fdaa2,FP_SCR2+4(%a6) + clrl FP_SCR2+8(%a6) + ftstx %fp0 |test sign of argument + movel #0x7fdc0000,FP_SCR3(%a6) |create low half of 2**16383* +| ;PI/2 at FP_SCR3 + movel #0x85a308d3,FP_SCR3+4(%a6) + clrl FP_SCR3+8(%a6) + fblt red_neg + orw #0x8000,FP_SCR2(%a6) |positive arg + orw #0x8000,FP_SCR3(%a6) +red_neg: + faddx FP_SCR2(%a6),%fp0 |high part of reduction is exact + fmovex %fp0,%fp1 |save high result in fp1 + faddx FP_SCR3(%a6),%fp0 |low part of reduction + fsubx %fp0,%fp1 |determine low component of result + faddx FP_SCR3(%a6),%fp1 |fp0/fp1 are reduced argument. + +|--ON ENTRY, FP0 IS X, ON RETURN, FP0 IS X REM PI/2, |X| <= PI/4. +|--integer quotient will be stored in N +|--Intermeditate remainder is 66-bit long; (R,r) in (FP0,FP1) + +LOOP: + fmovex %fp0,INARG(%a6) | ...+-2**K * F, 1 <= F < 2 + movew INARG(%a6),%d0 + movel %d0,%a1 | ...save a copy of D0 + andil #0x00007FFF,%d0 + subil #0x00003FFF,%d0 | ...D0 IS K + cmpil #28,%d0 + bles LASTLOOP +CONTLOOP: + subil #27,%d0 | ...D0 IS L := K-27 + movel #0,ENDFLAG(%a6) + bras WORK +LASTLOOP: + clrl %d0 | ...D0 IS L := 0 + movel #1,ENDFLAG(%a6) + +WORK: +|--FIND THE REMAINDER OF (R,r) W.R.T. 2**L * (PI/2). L IS SO CHOSEN +|--THAT INT( X * (2/PI) / 2**(L) ) < 2**29. + +|--CREATE 2**(-L) * (2/PI), SIGN(INARG)*2**(63), +|--2**L * (PIby2_1), 2**L * (PIby2_2) + + movel #0x00003FFE,%d2 | ...BIASED EXPO OF 2/PI + subl %d0,%d2 | ...BIASED EXPO OF 2**(-L)*(2/PI) + + movel #0xA2F9836E,FP_SCR1+4(%a6) + movel #0x4E44152A,FP_SCR1+8(%a6) + movew %d2,FP_SCR1(%a6) | ...FP_SCR1 is 2**(-L)*(2/PI) + + fmovex %fp0,%fp2 + fmulx FP_SCR1(%a6),%fp2 +|--WE MUST NOW FIND INT(FP2). SINCE WE NEED THIS VALUE IN +|--FLOATING POINT FORMAT, THE TWO FMOVE'S FMOVE.L FP <--> N +|--WILL BE TOO INEFFICIENT. THE WAY AROUND IT IS THAT +|--(SIGN(INARG)*2**63 + FP2) - SIGN(INARG)*2**63 WILL GIVE +|--US THE DESIRED VALUE IN FLOATING POINT. + +|--HIDE SIX CYCLES OF INSTRUCTION + movel %a1,%d2 + swap %d2 + andil #0x80000000,%d2 + oril #0x5F000000,%d2 | ...D2 IS SIGN(INARG)*2**63 IN SGL + movel %d2,TWOTO63(%a6) + + movel %d0,%d2 + addil #0x00003FFF,%d2 | ...BIASED EXPO OF 2**L * (PI/2) + +|--FP2 IS READY + fadds TWOTO63(%a6),%fp2 | ...THE FRACTIONAL PART OF FP1 IS ROUNDED + +|--HIDE 4 CYCLES OF INSTRUCTION; creating 2**(L)*Piby2_1 and 2**(L)*Piby2_2 + movew %d2,FP_SCR2(%a6) + clrw FP_SCR2+2(%a6) + movel #0xC90FDAA2,FP_SCR2+4(%a6) + clrl FP_SCR2+8(%a6) | ...FP_SCR2 is 2**(L) * Piby2_1 + +|--FP2 IS READY + fsubs TWOTO63(%a6),%fp2 | ...FP2 is N + + addil #0x00003FDD,%d0 + movew %d0,FP_SCR3(%a6) + clrw FP_SCR3+2(%a6) + movel #0x85A308D3,FP_SCR3+4(%a6) + clrl FP_SCR3+8(%a6) | ...FP_SCR3 is 2**(L) * Piby2_2 + + movel ENDFLAG(%a6),%d0 + +|--We are now ready to perform (R+r) - N*P1 - N*P2, P1 = 2**(L) * Piby2_1 and +|--P2 = 2**(L) * Piby2_2 + fmovex %fp2,%fp4 + fmulx FP_SCR2(%a6),%fp4 | ...W = N*P1 + fmovex %fp2,%fp5 + fmulx FP_SCR3(%a6),%fp5 | ...w = N*P2 + fmovex %fp4,%fp3 +|--we want P+p = W+w but |p| <= half ulp of P +|--Then, we need to compute A := R-P and a := r-p + faddx %fp5,%fp3 | ...FP3 is P + fsubx %fp3,%fp4 | ...W-P + + fsubx %fp3,%fp0 | ...FP0 is A := R - P + faddx %fp5,%fp4 | ...FP4 is p = (W-P)+w + + fmovex %fp0,%fp3 | ...FP3 A + fsubx %fp4,%fp1 | ...FP1 is a := r - p + +|--Now we need to normalize (A,a) to "new (R,r)" where R+r = A+a but +|--|r| <= half ulp of R. + faddx %fp1,%fp0 | ...FP0 is R := A+a +|--No need to calculate r if this is the last loop + cmpil #0,%d0 + bgt RESTORE + +|--Need to calculate r + fsubx %fp0,%fp3 | ...A-R + faddx %fp3,%fp1 | ...FP1 is r := (A-R)+a + bra LOOP + +RESTORE: + fmovel %fp2,N(%a6) + movel (%a7)+,%d2 + fmovemx (%a7)+,%fp2-%fp5 + + + movel N(%a6),%d0 + rorl #1,%d0 + + + bra TANCONT + + |end diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/stanh.S linux/arch/m68k/fpsp040/stanh.S --- v1.3.93/linux/arch/m68k/fpsp040/stanh.S Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/fpsp040/stanh.S Sat Feb 24 22:58:44 1996 @@ -0,0 +1,185 @@ +| +| stanh.sa 3.1 12/10/90 +| +| The entry point sTanh computes the hyperbolic tangent of +| an input argument; sTanhd does the same except for denormalized +| input. +| +| Input: Double-extended number X in location pointed to +| by address register a0. +| +| Output: The value tanh(X) returned in floating-point register Fp0. +| +| Accuracy and Monotonicity: The returned result is within 3 ulps in +| 64 significant bit, i.e. within 0.5001 ulp to 53 bits if the +| result is subsequently rounded to double precision. The +| result is provably monotonic in double precision. +| +| Speed: The program stanh takes approximately 270 cycles. +| +| Algorithm: +| +| TANH +| 1. If |X| >= (5/2) log2 or |X| <= 2**(-40), go to 3. +| +| 2. (2**(-40) < |X| < (5/2) log2) Calculate tanh(X) by +| sgn := sign(X), y := 2|X|, z := expm1(Y), and +| tanh(X) = sgn*( z/(2+z) ). +| Exit. +| +| 3. (|X| <= 2**(-40) or |X| >= (5/2) log2). If |X| < 1, +| go to 7. +| +| 4. (|X| >= (5/2) log2) If |X| >= 50 log2, go to 6. +| +| 5. ((5/2) log2 <= |X| < 50 log2) Calculate tanh(X) by +| sgn := sign(X), y := 2|X|, z := exp(Y), +| tanh(X) = sgn - [ sgn*2/(1+z) ]. +| Exit. +| +| 6. (|X| >= 50 log2) Tanh(X) = +-1 (round to nearest). Thus, we +| calculate Tanh(X) by +| sgn := sign(X), Tiny := 2**(-126), +| tanh(X) := sgn - sgn*Tiny. +| Exit. +| +| 7. (|X| < 2**(-40)). Tanh(X) = X. Exit. +| + +| Copyright (C) Motorola, Inc. 1990 +| All Rights Reserved +| +| THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA +| The copyright notice above does not evidence any +| actual or intended publication of such source code. + +|STANH idnt 2,1 | Motorola 040 Floating Point Software Package + + |section 8 + + .include "fpsp.h" + + .set X,FP_SCR5 + .set XDCARE,X+2 + .set XFRAC,X+4 + + .set SGN,L_SCR3 + + .set V,FP_SCR6 + +BOUNDS1: .long 0x3FD78000,0x3FFFDDCE | ... 2^(-40), (5/2)LOG2 + + |xref t_frcinx + |xref t_extdnrm + |xref setox + |xref setoxm1 + + .global stanhd +stanhd: +|--TANH(X) = X FOR DENORMALIZED X + + bra t_extdnrm + + .global stanh +stanh: + fmovex (%a0),%fp0 | ...LOAD INPUT + + fmovex %fp0,X(%a6) + movel (%a0),%d0 + movew 4(%a0),%d0 + movel %d0,X(%a6) + andl #0x7FFFFFFF,%d0 + cmp2l BOUNDS1(%pc),%d0 | ...2**(-40) < |X| < (5/2)LOG2 ? + bcss TANHBORS + +|--THIS IS THE USUAL CASE +|--Y = 2|X|, Z = EXPM1(Y), TANH(X) = SIGN(X) * Z / (Z+2). + + movel X(%a6),%d0 + movel %d0,SGN(%a6) + andl #0x7FFF0000,%d0 + addl #0x00010000,%d0 | ...EXPONENT OF 2|X| + movel %d0,X(%a6) + andl #0x80000000,SGN(%a6) + fmovex X(%a6),%fp0 | ...FP0 IS Y = 2|X| + + movel %d1,-(%a7) + clrl %d1 + fmovemx %fp0-%fp0,(%a0) + bsr setoxm1 | ...FP0 IS Z = EXPM1(Y) + movel (%a7)+,%d1 + + fmovex %fp0,%fp1 + fadds #0x40000000,%fp1 | ...Z+2 + movel SGN(%a6),%d0 + fmovex %fp1,V(%a6) + eorl %d0,V(%a6) + + fmovel %d1,%FPCR |restore users exceptions + fdivx V(%a6),%fp0 + bra t_frcinx + +TANHBORS: + cmpl #0x3FFF8000,%d0 + blt TANHSM + + cmpl #0x40048AA1,%d0 + bgt TANHHUGE + +|-- (5/2) LOG2 < |X| < 50 LOG2, +|--TANH(X) = 1 - (2/[EXP(2X)+1]). LET Y = 2|X|, SGN = SIGN(X), +|--TANH(X) = SGN - SGN*2/[EXP(Y)+1]. + + movel X(%a6),%d0 + movel %d0,SGN(%a6) + andl #0x7FFF0000,%d0 + addl #0x00010000,%d0 | ...EXPO OF 2|X| + movel %d0,X(%a6) | ...Y = 2|X| + andl #0x80000000,SGN(%a6) + movel SGN(%a6),%d0 + fmovex X(%a6),%fp0 | ...Y = 2|X| + + movel %d1,-(%a7) + clrl %d1 + fmovemx %fp0-%fp0,(%a0) + bsr setox | ...FP0 IS EXP(Y) + movel (%a7)+,%d1 + movel SGN(%a6),%d0 + fadds #0x3F800000,%fp0 | ...EXP(Y)+1 + + eorl #0xC0000000,%d0 | ...-SIGN(X)*2 + fmoves %d0,%fp1 | ...-SIGN(X)*2 IN SGL FMT + fdivx %fp0,%fp1 | ...-SIGN(X)2 / [EXP(Y)+1 ] + + movel SGN(%a6),%d0 + orl #0x3F800000,%d0 | ...SGN + fmoves %d0,%fp0 | ...SGN IN SGL FMT + + fmovel %d1,%FPCR |restore users exceptions + faddx %fp1,%fp0 + + bra t_frcinx + +TANHSM: + movew #0x0000,XDCARE(%a6) + + fmovel %d1,%FPCR |restore users exceptions + fmovex X(%a6),%fp0 |last inst - possible exception set + + bra t_frcinx + +TANHHUGE: +|---RETURN SGN(X) - SGN(X)EPS + movel X(%a6),%d0 + andl #0x80000000,%d0 + orl #0x3F800000,%d0 + fmoves %d0,%fp0 + andl #0x80000000,%d0 + eorl #0x80800000,%d0 | ...-SIGN(X)*EPS + + fmovel %d1,%FPCR |restore users exceptions + fadds %d0,%fp0 + + bra t_frcinx + + |end diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/sto_res.S linux/arch/m68k/fpsp040/sto_res.S --- v1.3.93/linux/arch/m68k/fpsp040/sto_res.S Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/fpsp040/sto_res.S Sat Feb 24 22:58:44 1996 @@ -0,0 +1,98 @@ +| +| sto_res.sa 3.1 12/10/90 +| +| Takes the result and puts it in where the user expects it. +| Library functions return result in fp0. If fp0 is not the +| users destination register then fp0 is moved to the the +| correct floating-point destination register. fp0 and fp1 +| are then restored to the original contents. +| +| Input: result in fp0,fp1 +| +| d2 & a0 should be kept unmodified +| +| Output: moves the result to the true destination reg or mem +| +| Modifies: destination floating point register +| + +| Copyright (C) Motorola, Inc. 1990 +| All Rights Reserved +| +| THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA +| The copyright notice above does not evidence any +| actual or intended publication of such source code. + +STO_RES: |idnt 2,1 | Motorola 040 Floating Point Software Package + + + |section 8 + + .include "fpsp.h" + + .global sto_cos +sto_cos: + bfextu CMDREG1B(%a6){#13:#3},%d0 |extract cos destination + cmpib #3,%d0 |check for fp0/fp1 cases + bles c_fp0123 + fmovemx %fp1-%fp1,-(%a7) + moveql #7,%d1 + subl %d0,%d1 |d1 = 7- (dest. reg. no.) + clrl %d0 + bsetl %d1,%d0 |d0 is dynamic register mask + fmovemx (%a7)+,%d0 + rts +c_fp0123: + cmpib #0,%d0 + beqs c_is_fp0 + cmpib #1,%d0 + beqs c_is_fp1 + cmpib #2,%d0 + beqs c_is_fp2 +c_is_fp3: + fmovemx %fp1-%fp1,USER_FP3(%a6) + rts +c_is_fp2: + fmovemx %fp1-%fp1,USER_FP2(%a6) + rts +c_is_fp1: + fmovemx %fp1-%fp1,USER_FP1(%a6) + rts +c_is_fp0: + fmovemx %fp1-%fp1,USER_FP0(%a6) + rts + + + .global sto_res +sto_res: + bfextu CMDREG1B(%a6){#6:#3},%d0 |extract destination register + cmpib #3,%d0 |check for fp0/fp1 cases + bles fp0123 + fmovemx %fp0-%fp0,-(%a7) + moveql #7,%d1 + subl %d0,%d1 |d1 = 7- (dest. reg. no.) + clrl %d0 + bsetl %d1,%d0 |d0 is dynamic register mask + fmovemx (%a7)+,%d0 + rts +fp0123: + cmpib #0,%d0 + beqs is_fp0 + cmpib #1,%d0 + beqs is_fp1 + cmpib #2,%d0 + beqs is_fp2 +is_fp3: + fmovemx %fp0-%fp0,USER_FP3(%a6) + rts +is_fp2: + fmovemx %fp0-%fp0,USER_FP2(%a6) + rts +is_fp1: + fmovemx %fp0-%fp0,USER_FP1(%a6) + rts +is_fp0: + fmovemx %fp0-%fp0,USER_FP0(%a6) + rts + + |end diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/stwotox.S linux/arch/m68k/fpsp040/stwotox.S --- v1.3.93/linux/arch/m68k/fpsp040/stwotox.S Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/fpsp040/stwotox.S Sat Feb 24 22:58:44 1996 @@ -0,0 +1,427 @@ +| +| stwotox.sa 3.1 12/10/90 +| +| stwotox --- 2**X +| stwotoxd --- 2**X for denormalized X +| stentox --- 10**X +| stentoxd --- 10**X for denormalized X +| +| Input: Double-extended number X in location pointed to +| by address register a0. +| +| Output: The function values are returned in Fp0. +| +| Accuracy and Monotonicity: The returned result is within 2 ulps in +| 64 significant bit, i.e. within 0.5001 ulp to 53 bits if the +| result is subsequently rounded to double precision. The +| result is provably monotonic in double precision. +| +| Speed: The program stwotox takes approximately 190 cycles and the +| program stentox takes approximately 200 cycles. +| +| Algorithm: +| +| twotox +| 1. If |X| > 16480, go to ExpBig. +| +| 2. If |X| < 2**(-70), go to ExpSm. +| +| 3. Decompose X as X = N/64 + r where |r| <= 1/128. Furthermore +| decompose N as +| N = 64(M + M') + j, j = 0,1,2,...,63. +| +| 4. Overwrite r := r * log2. Then +| 2**X = 2**(M') * 2**(M) * 2**(j/64) * exp(r). +| Go to expr to compute that expression. +| +| tentox +| 1. If |X| > 16480*log_10(2) (base 10 log of 2), go to ExpBig. +| +| 2. If |X| < 2**(-70), go to ExpSm. +| +| 3. Set y := X*log_2(10)*64 (base 2 log of 10). Set +| N := round-to-int(y). Decompose N as +| N = 64(M + M') + j, j = 0,1,2,...,63. +| +| 4. Define r as +| r := ((X - N*L1)-N*L2) * L10 +| where L1, L2 are the leading and trailing parts of log_10(2)/64 +| and L10 is the natural log of 10. Then +| 10**X = 2**(M') * 2**(M) * 2**(j/64) * exp(r). +| Go to expr to compute that expression. +| +| expr +| 1. Fetch 2**(j/64) from table as Fact1 and Fact2. +| +| 2. Overwrite Fact1 and Fact2 by +| Fact1 := 2**(M) * Fact1 +| Fact2 := 2**(M) * Fact2 +| Thus Fact1 + Fact2 = 2**(M) * 2**(j/64). +| +| 3. Calculate P where 1 + P approximates exp(r): +| P = r + r*r*(A1+r*(A2+...+r*A5)). +| +| 4. Let AdjFact := 2**(M'). Return +| AdjFact * ( Fact1 + ((Fact1*P) + Fact2) ). +| Exit. +| +| ExpBig +| 1. Generate overflow by Huge * Huge if X > 0; otherwise, generate +| underflow by Tiny * Tiny. +| +| ExpSm +| 1. Return 1 + X. +| + +| Copyright (C) Motorola, Inc. 1990 +| All Rights Reserved +| +| THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA +| The copyright notice above does not evidence any +| actual or intended publication of such source code. + +|STWOTOX idnt 2,1 | Motorola 040 Floating Point Software Package + + |section 8 + + .include "fpsp.h" + +BOUNDS1: .long 0x3FB98000,0x400D80C0 | ... 2^(-70),16480 +BOUNDS2: .long 0x3FB98000,0x400B9B07 | ... 2^(-70),16480 LOG2/LOG10 + +L2TEN64: .long 0x406A934F,0x0979A371 | ... 64LOG10/LOG2 +L10TWO1: .long 0x3F734413,0x509F8000 | ... LOG2/64LOG10 + +L10TWO2: .long 0xBFCD0000,0xC0219DC1,0xDA994FD2,0x00000000 + +LOG10: .long 0x40000000,0x935D8DDD,0xAAA8AC17,0x00000000 + +LOG2: .long 0x3FFE0000,0xB17217F7,0xD1CF79AC,0x00000000 + +EXPA5: .long 0x3F56C16D,0x6F7BD0B2 +EXPA4: .long 0x3F811112,0x302C712C +EXPA3: .long 0x3FA55555,0x55554CC1 +EXPA2: .long 0x3FC55555,0x55554A54 +EXPA1: .long 0x3FE00000,0x00000000,0x00000000,0x00000000 + +HUGE: .long 0x7FFE0000,0xFFFFFFFF,0xFFFFFFFF,0x00000000 +TINY: .long 0x00010000,0xFFFFFFFF,0xFFFFFFFF,0x00000000 + +EXPTBL: + .long 0x3FFF0000,0x80000000,0x00000000,0x3F738000 + .long 0x3FFF0000,0x8164D1F3,0xBC030773,0x3FBEF7CA + .long 0x3FFF0000,0x82CD8698,0xAC2BA1D7,0x3FBDF8A9 + .long 0x3FFF0000,0x843A28C3,0xACDE4046,0x3FBCD7C9 + .long 0x3FFF0000,0x85AAC367,0xCC487B15,0xBFBDE8DA + .long 0x3FFF0000,0x871F6196,0x9E8D1010,0x3FBDE85C + .long 0x3FFF0000,0x88980E80,0x92DA8527,0x3FBEBBF1 + .long 0x3FFF0000,0x8A14D575,0x496EFD9A,0x3FBB80CA + .long 0x3FFF0000,0x8B95C1E3,0xEA8BD6E7,0xBFBA8373 + .long 0x3FFF0000,0x8D1ADF5B,0x7E5BA9E6,0xBFBE9670 + .long 0x3FFF0000,0x8EA4398B,0x45CD53C0,0x3FBDB700 + .long 0x3FFF0000,0x9031DC43,0x1466B1DC,0x3FBEEEB0 + .long 0x3FFF0000,0x91C3D373,0xAB11C336,0x3FBBFD6D + .long 0x3FFF0000,0x935A2B2F,0x13E6E92C,0xBFBDB319 + .long 0x3FFF0000,0x94F4EFA8,0xFEF70961,0x3FBDBA2B + .long 0x3FFF0000,0x96942D37,0x20185A00,0x3FBE91D5 + .long 0x3FFF0000,0x9837F051,0x8DB8A96F,0x3FBE8D5A + .long 0x3FFF0000,0x99E04593,0x20B7FA65,0xBFBCDE7B + .long 0x3FFF0000,0x9B8D39B9,0xD54E5539,0xBFBEBAAF + .long 0x3FFF0000,0x9D3ED9A7,0x2CFFB751,0xBFBD86DA + .long 0x3FFF0000,0x9EF53260,0x91A111AE,0xBFBEBEDD + .long 0x3FFF0000,0xA0B0510F,0xB9714FC2,0x3FBCC96E + .long 0x3FFF0000,0xA2704303,0x0C496819,0xBFBEC90B + .long 0x3FFF0000,0xA43515AE,0x09E6809E,0x3FBBD1DB + .long 0x3FFF0000,0xA5FED6A9,0xB15138EA,0x3FBCE5EB + .long 0x3FFF0000,0xA7CD93B4,0xE965356A,0xBFBEC274 + .long 0x3FFF0000,0xA9A15AB4,0xEA7C0EF8,0x3FBEA83C + .long 0x3FFF0000,0xAB7A39B5,0xA93ED337,0x3FBECB00 + .long 0x3FFF0000,0xAD583EEA,0x42A14AC6,0x3FBE9301 + .long 0x3FFF0000,0xAF3B78AD,0x690A4375,0xBFBD8367 + .long 0x3FFF0000,0xB123F581,0xD2AC2590,0xBFBEF05F + .long 0x3FFF0000,0xB311C412,0xA9112489,0x3FBDFB3C + .long 0x3FFF0000,0xB504F333,0xF9DE6484,0x3FBEB2FB + .long 0x3FFF0000,0xB6FD91E3,0x28D17791,0x3FBAE2CB + .long 0x3FFF0000,0xB8FBAF47,0x62FB9EE9,0x3FBCDC3C + .long 0x3FFF0000,0xBAFF5AB2,0x133E45FB,0x3FBEE9AA + .long 0x3FFF0000,0xBD08A39F,0x580C36BF,0xBFBEAEFD + .long 0x3FFF0000,0xBF1799B6,0x7A731083,0xBFBCBF51 + .long 0x3FFF0000,0xC12C4CCA,0x66709456,0x3FBEF88A + .long 0x3FFF0000,0xC346CCDA,0x24976407,0x3FBD83B2 + .long 0x3FFF0000,0xC5672A11,0x5506DADD,0x3FBDF8AB + .long 0x3FFF0000,0xC78D74C8,0xABB9B15D,0xBFBDFB17 + .long 0x3FFF0000,0xC9B9BD86,0x6E2F27A3,0xBFBEFE3C + .long 0x3FFF0000,0xCBEC14FE,0xF2727C5D,0xBFBBB6F8 + .long 0x3FFF0000,0xCE248C15,0x1F8480E4,0xBFBCEE53 + .long 0x3FFF0000,0xD06333DA,0xEF2B2595,0xBFBDA4AE + .long 0x3FFF0000,0xD2A81D91,0xF12AE45A,0x3FBC9124 + .long 0x3FFF0000,0xD4F35AAB,0xCFEDFA1F,0x3FBEB243 + .long 0x3FFF0000,0xD744FCCA,0xD69D6AF4,0x3FBDE69A + .long 0x3FFF0000,0xD99D15C2,0x78AFD7B6,0xBFB8BC61 + .long 0x3FFF0000,0xDBFBB797,0xDAF23755,0x3FBDF610 + .long 0x3FFF0000,0xDE60F482,0x5E0E9124,0xBFBD8BE1 + .long 0x3FFF0000,0xE0CCDEEC,0x2A94E111,0x3FBACB12 + .long 0x3FFF0000,0xE33F8972,0xBE8A5A51,0x3FBB9BFE + .long 0x3FFF0000,0xE5B906E7,0x7C8348A8,0x3FBCF2F4 + .long 0x3FFF0000,0xE8396A50,0x3C4BDC68,0x3FBEF22F + .long 0x3FFF0000,0xEAC0C6E7,0xDD24392F,0xBFBDBF4A + .long 0x3FFF0000,0xED4F301E,0xD9942B84,0x3FBEC01A + .long 0x3FFF0000,0xEFE4B99B,0xDCDAF5CB,0x3FBE8CAC + .long 0x3FFF0000,0xF281773C,0x59FFB13A,0xBFBCBB3F + .long 0x3FFF0000,0xF5257D15,0x2486CC2C,0x3FBEF73A + .long 0x3FFF0000,0xF7D0DF73,0x0AD13BB9,0xBFB8B795 + .long 0x3FFF0000,0xFA83B2DB,0x722A033A,0x3FBEF84B + .long 0x3FFF0000,0xFD3E0C0C,0xF486C175,0xBFBEF581 + + .set N,L_SCR1 + + .set X,FP_SCR1 + .set XDCARE,X+2 + .set XFRAC,X+4 + + .set ADJFACT,FP_SCR2 + + .set FACT1,FP_SCR3 + .set FACT1HI,FACT1+4 + .set FACT1LOW,FACT1+8 + + .set FACT2,FP_SCR4 + .set FACT2HI,FACT2+4 + .set FACT2LOW,FACT2+8 + + | xref t_unfl + |xref t_ovfl + |xref t_frcinx + + .global stwotoxd +stwotoxd: +|--ENTRY POINT FOR 2**(X) FOR DENORMALIZED ARGUMENT + + fmovel %d1,%fpcr | ...set user's rounding mode/precision + fmoves #0x3F800000,%fp0 | ...RETURN 1 + X + movel (%a0),%d0 + orl #0x00800001,%d0 + fadds %d0,%fp0 + bra t_frcinx + + .global stwotox +stwotox: +|--ENTRY POINT FOR 2**(X), HERE X IS FINITE, NON-ZERO, AND NOT NAN'S + fmovemx (%a0),%fp0-%fp0 | ...LOAD INPUT, do not set cc's + + movel (%a0),%d0 + movew 4(%a0),%d0 + fmovex %fp0,X(%a6) + andil #0x7FFFFFFF,%d0 + + cmpil #0x3FB98000,%d0 | ...|X| >= 2**(-70)? + bges TWOOK1 + bra EXPBORS + +TWOOK1: + cmpil #0x400D80C0,%d0 | ...|X| > 16480? + bles TWOMAIN + bra EXPBORS + + +TWOMAIN: +|--USUAL CASE, 2^(-70) <= |X| <= 16480 + + fmovex %fp0,%fp1 + fmuls #0x42800000,%fp1 | ...64 * X + + fmovel %fp1,N(%a6) | ...N = ROUND-TO-INT(64 X) + movel %d2,-(%sp) + lea EXPTBL,%a1 | ...LOAD ADDRESS OF TABLE OF 2^(J/64) + fmovel N(%a6),%fp1 | ...N --> FLOATING FMT + movel N(%a6),%d0 + movel %d0,%d2 + andil #0x3F,%d0 | ...D0 IS J + asll #4,%d0 | ...DISPLACEMENT FOR 2^(J/64) + addal %d0,%a1 | ...ADDRESS FOR 2^(J/64) + asrl #6,%d2 | ...d2 IS L, N = 64L + J + movel %d2,%d0 + asrl #1,%d0 | ...D0 IS M + subl %d0,%d2 | ...d2 IS M', N = 64(M+M') + J + addil #0x3FFF,%d2 + movew %d2,ADJFACT(%a6) | ...ADJFACT IS 2^(M') + movel (%sp)+,%d2 +|--SUMMARY: a1 IS ADDRESS FOR THE LEADING PORTION OF 2^(J/64), +|--D0 IS M WHERE N = 64(M+M') + J. NOTE THAT |M| <= 16140 BY DESIGN. +|--ADJFACT = 2^(M'). +|--REGISTERS SAVED SO FAR ARE (IN ORDER) FPCR, D0, FP1, a1, AND FP2. + + fmuls #0x3C800000,%fp1 | ...(1/64)*N + movel (%a1)+,FACT1(%a6) + movel (%a1)+,FACT1HI(%a6) + movel (%a1)+,FACT1LOW(%a6) + movew (%a1)+,FACT2(%a6) + clrw FACT2+2(%a6) + + fsubx %fp1,%fp0 | ...X - (1/64)*INT(64 X) + + movew (%a1)+,FACT2HI(%a6) + clrw FACT2HI+2(%a6) + clrl FACT2LOW(%a6) + addw %d0,FACT1(%a6) + + fmulx LOG2,%fp0 | ...FP0 IS R + addw %d0,FACT2(%a6) + + bra expr + +EXPBORS: +|--FPCR, D0 SAVED + cmpil #0x3FFF8000,%d0 + bgts EXPBIG + +EXPSM: +|--|X| IS SMALL, RETURN 1 + X + + fmovel %d1,%FPCR |restore users exceptions + fadds #0x3F800000,%fp0 | ...RETURN 1 + X + + bra t_frcinx + +EXPBIG: +|--|X| IS LARGE, GENERATE OVERFLOW IF X > 0; ELSE GENERATE UNDERFLOW +|--REGISTERS SAVE SO FAR ARE FPCR AND D0 + movel X(%a6),%d0 + cmpil #0,%d0 + blts EXPNEG + + bclrb #7,(%a0) |t_ovfl expects positive value + bra t_ovfl + +EXPNEG: + bclrb #7,(%a0) |t_unfl expects positive value + bra t_unfl + + .global stentoxd +stentoxd: +|--ENTRY POINT FOR 10**(X) FOR DENORMALIZED ARGUMENT + + fmovel %d1,%fpcr | ...set user's rounding mode/precision + fmoves #0x3F800000,%fp0 | ...RETURN 1 + X + movel (%a0),%d0 + orl #0x00800001,%d0 + fadds %d0,%fp0 + bra t_frcinx + + .global stentox +stentox: +|--ENTRY POINT FOR 10**(X), HERE X IS FINITE, NON-ZERO, AND NOT NAN'S + fmovemx (%a0),%fp0-%fp0 | ...LOAD INPUT, do not set cc's + + movel (%a0),%d0 + movew 4(%a0),%d0 + fmovex %fp0,X(%a6) + andil #0x7FFFFFFF,%d0 + + cmpil #0x3FB98000,%d0 | ...|X| >= 2**(-70)? + bges TENOK1 + bra EXPBORS + +TENOK1: + cmpil #0x400B9B07,%d0 | ...|X| <= 16480*log2/log10 ? + bles TENMAIN + bra EXPBORS + +TENMAIN: +|--USUAL CASE, 2^(-70) <= |X| <= 16480 LOG 2 / LOG 10 + + fmovex %fp0,%fp1 + fmuld L2TEN64,%fp1 | ...X*64*LOG10/LOG2 + + fmovel %fp1,N(%a6) | ...N=INT(X*64*LOG10/LOG2) + movel %d2,-(%sp) + lea EXPTBL,%a1 | ...LOAD ADDRESS OF TABLE OF 2^(J/64) + fmovel N(%a6),%fp1 | ...N --> FLOATING FMT + movel N(%a6),%d0 + movel %d0,%d2 + andil #0x3F,%d0 | ...D0 IS J + asll #4,%d0 | ...DISPLACEMENT FOR 2^(J/64) + addal %d0,%a1 | ...ADDRESS FOR 2^(J/64) + asrl #6,%d2 | ...d2 IS L, N = 64L + J + movel %d2,%d0 + asrl #1,%d0 | ...D0 IS M + subl %d0,%d2 | ...d2 IS M', N = 64(M+M') + J + addil #0x3FFF,%d2 + movew %d2,ADJFACT(%a6) | ...ADJFACT IS 2^(M') + movel (%sp)+,%d2 + +|--SUMMARY: a1 IS ADDRESS FOR THE LEADING PORTION OF 2^(J/64), +|--D0 IS M WHERE N = 64(M+M') + J. NOTE THAT |M| <= 16140 BY DESIGN. +|--ADJFACT = 2^(M'). +|--REGISTERS SAVED SO FAR ARE (IN ORDER) FPCR, D0, FP1, a1, AND FP2. + + fmovex %fp1,%fp2 + + fmuld L10TWO1,%fp1 | ...N*(LOG2/64LOG10)_LEAD + movel (%a1)+,FACT1(%a6) + + fmulx L10TWO2,%fp2 | ...N*(LOG2/64LOG10)_TRAIL + + movel (%a1)+,FACT1HI(%a6) + movel (%a1)+,FACT1LOW(%a6) + fsubx %fp1,%fp0 | ...X - N L_LEAD + movew (%a1)+,FACT2(%a6) + + fsubx %fp2,%fp0 | ...X - N L_TRAIL + + clrw FACT2+2(%a6) + movew (%a1)+,FACT2HI(%a6) + clrw FACT2HI+2(%a6) + clrl FACT2LOW(%a6) + + fmulx LOG10,%fp0 | ...FP0 IS R + + addw %d0,FACT1(%a6) + addw %d0,FACT2(%a6) + +expr: +|--FPCR, FP2, FP3 ARE SAVED IN ORDER AS SHOWN. +|--ADJFACT CONTAINS 2**(M'), FACT1 + FACT2 = 2**(M) * 2**(J/64). +|--FP0 IS R. THE FOLLOWING CODE COMPUTES +|-- 2**(M'+M) * 2**(J/64) * EXP(R) + + fmovex %fp0,%fp1 + fmulx %fp1,%fp1 | ...FP1 IS S = R*R + + fmoved EXPA5,%fp2 | ...FP2 IS A5 + fmoved EXPA4,%fp3 | ...FP3 IS A4 + + fmulx %fp1,%fp2 | ...FP2 IS S*A5 + fmulx %fp1,%fp3 | ...FP3 IS S*A4 + + faddd EXPA3,%fp2 | ...FP2 IS A3+S*A5 + faddd EXPA2,%fp3 | ...FP3 IS A2+S*A4 + + fmulx %fp1,%fp2 | ...FP2 IS S*(A3+S*A5) + fmulx %fp1,%fp3 | ...FP3 IS S*(A2+S*A4) + + faddd EXPA1,%fp2 | ...FP2 IS A1+S*(A3+S*A5) + fmulx %fp0,%fp3 | ...FP3 IS R*S*(A2+S*A4) + + fmulx %fp1,%fp2 | ...FP2 IS S*(A1+S*(A3+S*A5)) + faddx %fp3,%fp0 | ...FP0 IS R+R*S*(A2+S*A4) + + faddx %fp2,%fp0 | ...FP0 IS EXP(R) - 1 + + +|--FINAL RECONSTRUCTION PROCESS +|--EXP(X) = 2^M*2^(J/64) + 2^M*2^(J/64)*(EXP(R)-1) - (1 OR 0) + + fmulx FACT1(%a6),%fp0 + faddx FACT2(%a6),%fp0 + faddx FACT1(%a6),%fp0 + + fmovel %d1,%FPCR |restore users exceptions + clrw ADJFACT+2(%a6) + movel #0x80000000,ADJFACT+4(%a6) + clrl ADJFACT+8(%a6) + fmulx ADJFACT(%a6),%fp0 | ...FINAL ADJUSTMENT + + bra t_frcinx + + |end diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/tbldo.S linux/arch/m68k/fpsp040/tbldo.S --- v1.3.93/linux/arch/m68k/fpsp040/tbldo.S Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/fpsp040/tbldo.S Sat Feb 24 22:58:44 1996 @@ -0,0 +1,554 @@ +| +| tbldo.sa 3.1 12/10/90 +| +| Modified: +| 8/16/90 chinds The table was constructed to use only one level +| of indirection in do_func for monoadic +| functions. Dyadic functions require two +| levels, and the tables are still contained +| in do_func. The table is arranged for +| index with a 10-bit index, with the first +| 7 bits the opcode, and the remaining 3 +| the stag. For dyadic functions, all +| valid addresses are to the generic entry +| point. +| + +| Copyright (C) Motorola, Inc. 1990 +| All Rights Reserved +| +| THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA +| The copyright notice above does not evidence any +| actual or intended publication of such source code. + +|TBLDO idnt 2,1 | Motorola 040 Floating Point Software Package + + |section 8 + + |xref ld_pinf,ld_pone,ld_ppi2 + |xref t_dz2,t_operr + |xref serror,sone,szero,sinf,snzrinx + |xref sopr_inf,spi_2,src_nan,szr_inf + + |xref smovcr + |xref pmod,prem,pscale + |xref satanh,satanhd + |xref sacos,sacosd,sasin,sasind,satan,satand + |xref setox,setoxd,setoxm1,setoxm1d,setoxm1i + |xref sgetexp,sgetexpd,sgetman,sgetmand + |xref sint,sintd,sintrz + |xref ssincos,ssincosd,ssincosi,ssincosnan,ssincosz + |xref scos,scosd,ssin,ssind,stan,stand + |xref scosh,scoshd,ssinh,ssinhd,stanh,stanhd + |xref sslog10,sslog2,sslogn,sslognp1 + |xref sslog10d,sslog2d,sslognd,slognp1d + |xref stentox,stentoxd,stwotox,stwotoxd + +| instruction ;opcode-stag Notes + .global tblpre +tblpre: + .long smovcr |$00-0 fmovecr all + .long smovcr |$00-1 fmovecr all + .long smovcr |$00-2 fmovecr all + .long smovcr |$00-3 fmovecr all + .long smovcr |$00-4 fmovecr all + .long smovcr |$00-5 fmovecr all + .long smovcr |$00-6 fmovecr all + .long smovcr |$00-7 fmovecr all + + .long sint |$01-0 fint norm + .long szero |$01-1 fint zero + .long sinf |$01-2 fint inf + .long src_nan |$01-3 fint nan + .long sintd |$01-4 fint denorm inx + .long serror |$01-5 fint ERROR + .long serror |$01-6 fint ERROR + .long serror |$01-7 fint ERROR + + .long ssinh |$02-0 fsinh norm + .long szero |$02-1 fsinh zero + .long sinf |$02-2 fsinh inf + .long src_nan |$02-3 fsinh nan + .long ssinhd |$02-4 fsinh denorm + .long serror |$02-5 fsinh ERROR + .long serror |$02-6 fsinh ERROR + .long serror |$02-7 fsinh ERROR + + .long sintrz |$03-0 fintrz norm + .long szero |$03-1 fintrz zero + .long sinf |$03-2 fintrz inf + .long src_nan |$03-3 fintrz nan + .long snzrinx |$03-4 fintrz denorm inx + .long serror |$03-5 fintrz ERROR + .long serror |$03-6 fintrz ERROR + .long serror |$03-7 fintrz ERROR + + .long serror |$04-0 ERROR - illegal extension + .long serror |$04-1 ERROR - illegal extension + .long serror |$04-2 ERROR - illegal extension + .long serror |$04-3 ERROR - illegal extension + .long serror |$04-4 ERROR - illegal extension + .long serror |$04-5 ERROR - illegal extension + .long serror |$04-6 ERROR - illegal extension + .long serror |$04-7 ERROR - illegal extension + + .long serror |$05-0 ERROR - illegal extension + .long serror |$05-1 ERROR - illegal extension + .long serror |$05-2 ERROR - illegal extension + .long serror |$05-3 ERROR - illegal extension + .long serror |$05-4 ERROR - illegal extension + .long serror |$05-5 ERROR - illegal extension + .long serror |$05-6 ERROR - illegal extension + .long serror |$05-7 ERROR - illegal extension + + .long sslognp1 |$06-0 flognp1 norm + .long szero |$06-1 flognp1 zero + .long sopr_inf |$06-2 flognp1 inf + .long src_nan |$06-3 flognp1 nan + .long slognp1d |$06-4 flognp1 denorm + .long serror |$06-5 flognp1 ERROR + .long serror |$06-6 flognp1 ERROR + .long serror |$06-7 flognp1 ERROR + + .long serror |$07-0 ERROR - illegal extension + .long serror |$07-1 ERROR - illegal extension + .long serror |$07-2 ERROR - illegal extension + .long serror |$07-3 ERROR - illegal extension + .long serror |$07-4 ERROR - illegal extension + .long serror |$07-5 ERROR - illegal extension + .long serror |$07-6 ERROR - illegal extension + .long serror |$07-7 ERROR - illegal extension + + .long setoxm1 |$08-0 fetoxm1 norm + .long szero |$08-1 fetoxm1 zero + .long setoxm1i |$08-2 fetoxm1 inf + .long src_nan |$08-3 fetoxm1 nan + .long setoxm1d |$08-4 fetoxm1 denorm + .long serror |$08-5 fetoxm1 ERROR + .long serror |$08-6 fetoxm1 ERROR + .long serror |$08-7 fetoxm1 ERROR + + .long stanh |$09-0 ftanh norm + .long szero |$09-1 ftanh zero + .long sone |$09-2 ftanh inf + .long src_nan |$09-3 ftanh nan + .long stanhd |$09-4 ftanh denorm + .long serror |$09-5 ftanh ERROR + .long serror |$09-6 ftanh ERROR + .long serror |$09-7 ftanh ERROR + + .long satan |$0a-0 fatan norm + .long szero |$0a-1 fatan zero + .long spi_2 |$0a-2 fatan inf + .long src_nan |$0a-3 fatan nan + .long satand |$0a-4 fatan denorm + .long serror |$0a-5 fatan ERROR + .long serror |$0a-6 fatan ERROR + .long serror |$0a-7 fatan ERROR + + .long serror |$0b-0 ERROR - illegal extension + .long serror |$0b-1 ERROR - illegal extension + .long serror |$0b-2 ERROR - illegal extension + .long serror |$0b-3 ERROR - illegal extension + .long serror |$0b-4 ERROR - illegal extension + .long serror |$0b-5 ERROR - illegal extension + .long serror |$0b-6 ERROR - illegal extension + .long serror |$0b-7 ERROR - illegal extension + + .long sasin |$0c-0 fasin norm + .long szero |$0c-1 fasin zero + .long t_operr |$0c-2 fasin inf + .long src_nan |$0c-3 fasin nan + .long sasind |$0c-4 fasin denorm + .long serror |$0c-5 fasin ERROR + .long serror |$0c-6 fasin ERROR + .long serror |$0c-7 fasin ERROR + + .long satanh |$0d-0 fatanh norm + .long szero |$0d-1 fatanh zero + .long t_operr |$0d-2 fatanh inf + .long src_nan |$0d-3 fatanh nan + .long satanhd |$0d-4 fatanh denorm + .long serror |$0d-5 fatanh ERROR + .long serror |$0d-6 fatanh ERROR + .long serror |$0d-7 fatanh ERROR + + .long ssin |$0e-0 fsin norm + .long szero |$0e-1 fsin zero + .long t_operr |$0e-2 fsin inf + .long src_nan |$0e-3 fsin nan + .long ssind |$0e-4 fsin denorm + .long serror |$0e-5 fsin ERROR + .long serror |$0e-6 fsin ERROR + .long serror |$0e-7 fsin ERROR + + .long stan |$0f-0 ftan norm + .long szero |$0f-1 ftan zero + .long t_operr |$0f-2 ftan inf + .long src_nan |$0f-3 ftan nan + .long stand |$0f-4 ftan denorm + .long serror |$0f-5 ftan ERROR + .long serror |$0f-6 ftan ERROR + .long serror |$0f-7 ftan ERROR + + .long setox |$10-0 fetox norm + .long ld_pone |$10-1 fetox zero + .long szr_inf |$10-2 fetox inf + .long src_nan |$10-3 fetox nan + .long setoxd |$10-4 fetox denorm + .long serror |$10-5 fetox ERROR + .long serror |$10-6 fetox ERROR + .long serror |$10-7 fetox ERROR + + .long stwotox |$11-0 ftwotox norm + .long ld_pone |$11-1 ftwotox zero + .long szr_inf |$11-2 ftwotox inf + .long src_nan |$11-3 ftwotox nan + .long stwotoxd |$11-4 ftwotox denorm + .long serror |$11-5 ftwotox ERROR + .long serror |$11-6 ftwotox ERROR + .long serror |$11-7 ftwotox ERROR + + .long stentox |$12-0 ftentox norm + .long ld_pone |$12-1 ftentox zero + .long szr_inf |$12-2 ftentox inf + .long src_nan |$12-3 ftentox nan + .long stentoxd |$12-4 ftentox denorm + .long serror |$12-5 ftentox ERROR + .long serror |$12-6 ftentox ERROR + .long serror |$12-7 ftentox ERROR + + .long serror |$13-0 ERROR - illegal extension + .long serror |$13-1 ERROR - illegal extension + .long serror |$13-2 ERROR - illegal extension + .long serror |$13-3 ERROR - illegal extension + .long serror |$13-4 ERROR - illegal extension + .long serror |$13-5 ERROR - illegal extension + .long serror |$13-6 ERROR - illegal extension + .long serror |$13-7 ERROR - illegal extension + + .long sslogn |$14-0 flogn norm + .long t_dz2 |$14-1 flogn zero + .long sopr_inf |$14-2 flogn inf + .long src_nan |$14-3 flogn nan + .long sslognd |$14-4 flogn denorm + .long serror |$14-5 flogn ERROR + .long serror |$14-6 flogn ERROR + .long serror |$14-7 flogn ERROR + + .long sslog10 |$15-0 flog10 norm + .long t_dz2 |$15-1 flog10 zero + .long sopr_inf |$15-2 flog10 inf + .long src_nan |$15-3 flog10 nan + .long sslog10d |$15-4 flog10 denorm + .long serror |$15-5 flog10 ERROR + .long serror |$15-6 flog10 ERROR + .long serror |$15-7 flog10 ERROR + + .long sslog2 |$16-0 flog2 norm + .long t_dz2 |$16-1 flog2 zero + .long sopr_inf |$16-2 flog2 inf + .long src_nan |$16-3 flog2 nan + .long sslog2d |$16-4 flog2 denorm + .long serror |$16-5 flog2 ERROR + .long serror |$16-6 flog2 ERROR + .long serror |$16-7 flog2 ERROR + + .long serror |$17-0 ERROR - illegal extension + .long serror |$17-1 ERROR - illegal extension + .long serror |$17-2 ERROR - illegal extension + .long serror |$17-3 ERROR - illegal extension + .long serror |$17-4 ERROR - illegal extension + .long serror |$17-5 ERROR - illegal extension + .long serror |$17-6 ERROR - illegal extension + .long serror |$17-7 ERROR - illegal extension + + .long serror |$18-0 ERROR - illegal extension + .long serror |$18-1 ERROR - illegal extension + .long serror |$18-2 ERROR - illegal extension + .long serror |$18-3 ERROR - illegal extension + .long serror |$18-4 ERROR - illegal extension + .long serror |$18-5 ERROR - illegal extension + .long serror |$18-6 ERROR - illegal extension + .long serror |$18-7 ERROR - illegal extension + + .long scosh |$19-0 fcosh norm + .long ld_pone |$19-1 fcosh zero + .long ld_pinf |$19-2 fcosh inf + .long src_nan |$19-3 fcosh nan + .long scoshd |$19-4 fcosh denorm + .long serror |$19-5 fcosh ERROR + .long serror |$19-6 fcosh ERROR + .long serror |$19-7 fcosh ERROR + + .long serror |$1a-0 ERROR - illegal extension + .long serror |$1a-1 ERROR - illegal extension + .long serror |$1a-2 ERROR - illegal extension + .long serror |$1a-3 ERROR - illegal extension + .long serror |$1a-4 ERROR - illegal extension + .long serror |$1a-5 ERROR - illegal extension + .long serror |$1a-6 ERROR - illegal extension + .long serror |$1a-7 ERROR - illegal extension + + .long serror |$1b-0 ERROR - illegal extension + .long serror |$1b-1 ERROR - illegal extension + .long serror |$1b-2 ERROR - illegal extension + .long serror |$1b-3 ERROR - illegal extension + .long serror |$1b-4 ERROR - illegal extension + .long serror |$1b-5 ERROR - illegal extension + .long serror |$1b-6 ERROR - illegal extension + .long serror |$1b-7 ERROR - illegal extension + + .long sacos |$1c-0 facos norm + .long ld_ppi2 |$1c-1 facos zero + .long t_operr |$1c-2 facos inf + .long src_nan |$1c-3 facos nan + .long sacosd |$1c-4 facos denorm + .long serror |$1c-5 facos ERROR + .long serror |$1c-6 facos ERROR + .long serror |$1c-7 facos ERROR + + .long scos |$1d-0 fcos norm + .long ld_pone |$1d-1 fcos zero + .long t_operr |$1d-2 fcos inf + .long src_nan |$1d-3 fcos nan + .long scosd |$1d-4 fcos denorm + .long serror |$1d-5 fcos ERROR + .long serror |$1d-6 fcos ERROR + .long serror |$1d-7 fcos ERROR + + .long sgetexp |$1e-0 fgetexp norm + .long szero |$1e-1 fgetexp zero + .long t_operr |$1e-2 fgetexp inf + .long src_nan |$1e-3 fgetexp nan + .long sgetexpd |$1e-4 fgetexp denorm + .long serror |$1e-5 fgetexp ERROR + .long serror |$1e-6 fgetexp ERROR + .long serror |$1e-7 fgetexp ERROR + + .long sgetman |$1f-0 fgetman norm + .long szero |$1f-1 fgetman zero + .long t_operr |$1f-2 fgetman inf + .long src_nan |$1f-3 fgetman nan + .long sgetmand |$1f-4 fgetman denorm + .long serror |$1f-5 fgetman ERROR + .long serror |$1f-6 fgetman ERROR + .long serror |$1f-7 fgetman ERROR + + .long serror |$20-0 ERROR - illegal extension + .long serror |$20-1 ERROR - illegal extension + .long serror |$20-2 ERROR - illegal extension + .long serror |$20-3 ERROR - illegal extension + .long serror |$20-4 ERROR - illegal extension + .long serror |$20-5 ERROR - illegal extension + .long serror |$20-6 ERROR - illegal extension + .long serror |$20-7 ERROR - illegal extension + + .long pmod |$21-0 fmod all + .long pmod |$21-1 fmod all + .long pmod |$21-2 fmod all + .long pmod |$21-3 fmod all + .long pmod |$21-4 fmod all + .long serror |$21-5 fmod ERROR + .long serror |$21-6 fmod ERROR + .long serror |$21-7 fmod ERROR + + .long serror |$22-0 ERROR - illegal extension + .long serror |$22-1 ERROR - illegal extension + .long serror |$22-2 ERROR - illegal extension + .long serror |$22-3 ERROR - illegal extension + .long serror |$22-4 ERROR - illegal extension + .long serror |$22-5 ERROR - illegal extension + .long serror |$22-6 ERROR - illegal extension + .long serror |$22-7 ERROR - illegal extension + + .long serror |$23-0 ERROR - illegal extension + .long serror |$23-1 ERROR - illegal extension + .long serror |$23-2 ERROR - illegal extension + .long serror |$23-3 ERROR - illegal extension + .long serror |$23-4 ERROR - illegal extension + .long serror |$23-5 ERROR - illegal extension + .long serror |$23-6 ERROR - illegal extension + .long serror |$23-7 ERROR - illegal extension + + .long serror |$24-0 ERROR - illegal extension + .long serror |$24-1 ERROR - illegal extension + .long serror |$24-2 ERROR - illegal extension + .long serror |$24-3 ERROR - illegal extension + .long serror |$24-4 ERROR - illegal extension + .long serror |$24-5 ERROR - illegal extension + .long serror |$24-6 ERROR - illegal extension + .long serror |$24-7 ERROR - illegal extension + + .long prem |$25-0 frem all + .long prem |$25-1 frem all + .long prem |$25-2 frem all + .long prem |$25-3 frem all + .long prem |$25-4 frem all + .long serror |$25-5 frem ERROR + .long serror |$25-6 frem ERROR + .long serror |$25-7 frem ERROR + + .long pscale |$26-0 fscale all + .long pscale |$26-1 fscale all + .long pscale |$26-2 fscale all + .long pscale |$26-3 fscale all + .long pscale |$26-4 fscale all + .long serror |$26-5 fscale ERROR + .long serror |$26-6 fscale ERROR + .long serror |$26-7 fscale ERROR + + .long serror |$27-0 ERROR - illegal extension + .long serror |$27-1 ERROR - illegal extension + .long serror |$27-2 ERROR - illegal extension + .long serror |$27-3 ERROR - illegal extension + .long serror |$27-4 ERROR - illegal extension + .long serror |$27-5 ERROR - illegal extension + .long serror |$27-6 ERROR - illegal extension + .long serror |$27-7 ERROR - illegal extension + + .long serror |$28-0 ERROR - illegal extension + .long serror |$28-1 ERROR - illegal extension + .long serror |$28-2 ERROR - illegal extension + .long serror |$28-3 ERROR - illegal extension + .long serror |$28-4 ERROR - illegal extension + .long serror |$28-5 ERROR - illegal extension + .long serror |$28-6 ERROR - illegal extension + .long serror |$28-7 ERROR - illegal extension + + .long serror |$29-0 ERROR - illegal extension + .long serror |$29-1 ERROR - illegal extension + .long serror |$29-2 ERROR - illegal extension + .long serror |$29-3 ERROR - illegal extension + .long serror |$29-4 ERROR - illegal extension + .long serror |$29-5 ERROR - illegal extension + .long serror |$29-6 ERROR - illegal extension + .long serror |$29-7 ERROR - illegal extension + + .long serror |$2a-0 ERROR - illegal extension + .long serror |$2a-1 ERROR - illegal extension + .long serror |$2a-2 ERROR - illegal extension + .long serror |$2a-3 ERROR - illegal extension + .long serror |$2a-4 ERROR - illegal extension + .long serror |$2a-5 ERROR - illegal extension + .long serror |$2a-6 ERROR - illegal extension + .long serror |$2a-7 ERROR - illegal extension + + .long serror |$2b-0 ERROR - illegal extension + .long serror |$2b-1 ERROR - illegal extension + .long serror |$2b-2 ERROR - illegal extension + .long serror |$2b-3 ERROR - illegal extension + .long serror |$2b-4 ERROR - illegal extension + .long serror |$2b-5 ERROR - illegal extension + .long serror |$2b-6 ERROR - illegal extension + .long serror |$2b-7 ERROR - illegal extension + + .long serror |$2c-0 ERROR - illegal extension + .long serror |$2c-1 ERROR - illegal extension + .long serror |$2c-2 ERROR - illegal extension + .long serror |$2c-3 ERROR - illegal extension + .long serror |$2c-4 ERROR - illegal extension + .long serror |$2c-5 ERROR - illegal extension + .long serror |$2c-6 ERROR - illegal extension + .long serror |$2c-7 ERROR - illegal extension + + .long serror |$2d-0 ERROR - illegal extension + .long serror |$2d-1 ERROR - illegal extension + .long serror |$2d-2 ERROR - illegal extension + .long serror |$2d-3 ERROR - illegal extension + .long serror |$2d-4 ERROR - illegal extension + .long serror |$2d-5 ERROR - illegal extension + .long serror |$2d-6 ERROR - illegal extension + .long serror |$2d-7 ERROR - illegal extension + + .long serror |$2e-0 ERROR - illegal extension + .long serror |$2e-1 ERROR - illegal extension + .long serror |$2e-2 ERROR - illegal extension + .long serror |$2e-3 ERROR - illegal extension + .long serror |$2e-4 ERROR - illegal extension + .long serror |$2e-5 ERROR - illegal extension + .long serror |$2e-6 ERROR - illegal extension + .long serror |$2e-7 ERROR - illegal extension + + .long serror |$2f-0 ERROR - illegal extension + .long serror |$2f-1 ERROR - illegal extension + .long serror |$2f-2 ERROR - illegal extension + .long serror |$2f-3 ERROR - illegal extension + .long serror |$2f-4 ERROR - illegal extension + .long serror |$2f-5 ERROR - illegal extension + .long serror |$2f-6 ERROR - illegal extension + .long serror |$2f-7 ERROR - illegal extension + + .long ssincos |$30-0 fsincos norm + .long ssincosz |$30-1 fsincos zero + .long ssincosi |$30-2 fsincos inf + .long ssincosnan |$30-3 fsincos nan + .long ssincosd |$30-4 fsincos denorm + .long serror |$30-5 fsincos ERROR + .long serror |$30-6 fsincos ERROR + .long serror |$30-7 fsincos ERROR + + .long ssincos |$31-0 fsincos norm + .long ssincosz |$31-1 fsincos zero + .long ssincosi |$31-2 fsincos inf + .long ssincosnan |$31-3 fsincos nan + .long ssincosd |$31-4 fsincos denorm + .long serror |$31-5 fsincos ERROR + .long serror |$31-6 fsincos ERROR + .long serror |$31-7 fsincos ERROR + + .long ssincos |$32-0 fsincos norm + .long ssincosz |$32-1 fsincos zero + .long ssincosi |$32-2 fsincos inf + .long ssincosnan |$32-3 fsincos nan + .long ssincosd |$32-4 fsincos denorm + .long serror |$32-5 fsincos ERROR + .long serror |$32-6 fsincos ERROR + .long serror |$32-7 fsincos ERROR + + .long ssincos |$33-0 fsincos norm + .long ssincosz |$33-1 fsincos zero + .long ssincosi |$33-2 fsincos inf + .long ssincosnan |$33-3 fsincos nan + .long ssincosd |$33-4 fsincos denorm + .long serror |$33-5 fsincos ERROR + .long serror |$33-6 fsincos ERROR + .long serror |$33-7 fsincos ERROR + + .long ssincos |$34-0 fsincos norm + .long ssincosz |$34-1 fsincos zero + .long ssincosi |$34-2 fsincos inf + .long ssincosnan |$34-3 fsincos nan + .long ssincosd |$34-4 fsincos denorm + .long serror |$34-5 fsincos ERROR + .long serror |$34-6 fsincos ERROR + .long serror |$34-7 fsincos ERROR + + .long ssincos |$35-0 fsincos norm + .long ssincosz |$35-1 fsincos zero + .long ssincosi |$35-2 fsincos inf + .long ssincosnan |$35-3 fsincos nan + .long ssincosd |$35-4 fsincos denorm + .long serror |$35-5 fsincos ERROR + .long serror |$35-6 fsincos ERROR + .long serror |$35-7 fsincos ERROR + + .long ssincos |$36-0 fsincos norm + .long ssincosz |$36-1 fsincos zero + .long ssincosi |$36-2 fsincos inf + .long ssincosnan |$36-3 fsincos nan + .long ssincosd |$36-4 fsincos denorm + .long serror |$36-5 fsincos ERROR + .long serror |$36-6 fsincos ERROR + .long serror |$36-7 fsincos ERROR + + .long ssincos |$37-0 fsincos norm + .long ssincosz |$37-1 fsincos zero + .long ssincosi |$37-2 fsincos inf + .long ssincosnan |$37-3 fsincos nan + .long ssincosd |$37-4 fsincos denorm + .long serror |$37-5 fsincos ERROR + .long serror |$37-6 fsincos ERROR + .long serror |$37-7 fsincos ERROR + + |end diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/util.S linux/arch/m68k/fpsp040/util.S --- v1.3.93/linux/arch/m68k/fpsp040/util.S Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/fpsp040/util.S Sat Feb 24 22:58:45 1996 @@ -0,0 +1,748 @@ +| +| util.sa 3.7 7/29/91 +| +| This file contains routines used by other programs. +| +| ovf_res: used by overflow to force the correct +| result. ovf_r_k, ovf_r_x2, ovf_r_x3 are +| derivatives of this routine. +| get_fline: get user's opcode word +| g_dfmtou: returns the destination format. +| g_opcls: returns the opclass of the float instruction. +| g_rndpr: returns the rounding precision. +| reg_dest: write byte, word, or long data to Dn +| +| +| Copyright (C) Motorola, Inc. 1990 +| All Rights Reserved +| +| THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA +| The copyright notice above does not evidence any +| actual or intended publication of such source code. + +|UTIL idnt 2,1 | Motorola 040 Floating Point Software Package + + |section 8 + + .include "fpsp.h" + + |xref mem_read + + .global g_dfmtou + .global g_opcls + .global g_rndpr + .global get_fline + .global reg_dest + +| +| Final result table for ovf_res. Note that the negative counterparts +| are unnecessary as ovf_res always returns the sign separately from +| the exponent. +| ;+inf +EXT_PINF: .long 0x7fff0000,0x00000000,0x00000000,0x00000000 +| ;largest +ext +EXT_PLRG: .long 0x7ffe0000,0xffffffff,0xffffffff,0x00000000 +| ;largest magnitude +sgl in ext +SGL_PLRG: .long 0x407e0000,0xffffff00,0x00000000,0x00000000 +| ;largest magnitude +dbl in ext +DBL_PLRG: .long 0x43fe0000,0xffffffff,0xfffff800,0x00000000 +| ;largest -ext + +tblovfl: + .long EXT_RN + .long EXT_RZ + .long EXT_RM + .long EXT_RP + .long SGL_RN + .long SGL_RZ + .long SGL_RM + .long SGL_RP + .long DBL_RN + .long DBL_RZ + .long DBL_RM + .long DBL_RP + .long error + .long error + .long error + .long error + + +| +| ovf_r_k --- overflow result calculation +| +| This entry point is used by kernel_ex. +| +| This forces the destination precision to be extended +| +| Input: operand in ETEMP +| Output: a result is in ETEMP (internal extended format) +| + .global ovf_r_k +ovf_r_k: + lea ETEMP(%a6),%a0 |a0 points to source operand + bclrb #sign_bit,ETEMP_EX(%a6) + sne ETEMP_SGN(%a6) |convert to internal IEEE format + +| +| ovf_r_x2 --- overflow result calculation +| +| This entry point used by x_ovfl. (opclass 0 and 2) +| +| Input a0 points to an operand in the internal extended format +| Output a0 points to the result in the internal extended format +| +| This sets the round precision according to the user's FPCR unless the +| instruction is fsgldiv or fsglmul or fsadd, fdadd, fsub, fdsub, fsmul, +| fdmul, fsdiv, fddiv, fssqrt, fsmove, fdmove, fsabs, fdabs, fsneg, fdneg. +| If the instruction is fsgldiv of fsglmul, the rounding precision must be +| extended. If the instruction is not fsgldiv or fsglmul but a force- +| precision instruction, the rounding precision is then set to the force +| precision. + + .global ovf_r_x2 +ovf_r_x2: + btstb #E3,E_BYTE(%a6) |check for nu exception + beql ovf_e1_exc |it is cu exception +ovf_e3_exc: + movew CMDREG3B(%a6),%d0 |get the command word + andiw #0x00000060,%d0 |clear all bits except 6 and 5 + cmpil #0x00000040,%d0 + beql ovff_sgl |force precision is single + cmpil #0x00000060,%d0 + beql ovff_dbl |force precision is double + movew CMDREG3B(%a6),%d0 |get the command word again + andil #0x7f,%d0 |clear all except operation + cmpil #0x33,%d0 + beql ovf_fsgl |fsglmul or fsgldiv + cmpil #0x30,%d0 + beql ovf_fsgl + bra ovf_fpcr |instruction is none of the above +| ;use FPCR +ovf_e1_exc: + movew CMDREG1B(%a6),%d0 |get command word + andil #0x00000044,%d0 |clear all bits except 6 and 2 + cmpil #0x00000040,%d0 + beql ovff_sgl |the instruction is force single + cmpil #0x00000044,%d0 + beql ovff_dbl |the instruction is force double + movew CMDREG1B(%a6),%d0 |again get the command word + andil #0x0000007f,%d0 |clear all except the op code + cmpil #0x00000027,%d0 + beql ovf_fsgl |fsglmul + cmpil #0x00000024,%d0 + beql ovf_fsgl |fsgldiv + bra ovf_fpcr |none of the above, use FPCR +| +| +| Inst is either fsgldiv or fsglmul. Force extended precision. +| +ovf_fsgl: + clrl %d0 + bras ovf_res + +ovff_sgl: + movel #0x00000001,%d0 |set single + bras ovf_res +ovff_dbl: + movel #0x00000002,%d0 |set double + bras ovf_res +| +| The precision is in the fpcr. +| +ovf_fpcr: + bfextu FPCR_MODE(%a6){#0:#2},%d0 |set round precision + bras ovf_res + +| +| +| ovf_r_x3 --- overflow result calculation +| +| This entry point used by x_ovfl. (opclass 3 only) +| +| Input a0 points to an operand in the internal extended format +| Output a0 points to the result in the internal extended format +| +| This sets the round precision according to the destination size. +| + .global ovf_r_x3 +ovf_r_x3: + bsr g_dfmtou |get dest fmt in d0{1:0} +| ;for fmovout, the destination format +| ;is the rounding precision + +| +| ovf_res --- overflow result calculation +| +| Input: +| a0 points to operand in internal extended format +| Output: +| a0 points to result in internal extended format +| + .global ovf_res +ovf_res: + lsll #2,%d0 |move round precision to d0{3:2} + bfextu FPCR_MODE(%a6){#2:#2},%d1 |set round mode + orl %d1,%d0 |index is fmt:mode in d0{3:0} + leal tblovfl,%a1 |load a1 with table address + movel %a1@(%d0:l:4),%a1 |use d0 as index to the table + jmp (%a1) |go to the correct routine +| +|case DEST_FMT = EXT +| +EXT_RN: + leal EXT_PINF,%a1 |answer is +/- infinity + bsetb #inf_bit,FPSR_CC(%a6) + bra set_sign |now go set the sign +EXT_RZ: + leal EXT_PLRG,%a1 |answer is +/- large number + bra set_sign |now go set the sign +EXT_RM: + tstb LOCAL_SGN(%a0) |if negative overflow + beqs e_rm_pos +e_rm_neg: + leal EXT_PINF,%a1 |answer is negative infinity + orl #neginf_mask,USER_FPSR(%a6) + bra end_ovfr +e_rm_pos: + leal EXT_PLRG,%a1 |answer is large positive number + bra end_ovfr +EXT_RP: + tstb LOCAL_SGN(%a0) |if negative overflow + beqs e_rp_pos +e_rp_neg: + leal EXT_PLRG,%a1 |answer is large negative number + bsetb #neg_bit,FPSR_CC(%a6) + bra end_ovfr +e_rp_pos: + leal EXT_PINF,%a1 |answer is positive infinity + bsetb #inf_bit,FPSR_CC(%a6) + bra end_ovfr +| +|case DEST_FMT = DBL +| +DBL_RN: + leal EXT_PINF,%a1 |answer is +/- infinity + bsetb #inf_bit,FPSR_CC(%a6) + bra set_sign +DBL_RZ: + leal DBL_PLRG,%a1 |answer is +/- large number + bra set_sign |now go set the sign +DBL_RM: + tstb LOCAL_SGN(%a0) |if negative overflow + beqs d_rm_pos +d_rm_neg: + leal EXT_PINF,%a1 |answer is negative infinity + orl #neginf_mask,USER_FPSR(%a6) + bra end_ovfr |inf is same for all precisions (ext,dbl,sgl) +d_rm_pos: + leal DBL_PLRG,%a1 |answer is large positive number + bra end_ovfr +DBL_RP: + tstb LOCAL_SGN(%a0) |if negative overflow + beqs d_rp_pos +d_rp_neg: + leal DBL_PLRG,%a1 |answer is large negative number + bsetb #neg_bit,FPSR_CC(%a6) + bra end_ovfr +d_rp_pos: + leal EXT_PINF,%a1 |answer is positive infinity + bsetb #inf_bit,FPSR_CC(%a6) + bra end_ovfr +| +|case DEST_FMT = SGL +| +SGL_RN: + leal EXT_PINF,%a1 |answer is +/- infinity + bsetb #inf_bit,FPSR_CC(%a6) + bras set_sign +SGL_RZ: + leal SGL_PLRG,%a1 |anwer is +/- large number + bras set_sign +SGL_RM: + tstb LOCAL_SGN(%a0) |if negative overflow + beqs s_rm_pos +s_rm_neg: + leal EXT_PINF,%a1 |answer is negative infinity + orl #neginf_mask,USER_FPSR(%a6) + bras end_ovfr +s_rm_pos: + leal SGL_PLRG,%a1 |answer is large positive number + bras end_ovfr +SGL_RP: + tstb LOCAL_SGN(%a0) |if negative overflow + beqs s_rp_pos +s_rp_neg: + leal SGL_PLRG,%a1 |answer is large negative number + bsetb #neg_bit,FPSR_CC(%a6) + bras end_ovfr +s_rp_pos: + leal EXT_PINF,%a1 |answer is postive infinity + bsetb #inf_bit,FPSR_CC(%a6) + bras end_ovfr + +set_sign: + tstb LOCAL_SGN(%a0) |if negative overflow + beqs end_ovfr +neg_sign: + bsetb #neg_bit,FPSR_CC(%a6) + +end_ovfr: + movew LOCAL_EX(%a1),LOCAL_EX(%a0) |do not overwrite sign + movel LOCAL_HI(%a1),LOCAL_HI(%a0) + movel LOCAL_LO(%a1),LOCAL_LO(%a0) + rts + + +| +| ERROR +| +error: + rts +| +| get_fline --- get f-line opcode of interrupted instruction +| +| Returns opcode in the low word of d0. +| +get_fline: + movel USER_FPIAR(%a6),%a0 |opcode address + movel #0,-(%a7) |reserve a word on the stack + leal 2(%a7),%a1 |point to low word of temporary + movel #2,%d0 |count + bsrl mem_read + movel (%a7)+,%d0 + rts +| +| g_rndpr --- put rounding precision in d0{1:0} +| +| valid return codes are: +| 00 - extended +| 01 - single +| 10 - double +| +| begin +| get rounding precision (cmdreg3b{6:5}) +| begin +| case opclass = 011 (move out) +| get destination format - this is the also the rounding precision +| +| case opclass = 0x0 +| if E3 +| *case RndPr(from cmdreg3b{6:5} = 11 then RND_PREC = DBL +| *case RndPr(from cmdreg3b{6:5} = 10 then RND_PREC = SGL +| case RndPr(from cmdreg3b{6:5} = 00 | 01 +| use precision from FPCR{7:6} +| case 00 then RND_PREC = EXT +| case 01 then RND_PREC = SGL +| case 10 then RND_PREC = DBL +| else E1 +| use precision in FPCR{7:6} +| case 00 then RND_PREC = EXT +| case 01 then RND_PREC = SGL +| case 10 then RND_PREC = DBL +| end +| +g_rndpr: + bsr g_opcls |get opclass in d0{2:0} + cmpw #0x0003,%d0 |check for opclass 011 + bnes op_0x0 + +| +| For move out instructions (opclass 011) the destination format +| is the same as the rounding precision. Pass results from g_dfmtou. +| + bsr g_dfmtou + rts +op_0x0: + btstb #E3,E_BYTE(%a6) + beql unf_e1_exc |branch to e1 underflow +unf_e3_exc: + movel CMDREG3B(%a6),%d0 |rounding precision in d0{10:9} + bfextu %d0{#9:#2},%d0 |move the rounding prec bits to d0{1:0} + cmpil #0x2,%d0 + beql unff_sgl |force precision is single + cmpil #0x3,%d0 |force precision is double + beql unff_dbl + movew CMDREG3B(%a6),%d0 |get the command word again + andil #0x7f,%d0 |clear all except operation + cmpil #0x33,%d0 + beql unf_fsgl |fsglmul or fsgldiv + cmpil #0x30,%d0 + beql unf_fsgl |fsgldiv or fsglmul + bra unf_fpcr +unf_e1_exc: + movel CMDREG1B(%a6),%d0 |get 32 bits off the stack, 1st 16 bits +| ;are the command word + andil #0x00440000,%d0 |clear all bits except bits 6 and 2 + cmpil #0x00400000,%d0 + beql unff_sgl |force single + cmpil #0x00440000,%d0 |force double + beql unff_dbl + movel CMDREG1B(%a6),%d0 |get the command word again + andil #0x007f0000,%d0 |clear all bits except the operation + cmpil #0x00270000,%d0 + beql unf_fsgl |fsglmul + cmpil #0x00240000,%d0 + beql unf_fsgl |fsgldiv + bra unf_fpcr + +| +| Convert to return format. The values from cmdreg3b and the return +| values are: +| cmdreg3b return precision +| -------- ------ --------- +| 00,01 0 ext +| 10 1 sgl +| 11 2 dbl +| Force single +| +unff_sgl: + movel #1,%d0 |return 1 + rts +| +| Force double +| +unff_dbl: + movel #2,%d0 |return 2 + rts +| +| Force extended +| +unf_fsgl: + movel #0,%d0 + rts +| +| Get rounding precision set in FPCR{7:6}. +| +unf_fpcr: + movel USER_FPCR(%a6),%d0 |rounding precision bits in d0{7:6} + bfextu %d0{#24:#2},%d0 |move the rounding prec bits to d0{1:0} + rts +| +| g_opcls --- put opclass in d0{2:0} +| +g_opcls: + btstb #E3,E_BYTE(%a6) + beqs opc_1b |if set, go to cmdreg1b +opc_3b: + clrl %d0 |if E3, only opclass 0x0 is possible + rts +opc_1b: + movel CMDREG1B(%a6),%d0 + bfextu %d0{#0:#3},%d0 |shift opclass bits d0{31:29} to d0{2:0} + rts +| +| g_dfmtou --- put destination format in d0{1:0} +| +| If E1, the format is from cmdreg1b{12:10} +| If E3, the format is extended. +| +| Dest. Fmt. +| extended 010 -> 00 +| single 001 -> 01 +| double 101 -> 10 +| +g_dfmtou: + btstb #E3,E_BYTE(%a6) + beqs op011 + clrl %d0 |if E1, size is always ext + rts +op011: + movel CMDREG1B(%a6),%d0 + bfextu %d0{#3:#3},%d0 |dest fmt from cmdreg1b{12:10} + cmpb #1,%d0 |check for single + bnes not_sgl + movel #1,%d0 + rts +not_sgl: + cmpb #5,%d0 |check for double + bnes not_dbl + movel #2,%d0 + rts +not_dbl: + clrl %d0 |must be extended + rts + +| +| +| Final result table for unf_sub. Note that the negative counterparts +| are unnecessary as unf_sub always returns the sign separately from +| the exponent. +| ;+zero +EXT_PZRO: .long 0x00000000,0x00000000,0x00000000,0x00000000 +| ;+zero +SGL_PZRO: .long 0x3f810000,0x00000000,0x00000000,0x00000000 +| ;+zero +DBL_PZRO: .long 0x3c010000,0x00000000,0x00000000,0x00000000 +| ;smallest +ext denorm +EXT_PSML: .long 0x00000000,0x00000000,0x00000001,0x00000000 +| ;smallest +sgl denorm +SGL_PSML: .long 0x3f810000,0x00000100,0x00000000,0x00000000 +| ;smallest +dbl denorm +DBL_PSML: .long 0x3c010000,0x00000000,0x00000800,0x00000000 +| +| UNF_SUB --- underflow result calculation +| +| Input: +| d0 contains round precision +| a0 points to input operand in the internal extended format +| +| Output: +| a0 points to correct internal extended precision result. +| + +tblunf: + .long uEXT_RN + .long uEXT_RZ + .long uEXT_RM + .long uEXT_RP + .long uSGL_RN + .long uSGL_RZ + .long uSGL_RM + .long uSGL_RP + .long uDBL_RN + .long uDBL_RZ + .long uDBL_RM + .long uDBL_RP + .long uDBL_RN + .long uDBL_RZ + .long uDBL_RM + .long uDBL_RP + + .global unf_sub +unf_sub: + lsll #2,%d0 |move round precision to d0{3:2} + bfextu FPCR_MODE(%a6){#2:#2},%d1 |set round mode + orl %d1,%d0 |index is fmt:mode in d0{3:0} + leal tblunf,%a1 |load a1 with table address + movel %a1@(%d0:l:4),%a1 |use d0 as index to the table + jmp (%a1) |go to the correct routine +| +|case DEST_FMT = EXT +| +uEXT_RN: + leal EXT_PZRO,%a1 |answer is +/- zero + bsetb #z_bit,FPSR_CC(%a6) + bra uset_sign |now go set the sign +uEXT_RZ: + leal EXT_PZRO,%a1 |answer is +/- zero + bsetb #z_bit,FPSR_CC(%a6) + bra uset_sign |now go set the sign +uEXT_RM: + tstb LOCAL_SGN(%a0) |if negative underflow + beqs ue_rm_pos +ue_rm_neg: + leal EXT_PSML,%a1 |answer is negative smallest denorm + bsetb #neg_bit,FPSR_CC(%a6) + bra end_unfr +ue_rm_pos: + leal EXT_PZRO,%a1 |answer is positive zero + bsetb #z_bit,FPSR_CC(%a6) + bra end_unfr +uEXT_RP: + tstb LOCAL_SGN(%a0) |if negative underflow + beqs ue_rp_pos +ue_rp_neg: + leal EXT_PZRO,%a1 |answer is negative zero + oril #negz_mask,USER_FPSR(%a6) + bra end_unfr +ue_rp_pos: + leal EXT_PSML,%a1 |answer is positive smallest denorm + bra end_unfr +| +|case DEST_FMT = DBL +| +uDBL_RN: + leal DBL_PZRO,%a1 |answer is +/- zero + bsetb #z_bit,FPSR_CC(%a6) + bra uset_sign +uDBL_RZ: + leal DBL_PZRO,%a1 |answer is +/- zero + bsetb #z_bit,FPSR_CC(%a6) + bra uset_sign |now go set the sign +uDBL_RM: + tstb LOCAL_SGN(%a0) |if negative overflow + beqs ud_rm_pos +ud_rm_neg: + leal DBL_PSML,%a1 |answer is smallest denormalized negative + bsetb #neg_bit,FPSR_CC(%a6) + bra end_unfr +ud_rm_pos: + leal DBL_PZRO,%a1 |answer is positive zero + bsetb #z_bit,FPSR_CC(%a6) + bra end_unfr +uDBL_RP: + tstb LOCAL_SGN(%a0) |if negative overflow + beqs ud_rp_pos +ud_rp_neg: + leal DBL_PZRO,%a1 |answer is negative zero + oril #negz_mask,USER_FPSR(%a6) + bra end_unfr +ud_rp_pos: + leal DBL_PSML,%a1 |answer is smallest denormalized negative + bra end_unfr +| +|case DEST_FMT = SGL +| +uSGL_RN: + leal SGL_PZRO,%a1 |answer is +/- zero + bsetb #z_bit,FPSR_CC(%a6) + bras uset_sign +uSGL_RZ: + leal SGL_PZRO,%a1 |answer is +/- zero + bsetb #z_bit,FPSR_CC(%a6) + bras uset_sign +uSGL_RM: + tstb LOCAL_SGN(%a0) |if negative overflow + beqs us_rm_pos +us_rm_neg: + leal SGL_PSML,%a1 |answer is smallest denormalized negative + bsetb #neg_bit,FPSR_CC(%a6) + bras end_unfr +us_rm_pos: + leal SGL_PZRO,%a1 |answer is positive zero + bsetb #z_bit,FPSR_CC(%a6) + bras end_unfr +uSGL_RP: + tstb LOCAL_SGN(%a0) |if negative overflow + beqs us_rp_pos +us_rp_neg: + leal SGL_PZRO,%a1 |answer is negative zero + oril #negz_mask,USER_FPSR(%a6) + bras end_unfr +us_rp_pos: + leal SGL_PSML,%a1 |answer is smallest denormalized positive + bras end_unfr + +uset_sign: + tstb LOCAL_SGN(%a0) |if negative overflow + beqs end_unfr +uneg_sign: + bsetb #neg_bit,FPSR_CC(%a6) + +end_unfr: + movew LOCAL_EX(%a1),LOCAL_EX(%a0) |be careful not to overwrite sign + movel LOCAL_HI(%a1),LOCAL_HI(%a0) + movel LOCAL_LO(%a1),LOCAL_LO(%a0) + rts +| +| reg_dest --- write byte, word, or long data to Dn +| +| +| Input: +| L_SCR1: Data +| d1: data size and dest register number formatted as: +| +| 32 5 4 3 2 1 0 +| ----------------------------------------------- +| | 0 | Size | Dest Reg # | +| ----------------------------------------------- +| +| Size is: +| 0 - Byte +| 1 - Word +| 2 - Long/Single +| +pregdst: + .long byte_d0 + .long byte_d1 + .long byte_d2 + .long byte_d3 + .long byte_d4 + .long byte_d5 + .long byte_d6 + .long byte_d7 + .long word_d0 + .long word_d1 + .long word_d2 + .long word_d3 + .long word_d4 + .long word_d5 + .long word_d6 + .long word_d7 + .long long_d0 + .long long_d1 + .long long_d2 + .long long_d3 + .long long_d4 + .long long_d5 + .long long_d6 + .long long_d7 + +reg_dest: + leal pregdst,%a0 + movel %a0@(%d1:l:4),%a0 + jmp (%a0) + +byte_d0: + moveb L_SCR1(%a6),USER_D0+3(%a6) + rts +byte_d1: + moveb L_SCR1(%a6),USER_D1+3(%a6) + rts +byte_d2: + moveb L_SCR1(%a6),%d2 + rts +byte_d3: + moveb L_SCR1(%a6),%d3 + rts +byte_d4: + moveb L_SCR1(%a6),%d4 + rts +byte_d5: + moveb L_SCR1(%a6),%d5 + rts +byte_d6: + moveb L_SCR1(%a6),%d6 + rts +byte_d7: + moveb L_SCR1(%a6),%d7 + rts +word_d0: + movew L_SCR1(%a6),USER_D0+2(%a6) + rts +word_d1: + movew L_SCR1(%a6),USER_D1+2(%a6) + rts +word_d2: + movew L_SCR1(%a6),%d2 + rts +word_d3: + movew L_SCR1(%a6),%d3 + rts +word_d4: + movew L_SCR1(%a6),%d4 + rts +word_d5: + movew L_SCR1(%a6),%d5 + rts +word_d6: + movew L_SCR1(%a6),%d6 + rts +word_d7: + movew L_SCR1(%a6),%d7 + rts +long_d0: + movel L_SCR1(%a6),USER_D0(%a6) + rts +long_d1: + movel L_SCR1(%a6),USER_D1(%a6) + rts +long_d2: + movel L_SCR1(%a6),%d2 + rts +long_d3: + movel L_SCR1(%a6),%d3 + rts +long_d4: + movel L_SCR1(%a6),%d4 + rts +long_d5: + movel L_SCR1(%a6),%d5 + rts +long_d6: + movel L_SCR1(%a6),%d6 + rts +long_d7: + movel L_SCR1(%a6),%d7 + rts + |end diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/x_bsun.S linux/arch/m68k/fpsp040/x_bsun.S --- v1.3.93/linux/arch/m68k/fpsp040/x_bsun.S Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/fpsp040/x_bsun.S Sat Feb 24 22:58:45 1996 @@ -0,0 +1,47 @@ +| +| x_bsun.sa 3.3 7/1/91 +| +| fpsp_bsun --- FPSP handler for branch/set on unordered exception +| +| Copy the PC to FPIAR to maintain 881/882 compatability +| +| The real_bsun handler will need to perform further corrective +| measures as outlined in the 040 User's Manual on pages +| 9-41f, section 9.8.3. +| + +| Copyright (C) Motorola, Inc. 1990 +| All Rights Reserved +| +| THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA +| The copyright notice above does not evidence any +| actual or intended publication of such source code. + +X_BSUN: |idnt 2,1 | Motorola 040 Floating Point Software Package + + |section 8 + + .include "fpsp.h" + + |xref real_bsun + + .global fpsp_bsun +fpsp_bsun: +| + link %a6,#-LOCAL_SIZE + fsave -(%a7) + moveml %d0-%d1/%a0-%a1,USER_DA(%a6) + fmovemx %fp0-%fp3,USER_FP0(%a6) + fmoveml %fpcr/%fpsr/%fpiar,USER_FPCR(%a6) + +| + movel EXC_PC(%a6),USER_FPIAR(%a6) +| + moveml USER_DA(%a6),%d0-%d1/%a0-%a1 + fmovemx USER_FP0(%a6),%fp0-%fp3 + fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar + frestore (%a7)+ + unlk %a6 + bral real_bsun +| + |end diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/x_fline.S linux/arch/m68k/fpsp040/x_fline.S --- v1.3.93/linux/arch/m68k/fpsp040/x_fline.S Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/fpsp040/x_fline.S Sat Feb 24 22:58:45 1996 @@ -0,0 +1,104 @@ +| +| x_fline.sa 3.3 1/10/91 +| +| fpsp_fline --- FPSP handler for fline exception +| +| First determine if the exception is one of the unimplemented +| floating point instructions. If so, let fpsp_unimp handle it. +| Next, determine if the instruction is an fmovecr with a non-zero +| field. If so, handle here and return. Otherwise, it +| must be a real F-line exception. +| + +| Copyright (C) Motorola, Inc. 1990 +| All Rights Reserved +| +| THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA +| The copyright notice above does not evidence any +| actual or intended publication of such source code. + +X_FLINE: |idnt 2,1 | Motorola 040 Floating Point Software Package + + |section 8 + + .include "fpsp.h" + + |xref real_fline + |xref fpsp_unimp + |xref uni_2 + |xref mem_read + |xref fpsp_fmt_error + + .global fpsp_fline +fpsp_fline: +| +| check for unimplemented vector first. Use EXC_VEC-4 because +| the equate is valid only after a 'link a6' has pushed one more +| long onto the stack. +| + cmpw #UNIMP_VEC,EXC_VEC-4(%a7) + beql fpsp_unimp + +| +| fmovecr with non-zero handling here +| + subl #4,%a7 |4 accounts for 2-word difference +| ;between six word frame (unimp) and +| ;four word frame + link %a6,#-LOCAL_SIZE + fsave -(%a7) + moveml %d0-%d1/%a0-%a1,USER_DA(%a6) + moveal EXC_PC+4(%a6),%a0 |get address of fline instruction + leal L_SCR1(%a6),%a1 |use L_SCR1 as scratch + movel #4,%d0 + addl #4,%a6 |to offset the sub.l #4,a7 above so that +| ;a6 can point correctly to the stack frame +| ;before branching to mem_read + bsrl mem_read + subl #4,%a6 + movel L_SCR1(%a6),%d0 |d0 contains the fline and command word + bfextu %d0{#4:#3},%d1 |extract coprocessor id + cmpib #1,%d1 |check if cpid=1 + bne not_mvcr |exit if not + bfextu %d0{#16:#6},%d1 + cmpib #0x17,%d1 |check if it is an FMOVECR encoding + bne not_mvcr +| ;if an FMOVECR instruction, fix stack +| ;and go to FPSP_UNIMP +fix_stack: + cmpib #VER_40,(%a7) |test for orig unimp frame + bnes ck_rev + subl #UNIMP_40_SIZE-4,%a7 |emulate an orig fsave + moveb #VER_40,(%a7) + moveb #UNIMP_40_SIZE-4,1(%a7) + clrw 2(%a7) + bras fix_con +ck_rev: + cmpib #VER_41,(%a7) |test for rev unimp frame + bnel fpsp_fmt_error |if not $40 or $41, exit with error + subl #UNIMP_41_SIZE-4,%a7 |emulate a rev fsave + moveb #VER_41,(%a7) + moveb #UNIMP_41_SIZE-4,1(%a7) + clrw 2(%a7) +fix_con: + movew EXC_SR+4(%a6),EXC_SR(%a6) |move stacked sr to new position + movel EXC_PC+4(%a6),EXC_PC(%a6) |move stacked pc to new position + fmovel EXC_PC(%a6),%FPIAR |point FPIAR to fline inst + movel #4,%d1 + addl %d1,EXC_PC(%a6) |increment stacked pc value to next inst + movew #0x202c,EXC_VEC(%a6) |reformat vector to unimp + clrl EXC_EA(%a6) |clear the EXC_EA field + movew %d0,CMDREG1B(%a6) |move the lower word into CMDREG1B + clrl E_BYTE(%a6) + bsetb #UFLAG,T_BYTE(%a6) + moveml USER_DA(%a6),%d0-%d1/%a0-%a1 |restore data registers + bral uni_2 + +not_mvcr: + moveml USER_DA(%a6),%d0-%d1/%a0-%a1 |restore data registers + frestore (%a7)+ + unlk %a6 + addl #4,%a7 + bral real_fline + + |end diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/x_operr.S linux/arch/m68k/fpsp040/x_operr.S --- v1.3.93/linux/arch/m68k/fpsp040/x_operr.S Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/fpsp040/x_operr.S Sat Feb 24 22:58:45 1996 @@ -0,0 +1,356 @@ +| +| x_operr.sa 3.5 7/1/91 +| +| fpsp_operr --- FPSP handler for operand error exception +| +| See 68040 User's Manual pp. 9-44f +| +| Note 1: For trap disabled 040 does the following: +| If the dest is a fp reg, then an extended precision non_signaling +| NAN is stored in the dest reg. If the dest format is b, w, or l and +| the source op is a NAN, then garbage is stored as the result (actually +| the upper 32 bits of the mantissa are sent to the integer unit). If +| the dest format is integer (b, w, l) and the operr is caused by +| integer overflow, or the source op is inf, then the result stored is +| garbage. +| There are three cases in which operr is incorrectly signaled on the +| 040. This occurs for move_out of format b, w, or l for the largest +| negative integer (-2^7 for b, -2^15 for w, -2^31 for l). +| +| On opclass = 011 fmove.(b,w,l) that causes a conversion +| overflow -> OPERR, the exponent in wbte (and fpte) is: +| byte 56 - (62 - exp) +| word 48 - (62 - exp) +| long 32 - (62 - exp) +| +| where exp = (true exp) - 1 +| +| So, wbtemp and fptemp will contain the following on erroneoulsy +| signalled operr: +| fpts = 1 +| fpte = $4000 (15 bit externally) +| byte fptm = $ffffffff ffffff80 +| word fptm = $ffffffff ffff8000 +| long fptm = $ffffffff 80000000 +| +| Note 2: For trap enabled 040 does the following: +| If the inst is move_out, then same as Note 1. +| If the inst is not move_out, the dest is not modified. +| The exceptional operand is not defined for integer overflow +| during a move_out. +| + +| Copyright (C) Motorola, Inc. 1990 +| All Rights Reserved +| +| THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA +| The copyright notice above does not evidence any +| actual or intended publication of such source code. + +X_OPERR: |idnt 2,1 | Motorola 040 Floating Point Software Package + + |section 8 + + .include "fpsp.h" + + |xref mem_write + |xref real_operr + |xref real_inex + |xref get_fline + |xref fpsp_done + |xref reg_dest + + .global fpsp_operr +fpsp_operr: +| + link %a6,#-LOCAL_SIZE + fsave -(%a7) + moveml %d0-%d1/%a0-%a1,USER_DA(%a6) + fmovemx %fp0-%fp3,USER_FP0(%a6) + fmoveml %fpcr/%fpsr/%fpiar,USER_FPCR(%a6) + +| +| Check if this is an opclass 3 instruction. +| If so, fall through, else branch to operr_end +| + btstb #TFLAG,T_BYTE(%a6) + beqs operr_end + +| +| If the destination size is B,W,or L, the operr must be +| handled here. +| + movel CMDREG1B(%a6),%d0 + bfextu %d0{#3:#3},%d0 |0=long, 4=word, 6=byte + cmpib #0,%d0 |determine size; check long + beq operr_long + cmpib #4,%d0 |check word + beq operr_word + cmpib #6,%d0 |check byte + beq operr_byte + +| +| The size is not B,W,or L, so the operr is handled by the +| kernel handler. Set the operr bits and clean up, leaving +| only the integer exception frame on the stack, and the +| fpu in the original exceptional state. +| +operr_end: + bsetb #operr_bit,FPSR_EXCEPT(%a6) + bsetb #aiop_bit,FPSR_AEXCEPT(%a6) + + moveml USER_DA(%a6),%d0-%d1/%a0-%a1 + fmovemx USER_FP0(%a6),%fp0-%fp3 + fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar + frestore (%a7)+ + unlk %a6 + bral real_operr + +operr_long: + moveql #4,%d1 |write size to d1 + moveb STAG(%a6),%d0 |test stag for nan + andib #0xe0,%d0 |clr all but tag + cmpib #0x60,%d0 |check for nan + beq operr_nan + cmpil #0x80000000,FPTEMP_LO(%a6) |test if ls lword is special + bnes chklerr |if not equal, check for incorrect operr + bsr check_upper |check if exp and ms mant are special + tstl %d0 + bnes chklerr |if d0 is true, check for incorrect operr + movel #0x80000000,%d0 |store special case result + bsr operr_store + bra not_enabled |clean and exit +| +| CHECK FOR INCORRECTLY GENERATED OPERR EXCEPTION HERE +| +chklerr: + movew FPTEMP_EX(%a6),%d0 + andw #0x7FFF,%d0 |ignore sign bit + cmpw #0x3FFE,%d0 |this is the only possible exponent value + bnes chklerr2 +fixlong: + movel FPTEMP_LO(%a6),%d0 + bsr operr_store + bra not_enabled +chklerr2: + movew FPTEMP_EX(%a6),%d0 + andw #0x7FFF,%d0 |ignore sign bit + cmpw #0x4000,%d0 + bcc store_max |exponent out of range + + movel FPTEMP_LO(%a6),%d0 + andl #0x7FFF0000,%d0 |look for all 1's on bits 30-16 + cmpl #0x7FFF0000,%d0 + beqs fixlong + + tstl FPTEMP_LO(%a6) + bpls chklepos + cmpl #0xFFFFFFFF,FPTEMP_HI(%a6) + beqs fixlong + bra store_max +chklepos: + tstl FPTEMP_HI(%a6) + beqs fixlong + bra store_max + +operr_word: + moveql #2,%d1 |write size to d1 + moveb STAG(%a6),%d0 |test stag for nan + andib #0xe0,%d0 |clr all but tag + cmpib #0x60,%d0 |check for nan + beq operr_nan + cmpil #0xffff8000,FPTEMP_LO(%a6) |test if ls lword is special + bnes chkwerr |if not equal, check for incorrect operr + bsr check_upper |check if exp and ms mant are special + tstl %d0 + bnes chkwerr |if d0 is true, check for incorrect operr + movel #0x80000000,%d0 |store special case result + bsr operr_store + bra not_enabled |clean and exit +| +| CHECK FOR INCORRECTLY GENERATED OPERR EXCEPTION HERE +| +chkwerr: + movew FPTEMP_EX(%a6),%d0 + andw #0x7FFF,%d0 |ignore sign bit + cmpw #0x3FFE,%d0 |this is the only possible exponent value + bnes store_max + movel FPTEMP_LO(%a6),%d0 + swap %d0 + bsr operr_store + bra not_enabled + +operr_byte: + moveql #1,%d1 |write size to d1 + moveb STAG(%a6),%d0 |test stag for nan + andib #0xe0,%d0 |clr all but tag + cmpib #0x60,%d0 |check for nan + beqs operr_nan + cmpil #0xffffff80,FPTEMP_LO(%a6) |test if ls lword is special + bnes chkberr |if not equal, check for incorrect operr + bsr check_upper |check if exp and ms mant are special + tstl %d0 + bnes chkberr |if d0 is true, check for incorrect operr + movel #0x80000000,%d0 |store special case result + bsr operr_store + bra not_enabled |clean and exit +| +| CHECK FOR INCORRECTLY GENERATED OPERR EXCEPTION HERE +| +chkberr: + movew FPTEMP_EX(%a6),%d0 + andw #0x7FFF,%d0 |ignore sign bit + cmpw #0x3FFE,%d0 |this is the only possible exponent value + bnes store_max + movel FPTEMP_LO(%a6),%d0 + asll #8,%d0 + swap %d0 + bsr operr_store + bra not_enabled + +| +| This operr condition is not of the special case. Set operr +| and aiop and write the portion of the nan to memory for the +| given size. +| +operr_nan: + orl #opaop_mask,USER_FPSR(%a6) |set operr & aiop + + movel ETEMP_HI(%a6),%d0 |output will be from upper 32 bits + bsr operr_store + bra end_operr +| +| Store_max loads the max pos or negative for the size, sets +| the operr and aiop bits, and clears inex and ainex, incorrectly +| set by the 040. +| +store_max: + orl #opaop_mask,USER_FPSR(%a6) |set operr & aiop + bclrb #inex2_bit,FPSR_EXCEPT(%a6) + bclrb #ainex_bit,FPSR_AEXCEPT(%a6) + fmovel #0,%FPSR + + tstw FPTEMP_EX(%a6) |check sign + blts load_neg + movel #0x7fffffff,%d0 + bsr operr_store + bra end_operr +load_neg: + movel #0x80000000,%d0 + bsr operr_store + bra end_operr + +| +| This routine stores the data in d0, for the given size in d1, +| to memory or data register as required. A read of the fline +| is required to determine the destination. +| +operr_store: + movel %d0,L_SCR1(%a6) |move write data to L_SCR1 + movel %d1,-(%a7) |save register size + bsrl get_fline |fline returned in d0 + movel (%a7)+,%d1 + bftst %d0{#26:#3} |if mode is zero, dest is Dn + bnes dest_mem +| +| Destination is Dn. Get register number from d0. Data is on +| the stack at (a7). D1 has size: 1=byte,2=word,4=long/single +| + andil #7,%d0 |isolate register number + cmpil #4,%d1 + beqs op_long |the most frequent case + cmpil #2,%d1 + bnes op_con + orl #8,%d0 + bras op_con +op_long: + orl #0x10,%d0 +op_con: + movel %d0,%d1 |format size:reg for reg_dest + bral reg_dest |call to reg_dest returns to caller +| ;of operr_store +| +| Destination is memory. Get from integer exception frame +| and call mem_write. +| +dest_mem: + leal L_SCR1(%a6),%a0 |put ptr to write data in a0 + movel EXC_EA(%a6),%a1 |put user destination address in a1 + movel %d1,%d0 |put size in d0 + bsrl mem_write + rts +| +| Check the exponent for $c000 and the upper 32 bits of the +| mantissa for $ffffffff. If both are true, return d0 clr +| and store the lower n bits of the least lword of FPTEMP +| to d0 for write out. If not, it is a real operr, and set d0. +| +check_upper: + cmpil #0xffffffff,FPTEMP_HI(%a6) |check if first byte is all 1's + bnes true_operr |if not all 1's then was true operr + cmpiw #0xc000,FPTEMP_EX(%a6) |check if incorrectly signalled + beqs not_true_operr |branch if not true operr + cmpiw #0xbfff,FPTEMP_EX(%a6) |check if incorrectly signalled + beqs not_true_operr |branch if not true operr +true_operr: + movel #1,%d0 |signal real operr + rts +not_true_operr: + clrl %d0 |signal no real operr + rts + +| +| End_operr tests for operr enabled. If not, it cleans up the stack +| and does an rte. If enabled, it cleans up the stack and branches +| to the kernel operr handler with only the integer exception +| frame on the stack and the fpu in the original exceptional state +| with correct data written to the destination. +| +end_operr: + btstb #operr_bit,FPCR_ENABLE(%a6) + beqs not_enabled +enabled: + moveml USER_DA(%a6),%d0-%d1/%a0-%a1 + fmovemx USER_FP0(%a6),%fp0-%fp3 + fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar + frestore (%a7)+ + unlk %a6 + bral real_operr + +not_enabled: +| +| It is possible to have either inex2 or inex1 exceptions with the +| operr. If the inex enable bit is set in the FPCR, and either +| inex2 or inex1 occured, we must clean up and branch to the +| real inex handler. +| +ck_inex: + moveb FPCR_ENABLE(%a6),%d0 + andb FPSR_EXCEPT(%a6),%d0 + andib #0x3,%d0 + beq operr_exit +| +| Inexact enabled and reported, and we must take an inexact exception. +| +take_inex: + moveb #INEX_VEC,EXC_VEC+1(%a6) + movel USER_FPSR(%a6),FPSR_SHADOW(%a6) + orl #sx_mask,E_BYTE(%a6) + moveml USER_DA(%a6),%d0-%d1/%a0-%a1 + fmovemx USER_FP0(%a6),%fp0-%fp3 + fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar + frestore (%a7)+ + unlk %a6 + bral real_inex +| +| Since operr is only an E1 exception, there is no need to frestore +| any state back to the fpu. +| +operr_exit: + moveml USER_DA(%a6),%d0-%d1/%a0-%a1 + fmovemx USER_FP0(%a6),%fp0-%fp3 + fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar + unlk %a6 + bral fpsp_done + + |end diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/x_ovfl.S linux/arch/m68k/fpsp040/x_ovfl.S --- v1.3.93/linux/arch/m68k/fpsp040/x_ovfl.S Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/fpsp040/x_ovfl.S Sat Feb 24 22:58:45 1996 @@ -0,0 +1,186 @@ +| +| x_ovfl.sa 3.5 7/1/91 +| +| fpsp_ovfl --- FPSP handler for overflow exception +| +| Overflow occurs when a floating-point intermediate result is +| too large to be represented in a floating-point data register, +| or when storing to memory, the contents of a floating-point +| data register are too large to be represented in the +| destination format. +| +| Trap disabled results +| +| If the instruction is move_out, then garbage is stored in the +| destination. If the instruction is not move_out, then the +| destination is not affected. For 68881 compatibility, the +| following values should be stored at the destination, based +| on the current rounding mode: +| +| RN Infinity with the sign of the intermediate result. +| RZ Largest magnitude number, with the sign of the +| intermediate result. +| RM For pos overflow, the largest pos number. For neg overflow, +| -infinity +| RP For pos overflow, +infinity. For neg overflow, the largest +| neg number +| +| Trap enabled results +| All trap disabled code applies. In addition the exceptional +| operand needs to be made available to the users exception handler +| with a bias of $6000 subtracted from the exponent. +| +| + +| Copyright (C) Motorola, Inc. 1990 +| All Rights Reserved +| +| THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA +| The copyright notice above does not evidence any +| actual or intended publication of such source code. + +X_OVFL: |idnt 2,1 | Motorola 040 Floating Point Software Package + + |section 8 + + .include "fpsp.h" + + |xref ovf_r_x2 + |xref ovf_r_x3 + |xref store + |xref real_ovfl + |xref real_inex + |xref fpsp_done + |xref g_opcls + |xref b1238_fix + + .global fpsp_ovfl +fpsp_ovfl: + link %a6,#-LOCAL_SIZE + fsave -(%a7) + moveml %d0-%d1/%a0-%a1,USER_DA(%a6) + fmovemx %fp0-%fp3,USER_FP0(%a6) + fmoveml %fpcr/%fpsr/%fpiar,USER_FPCR(%a6) + +| +| The 040 doesn't set the AINEX bit in the FPSR, the following +| line temporarily rectifies this error. +| + bsetb #ainex_bit,FPSR_AEXCEPT(%a6) +| + bsrl ovf_adj |denormalize, round & store interm op +| +| if overflow traps not enabled check for inexact exception +| + btstb #ovfl_bit,FPCR_ENABLE(%a6) + beqs ck_inex +| + btstb #E3,E_BYTE(%a6) + beqs no_e3_1 + bfextu CMDREG3B(%a6){#6:#3},%d0 |get dest reg no + bclrb %d0,FPR_DIRTY_BITS(%a6) |clr dest dirty bit + bsrl b1238_fix + movel USER_FPSR(%a6),FPSR_SHADOW(%a6) + orl #sx_mask,E_BYTE(%a6) +no_e3_1: + moveml USER_DA(%a6),%d0-%d1/%a0-%a1 + fmovemx USER_FP0(%a6),%fp0-%fp3 + fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar + frestore (%a7)+ + unlk %a6 + bral real_ovfl +| +| It is possible to have either inex2 or inex1 exceptions with the +| ovfl. If the inex enable bit is set in the FPCR, and either +| inex2 or inex1 occured, we must clean up and branch to the +| real inex handler. +| +ck_inex: +| move.b FPCR_ENABLE(%a6),%d0 +| and.b FPSR_EXCEPT(%a6),%d0 +| andi.b #$3,%d0 + btstb #inex2_bit,FPCR_ENABLE(%a6) + beqs ovfl_exit +| +| Inexact enabled and reported, and we must take an inexact exception. +| +take_inex: + btstb #E3,E_BYTE(%a6) + beqs no_e3_2 + bfextu CMDREG3B(%a6){#6:#3},%d0 |get dest reg no + bclrb %d0,FPR_DIRTY_BITS(%a6) |clr dest dirty bit + bsrl b1238_fix + movel USER_FPSR(%a6),FPSR_SHADOW(%a6) + orl #sx_mask,E_BYTE(%a6) +no_e3_2: + moveb #INEX_VEC,EXC_VEC+1(%a6) + moveml USER_DA(%a6),%d0-%d1/%a0-%a1 + fmovemx USER_FP0(%a6),%fp0-%fp3 + fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar + frestore (%a7)+ + unlk %a6 + bral real_inex + +ovfl_exit: + bclrb #E3,E_BYTE(%a6) |test and clear E3 bit + beqs e1_set +| +| Clear dirty bit on dest resister in the frame before branching +| to b1238_fix. +| + bfextu CMDREG3B(%a6){#6:#3},%d0 |get dest reg no + bclrb %d0,FPR_DIRTY_BITS(%a6) |clr dest dirty bit + bsrl b1238_fix |test for bug1238 case + + movel USER_FPSR(%a6),FPSR_SHADOW(%a6) + orl #sx_mask,E_BYTE(%a6) + moveml USER_DA(%a6),%d0-%d1/%a0-%a1 + fmovemx USER_FP0(%a6),%fp0-%fp3 + fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar + frestore (%a7)+ + unlk %a6 + bral fpsp_done +e1_set: + moveml USER_DA(%a6),%d0-%d1/%a0-%a1 + fmovemx USER_FP0(%a6),%fp0-%fp3 + fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar + unlk %a6 + bral fpsp_done + +| +| ovf_adj +| +ovf_adj: +| +| Have a0 point to the correct operand. +| + btstb #E3,E_BYTE(%a6) |test E3 bit + beqs ovf_e1 + + lea WBTEMP(%a6),%a0 + bras ovf_com +ovf_e1: + lea ETEMP(%a6),%a0 + +ovf_com: + bclrb #sign_bit,LOCAL_EX(%a0) + sne LOCAL_SGN(%a0) + + bsrl g_opcls |returns opclass in d0 + cmpiw #3,%d0 |check for opclass3 + bnes not_opc011 + +| +| FPSR_CC is saved and restored because ovf_r_x3 affects it. The +| CCs are defined to be 'not affected' for the opclass3 instruction. +| + moveb FPSR_CC(%a6),L_SCR1(%a6) + bsrl ovf_r_x3 |returns a0 pointing to result + moveb L_SCR1(%a6),FPSR_CC(%a6) + bral store |stores to memory or register + +not_opc011: + bsrl ovf_r_x2 |returns a0 pointing to result + bral store |stores to memory or register + + |end diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/x_snan.S linux/arch/m68k/fpsp040/x_snan.S --- v1.3.93/linux/arch/m68k/fpsp040/x_snan.S Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/fpsp040/x_snan.S Sat Feb 24 22:58:45 1996 @@ -0,0 +1,277 @@ +| +| x_snan.sa 3.3 7/1/91 +| +| fpsp_snan --- FPSP handler for signalling NAN exception +| +| SNAN for float -> integer conversions (integer conversion of +| an SNAN) is a non-maskable run-time exception. +| +| For trap disabled the 040 does the following: +| If the dest data format is s, d, or x, then the SNAN bit in the NAN +| is set to one and the resulting non-signaling NAN (truncated if +| necessary) is transferred to the dest. If the dest format is b, w, +| or l, then garbage is written to the dest (actually the upper 32 bits +| of the mantissa are sent to the integer unit). +| +| For trap enabled the 040 does the following: +| If the inst is move_out, then the results are the same as for trap +| disabled with the exception posted. If the instruction is not move_ +| out, the dest. is not modified, and the exception is posted. +| + +| Copyright (C) Motorola, Inc. 1990 +| All Rights Reserved +| +| THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA +| The copyright notice above does not evidence any +| actual or intended publication of such source code. + +X_SNAN: |idnt 2,1 | Motorola 040 Floating Point Software Package + + |section 8 + + .include "fpsp.h" + + |xref get_fline + |xref mem_write + |xref real_snan + |xref real_inex + |xref fpsp_done + |xref reg_dest + + .global fpsp_snan +fpsp_snan: + link %a6,#-LOCAL_SIZE + fsave -(%a7) + moveml %d0-%d1/%a0-%a1,USER_DA(%a6) + fmovemx %fp0-%fp3,USER_FP0(%a6) + fmoveml %fpcr/%fpsr/%fpiar,USER_FPCR(%a6) + +| +| Check if trap enabled +| + btstb #snan_bit,FPCR_ENABLE(%a6) + bnes ena |If enabled, then branch + + bsrl move_out |else SNAN disabled +| +| It is possible to have an inex1 exception with the +| snan. If the inex enable bit is set in the FPCR, and either +| inex2 or inex1 occured, we must clean up and branch to the +| real inex handler. +| +ck_inex: + moveb FPCR_ENABLE(%a6),%d0 + andb FPSR_EXCEPT(%a6),%d0 + andib #0x3,%d0 + beq end_snan +| +| Inexact enabled and reported, and we must take an inexact exception. +| +take_inex: + moveb #INEX_VEC,EXC_VEC+1(%a6) + moveml USER_DA(%a6),%d0-%d1/%a0-%a1 + fmovemx USER_FP0(%a6),%fp0-%fp3 + fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar + frestore (%a7)+ + unlk %a6 + bral real_inex +| +| SNAN is enabled. Check if inst is move_out. +| Make any corrections to the 040 output as necessary. +| +ena: + btstb #5,CMDREG1B(%a6) |if set, inst is move out + beq not_out + + bsrl move_out + +report_snan: + moveb (%a7),VER_TMP(%a6) + cmpib #VER_40,(%a7) |test for orig unimp frame + bnes ck_rev + moveql #13,%d0 |need to zero 14 lwords + bras rep_con +ck_rev: + moveql #11,%d0 |need to zero 12 lwords +rep_con: + clrl (%a7) +loop1: + clrl -(%a7) |clear and dec a7 + dbra %d0,loop1 + moveb VER_TMP(%a6),(%a7) |format a busy frame + moveb #BUSY_SIZE-4,1(%a7) + movel USER_FPSR(%a6),FPSR_SHADOW(%a6) + orl #sx_mask,E_BYTE(%a6) + moveml USER_DA(%a6),%d0-%d1/%a0-%a1 + fmovemx USER_FP0(%a6),%fp0-%fp3 + fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar + frestore (%a7)+ + unlk %a6 + bral real_snan +| +| Exit snan handler by expanding the unimp frame into a busy frame +| +end_snan: + bclrb #E1,E_BYTE(%a6) + + moveb (%a7),VER_TMP(%a6) + cmpib #VER_40,(%a7) |test for orig unimp frame + bnes ck_rev2 + moveql #13,%d0 |need to zero 14 lwords + bras rep_con2 +ck_rev2: + moveql #11,%d0 |need to zero 12 lwords +rep_con2: + clrl (%a7) +loop2: + clrl -(%a7) |clear and dec a7 + dbra %d0,loop2 + moveb VER_TMP(%a6),(%a7) |format a busy frame + moveb #BUSY_SIZE-4,1(%a7) |write busy size + movel USER_FPSR(%a6),FPSR_SHADOW(%a6) + orl #sx_mask,E_BYTE(%a6) + moveml USER_DA(%a6),%d0-%d1/%a0-%a1 + fmovemx USER_FP0(%a6),%fp0-%fp3 + fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar + frestore (%a7)+ + unlk %a6 + bral fpsp_done + +| +| Move_out +| +move_out: + movel EXC_EA(%a6),%a0 |get from exc frame + + bfextu CMDREG1B(%a6){#3:#3},%d0 |move rx field to d0{2:0} + cmpil #0,%d0 |check for long + beqs sto_long |branch if move_out long + + cmpil #4,%d0 |check for word + beqs sto_word |branch if move_out word + + cmpil #6,%d0 |check for byte + beqs sto_byte |branch if move_out byte + +| +| Not byte, word or long +| + rts +| +| Get the 32 most significant bits of etemp mantissa +| +sto_long: + movel ETEMP_HI(%a6),%d1 + movel #4,%d0 |load byte count +| +| Set signalling nan bit +| + bsetl #30,%d1 +| +| Store to the users destination address +| + tstl %a0 |check if is 0 + beqs wrt_dn |destination is a data register + + movel %d1,-(%a7) |move the snan onto the stack + movel %a0,%a1 |load dest addr into a1 + movel %a7,%a0 |load src addr of snan into a0 + bsrl mem_write |write snan to user memory + movel (%a7)+,%d1 |clear off stack + rts +| +| Get the 16 most significant bits of etemp mantissa +| +sto_word: + movel ETEMP_HI(%a6),%d1 + movel #2,%d0 |load byte count +| +| Set signalling nan bit +| + bsetl #30,%d1 +| +| Store to the users destination address +| + tstl %a0 |check if is 0 + beqs wrt_dn |destination is a data register + + movel %d1,-(%a7) |move the snan onto the stack + movel %a0,%a1 |load dest addr into a1 + movel %a7,%a0 |point to low word + bsrl mem_write |write snan to user memory + movel (%a7)+,%d1 |clear off stack + rts +| +| Get the 8 most significant bits of etemp mantissa +| +sto_byte: + movel ETEMP_HI(%a6),%d1 + movel #1,%d0 |load byte count +| +| Set signalling nan bit +| + bsetl #30,%d1 +| +| Store to the users destination address +| + tstl %a0 |check if is 0 + beqs wrt_dn |destination is a data register + movel %d1,-(%a7) |move the snan onto the stack + movel %a0,%a1 |load dest addr into a1 + movel %a7,%a0 |point to source byte + bsrl mem_write |write snan to user memory + movel (%a7)+,%d1 |clear off stack + rts + +| +| wrt_dn --- write to a data register +| +| We get here with D1 containing the data to write and D0 the +| number of bytes to write: 1=byte,2=word,4=long. +| +wrt_dn: + movel %d1,L_SCR1(%a6) |data + movel %d0,-(%a7) |size + bsrl get_fline |returns fline word in d0 + movel %d0,%d1 + andil #0x7,%d1 |d1 now holds register number + movel (%sp)+,%d0 |get original size + cmpil #4,%d0 + beqs wrt_long + cmpil #2,%d0 + bnes wrt_byte +wrt_word: + orl #0x8,%d1 + bral reg_dest +wrt_long: + orl #0x10,%d1 + bral reg_dest +wrt_byte: + bral reg_dest +| +| Check if it is a src nan or dst nan +| +not_out: + movel DTAG(%a6),%d0 + bfextu %d0{#0:#3},%d0 |isolate dtag in lsbs + + cmpib #3,%d0 |check for nan in destination + bnes issrc |destination nan has priority +dst_nan: + btstb #6,FPTEMP_HI(%a6) |check if dest nan is an snan + bnes issrc |no, so check source for snan + movew FPTEMP_EX(%a6),%d0 + bras cont +issrc: + movew ETEMP_EX(%a6),%d0 +cont: + btstl #15,%d0 |test for sign of snan + beqs clr_neg + bsetb #neg_bit,FPSR_CC(%a6) + bra report_snan +clr_neg: + bclrb #neg_bit,FPSR_CC(%a6) + bra report_snan + + |end diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/x_store.S linux/arch/m68k/fpsp040/x_store.S --- v1.3.93/linux/arch/m68k/fpsp040/x_store.S Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/fpsp040/x_store.S Sat Feb 24 22:58:45 1996 @@ -0,0 +1,256 @@ +| +| x_store.sa 3.2 1/24/91 +| +| store --- store operand to memory or register +| +| Used by underflow and overflow handlers. +| +| a6 = points to fp value to be stored. +| + +| Copyright (C) Motorola, Inc. 1990 +| All Rights Reserved +| +| THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA +| The copyright notice above does not evidence any +| actual or intended publication of such source code. + +X_STORE: |idnt 2,1 | Motorola 040 Floating Point Software Package + + |section 8 + +fpreg_mask: + .byte 0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01 + + .include "fpsp.h" + + |xref mem_write + |xref get_fline + |xref g_opcls + |xref g_dfmtou + |xref reg_dest + + .global dest_ext + .global dest_dbl + .global dest_sgl + + .global store +store: + btstb #E3,E_BYTE(%a6) + beqs E1_sto +E3_sto: + movel CMDREG3B(%a6),%d0 + bfextu %d0{#6:#3},%d0 |isolate dest. reg from cmdreg3b +sto_fp: + lea fpreg_mask,%a1 + moveb (%a1,%d0.w),%d0 |convert reg# to dynamic register mask + tstb LOCAL_SGN(%a0) + beqs is_pos + bsetb #sign_bit,LOCAL_EX(%a0) +is_pos: + fmovemx (%a0),%d0 |move to correct register +| +| if fp0-fp3 is being modified, we must put a copy +| in the USER_FPn variable on the stack because all exception +| handlers restore fp0-fp3 from there. +| + cmpb #0x80,%d0 + bnes not_fp0 + fmovemx %fp0-%fp0,USER_FP0(%a6) + rts +not_fp0: + cmpb #0x40,%d0 + bnes not_fp1 + fmovemx %fp1-%fp1,USER_FP1(%a6) + rts +not_fp1: + cmpb #0x20,%d0 + bnes not_fp2 + fmovemx %fp2-%fp2,USER_FP2(%a6) + rts +not_fp2: + cmpb #0x10,%d0 + bnes not_fp3 + fmovemx %fp3-%fp3,USER_FP3(%a6) + rts +not_fp3: + rts + +E1_sto: + bsrl g_opcls |returns opclass in d0 + cmpib #3,%d0 + beq opc011 |branch if opclass 3 + movel CMDREG1B(%a6),%d0 + bfextu %d0{#6:#3},%d0 |extract destination register + bras sto_fp + +opc011: + bsrl g_dfmtou |returns dest format in d0 +| ;ext=00, sgl=01, dbl=10 + movel %a0,%a1 |save source addr in a1 + movel EXC_EA(%a6),%a0 |get the address + cmpil #0,%d0 |if dest format is extended + beq dest_ext |then branch + cmpil #1,%d0 |if dest format is single + beqs dest_sgl |then branch +| +| fall through to dest_dbl +| + +| +| dest_dbl --- write double precision value to user space +| +|Input +| a0 -> destination address +| a1 -> source in extended precision +|Output +| a0 -> destroyed +| a1 -> destroyed +| d0 -> 0 +| +|Changes extended precision to double precision. +| Note: no attempt is made to round the extended value to double. +| dbl_sign = ext_sign +| dbl_exp = ext_exp - $3fff(ext bias) + $7ff(dbl bias) +| get rid of ext integer bit +| dbl_mant = ext_mant{62:12} +| +| --------------- --------------- --------------- +| extended -> |s| exp | |1| ms mant | | ls mant | +| --------------- --------------- --------------- +| 95 64 63 62 32 31 11 0 +| | | +| | | +| | | +| v v +| --------------- --------------- +| double -> |s|exp| mant | | mant | +| --------------- --------------- +| 63 51 32 31 0 +| +dest_dbl: + clrl %d0 |clear d0 + movew LOCAL_EX(%a1),%d0 |get exponent + subw #0x3fff,%d0 |subtract extended precision bias + cmpw #0x4000,%d0 |check if inf + beqs inf |if so, special case + addw #0x3ff,%d0 |add double precision bias + swap %d0 |d0 now in upper word + lsll #4,%d0 |d0 now in proper place for dbl prec exp + tstb LOCAL_SGN(%a1) + beqs get_mant |if postive, go process mantissa + bsetl #31,%d0 |if negative, put in sign information +| ; before continuing + bras get_mant |go process mantissa +inf: + movel #0x7ff00000,%d0 |load dbl inf exponent + clrl LOCAL_HI(%a1) |clear msb + tstb LOCAL_SGN(%a1) + beqs dbl_inf |if positive, go ahead and write it + bsetl #31,%d0 |if negative put in sign information +dbl_inf: + movel %d0,LOCAL_EX(%a1) |put the new exp back on the stack + bras dbl_wrt +get_mant: + movel LOCAL_HI(%a1),%d1 |get ms mantissa + bfextu %d1{#1:#20},%d1 |get upper 20 bits of ms + orl %d1,%d0 |put these bits in ms word of double + movel %d0,LOCAL_EX(%a1) |put the new exp back on the stack + movel LOCAL_HI(%a1),%d1 |get ms mantissa + movel #21,%d0 |load shift count + lsll %d0,%d1 |put lower 11 bits in upper bits + movel %d1,LOCAL_HI(%a1) |build lower lword in memory + movel LOCAL_LO(%a1),%d1 |get ls mantissa + bfextu %d1{#0:#21},%d0 |get ls 21 bits of double + orl %d0,LOCAL_HI(%a1) |put them in double result +dbl_wrt: + movel #0x8,%d0 |byte count for double precision number + exg %a0,%a1 |a0=supervisor source, a1=user dest + bsrl mem_write |move the number to the user's memory + rts +| +| dest_sgl --- write single precision value to user space +| +|Input +| a0 -> destination address +| a1 -> source in extended precision +| +|Output +| a0 -> destroyed +| a1 -> destroyed +| d0 -> 0 +| +|Changes extended precision to single precision. +| sgl_sign = ext_sign +| sgl_exp = ext_exp - $3fff(ext bias) + $7f(sgl bias) +| get rid of ext integer bit +| sgl_mant = ext_mant{62:12} +| +| --------------- --------------- --------------- +| extended -> |s| exp | |1| ms mant | | ls mant | +| --------------- --------------- --------------- +| 95 64 63 62 40 32 31 12 0 +| | | +| | | +| | | +| v v +| --------------- +| single -> |s|exp| mant | +| --------------- +| 31 22 0 +| +dest_sgl: + clrl %d0 + movew LOCAL_EX(%a1),%d0 |get exponent + subw #0x3fff,%d0 |subtract extended precision bias + cmpw #0x4000,%d0 |check if inf + beqs sinf |if so, special case + addw #0x7f,%d0 |add single precision bias + swap %d0 |put exp in upper word of d0 + lsll #7,%d0 |shift it into single exp bits + tstb LOCAL_SGN(%a1) + beqs get_sman |if positive, continue + bsetl #31,%d0 |if negative, put in sign first + bras get_sman |get mantissa +sinf: + movel #0x7f800000,%d0 |load single inf exp to d0 + tstb LOCAL_SGN(%a1) + beqs sgl_wrt |if positive, continue + bsetl #31,%d0 |if negative, put in sign info + bras sgl_wrt + +get_sman: + movel LOCAL_HI(%a1),%d1 |get ms mantissa + bfextu %d1{#1:#23},%d1 |get upper 23 bits of ms + orl %d1,%d0 |put these bits in ms word of single + +sgl_wrt: + movel %d0,L_SCR1(%a6) |put the new exp back on the stack + movel #0x4,%d0 |byte count for single precision number + tstl %a0 |users destination address + beqs sgl_Dn |destination is a data register + exg %a0,%a1 |a0=supervisor source, a1=user dest + leal L_SCR1(%a6),%a0 |point a0 to data + bsrl mem_write |move the number to the user's memory + rts +sgl_Dn: + bsrl get_fline |returns fline word in d0 + andw #0x7,%d0 |isolate register number + movel %d0,%d1 |d1 has size:reg formatted for reg_dest + orl #0x10,%d1 |reg_dest wants size added to reg# + bral reg_dest |size is X, rts in reg_dest will +| ;return to caller of dest_sgl + +dest_ext: + tstb LOCAL_SGN(%a1) |put back sign into exponent word + beqs dstx_cont + bsetb #sign_bit,LOCAL_EX(%a1) +dstx_cont: + clrb LOCAL_SGN(%a1) |clear out the sign byte + + movel #0x0c,%d0 |byte count for extended number + exg %a0,%a1 |a0=supervisor source, a1=user dest + bsrl mem_write |move the number to the user's memory + rts + + |end diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/x_unfl.S linux/arch/m68k/fpsp040/x_unfl.S --- v1.3.93/linux/arch/m68k/fpsp040/x_unfl.S Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/fpsp040/x_unfl.S Sat Feb 24 22:58:45 1996 @@ -0,0 +1,269 @@ +| +| x_unfl.sa 3.4 7/1/91 +| +| fpsp_unfl --- FPSP handler for underflow exception +| +| Trap disabled results +| For 881/2 compatibility, sw must denormalize the intermediate +| result, then store the result. Denormalization is accomplished +| by taking the intermediate result (which is always normalized) and +| shifting the mantissa right while incrementing the exponent until +| it is equal to the denormalized exponent for the destination +| format. After denormalizatoin, the result is rounded to the +| destination format. +| +| Trap enabled results +| All trap disabled code applies. In addition the exceptional +| operand needs to made available to the user with a bias of $6000 +| added to the exponent. +| + +| Copyright (C) Motorola, Inc. 1990 +| All Rights Reserved +| +| THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA +| The copyright notice above does not evidence any +| actual or intended publication of such source code. + +X_UNFL: |idnt 2,1 | Motorola 040 Floating Point Software Package + + |section 8 + + .include "fpsp.h" + + |xref denorm + |xref round + |xref store + |xref g_rndpr + |xref g_opcls + |xref g_dfmtou + |xref real_unfl + |xref real_inex + |xref fpsp_done + |xref b1238_fix + + .global fpsp_unfl +fpsp_unfl: + link %a6,#-LOCAL_SIZE + fsave -(%a7) + moveml %d0-%d1/%a0-%a1,USER_DA(%a6) + fmovemx %fp0-%fp3,USER_FP0(%a6) + fmoveml %fpcr/%fpsr/%fpiar,USER_FPCR(%a6) + +| + bsrl unf_res |denormalize, round & store interm op +| +| If underflow exceptions are not enabled, check for inexact +| exception +| + btstb #unfl_bit,FPCR_ENABLE(%a6) + beqs ck_inex + + btstb #E3,E_BYTE(%a6) + beqs no_e3_1 +| +| Clear dirty bit on dest resister in the frame before branching +| to b1238_fix. +| + bfextu CMDREG3B(%a6){#6:#3},%d0 |get dest reg no + bclrb %d0,FPR_DIRTY_BITS(%a6) |clr dest dirty bit + bsrl b1238_fix |test for bug1238 case + movel USER_FPSR(%a6),FPSR_SHADOW(%a6) + orl #sx_mask,E_BYTE(%a6) +no_e3_1: + moveml USER_DA(%a6),%d0-%d1/%a0-%a1 + fmovemx USER_FP0(%a6),%fp0-%fp3 + fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar + frestore (%a7)+ + unlk %a6 + bral real_unfl +| +| It is possible to have either inex2 or inex1 exceptions with the +| unfl. If the inex enable bit is set in the FPCR, and either +| inex2 or inex1 occured, we must clean up and branch to the +| real inex handler. +| +ck_inex: + moveb FPCR_ENABLE(%a6),%d0 + andb FPSR_EXCEPT(%a6),%d0 + andib #0x3,%d0 + beqs unfl_done + +| +| Inexact enabled and reported, and we must take an inexact exception +| +take_inex: + btstb #E3,E_BYTE(%a6) + beqs no_e3_2 +| +| Clear dirty bit on dest resister in the frame before branching +| to b1238_fix. +| + bfextu CMDREG3B(%a6){#6:#3},%d0 |get dest reg no + bclrb %d0,FPR_DIRTY_BITS(%a6) |clr dest dirty bit + bsrl b1238_fix |test for bug1238 case + movel USER_FPSR(%a6),FPSR_SHADOW(%a6) + orl #sx_mask,E_BYTE(%a6) +no_e3_2: + moveb #INEX_VEC,EXC_VEC+1(%a6) + moveml USER_DA(%a6),%d0-%d1/%a0-%a1 + fmovemx USER_FP0(%a6),%fp0-%fp3 + fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar + frestore (%a7)+ + unlk %a6 + bral real_inex + +unfl_done: + bclrb #E3,E_BYTE(%a6) + beqs e1_set |if set then branch +| +| Clear dirty bit on dest resister in the frame before branching +| to b1238_fix. +| + bfextu CMDREG3B(%a6){#6:#3},%d0 |get dest reg no + bclrb %d0,FPR_DIRTY_BITS(%a6) |clr dest dirty bit + bsrl b1238_fix |test for bug1238 case + movel USER_FPSR(%a6),FPSR_SHADOW(%a6) + orl #sx_mask,E_BYTE(%a6) + moveml USER_DA(%a6),%d0-%d1/%a0-%a1 + fmovemx USER_FP0(%a6),%fp0-%fp3 + fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar + frestore (%a7)+ + unlk %a6 + bral fpsp_done +e1_set: + moveml USER_DA(%a6),%d0-%d1/%a0-%a1 + fmovemx USER_FP0(%a6),%fp0-%fp3 + fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar + unlk %a6 + bral fpsp_done +| +| unf_res --- underflow result calculation +| +unf_res: + bsrl g_rndpr |returns RND_PREC in d0 0=ext, +| ;1=sgl, 2=dbl +| ;we need the RND_PREC in the +| ;upper word for round + movew #0,-(%a7) + movew %d0,-(%a7) |copy RND_PREC to stack +| +| +| If the exception bit set is E3, the exceptional operand from the +| fpu is in WBTEMP; else it is in FPTEMP. +| + btstb #E3,E_BYTE(%a6) + beqs unf_E1 +unf_E3: + lea WBTEMP(%a6),%a0 |a0 now points to operand +| +| Test for fsgldiv and fsglmul. If the inst was one of these, then +| force the precision to extended for the denorm routine. Use +| the user's precision for the round routine. +| + movew CMDREG3B(%a6),%d1 |check for fsgldiv or fsglmul + andiw #0x7f,%d1 + cmpiw #0x30,%d1 |check for sgldiv + beqs unf_sgl + cmpiw #0x33,%d1 |check for sglmul + bnes unf_cont |if not, use fpcr prec in round +unf_sgl: + clrl %d0 + movew #0x1,(%a7) |override g_rndpr precision +| ;force single + bras unf_cont +unf_E1: + lea FPTEMP(%a6),%a0 |a0 now points to operand +unf_cont: + bclrb #sign_bit,LOCAL_EX(%a0) |clear sign bit + sne LOCAL_SGN(%a0) |store sign + + bsrl denorm |returns denorm, a0 points to it +| +| WARNING: +| ;d0 has guard,round sticky bit +| ;make sure that it is not corrupted +| ;before it reaches the round subroutine +| ;also ensure that a0 isn't corrupted + +| +| Set up d1 for round subroutine d1 contains the PREC/MODE +| information respectively on upper/lower register halves. +| + bfextu FPCR_MODE(%a6){#2:#2},%d1 |get mode from FPCR +| ;mode in lower d1 + addl (%a7)+,%d1 |merge PREC/MODE +| +| WARNING: a0 and d0 are assumed to be intact between the denorm and +| round subroutines. All code between these two subroutines +| must not corrupt a0 and d0. +| +| +| Perform Round +| Input: a0 points to input operand +| d0{31:29} has guard, round, sticky +| d1{01:00} has rounding mode +| d1{17:16} has rounding precision +| Output: a0 points to rounded operand +| + + bsrl round |returns rounded denorm at (a0) +| +| Differentiate between store to memory vs. store to register +| +unf_store: + bsrl g_opcls |returns opclass in d0{2:0} + cmpib #0x3,%d0 + bnes not_opc011 +| +| At this point, a store to memory is pending +| +opc011: + bsrl g_dfmtou + tstb %d0 + beqs ext_opc011 |If extended, do not subtract +| ;If destination format is sgl/dbl, + tstb LOCAL_HI(%a0) |If rounded result is normal,don't +| ;subtract + bmis ext_opc011 + subqw #1,LOCAL_EX(%a0) |account for denorm bias vs. +| ;normalized bias +| ; normalized denormalized +| ;single $7f $7e +| ;double $3ff $3fe +| +ext_opc011: + bsrl store |stores to memory + bras unf_done |finish up + +| +| At this point, a store to a float register is pending +| +not_opc011: + bsrl store |stores to float register +| ;a0 is not corrupted on a store to a +| ;float register. +| +| Set the condition codes according to result +| + tstl LOCAL_HI(%a0) |check upper mantissa + bnes ck_sgn + tstl LOCAL_LO(%a0) |check lower mantissa + bnes ck_sgn + bsetb #z_bit,FPSR_CC(%a6) |set condition codes if zero +ck_sgn: + btstb #sign_bit,LOCAL_EX(%a0) |check the sign bit + beqs unf_done + bsetb #neg_bit,FPSR_CC(%a6) + +| +| Finish. +| +unf_done: + btstb #inex2_bit,FPSR_EXCEPT(%a6) + beqs no_aunfl + bsetb #aunfl_bit,FPSR_AEXCEPT(%a6) +no_aunfl: + rts + + |end diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/x_unimp.S linux/arch/m68k/fpsp040/x_unimp.S --- v1.3.93/linux/arch/m68k/fpsp040/x_unimp.S Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/fpsp040/x_unimp.S Sat Feb 24 22:58:45 1996 @@ -0,0 +1,77 @@ +| +| x_unimp.sa 3.3 7/1/91 +| +| fpsp_unimp --- FPSP handler for unimplemented instruction +| exception. +| +| Invoked when the user program encounters a floating-point +| op-code that hardware does not support. Trap vector# 11 +| (See table 8-1 MC68030 User's Manual). +| +| +| Note: An fsave for an unimplemented inst. will create a short +| fsave stack. +| +| Input: 1. Six word stack frame for unimplemented inst, four word +| for illegal +| (See table 8-7 MC68030 User's Manual). +| 2. Unimp (short) fsave state frame created here by fsave +| instruction. +| +| +| Copyright (C) Motorola, Inc. 1990 +| All Rights Reserved +| +| THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA +| The copyright notice above does not evidence any +| actual or intended publication of such source code. + +X_UNIMP: |idnt 2,1 | Motorola 040 Floating Point Software Package + + |section 8 + + .include "fpsp.h" + + |xref get_op + |xref do_func + |xref sto_res + |xref gen_except + |xref fpsp_fmt_error + + .global fpsp_unimp + .global uni_2 +fpsp_unimp: + link %a6,#-LOCAL_SIZE + fsave -(%a7) +uni_2: + moveml %d0-%d1/%a0-%a1,USER_DA(%a6) + fmovemx %fp0-%fp3,USER_FP0(%a6) + fmoveml %fpcr/%fpsr/%fpiar,USER_FPCR(%a6) + moveb (%a7),%d0 |test for valid version num + andib #0xf0,%d0 |test for $4x + cmpib #VER_4,%d0 |must be $4x or exit + bnel fpsp_fmt_error +| +| Temporary D25B Fix +| The following lines are used to ensure that the FPSR +| exception byte and condition codes are clear before proceeding +| + movel USER_FPSR(%a6),%d0 + andl #0xFF00FF,%d0 |clear all but accrued exceptions + movel %d0,USER_FPSR(%a6) + fmovel #0,%FPSR |clear all user bits + fmovel #0,%FPCR |clear all user exceptions for FPSP + + clrb UFLG_TMP(%a6) |clr flag for unsupp data + + bsrl get_op |go get operand(s) + clrb STORE_FLG(%a6) + bsrl do_func |do the function + fsave -(%a7) |capture possible exc state + tstb STORE_FLG(%a6) + bnes no_store |if STORE_FLG is set, no store + bsrl sto_res |store the result in user space +no_store: + bral gen_except |post any exceptions and return + + |end diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/x_unsupp.S linux/arch/m68k/fpsp040/x_unsupp.S --- v1.3.93/linux/arch/m68k/fpsp040/x_unsupp.S Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/fpsp040/x_unsupp.S Sat Feb 24 22:58:45 1996 @@ -0,0 +1,83 @@ +| +| x_unsupp.sa 3.3 7/1/91 +| +| fpsp_unsupp --- FPSP handler for unsupported data type exception +| +| Trap vector #55 (See table 8-1 Mc68030 User's manual). +| Invoked when the user program encounters a data format (packed) that +| hardware does not support or a data type (denormalized numbers or un- +| normalized numbers). +| Normalizes denorms and unnorms, unpacks packed numbers then stores +| them back into the machine to let the 040 finish the operation. +| +| Unsupp calls two routines: +| 1. get_op - gets the operand(s) +| 2. res_func - restore the function back into the 040 or +| if fmove.p fpm, then pack source (fpm) +| and store in users memory . +| +| Input: Long fsave stack frame +| +| + +| Copyright (C) Motorola, Inc. 1990 +| All Rights Reserved +| +| THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA +| The copyright notice above does not evidence any +| actual or intended publication of such source code. + +X_UNSUPP: |idnt 2,1 | Motorola 040 Floating Point Software Package + + |section 8 + + .include "fpsp.h" + + |xref get_op + |xref res_func + |xref gen_except + |xref fpsp_fmt_error + + .global fpsp_unsupp +fpsp_unsupp: +| + link %a6,#-LOCAL_SIZE + fsave -(%a7) + moveml %d0-%d1/%a0-%a1,USER_DA(%a6) + fmovemx %fp0-%fp3,USER_FP0(%a6) + fmoveml %fpcr/%fpsr/%fpiar,USER_FPCR(%a6) + + + moveb (%a7),VER_TMP(%a6) |save version number + moveb (%a7),%d0 |test for valid version num + andib #0xf0,%d0 |test for $4x + cmpib #VER_4,%d0 |must be $4x or exit + bnel fpsp_fmt_error + + fmovel #0,%FPSR |clear all user status bits + fmovel #0,%FPCR |clear all user control bits +| +| The following lines are used to ensure that the FPSR +| exception byte and condition codes are clear before proceeding, +| except in the case of fmove, which leaves the cc's intact. +| +unsupp_con: + movel USER_FPSR(%a6),%d1 + btst #5,CMDREG1B(%a6) |looking for fmove out + bne fmove_con + andl #0xFF00FF,%d1 |clear all but aexcs and qbyte + bras end_fix +fmove_con: + andl #0x0FFF40FF,%d1 |clear all but cc's, snan bit, aexcs, and qbyte +end_fix: + movel %d1,USER_FPSR(%a6) + + st UFLG_TMP(%a6) |set flag for unsupp data + + bsrl get_op |everything okay, go get operand(s) + bsrl res_func |fix up stack frame so can restore it + clrl -(%a7) + moveb VER_TMP(%a6),(%a7) |move idle fmt word to top of stack + bral gen_except +| + |end diff -u --recursive --new-file v1.3.93/linux/arch/m68k/ifpsp060/CHANGES linux/arch/m68k/ifpsp060/CHANGES --- v1.3.93/linux/arch/m68k/ifpsp060/CHANGES Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/ifpsp060/CHANGES Mon Jan 8 22:08:12 1996 @@ -0,0 +1,120 @@ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP +M68000 Hi-Performance Microprocessor Division +M68060 Software Package +Production Release P1.00 -- October 10, 1994 + +M68060 Software Package Copyright © 1993, 1994 Motorola Inc. All rights reserved. + +THE SOFTWARE is provided on an "AS IS" basis and without warranty. +To the maximum extent permitted by applicable law, +MOTOROLA DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED, +INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE +and any warranty against infringement with regard to the SOFTWARE +(INCLUDING ANY MODIFIED VERSIONS THEREOF) and any accompanying written materials. + +To the maximum extent permitted by applicable law, +IN NO EVENT SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER +(INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, +BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY LOSS) +ARISING OF THE USE OR INABILITY TO USE THE SOFTWARE. +Motorola assumes no responsibility for the maintenance and support of the SOFTWARE. + +You are hereby granted a copyright license to use, modify, and distribute the SOFTWARE +so long as this entire notice is retained without alteration in any modified and/or +redistributed versions, and that such modified versions are clearly identified as such. +No licenses are granted by implication, estoppel or otherwise under any patents +or trademarks of Motorola, Inc. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +CHANGES SINCE LAST RELEASE: +--------------------------- + +1) "movep" emulation where data was being read from memory +was reading the intermediate bytes. Emulation now only +reads the required bytes. + +2) "flogn", "flog2", and "flog10" of "1" was setting the +Inexact FPSR bit. Emulation now does not set Inexact for +this case. + +3) For an opclass three FP instruction where the effective addressing +mode was pre-decrement or post-increment and the address register +was A0 or A1, the address register was not being updated as a result +of the operation. This has been corrected. + +4) Beta B.2 version had the following erratum: + + Scenario: + --------- + If {i,d}mem_{read,write}_{byte,word,long}() returns + a failing value to the 68060SP, the package ignores + this return value and continues with program execution + as if it never received a failing value. + + Effect: + ------- + For example, if a user executed "fsin.x ADDR,fp0" where + ADDR should cause a "segmentation violation", the memory read + requested by the package should return a failing value + to the package. Since the package currently ignores this + return value, the user program will continue to the + next instruction, and the result created in fp0 will be + undefined. + + Fix: + ---- + This has been fixed in the current release. + + Notes: + ------ + Upon receiving a non-zero (failing) return value from + a {i,d}mem_{read,write}_{byte,word,long}() "call-out", + the package creates a 16-byte access error stack frame + from the current exception stack frame and exits + through the "call-out" _real_access(). This is the process + as described in the MC68060 User's Manual. + + For instruction read access errors, the info stacked is: + SR = SR at time of exception + PC = PC of instruction being emulated + VOFF = $4008 (stack frame format type) + ADDRESS = PC of instruction being emulated + FSLW = FAULT STATUS LONGWORD + + The valid FSLW bits are: + bit 27 = 1 (misaligned bit) + bit 24 = 1 (read) + bit 23 = 0 (write) + bit 22:21 = 10 (SIZE = word) + bit 20:19 = 00 (TT) + bit 18:16 = x10 (TM; x = 1 for supervisor mode) + bit 15 = 1 (IO) + bit 0 = 1 (Software Emulation Error) + + all other bits are EQUAL TO ZERO and can be set by the _real_access() + "call-out" stub by the user as appropriate. The MC68060 User's Manual + stated that ONLY "bit 0" would be set. The 060SP attempts to set a few + other bits. + + For data read/write access errors, the info stacked is: + SR = SR at time of exception + PC = PC of instruction being emulated + VOFF = $4008 (stack frame format type) + ADDRESS = Address of source or destination operand + FSLW = FAULT STATUS LONGWORD + + The valid FSLW bits are: + bit 27 = 0 (misaligned bit) + bit 24 = x (read; 1 if read, 0 if write) + bit 23 = x (write; 1 if write, 0 if read) + bit 22:21 = xx (SIZE; see MC68060 User's Manual) + bit 20:19 = 00 (TT) + bit 18:16 = x01 (TM; x = 1 for supervisor mode) + bit 15 = 0 (IO) + bit 0 = 1 (Software Emulation Error) + + all other bits are EQUAL TO ZERO and can be set by the _real_access() + "call-out" stub by the user as appropriate. The MC68060 User's Manual + stated that ONLY "bit 0" would be set. The 060SP attempts to set a few + other bits. diff -u --recursive --new-file v1.3.93/linux/arch/m68k/ifpsp060/MISC linux/arch/m68k/ifpsp060/MISC --- v1.3.93/linux/arch/m68k/ifpsp060/MISC Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/ifpsp060/MISC Mon Jan 8 22:08:12 1996 @@ -0,0 +1,201 @@ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP +M68000 Hi-Performance Microprocessor Division +M68060 Software Package +Production Release P1.00 -- October 10, 1994 + +M68060 Software Package Copyright © 1993, 1994 Motorola Inc. All rights reserved. + +THE SOFTWARE is provided on an "AS IS" basis and without warranty. +To the maximum extent permitted by applicable law, +MOTOROLA DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED, +INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE +and any warranty against infringement with regard to the SOFTWARE +(INCLUDING ANY MODIFIED VERSIONS THEREOF) and any accompanying written materials. + +To the maximum extent permitted by applicable law, +IN NO EVENT SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER +(INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, +BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY LOSS) +ARISING OF THE USE OR INABILITY TO USE THE SOFTWARE. +Motorola assumes no responsibility for the maintenance and support of the SOFTWARE. + +You are hereby granted a copyright license to use, modify, and distribute the SOFTWARE +so long as this entire notice is retained without alteration in any modified and/or +redistributed versions, and that such modified versions are clearly identified as such. +No licenses are granted by implication, estoppel or otherwise under any patents +or trademarks of Motorola, Inc. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +RELEASE FILE VERSIONS: +----------------------- + +fpsp.sa +---------- +freal.s : 2.4 +hdr.fpu : 2.4 +x_fovfl.s : 2.16 +x_funfl.s : 2.19 +x_funsupp.s : 2.27 +x_effadd.s : 2.21 +x_foperr.s : 2.9 +x_fsnan.s : 2.12 +x_finex.s : 2.14 +x_fdz.s : 2.5 +x_fline.s : 2.5 +x_funimp.s : 2.27 +fsin.s : 2.6 +ftan.s : 2.6 +fatan.s : 2.3 +fasin.s : 2.3 +facos.s : 2.5 +fetox.s : 2.4 +fgetem.s : 2.5 +fcosh.s : 2.4 +fsinh.s : 2.5 +ftanh.s : 2.3 +flogn.s : 2.6 +fatanh.s : 2.4 +flog2.s : 2.4 +ftwotox.s : 2.4 +fmovecr.s : 2.5 +fscale.s : 2.5 +frem_mod.s : 2.6 +fkern.s : 2.6 +fkern2.s : 2.5 +fgen_except.s: 2.7 +foptbl.s : 2.3 +fmul.s : 2.5 +fin.s : 2.4 +fdiv.s : 2.5 +fneg.s : 2.4 +ftst.s : 2.3 +fint.s : 2.3 +fintrz.s : 2.3 +fabs.s : 2.4 +fcmp.s : 2.4 +fsglmul.s : 2.5 +fsgldiv.s : 2.8 +fadd.s : 2.6 +fsub.s : 2.6 +fsqrt.s : 2.4 +fmisc.s : 2.3 +fdbcc.s : 2.8 +ftrapcc.s : 2.5 +fscc.s : 2.6 +fmovm.s : 2.15 +fctrl.s : 2.6 +fcalc_ea.s : 2.7 +fmem.s : 2.9 +fout.s : 2.9 +ireg.s : 2.6 +fdenorm.s : 2.3 +fround.s : 2.4 +fnorm.s : 2.3 +foptag_set.s: 2.4 +fresult.s : 2.3 +fpack.s : 2.6 +fdecbin.s : 2.4 +fbindec.s : 2.5 +fbinstr.s : 2.3 +faccess.s : 2.3 + +pfpsp.sa +---------- +freal.s : 2.4 +hdr.fpu : 2.4 +x_fovfl.s : 2.16 +x_funfl.s : 2.19 +x_funsupp.s : 2.27 +x_effadd.s : 2.21 +x_foperr.s : 2.9 +x_fsnan.s : 2.12 +x_finex.s : 2.14 +x_fdz.s : 2.5 +x_fline2.s : 2.3 +fcalc_ea.s : 2.7 +foptbl2.s : 2.4 +fmovm.s : 2.15 +fctrl.s : 2.6 +fmisc.s : 2.3 +fdenorm.s : 2.3 +fround.s : 2.4 +fnorm.s : 2.3 +foptag_set.s: 2.4 +fresult.s : 2.3 +fout.s : 2.9 +fmul.s : 2.5 +fin.s : 2.4 +fdiv.s : 2.5 +fneg.s : 2.4 +ftst.s : 2.3 +fint.s : 2.3 +fintrz.s : 2.3 +fabs.s : 2.4 +fcmp.s : 2.4 +fsglmul.s : 2.5 +fsgldiv.s : 2.8 +fadd.s : 2.6 +fsub.s : 2.6 +fsqrt.s : 2.4 +ireg.s : 2.6 +fpack.s : 2.6 +fdecbin.s : 2.4 +fbindec.s : 2.5 +fbinstr.s : 2.3 +faccess.s : 2.3 + +fplsp.sa +---------- +lfptop.s : 2.3 +hdr.fpu : 2.4 +fsin.s : 2.6 +ftan.s : 2.6 +fatan.s : 2.3 +fasin.s : 2.3 +facos.s : 2.5 +fetox.s : 2.4 +fgetem.s : 2.5 +fcosh.s : 2.4 +fsinh.s : 2.5 +ftanh.s : 2.3 +flogn.s : 2.6 +fatanh.s : 2.4 +flog2.s : 2.4 +ftwotox.s : 2.4 +fscale.s : 2.5 +frem_mod.s : 2.6 +l_support.s : 2.15 +fnorm.s : 2.3 + +isp.sa +---------- +ireal.s : 2.4 +hdr.int : 2.4 +x_uieh.s : 2.13 +icalc_ea.s : 2.11 +imovep.s : 2.8 +ichk2cmp2.s : 2.6 +idiv64.s : 2.10 +imul64.s : +icas2.s : 2.11 +icas.s : 2.12 +icas2_core.s: 2.6 +icas_core.s : 2.6 + +ilsp.sa +---------- +litop.s : 2.2 +l_idiv64.s : 2.8 +l_imul64.s : 2.6 +l_ichk2cmp2.s: 2.5 + +ex. files +---------- +wrk/fskeleton.s: 2.2 +wrk/iskeleton.s: 2.2 +wrk/os.s : 2.1 + +tests +---------- +itest.s : 2.2 +ftest.s : 2.1 diff -u --recursive --new-file v1.3.93/linux/arch/m68k/ifpsp060/Makefile linux/arch/m68k/ifpsp060/Makefile --- v1.3.93/linux/arch/m68k/ifpsp060/Makefile Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/ifpsp060/Makefile Sat Feb 24 14:51:12 1996 @@ -0,0 +1,28 @@ +# Makefile for 680x0 Linux 68060 integer/floating point support package +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "README.legal" in the main directory of this archive +# for more details. + +#.c.s: +# $(CC) $(CFLAGS) -S $< +#.c.o: +# $(CC) $(CFLAGS) -c $< +#.s.o: +# $(AS) -o $*.o $< +.S.o: + $(AS) -o $*.o $< +# $(CC) -D__ASSEMBLY__ -traditional -c -o $*.o $< + +OS_TARGET := ifpsp.o + +OS_OBJS := fskeleton.o iskeleton.o os.o + +all: $(OS_TARGET) + +include $(TOPDIR)/Rules.make + +$(OS_OBJS): + +$(OS_TARGET): $(OS_OBJS) + $(LD) -x -r -o $(OS_TARGET) $(OS_OBJS) diff -u --recursive --new-file v1.3.93/linux/arch/m68k/ifpsp060/README linux/arch/m68k/ifpsp060/README --- v1.3.93/linux/arch/m68k/ifpsp060/README Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/ifpsp060/README Mon Jan 8 22:08:13 1996 @@ -0,0 +1,71 @@ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP +M68000 Hi-Performance Microprocessor Division +M68060 Software Package +Production Release P1.00 -- October 10, 1994 + +M68060 Software Package Copyright © 1993, 1994 Motorola Inc. All rights reserved. + +THE SOFTWARE is provided on an "AS IS" basis and without warranty. +To the maximum extent permitted by applicable law, +MOTOROLA DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED, +INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE +and any warranty against infringement with regard to the SOFTWARE +(INCLUDING ANY MODIFIED VERSIONS THEREOF) and any accompanying written materials. + +To the maximum extent permitted by applicable law, +IN NO EVENT SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER +(INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, +BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY LOSS) +ARISING OF THE USE OR INABILITY TO USE THE SOFTWARE. +Motorola assumes no responsibility for the maintenance and support of the SOFTWARE. + +You are hereby granted a copyright license to use, modify, and distribute the SOFTWARE +so long as this entire notice is retained without alteration in any modified and/or +redistributed versions, and that such modified versions are clearly identified as such. +No licenses are granted by implication, estoppel or otherwise under any patents +or trademarks of Motorola, Inc. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Files in this directory: +------------------------- + +fpsp.sa Full FP Kernel Module - hex image +fpsp.s Full FP Kernel Module - source code +fpsp.doc Full FP Kernel Module - on-line documentation + +pfpsp.sa Partial FP Kernel Module - hex image +pfpsp.s Partial FP Kernel Module - source code + +fplsp.sa FP Library Module - hex image +fplsp.s FP Library Module - source code +fplsp.doc FP Library Module - on-line documentation + +isp.sa Integer Unimplemented Kernel Module - hex image +isp.s Integer Unimplemented Kernel Module - source code +isp.doc Integer Unimplemented Kernel Module - on-line doc + +ilsp.sa Integer Unimplemented Library Module - hex image +ilsp.s Integer Unimplemented Library Module - source code +ilsp.doc Integer Unimplemented Library Module - on-line doc + +fskeleton.s Sample Call-outs needed by fpsp.sa and pfpsp.sa + +iskeleton.s Sample Call-outs needed by isp.sa + +os.s Sample Call-outs needed by fpsp.sa, pfpsp.sa, and isp.sa + +ftest.sa Simple test program to test that {p}fpsp.sa + was connected properly; hex image +ftest.s above test; source code + +itest.sa Simple test program to test that isp.sa was + connected properly; hex image +itest.s above test; source code + +test.doc on-line documentation for {i,f}test.sa + +README This file + +ERRATA Known errata for this release + +MISC Release file version numbers diff -u --recursive --new-file v1.3.93/linux/arch/m68k/ifpsp060/TEST.DOC linux/arch/m68k/ifpsp060/TEST.DOC --- v1.3.93/linux/arch/m68k/ifpsp060/TEST.DOC Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/ifpsp060/TEST.DOC Mon Jan 8 22:08:13 1996 @@ -0,0 +1,208 @@ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP +M68000 Hi-Performance Microprocessor Division +M68060 Software Package +Production Release P1.00 -- October 10, 1994 + +M68060 Software Package Copyright © 1993, 1994 Motorola Inc. All rights reserved. + +THE SOFTWARE is provided on an "AS IS" basis and without warranty. +To the maximum extent permitted by applicable law, +MOTOROLA DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED, +INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE +and any warranty against infringement with regard to the SOFTWARE +(INCLUDING ANY MODIFIED VERSIONS THEREOF) and any accompanying written materials. + +To the maximum extent permitted by applicable law, +IN NO EVENT SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER +(INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, +BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY LOSS) +ARISING OF THE USE OR INABILITY TO USE THE SOFTWARE. +Motorola assumes no responsibility for the maintenance and support of the SOFTWARE. + +You are hereby granted a copyright license to use, modify, and distribute the SOFTWARE +so long as this entire notice is retained without alteration in any modified and/or +redistributed versions, and that such modified versions are clearly identified as such. +No licenses are granted by implication, estoppel or otherwise under any patents +or trademarks of Motorola, Inc. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +68060 SOFTWARE PACKAGE (Kernel version) SIMPLE TESTS +----------------------------------------------------- + +The files itest.sa and ftest.sa contain simple tests to check +the state of the 68060ISP and 68060FPSP once they have been installed. + +Release file format: +-------------------- +The release files itest.sa and ftest.sa are essentially +hexadecimal images of the actual tests. This format is the +ONLY format that will be supported. The hex images were created +by assembling the source code and then converting the resulting +binary output images into ASCII text files. The hexadecimal +numbers are listed using the Motorola Assembly syntax assembler +directive "dc.l" (define constant longword). The files can be +converted to other assembly syntaxes by using any word processor +with a global search and replace function. + +To assist in assembling and linking these modules with other modules, +the instaler should add symbolic labels to the top of the files. +This will allow the calling routines to access the entry points +of these packages. + +The source code itest.s and ftest.s have been included but only +for documentation purposes. + +Release file structure: +----------------------- + +(top of module) + ----------------- + | | - 128 byte-sized section + (1) | Call-Out | - 4 bytes per entry (user fills these in) + | | + ----------------- + | | - 8 bytes per entry + (2) | Entry Point | - user does "bsr" or "jsr" to this address + | | + ----------------- + | | - code section + (3) ~ ~ + | | + ----------------- +(bottom of module) + +The first section of this module is the "Call-out" section. This section +is NOT INCLUDED in {i,f}test.sa (an example "Call-out" section is provided at +the end of this file). The purpose of this section is to allow the test +routines to reference external printing functions that must be provided +by the host operating system. This section MUST be exactly 128 bytes in +size. There are 32 fields, each 4 bytes in size. Each field corresponds +to a function required by the test packages (these functions and their +location are listed in "68060{ISP,FPSP}-TEST call-outs" below). Each field +entry should contain the address of the corresponding function RELATIVE to +the starting address of the "call-out" section. The "Call-out" section must +sit adjacent to the {i,f}test.sa image in memory. Since itest.sa and ftest.sa +are individual tests, they each require their own "Call-out" sections. + +The second section, the "Entry-point" section, is used by external routines +to access the test routines. Since the {i,f}test.sa hex files contain +no symbol names, this section contains function entry points that are fixed +with respect to the top of the package. The currently defined entry-points +are listed in section "68060{ISP,FPSP}-TEST entry points" below. A calling +routine would simply execute a "bsr" or "jsr" that jumped to the selected +function entry-point. + +For example, to run the 060ISP test, write a program that includes the +itest.sa data and execute something similar to: + + bsr _060ISP_TEST+128+0 + +(_060ISP_TEST is the starting address of the "Call-out" section; the "Call-out" +section is 128 bytes long; and the 68060ISP test entry point is located +0 bytes from the top of the "Entry-point" section.) + +The third section is the code section. After entering through an "Entry-point", +the entry code jumps to the appropriate test code within the code section. + +68060ISP-TEST Call-outs: +------------------------ +0x0: _print_string() +0x4: _print_number() + +68060FPSP-TEST Call-outs: +------------------------- +0x0: _print_string() +0x4: _print_number() + +The test packages call _print_string() and _print_number() +as subroutines and expect the main program to print a string +or a number to a file or to the screen. +In "C"-like fashion, the test program calls: + + print_string("Test passed"); + + or + + print_number(20); + +For _print_string(), the test programs pass a longword address +of the string on the stack. For _print_number(), the test programs pass +a longword number to be printed. + +For debugging purposes, after the main program performs a "print" +for a test package, it should flush the output so that it's not +buffered. In this way, if the test program crashes, at least the previous +statements printed will be seen. + +68060ISP-TEST Entry-points: +--------------------------- +0x0: integer test + +68060FPSP-TEST Entry-points: +---------------------------- +0x00: main fp test +0x08: FP unimplemented test +0x10: FP enabled snan/operr/ovfl/unfl/dz/inex + +The floating-point unit test has 3 entry points which will require +3 different calls to the package if each of the three following tests +is desired: + +main fp test: tests (1) unimp effective address exception + (2) unsupported data type exceptions + (3) non-maskable overflow/underflow exceptions + +FP unimplemented: tests FP unimplemented exception. this one is + separate from the previous tests for systems that don't + want FP unimplemented instructions. + +FP enabled: tests enabled snan/operr/ovfl/unfl/dz/inex. + basically, it enables each of these exceptions and forces + each using an implemented FP instruction. this process + exercizes _fpsp_{snan,operr,ovfl,unfl,dz,inex}() and + _real_{snan,operr,ovfl,unfl,dz,inex}(). the test expects + _real_XXXX() to do nothing except clear the exception + and "rte". if a system's _real_XXXX() handler creates an + alternate result, the test will print "failed" but this + is acceptable. + +Miscellaneous: +-------------- +Again, itest.sa and ftest.sa are simple tests and do not thoroughly +test all 68060SP connections. For example, they do not test connections +to _real_access(), _real_trace(), _real_trap(), etc. because these +will be system-implemented several different ways and the test packages +must remain system independent. + +Example test package set-up: +---------------------------- +_print_str: + . # provided by system + rts + +_print_num: + . # provided by system + rts + + . + . + bsr _060FPSP_TEST+128+0 + . + . + rts + +# beginning of "Call-out" section; provided by integrator. +# MUST be 128 bytes long. +_060FPSP_TEST: + long _print_str - _060FPSP_TEST + long _print_num - _060FPSP_TEST + space 120 + +# ftest.sa starts here; start of "Entry-point" section. + long 0x60ff0000, 0x00002346 + long 0x60ff0000, 0x00018766 + long 0x60ff0000, 0x00023338 + long 0x24377299, 0xab2643ea + . + . + . diff -u --recursive --new-file v1.3.93/linux/arch/m68k/ifpsp060/fplsp.doc linux/arch/m68k/ifpsp060/fplsp.doc --- v1.3.93/linux/arch/m68k/ifpsp060/fplsp.doc Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/ifpsp060/fplsp.doc Mon Jan 8 22:08:13 1996 @@ -0,0 +1,231 @@ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP +M68000 Hi-Performance Microprocessor Division +M68060 Software Package +Production Release P1.00 -- October 10, 1994 + +M68060 Software Package Copyright © 1993, 1994 Motorola Inc. All rights reserved. + +THE SOFTWARE is provided on an "AS IS" basis and without warranty. +To the maximum extent permitted by applicable law, +MOTOROLA DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED, +INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE +and any warranty against infringement with regard to the SOFTWARE +(INCLUDING ANY MODIFIED VERSIONS THEREOF) and any accompanying written materials. + +To the maximum extent permitted by applicable law, +IN NO EVENT SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER +(INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, +BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY LOSS) +ARISING OF THE USE OR INABILITY TO USE THE SOFTWARE. +Motorola assumes no responsibility for the maintenance and support of the SOFTWARE. + +You are hereby granted a copyright license to use, modify, and distribute the SOFTWARE +so long as this entire notice is retained without alteration in any modified and/or +redistributed versions, and that such modified versions are clearly identified as such. +No licenses are granted by implication, estoppel or otherwise under any patents +or trademarks of Motorola, Inc. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +68060 FLOATING-POINT SOFTWARE PACKAGE (Library version) +-------------------------------------------------------- + +The file fplsp.sa contains the "Library version" of the +68060SP Floating-Point Software Package. The routines +included in this module can be used to emulate the +FP instructions not implemented in 68060 hardware. These +instructions normally take exception vector #11 +"FP Unimplemented Instruction". + +By re-compiling a program that uses these instructions, and +making subroutine calls in place of the unimplemented +instructions, a program can avoid the overhead associated +with taking the exception. + +Release file format: +-------------------- +The file fplsp.sa is essentially a hexadecimal image of the +release package. This is the ONLY format which will be supported. +The hex image was created by assembling the source code and +then converting the resulting binary output image into an +ASCII text file. The hexadecimal numbers are listed +using the Motorola Assembly Syntax assembler directive "dc.l" +(define constant longword). The file can be converted to other +assembly syntaxes by using any word processor with a global +search and replace function. + +To assist in assembling and linking this module with other modules, +the installer should add a symbolic label to the top of the file. +This will allow calling routines to access the entry points +of this package. + +The source code fplsp.s has also been included but only for +documentation purposes. + +Release file structure: +----------------------- +The file fplsp.sa contains an "Entry-Point" section and a +code section. The FPLSP has no "Call-Out" section. The first section +is the "Entry-Point" section. In order to access a function in the +package, a program must "bsr" or "jsr" to the location listed +below in "68060FPLSP entry points" that corresponds to the desired +function. A branch instruction located at the selected entry point +within the package will then enter the correct emulation code routine. + +The entry point addresses at the beginning of the package will remain +fixed so that a program calling the routines will not have to be +re-compiled with every new 68060FPLSP release. + +There are 3 entry-points for each instruction type: single precision, +double precision, and extended precision. + +As an example, the "fsin" library instruction can be passed an +extended precision operand if program executes: + +# fsin.x fp0 + + fmovm.x &0x01,-(%sp) # pass operand on stack + bsr.l _060FPLSP_TOP+0x1a8 # branch to fsin routine + add.l &0xc,%sp # clear operand from stack + +Upon return, fp0 holds the correct result. The FPSR is +set correctly. The FPCR is unchanged. The FPIAR is undefined. + +Another example. This time, a dyadic operation: + +# frem.s %fp1,%fp0 + + fmov.s %fp1,-(%sp) # pass src operand + fmov.s %fp0,-(%sp) # pass dst operand + bsr.l _060FPLSP_TOP+0x168 # branch to frem routine + addq.l &0x8,%sp # clear operands from stack + +Again, the result is returned in fp0. Note that BOTH operands +are passed in single precision format. + +Exception reporting: +-------------------- +The package takes exceptions according to the FPCR value upon subroutine +entry. If an exception should be reported, then the package forces +this exception using implemented floating-point instructions. +For example, if the instruction being emulated should cause a +floating-point Operand Error exception, then the library routine +executes an FMUL of a zero and an infinity to force the OPERR +exception. Although the FPIAR will be undefined for the enabled +Operand Error exception handler, the user will at least be able +to record that the event occurred. + +Miscellaneous: +-------------- +The package does not attempt to correctly emulate instructions +with Signalling NAN inputs. Use of SNANs should be avoided with +this package. + +The fabs/fadd/fdiv/fint/fintrz/fmul/fneg/fsqrt/fsub entry points +are provided for the convenience of older compilers that make +subroutine calls for all fp instructions. The code does NOT emulate +the instruction but rather simply executes it. + +68060FPLSP entry points: +------------------------ +_060FPLSP_TOP: +0x000: _060LSP__facoss_ +0x008: _060LSP__facosd_ +0x010: _060LSP__facosx_ +0x018: _060LSP__fasins_ +0x020: _060LSP__fasind_ +0x028: _060LSP__fasinx_ +0x030: _060LSP__fatans_ +0x038: _060LSP__fatand_ +0x040: _060LSP__fatanx_ +0x048: _060LSP__fatanhs_ +0x050: _060LSP__fatanhd_ +0x058: _060LSP__fatanhx_ +0x060: _060LSP__fcoss_ +0x068: _060LSP__fcosd_ +0x070: _060LSP__fcosx_ +0x078: _060LSP__fcoshs_ +0x080: _060LSP__fcoshd_ +0x088: _060LSP__fcoshx_ +0x090: _060LSP__fetoxs_ +0x098: _060LSP__fetoxd_ +0x0a0: _060LSP__fetoxx_ +0x0a8: _060LSP__fetoxm1s_ +0x0b0: _060LSP__fetoxm1d_ +0x0b8: _060LSP__fetoxm1x_ +0x0c0: _060LSP__fgetexps_ +0x0c8: _060LSP__fgetexpd_ +0x0d0: _060LSP__fgetexpx_ +0x0d8: _060LSP__fgetmans_ +0x0e0: _060LSP__fgetmand_ +0x0e8: _060LSP__fgetmanx_ +0x0f0: _060LSP__flog10s_ +0x0f8: _060LSP__flog10d_ +0x100: _060LSP__flog10x_ +0x108: _060LSP__flog2s_ +0x110: _060LSP__flog2d_ +0x118: _060LSP__flog2x_ +0x120: _060LSP__flogns_ +0x128: _060LSP__flognd_ +0x130: _060LSP__flognx_ +0x138: _060LSP__flognp1s_ +0x140: _060LSP__flognp1d_ +0x148: _060LSP__flognp1x_ +0x150: _060LSP__fmods_ +0x158: _060LSP__fmodd_ +0x160: _060LSP__fmodx_ +0x168: _060LSP__frems_ +0x170: _060LSP__fremd_ +0x178: _060LSP__fremx_ +0x180: _060LSP__fscales_ +0x188: _060LSP__fscaled_ +0x190: _060LSP__fscalex_ +0x198: _060LSP__fsins_ +0x1a0: _060LSP__fsind_ +0x1a8: _060LSP__fsinx_ +0x1b0: _060LSP__fsincoss_ +0x1b8: _060LSP__fsincosd_ +0x1c0: _060LSP__fsincosx_ +0x1c8: _060LSP__fsinhs_ +0x1d0: _060LSP__fsinhd_ +0x1d8: _060LSP__fsinhx_ +0x1e0: _060LSP__ftans_ +0x1e8: _060LSP__ftand_ +0x1f0: _060LSP__ftanx_ +0x1f8: _060LSP__ftanhs_ +0x200: _060LSP__ftanhd_ +0x208: _060LSP__ftanhx_ +0x210: _060LSP__ftentoxs_ +0x218: _060LSP__ftentoxd_ +0x220: _060LSP__ftentoxx_ +0x228: _060LSP__ftwotoxs_ +0x230: _060LSP__ftwotoxd_ +0x238: _060LSP__ftwotoxx_ + +0x240: _060LSP__fabss_ +0x248: _060LSP__fabsd_ +0x250: _060LSP__fabsx_ +0x258: _060LSP__fadds_ +0x260: _060LSP__faddd_ +0x268: _060LSP__faddx_ +0x270: _060LSP__fdivs_ +0x278: _060LSP__fdivd_ +0x280: _060LSP__fdivx_ +0x288: _060LSP__fints_ +0x290: _060LSP__fintd_ +0x298: _060LSP__fintx_ +0x2a0: _060LSP__fintrzs_ +0x2a8: _060LSP__fintrzd_ +0x2b0: _060LSP__fintrzx_ +0x2b8: _060LSP__fmuls_ +0x2c0: _060LSP__fmuld_ +0x2c8: _060LSP__fmulx_ +0x2d0: _060LSP__fnegs_ +0x2d8: _060LSP__fnegd_ +0x2e0: _060LSP__fnegx_ +0x2e8: _060LSP__fsqrts_ +0x2f0: _060LSP__fsqrtd_ +0x2f8: _060LSP__fsqrtx_ +0x300: _060LSP__fsubs_ +0x308: _060LSP__fsubd_ +0x310: _060LSP__fsubx_ diff -u --recursive --new-file v1.3.93/linux/arch/m68k/ifpsp060/fplsp.sa linux/arch/m68k/ifpsp060/fplsp.sa --- v1.3.93/linux/arch/m68k/ifpsp060/fplsp.sa Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/ifpsp060/fplsp.sa Mon Jan 8 22:08:14 1996 @@ -0,0 +1,1946 @@ + dc.l $60ff0000,$238e0000,$60ff0000,$24200000 + dc.l $60ff0000,$24b60000,$60ff0000,$11060000 + dc.l $60ff0000,$11980000,$60ff0000,$122e0000 + dc.l $60ff0000,$0f160000,$60ff0000,$0fa80000 + dc.l $60ff0000,$103e0000,$60ff0000,$12ae0000 + dc.l $60ff0000,$13400000,$60ff0000,$13d60000 + dc.l $60ff0000,$05ae0000,$60ff0000,$06400000 + dc.l $60ff0000,$06d60000,$60ff0000,$213e0000 + dc.l $60ff0000,$21d00000,$60ff0000,$22660000 + dc.l $60ff0000,$16160000,$60ff0000,$16a80000 + dc.l $60ff0000,$173e0000,$60ff0000,$0aee0000 + dc.l $60ff0000,$0b800000,$60ff0000,$0c160000 + dc.l $60ff0000,$24a60000,$60ff0000,$25380000 + dc.l $60ff0000,$25ce0000,$60ff0000,$26660000 + dc.l $60ff0000,$26f80000,$60ff0000,$278e0000 + dc.l $60ff0000,$1d160000,$60ff0000,$1da80000 + dc.l $60ff0000,$1e3e0000,$60ff0000,$1ed60000 + dc.l $60ff0000,$1f680000,$60ff0000,$1ffe0000 + dc.l $60ff0000,$1b0e0000,$60ff0000,$1ba00000 + dc.l $60ff0000,$1c360000,$60ff0000,$08860000 + dc.l $60ff0000,$09180000,$60ff0000,$09ae0000 + dc.l $60ff0000,$2bf00000,$60ff0000,$2ca40000 + dc.l $60ff0000,$2d580000,$60ff0000,$29980000 + dc.l $60ff0000,$2a4c0000,$60ff0000,$2b000000 + dc.l $60ff0000,$2e000000,$60ff0000,$2eb40000 + dc.l $60ff0000,$2f680000,$60ff0000,$029e0000 + dc.l $60ff0000,$03300000,$60ff0000,$03c60000 + dc.l $60ff0000,$27660000,$60ff0000,$27fe0000 + dc.l $60ff0000,$289a0000,$60ff0000,$061e0000 + dc.l $60ff0000,$06b00000,$60ff0000,$07460000 + dc.l $60ff0000,$12ee0000,$60ff0000,$13800000 + dc.l $60ff0000,$14160000,$60ff0000,$0b760000 + dc.l $60ff0000,$0c080000,$60ff0000,$0c9e0000 + dc.l $60ff0000,$18460000,$60ff0000,$18d80000 + dc.l $60ff0000,$196e0000,$60ff0000,$16560000 + dc.l $60ff0000,$16e80000,$60ff0000,$177e0000 + dc.l $60ff0000,$72fe0000,$60ff0000,$72fe0000 + dc.l $60ff0000,$72fe0000,$60ff0000,$71be0000 + dc.l $60ff0000,$71d40000,$60ff0000,$71ea0000 + dc.l $60ff0000,$72840000,$60ff0000,$729a0000 + dc.l $60ff0000,$72b00000,$60ff0000,$72fe0000 + dc.l $60ff0000,$72fe0000,$60ff0000,$72fe0000 + dc.l $60ff0000,$72fe0000,$60ff0000,$72fe0000 + dc.l $60ff0000,$72fe0000,$60ff0000,$71f20000 + dc.l $60ff0000,$72080000,$60ff0000,$721e0000 + dc.l $60ff0000,$72860000,$60ff0000,$72860000 + dc.l $60ff0000,$72860000,$60ff0000,$72860000 + dc.l $60ff0000,$72860000,$60ff0000,$72860000 + dc.l $60ff0000,$71600000,$60ff0000,$71760000 + dc.l $60ff0000,$718c0000,$51fc51fc,$51fc51fc + dc.l $51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc + dc.l $51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc + dc.l $51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc + dc.l $51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc + dc.l $51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc + dc.l $51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc + dc.l $51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc + dc.l $51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc + dc.l $51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc + dc.l $51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc + dc.l $51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc + dc.l $51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc + dc.l $51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc + dc.l $51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc + dc.l $40c62d38,$d3d64634,$3d6f90ae,$b1e75cc7 + dc.l $40000000,$c90fdaa2,$2168c235,$00000000 + dc.l $3fff0000,$c90fdaa2,$2168c235,$00000000 + dc.l $3fe45f30,$6dc9c883,$4e56ff40,$48ee0303 + dc.l $ff9cf22e,$b800ff60,$f22ef0c0,$ffdcf23c + dc.l $90000000,$0000f22e,$44000008,$f22e6800 + dc.l $ff6c41ee,$ff6c61ff,$00006c76,$1d40ff4e + dc.l $120002ae,$00ff00ff,$ff644280,$102eff63 + dc.l $4a016608,$61ff0000,$2ddc6030,$0c010001 + dc.l $660861ff,$00007124,$60220c01,$00026608 + dc.l $61ff0000,$6d226014,$0c010003,$660861ff + dc.l $00006f4c,$600661ff,$00002f8e,$4cee0303 + dc.l $ff9cf22e,$9800ff60,$f22ed040,$ffe84e5e + dc.l $4e754e56,$ff4048ee,$0303ff9c,$f22eb800 + dc.l $ff60f22e,$f0c0ffdc,$f23c9000,$00000000 + dc.l $f22e5400,$0008f22e,$6800ff6c,$41eeff6c + dc.l $61ff0000,$6bdc1d40,$ff4e1200,$02ae00ff + dc.l $00ffff64,$4280102e,$ff631d41,$ff4e4a01 + dc.l $660861ff,$00002d3e,$60300c01,$00016608 + dc.l $61ff0000,$70866022,$0c010002,$660861ff + dc.l $00006c84,$60140c01,$00036608,$61ff0000 + dc.l $6eae6006,$61ff0000,$2ef04cee,$0303ff9c + dc.l $f22e9800,$ff60f22e,$d040ffe8,$4e5e4e75 + dc.l $4e56ff40,$48ee0303,$ff9cf22e,$b800ff60 + dc.l $f22ef0c0,$ffdcf23c,$90000000,$000041ee + dc.l $ff6c216e,$00080000,$216e000c,$0004216e + dc.l $00100008,$61ff0000,$6b381d40,$ff4e1200 + dc.l $02ae00ff,$00ffff64,$4280102e,$ff634a01 + dc.l $660861ff,$00002c9e,$60300c01,$00016608 + dc.l $61ff0000,$6fe66022,$0c010002,$660861ff + dc.l $00006be4,$60140c01,$00036608,$61ff0000 + dc.l $6e0e6006,$61ff0000,$2e504cee,$0303ff9c + dc.l $f22e9800,$ff60f22e,$d040ffe8,$4e5e4e75 + dc.l $4e56ff40,$48ee0303,$ff9cf22e,$b800ff60 + dc.l $f22ef0c0,$ffdcf23c,$90000000,$0000f22e + dc.l $44000008,$f22e6800,$ff6c41ee,$ff6c61ff + dc.l $00006a9e,$1d40ff4e,$120002ae,$00ff00ff + dc.l $ff644280,$102eff63,$4a016608,$61ff0000 + dc.l $2c0e6030,$0c010001,$660861ff,$00006fc8 + dc.l $60220c01,$00026608,$61ff0000,$6b4a6014 + dc.l $0c010003,$660861ff,$00006d74,$600661ff + dc.l $00002dbc,$4cee0303,$ff9cf22e,$9800ff60 + dc.l $f22ed040,$ffe84e5e,$4e754e56,$ff4048ee + dc.l $0303ff9c,$f22eb800,$ff60f22e,$f0c0ffdc + dc.l $f23c9000,$00000000,$f22e5400,$0008f22e + dc.l $6800ff6c,$41eeff6c,$61ff0000,$6a041d40 + dc.l $ff4e1200,$02ae00ff,$00ffff64,$4280102e + dc.l $ff631d41,$ff4e4a01,$660861ff,$00002b70 + dc.l $60300c01,$00016608,$61ff0000,$6f2a6022 + dc.l $0c010002,$660861ff,$00006aac,$60140c01 + dc.l $00036608,$61ff0000,$6cd66006,$61ff0000 + dc.l $2d1e4cee,$0303ff9c,$f22e9800,$ff60f22e + dc.l $d040ffe8,$4e5e4e75,$4e56ff40,$48ee0303 + dc.l $ff9cf22e,$b800ff60,$f22ef0c0,$ffdcf23c + dc.l $90000000,$000041ee,$ff6c216e,$00080000 + dc.l $216e000c,$0004216e,$00100008,$61ff0000 + dc.l $69601d40,$ff4e1200,$02ae00ff,$00ffff64 + dc.l $4280102e,$ff634a01,$660861ff,$00002ad0 + dc.l $60300c01,$00016608,$61ff0000,$6e8a6022 + dc.l $0c010002,$660861ff,$00006a0c,$60140c01 + dc.l $00036608,$61ff0000,$6c366006,$61ff0000 + dc.l $2c7e4cee,$0303ff9c,$f22e9800,$ff60f22e + dc.l $d040ffe8,$4e5e4e75,$4e56ff40,$48ee0303 + dc.l $ff9cf22e,$b800ff60,$f22ef0c0,$ffdcf23c + dc.l $90000000,$0000f22e,$44000008,$f22e6800 + dc.l $ff6c41ee,$ff6c61ff,$000068c6,$1d40ff4e + dc.l $120002ae,$00ff00ff,$ff644280,$102eff63 + dc.l $4a016608,$61ff0000,$4e686030,$0c010001 + dc.l $660861ff,$00006d74,$60220c01,$00026608 + dc.l $61ff0000,$6d946014,$0c010003,$660861ff + dc.l $00006b9c,$600661ff,$00004f14,$4cee0303 + dc.l $ff9cf22e,$9800ff60,$f22ed040,$ffe84e5e + dc.l $4e754e56,$ff4048ee,$0303ff9c,$f22eb800 + dc.l $ff60f22e,$f0c0ffdc,$f23c9000,$00000000 + dc.l $f22e5400,$0008f22e,$6800ff6c,$41eeff6c + dc.l $61ff0000,$682c1d40,$ff4e1200,$02ae00ff + dc.l $00ffff64,$4280102e,$ff631d41,$ff4e4a01 + dc.l $660861ff,$00004dca,$60300c01,$00016608 + dc.l $61ff0000,$6cd66022,$0c010002,$660861ff + dc.l $00006cf6,$60140c01,$00036608,$61ff0000 + dc.l $6afe6006,$61ff0000,$4e764cee,$0303ff9c + dc.l $f22e9800,$ff60f22e,$d040ffe8,$4e5e4e75 + dc.l $4e56ff40,$48ee0303,$ff9cf22e,$b800ff60 + dc.l $f22ef0c0,$ffdcf23c,$90000000,$000041ee + dc.l $ff6c216e,$00080000,$216e000c,$0004216e + dc.l $00100008,$61ff0000,$67881d40,$ff4e1200 + dc.l $02ae00ff,$00ffff64,$4280102e,$ff634a01 + dc.l $660861ff,$00004d2a,$60300c01,$00016608 + dc.l $61ff0000,$6c366022,$0c010002,$660861ff + dc.l $00006c56,$60140c01,$00036608,$61ff0000 + dc.l $6a5e6006,$61ff0000,$4dd64cee,$0303ff9c + dc.l $f22e9800,$ff60f22e,$d040ffe8,$4e5e4e75 + dc.l $4e56ff40,$48ee0303,$ff9cf22e,$b800ff60 + dc.l $f22ef0c0,$ffdcf23c,$90000000,$0000f22e + dc.l $44000008,$f22e6800,$ff6c41ee,$ff6c61ff + dc.l $000066ee,$1d40ff4e,$120002ae,$00ff00ff + dc.l $ff644280,$102eff63,$4a016608,$61ff0000 + dc.l $59b26030,$0c010001,$660861ff,$00006b9c + dc.l $60220c01,$00026608,$61ff0000,$6bf26014 + dc.l $0c010003,$660861ff,$000069c4,$600661ff + dc.l $00005ad4,$4cee0303,$ff9cf22e,$9800ff60 + dc.l $f22ed040,$ffe84e5e,$4e754e56,$ff4048ee + dc.l $0303ff9c,$f22eb800,$ff60f22e,$f0c0ffdc + dc.l $f23c9000,$00000000,$f22e5400,$0008f22e + dc.l $6800ff6c,$41eeff6c,$61ff0000,$66541d40 + dc.l $ff4e1200,$02ae00ff,$00ffff64,$4280102e + dc.l $ff631d41,$ff4e4a01,$660861ff,$00005914 + dc.l $60300c01,$00016608,$61ff0000,$6afe6022 + dc.l $0c010002,$660861ff,$00006b54,$60140c01 + dc.l $00036608,$61ff0000,$69266006,$61ff0000 + dc.l $5a364cee,$0303ff9c,$f22e9800,$ff60f22e + dc.l $d040ffe8,$4e5e4e75,$4e56ff40,$48ee0303 + dc.l $ff9cf22e,$b800ff60,$f22ef0c0,$ffdcf23c + dc.l $90000000,$000041ee,$ff6c216e,$00080000 + dc.l $216e000c,$0004216e,$00100008,$61ff0000 + dc.l $65b01d40,$ff4e1200,$02ae00ff,$00ffff64 + dc.l $4280102e,$ff634a01,$660861ff,$00005874 + dc.l $60300c01,$00016608,$61ff0000,$6a5e6022 + dc.l $0c010002,$660861ff,$00006ab4,$60140c01 + dc.l $00036608,$61ff0000,$68866006,$61ff0000 + dc.l $59964cee,$0303ff9c,$f22e9800,$ff60f22e + dc.l $d040ffe8,$4e5e4e75,$4e56ff40,$48ee0303 + dc.l $ff9cf22e,$b800ff60,$f22ef0c0,$ffdcf23c + dc.l $90000000,$0000f22e,$44000008,$f22e6800 + dc.l $ff6c41ee,$ff6c61ff,$00006516,$1d40ff4e + dc.l $120002ae,$00ff00ff,$ff644280,$102eff63 + dc.l $4a016608,$61ff0000,$46c46030,$0c010001 + dc.l $660861ff,$000069c4,$60220c01,$00026608 + dc.l $61ff0000,$6a246014,$0c010003,$660861ff + dc.l $000067ec,$600661ff,$00004948,$4cee0303 + dc.l $ff9cf22e,$9800ff60,$f22ed040,$ffe84e5e + dc.l $4e754e56,$ff4048ee,$0303ff9c,$f22eb800 + dc.l $ff60f22e,$f0c0ffdc,$f23c9000,$00000000 + dc.l $f22e5400,$0008f22e,$6800ff6c,$41eeff6c + dc.l $61ff0000,$647c1d40,$ff4e1200,$02ae00ff + dc.l $00ffff64,$4280102e,$ff631d41,$ff4e4a01 + dc.l $660861ff,$00004626,$60300c01,$00016608 + dc.l $61ff0000,$69266022,$0c010002,$660861ff + dc.l $00006986,$60140c01,$00036608,$61ff0000 + dc.l $674e6006,$61ff0000,$48aa4cee,$0303ff9c + dc.l $f22e9800,$ff60f22e,$d040ffe8,$4e5e4e75 + dc.l $4e56ff40,$48ee0303,$ff9cf22e,$b800ff60 + dc.l $f22ef0c0,$ffdcf23c,$90000000,$000041ee + dc.l $ff6c216e,$00080000,$216e000c,$0004216e + dc.l $00100008,$61ff0000,$63d81d40,$ff4e1200 + dc.l $02ae00ff,$00ffff64,$4280102e,$ff634a01 + dc.l $660861ff,$00004586,$60300c01,$00016608 + dc.l $61ff0000,$68866022,$0c010002,$660861ff + dc.l $000068e6,$60140c01,$00036608,$61ff0000 + dc.l $66ae6006,$61ff0000,$480a4cee,$0303ff9c + dc.l $f22e9800,$ff60f22e,$d040ffe8,$4e5e4e75 + dc.l $4e56ff40,$48ee0303,$ff9cf22e,$b800ff60 + dc.l $f22ef0c0,$ffdcf23c,$90000000,$0000f22e + dc.l $44000008,$f22e6800,$ff6c41ee,$ff6c61ff + dc.l $0000633e,$1d40ff4e,$120002ae,$00ff00ff + dc.l $ff644280,$102eff63,$4a016608,$61ff0000 + dc.l $49c46030,$0c010001,$660861ff,$000067ec + dc.l $60220c01,$00026608,$61ff0000,$68546014 + dc.l $0c010003,$660861ff,$00006614,$600661ff + dc.l $00004afa,$4cee0303,$ff9cf22e,$9800ff60 + dc.l $f22ed040,$ffe84e5e,$4e754e56,$ff4048ee + dc.l $0303ff9c,$f22eb800,$ff60f22e,$f0c0ffdc + dc.l $f23c9000,$00000000,$f22e5400,$0008f22e + dc.l $6800ff6c,$41eeff6c,$61ff0000,$62a41d40 + dc.l $ff4e1200,$02ae00ff,$00ffff64,$4280102e + dc.l $ff631d41,$ff4e4a01,$660861ff,$00004926 + dc.l $60300c01,$00016608,$61ff0000,$674e6022 + dc.l $0c010002,$660861ff,$000067b6,$60140c01 + dc.l $00036608,$61ff0000,$65766006,$61ff0000 + dc.l $4a5c4cee,$0303ff9c,$f22e9800,$ff60f22e + dc.l $d040ffe8,$4e5e4e75,$4e56ff40,$48ee0303 + dc.l $ff9cf22e,$b800ff60,$f22ef0c0,$ffdcf23c + dc.l $90000000,$000041ee,$ff6c216e,$00080000 + dc.l $216e000c,$0004216e,$00100008,$61ff0000 + dc.l $62001d40,$ff4e1200,$02ae00ff,$00ffff64 + dc.l $4280102e,$ff634a01,$660861ff,$00004886 + dc.l $60300c01,$00016608,$61ff0000,$66ae6022 + dc.l $0c010002,$660861ff,$00006716,$60140c01 + dc.l $00036608,$61ff0000,$64d66006,$61ff0000 + dc.l $49bc4cee,$0303ff9c,$f22e9800,$ff60f22e + dc.l $d040ffe8,$4e5e4e75,$4e56ff40,$48ee0303 + dc.l $ff9cf22e,$b800ff60,$f22ef0c0,$ffdcf23c + dc.l $90000000,$0000f22e,$44000008,$f22e6800 + dc.l $ff6c41ee,$ff6c61ff,$00006166,$1d40ff4e + dc.l $120002ae,$00ff00ff,$ff644280,$102eff63 + dc.l $4a016608,$61ff0000,$391c6030,$0c010001 + dc.l $660861ff,$00006614,$60220c01,$00026608 + dc.l $61ff0000,$66b86014,$0c010003,$660861ff + dc.l $0000643c,$600661ff,$00003b28,$4cee0303 + dc.l $ff9cf22e,$9800ff60,$f22ed040,$ffe84e5e + dc.l $4e754e56,$ff4048ee,$0303ff9c,$f22eb800 + dc.l $ff60f22e,$f0c0ffdc,$f23c9000,$00000000 + dc.l $f22e5400,$0008f22e,$6800ff6c,$41eeff6c + dc.l $61ff0000,$60cc1d40,$ff4e1200,$02ae00ff + dc.l $00ffff64,$4280102e,$ff631d41,$ff4e4a01 + dc.l $660861ff,$0000387e,$60300c01,$00016608 + dc.l $61ff0000,$65766022,$0c010002,$660861ff + dc.l $0000661a,$60140c01,$00036608,$61ff0000 + dc.l $639e6006,$61ff0000,$3a8a4cee,$0303ff9c + dc.l $f22e9800,$ff60f22e,$d040ffe8,$4e5e4e75 + dc.l $4e56ff40,$48ee0303,$ff9cf22e,$b800ff60 + dc.l $f22ef0c0,$ffdcf23c,$90000000,$000041ee + dc.l $ff6c216e,$00080000,$216e000c,$0004216e + dc.l $00100008,$61ff0000,$60281d40,$ff4e1200 + dc.l $02ae00ff,$00ffff64,$4280102e,$ff634a01 + dc.l $660861ff,$000037de,$60300c01,$00016608 + dc.l $61ff0000,$64d66022,$0c010002,$660861ff + dc.l $0000657a,$60140c01,$00036608,$61ff0000 + dc.l $62fe6006,$61ff0000,$39ea4cee,$0303ff9c + dc.l $f22e9800,$ff60f22e,$d040ffe8,$4e5e4e75 + dc.l $4e56ff40,$48ee0303,$ff9cf22e,$b800ff60 + dc.l $f22ef0c0,$ffdcf23c,$90000000,$0000f22e + dc.l $44000008,$f22e6800,$ff6c41ee,$ff6c61ff + dc.l $00005f8e,$1d40ff4e,$120002ae,$00ff00ff + dc.l $ff644280,$102eff63,$4a016608,$61ff0000 + dc.l $39886030,$0c010001,$660861ff,$0000643c + dc.l $60220c01,$00026608,$61ff0000,$603a6014 + dc.l $0c010003,$660861ff,$00006264,$600661ff + dc.l $00003a04,$4cee0303,$ff9cf22e,$9800ff60 + dc.l $f22ed040,$ffe84e5e,$4e754e56,$ff4048ee + dc.l $0303ff9c,$f22eb800,$ff60f22e,$f0c0ffdc + dc.l $f23c9000,$00000000,$f22e5400,$0008f22e + dc.l $6800ff6c,$41eeff6c,$61ff0000,$5ef41d40 + dc.l $ff4e1200,$02ae00ff,$00ffff64,$4280102e + dc.l $ff631d41,$ff4e4a01,$660861ff,$000038ea + dc.l $60300c01,$00016608,$61ff0000,$639e6022 + dc.l $0c010002,$660861ff,$00005f9c,$60140c01 + dc.l $00036608,$61ff0000,$61c66006,$61ff0000 + dc.l $39664cee,$0303ff9c,$f22e9800,$ff60f22e + dc.l $d040ffe8,$4e5e4e75,$4e56ff40,$48ee0303 + dc.l $ff9cf22e,$b800ff60,$f22ef0c0,$ffdcf23c + dc.l $90000000,$000041ee,$ff6c216e,$00080000 + dc.l $216e000c,$0004216e,$00100008,$61ff0000 + dc.l $5e501d40,$ff4e1200,$02ae00ff,$00ffff64 + dc.l $4280102e,$ff634a01,$660861ff,$0000384a + dc.l $60300c01,$00016608,$61ff0000,$62fe6022 + dc.l $0c010002,$660861ff,$00005efc,$60140c01 + dc.l $00036608,$61ff0000,$61266006,$61ff0000 + dc.l $38c64cee,$0303ff9c,$f22e9800,$ff60f22e + dc.l $d040ffe8,$4e5e4e75,$4e56ff40,$48ee0303 + dc.l $ff9cf22e,$b800ff60,$f22ef0c0,$ffdcf23c + dc.l $90000000,$0000f22e,$44000008,$f22e6800 + dc.l $ff6c41ee,$ff6c61ff,$00005db6,$1d40ff4e + dc.l $120002ae,$00ff00ff,$ff644280,$102eff63 + dc.l $4a016608,$61ff0000,$51d46030,$0c010001 + dc.l $660861ff,$00006264,$60220c01,$00026608 + dc.l $61ff0000,$5e626014,$0c010003,$660861ff + dc.l $0000608c,$600661ff,$00005224,$4cee0303 + dc.l $ff9cf22e,$9800ff60,$f22ed040,$ffe84e5e + dc.l $4e754e56,$ff4048ee,$0303ff9c,$f22eb800 + dc.l $ff60f22e,$f0c0ffdc,$f23c9000,$00000000 + dc.l $f22e5400,$0008f22e,$6800ff6c,$41eeff6c + dc.l $61ff0000,$5d1c1d40,$ff4e1200,$02ae00ff + dc.l $00ffff64,$4280102e,$ff631d41,$ff4e4a01 + dc.l $660861ff,$00005136,$60300c01,$00016608 + dc.l $61ff0000,$61c66022,$0c010002,$660861ff + dc.l $00005dc4,$60140c01,$00036608,$61ff0000 + dc.l $5fee6006,$61ff0000,$51864cee,$0303ff9c + dc.l $f22e9800,$ff60f22e,$d040ffe8,$4e5e4e75 + dc.l $4e56ff40,$48ee0303,$ff9cf22e,$b800ff60 + dc.l $f22ef0c0,$ffdcf23c,$90000000,$000041ee + dc.l $ff6c216e,$00080000,$216e000c,$0004216e + dc.l $00100008,$61ff0000,$5c781d40,$ff4e1200 + dc.l $02ae00ff,$00ffff64,$4280102e,$ff634a01 + dc.l $660861ff,$00005096,$60300c01,$00016608 + dc.l $61ff0000,$61266022,$0c010002,$660861ff + dc.l $00005d24,$60140c01,$00036608,$61ff0000 + dc.l $5f4e6006,$61ff0000,$50e64cee,$0303ff9c + dc.l $f22e9800,$ff60f22e,$d040ffe8,$4e5e4e75 + dc.l $4e56ff40,$48ee0303,$ff9cf22e,$b800ff60 + dc.l $f22ef0c0,$ffdcf23c,$90000000,$0000f22e + dc.l $44000008,$f22e6800,$ff6c41ee,$ff6c61ff + dc.l $00005bde,$1d40ff4e,$120002ae,$00ff00ff + dc.l $ff644280,$102eff63,$4a016608,$61ff0000 + dc.l $28066030,$0c010001,$660861ff,$0000608c + dc.l $60220c01,$00026608,$61ff0000,$5c8a6014 + dc.l $0c010003,$660861ff,$00005eb4,$600661ff + dc.l $00002938,$4cee0303,$ff9cf22e,$9800ff60 + dc.l $f22ed040,$ffe84e5e,$4e754e56,$ff4048ee + dc.l $0303ff9c,$f22eb800,$ff60f22e,$f0c0ffdc + dc.l $f23c9000,$00000000,$f22e5400,$0008f22e + dc.l $6800ff6c,$41eeff6c,$61ff0000,$5b441d40 + dc.l $ff4e1200,$02ae00ff,$00ffff64,$4280102e + dc.l $ff631d41,$ff4e4a01,$660861ff,$00002768 + dc.l $60300c01,$00016608,$61ff0000,$5fee6022 + dc.l $0c010002,$660861ff,$00005bec,$60140c01 + dc.l $00036608,$61ff0000,$5e166006,$61ff0000 + dc.l $289a4cee,$0303ff9c,$f22e9800,$ff60f22e + dc.l $d040ffe8,$4e5e4e75,$4e56ff40,$48ee0303 + dc.l $ff9cf22e,$b800ff60,$f22ef0c0,$ffdcf23c + dc.l $90000000,$000041ee,$ff6c216e,$00080000 + dc.l $216e000c,$0004216e,$00100008,$61ff0000 + dc.l $5aa01d40,$ff4e1200,$02ae00ff,$00ffff64 + dc.l $4280102e,$ff634a01,$660861ff,$000026c8 + dc.l $60300c01,$00016608,$61ff0000,$5f4e6022 + dc.l $0c010002,$660861ff,$00005b4c,$60140c01 + dc.l $00036608,$61ff0000,$5d766006,$61ff0000 + dc.l $27fa4cee,$0303ff9c,$f22e9800,$ff60f22e + dc.l $d040ffe8,$4e5e4e75,$4e56ff40,$48ee0303 + dc.l $ff9cf22e,$b800ff60,$f22ef0c0,$ffdcf23c + dc.l $90000000,$0000f22e,$44000008,$f22e6800 + dc.l $ff6c41ee,$ff6c61ff,$00005a06,$1d40ff4e + dc.l $120002ae,$00ff00ff,$ff644280,$102eff63 + dc.l $4a016608,$61ff0000,$39e46030,$0c010001 + dc.l $660861ff,$00005f30,$60220c01,$00026608 + dc.l $61ff0000,$5f026014,$0c010003,$660861ff + dc.l $00005cdc,$600661ff,$00003b5e,$4cee0303 + dc.l $ff9cf22e,$9800ff60,$f22ed040,$ffe84e5e + dc.l $4e754e56,$ff4048ee,$0303ff9c,$f22eb800 + dc.l $ff60f22e,$f0c0ffdc,$f23c9000,$00000000 + dc.l $f22e5400,$0008f22e,$6800ff6c,$41eeff6c + dc.l $61ff0000,$596c1d40,$ff4e1200,$02ae00ff + dc.l $00ffff64,$4280102e,$ff631d41,$ff4e4a01 + dc.l $660861ff,$00003946,$60300c01,$00016608 + dc.l $61ff0000,$5e926022,$0c010002,$660861ff + dc.l $00005e64,$60140c01,$00036608,$61ff0000 + dc.l $5c3e6006,$61ff0000,$3ac04cee,$0303ff9c + dc.l $f22e9800,$ff60f22e,$d040ffe8,$4e5e4e75 + dc.l $4e56ff40,$48ee0303,$ff9cf22e,$b800ff60 + dc.l $f22ef0c0,$ffdcf23c,$90000000,$000041ee + dc.l $ff6c216e,$00080000,$216e000c,$0004216e + dc.l $00100008,$61ff0000,$58c81d40,$ff4e1200 + dc.l $02ae00ff,$00ffff64,$4280102e,$ff634a01 + dc.l $660861ff,$000038a6,$60300c01,$00016608 + dc.l $61ff0000,$5df26022,$0c010002,$660861ff + dc.l $00005dc4,$60140c01,$00036608,$61ff0000 + dc.l $5b9e6006,$61ff0000,$3a204cee,$0303ff9c + dc.l $f22e9800,$ff60f22e,$d040ffe8,$4e5e4e75 + dc.l $4e56ff40,$48ee0303,$ff9cf22e,$b800ff60 + dc.l $f22ef0c0,$ffdcf23c,$90000000,$0000f22e + dc.l $44000008,$f22e6800,$ff6c41ee,$ff6c61ff + dc.l $0000582e,$1d40ff4e,$120002ae,$00ff00ff + dc.l $ff644280,$102eff63,$4a016608,$61ff0000 + dc.l $522e6030,$0c010001,$660861ff,$00005d58 + dc.l $60220c01,$00026608,$61ff0000,$5d2a6014 + dc.l $0c010003,$660861ff,$00005b04,$600661ff + dc.l $000052d6,$4cee0303,$ff9cf22e,$9800ff60 + dc.l $f22ed040,$ffe84e5e,$4e754e56,$ff4048ee + dc.l $0303ff9c,$f22eb800,$ff60f22e,$f0c0ffdc + dc.l $f23c9000,$00000000,$f22e5400,$0008f22e + dc.l $6800ff6c,$41eeff6c,$61ff0000,$57941d40 + dc.l $ff4e1200,$02ae00ff,$00ffff64,$4280102e + dc.l $ff631d41,$ff4e4a01,$660861ff,$00005190 + dc.l $60300c01,$00016608,$61ff0000,$5cba6022 + dc.l $0c010002,$660861ff,$00005c8c,$60140c01 + dc.l $00036608,$61ff0000,$5a666006,$61ff0000 + dc.l $52384cee,$0303ff9c,$f22e9800,$ff60f22e + dc.l $d040ffe8,$4e5e4e75,$4e56ff40,$48ee0303 + dc.l $ff9cf22e,$b800ff60,$f22ef0c0,$ffdcf23c + dc.l $90000000,$000041ee,$ff6c216e,$00080000 + dc.l $216e000c,$0004216e,$00100008,$61ff0000 + dc.l $56f01d40,$ff4e1200,$02ae00ff,$00ffff64 + dc.l $4280102e,$ff634a01,$660861ff,$000050f0 + dc.l $60300c01,$00016608,$61ff0000,$5c1a6022 + dc.l $0c010002,$660861ff,$00005bec,$60140c01 + dc.l $00036608,$61ff0000,$59c66006,$61ff0000 + dc.l $51984cee,$0303ff9c,$f22e9800,$ff60f22e + dc.l $d040ffe8,$4e5e4e75,$4e56ff40,$48ee0303 + dc.l $ff9cf22e,$b800ff60,$f22ef0c0,$ffdcf23c + dc.l $90000000,$0000f22e,$44000008,$f22e6800 + dc.l $ff6c41ee,$ff6c61ff,$00005656,$1d40ff4e + dc.l $120002ae,$00ff00ff,$ff644280,$102eff63 + dc.l $4a016608,$61ff0000,$514e6030,$0c010001 + dc.l $660861ff,$00005b80,$60220c01,$00026608 + dc.l $61ff0000,$5b526014,$0c010003,$660861ff + dc.l $0000592c,$600661ff,$0000524c,$4cee0303 + dc.l $ff9cf22e,$9800ff60,$f22ed040,$ffe84e5e + dc.l $4e754e56,$ff4048ee,$0303ff9c,$f22eb800 + dc.l $ff60f22e,$f0c0ffdc,$f23c9000,$00000000 + dc.l $f22e5400,$0008f22e,$6800ff6c,$41eeff6c + dc.l $61ff0000,$55bc1d40,$ff4e1200,$02ae00ff + dc.l $00ffff64,$4280102e,$ff631d41,$ff4e4a01 + dc.l $660861ff,$000050b0,$60300c01,$00016608 + dc.l $61ff0000,$5ae26022,$0c010002,$660861ff + dc.l $00005ab4,$60140c01,$00036608,$61ff0000 + dc.l $588e6006,$61ff0000,$51ae4cee,$0303ff9c + dc.l $f22e9800,$ff60f22e,$d040ffe8,$4e5e4e75 + dc.l $4e56ff40,$48ee0303,$ff9cf22e,$b800ff60 + dc.l $f22ef0c0,$ffdcf23c,$90000000,$000041ee + dc.l $ff6c216e,$00080000,$216e000c,$0004216e + dc.l $00100008,$61ff0000,$55181d40,$ff4e1200 + dc.l $02ae00ff,$00ffff64,$4280102e,$ff634a01 + dc.l $660861ff,$00005010,$60300c01,$00016608 + dc.l $61ff0000,$5a426022,$0c010002,$660861ff + dc.l $00005a14,$60140c01,$00036608,$61ff0000 + dc.l $57ee6006,$61ff0000,$510e4cee,$0303ff9c + dc.l $f22e9800,$ff60f22e,$d040ffe8,$4e5e4e75 + dc.l $4e56ff40,$48ee0303,$ff9cf22e,$b800ff60 + dc.l $f22ef0c0,$ffdcf23c,$90000000,$0000f22e + dc.l $44000008,$f22e6800,$ff6c41ee,$ff6c61ff + dc.l $0000547e,$1d40ff4e,$120002ae,$00ff00ff + dc.l $ff644280,$102eff63,$4a016608,$61ff0000 + dc.l $45026030,$0c010001,$660861ff,$000054c8 + dc.l $60220c01,$00026608,$61ff0000,$59826014 + dc.l $0c010003,$660861ff,$00005754,$600661ff + dc.l $00004682,$4cee0303,$ff9cf22e,$9800ff60 + dc.l $f22ed040,$ffe84e5e,$4e754e56,$ff4048ee + dc.l $0303ff9c,$f22eb800,$ff60f22e,$f0c0ffdc + dc.l $f23c9000,$00000000,$f22e5400,$0008f22e + dc.l $6800ff6c,$41eeff6c,$61ff0000,$53e41d40 + dc.l $ff4e1200,$02ae00ff,$00ffff64,$4280102e + dc.l $ff631d41,$ff4e4a01,$660861ff,$00004464 + dc.l $60300c01,$00016608,$61ff0000,$542a6022 + dc.l $0c010002,$660861ff,$000058e4,$60140c01 + dc.l $00036608,$61ff0000,$56b66006,$61ff0000 + dc.l $45e44cee,$0303ff9c,$f22e9800,$ff60f22e + dc.l $d040ffe8,$4e5e4e75,$4e56ff40,$48ee0303 + dc.l $ff9cf22e,$b800ff60,$f22ef0c0,$ffdcf23c + dc.l $90000000,$000041ee,$ff6c216e,$00080000 + dc.l $216e000c,$0004216e,$00100008,$61ff0000 + dc.l $53401d40,$ff4e1200,$02ae00ff,$00ffff64 + dc.l $4280102e,$ff634a01,$660861ff,$000043c4 + dc.l $60300c01,$00016608,$61ff0000,$538a6022 + dc.l $0c010002,$660861ff,$00005844,$60140c01 + dc.l $00036608,$61ff0000,$56166006,$61ff0000 + dc.l $45444cee,$0303ff9c,$f22e9800,$ff60f22e + dc.l $d040ffe8,$4e5e4e75,$4e56ff40,$48ee0303 + dc.l $ff9cf22e,$b800ff60,$f22ef0c0,$ffdcf23c + dc.l $90000000,$0000f22e,$44000008,$f22e6800 + dc.l $ff6c41ee,$ff6c61ff,$000052a6,$1d40ff4e + dc.l $120002ae,$00ff00ff,$ff644280,$102eff63 + dc.l $4a016608,$61ff0000,$476c6030,$0c010001 + dc.l $660861ff,$000052f0,$60220c01,$00026608 + dc.l $61ff0000,$57aa6014,$0c010003,$660861ff + dc.l $0000557c,$600661ff,$0000476a,$4cee0303 + dc.l $ff9cf22e,$9800ff60,$f22ed040,$ffe84e5e + dc.l $4e754e56,$ff4048ee,$0303ff9c,$f22eb800 + dc.l $ff60f22e,$f0c0ffdc,$f23c9000,$00000000 + dc.l $f22e5400,$0008f22e,$6800ff6c,$41eeff6c + dc.l $61ff0000,$520c1d40,$ff4e1200,$02ae00ff + dc.l $00ffff64,$4280102e,$ff631d41,$ff4e4a01 + dc.l $660861ff,$000046ce,$60300c01,$00016608 + dc.l $61ff0000,$52526022,$0c010002,$660861ff + dc.l $0000570c,$60140c01,$00036608,$61ff0000 + dc.l $54de6006,$61ff0000,$46cc4cee,$0303ff9c + dc.l $f22e9800,$ff60f22e,$d040ffe8,$4e5e4e75 + dc.l $4e56ff40,$48ee0303,$ff9cf22e,$b800ff60 + dc.l $f22ef0c0,$ffdcf23c,$90000000,$000041ee + dc.l $ff6c216e,$00080000,$216e000c,$0004216e + dc.l $00100008,$61ff0000,$51681d40,$ff4e1200 + dc.l $02ae00ff,$00ffff64,$4280102e,$ff634a01 + dc.l $660861ff,$0000462e,$60300c01,$00016608 + dc.l $61ff0000,$51b26022,$0c010002,$660861ff + dc.l $0000566c,$60140c01,$00036608,$61ff0000 + dc.l $543e6006,$61ff0000,$462c4cee,$0303ff9c + dc.l $f22e9800,$ff60f22e,$d040ffe8,$4e5e4e75 + dc.l $4e56ff40,$48ee0303,$ff9cf22e,$b800ff60 + dc.l $f22ef0c0,$ffdcf23c,$90000000,$0000f22e + dc.l $44000008,$f22e6800,$ff6c41ee,$ff6c61ff + dc.l $000050ce,$1d40ff4e,$120002ae,$00ff00ff + dc.l $ff644280,$102eff63,$4a016608,$61ff0000 + dc.l $45e46030,$0c010001,$660861ff,$00005118 + dc.l $60220c01,$00026608,$61ff0000,$55d26014 + dc.l $0c010003,$660861ff,$000053a4,$600661ff + dc.l $0000460c,$4cee0303,$ff9cf22e,$9800ff60 + dc.l $f22ed040,$ffe84e5e,$4e754e56,$ff4048ee + dc.l $0303ff9c,$f22eb800,$ff60f22e,$f0c0ffdc + dc.l $f23c9000,$00000000,$f22e5400,$0008f22e + dc.l $6800ff6c,$41eeff6c,$61ff0000,$50341d40 + dc.l $ff4e1200,$02ae00ff,$00ffff64,$4280102e + dc.l $ff631d41,$ff4e4a01,$660861ff,$00004546 + dc.l $60300c01,$00016608,$61ff0000,$507a6022 + dc.l $0c010002,$660861ff,$00005534,$60140c01 + dc.l $00036608,$61ff0000,$53066006,$61ff0000 + dc.l $456e4cee,$0303ff9c,$f22e9800,$ff60f22e + dc.l $d040ffe8,$4e5e4e75,$4e56ff40,$48ee0303 + dc.l $ff9cf22e,$b800ff60,$f22ef0c0,$ffdcf23c + dc.l $90000000,$000041ee,$ff6c216e,$00080000 + dc.l $216e000c,$0004216e,$00100008,$61ff0000 + dc.l $4f901d40,$ff4e1200,$02ae00ff,$00ffff64 + dc.l $4280102e,$ff634a01,$660861ff,$000044a6 + dc.l $60300c01,$00016608,$61ff0000,$4fda6022 + dc.l $0c010002,$660861ff,$00005494,$60140c01 + dc.l $00036608,$61ff0000,$52666006,$61ff0000 + dc.l $44ce4cee,$0303ff9c,$f22e9800,$ff60f22e + dc.l $d040ffe8,$4e5e4e75,$4e56ff40,$48ee0303 + dc.l $ff9cf22e,$b800ff60,$f22ef0c0,$ffdcf23c + dc.l $90000000,$0000f22e,$44000008,$f22e6800 + dc.l $ff6c41ee,$ff6c61ff,$00004ef6,$1d40ff4e + dc.l $120002ae,$00ff00ff,$ff644280,$102eff63 + dc.l $4a016608,$61ff0000,$33da6030,$0c010001 + dc.l $660861ff,$00005420,$60220c01,$00026608 + dc.l $61ff0000,$53ca6014,$0c010003,$660861ff + dc.l $000051cc,$600661ff,$0000344c,$4cee0303 + dc.l $ff9cf22e,$9800ff60,$f22ed040,$ffe84e5e + dc.l $4e754e56,$ff4048ee,$0303ff9c,$f22eb800 + dc.l $ff60f22e,$f0c0ffdc,$f23c9000,$00000000 + dc.l $f22e5400,$0008f22e,$6800ff6c,$41eeff6c + dc.l $61ff0000,$4e5c1d40,$ff4e1200,$02ae00ff + dc.l $00ffff64,$4280102e,$ff631d41,$ff4e4a01 + dc.l $660861ff,$0000333c,$60300c01,$00016608 + dc.l $61ff0000,$53826022,$0c010002,$660861ff + dc.l $0000532c,$60140c01,$00036608,$61ff0000 + dc.l $512e6006,$61ff0000,$33ae4cee,$0303ff9c + dc.l $f22e9800,$ff60f22e,$d040ffe8,$4e5e4e75 + dc.l $4e56ff40,$48ee0303,$ff9cf22e,$b800ff60 + dc.l $f22ef0c0,$ffdcf23c,$90000000,$000041ee + dc.l $ff6c216e,$00080000,$216e000c,$0004216e + dc.l $00100008,$61ff0000,$4db81d40,$ff4e1200 + dc.l $02ae00ff,$00ffff64,$4280102e,$ff634a01 + dc.l $660861ff,$0000329c,$60300c01,$00016608 + dc.l $61ff0000,$52e26022,$0c010002,$660861ff + dc.l $0000528c,$60140c01,$00036608,$61ff0000 + dc.l $508e6006,$61ff0000,$330e4cee,$0303ff9c + dc.l $f22e9800,$ff60f22e,$d040ffe8,$4e5e4e75 + dc.l $4e56ff40,$48ee0303,$ff9cf22e,$b800ff60 + dc.l $f22ef0c0,$ffdcf23c,$90000000,$0000f22e + dc.l $44000008,$f22e6800,$ff6c41ee,$ff6c61ff + dc.l $00004d1e,$1d40ff4e,$120002ae,$00ff00ff + dc.l $ff644280,$102eff63,$4a016608,$61ff0000 + dc.l $27cc6030,$0c010001,$660861ff,$00005284 + dc.l $60220c01,$00026608,$61ff0000,$4dca6014 + dc.l $0c010003,$660861ff,$00004ff4,$600661ff + dc.l $0000282a,$4cee0303,$ff9cf22e,$9800ff60 + dc.l $f22ed040,$ffe84e5e,$4e754e56,$ff4048ee + dc.l $0303ff9c,$f22eb800,$ff60f22e,$f0c0ffdc + dc.l $f23c9000,$00000000,$f22e5400,$0008f22e + dc.l $6800ff6c,$41eeff6c,$61ff0000,$4c841d40 + dc.l $ff4e1200,$02ae00ff,$00ffff64,$4280102e + dc.l $ff631d41,$ff4e4a01,$660861ff,$0000272e + dc.l $60300c01,$00016608,$61ff0000,$51e66022 + dc.l $0c010002,$660861ff,$00004d2c,$60140c01 + dc.l $00036608,$61ff0000,$4f566006,$61ff0000 + dc.l $278c4cee,$0303ff9c,$f22e9800,$ff60f22e + dc.l $d040ffe8,$4e5e4e75,$4e56ff40,$48ee0303 + dc.l $ff9cf22e,$b800ff60,$f22ef0c0,$ffdcf23c + dc.l $90000000,$000041ee,$ff6c216e,$00080000 + dc.l $216e000c,$0004216e,$00100008,$61ff0000 + dc.l $4be01d40,$ff4e1200,$02ae00ff,$00ffff64 + dc.l $4280102e,$ff634a01,$660861ff,$0000268e + dc.l $60300c01,$00016608,$61ff0000,$51466022 + dc.l $0c010002,$660861ff,$00004c8c,$60140c01 + dc.l $00036608,$61ff0000,$4eb66006,$61ff0000 + dc.l $26ec4cee,$0303ff9c,$f22e9800,$ff60f22e + dc.l $d040ffe8,$4e5e4e75,$4e56ff40,$48ee0303 + dc.l $ff9cf22e,$b800ff60,$f22ef0c0,$ffdcf23c + dc.l $90000000,$0000f22e,$44000008,$f22e6800 + dc.l $ff6c41ee,$ff6c61ff,$00004b46,$1d40ff4e + dc.l $120002ae,$00ff00ff,$ff644280,$102eff63 + dc.l $4a016608,$61ff0000,$2fb06030,$0c010001 + dc.l $660861ff,$00004ff4,$60220c01,$00026608 + dc.l $61ff0000,$4bf26014,$0c010003,$660861ff + dc.l $00004e1c,$600661ff,$00002f9a,$4cee0303 + dc.l $ff9cf22e,$9800ff60,$f22ed040,$ffe84e5e + dc.l $4e754e56,$ff4048ee,$0303ff9c,$f22eb800 + dc.l $ff60f22e,$f0c0ffdc,$f23c9000,$00000000 + dc.l $f22e5400,$0008f22e,$6800ff6c,$41eeff6c + dc.l $61ff0000,$4aac1d40,$ff4e1200,$02ae00ff + dc.l $00ffff64,$4280102e,$ff631d41,$ff4e4a01 + dc.l $660861ff,$00002f12,$60300c01,$00016608 + dc.l $61ff0000,$4f566022,$0c010002,$660861ff + dc.l $00004b54,$60140c01,$00036608,$61ff0000 + dc.l $4d7e6006,$61ff0000,$2efc4cee,$0303ff9c + dc.l $f22e9800,$ff60f22e,$d040ffe8,$4e5e4e75 + dc.l $4e56ff40,$48ee0303,$ff9cf22e,$b800ff60 + dc.l $f22ef0c0,$ffdcf23c,$90000000,$000041ee + dc.l $ff6c216e,$00080000,$216e000c,$0004216e + dc.l $00100008,$61ff0000,$4a081d40,$ff4e1200 + dc.l $02ae00ff,$00ffff64,$4280102e,$ff634a01 + dc.l $660861ff,$00002e72,$60300c01,$00016608 + dc.l $61ff0000,$4eb66022,$0c010002,$660861ff + dc.l $00004ab4,$60140c01,$00036608,$61ff0000 + dc.l $4cde6006,$61ff0000,$2e5c4cee,$0303ff9c + dc.l $f22e9800,$ff60f22e,$d040ffe8,$4e5e4e75 + dc.l $4e56ff40,$48ee0303,$ff9cf22e,$b800ff60 + dc.l $f22ef0c0,$ffdcf23c,$90000000,$0000f22e + dc.l $44000008,$f22e6800,$ff6c41ee,$ff6c61ff + dc.l $0000496e,$1d40ff4e,$120002ae,$00ff00ff + dc.l $ff644280,$102eff63,$4a016608,$61ff0000 + dc.l $2e0c6030,$0c010001,$660861ff,$00004e1c + dc.l $60220c01,$00026608,$61ff0000,$4a1a6014 + dc.l $0c010003,$660861ff,$00004c44,$600661ff + dc.l $00002e08,$4cee0303,$ff9cf22e,$9800ff60 + dc.l $f22ed040,$ffe84e5e,$4e754e56,$ff4048ee + dc.l $0303ff9c,$f22eb800,$ff60f22e,$f0c0ffdc + dc.l $f23c9000,$00000000,$f22e5400,$0008f22e + dc.l $6800ff6c,$41eeff6c,$61ff0000,$48d41d40 + dc.l $ff4e1200,$02ae00ff,$00ffff64,$4280102e + dc.l $ff631d41,$ff4e4a01,$660861ff,$00002d6e + dc.l $60300c01,$00016608,$61ff0000,$4d7e6022 + dc.l $0c010002,$660861ff,$0000497c,$60140c01 + dc.l $00036608,$61ff0000,$4ba66006,$61ff0000 + dc.l $2d6a4cee,$0303ff9c,$f22e9800,$ff60f22e + dc.l $d040ffe8,$4e5e4e75,$4e56ff40,$48ee0303 + dc.l $ff9cf22e,$b800ff60,$f22ef0c0,$ffdcf23c + dc.l $90000000,$000041ee,$ff6c216e,$00080000 + dc.l $216e000c,$0004216e,$00100008,$61ff0000 + dc.l $48301d40,$ff4e1200,$02ae00ff,$00ffff64 + dc.l $4280102e,$ff634a01,$660861ff,$00002cce + dc.l $60300c01,$00016608,$61ff0000,$4cde6022 + dc.l $0c010002,$660861ff,$000048dc,$60140c01 + dc.l $00036608,$61ff0000,$4b066006,$61ff0000 + dc.l $2cca4cee,$0303ff9c,$f22e9800,$ff60f22e + dc.l $d040ffe8,$4e5e4e75,$4e56ff40,$48ee0303 + dc.l $ff9cf22e,$b800ff60,$f22ef0c0,$ffdcf23c + dc.l $90000000,$0000f22e,$44000008,$f22e6800 + dc.l $ff6c41ee,$ff6c61ff,$00004796,$1d40ff4e + dc.l $120002ae,$00ff00ff,$ff644280,$102eff63 + dc.l $4a016608,$61ff0000,$0af46030,$0c010001 + dc.l $660861ff,$00004d18,$60220c01,$00026608 + dc.l $61ff0000,$4d386014,$0c010003,$660861ff + dc.l $00004d34,$600661ff,$00000d58,$4cee0303 + dc.l $ff9cf22e,$9800ff60,$f227e003,$f21fd040 + dc.l $f21fd080,$4e5e4e75,$4e56ff40,$48ee0303 + dc.l $ff9cf22e,$b800ff60,$f22ef0c0,$ffdcf23c + dc.l $90000000,$0000f22e,$54000008,$f22e6800 + dc.l $ff6c41ee,$ff6c61ff,$000046f6,$1d40ff4e + dc.l $120002ae,$00ff00ff,$ff644280,$102eff63 + dc.l $1d41ff4e,$4a016608,$61ff0000,$0a506030 + dc.l $0c010001,$660861ff,$00004c74,$60220c01 + dc.l $00026608,$61ff0000,$4c946014,$0c010003 + dc.l $660861ff,$00004c90,$600661ff,$00000cb4 + dc.l $4cee0303,$ff9cf22e,$9800ff60,$f227e003 + dc.l $f21fd040,$f21fd080,$4e5e4e75,$4e56ff40 + dc.l $48ee0303,$ff9cf22e,$b800ff60,$f22ef0c0 + dc.l $ffdcf23c,$90000000,$000041ee,$ff6c216e + dc.l $00080000,$216e000c,$0004216e,$00100008 + dc.l $61ff0000,$464c1d40,$ff4e1200,$02ae00ff + dc.l $00ffff64,$4280102e,$ff634a01,$660861ff + dc.l $000009aa,$60300c01,$00016608,$61ff0000 + dc.l $4bce6022,$0c010002,$660861ff,$00004bee + dc.l $60140c01,$00036608,$61ff0000,$4bea6006 + dc.l $61ff0000,$0c0e4cee,$0303ff9c,$f22e9800 + dc.l $ff60f227,$e003f21f,$d040f21f,$d0804e5e + dc.l $4e754e56,$ff4048ee,$0303ff9c,$f22eb800 + dc.l $ff60f22e,$f0c0ffdc,$f23c9000,$00000000 + dc.l $f22e4400,$0008f22e,$6800ff78,$41eeff78 + dc.l $61ff0000,$45ac1d40,$ff4ff22e,$4400000c + dc.l $f22e6800,$ff6c41ee,$ff6c61ff,$00004592 + dc.l $1d40ff4e,$220002ae,$00ff00ff,$ff644280 + dc.l $102eff63,$41eeff6c,$43eeff78,$4a016608 + dc.l $61ff0000,$4c466030,$0c010001,$660861ff + dc.l $00004c64,$60220c01,$00026608,$61ff0000 + dc.l $4c846014,$0c010003,$660861ff,$00004d16 + dc.l $600661ff,$00004c14,$4cee0303,$ff9cf22e + dc.l $9800ff60,$f22ed040,$ffe84e5e,$4e754e56 + dc.l $ff4048ee,$0303ff9c,$f22eb800,$ff60f22e + dc.l $f0c0ffdc,$f23c9000,$00000000,$f22e5400 + dc.l $0008f22e,$6800ff78,$41eeff78,$61ff0000 + dc.l $44f01d40,$ff4ff22e,$54000010,$f22e6800 + dc.l $ff6c41ee,$ff6c61ff,$000044d6,$1d40ff4e + dc.l $220002ae,$00ff00ff,$ff644280,$102eff63 + dc.l $41eeff6c,$43eeff78,$4a016608,$61ff0000 + dc.l $4b8a6030,$0c010001,$660861ff,$00004ba8 + dc.l $60220c01,$00026608,$61ff0000,$4bc86014 + dc.l $0c010003,$660861ff,$00004c5a,$600661ff + dc.l $00004b58,$4cee0303,$ff9cf22e,$9800ff60 + dc.l $f22ed040,$ffe84e5e,$4e754e56,$ff4048ee + dc.l $0303ff9c,$f22eb800,$ff60f22e,$f0c0ffdc + dc.l $f23c9000,$00000000,$41eeff78,$216e0008 + dc.l $0000216e,$000c0004,$216e0010,$000861ff + dc.l $0000442e,$1d40ff4f,$41eeff6c,$216e0014 + dc.l $0000216e,$00180004,$216e001c,$000861ff + dc.l $0000440e,$1d40ff4e,$220002ae,$00ff00ff + dc.l $ff644280,$102eff63,$41eeff6c,$43eeff78 + dc.l $4a016608,$61ff0000,$4ac26030,$0c010001 + dc.l $660861ff,$00004ae0,$60220c01,$00026608 + dc.l $61ff0000,$4b006014,$0c010003,$660861ff + dc.l $00004b92,$600661ff,$00004a90,$4cee0303 + dc.l $ff9cf22e,$9800ff60,$f22ed040,$ffe84e5e + dc.l $4e754e56,$ff4048ee,$0303ff9c,$f22eb800 + dc.l $ff60f22e,$f0c0ffdc,$f23c9000,$00000000 + dc.l $f22e4400,$0008f22e,$6800ff78,$41eeff78 + dc.l $61ff0000,$436c1d40,$ff4ff22e,$4400000c + dc.l $f22e6800,$ff6c41ee,$ff6c61ff,$00004352 + dc.l $1d40ff4e,$220002ae,$00ff00ff,$ff644280 + dc.l $102eff63,$41eeff6c,$43eeff78,$4a016608 + dc.l $61ff0000,$491c6030,$0c010001,$660861ff + dc.l $0000493a,$60220c01,$00026608,$61ff0000 + dc.l $495a6014,$0c010003,$660861ff,$00004ad6 + dc.l $600661ff,$000048ea,$4cee0303,$ff9cf22e + dc.l $9800ff60,$f22ed040,$ffe84e5e,$4e754e56 + dc.l $ff4048ee,$0303ff9c,$f22eb800,$ff60f22e + dc.l $f0c0ffdc,$f23c9000,$00000000,$f22e5400 + dc.l $0008f22e,$6800ff78,$41eeff78,$61ff0000 + dc.l $42b01d40,$ff4ff22e,$54000010,$f22e6800 + dc.l $ff6c41ee,$ff6c61ff,$00004296,$1d40ff4e + dc.l $220002ae,$00ff00ff,$ff644280,$102eff63 + dc.l $41eeff6c,$43eeff78,$4a016608,$61ff0000 + dc.l $48606030,$0c010001,$660861ff,$0000487e + dc.l $60220c01,$00026608,$61ff0000,$489e6014 + dc.l $0c010003,$660861ff,$00004a1a,$600661ff + dc.l $0000482e,$4cee0303,$ff9cf22e,$9800ff60 + dc.l $f22ed040,$ffe84e5e,$4e754e56,$ff4048ee + dc.l $0303ff9c,$f22eb800,$ff60f22e,$f0c0ffdc + dc.l $f23c9000,$00000000,$41eeff78,$216e0008 + dc.l $0000216e,$000c0004,$216e0010,$000861ff + dc.l $000041ee,$1d40ff4f,$41eeff6c,$216e0014 + dc.l $0000216e,$00180004,$216e001c,$000861ff + dc.l $000041ce,$1d40ff4e,$220002ae,$00ff00ff + dc.l $ff644280,$102eff63,$41eeff6c,$43eeff78 + dc.l $4a016608,$61ff0000,$47986030,$0c010001 + dc.l $660861ff,$000047b6,$60220c01,$00026608 + dc.l $61ff0000,$47d66014,$0c010003,$660861ff + dc.l $00004952,$600661ff,$00004766,$4cee0303 + dc.l $ff9cf22e,$9800ff60,$f22ed040,$ffe84e5e + dc.l $4e754e56,$ff4048ee,$0303ff9c,$f22eb800 + dc.l $ff60f22e,$f0c0ffdc,$f23c9000,$00000000 + dc.l $f22e4400,$0008f22e,$6800ff78,$41eeff78 + dc.l $61ff0000,$412c1d40,$ff4ff22e,$4400000c + dc.l $f22e6800,$ff6c41ee,$ff6c61ff,$00004112 + dc.l $1d40ff4e,$220002ae,$00ff00ff,$ff644280 + dc.l $102eff63,$41eeff6c,$43eeff78,$4a016608 + dc.l $61ff0000,$484a6030,$0c010001,$660861ff + dc.l $0000486a,$60220c01,$00026608,$61ff0000 + dc.l $488a6014,$0c010003,$660861ff,$00004896 + dc.l $600661ff,$00004818,$4cee0303,$ff9cf22e + dc.l $9800ff60,$f22ed040,$ffe84e5e,$4e754e56 + dc.l $ff4048ee,$0303ff9c,$f22eb800,$ff60f22e + dc.l $f0c0ffdc,$f23c9000,$00000000,$f22e5400 + dc.l $0008f22e,$6800ff78,$41eeff78,$61ff0000 + dc.l $40701d40,$ff4ff22e,$54000010,$f22e6800 + dc.l $ff6c41ee,$ff6c61ff,$00004056,$1d40ff4e + dc.l $220002ae,$00ff00ff,$ff644280,$102eff63 + dc.l $41eeff6c,$43eeff78,$4a016608,$61ff0000 + dc.l $478e6030,$0c010001,$660861ff,$000047ae + dc.l $60220c01,$00026608,$61ff0000,$47ce6014 + dc.l $0c010003,$660861ff,$000047da,$600661ff + dc.l $0000475c,$4cee0303,$ff9cf22e,$9800ff60 + dc.l $f22ed040,$ffe84e5e,$4e754e56,$ff4048ee + dc.l $0303ff9c,$f22eb800,$ff60f22e,$f0c0ffdc + dc.l $f23c9000,$00000000,$41eeff78,$216e0008 + dc.l $0000216e,$000c0004,$216e0010,$000861ff + dc.l $00003fae,$1d40ff4f,$41eeff6c,$216e0014 + dc.l $0000216e,$00180004,$216e001c,$000861ff + dc.l $00003f8e,$1d40ff4e,$220002ae,$00ff00ff + dc.l $ff644280,$102eff63,$41eeff6c,$43eeff78 + dc.l $4a016608,$61ff0000,$46c66030,$0c010001 + dc.l $660861ff,$000046e6,$60220c01,$00026608 + dc.l $61ff0000,$47066014,$0c010003,$660861ff + dc.l $00004712,$600661ff,$00004694,$4cee0303 + dc.l $ff9cf22e,$9800ff60,$f22ed040,$ffe84e5e + dc.l $4e75bd6a,$aa77ccc9,$94f53de6,$12097aae + dc.l $8da1be5a,$e6452a11,$8ae43ec7,$1de3a534 + dc.l $1531bf2a,$01a01a01,$8b590000,$00000000 + dc.l $00003ff8,$00008888,$88888888,$59af0000 + dc.l $0000bffc,$0000aaaa,$aaaaaaaa,$aa990000 + dc.l $00003d2a,$c4d0d601,$1ee3bda9,$396f9f45 + dc.l $ac193e21,$eed90612,$c972be92,$7e4fb79d + dc.l $9fcf3efa,$01a01a01,$d4230000,$00000000 + dc.l $0000bff5,$0000b60b,$60b60b61,$d4380000 + dc.l $00003ffa,$0000aaaa,$aaaaaaaa,$ab5ebf00 + dc.l $00002d7c,$00000000,$ff5c6008,$2d7c0000 + dc.l $0001ff5c,$f2104800,$f22e6800,$ff842210 + dc.l $32280004,$02817fff,$ffff0c81,$3fd78000 + dc.l $6c046000,$01780c81,$4004bc7e,$6d046000 + dc.l $0468f200,$0080f23a,$54a3d186,$43fb0170 + dc.l $00000866,$f22e6080,$ff58222e,$ff58e981 + dc.l $d3c1f219,$4828f211,$4428222e,$ff58d2ae + dc.l $ff5ce299,$0c810000,$00006d00,$0088f227 + dc.l $e00cf22e,$6800ff84,$f2000023,$f23a5580 + dc.l $fed2f23a,$5500fed4,$f2000080,$f20004a3 + dc.l $e2990281,$80000000,$b3aeff84,$f20005a3 + dc.l $f2000523,$f23a55a2,$febaf23a,$5522febc + dc.l $f20005a3,$f2000523,$f23a55a2,$feb6f23a + dc.l $4922fec0,$f2000ca3,$f2000123,$f23a48a2 + dc.l $fec2f22e,$4823ff84,$f20008a2,$f2000423 + dc.l $f21fd030,$f2009000,$f22e4822,$ff8460ff + dc.l $00004006,$f227e00c,$f2000023,$f23a5500 + dc.l $fea2f23a,$5580fea4,$f2000080,$f20004a3 + dc.l $f22e6800,$ff84e299,$02818000,$0000f200 + dc.l $0523b3ae,$ff840281,$80000000,$f20005a3 + dc.l $00813f80,$00002d41,$ff54f23a,$5522fe74 + dc.l $f23a55a2,$fe76f200,$0523f200,$05a3f23a + dc.l $5522fe70,$f23a49a2,$fe7af200,$0523f200 + dc.l $0ca3f23a,$4922fe7c,$f23a44a2,$fe82f200 + dc.l $0823f200,$0422f22e,$4823ff84,$f21fd030 + dc.l $f2009000,$f22e4422,$ff5460ff,$00003f6a + dc.l $0c813fff,$80006eff,$00000300,$222eff5c + dc.l $0c810000,$00006e14,$f2009000,$123c0003 + dc.l $f22e4800,$ff8460ff,$00003f36,$f23c4400 + dc.l $3f800000,$f2009000,$f23c4422,$80800000 + dc.l $60ff0000,$3f2c60ff,$00003f64,$f23c4400 + dc.l $3f800000,$60ff0000,$3f182d7c,$00000004 + dc.l $ff5cf210,$4800f22e,$6800ff84,$22103228 + dc.l $00040281,$7fffffff,$0c813fd7,$80006c04 + dc.l $60000240,$0c814004,$bc7e6d04,$6000027a + dc.l $f2000080,$f23a54a3,$cf9843fb,$01700000 + dc.l $0678f22e,$6080ff58,$222eff58,$e981d3c1 + dc.l $f2194828,$f2114428,$222eff58,$e2990c81 + dc.l $00000000,$6c000106,$f227e004,$f22e6800 + dc.l $ff84f200,$0023f23a,$5480fce8,$f23a5500 + dc.l $fd32f200,$00a3f200,$01232f02,$2401e29a + dc.l $02828000,$0000b382,$02828000,$0000f23a + dc.l $54a2fcc8,$f23a5522,$fd12f200,$00a3b5ae + dc.l $ff84241f,$f2000123,$e2990281,$80000000 + dc.l $2d7c3f80,$0000ff54,$b3aeff54,$f23a54a2 + dc.l $fca2f23a,$5522fcec,$f20000a3,$f2000123 + dc.l $f22e6800,$ff90f23a,$54a2fc90,$b3aeff90 + dc.l $f23a5522,$fcd6f200,$00a3f200,$0123f23a + dc.l $54a2fc80,$f23a5522,$fccaf200,$00a3f200 + dc.l $0123f23a,$48a2fc7c,$f23a4922,$fcc6f200 + dc.l $00a3f200,$0123f23a,$48a2fc78,$f23a4922 + dc.l $fcc2f200,$00a3f200,$0823f22e,$48a3ff84 + dc.l $f23a4422,$fcbaf22e,$4823ff90,$f21fd020 + dc.l $f2009000,$f22e48a2,$ff8461ff,$00003e22 + dc.l $f22e4422,$ff5460ff,$00003d9e,$f227e004 + dc.l $f22e6800,$ff84f200,$0023f23a,$5480fc34 + dc.l $f23a5500,$fbdef200,$00a3f22e,$6800ff90 + dc.l $f2000123,$e2990281,$80000000,$f23a54a2 + dc.l $fc1af23a,$5522fbc4,$b3aeff84,$b3aeff90 + dc.l $f20000a3,$00813f80,$00002d41,$ff54f200 + dc.l $0123f23a,$54a2fbfc,$f23a5522,$fba6f200 + dc.l $00a3f200,$0123f23a,$54a2fbf0,$f23a5522 + dc.l $fb9af200,$00a3f200,$0123f23a,$54a2fbe4 + dc.l $f23a5522,$fb8ef200,$00a3f200,$0123f23a + dc.l $48a2fbe0,$f23a4922,$fb8af200,$00a3f200 + dc.l $0123f23a,$48a2fbdc,$f23a4922,$fb86f200 + dc.l $00a3f200,$0823f23a,$44a2fbd4,$f22e4823 + dc.l $ff84f22e,$48a3ff90,$f21fd020,$f2009000 + dc.l $f22e44a2,$ff5461ff,$00003d36,$f22e4822 + dc.l $ff8460ff,$00003cb2,$0c813fff,$80006e00 + dc.l $0048f23c,$44803f80,$0000f200,$9000f23c + dc.l $44a80080,$000061ff,$00003d06,$f200b000 + dc.l $123c0003,$f22e4800,$ff8460ff,$00003c72 + dc.l $2f00f23c,$44803f80,$000061ff,$00003ce2 + dc.l $201f60ff,$00003ca8,$f227e03c,$2f02f23c + dc.l $44800000,$00000c81,$7ffeffff,$66523d7c + dc.l $7ffeff84,$2d7cc90f,$daa2ff88,$42aeff8c + dc.l $3d7c7fdc,$ff902d7c,$85a308d3,$ff9442ae + dc.l $ff98f200,$003af294,$000e002e,$0080ff84 + dc.l $002e0080,$ff90f22e,$4822ff84,$f2000080 + dc.l $f22e4822,$ff90f200,$00a8f22e,$48a2ff90 + dc.l $f22e6800,$ff84322e,$ff842241,$02810000 + dc.l $7fff0481,$00003fff,$0c810000,$001c6f0e + dc.l $04810000,$001b1d7c,$0000ff58,$60084281 + dc.l $1d7c0001,$ff58243c,$00003ffe,$94812d7c + dc.l $a2f9836e,$ff882d7c,$4e44152a,$ff8c3d42 + dc.l $ff84f200,$0100f22e,$4923ff84,$24094842 + dc.l $02828000,$00000082,$5f000000,$2d42ff54 + dc.l $f22e4522,$ff54f22e,$4528ff54,$24010682 + dc.l $00003fff,$3d42ff84,$2d7cc90f,$daa2ff88 + dc.l $42aeff8c,$06810000,$3fdd3d41,$ff902d7c + dc.l $85a308d3,$ff9442ae,$ff98122e,$ff58f200 + dc.l $0a00f22e,$4a23ff84,$f2000a80,$f22e4aa3 + dc.l $ff90f200,$1180f200,$15a2f200,$0e28f200 + dc.l $0c28f200,$1622f200,$0180f200,$10a8f200 + dc.l $04220c01,$00006e00,$000ef200,$01a8f200 + dc.l $0ca26000,$ff0cf22e,$6100ff58,$241ff21f + dc.l $d03c222e,$ff5c0c81,$00000004,$6d00fa4c + dc.l $6000fc36,$3ea0b759,$f50f8688,$bef2baa5 + dc.l $a8924f04,$bf346f59,$b39ba65f,$00000000 + dc.l $00000000,$3ff60000,$e073d3fc,$199c4a00 + dc.l $00000000,$3ff90000,$d23cd684,$15d95fa1 + dc.l $00000000,$bffc0000,$8895a6c5,$fb423bca + dc.l $00000000,$bffd0000,$eef57e0d,$a84bc8ce + dc.l $00000000,$3ffc0000,$a2f9836e,$4e44152a + dc.l $00000000,$40010000,$c90fdaa2,$00000000 + dc.l $00000000,$3fdf0000,$85a308d4,$00000000 + dc.l $00000000,$c0040000,$c90fdaa2,$2168c235 + dc.l $21800000,$c0040000,$c2c75bcd,$105d7c23 + dc.l $a0d00000,$c0040000,$bc7edcf7,$ff523611 + dc.l $a1e80000,$c0040000,$b6365e22,$ee46f000 + dc.l $21480000,$c0040000,$afeddf4d,$dd3ba9ee + dc.l $a1200000,$c0040000,$a9a56078,$cc3063dd + dc.l $21fc0000,$c0040000,$a35ce1a3,$bb251dcb + dc.l $21100000,$c0040000,$9d1462ce,$aa19d7b9 + dc.l $a1580000,$c0040000,$96cbe3f9,$990e91a8 + dc.l $21e00000,$c0040000,$90836524,$88034b96 + dc.l $20b00000,$c0040000,$8a3ae64f,$76f80584 + dc.l $a1880000,$c0040000,$83f2677a,$65ecbf73 + dc.l $21c40000,$c0030000,$fb53d14a,$a9c2f2c2 + dc.l $20000000,$c0030000,$eec2d3a0,$87ac669f + dc.l $21380000,$c0030000,$e231d5f6,$6595da7b + dc.l $a1300000,$c0030000,$d5a0d84c,$437f4e58 + dc.l $9fc00000,$c0030000,$c90fdaa2,$2168c235 + dc.l $21000000,$c0030000,$bc7edcf7,$ff523611 + dc.l $a1680000,$c0030000,$afeddf4d,$dd3ba9ee + dc.l $a0a00000,$c0030000,$a35ce1a3,$bb251dcb + dc.l $20900000,$c0030000,$96cbe3f9,$990e91a8 + dc.l $21600000,$c0030000,$8a3ae64f,$76f80584 + dc.l $a1080000,$c0020000,$fb53d14a,$a9c2f2c2 + dc.l $1f800000,$c0020000,$e231d5f6,$6595da7b + dc.l $a0b00000,$c0020000,$c90fdaa2,$2168c235 + dc.l $20800000,$c0020000,$afeddf4d,$dd3ba9ee + dc.l $a0200000,$c0020000,$96cbe3f9,$990e91a8 + dc.l $20e00000,$c0010000,$fb53d14a,$a9c2f2c2 + dc.l $1f000000,$c0010000,$c90fdaa2,$2168c235 + dc.l $20000000,$c0010000,$96cbe3f9,$990e91a8 + dc.l $20600000,$c0000000,$c90fdaa2,$2168c235 + dc.l $1f800000,$bfff0000,$c90fdaa2,$2168c235 + dc.l $1f000000,$00000000,$00000000,$00000000 + dc.l $00000000,$3fff0000,$c90fdaa2,$2168c235 + dc.l $9f000000,$40000000,$c90fdaa2,$2168c235 + dc.l $9f800000,$40010000,$96cbe3f9,$990e91a8 + dc.l $a0600000,$40010000,$c90fdaa2,$2168c235 + dc.l $a0000000,$40010000,$fb53d14a,$a9c2f2c2 + dc.l $9f000000,$40020000,$96cbe3f9,$990e91a8 + dc.l $a0e00000,$40020000,$afeddf4d,$dd3ba9ee + dc.l $20200000,$40020000,$c90fdaa2,$2168c235 + dc.l $a0800000,$40020000,$e231d5f6,$6595da7b + dc.l $20b00000,$40020000,$fb53d14a,$a9c2f2c2 + dc.l $9f800000,$40030000,$8a3ae64f,$76f80584 + dc.l $21080000,$40030000,$96cbe3f9,$990e91a8 + dc.l $a1600000,$40030000,$a35ce1a3,$bb251dcb + dc.l $a0900000,$40030000,$afeddf4d,$dd3ba9ee + dc.l $20a00000,$40030000,$bc7edcf7,$ff523611 + dc.l $21680000,$40030000,$c90fdaa2,$2168c235 + dc.l $a1000000,$40030000,$d5a0d84c,$437f4e58 + dc.l $1fc00000,$40030000,$e231d5f6,$6595da7b + dc.l $21300000,$40030000,$eec2d3a0,$87ac669f + dc.l $a1380000,$40030000,$fb53d14a,$a9c2f2c2 + dc.l $a0000000,$40040000,$83f2677a,$65ecbf73 + dc.l $a1c40000,$40040000,$8a3ae64f,$76f80584 + dc.l $21880000,$40040000,$90836524,$88034b96 + dc.l $a0b00000,$40040000,$96cbe3f9,$990e91a8 + dc.l $a1e00000,$40040000,$9d1462ce,$aa19d7b9 + dc.l $21580000,$40040000,$a35ce1a3,$bb251dcb + dc.l $a1100000,$40040000,$a9a56078,$cc3063dd + dc.l $a1fc0000,$40040000,$afeddf4d,$dd3ba9ee + dc.l $21200000,$40040000,$b6365e22,$ee46f000 + dc.l $a1480000,$40040000,$bc7edcf7,$ff523611 + dc.l $21e80000,$40040000,$c2c75bcd,$105d7c23 + dc.l $20d00000,$40040000,$c90fdaa2,$2168c235 + dc.l $a1800000,$f2104800,$22103228,$00040281 + dc.l $7fffffff,$0c813fd7,$80006c04,$60000134 + dc.l $0c814004,$bc7e6d04,$60000144,$f2000080 + dc.l $f23a54a3,$c6dc43fa,$fdbcf201,$6080e981 + dc.l $d3c1f219,$4828f211,$4428ea99,$02818000 + dc.l $0000f227,$e00c0c81,$00000000,$6d000072 + dc.l $f2000080,$f20004a3,$f23a5580,$faf8f23a + dc.l $5500fafa,$f20005a3,$f2000523,$f23a55a2 + dc.l $faf4f23a,$4922fafe,$f20005a3,$f2000523 + dc.l $f23a49a2,$fb00f23a,$4922fb0a,$f20005a3 + dc.l $f2000523,$f23a49a2,$fb0cf200,$0123f200 + dc.l $0ca3f200,$0822f23c,$44a23f80,$0000f21f + dc.l $d030f200,$9000f200,$042060ff,$0000357a + dc.l $f2000080,$f2000023,$f23a5580,$fa88f23a + dc.l $5500fa8a,$f20001a3,$f2000123,$f23a55a2 + dc.l $fa84f23a,$4922fa8e,$f20001a3,$f2000123 + dc.l $f23a49a2,$fa90f23a,$4922fa9a,$f20001a3 + dc.l $f2000123,$f23a49a2,$fa9cf200,$0523f200 + dc.l $0c23f200,$08a2f23c,$44223f80,$0000f21f + dc.l $d030f227,$68800a97,$80000000,$f2009000 + dc.l $f21f4820,$60ff0000,$35000c81,$3fff8000 + dc.l $6e1cf227,$6800f200,$9000123c,$0003f21f + dc.l $480060ff,$000034da,$60ff0000,$3522f227 + dc.l $e03c2f02,$f23c4480,$00000000,$0c817ffe + dc.l $ffff6652,$3d7c7ffe,$ff842d7c,$c90fdaa2 + dc.l $ff8842ae,$ff8c3d7c,$7fdcff90,$2d7c85a3 + dc.l $08d3ff94,$42aeff98,$f200003a,$f294000e + dc.l $002e0080,$ff84002e,$0080ff90,$f22e4822 + dc.l $ff84f200,$0080f22e,$4822ff90,$f20000a8 + dc.l $f22e48a2,$ff90f22e,$6800ff84,$322eff84 + dc.l $22410281,$00007fff,$04810000,$3fff0c81 + dc.l $0000001c,$6f0e0481,$0000001b,$1d7c0000 + dc.l $ff586008,$42811d7c,$0001ff58,$243c0000 + dc.l $3ffe9481,$2d7ca2f9,$836eff88,$2d7c4e44 + dc.l $152aff8c,$3d42ff84,$f2000100,$f22e4923 + dc.l $ff842409,$48420282,$80000000,$00825f00 + dc.l $00002d42,$ff54f22e,$4522ff54,$f22e4528 + dc.l $ff542401,$06820000,$3fff3d42,$ff842d7c + dc.l $c90fdaa2,$ff8842ae,$ff8c0681,$00003fdd + dc.l $3d41ff90,$2d7c85a3,$08d3ff94,$42aeff98 + dc.l $122eff58,$f2000a00,$f22e4a23,$ff84f200 + dc.l $0a80f22e,$4aa3ff90,$f2001180,$f20015a2 + dc.l $f2000e28,$f2000c28,$f2001622,$f2000180 + dc.l $f20010a8,$f2000422,$0c010000,$6e00000e + dc.l $f20001a8,$f2000ca2,$6000ff0c,$f22e6100 + dc.l $ff54241f,$f21fd03c,$222eff54,$e2996000 + dc.l $fd72bff6,$687e3149,$87d84002,$ac6934a2 + dc.l $6db3bfc2,$476f4e1d,$a28e3fb3,$44447f87 + dc.l $6989bfb7,$44ee7faf,$45db3fbc,$71c64694 + dc.l $0220bfc2,$49249218,$72f93fc9,$99999999 + dc.l $8fa9bfd5,$55555555,$5555bfb7,$0bf39853 + dc.l $9e6a3fbc,$7187962d,$1d7dbfc2,$49248271 + dc.l $07b83fc9,$99999996,$263ebfd5,$55555555 + dc.l $55363fff,$0000c90f,$daa22168,$c2350000 + dc.l $0000bfff,$0000c90f,$daa22168,$c2350000 + dc.l $00000001,$00008000,$00000000,$00000000 + dc.l $00008001,$00008000,$00000000,$00000000 + dc.l $00003ffb,$000083d1,$52c5060b,$7a510000 + dc.l $00003ffb,$00008bc8,$54456549,$8b8b0000 + dc.l $00003ffb,$000093be,$40601762,$6b0d0000 + dc.l $00003ffb,$00009bb3,$078d35ae,$c2020000 + dc.l $00003ffb,$0000a3a6,$9a525ddc,$e7de0000 + dc.l $00003ffb,$0000ab98,$e9436276,$56190000 + dc.l $00003ffb,$0000b389,$e502f9c5,$98620000 + dc.l $00003ffb,$0000bb79,$7e436b09,$e6fb0000 + dc.l $00003ffb,$0000c367,$a5c739e5,$f4460000 + dc.l $00003ffb,$0000cb54,$4c61cff7,$d5c60000 + dc.l $00003ffb,$0000d33f,$62f82488,$533e0000 + dc.l $00003ffb,$0000db28,$da816240,$4c770000 + dc.l $00003ffb,$0000e310,$a4078ad3,$4f180000 + dc.l $00003ffb,$0000eaf6,$b0a8188e,$e1eb0000 + dc.l $00003ffb,$0000f2da,$f1949dbe,$79d50000 + dc.l $00003ffb,$0000fabd,$581361d4,$7e3e0000 + dc.l $00003ffc,$00008346,$ac210959,$ecc40000 + dc.l $00003ffc,$00008b23,$2a083042,$82d80000 + dc.l $00003ffc,$000092fb,$70b8d29a,$e2f90000 + dc.l $00003ffc,$00009acf,$476f5ccd,$1cb40000 + dc.l $00003ffc,$0000a29e,$76304954,$f23f0000 + dc.l $00003ffc,$0000aa68,$c5d08ab8,$52300000 + dc.l $00003ffc,$0000b22d,$fffd9d53,$9f830000 + dc.l $00003ffc,$0000b9ed,$ef453e90,$0ea50000 + dc.l $00003ffc,$0000c1a8,$5f1cc75e,$3ea50000 + dc.l $00003ffc,$0000c95d,$1be82813,$8de60000 + dc.l $00003ffc,$0000d10b,$f300840d,$2de40000 + dc.l $00003ffc,$0000d8b4,$b2ba6bc0,$5e7a0000 + dc.l $00003ffc,$0000e057,$2a6bb423,$35f60000 + dc.l $00003ffc,$0000e7f3,$2a70ea9c,$aa8f0000 + dc.l $00003ffc,$0000ef88,$843264ec,$efaa0000 + dc.l $00003ffc,$0000f717,$0a28ecc0,$66660000 + dc.l $00003ffd,$0000812f,$d288332d,$ad320000 + dc.l $00003ffd,$000088a8,$d1b1218e,$4d640000 + dc.l $00003ffd,$00009012,$ab3f23e4,$aee80000 + dc.l $00003ffd,$0000976c,$c3d411e7,$f1b90000 + dc.l $00003ffd,$00009eb6,$89493889,$a2270000 + dc.l $00003ffd,$0000a5ef,$72c34487,$361b0000 + dc.l $00003ffd,$0000ad17,$00baf07a,$72270000 + dc.l $00003ffd,$0000b42c,$bcfafd37,$efb70000 + dc.l $00003ffd,$0000bb30,$3a940ba8,$0f890000 + dc.l $00003ffd,$0000c221,$15c6fcae,$bbaf0000 + dc.l $00003ffd,$0000c8fe,$f3e68633,$12210000 + dc.l $00003ffd,$0000cfc9,$8330b400,$0c700000 + dc.l $00003ffd,$0000d680,$7aa1102c,$5bf90000 + dc.l $00003ffd,$0000dd23,$99bc3125,$2aa30000 + dc.l $00003ffd,$0000e3b2,$a8556b8f,$c5170000 + dc.l $00003ffd,$0000ea2d,$764f6431,$59890000 + dc.l $00003ffd,$0000f3bf,$5bf8bad1,$a21d0000 + dc.l $00003ffe,$0000801c,$e39e0d20,$5c9a0000 + dc.l $00003ffe,$00008630,$a2dada1e,$d0660000 + dc.l $00003ffe,$00008c1a,$d445f3e0,$9b8c0000 + dc.l $00003ffe,$000091db,$8f1664f3,$50e20000 + dc.l $00003ffe,$00009773,$1420365e,$538c0000 + dc.l $00003ffe,$00009ce1,$c8e6a0b8,$cdba0000 + dc.l $00003ffe,$0000a228,$32dbcada,$ae090000 + dc.l $00003ffe,$0000a746,$f2ddb760,$22940000 + dc.l $00003ffe,$0000ac3e,$c0fb997d,$d6a20000 + dc.l $00003ffe,$0000b110,$688aebdc,$6f6a0000 + dc.l $00003ffe,$0000b5bc,$c49059ec,$c4b00000 + dc.l $00003ffe,$0000ba44,$bc7dd470,$782f0000 + dc.l $00003ffe,$0000bea9,$4144fd04,$9aac0000 + dc.l $00003ffe,$0000c2eb,$4abb6616,$28b60000 + dc.l $00003ffe,$0000c70b,$d54ce602,$ee140000 + dc.l $00003ffe,$0000cd00,$0549adec,$71590000 + dc.l $00003ffe,$0000d484,$57d2d8ea,$4ea30000 + dc.l $00003ffe,$0000db94,$8da712de,$ce3b0000 + dc.l $00003ffe,$0000e238,$55f969e8,$096a0000 + dc.l $00003ffe,$0000e877,$1129c435,$32590000 + dc.l $00003ffe,$0000ee57,$c16e0d37,$9c0d0000 + dc.l $00003ffe,$0000f3e1,$0211a87c,$37790000 + dc.l $00003ffe,$0000f919,$039d758b,$8d410000 + dc.l $00003ffe,$0000fe05,$8b8f6493,$5fb30000 + dc.l $00003fff,$00008155,$fb497b68,$5d040000 + dc.l $00003fff,$00008388,$9e3549d1,$08e10000 + dc.l $00003fff,$0000859c,$fa76511d,$724b0000 + dc.l $00003fff,$00008795,$2ecfff81,$31e70000 + dc.l $00003fff,$00008973,$2fd19557,$641b0000 + dc.l $00003fff,$00008b38,$cad10193,$2a350000 + dc.l $00003fff,$00008ce7,$a8d8301e,$e6b50000 + dc.l $00003fff,$00008f46,$a39e2eae,$52810000 + dc.l $00003fff,$0000922d,$a7d79188,$84870000 + dc.l $00003fff,$000094d1,$9fcbdedf,$52410000 + dc.l $00003fff,$0000973a,$b94419d2,$a08b0000 + dc.l $00003fff,$0000996f,$f00e08e1,$0b960000 + dc.l $00003fff,$00009b77,$3f951232,$1da70000 + dc.l $00003fff,$00009d55,$cc320f93,$56240000 + dc.l $00003fff,$00009f10,$0575006c,$c5710000 + dc.l $00003fff,$0000a0a9,$c290d97c,$c06c0000 + dc.l $00003fff,$0000a226,$59ebebc0,$630a0000 + dc.l $00003fff,$0000a388,$b4aff6ef,$0ec90000 + dc.l $00003fff,$0000a4d3,$5f1061d2,$92c40000 + dc.l $00003fff,$0000a608,$95dcfbe3,$187e0000 + dc.l $00003fff,$0000a72a,$51dc7367,$beac0000 + dc.l $00003fff,$0000a83a,$51530956,$168f0000 + dc.l $00003fff,$0000a93a,$20077539,$546e0000 + dc.l $00003fff,$0000aa9e,$7245023b,$26050000 + dc.l $00003fff,$0000ac4c,$84ba6fe4,$d58f0000 + dc.l $00003fff,$0000adce,$4a4a606b,$97120000 + dc.l $00003fff,$0000af2a,$2dcd8d26,$3c9c0000 + dc.l $00003fff,$0000b065,$6f81f222,$65c70000 + dc.l $00003fff,$0000b184,$65150f71,$496a0000 + dc.l $00003fff,$0000b28a,$aa156f9a,$da350000 + dc.l $00003fff,$0000b37b,$44ff3766,$b8950000 + dc.l $00003fff,$0000b458,$c3dce963,$04330000 + dc.l $00003fff,$0000b525,$529d5622,$46bd0000 + dc.l $00003fff,$0000b5e2,$cca95f9d,$88cc0000 + dc.l $00003fff,$0000b692,$cada7aca,$1ada0000 + dc.l $00003fff,$0000b736,$aea7a692,$58380000 + dc.l $00003fff,$0000b7cf,$ab287e9f,$7b360000 + dc.l $00003fff,$0000b85e,$cc66cb21,$98350000 + dc.l $00003fff,$0000b8e4,$fd5a20a5,$93da0000 + dc.l $00003fff,$0000b99f,$41f64aff,$9bb50000 + dc.l $00003fff,$0000ba7f,$1e17842b,$be7b0000 + dc.l $00003fff,$0000bb47,$12857637,$e17d0000 + dc.l $00003fff,$0000bbfa,$be8a4788,$df6f0000 + dc.l $00003fff,$0000bc9d,$0fad2b68,$9d790000 + dc.l $00003fff,$0000bd30,$6a39471e,$cd860000 + dc.l $00003fff,$0000bdb6,$c731856a,$f18a0000 + dc.l $00003fff,$0000be31,$cac502e8,$0d700000 + dc.l $00003fff,$0000bea2,$d55ce331,$94e20000 + dc.l $00003fff,$0000bf0b,$10b7c031,$28f00000 + dc.l $00003fff,$0000bf6b,$7a18dacb,$778d0000 + dc.l $00003fff,$0000bfc4,$ea4663fa,$18f60000 + dc.l $00003fff,$0000c018,$1bde8b89,$a4540000 + dc.l $00003fff,$0000c065,$b066cfbf,$64390000 + dc.l $00003fff,$0000c0ae,$345f5634,$0ae60000 + dc.l $00003fff,$0000c0f2,$22919cb9,$e6a70000 + dc.l $0000f210,$48002210,$32280004,$f22e6800 + dc.l $ff840281,$7fffffff,$0c813ffb,$80006c04 + dc.l $600000d0,$0c814002,$ffff6f04,$6000014c + dc.l $02aef800,$0000ff88,$00ae0400,$0000ff88 + dc.l $2d7c0000,$0000ff8c,$f2000080,$f22e48a3 + dc.l $ff84f22e,$4828ff84,$f23c44a2,$3f800000 + dc.l $f2000420,$2f022401,$02810000,$78000282 + dc.l $7fff0000,$04823ffb,$0000e282,$d282ee81 + dc.l $43faf780,$d3c12d59,$ff902d59,$ff942d59 + dc.l $ff98222e,$ff840281,$80000000,$83aeff90 + dc.l $241ff227,$e004f200,$0080f200,$04a3f23a + dc.l $5500f6a0,$f2000522,$f2000523,$f20000a3 + dc.l $f23a5522,$f696f23a,$54a3f698,$f20008a3 + dc.l $f2000422,$f21fd020,$f2009000,$f22e4822 + dc.l $ff9060ff,$000029d2,$0c813fff,$80006e00 + dc.l $008a0c81,$3fd78000,$6d00006c,$f227e00c + dc.l $f2000023,$f2000080,$f20004a3,$f23a5500 + dc.l $f65af23a,$5580f65c,$f2000523,$f20005a3 + dc.l $f23a5522,$f656f23a,$55a2f658,$f2000523 + dc.l $f2000ca3,$f23a5522,$f652f23a,$54a2f654 + dc.l $f2000123,$f22e4823,$ff84f200,$08a2f200 + dc.l $0423f21f,$d030f200,$9000f22e,$4822ff84 + dc.l $60ff0000,$2954f200,$9000123c,$0003f22e + dc.l $4800ff84,$60ff0000,$29380c81,$40638000 + dc.l $6e00008e,$f227e00c,$f23c4480,$bf800000 + dc.l $f20000a0,$f2000400,$f2000023,$f22e6880 + dc.l $ff84f200,$0080f200,$04a3f23a,$5580f5ec + dc.l $f23a5500,$f5eef200,$05a3f200,$0523f23a + dc.l $55a2f5e8,$f23a5522,$f5eaf200,$0ca3f200 + dc.l $0123f23a,$54a2f5e4,$f22e4823,$ff84f200 + dc.l $08a2f200,$0423f22e,$4822ff84,$f21fd030 + dc.l $f2009000,$4a106a0c,$f23a4822,$f5d660ff + dc.l $000028c6,$f23a4822,$f5ba60ff,$000028b2 + dc.l $4a106a16,$f23a4800,$f5baf200,$9000f23a + dc.l $4822f5c0,$60ff0000,$28a0f23a,$4800f594 + dc.l $f2009000,$f23a4822,$f5ba60ff,$00002882 + dc.l $60ff0000,$28baf210,$48002210,$32280004 + dc.l $02817fff,$ffff0c81,$3fff8000,$6c4e0c81 + dc.l $3fd78000,$6d00007c,$f23c4480,$3f800000 + dc.l $f20000a8,$f227e004,$f23c4500,$3f800000 + dc.l $f2000122,$f20008a3,$f21fd020,$f2000484 + dc.l $f2000420,$f227e001,$41d761ff,$fffffd66 + dc.l $dffc0000,$000c60ff,$0000280e,$f2000018 + dc.l $f23c4438,$3f800000,$f2d20000,$265af23a + dc.l $4800b8ae,$22100281,$80000000,$00813f80 + dc.l $00002f01,$f2009000,$f21f4423,$60ff0000 + dc.l $27d8f200,$9000123c,$0003f210,$480060ff + dc.l $000027be,$60ff0000,$2806f210,$48002210 + dc.l $32280004,$02817fff,$ffff0c81,$3fff8000 + dc.l $6c44f23c,$44803f80,$0000f200,$00a2f200 + dc.l $001af23c,$44223f80,$0000f200,$0420f200 + dc.l $00042f00,$4280f227,$e00141d7,$61ffffff + dc.l $fcc4dffc,$0000000c,$f21f9000,$f2000022 + dc.l $60ff0000,$276cf200,$0018f23c,$44383f80 + dc.l $0000f2d2,$000025b0,$4a106a18,$f23a4800 + dc.l $b7f0f200,$9000f23c,$44220080,$000060ff + dc.l $0000273e,$60ff0000,$2988f200,$9000f23a + dc.l $4800b7de,$60ff0000,$27283fdc,$000082e3 + dc.l $08654361,$c4c60000,$00003fa5,$55555555 + dc.l $4cc13fc5,$55555555,$4a543f81,$11111117 + dc.l $43853fa5,$55555555,$4f5a3fc5,$55555555 + dc.l $55550000,$00000000,$00003ec7,$1de3a577 + dc.l $46823efa,$01a019d7,$cb683f2a,$01a01a01 + dc.l $9df33f56,$c16c16c1,$70e23f81,$11111111 + dc.l $11113fa5,$55555555,$55553ffc,$0000aaaa + dc.l $aaaaaaaa,$aaab0000,$000048b0,$00000000 + dc.l $00003730,$00000000,$00003fff,$00008000 + dc.l $00000000,$00000000,$00003fff,$00008164 + dc.l $d1f3bc03,$07749f84,$1a9b3fff,$000082cd + dc.l $8698ac2b,$a1d89fc1,$d5b93fff,$0000843a + dc.l $28c3acde,$4048a072,$83693fff,$000085aa + dc.l $c367cc48,$7b141fc5,$c95c3fff,$0000871f + dc.l $61969e8d,$10101ee8,$5c9f3fff,$00008898 + dc.l $0e8092da,$85289fa2,$07293fff,$00008a14 + dc.l $d575496e,$fd9ca07b,$f9af3fff,$00008b95 + dc.l $c1e3ea8b,$d6e8a002,$0dcf3fff,$00008d1a + dc.l $df5b7e5b,$a9e4205a,$63da3fff,$00008ea4 + dc.l $398b45cd,$53c01eb7,$00513fff,$00009031 + dc.l $dc431466,$b1dc1f6e,$b0293fff,$000091c3 + dc.l $d373ab11,$c338a078,$14943fff,$0000935a + dc.l $2b2f13e6,$e92c9eb3,$19b03fff,$000094f4 + dc.l $efa8fef7,$09602017,$457d3fff,$00009694 + dc.l $2d372018,$5a001f11,$d5373fff,$00009837 + dc.l $f0518db8,$a9709fb9,$52dd3fff,$000099e0 + dc.l $459320b7,$fa641fe4,$30873fff,$00009b8d + dc.l $39b9d54e,$55381fa2,$a8183fff,$00009d3e + dc.l $d9a72cff,$b7501fde,$494d3fff,$00009ef5 + dc.l $326091a1,$11ac2050,$48903fff,$0000a0b0 + dc.l $510fb971,$4fc4a073,$691c3fff,$0000a270 + dc.l $43030c49,$68181f9b,$7a053fff,$0000a435 + dc.l $15ae09e6,$80a0a079,$71263fff,$0000a5fe + dc.l $d6a9b151,$38eca071,$a1403fff,$0000a7cd + dc.l $93b4e965,$3568204f,$62da3fff,$0000a9a1 + dc.l $5ab4ea7c,$0ef81f28,$3c4a3fff,$0000ab7a + dc.l $39b5a93e,$d3389f9a,$7fdc3fff,$0000ad58 + dc.l $3eea42a1,$4ac8a05b,$3fac3fff,$0000af3b + dc.l $78ad690a,$43741fdf,$26103fff,$0000b123 + dc.l $f581d2ac,$25909f70,$5f903fff,$0000b311 + dc.l $c412a911,$2488201f,$678a3fff,$0000b504 + dc.l $f333f9de,$64841f32,$fb133fff,$0000b6fd + dc.l $91e328d1,$77902003,$8b303fff,$0000b8fb + dc.l $af4762fb,$9ee8200d,$c3cc3fff,$0000baff + dc.l $5ab2133e,$45fc9f8b,$2ae63fff,$0000bd08 + dc.l $a39f580c,$36c0a02b,$bf703fff,$0000bf17 + dc.l $99b67a73,$1084a00b,$f5183fff,$0000c12c + dc.l $4cca6670,$9458a041,$dd413fff,$0000c346 + dc.l $ccda2497,$64089fdf,$137b3fff,$0000c567 + dc.l $2a115506,$dadc201f,$15683fff,$0000c78d + dc.l $74c8abb9,$b15c1fc1,$3a2e3fff,$0000c9b9 + dc.l $bd866e2f,$27a4a03f,$8f033fff,$0000cbec + dc.l $14fef272,$7c5c1ff4,$907d3fff,$0000ce24 + dc.l $8c151f84,$80e49e6e,$53e43fff,$0000d063 + dc.l $33daef2b,$25941fd6,$d45c3fff,$0000d2a8 + dc.l $1d91f12a,$e45ca076,$edb93fff,$0000d4f3 + dc.l $5aabcfed,$fa209fa6,$de213fff,$0000d744 + dc.l $fccad69d,$6af41ee6,$9a2f3fff,$0000d99d + dc.l $15c278af,$d7b4207f,$439f3fff,$0000dbfb + dc.l $b797daf2,$3754201e,$c2073fff,$0000de60 + dc.l $f4825e0e,$91249e8b,$e1753fff,$0000e0cc + dc.l $deec2a94,$e1102003,$2c4b3fff,$0000e33f + dc.l $8972be8a,$5a502004,$dff53fff,$0000e5b9 + dc.l $06e77c83,$48a81e72,$f47a3fff,$0000e839 + dc.l $6a503c4b,$dc681f72,$2f223fff,$0000eac0 + dc.l $c6e7dd24,$3930a017,$e9453fff,$0000ed4f + dc.l $301ed994,$2b841f40,$1a5b3fff,$0000efe4 + dc.l $b99bdcda,$f5cc9fb9,$a9e33fff,$0000f281 + dc.l $773c59ff,$b1382074,$4c053fff,$0000f525 + dc.l $7d152486,$cc2c1f77,$3a193fff,$0000f7d0 + dc.l $df730ad1,$3bb81ffe,$90d53fff,$0000fa83 + dc.l $b2db722a,$033ca041,$ed223fff,$0000fd3e + dc.l $0c0cf486,$c1741f85,$3f3a2210,$02817fff + dc.l $00000c81,$3fbe0000,$6c0660ff,$00000108 + dc.l $32280004,$0c81400c,$b1676d06,$60ff0000 + dc.l $010cf210,$4800f200,$0080f23c,$442342b8 + dc.l $aa3bf227,$e00c2d7c,$00000000,$ff58f201 + dc.l $600043fa,$fbb6f201,$40002d41,$ff540281 + dc.l $0000003f,$e989d3c1,$222eff54,$ec810641 + dc.l $3fff3d7a,$fb06ff54,$f2000100,$f23c4423 + dc.l $bc317218,$f23a4923,$faf2f200,$0422f200 + dc.l $0822f200,$0080f200,$04a3f23c,$45003ab6 + dc.l $0b70f200,$0523f200,$0580f23c,$45a33c08 + dc.l $8895f23a,$5522fad4,$f23a55a2,$fad6f200 + dc.l $05233d41,$ff842d7c,$80000000,$ff8842ae + dc.l $ff8cf200,$05a3f23c,$45223f00,$0000f200 + dc.l $01a3f200,$0523f200,$0c22f219,$4880f200 + dc.l $0822f200,$0423f21f,$d030f211,$4422f200 + dc.l $0422222e,$ff584a81,$6706f22e,$4823ff90 + dc.l $f2009000,$123c0000,$f22e4823,$ff8460ff + dc.l $0000216e,$f210d080,$f2009000,$f23c4422 + dc.l $3f800000,$60ff0000,$21680c81,$400cb27c + dc.l $6e66f210,$4800f200,$0080f23c,$442342b8 + dc.l $aa3bf227,$e00c2d7c,$00000001,$ff58f201 + dc.l $600043fa,$faa6f201,$40002d41,$ff540281 + dc.l $0000003f,$e989d3c1,$222eff54,$ec812d41 + dc.l $ff54e281,$93aeff54,$06413fff,$3d41ff90 + dc.l $2d7c8000,$0000ff94,$42aeff98,$222eff54 + dc.l $06413fff,$6000fed2,$4a106bff,$00001fbc + dc.l $60ff0000,$20ae2f10,$02978000,$00000097 + dc.l $00800000,$f23c4400,$3f800000,$f2009000 + dc.l $f21f4422,$60ff0000,$20c82210,$02817fff + dc.l $00000c81,$3ffd0000,$6c0660ff,$0000015e + dc.l $32280004,$0c814004,$c2156f06,$60ff0000 + dc.l $026cf210,$4800f200,$0080f23c,$442342b8 + dc.l $aa3bf227,$e00cf201,$600043fa,$f9eef201 + dc.l $40002d41,$ff540281,$0000003f,$e989d3c1 + dc.l $222eff54,$ec812d41,$ff54f200,$0100f23c + dc.l $4423bc31,$7218f23a,$4923f930,$f2000422 + dc.l $f2000822,$06413fff,$f2000080,$f20004a3 + dc.l $f23c4500,$3950097b,$f2000523,$f2000580 + dc.l $f23c45a3,$3ab60b6a,$f23a5522,$f91ef23a + dc.l $55a2f920,$3d41ff84,$2d7c8000,$0000ff88 + dc.l $42aeff8c,$f2000523,$222eff54,$4441f200 + dc.l $05a30641,$3ffff23a,$5522f900,$f23c45a2 + dc.l $3f000000,$f2000523,$00418000,$3d41ff90 + dc.l $2d7c8000,$0000ff94,$42aeff98,$f2000ca3 + dc.l $f2000123,$f2000422,$f2000822,$f21fd030 + dc.l $f2114823,$222eff54,$0c810000,$003f6f1a + dc.l $f2294480,$000cf22e,$48a2ff90,$f2000422 + dc.l $f2114822,$60ff0000,$00340c81,$fffffffd + dc.l $6c16f229,$4422000c,$f2114822,$f22e4822 + dc.l $ff9060ff,$00000016,$f2194880,$f2114422 + dc.l $f22e48a2,$ff90f200,$0422f200,$9000f22e + dc.l $4823ff84,$60ff0000,$1f500c81,$3fbe0000 + dc.l $6c6c0c81,$00330000,$6d2c2d7c,$80010000 + dc.l $ff842d7c,$80000000,$ff8842ae,$ff8cf210 + dc.l $4800f200,$9000123c,$0002f22e,$4822ff84 + dc.l $60ff0000,$1f0cf210,$4800f23a,$5423f86c + dc.l $2d7c8001,$0000ff84,$2d7c8000,$0000ff88 + dc.l $42aeff8c,$f22e4822,$ff84f200,$9000123c + dc.l $0000f23a,$5423f84c,$60ff0000,$1ed4f210 + dc.l $4800f200,$0023f227,$e00cf23c,$44802f30 + dc.l $caa8f200,$00a3f23c,$4500310f,$8290f23c + dc.l $44a232d7,$3220f200,$0123f200,$00a3f23c + dc.l $45223493,$f281f23a,$54a2f7c0,$f2000123 + dc.l $f20000a3,$f23a5522,$f7baf23a,$54a2f7bc + dc.l $f2000123,$f20000a3,$f23a5522,$f7b6f23a + dc.l $54a2f7b8,$f2000123,$f20000a3,$f23a5522 + dc.l $f7b2f23a,$48a2f7b4,$f2000123,$f20000a3 + dc.l $f2000123,$f21048a3,$f23c4423,$3f000000 + dc.l $f20008a2,$f21fd030,$f2000422,$f2009000 + dc.l $f2104822,$60ff0000,$1e302210,$0c810000 + dc.l $00006e00,$fbacf23c,$4400bf80,$0000f200 + dc.l $9000f23c,$44220080,$000060ff,$00001e1a + dc.l $60ff0000,$1e4a3028,$00000880,$000f0440 + dc.l $3ffff200,$50006d02,$4e751d7c,$0008ff64 + dc.l $4e7561ff,$00002342,$44400440,$3ffff200 + dc.l $50001d7c,$0008ff64,$4e753028,$00000040 + dc.l $7fff0880,$000e2d68,$0004ff88,$2d680008 + dc.l $ff8c3d40,$ff84f22e,$4800ff84,$6b024e75 + dc.l $1d7c0008,$ff644e75,$61ff0000,$22fc60ca + dc.l $7ffb0000,$80000000,$00000000,$00000000 + dc.l $f2104800,$22103228,$00040281,$7fffffff + dc.l $0c81400c,$b1676e42,$f2000018,$2f004280 + dc.l $f227e001,$41d761ff,$fffffad2,$dffc0000 + dc.l $000cf23c,$44233f00,$0000201f,$f23c4480 + dc.l $3e800000,$f20000a0,$f2009000,$123c0002 + dc.l $f2000422,$60ff0000,$1d280c81,$400cb2b3 + dc.l $6e3cf200,$0018f23a,$5428adb6,$f23a5428 + dc.l $adb82f00,$4280f227,$e00141d7,$61ffffff + dc.l $fa7cdffc,$0000000c,$201ff200,$9000123c + dc.l $0000f23a,$4823ff5a,$60ff0000,$1ce460ff + dc.l $00001cb0,$f23c4400,$3f800000,$f2009000 + dc.l $f23c4422,$00800000,$60ff0000,$1cd4f210 + dc.l $48002210,$32280004,$22410281,$7fffffff + dc.l $0c81400c,$b1676e62,$f2000018,$48e78040 + dc.l $f227e001,$41d74280,$61ffffff,$fbe0dffc + dc.l $0000000c,$f23c9000,$00000000,$4cdf0201 + dc.l $f2000080,$f23c44a2,$3f800000,$f2276800 + dc.l $f2000420,$22090281,$80000000,$00813f00 + dc.l $0000f21f,$48222f01,$f2009000,$123c0000 + dc.l $f21f4423,$60ff0000,$1c480c81,$400cb2b3 + dc.l $6eff0000,$1bc2f200,$0018f23a,$5428acd2 + dc.l $2f3c0000,$00002f3c,$80000000,$22090281 + dc.l $80000000,$00817ffb,$00002f01,$f23a5428 + dc.l $acb82f00,$4280f227,$e00141d7,$61ffffff + dc.l $f97cdffc,$0000000c,$201ff200,$9000123c + dc.l $0000f21f,$482360ff,$00001be6,$60ff0000 + dc.l $1c2ef210,$4800f22e,$6800ff84,$22103228 + dc.l $00042d41,$ff840281,$7fffffff,$0c813fd7 + dc.l $80006d00,$00740c81,$3fffddce,$6e00006a + dc.l $222eff84,$2d41ff5c,$02817fff,$00000681 + dc.l $00010000,$2d41ff84,$02ae8000,$0000ff5c + dc.l $f22e4800,$ff842f00,$4280f227,$e00141d7 + dc.l $61ffffff,$fac8dffc,$0000000c,$201ff200 + dc.l $0080f23c,$44a24000,$0000222e,$ff5cf22e + dc.l $6880ff84,$b3aeff84,$f2009000,$f22e4820 + dc.l $ff8460ff,$00001b52,$0c813fff,$80006d00 + dc.l $00880c81,$40048aa1,$6e000092,$222eff84 + dc.l $2d41ff5c,$02817fff,$00000681,$00010000 + dc.l $2d41ff84,$02ae8000,$0000ff5c,$222eff5c + dc.l $f22e4800,$ff842f00,$4280f227,$e00141d7 + dc.l $61ffffff,$f878dffc,$0000000c,$201f222e + dc.l $ff5cf23c,$44223f80,$00000a81,$c0000000 + dc.l $f2014480,$f20000a0,$222eff5c,$00813f80 + dc.l $0000f201,$4400f200,$9000123c,$0002f200 + dc.l $042260ff,$00001ac2,$f2009000,$123c0003 + dc.l $f22e4800,$ff8460ff,$00001aa6,$222eff84 + dc.l $02818000,$00000081,$3f800000,$f2014400 + dc.l $02818000,$00000a81,$80800000,$f2009000 + dc.l $f2014422,$60ff0000,$1a8060ff,$00001ac0 + dc.l $3ffe0000,$b17217f7,$d1cf79ac,$00000000 + dc.l $3f800000,$00000000,$7f800000,$bf800000 + dc.l $3fc2499a,$b5e4040b,$bfc555b5,$848cb7db + dc.l $3fc99999,$987d8730,$bfcfffff,$ff6f7e97 + dc.l $3fd55555,$555555a4,$bfe00000,$00000008 + dc.l $3f175496,$add7dad6,$3f3c71c2,$fe80c7e0 + dc.l $3f624924,$928bccff,$3f899999,$999995ec + dc.l $3fb55555,$55555555,$40000000,$00000000 + dc.l $3f990000,$80000000,$00000000,$00000000 + dc.l $3ffe0000,$fe03f80f,$e03f80fe,$00000000 + dc.l $3ff70000,$ff015358,$833c47e2,$00000000 + dc.l $3ffe0000,$fa232cf2,$52138ac0,$00000000 + dc.l $3ff90000,$bdc8d83e,$ad88d549,$00000000 + dc.l $3ffe0000,$f6603d98,$0f6603da,$00000000 + dc.l $3ffa0000,$9cf43dcf,$f5eafd48,$00000000 + dc.l $3ffe0000,$f2b9d648,$0f2b9d65,$00000000 + dc.l $3ffa0000,$da16eb88,$cb8df614,$00000000 + dc.l $3ffe0000,$ef2eb71f,$c4345238,$00000000 + dc.l $3ffb0000,$8b29b775,$1bd70743,$00000000 + dc.l $3ffe0000,$ebbdb2a5,$c1619c8c,$00000000 + dc.l $3ffb0000,$a8d839f8,$30c1fb49,$00000000 + dc.l $3ffe0000,$e865ac7b,$7603a197,$00000000 + dc.l $3ffb0000,$c61a2eb1,$8cd907ad,$00000000 + dc.l $3ffe0000,$e525982a,$f70c880e,$00000000 + dc.l $3ffb0000,$e2f2a47a,$de3a18af,$00000000 + dc.l $3ffe0000,$e1fc780e,$1fc780e2,$00000000 + dc.l $3ffb0000,$ff64898e,$df55d551,$00000000 + dc.l $3ffe0000,$dee95c4c,$a037ba57,$00000000 + dc.l $3ffc0000,$8db956a9,$7b3d0148,$00000000 + dc.l $3ffe0000,$dbeb61ee,$d19c5958,$00000000 + dc.l $3ffc0000,$9b8fe100,$f47ba1de,$00000000 + dc.l $3ffe0000,$d901b203,$6406c80e,$00000000 + dc.l $3ffc0000,$a9372f1d,$0da1bd17,$00000000 + dc.l $3ffe0000,$d62b80d6,$2b80d62c,$00000000 + dc.l $3ffc0000,$b6b07f38,$ce90e46b,$00000000 + dc.l $3ffe0000,$d3680d36,$80d3680d,$00000000 + dc.l $3ffc0000,$c3fd0329,$06488481,$00000000 + dc.l $3ffe0000,$d0b69fcb,$d2580d0b,$00000000 + dc.l $3ffc0000,$d11de0ff,$15ab18ca,$00000000 + dc.l $3ffe0000,$ce168a77,$25080ce1,$00000000 + dc.l $3ffc0000,$de1433a1,$6c66b150,$00000000 + dc.l $3ffe0000,$cb8727c0,$65c393e0,$00000000 + dc.l $3ffc0000,$eae10b5a,$7ddc8add,$00000000 + dc.l $3ffe0000,$c907da4e,$871146ad,$00000000 + dc.l $3ffc0000,$f7856e5e,$e2c9b291,$00000000 + dc.l $3ffe0000,$c6980c69,$80c6980c,$00000000 + dc.l $3ffd0000,$82012ca5,$a68206d7,$00000000 + dc.l $3ffe0000,$c4372f85,$5d824ca6,$00000000 + dc.l $3ffd0000,$882c5fcd,$7256a8c5,$00000000 + dc.l $3ffe0000,$c1e4bbd5,$95f6e947,$00000000 + dc.l $3ffd0000,$8e44c60b,$4ccfd7de,$00000000 + dc.l $3ffe0000,$bfa02fe8,$0bfa02ff,$00000000 + dc.l $3ffd0000,$944ad09e,$f4351af6,$00000000 + dc.l $3ffe0000,$bd691047,$07661aa3,$00000000 + dc.l $3ffd0000,$9a3eecd4,$c3eaa6b2,$00000000 + dc.l $3ffe0000,$bb3ee721,$a54d880c,$00000000 + dc.l $3ffd0000,$a0218434,$353f1de8,$00000000 + dc.l $3ffe0000,$b92143fa,$36f5e02e,$00000000 + dc.l $3ffd0000,$a5f2fcab,$bbc506da,$00000000 + dc.l $3ffe0000,$b70fbb5a,$19be3659,$00000000 + dc.l $3ffd0000,$abb3b8ba,$2ad362a5,$00000000 + dc.l $3ffe0000,$b509e68a,$9b94821f,$00000000 + dc.l $3ffd0000,$b1641795,$ce3ca97b,$00000000 + dc.l $3ffe0000,$b30f6352,$8917c80b,$00000000 + dc.l $3ffd0000,$b7047551,$5d0f1c61,$00000000 + dc.l $3ffe0000,$b11fd3b8,$0b11fd3c,$00000000 + dc.l $3ffd0000,$bc952afe,$ea3d13e1,$00000000 + dc.l $3ffe0000,$af3addc6,$80af3ade,$00000000 + dc.l $3ffd0000,$c2168ed0,$f458ba4a,$00000000 + dc.l $3ffe0000,$ad602b58,$0ad602b6,$00000000 + dc.l $3ffd0000,$c788f439,$b3163bf1,$00000000 + dc.l $3ffe0000,$ab8f69e2,$8359cd11,$00000000 + dc.l $3ffd0000,$ccecac08,$bf04565d,$00000000 + dc.l $3ffe0000,$a9c84a47,$a07f5638,$00000000 + dc.l $3ffd0000,$d2420487,$2dd85160,$00000000 + dc.l $3ffe0000,$a80a80a8,$0a80a80b,$00000000 + dc.l $3ffd0000,$d7894992,$3bc3588a,$00000000 + dc.l $3ffe0000,$a655c439,$2d7b73a8,$00000000 + dc.l $3ffd0000,$dcc2c4b4,$9887dacc,$00000000 + dc.l $3ffe0000,$a4a9cf1d,$96833751,$00000000 + dc.l $3ffd0000,$e1eebd3e,$6d6a6b9e,$00000000 + dc.l $3ffe0000,$a3065e3f,$ae7cd0e0,$00000000 + dc.l $3ffd0000,$e70d785c,$2f9f5bdc,$00000000 + dc.l $3ffe0000,$a16b312e,$a8fc377d,$00000000 + dc.l $3ffd0000,$ec1f392c,$5179f283,$00000000 + dc.l $3ffe0000,$9fd809fd,$809fd80a,$00000000 + dc.l $3ffd0000,$f12440d3,$e36130e6,$00000000 + dc.l $3ffe0000,$9e4cad23,$dd5f3a20,$00000000 + dc.l $3ffd0000,$f61cce92,$346600bb,$00000000 + dc.l $3ffe0000,$9cc8e160,$c3fb19b9,$00000000 + dc.l $3ffd0000,$fb091fd3,$8145630a,$00000000 + dc.l $3ffe0000,$9b4c6f9e,$f03a3caa,$00000000 + dc.l $3ffd0000,$ffe97042,$bfa4c2ad,$00000000 + dc.l $3ffe0000,$99d722da,$bde58f06,$00000000 + dc.l $3ffe0000,$825efced,$49369330,$00000000 + dc.l $3ffe0000,$9868c809,$868c8098,$00000000 + dc.l $3ffe0000,$84c37a7a,$b9a905c9,$00000000 + dc.l $3ffe0000,$97012e02,$5c04b809,$00000000 + dc.l $3ffe0000,$87224c2e,$8e645fb7,$00000000 + dc.l $3ffe0000,$95a02568,$095a0257,$00000000 + dc.l $3ffe0000,$897b8cac,$9f7de298,$00000000 + dc.l $3ffe0000,$94458094,$45809446,$00000000 + dc.l $3ffe0000,$8bcf55de,$c4cd05fe,$00000000 + dc.l $3ffe0000,$92f11384,$0497889c,$00000000 + dc.l $3ffe0000,$8e1dc0fb,$89e125e5,$00000000 + dc.l $3ffe0000,$91a2b3c4,$d5e6f809,$00000000 + dc.l $3ffe0000,$9066e68c,$955b6c9b,$00000000 + dc.l $3ffe0000,$905a3863,$3e06c43b,$00000000 + dc.l $3ffe0000,$92aade74,$c7be59e0,$00000000 + dc.l $3ffe0000,$8f1779d9,$fdc3a219,$00000000 + dc.l $3ffe0000,$94e9bff6,$15845643,$00000000 + dc.l $3ffe0000,$8dda5202,$37694809,$00000000 + dc.l $3ffe0000,$9723a1b7,$20134203,$00000000 + dc.l $3ffe0000,$8ca29c04,$6514e023,$00000000 + dc.l $3ffe0000,$995899c8,$90eb8990,$00000000 + dc.l $3ffe0000,$8b70344a,$139bc75a,$00000000 + dc.l $3ffe0000,$9b88bdaa,$3a3dae2f,$00000000 + dc.l $3ffe0000,$8a42f870,$5669db46,$00000000 + dc.l $3ffe0000,$9db4224f,$ffe1157c,$00000000 + dc.l $3ffe0000,$891ac73a,$e9819b50,$00000000 + dc.l $3ffe0000,$9fdadc26,$8b7a12da,$00000000 + dc.l $3ffe0000,$87f78087,$f78087f8,$00000000 + dc.l $3ffe0000,$a1fcff17,$ce733bd4,$00000000 + dc.l $3ffe0000,$86d90544,$7a34acc6,$00000000 + dc.l $3ffe0000,$a41a9e8f,$5446fb9f,$00000000 + dc.l $3ffe0000,$85bf3761,$2cee3c9b,$00000000 + dc.l $3ffe0000,$a633cd7e,$6771cd8b,$00000000 + dc.l $3ffe0000,$84a9f9c8,$084a9f9d,$00000000 + dc.l $3ffe0000,$a8489e60,$0b435a5e,$00000000 + dc.l $3ffe0000,$83993052,$3fbe3368,$00000000 + dc.l $3ffe0000,$aa59233c,$cca4bd49,$00000000 + dc.l $3ffe0000,$828cbfbe,$b9a020a3,$00000000 + dc.l $3ffe0000,$ac656dae,$6bcc4985,$00000000 + dc.l $3ffe0000,$81848da8,$faf0d277,$00000000 + dc.l $3ffe0000,$ae6d8ee3,$60bb2468,$00000000 + dc.l $3ffe0000,$80808080,$80808081,$00000000 + dc.l $3ffe0000,$b07197a2,$3c46c654,$00000000 + dc.l $f2104800,$2d7c0000,$0000ff54,$22103228 + dc.l $00042d50,$ff842d68,$0004ff88,$2d680008 + dc.l $ff8c0c81,$00000000,$6d000182,$0c813ffe + dc.l $f07d6d0a,$0c813fff,$88416f00,$00e2e081 + dc.l $e0810481,$00003fff,$d2aeff54,$41faf7b2 + dc.l $f2014080,$2d7c3fff,$0000ff84,$2d6eff88 + dc.l $ff9402ae,$fe000000,$ff9400ae,$01000000 + dc.l $ff94222e,$ff940281,$7e000000,$e081e081 + dc.l $e881d1c1,$f22e4800,$ff842d7c,$3fff0000 + dc.l $ff9042ae,$ff98f22e,$4828ff90,$f227e00c + dc.l $f2104823,$f23a48a3,$f6c8f200,$0100f200 + dc.l $0923f22e,$6880ff84,$f2000980,$f2000880 + dc.l $f23a54a3,$f6ccf23a,$5523f6ce,$f23a54a2 + dc.l $f6d0f23a,$5522f6d2,$f2000ca3,$f2000d23 + dc.l $f23a54a2,$f6ccf23a,$5522f6ce,$f2000ca3 + dc.l $d1fc0000,$0010f200,$0d23f200,$00a3f200 + dc.l $0822f210,$48a2f21f,$d030f200,$0422f200 + dc.l $9000f22e,$4822ff84,$60ff0000,$10ccf23c + dc.l $58380001,$f2c10000,$1318f200,$0080f23a + dc.l $44a8f64e,$f23a4422,$f648f200,$04a2f200 + dc.l $00a0f227,$e00cf200,$0400f200,$0023f22e + dc.l $6880ff84,$f2000080,$f20004a3,$f23a5580 + dc.l $f660f23a,$5500f662,$f20005a3,$f2000523 + dc.l $f23a55a2,$f65cf23a,$5522f65e,$f2000ca3 + dc.l $f2000123,$f23a54a2,$f658f22e,$4823ff84 + dc.l $f20008a2,$f21fd030,$f2000423,$f2009000 + dc.l $f22e4822,$ff8460ff,$0000103e,$60ff0000 + dc.l $0e962d7c,$ffffff9c,$ff5448e7,$3f002610 + dc.l $28280004,$2a280008,$42824a84,$66342805 + dc.l $42857420,$4286edc4,$6000edac,$d4862d43 + dc.l $ff842d44,$ff882d45,$ff8c4482,$2d42ff54 + dc.l $f22e4800,$ff844cdf,$00fc41ee,$ff846000 + dc.l $fe0c4286,$edc46000,$2406edac,$2e05edad + dc.l $44860686,$00000020,$ecaf8887,$2d43ff84 + dc.l $2d44ff88,$2d45ff8c,$44822d42,$ff54f22e + dc.l $4800ff84,$4cdf00fc,$41eeff84,$6000fdce + dc.l $f2104800,$f2000018,$f23a4838,$f5a4f292 + dc.l $0014f200,$9000123c,$0003f210,$480060ff + dc.l $00000f7e,$f2104800,$2d7c0000,$0000ff54 + dc.l $f2000080,$f23a4422,$f508f22e,$6800ff84 + dc.l $3d6eff88,$ff86222e,$ff840c81,$00000000 + dc.l $6f0000da,$0c813ffe,$80006d00,$fda20c81 + dc.l $3fffc000,$6e00fd98,$0c813ffe,$f07d6d00 + dc.l $001a0c81,$3fff8841,$6e000010,$f20004a2 + dc.l $f23a4422,$f4bc6000,$fe762d6e,$ff88ff94 + dc.l $02aefe00,$0000ff94,$00ae0100,$0000ff94 + dc.l $0c813fff,$80006c44,$f23a4400,$f4fc2d7c + dc.l $3fff0000,$ff9042ae,$ff98f22e,$4828ff90 + dc.l $222eff94,$02817e00,$0000e081,$e081e881 + dc.l $f20004a2,$f227e00c,$f2000422,$41faf4e2 + dc.l $d1c1f23a,$4480f466,$6000fd76,$f23a4400 + dc.l $f4502d7c,$3fff0000,$ff9042ae,$ff98f22e + dc.l $4828ff90,$222eff94,$02817e00,$0000e081 + dc.l $e081e881,$f2000422,$f227e00c,$41faf4a2 + dc.l $d1c1f23a,$4480f41e,$6000fd36,$0c810000 + dc.l $00006d10,$f23a4400,$f414f200,$900060ff + dc.l $00000c4e,$f23a4400,$f3fcf200,$900060ff + dc.l $00000cb4,$60ff0000,$0e962210,$32280004 + dc.l $02817fff,$ffff0c81,$3fff8000,$6c56f210 + dc.l $4818f200,$0080f200,$049af200,$0022f23c + dc.l $44a23f80,$0000f200,$04202210,$02818000 + dc.l $00000081,$3f000000,$2f012f00,$4280f227 + dc.l $e00141d7,$61ffffff,$fe5adffc,$0000000c + dc.l $201ff200,$9000123c,$0000f21f,$442360ff + dc.l $00000dde,$f2104818,$f23c4438,$3f800000 + dc.l $f2d20000,$0c3260ff,$00000bb6,$60ff0000 + dc.l $0e0e3ffd,$0000de5b,$d8a93728,$71950000 + dc.l $00003fff,$0000b8aa,$3b295c17,$f0bc0000 + dc.l $0000f23c,$58000001,$f2104838,$f2c10000 + dc.l $0ff02210,$6d000090,$2f004280,$61ffffff + dc.l $fba2f21f,$9000f23a,$4823ffb8,$60ff0000 + dc.l $0d782210,$6d000070,$2f004280,$61ffffff + dc.l $fd34f21f,$9000f23a,$4823ff98,$60ff0000 + dc.l $0d682210,$6d000050,$22280008,$662e2228 + dc.l $00040281,$7fffffff,$66223210,$02810000 + dc.l $7fff0481,$00003fff,$67ff0000,$0f84f200 + dc.l $9000f201,$400060ff,$00000d1e,$2f004280 + dc.l $61ffffff,$fb2ef21f,$9000f23a,$4823ff54 + dc.l $60ff0000,$0d0460ff,$00000b5c,$22106d00 + dc.l $fff62f00,$428061ff,$fffffcba,$f21f9000 + dc.l $f23a4823,$ff2e60ff,$00000cee,$406a934f + dc.l $0979a371,$3f734413,$509f8000,$bfcd0000 + dc.l $c0219dc1,$da994fd2,$00000000,$40000000 + dc.l $935d8ddd,$aaa8ac17,$00000000,$3ffe0000 + dc.l $b17217f7,$d1cf79ac,$00000000,$3f56c16d + dc.l $6f7bd0b2,$3f811112,$302c712c,$3fa55555 + dc.l $55554cc1,$3fc55555,$55554a54,$3fe00000 + dc.l $00000000,$00000000,$00000000,$3fff0000 + dc.l $80000000,$00000000,$3f738000,$3fff0000 + dc.l $8164d1f3,$bc030773,$3fbef7ca,$3fff0000 + dc.l $82cd8698,$ac2ba1d7,$3fbdf8a9,$3fff0000 + dc.l $843a28c3,$acde4046,$3fbcd7c9,$3fff0000 + dc.l $85aac367,$cc487b15,$bfbde8da,$3fff0000 + dc.l $871f6196,$9e8d1010,$3fbde85c,$3fff0000 + dc.l $88980e80,$92da8527,$3fbebbf1,$3fff0000 + dc.l $8a14d575,$496efd9a,$3fbb80ca,$3fff0000 + dc.l $8b95c1e3,$ea8bd6e7,$bfba8373,$3fff0000 + dc.l $8d1adf5b,$7e5ba9e6,$bfbe9670,$3fff0000 + dc.l $8ea4398b,$45cd53c0,$3fbdb700,$3fff0000 + dc.l $9031dc43,$1466b1dc,$3fbeeeb0,$3fff0000 + dc.l $91c3d373,$ab11c336,$3fbbfd6d,$3fff0000 + dc.l $935a2b2f,$13e6e92c,$bfbdb319,$3fff0000 + dc.l $94f4efa8,$fef70961,$3fbdba2b,$3fff0000 + dc.l $96942d37,$20185a00,$3fbe91d5,$3fff0000 + dc.l $9837f051,$8db8a96f,$3fbe8d5a,$3fff0000 + dc.l $99e04593,$20b7fa65,$bfbcde7b,$3fff0000 + dc.l $9b8d39b9,$d54e5539,$bfbebaaf,$3fff0000 + dc.l $9d3ed9a7,$2cffb751,$bfbd86da,$3fff0000 + dc.l $9ef53260,$91a111ae,$bfbebedd,$3fff0000 + dc.l $a0b0510f,$b9714fc2,$3fbcc96e,$3fff0000 + dc.l $a2704303,$0c496819,$bfbec90b,$3fff0000 + dc.l $a43515ae,$09e6809e,$3fbbd1db,$3fff0000 + dc.l $a5fed6a9,$b15138ea,$3fbce5eb,$3fff0000 + dc.l $a7cd93b4,$e965356a,$bfbec274,$3fff0000 + dc.l $a9a15ab4,$ea7c0ef8,$3fbea83c,$3fff0000 + dc.l $ab7a39b5,$a93ed337,$3fbecb00,$3fff0000 + dc.l $ad583eea,$42a14ac6,$3fbe9301,$3fff0000 + dc.l $af3b78ad,$690a4375,$bfbd8367,$3fff0000 + dc.l $b123f581,$d2ac2590,$bfbef05f,$3fff0000 + dc.l $b311c412,$a9112489,$3fbdfb3c,$3fff0000 + dc.l $b504f333,$f9de6484,$3fbeb2fb,$3fff0000 + dc.l $b6fd91e3,$28d17791,$3fbae2cb,$3fff0000 + dc.l $b8fbaf47,$62fb9ee9,$3fbcdc3c,$3fff0000 + dc.l $baff5ab2,$133e45fb,$3fbee9aa,$3fff0000 + dc.l $bd08a39f,$580c36bf,$bfbeaefd,$3fff0000 + dc.l $bf1799b6,$7a731083,$bfbcbf51,$3fff0000 + dc.l $c12c4cca,$66709456,$3fbef88a,$3fff0000 + dc.l $c346ccda,$24976407,$3fbd83b2,$3fff0000 + dc.l $c5672a11,$5506dadd,$3fbdf8ab,$3fff0000 + dc.l $c78d74c8,$abb9b15d,$bfbdfb17,$3fff0000 + dc.l $c9b9bd86,$6e2f27a3,$bfbefe3c,$3fff0000 + dc.l $cbec14fe,$f2727c5d,$bfbbb6f8,$3fff0000 + dc.l $ce248c15,$1f8480e4,$bfbcee53,$3fff0000 + dc.l $d06333da,$ef2b2595,$bfbda4ae,$3fff0000 + dc.l $d2a81d91,$f12ae45a,$3fbc9124,$3fff0000 + dc.l $d4f35aab,$cfedfa1f,$3fbeb243,$3fff0000 + dc.l $d744fcca,$d69d6af4,$3fbde69a,$3fff0000 + dc.l $d99d15c2,$78afd7b6,$bfb8bc61,$3fff0000 + dc.l $dbfbb797,$daf23755,$3fbdf610,$3fff0000 + dc.l $de60f482,$5e0e9124,$bfbd8be1,$3fff0000 + dc.l $e0ccdeec,$2a94e111,$3fbacb12,$3fff0000 + dc.l $e33f8972,$be8a5a51,$3fbb9bfe,$3fff0000 + dc.l $e5b906e7,$7c8348a8,$3fbcf2f4,$3fff0000 + dc.l $e8396a50,$3c4bdc68,$3fbef22f,$3fff0000 + dc.l $eac0c6e7,$dd24392f,$bfbdbf4a,$3fff0000 + dc.l $ed4f301e,$d9942b84,$3fbec01a,$3fff0000 + dc.l $efe4b99b,$dcdaf5cb,$3fbe8cac,$3fff0000 + dc.l $f281773c,$59ffb13a,$bfbcbb3f,$3fff0000 + dc.l $f5257d15,$2486cc2c,$3fbef73a,$3fff0000 + dc.l $f7d0df73,$0ad13bb9,$bfb8b795,$3fff0000 + dc.l $fa83b2db,$722a033a,$3fbef84b,$3fff0000 + dc.l $fd3e0c0c,$f486c175,$bfbef581,$f210d080 + dc.l $22103228,$0004f22e,$6800ff84,$02817fff + dc.l $ffff0c81,$3fb98000,$6c046000,$00880c81 + dc.l $400d80c0,$6f046000,$007cf200,$0080f23c + dc.l $44a34280,$0000f22e,$6080ff54,$2f0243fa + dc.l $fbbcf22e,$4080ff54,$222eff54,$24010281 + dc.l $0000003f,$e981d3c1,$ec822202,$e2819481 + dc.l $06820000,$3ffff227,$e00cf23c,$44a33c80 + dc.l $00002d59,$ff842d59,$ff882d59,$ff8c3d59 + dc.l $ff90f200,$04283d59,$ff94426e,$ff9642ae + dc.l $ff98d36e,$ff84f23a,$4823fb22,$d36eff90 + dc.l $60000100,$0c813fff,$80006e12,$f2009000 + dc.l $f23c4422,$3f800000,$60ff0000,$07b4222e + dc.l $ff840c81,$00000000,$6d0660ff,$00000764 + dc.l $60ff0000,$0666f200,$9000f23c,$44003f80 + dc.l $00002210,$00810080,$0001f201,$442260ff + dc.l $0000077e,$f210d080,$22103228,$0004f22e + dc.l $6800ff84,$02817fff,$ffff0c81,$3fb98000 + dc.l $6c046000,$ff900c81,$400b9b07,$6f046000 + dc.l $ff84f200,$0080f23a,$54a3fa62,$f22e6080 + dc.l $ff542f02,$43fafac6,$f22e4080,$ff54222e + dc.l $ff542401,$02810000,$003fe981,$d3c1ec82 + dc.l $2202e281,$94810682,$00003fff,$f227e00c + dc.l $f2000500,$f23a54a3,$fa2c2d59,$ff84f23a + dc.l $4923fa2a,$2d59ff88,$2d59ff8c,$f2000428 + dc.l $3d59ff90,$f2000828,$3d59ff94,$426eff96 + dc.l $42aeff98,$f23a4823,$fa14d36e,$ff84d36e + dc.l $ff90f200,$0080f200,$04a3f23a,$5500fa1e + dc.l $f23a5580,$fa20f200,$0523f200,$05a3f23a + dc.l $5522fa1a,$f23a55a2,$fa1cf200,$0523f200 + dc.l $05a3f23a,$5522fa16,$f20001a3,$f2000523 + dc.l $f2000c22,$f2000822,$f21fd030,$f22e4823 + dc.l $ff84f22e,$4822ff90,$f22e4822,$ff84f200 + dc.l $90003d42,$ff84241f,$2d7c8000,$0000ff88 + dc.l $42aeff8c,$123c0000,$f22e4823,$ff8460ff + dc.l $0000063e,$f2009000,$f23c4400,$3f800000 + dc.l $22100081,$00800001,$f2014422,$60ff0000 + dc.l $06302f00,$32290000,$5beeff54,$02810000 + dc.l $7fff3028,$00000240,$7fff0c40,$3fff6d00 + dc.l $00c00c40,$400c6e00,$00a4f228,$48030000 + dc.l $f2006000,$f23c8800,$00000000,$4a290004 + dc.l $6b5e2f00,$3d690000,$ff842d69,$0004ff88 + dc.l $2d690008,$ff8c41ee,$ff8461ff,$00000b2a + dc.l $4480d09f,$f22ed080,$ff840c40,$c0016c36 + dc.l $f21f9000,$223c8000,$00000480,$ffffc001 + dc.l $44800c00,$00206c0a,$e0a942a7,$2f0142a7 + dc.l $60280400,$0020e0a9,$2f0142a7,$42a7601a + dc.l $f229d080,$0000f21f,$90000640,$3fff4840 + dc.l $42a72f3c,$80000000,$2f00f200,$b000123c + dc.l $0000f21f,$482360ff,$0000054c,$201fc149 + dc.l $4a290000,$6bff0000,$041c60ff,$00000464 + dc.l $4a290004,$6a16201f,$f2009000,$123c0003 + dc.l $f2294800,$000060ff,$0000051c,$201f2049 + dc.l $60ff0000,$05860001,$00008000,$00000000 + dc.l $00000000,$0000422e,$ff652f00,$422eff5c + dc.l $600c422e,$ff652f00,$1d7c0001,$ff5c48e7 + dc.l $3f003628,$00003d43,$ff580283,$00007fff + dc.l $28280004,$2a280008,$4a83663c,$263c0000 + dc.l $3ffe4a84,$66162805,$42850483,$00000020 + dc.l $4286edc4,$6000edac,$96866022,$4286edc4 + dc.l $60009686,$edac2e05,$edad4486,$06860000 + dc.l $0020ecaf,$88876006,$06830000,$3ffe3029 + dc.l $00003d40,$ff5a322e,$ff58b181,$02810000 + dc.l $80003d41,$ff5e0280,$00007fff,$22290004 + dc.l $24290008,$4a80663c,$203c0000,$3ffe4a81 + dc.l $66162202,$42820480,$00000020,$4286edc1 + dc.l $6000eda9,$90866022,$4286edc1,$60009086 + dc.l $eda92e02,$edaa4486,$06860000,$0020ecaf + dc.l $82876006,$06800000,$3ffe2d43,$ff542f00 + dc.l $90834286,$4283227c,$00000000,$4a806c06 + dc.l $201f6000,$006a588f,$4a866e0e,$b2846608 + dc.l $b4856604,$60000136,$65089485,$93844286 + dc.l $52834a80,$670ed683,$d482e391,$55c65289 + dc.l $538060d4,$202eff54,$4a816616,$22024282 + dc.l $04800000,$00204286,$edc16000,$eda99086 + dc.l $601c4286,$edc16000,$6b149086,$eda92e02 + dc.l $edaa4486,$06860000,$0020ecaf,$82870c80 + dc.l $000041fe,$6c2a3d40,$ff902d41,$ff942d42 + dc.l $ff982c2e,$ff543d46,$ff842d44,$ff882d45 + dc.l $ff8cf22e,$4800ff90,$1d7c0001,$ff5d6036 + dc.l $2d41ff94,$2d42ff98,$04800000,$3ffe3d40 + dc.l $ff902c2e,$ff540486,$00003ffe,$2d46ff54 + dc.l $f22e4800,$ff903d46,$ff842d44,$ff882d45 + dc.l $ff8c422e,$ff5d4a2e,$ff5c6722,$2c2eff54 + dc.l $5386b086,$6d186e0e,$b2846608,$b4856604 + dc.l $6000007a,$6508f22e,$4828ff84,$52833c2e + dc.l $ff5a6c04,$f200001a,$42863c2e,$ff5e7e08 + dc.l $eeae0283,$0000007f,$86861d43,$ff654cdf + dc.l $00fc201f,$f2009000,$4a2eff5d,$6710123c + dc.l $0000f23a,$4823fdc0,$60ff0000,$02ca123c + dc.l $0003f200,$000060ff,$000002bc,$52830c80 + dc.l $00000008,$6c04e1ab,$60024283,$f23c4400 + dc.l $00000000,$422eff5d,$6000ff94,$2c030286 + dc.l $00000001,$4a866700,$ff865283,$3c2eff5a + dc.l $0a860000,$80003d46,$ff5a6000,$ff723028 + dc.l $00000240,$7fff0c40,$7fff6738,$08280007 + dc.l $00046706,$103c0000,$4e754a40,$66184aa8 + dc.l $0004660c,$4aa80008,$6606103c,$00014e75 + dc.l $103c0004,$4e7561ff,$000007f6,$4e75103c + dc.l $00064e75,$4aa80008,$66122028,$00040280 + dc.l $7fffffff,$6606103c,$00024e75,$103c0003 + dc.l $4e757fff,$0000ffff,$ffffffff,$ffff4a28 + dc.l $00006a38,$00ae0a00,$0410ff64,$082e0002 + dc.l $ff62660a,$f23c4400,$ff800000,$4e75f22e + dc.l $d080ffdc,$f22e9000,$ff60f23c,$4480bf80 + dc.l $0000f23c,$44a00000,$00004e75,$00ae0200 + dc.l $0410ff64,$082e0002,$ff62660a,$f23c4400 + dc.l $7f800000,$4e75f22e,$d080ffdc,$f22e9000 + dc.l $ff60f23c,$44803f80,$0000f23c,$44a00000 + dc.l $00004e75,$00ae0100,$2080ff64,$082e0005 + dc.l $ff626608,$f23ad080,$ff6a4e75,$f22ed080 + dc.l $ffdcf22e,$9000ff60,$f227e004,$f23c4500 + dc.l $7f800000,$f23c4523,$00000000,$f21fd020 + dc.l $4e757ffe,$0000ffff,$ffffffff,$fffffffe + dc.l $0000ffff,$ffffffff,$ffff0000,$00008000 + dc.l $00000000,$00008000,$00008000,$00000000 + dc.l $00004a28,$00006a26,$00ae0800,$0a28ff64 + dc.l $f22e9000,$ff60f23a,$d080ffdc,$f23a4823 + dc.l $ffcaf200,$a800e198,$1d40ff64,$4e75006e + dc.l $0a28ff66,$f22e9000,$ff60f23a,$d080ffac + dc.l $f2000023,$f200a800,$e1981d40,$ff644e75 + dc.l $00ae0000,$1048ff64,$12000201,$00c06700 + dc.l $005a3d68,$0000ff84,$2d680004,$ff882d68 + dc.l $0008ff8c,$41eeff84,$48e7c080,$61ff0000 + dc.l $06184cdf,$01030c01,$00406610,$4aa80008 + dc.l $66184a28,$00076612,$60000020,$22280008 + dc.l $02810000,$07ff6700,$001200ae,$00000200 + dc.l $ff646006,$006e1248,$ff664a28,$00006a22 + dc.l $f22e9000,$ff60f23a,$d080ff14,$f23a4823 + dc.l $ff02f200,$a800e198,$00000000,$1d40ff64 + dc.l $4e75f22e,$9000ff60,$f23ad080,$fee6f23a + dc.l $4823fee0,$f200a800,$e1981d40,$ff644e75 + dc.l $006e1248,$ff66f22e,$9000ff60,$f23ad080 + dc.l $fec2f23a,$4823febc,$f200a800,$e1981d40 + dc.l $ff644e75,$f200a800,$81aeff64,$6020f200 + dc.l $a80081ae,$ff64f294,$000ef281,$0032006e + dc.l $0208ff66,$600800ae,$08000208,$ff64082e + dc.l $0001ff62,$66024e75,$f22e9000,$ff60f23c + dc.l $44803f80,$0000f23a,$48a2fe80,$4e751d7c + dc.l $0004ff64,$006e0208,$ff664e75,$f22e9000 + dc.l $ff60f228,$48000000,$f200a800,$00800000 + dc.l $0a2881ae,$ff644e75,$f22e9000,$ff60f228 + dc.l $48000000,$f200a800,$81aeff64,$4e754e75 + dc.l $f2294800,$00004a29,$00006b08,$1d7c0001 + dc.l $ff644e75,$1d7c0009,$ff644e75,$f2284800 + dc.l $00004a28,$00006b08,$1d7c0001,$ff644e75 + dc.l $1d7c0009,$ff644e75,$f227b000,$f23c9000 + dc.l $00000000,$f22f4400,$0008f21f,$9000f22f + dc.l $44220008,$4e75f227,$b000f23c,$90000000 + dc.l $0000f22f,$54000008,$f21f9000,$f22f5422 + dc.l $000c4e75,$f22fd080,$0004f22f,$48220010 + dc.l $4e75f227,$b000f23c,$90000000,$0000f22f + dc.l $44000008,$f21f9000,$f22f4428,$00084e75 + dc.l $f227b000,$f23c9000,$00000000,$f22f5400 + dc.l $0008f21f,$9000f22f,$5428000c,$4e75f22f + dc.l $d0800004,$f22f4828,$00104e75,$f227b000 + dc.l $f23c9000,$00000000,$f22f4400,$0008f21f + dc.l $9000f22f,$44230008,$4e75f227,$b000f23c + dc.l $90000000,$0000f22f,$54000008,$f21f9000 + dc.l $f22f5423,$000c4e75,$f22fd080,$0004f22f + dc.l $48230010,$4e75f227,$b000f23c,$90000000 + dc.l $0000f22f,$44000008,$f21f9000,$f22f4420 + dc.l $00084e75,$f227b000,$f23c9000,$00000000 + dc.l $f22f5400,$0008f21f,$9000f22f,$5420000c + dc.l $4e75f22f,$d0800004,$f22f4820,$00104e75 + dc.l $f22f4418,$00044e75,$f22f5418,$00044e75 + dc.l $f22f4818,$00044e75,$f22f441a,$00044e75 + dc.l $f22f541a,$00044e75,$f22f481a,$00044e75 + dc.l $f22f4404,$00044e75,$f22f5404,$00044e75 + dc.l $f22f4804,$00044e75,$f22f4401,$00044e75 + dc.l $f22f5401,$00044e75,$f22f4801,$00044e75 + dc.l $f22f4403,$00044e75,$f22f5403,$00044e75 + dc.l $f22f4803,$00044e75,$4a280000,$6b10f23c + dc.l $44000000,$00001d7c,$0004ff64,$4e75f23c + dc.l $44008000,$00001d7c,$000cff64,$4e754a29 + dc.l $00006bea,$60d84a28,$00006b10,$f23c4400 + dc.l $7f800000,$1d7c0002,$ff644e75,$f23c4400 + dc.l $ff800000,$1d7c000a,$ff644e75,$4a290000 + dc.l $6bea60d8,$4a280000,$6ba460d0,$4a280000 + dc.l $6b00fba2,$60c64a28,$00006b16,$60be4a28 + dc.l $00006b0e,$f23c4400,$3f800000,$422eff64 + dc.l $4e75f23c,$4400bf80,$00001d7c,$0008ff64 + dc.l $4e753fff,$0000c90f,$daa22168,$c235bfff + dc.l $0000c90f,$daa22168,$c2354a28,$00006b0e + dc.l $f2009000,$f23a4800,$ffda6000,$fcf2f200 + dc.l $9000f23a,$4800ffd8,$6000fcec,$f23c4480 + dc.l $3f800000,$4a280000,$6a10f23c,$44008000 + dc.l $00001d7c,$000cff64,$4e75f23c,$44000000 + dc.l $00001d7c,$0004ff64,$4e75f23a,$4880fa84 + dc.l $6000fb02,$f2284880,$00006000,$fd30122e + dc.l $ff4f67ff,$fffff782,$0c010001,$67000078 + dc.l $0c010002,$67ffffff,$fade0c01,$000467ff + dc.l $fffff766,$60ffffff,$fcea122e,$ff4f67ff + dc.l $fffffac4,$0c010001,$67ffffff,$faba0c01 + dc.l $000267ff,$fffffab0,$0c010004,$67ffffff + dc.l $faa660ff,$fffffcbc,$122eff4f,$67ff0000 + dc.l $00440c01,$000167ff,$0000001e,$0c010002 + dc.l $67ffffff,$fa820c01,$000467ff,$00000026 + dc.l $60ffffff,$fc8e1228,$00001029,$0000b101 + dc.l $02010080,$1d41ff65,$4a006a00,$fe526000 + dc.l $fe5e422e,$ff652f00,$12280000,$10290000 + dc.l $b1010201,$00801d41,$ff650c2e,$0004ff4f + dc.l $660c41e9,$0000201f,$60ffffff,$fc2ef21f + dc.l $9000f229,$48000000,$4a290000,$6b024e75 + dc.l $1d7c0008,$ff644e75,$122eff4f,$67ffffff + dc.l $f6a40c01,$00016700,$ff8e0c01,$000267ff + dc.l $fffff9f4,$0c010004,$67ffffff,$f68860ff + dc.l $fffffc00,$122eff4f,$67ffffff,$f9da0c01 + dc.l $000167ff,$fffff9d0,$0c010002,$67ffffff + dc.l $f9c60c01,$000467ff,$fffff9bc,$60ffffff + dc.l $fbd2122e,$ff4f6700,$ff5a0c01,$00016700 + dc.l $ff360c01,$000267ff,$fffff99c,$0c010004 + dc.l $67ffffff,$ff4060ff,$fffffba8,$122eff4f + dc.l $67ffffff,$f5000c01,$000167ff,$fffffd92 + dc.l $0c010002,$67ffffff,$fdb60c01,$000467ff + dc.l $fffff4e2,$60ffffff,$fb7a122e,$ff4f67ff + dc.l $fffff4d2,$0c010001,$67ffffff,$fd640c01 + dc.l $000267ff,$fffffd88,$0c010004,$67ffffff + dc.l $f4b460ff,$fffffb4c,$122eff4f,$67ffffff + dc.l $f9260c01,$000367ff,$fffffb38,$60ffffff + dc.l $f916122e,$ff4f0c01,$000367ff,$fffffb24 + dc.l $60ffffff,$fb3a2f02,$2f032028,$00042228 + dc.l $0008edc0,$2000671a,$e5a8e9c1,$30228083 + dc.l $e5a92140,$00042141,$00082002,$261f241f + dc.l $4e75edc1,$2000e5a9,$06820000,$00202141 + dc.l $000442a8,$00082002,$261f241f,$4e75ede8 + dc.l $00000004,$660eede8,$00000008,$67000074 + dc.l $06400020,$42813228,$00000241,$7fffb041 + dc.l $6e1c9240,$30280000,$02408000,$82403141 + dc.l $000061ff,$ffffff82,$103c0000,$4e750c01 + dc.l $00206e20,$e9e80840,$00042140,$00042028 + dc.l $0008e3a8,$21400008,$02688000,$0000103c + dc.l $00044e75,$04410020,$20280008,$e3a82140 + dc.l $000442a8,$00080268,$80000000,$103c0004 + dc.l $4e750268,$80000000,$103c0001,$4e7551fc diff -u --recursive --new-file v1.3.93/linux/arch/m68k/ifpsp060/fpsp.doc linux/arch/m68k/ifpsp060/fpsp.doc --- v1.3.93/linux/arch/m68k/ifpsp060/fpsp.doc Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/ifpsp060/fpsp.doc Mon Jan 8 22:08:15 1996 @@ -0,0 +1,295 @@ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP +M68000 Hi-Performance Microprocessor Division +M68060 Software Package +Production Release P1.00 -- October 10, 1994 + +M68060 Software Package Copyright © 1993, 1994 Motorola Inc. All rights reserved. + +THE SOFTWARE is provided on an "AS IS" basis and without warranty. +To the maximum extent permitted by applicable law, +MOTOROLA DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED, +INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE +and any warranty against infringement with regard to the SOFTWARE +(INCLUDING ANY MODIFIED VERSIONS THEREOF) and any accompanying written materials. + +To the maximum extent permitted by applicable law, +IN NO EVENT SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER +(INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, +BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY LOSS) +ARISING OF THE USE OR INABILITY TO USE THE SOFTWARE. +Motorola assumes no responsibility for the maintenance and support of the SOFTWARE. + +You are hereby granted a copyright license to use, modify, and distribute the SOFTWARE +so long as this entire notice is retained without alteration in any modified and/or +redistributed versions, and that such modified versions are clearly identified as such. +No licenses are granted by implication, estoppel or otherwise under any patents +or trademarks of Motorola, Inc. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +68060 FLOATING-POINT SOFTWARE PACKAGE (Kernel version) +------------------------------------------------------- + +The file fpsp.sa contains the 68060 Floating-Point Software +Package. This package is essentially a set of exception handlers +that can be integrated into an operating system. +These exception handlers emulate Unimplemented FP instructions, +instructions using unimplemented data types, and instructions +using unimplemented addressing modes. In addition, this package +includes exception handlers to provide full IEEE-754 compliant +exception handling. + +Release file format: +-------------------- +The file fpsp.sa is essentially a hexadecimal image of the +release package. This is the ONLY format which will be supported. +The hex image was created by assembling the source code and +then converting the resulting binary output image into an +ASCII text file. The hexadecimal numbers are listed +using the Motorola Assembly Syntax assembler directive "dc.l" +(define constant longword). The file can be converted to other +assembly syntaxes by using any word processor with a global +search and replace function. + +To assist in assembling and linking this module with other modules, +the installer should add a symbolic label to the top of the file. +This will allow calling routines to access the entry points +of this package. + +The source code fpsp.s has also been included but only for +documentation purposes. + +Release file structure: +----------------------- + +(top of module) + ----------------- + | | - 128 byte-sized section + (1) | Call-Out | - 4 bytes per entry (user fills these in) + | | - example routines in fskeleton.s + ----------------- + | | - 8 bytes per entry + (2) | Entry Point | - user does "bra" or "jmp" to this address + | | + ----------------- + | | - code section + (3) ~ ~ + | | + ----------------- +(bottom of module) + +The first section of this module is the "Call-out" section. This section +is NOT INCLUDED in fpsp.sa (an example "Call-out" section is provided at +the end of the file fskeleton.s). The purpose of this section is to allow +the FPSP routines to reference external functions that must be provided +by the host operating system. This section MUST be exactly 128 bytes in +size. There are 32 fields, each 4 bytes in size. Each field corresponds +to a function required by the FPSP (these functions and their location are +listed in "68060FPSP call-outs" below). Each field entry should contain +the address of the corresponding function RELATIVE to the starting address +of the "call-out" section. The "Call-out" section must sit adjacent to the +fpsp.sa image in memory. + +The second section, the "Entry-point" section, is used by external routines +to access the functions within the FPSP. Since the fpsp.sa hex file contains +no symbol names, this section contains function entry points that are fixed +with respect to the top of the package. The currently defined entry-points +are listed in section "68060 FPSP entry points" below. A calling routine +would simply execute a "bra" or "jmp" that jumped to the selected function +entry-point. + +For example, if the 68060 hardware took a "Line-F Emulator" exception +(vector #11), the operating system should execute something similar to: + + bra _060FPSP_TOP+128+48 + +(_060FPSP_TOP is the starting address of the "Call-out" section; the "Call-out" +section is 128 bytes long; and the F-Line FPSP handler entry point is located +48 bytes from the top of the "Entry-point" section.) + +The third section is the code section. After entering through an "Entry-point", +the entry code jumps to the appropriate emulation code within the code section. + +68060FPSP call-outs: (details in fskeleton.s) +-------------------- +0x000: _060_real_bsun +0x004: _060_real_snan +0x008: _060_real_operr +0x00c: _060_real_ovfl +0x010: _060_real_unfl +0x014: _060_real_dz +0x018: _060_real_inex +0x01c: _060_real_fline +0x020: _060_real_fpu_disabled +0x024: _060_real_trap +0x028: _060_real_trace +0x02c: _060_real_access +0x030: _060_fpsp_done + +0x034: (Motorola reserved) +0x038: (Motorola reserved) +0x03c: (Motorola reserved) + +0x040: _060_imem_read +0x044: _060_dmem_read +0x048: _060_dmem_write +0x04c: _060_imem_read_word +0x050: _060_imem_read_long +0x054: _060_dmem_read_byte +0x058: _060_dmem_read_word +0x05c: _060_dmem_read_long +0x060: _060_dmem_write_byte +0x064: _060_dmem_write_word +0x068: _060_dmem_write_long + +0x06c: (Motorola reserved) +0x070: (Motorola reserved) +0x074: (Motorola reserved) +0x078: (Motorola reserved) +0x07c: (Motorola reserved) + +68060FPSP entry points: +----------------------- +0x000: _060_fpsp_snan +0x008: _060_fpsp_operr +0x010: _060_fpsp_ovfl +0x018: _060_fpsp_unfl +0x020: _060_fpsp_dz +0x028: _060_fpsp_inex +0x030: _060_fpsp_fline +0x038: _060_fpsp_unsupp +0x040: _060_fpsp_effadd + + + +Miscellaneous: +-------------- + +_060_fpsp_snan: +---------------- +- documented in 3.5 of 060SP spec. +- Basic flow: + exception taken ---> enter _060_fpsp_snan --| + | + always exits through _060_real_snan <---- + +_060_fpsp_operr: +---------------- +- documented in 3.5 of 060SP spec. +- Basic flow: + exception taken ---> enter _060_fpsp_operr --| + | + always exits through _060_real_operr <----- + +_060_fpsp_dz: +---------------- +- documented in 3.7 of 060SP spec. +- Basic flow: + exception taken ---> enter _060_fpsp_dz --| + | + always exits through _060_real_dz <---- + +_060_fpsp_inex: +---------------- +- documented in 3.6 of 060SP spec. +- Basic flow: + exception taken ---> enter _060_fpsp_inex --| + | + always exits through _060_real_inex <---- + + +_060_fpsp_ovfl: +---------------- +- documented in 3.4 of 060SP spec. +- Basic flow: + exception taken ---> enter _060_fpsp_ovfl --| + | + may exit through _060_real_inex <---| + or | + may exit through _060_real_ovfl <---| + or | + may exit through _060_fpsp_done <---| + +_060_fpsp_unfl: +---------------- +- documented in 3.4 of 060SP spec. +- Basic flow: + exception taken ---> enter _060_fpsp_unfl --| + | + may exit through _060_real_inex <---| + or | + may exit through _060_real_unfl <---| + or | + may exit through _060_fpsp_done <---| + + +_060_fpsp_fline: +----------------- +- not fully documented in 060SP spec. +- Basic flow: + exception taken ---> enter _060_fpsp_fline --| + | + ------------------------------------------- + | | | + v v v + (unimplemented (fpu disabled) (possible F-line illegal) + stack frame) | v + | v special case "fmovecr"? + | exit through | + | _060_real_fpu_disabled ------------- + | | | + | ^ v v + | | (yes) (no) + | | v v + | | fpu disabled? exit through + | | | _060_real_fline + v | ------------- + | | | | + | | v v + | |-----------(yes) (no) + | | + |----<------------------------------------| + | + | + |----> may exit through _060_real_trace + | + |----> may exit through _060_real_trap + | + |----> may exit thorugh _060_real_bsun + | + |----> may exit through _060_fpsp_done + + +_060_fpsp_unsupp: +------------------ +- documented in 3.1 of 060SP spec. +- Basic flow: + exception taken ---> enter _060_fpsp_unsupp --| + | + | + may exit through _060_real_snan <----| + or | + may exit through _060_real_operr <----| + or | + may exit through _060_real_ovfl <----| + or | + may exit through _060_real_unfl <----| + or | + may exit through _060_real_inex <----| + or | + may exit through _060_real_trace <----| + or | + may exit through _060_fpsp_done <----| + + +_060_fpsp_effadd: +------------------ +- documented in 3.3 of 060 spec. +- Basic flow: + exception taken ---> enter _060_fpsp_effadd --| + | + | + may exit through _060_real_trace <----| + or | + may exit through _060_real_fpu_disabled <----| + or | + may exit through _060_fpsp_done <----| diff -u --recursive --new-file v1.3.93/linux/arch/m68k/ifpsp060/fpsp.sa linux/arch/m68k/ifpsp060/fpsp.sa --- v1.3.93/linux/arch/m68k/ifpsp060/fpsp.sa Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/ifpsp060/fpsp.sa Mon Jan 8 22:08:16 1996 @@ -0,0 +1,3401 @@ + .long 0x60ff0000,0x17400000,0x60ff0000,0x15f40000 + .long 0x60ff0000,0x02b60000,0x60ff0000,0x04700000 + .long 0x60ff0000,0x1b100000,0x60ff0000,0x19aa0000 + .long 0x60ff0000,0x1b5a0000,0x60ff0000,0x062e0000 + .long 0x60ff0000,0x102c0000,0x51fc51fc,0x51fc51fc + .long 0x51fc51fc,0x51fc51fc,0x51fc51fc,0x51fc51fc + .long 0x51fc51fc,0x51fc51fc,0x51fc51fc,0x51fc51fc + .long 0x51fc51fc,0x51fc51fc,0x51fc51fc,0x51fc51fc + .long 0x2f00203a,0xff2c487b,0x0930ffff,0xfef8202f + .long 0x00044e74,0x00042f00,0x203afef2,0x487b0930 + .long 0xfffffee2,0x202f0004,0x4e740004,0x2f00203a + .long 0xfee0487b,0x0930ffff,0xfecc202f,0x00044e74 + .long 0x00042f00,0x203afed2,0x487b0930,0xfffffeb6 + .long 0x202f0004,0x4e740004,0x2f00203a,0xfea4487b + .long 0x0930ffff,0xfea0202f,0x00044e74,0x00042f00 + .long 0x203afe96,0x487b0930,0xfffffe8a,0x202f0004 + .long 0x4e740004,0x2f00203a,0xfe7c487b,0x0930ffff + .long 0xfe74202f,0x00044e74,0x00042f00,0x203afe76 + .long 0x487b0930,0xfffffe5e,0x202f0004,0x4e740004 + .long 0x2f00203a,0xfe68487b,0x0930ffff,0xfe48202f + .long 0x00044e74,0x00042f00,0x203afe56,0x487b0930 + .long 0xfffffe32,0x202f0004,0x4e740004,0x2f00203a + .long 0xfe44487b,0x0930ffff,0xfe1c202f,0x00044e74 + .long 0x00042f00,0x203afe32,0x487b0930,0xfffffe06 + .long 0x202f0004,0x4e740004,0x2f00203a,0xfe20487b + .long 0x0930ffff,0xfdf0202f,0x00044e74,0x00042f00 + .long 0x203afe1e,0x487b0930,0xfffffdda,0x202f0004 + .long 0x4e740004,0x2f00203a,0xfe0c487b,0x0930ffff + .long 0xfdc4202f,0x00044e74,0x00042f00,0x203afdfa + .long 0x487b0930,0xfffffdae,0x202f0004,0x4e740004 + .long 0x2f00203a,0xfde8487b,0x0930ffff,0xfd98202f + .long 0x00044e74,0x00042f00,0x203afdd6,0x487b0930 + .long 0xfffffd82,0x202f0004,0x4e740004,0x2f00203a + .long 0xfdc4487b,0x0930ffff,0xfd6c202f,0x00044e74 + .long 0x00042f00,0x203afdb2,0x487b0930,0xfffffd56 + .long 0x202f0004,0x4e740004,0x2f00203a,0xfda0487b + .long 0x0930ffff,0xfd40202f,0x00044e74,0x00042f00 + .long 0x203afd8e,0x487b0930,0xfffffd2a,0x202f0004 + .long 0x4e740004,0x2f00203a,0xfd7c487b,0x0930ffff + .long 0xfd14202f,0x00044e74,0x00042f00,0x203afd6a + .long 0x487b0930,0xfffffcfe,0x202f0004,0x4e740004 + .long 0x40c62d38,0xd3d64634,0x3d6f90ae,0xb1e75cc7 + .long 0x40000000,0xc90fdaa2,0x2168c235,0x00000000 + .long 0x3fff0000,0xc90fdaa2,0x2168c235,0x00000000 + .long 0x3fe45f30,0x6dc9c883,0x4e56ff40,0xf32eff6c + .long 0x48ee0303,0xff9cf22e,0xbc00ff60,0xf22ef0c0 + .long 0xffdc2d6e,0xff68ff44,0x206eff44,0x58aeff44 + .long 0x61ffffff,0xff042d40,0xff40082e,0x0005ff42 + .long 0x66000116,0x41eeff6c,0x61ff0000,0x051c41ee + .long 0xff6c61ff,0x0000c1dc,0x1d40ff4e,0x082e0005 + .long 0xff436726,0xe9ee0183,0xff4261ff,0x0000bd22 + .long 0x41eeff78,0x61ff0000,0xc1ba0c00,0x00066606 + .long 0x61ff0000,0xc11e1d40,0xff4f4280,0x102eff63 + .long 0x122eff43,0x0241007f,0x02ae00ff,0x01ffff64 + .long 0xf23c9000,0x00000000,0xf23c8800,0x00000000 + .long 0x41eeff6c,0x43eeff78,0x223b1530,0x00007112 + .long 0x4ebb1930,0x0000710a,0xe9ee0183,0xff4261ff + .long 0x0000bd4e,0x082e0004,0xff626622,0x082e0001 + .long 0xff626644,0xf22ed0c0,0xffdcf22e,0x9c00ff60 + .long 0x4cee0303,0xff9c4e5e,0x60ffffff,0xfcc6f22e + .long 0xf040ff6c,0x3d7ce005,0xff6ef22e,0xd0c0ffdc + .long 0xf22e9c00,0xff604cee,0x0303ff9c,0xf36eff6c + .long 0x4e5e60ff,0xfffffcb2,0xf22ef040,0xff6c1d7c + .long 0x00c4000b,0x3d7ce001,0xff6ef22e,0xd0c0ffdc + .long 0xf22e9c00,0xff604cee,0x0303ff9c,0xf36eff6c + .long 0x4e5e60ff,0xfffffcae,0x1d7c0000,0xff4e4280 + .long 0x102eff63,0x02aeffff,0x00ffff64,0xf23c9000 + .long 0x00000000,0xf23c8800,0x00000000,0x41eeff6c + .long 0x61ff0000,0xb2ce082e,0x0004ff62,0x6600ff70 + .long 0x082e0001,0xff626600,0xff90f22e,0xd0c0ffdc + .long 0xf22e9c00,0xff604cee,0x0303ff9c,0x4e5e0817 + .long 0x000767ff,0xfffffc0c,0xf22fa400,0x00083f7c + .long 0x20240006,0x60ffffff,0xfcec4e56,0xff40f32e + .long 0xff6c48ee,0x0303ff9c,0xf22ebc00,0xff60f22e + .long 0xf0c0ffdc,0x2d6eff68,0xff44206e,0xff4458ae + .long 0xff4461ff,0xfffffd42,0x2d40ff40,0x082e0005 + .long 0xff426600,0x013241ee,0xff6c61ff,0x0000035a + .long 0x41eeff6c,0x61ff0000,0xc01a1d40,0xff4e082e + .long 0x0005ff43,0x672e082e,0x0004ff43,0x6626e9ee + .long 0x0183ff42,0x61ff0000,0xbb5841ee,0xff7861ff + .long 0x0000bff0,0x0c000006,0x660661ff,0x0000bf54 + .long 0x1d40ff4f,0x4280102e,0xff63122e,0xff430241 + .long 0x007f02ae,0x00ff01ff,0xff64f23c,0x90000000 + .long 0x0000f23c,0x88000000,0x000041ee,0xff6c43ee + .long 0xff78223b,0x15300000,0x6f484ebb,0x19300000 + .long 0x6f40e9ee,0x0183ff42,0x61ff0000,0xbb84082e + .long 0x0003ff62,0x6622082e,0x0001ff62,0x664ef22e + .long 0xd0c0ffdc,0xf22e9c00,0xff604cee,0x0303ff9c + .long 0x4e5e60ff,0xfffffafc,0x082e0003,0xff666700 + .long 0xffd6f22e,0xf040ff6c,0x3d7ce003,0xff6ef22e + .long 0xd0c0ffdc,0xf22e9c00,0xff604cee,0x0303ff9c + .long 0xf36eff6c,0x4e5e60ff,0xfffffaf4,0x082e0001 + .long 0xff666700,0xffaaf22e,0xf040ff6c,0x1d7c00c4 + .long 0x000b3d7c,0xe001ff6e,0xf22ed0c0,0xffdcf22e + .long 0x9c00ff60,0x4cee0303,0xff9cf36e,0xff6c4e5e + .long 0x60ffffff,0xfad01d7c,0x0000ff4e,0x4280102e + .long 0xff6302ae,0xffff00ff,0xff64f23c,0x90000000 + .long 0x0000f23c,0x88000000,0x000041ee,0xff6c61ff + .long 0x0000b0f0,0x082e0003,0xff626600,0xff66082e + .long 0x0001ff62,0x6600ff90,0xf22ed0c0,0xffdcf22e + .long 0x9c00ff60,0x4cee0303,0xff9c4e5e,0x08170007 + .long 0x67ffffff,0xfa2ef22f,0xa4000008,0x3f7c2024 + .long 0x000660ff,0xfffffb0e,0x4e56ff40,0xf32eff6c + .long 0x48ee0303,0xff9cf22e,0xbc00ff60,0xf22ef0c0 + .long 0xffdc082e,0x00050004,0x66084e68,0x2d48ffd8 + .long 0x600841ee,0x00102d48,0xffd82d6e,0xff68ff44 + .long 0x206eff44,0x58aeff44,0x61ffffff,0xfb4c2d40 + .long 0xff40422e,0xff4a082e,0x0005ff42,0x66000208 + .long 0xe9ee0006,0xff420c00,0x00136700,0x049e02ae + .long 0x00ff00ff,0xff64f23c,0x90000000,0x0000f23c + .long 0x88000000,0x000041ee,0xff6c61ff,0x0000013a + .long 0x41eeff6c,0x61ff0000,0xbdfa0c00,0x00066606 + .long 0x61ff0000,0xbd5e1d40,0xff4ee9ee,0x0183ff42 + .long 0x082e0005,0xff436728,0x0c2e003a,0xff436720 + .long 0x61ff0000,0xb92c41ee,0xff7861ff,0x0000bdc4 + .long 0x0c000006,0x660661ff,0x0000bd28,0x1d40ff4f + .long 0x4280102e,0xff63e9ee,0x1047ff43,0x41eeff6c + .long 0x43eeff78,0x223b1d30,0x00006d36,0x4ebb1930 + .long 0x00006d2e,0x102eff62,0x6634102e,0xff430200 + .long 0x00380c00,0x0038670c,0xe9ee0183,0xff4261ff + .long 0x0000b95e,0xf22ed0c0,0xffdcf22e,0x9c00ff60 + .long 0x4cee0303,0xff9c4e5e,0x60ffffff,0xf8e6c02e + .long 0xff66edc0,0x06086614,0x082e0004,0xff6667ba + .long 0x082e0001,0xff6267b2,0x60000066,0x04800000 + .long 0x00180c00,0x00066614,0x082e0003,0xff666600 + .long 0x004a082e,0x0004ff66,0x66000046,0x2f0061ff + .long 0x000007e0,0x201f3d7b,0x0222ff6e,0xf22ed0c0 + .long 0xffdcf22e,0x9c00ff60,0x4cee0303,0xff9cf36e + .long 0xff6c4e5e,0x60ffffff,0xf87ae000,0xe006e004 + .long 0xe005e003,0xe002e001,0xe001303c,0x000460bc + .long 0x303c0003,0x60b6e9ee,0x0006ff42,0x0c000011 + .long 0x67080c00,0x00156750,0x4e753028,0x00000240 + .long 0x7fff0c40,0x3f806708,0x0c40407f,0x672c4e75 + .long 0x02a87fff,0xffff0004,0x671861ff,0x0000bbbc + .long 0x44400640,0x3f810268,0x80000000,0x81680000 + .long 0x4e750268,0x80000000,0x4e750228,0x007f0004 + .long 0x00687fff,0x00004e75,0x30280000,0x02407fff + .long 0x0c403c00,0x67080c40,0x43ff67de,0x4e7502a8 + .long 0x7fffffff,0x00046606,0x4aa80008,0x67c461ff + .long 0x0000bb68,0x44400640,0x3c010268,0x80000000 + .long 0x81680000,0x4e75e9ee,0x00c3ff42,0x0c000003 + .long 0x670004a2,0x0c000007,0x6700049a,0x02aeffff + .long 0x00ffff64,0xf23c9000,0x00000000,0xf23c8800 + .long 0x00000000,0x302eff6c,0x02407fff,0x671041ee + .long 0xff6c61ff,0x0000bb5c,0x1d40ff4e,0x60061d7c + .long 0x0004ff4e,0x4280102e,0xff6341ee,0xff6c2d56 + .long 0xffd461ff,0x0000adec,0x102eff62,0x66000086 + .long 0x2caeffd4,0x082e0005,0x00046626,0x206effd8 + .long 0x4e60f22e,0xd0c0ffdc,0xf22e9c00,0xff604cee + .long 0x0303ff9c,0x4e5e0817,0x0007667a,0x60ffffff + .long 0xf7220c2e,0x0008ff4a,0x66d8f22e,0xf080ff6c + .long 0xf22ed0c0,0xffdcf22e,0x9c00ff60,0x4cee0303 + .long 0xff9c2c56,0x2f6f00c4,0x00b82f6f,0x00c800bc + .long 0x2f6f002c,0x00c42f6f,0x003000c8,0x2f6f0034 + .long 0x00ccdffc,0x000000b8,0x08170007,0x662860ff + .long 0xfffff6d0,0xc02eff66,0xedc00608,0x662a082e + .long 0x0004ff66,0x6700ff6a,0x082e0001,0xff626700 + .long 0xff606000,0x01663f7c,0x20240006,0xf22fa400 + .long 0x000860ff,0xfffff78e,0x04800000,0x0018303b + .long 0x020a4efb,0x00064afc,0x00080000,0x0000003a + .long 0x00640094,0x00000140,0x0000f22e,0xd0c0ffdc + .long 0xf22e9c00,0xff604cee,0x0303ff9c,0x3d7c30d8 + .long 0x000a3d7c,0xe006ff6e,0xf36eff6c,0x4e5e60ff + .long 0xfffff6d4,0xf22ed0c0,0xffdcf22e,0x9c00ff60 + .long 0x4cee0303,0xff9c3d7c,0x30d0000a,0x3d7ce004 + .long 0xff6ef36e,0xff6c4e5e,0x60ffffff,0xf694f22e + .long 0xf040ff6c,0xf22ed0c0,0xffdcf22e,0x9c00ff60 + .long 0x4cee0303,0xff9c3d7c,0x30d4000a,0x3d7ce005 + .long 0xff6ef36e,0xff6c4e5e,0x60ffffff,0xf60c2cae + .long 0xffd4082e,0x00050004,0x66000038,0x206effd8 + .long 0x4e60f22e,0xf040ff6c,0xf22ed0c0,0xffdcf22e + .long 0x9c00ff60,0x4cee0303,0xff9c3d7c,0x30cc000a + .long 0x3d7ce003,0xff6ef36e,0xff6c4e5e,0x60ffffff + .long 0xf5de0c2e,0x0008ff4a,0x66c8f22e,0xf080ff6c + .long 0xf22ef040,0xff78f22e,0xd0c0ffdc,0xf22e9c00 + .long 0xff604cee,0x0303ff9c,0x3d7c30cc,0x000a3d7c + .long 0xe003ff7a,0xf36eff78,0x2c562f6f,0x00c400b8 + .long 0x2f6f00c8,0x00bc2f6f,0x00cc00c0,0x2f6f002c + .long 0x00c42f6f,0x003000c8,0x2f6f0034,0x00ccdffc + .long 0x000000b8,0x60ffffff,0xf576f22e,0xf040ff6c + .long 0xf22ed0c0,0xffdcf22e,0x9c00ff60,0x4cee0303 + .long 0xff9c3d7c,0x30c4000a,0x3d7ce001,0xff6ef36e + .long 0xff6c4e5e,0x60ffffff,0xf55c02ae,0x00ff00ff + .long 0xff64f23c,0x90000000,0x0000f23c,0x88000000 + .long 0x000061ff,0x0000bdba,0x41eeff6c,0x61ff0000 + .long 0xb9621d40,0xff4ee9ee,0x0183ff42,0x082e0005 + .long 0xff436728,0x0c2e003a,0xff436720,0x61ff0000 + .long 0xb4a041ee,0xff7861ff,0x0000b938,0x0c000006 + .long 0x660661ff,0x0000b89c,0x1d40ff4f,0x4280102e + .long 0xff63e9ee,0x1047ff43,0x41eeff6c,0x43eeff78 + .long 0x223b1d30,0x000068aa,0x4ebb1930,0x000068a2 + .long 0x102eff62,0x6600008a,0x102eff43,0x02000038 + .long 0x0c000038,0x670ce9ee,0x0183ff42,0x61ff0000 + .long 0xb4d0082e,0x00050004,0x6600002a,0x206effd8 + .long 0x4e60f22e,0xd0c0ffdc,0xf22e9c00,0xff604cee + .long 0x0303ff9c,0x4e5e0817,0x00076600,0x012660ff + .long 0xfffff440,0x082e0002,0xff4a67d6,0xf22ed0c0 + .long 0xffdcf22e,0x9c00ff60,0x4cee0303,0xff9c4e5e + .long 0x2f6f0004,0x00102f6f,0x0000000c,0xdffc0000 + .long 0x000c0817,0x00076600,0x00ea60ff,0xfffff404 + .long 0xc02eff66,0xedc00608,0x6618082e,0x0004ff66 + .long 0x6700ff66,0x082e0001,0xff626700,0xff5c6000 + .long 0x006e0480,0x00000018,0x0c000006,0x6d14082e + .long 0x0003ff66,0x66000060,0x082e0004,0xff666600 + .long 0x004e082e,0x00050004,0x66000054,0x206effd8 + .long 0x4e603d7b,0x022aff6e,0xf22ed0c0,0xffdcf22e + .long 0x9c00ff60,0x4cee0303,0xff9cf36e,0xff6c4e5e + .long 0x08170007,0x6600006c,0x60ffffff,0xf386e000 + .long 0xe006e004,0xe005e003,0xe002e001,0xe001303c + .long 0x00036000,0xffae303c,0x00046000,0xffa6082e + .long 0x0002ff4a,0x67ac3d7b,0x02d6ff6e,0xf22ed0c0 + .long 0xffdcf22e,0x9c00ff60,0x4cee0303,0xff9cf36e + .long 0xff6c4e5e,0x2f6f0004,0x00102f6f,0x0000000c + .long 0xdffc0000,0x000c0817,0x00076606,0x60ffffff + .long 0xf3223f7c,0x20240006,0xf22fa400,0x000860ff + .long 0xfffff402,0x02aeffff,0x00ffff64,0xf23c9000 + .long 0x00000000,0xf23c8800,0x00000000,0xe9ee0183 + .long 0xff4261ff,0x0000b22a,0x41eeff6c,0x61ff0000 + .long 0xb7520c00,0x00066606,0x61ff0000,0xb6b61d40 + .long 0xff4e4280,0x102eff63,0x41eeff6c,0x2d56ffd4 + .long 0x61ff0000,0xa94e102e,0xff626600,0x00842cae + .long 0xffd4082e,0x00050004,0x6628206e,0xffd84e60 + .long 0xf22ed0c0,0xffdcf22e,0x9c00ff60,0x4cee0303 + .long 0xff9c4e5e,0x08170007,0x6600ff68,0x60ffffff + .long 0xf282082e,0x0003ff4a,0x67d6f22e,0xd0c0ffdc + .long 0xf22e9c00,0xff604cee,0x0303ff9c,0x2c562f6f + .long 0x00c400b8,0x2f6f00c8,0x00bc2f6f,0x003800c4 + .long 0x2f6f003c,0x00c82f6f,0x004000cc,0xdffc0000 + .long 0x00b80817,0x00076600,0xff1a60ff,0xfffff234 + .long 0xc02eff66,0xedc00608,0x6700ff74,0x2caeffd4 + .long 0x0c00001a,0x6e0000e8,0x67000072,0x082e0005 + .long 0x0004660a,0x206effd8,0x4e606000,0xfb8e0c2e + .long 0x0008ff4a,0x6600fb84,0xf22ed0c0,0xffdcf22e + .long 0x9c00ff60,0x4cee0303,0xff9c3d7c,0x30d8000a + .long 0x3d7ce006,0xff6ef36e,0xff6c2c56,0x2f6f00c4 + .long 0x00b82f6f,0x00c800bc,0x2f6f00cc,0x00c02f6f + .long 0x003800c4,0x2f6f003c,0x00c82f6f,0x004000cc + .long 0xdffc0000,0x00b860ff,0xfffff22c,0x082e0005 + .long 0x00046600,0x000c206e,0xffd84e60,0x6000fb46 + .long 0x0c2e0008,0xff4a6600,0xfb3cf22e,0xd0c0ffdc + .long 0xf22e9c00,0xff604cee,0x0303ff9c,0x3d7c30d0 + .long 0x000a3d7c,0xe004ff6e,0xf36eff6c,0x2c562f6f + .long 0x00c400b8,0x2f6f00c8,0x00bc2f6f,0x00cc00c0 + .long 0x2f6f0038,0x00c42f6f,0x003c00c8,0x2f6f0040 + .long 0x00ccdffc,0x000000b8,0x60ffffff,0xf1a4082e + .long 0x00050004,0x6600000c,0x206effd8,0x4e606000 + .long 0xfbda0c2e,0x0008ff4a,0x6600fbd0,0xf22ed0c0 + .long 0xffdcf22e,0x9c00ff60,0x4cee0303,0xff9c3d7c + .long 0x30c4000a,0x3d7ce001,0xff6ef36e,0xff6c2c56 + .long 0x2f6f00c4,0x00b82f6f,0x00c800bc,0x2f6f00cc + .long 0x00c02f6f,0x003800c4,0x2f6f003c,0x00c82f6f + .long 0x004000cc,0xdffc0000,0x00b860ff,0xfffff106 + .long 0xe9ee00c3,0xff420c00,0x00016708,0x0c000005 + .long 0x67344e75,0x302eff6c,0x02407fff,0x67260c40 + .long 0x3f806e20,0x44400640,0x3f81222e,0xff70e0a9 + .long 0x08c1001f,0x2d41ff70,0x026e8000,0xff6c006e + .long 0x3f80ff6c,0x4e75302e,0xff6c0240,0x7fff673a + .long 0x0c403c00,0x6e344a2e,0xff6c5bee,0xff6e3d40 + .long 0xff6c4280,0x41eeff6c,0x323c3c01,0x61ff0000 + .long 0xb156303c,0x3c004a2e,0xff6e6704,0x08c0000f + .long 0x08ee0007,0xff703d40,0xff6c4e75,0x082e0005 + .long 0x000467ff,0xfffff176,0x2d680000,0xff782d68 + .long 0x0004ff7c,0x2d680008,0xff804281,0x4e752f00 + .long 0x4e7a0808,0x08000001,0x66000460,0x201f4e56 + .long 0xff4048ee,0x0303ff9c,0xf22ebc00,0xff60f22e + .long 0xf0c0ffdc,0x2d6e0006,0xff44206e,0xff4458ae + .long 0xff4461ff,0xfffff152,0x2d40ff40,0x4a406b00 + .long 0x020e02ae,0x00ff00ff,0xff640800,0x000a6618 + .long 0x206eff44,0x43eeff6c,0x700c61ff,0xfffff0d2 + .long 0x4a816600,0x04926048,0x206eff44,0x43eeff6c + .long 0x700c61ff,0xfffff0ba,0x4a816600,0x047ae9ee + .long 0x004fff6c,0x0c407fff,0x6726102e,0xff6f0200 + .long 0x000f660c,0x4aaeff70,0x66064aae,0xff746710 + .long 0x41eeff6c,0x61ff0000,0xb88cf22e,0xf080ff6c + .long 0x06ae0000,0x000cff44,0x41eeff6c,0x61ff0000 + .long 0xb3c21d40,0xff4e0c00,0x0006660a,0x61ff0000 + .long 0xb3221d40,0xff4e422e,0xff53082e,0x0005ff43 + .long 0x6748082e,0x0004ff43,0x662ce9ee,0x0183ff42 + .long 0x61ff0000,0xaeec41ee,0xff7861ff,0x0000b384 + .long 0x1d40ff4f,0x0c000006,0x662061ff,0x0000b2e4 + .long 0x1d40ff4f,0x6014082e,0x0003ff43,0x670c50ee + .long 0xff53082e,0x0001ff43,0x67c04280,0x102eff63 + .long 0x122eff43,0x0241007f,0xf23c9000,0x00000000 + .long 0xf23c8800,0x00000000,0x41eeff6c,0x43eeff78 + .long 0x223b1530,0x000062ca,0x4ebb1930,0x000062c2 + .long 0x102eff62,0x66404a2e,0xff53660c,0xe9ee0183 + .long 0xff4261ff,0x0000aefa,0x2d6e0006,0xff682d6e + .long 0xff440006,0xf22ed0c0,0xffdcf22e,0x9c00ff60 + .long 0x4cee0303,0xff9c4e5e,0x08170007,0x66000096 + .long 0x60ffffff,0xee6ec02e,0xff66edc0,0x06086612 + .long 0x082e0004,0xff6667ae,0x082e0001,0xff6267ac + .long 0x60340480,0x00000018,0x0c000006,0x6610082e + .long 0x0004ff66,0x6620082e,0x0003ff66,0x66203d7b + .long 0x0206ff6e,0x601ee002,0xe006e004,0xe005e003 + .long 0xe002e001,0xe0013d7c,0xe005ff6e,0x60063d7c + .long 0xe003ff6e,0x2d6e0006,0xff682d6e,0xff440006 + .long 0xf22ed0c0,0xffdcf22e,0x9c00ff60,0x4cee0303 + .long 0xff9cf36e,0xff6c4e5e,0x08170007,0x660660ff + .long 0xffffede0,0x2f173f6f,0x00080004,0x3f7c2024 + .long 0x0006f22f,0xa4000008,0x60ffffff,0xeeb80800 + .long 0x000e6700,0x01c2082e,0x00050004,0x66164e68 + .long 0x2d48ffd8,0x61ff0000,0x9564206e,0xffd84e60 + .long 0x600001aa,0x422eff4a,0x41ee000c,0x2d48ffd8 + .long 0x61ff0000,0x95480c2e,0x0008ff4a,0x67000086 + .long 0x0c2e0004,0xff4a6600,0x0184082e,0x00070004 + .long 0x66363dae,0x00040804,0x2daeff44,0x08063dbc + .long 0x00f0080a,0x41f60804,0x2d480004,0xf22ed0c0 + .long 0xffdcf22e,0x9c00ff60,0x4cee0303,0xff9c4e5e + .long 0x2e5f60ff,0xffffed3c,0x3dae0004,0x08002dae + .long 0xff440802,0x3dbc2024,0x08062dae,0x00060808 + .long 0x41f60800,0x2d480004,0xf22ed0c0,0xffdcf22e + .long 0x9c00ff60,0x4cee0303,0xff9c4e5e,0x2e5f60ff + .long 0xffffedf2,0x1d41000a,0x1d40000b,0xf22ed0c0 + .long 0xffdcf22e,0x9c00ff60,0x4cee0303,0xff9c2f16 + .long 0x2f002f01,0x2f2eff44,0x4280102e,0x000b4480 + .long 0x082e0007,0x0004671c,0x3dae0004,0x08002dae + .long 0x00060808,0x2d9f0802,0x3dbc2024,0x08064876 + .long 0x08006014,0x3dae0004,0x08042d9f,0x08063dbc + .long 0x00f0080a,0x48760804,0x4281122e,0x000a4a01 + .long 0x6a0cf236,0xf080080c,0x06800000,0x000ce309 + .long 0x6a0cf236,0xf040080c,0x06800000,0x000ce309 + .long 0x6a0cf236,0xf020080c,0x06800000,0x000ce309 + .long 0x6a0cf236,0xf010080c,0x06800000,0x000ce309 + .long 0x6a0cf236,0xf008080c,0x06800000,0x000ce309 + .long 0x6a0cf236,0xf004080c,0x06800000,0x000ce309 + .long 0x6a0cf236,0xf002080c,0x06800000,0x000ce309 + .long 0x6a06f236,0xf001080c,0x222f0004,0x202f0008 + .long 0x2c6f000c,0x2e5f0817,0x000767ff,0xffffec04 + .long 0x60ffffff,0xecf061ff,0x00009bda,0xf22ed0c0 + .long 0xffdcf22e,0x9c00ff60,0x4cee0303,0xff9c082e + .long 0x00070004,0x660e2d6e,0xff440006,0x4e5e60ff + .long 0xffffebd0,0x2c563f6f,0x00c400c0,0x2f6f00c6 + .long 0x00c82f6f,0x000400c2,0x3f7c2024,0x00c6dffc + .long 0x000000c0,0x60ffffff,0xec9c201f,0x4e56ff40 + .long 0x48ee0303,0xff9c2d6e,0x0006ff44,0x206eff44 + .long 0x58aeff44,0x61ffffff,0xed002d40,0xff404a40 + .long 0x6b047010,0x60260800,0x000e6610,0xe9c014c3 + .long 0x700c0c01,0x00076614,0x58806010,0x428061ff + .long 0x0000967c,0x202eff44,0x90ae0006,0x3d40000a + .long 0x4cee0303,0xff9c4e5e,0x518f2f00,0x3f6f000c + .long 0x00042f6f,0x000e0006,0x4280302f,0x00122f6f + .long 0x00060010,0xd1af0006,0x3f7c402c,0x000a201f + .long 0x60ffffff,0xebe44e7a,0x08080800,0x0001660c + .long 0xf22e9c00,0xff60f22e,0xd0c0ffdc,0x4cee0303 + .long 0xff9c4e5e,0x514f2eaf,0x00083f6f,0x000c0004 + .long 0x3f7c4008,0x00062f6f,0x00020008,0x2f7c0942 + .long 0x8001000c,0x08170005,0x670608ef,0x0002000d + .long 0x60ffffff,0xebd64fee,0xff404e7a,0x18080801 + .long 0x0001660c,0xf22ed0c0,0xffdcf22f,0x9c000020 + .long 0x2c562f6f,0x00c400bc,0x3f6f00c8,0x00c03f7c + .long 0x400800c2,0x2f4800c4,0x3f4000c8,0x3f7c0001 + .long 0x00ca4cef,0x0303005c,0xdefc00bc,0x60a64e56 + .long 0xff40f32e,0xff6c48ee,0x0303ff9c,0xf22ebc00 + .long 0xff60f22e,0xf0c0ffdc,0x2d6eff68,0xff44206e + .long 0xff4458ae,0xff4461ff,0xffffebce,0x2d40ff40 + .long 0x0800000d,0x662841ee,0xff6c61ff,0xfffff1ea + .long 0xf22ed0c0,0xffdcf22e,0x9c00ff60,0x4cee0303 + .long 0xff9cf36e,0xff6c4e5e,0x60ffffff,0xea94322e + .long 0xff6c0241,0x7fff0c41,0x7fff661a,0x4aaeff74 + .long 0x660c222e,0xff700281,0x7fffffff,0x67082d6e + .long 0xff70ff54,0x6012223c,0x7fffffff,0x4a2eff6c + .long 0x6a025281,0x2d41ff54,0xe9c004c3,0x122eff41 + .long 0x307b0206,0x4efb8802,0x006c0000,0x0000ff98 + .long 0x003e0000,0x00100000,0x102eff54,0x0c010007 + .long 0x6f16206e,0x000c61ff,0xffffeb86,0x4a8166ff + .long 0x0000bca8,0x6000ff6a,0x02410007,0x61ff0000 + .long 0xa8046000,0xff5c302e,0xff540c01,0x00076f16 + .long 0x206e000c,0x61ffffff,0xeb6e4a81,0x66ff0000 + .long 0xbc886000,0xff3c0241,0x000761ff,0x0000a79a + .long 0x6000ff2e,0x202eff54,0x0c010007,0x6f16206e + .long 0x000c61ff,0xffffeb56,0x4a8166ff,0x0000bc68 + .long 0x6000ff0e,0x02410007,0x61ff0000,0xa7306000 + .long 0xff004e56,0xff40f32e,0xff6c48ee,0x0303ff9c + .long 0xf22ebc00,0xff60f22e,0xf0c0ffdc,0x2d6eff68 + .long 0xff44206e,0xff4458ae,0xff4461ff,0xffffea8a + .long 0x2d40ff40,0x0800000d,0x6600002a,0x41eeff6c + .long 0x61ffffff,0xf0a4f22e,0xd0c0ffdc,0xf22e9c00 + .long 0xff604cee,0x0303ff9c,0xf36eff6c,0x4e5e60ff + .long 0xffffe964,0xe9c004c3,0x122eff41,0x307b0206 + .long 0x4efb8802,0x007400a6,0x015a0000,0x00420104 + .long 0x00100000,0x102eff70,0x08c00006,0x0c010007 + .long 0x6f16206e,0x000c61ff,0xffffea76,0x4a8166ff + .long 0x0000bb98,0x6000ffa0,0x02410007,0x61ff0000 + .long 0xa6f46000,0xff92302e,0xff7008c0,0x000e0c01 + .long 0x00076f16,0x206e000c,0x61ffffff,0xea5a4a81 + .long 0x66ff0000,0xbb746000,0xff6e0241,0x000761ff + .long 0x0000a686,0x6000ff60,0x202eff70,0x08c0001e + .long 0x0c010007,0x6f16206e,0x000c61ff,0xffffea3e + .long 0x4a8166ff,0x0000bb50,0x6000ff3c,0x02410007 + .long 0x61ff0000,0xa6186000,0xff2e0c01,0x00076f2e + .long 0x202eff6c,0x02808000,0x00000080,0x7fc00000 + .long 0x222eff70,0xe0898081,0x206e000c,0x61ffffff + .long 0xe9fc4a81,0x66ff0000,0xbb0e6000,0xfefa202e + .long 0xff6c0280,0x80000000,0x00807fc0,0x00002f01 + .long 0x222eff70,0xe0898081,0x221f0241,0x000761ff + .long 0x0000a5ba,0x6000fed0,0x202eff6c,0x02808000 + .long 0x00000080,0x7ff80000,0x222eff70,0x2d40ff84 + .long 0x700be0a9,0x83aeff84,0x222eff70,0x02810000 + .long 0x07ffe0b9,0x2d41ff88,0x222eff74,0xe0a983ae + .long 0xff8841ee,0xff84226e,0x000c7008,0x61ffffff + .long 0xe8cc4a81,0x66ff0000,0xba9c6000,0xfe7a422e + .long 0xff4a3d6e,0xff6cff84,0x426eff86,0x202eff70 + .long 0x08c0001e,0x2d40ff88,0x2d6eff74,0xff8c082e + .long 0x00050004,0x66384e68,0x2d48ffd8,0x2d56ffd4 + .long 0x61ff0000,0x98922248,0x2d48000c,0x206effd8 + .long 0x4e602cae,0xffd441ee,0xff84700c,0x61ffffff + .long 0xe86c4a81,0x66ff0000,0xba4a6000,0xfe1a2d56 + .long 0xffd461ff,0x00009860,0x22482d48,0x000c2cae + .long 0xffd40c2e,0x0008ff4a,0x66ccf22e,0xd0c0ffdc + .long 0xf22e9c00,0xff604cee,0x0303ff9c,0xf36eff6c + .long 0x2c6effd4,0x2f6f00c4,0x00b82f6f,0x00c800bc + .long 0x2f6f00cc,0x00c02f6f,0x004400c4,0x2f6f0048 + .long 0x00c82f6f,0x004c00cc,0xdffc0000,0x00b860ff + .long 0xffffe734,0x4e56ff40,0xf32eff6c,0x48ee0303 + .long 0xff9cf22e,0xbc00ff60,0xf22ef0c0,0xffdc2d6e + .long 0xff68ff44,0x206eff44,0x58aeff44,0x61ffffff + .long 0xe7f82d40,0xff400800,0x000d6600,0x0106e9c0 + .long 0x04c36622,0x0c6e401e,0xff6c661a,0xf23c9000 + .long 0x00000000,0xf22e4000,0xff70f22e,0x6800ff6c + .long 0x3d7ce001,0xff6e41ee,0xff6c61ff,0xffffedea + .long 0x02ae00ff,0x01ffff64,0xf23c9000,0x00000000 + .long 0xf23c8800,0x00000000,0xe9ee1006,0xff420c01 + .long 0x00176700,0x009641ee,0xff6c61ff,0x0000aa84 + .long 0x1d40ff4e,0x082e0005,0xff43672e,0x082e0004 + .long 0xff436626,0xe9ee0183,0xff4261ff,0x0000a5c2 + .long 0x41eeff78,0x61ff0000,0xaa5a0c00,0x00066606 + .long 0x61ff0000,0xa9be1d40,0xff4f4280,0x102eff63 + .long 0x122eff43,0x0241007f,0x41eeff6c,0x43eeff78 + .long 0x223b1530,0x000059ca,0x4ebb1930,0x000059c2 + .long 0xe9ee0183,0xff4261ff,0x0000a606,0xf22ed0c0 + .long 0xffdcf22e,0x9c00ff60,0x4cee0303,0xff9cf36e + .long 0xff6c4e5e,0x60ffffff,0xe5cc4280,0x102eff63 + .long 0x122eff43,0x02810000,0x007f61ff,0x000043ce + .long 0x60be1d7c,0x0000ff4e,0x4280102e,0xff6302ae + .long 0xffff00ff,0xff6441ee,0xff6c61ff,0x00009be4 + .long 0x60aa4e56,0xff40f32e,0xff6c48ee,0x0303ff9c + .long 0xf22ebc00,0xff60f22e,0xf0c0ffdc,0x2d6eff68 + .long 0xff44206e,0xff4458ae,0xff4461ff,0xffffe69a + .long 0x2d40ff40,0x41eeff6c,0x61ffffff,0xecbcf22e + .long 0xd0c0ffdc,0xf22e9c00,0xff604cee,0x0303ff9c + .long 0xf36eff6c,0x4e5e60ff,0xffffe592,0x0c6f202c + .long 0x000667ff,0x000000aa,0x0c6f402c,0x000667ff + .long 0xffffe5a6,0x4e56ff40,0x48ee0303,0xff9c2d6e + .long 0x0006ff44,0x206eff44,0x58aeff44,0x61ffffff + .long 0xe638e9c0,0x100a0c41,0x03c86664,0xe9c01406 + .long 0x0c010017,0x665a4e7a,0x08080800,0x0001672a + .long 0x4cee0303,0xff9c4e5e,0x518f3eaf,0x00082f6f + .long 0x000a0002,0x3f7c402c,0x00062f6f,0x0002000c + .long 0x58af0002,0x60ffffff,0xe5404cee,0x0303ff9c + .long 0x4e5ef22f,0x84000002,0x58af0002,0x2f172f6f + .long 0x00080004,0x1f7c0020,0x000660ff,0x00000012 + .long 0x4cee0303,0xff9c4e5e,0x60ffffff,0xe4f64e56 + .long 0xff4048ee,0x0303ff9c,0xf22ebc00,0xff60f22e + .long 0xf0c0ffdc,0x082e0005,0x00046608,0x4e682d48 + .long 0xffd8600c,0x41ee0010,0x2d48ffd8,0x2d48ffd4 + .long 0x2d6eff68,0xff44206e,0xff4458ae,0xff4461ff + .long 0xffffe576,0x2d40ff40,0xf23c9000,0x00000000 + .long 0xf23c8800,0x00000000,0x422eff4a,0x08000016 + .long 0x66000182,0x422eff53,0x02ae00ff,0x00ffff64 + .long 0xe9c01406,0x0c010017,0x670000be,0x61ff0000 + .long 0x95fc4280,0x102eff63,0x122eff43,0x0241003f + .long 0xe749822e,0xff4e43ee,0xff7841ee,0xff6c323b + .long 0x132002b2,0x4ebb1120,0x02ac102e,0xff626600 + .long 0x00a2e9ee,0x0183ff42,0x61ff0000,0xa3e4f22e + .long 0xd0c0ffdc,0xf22e9c00,0xff604cee,0x0303ff9c + .long 0x0c2e0004,0xff4a672a,0x0c2e0008,0xff4a6722 + .long 0x4e5e0817,0x000767ff,0xffffe358,0xf327f22f + .long 0xa4000014,0xf35f3f7c,0x20240006,0x60ffffff + .long 0xe434082e,0x00050004,0x660c2f08,0x206effd8 + .long 0x4e60205f,0x60ca2f00,0x202effd8,0x90aeffd4 + .long 0x2dae0008,0x08082dae,0x00040804,0x3d400004 + .long 0x201f4e5e,0xded760aa,0x4280102e,0xff63122e + .long 0xff430281,0x0000007f,0x61ff0000,0x41506000 + .long 0xff5ac02e,0xff66edc0,0x06086616,0x082e0004 + .long 0xff666700,0xff4e082e,0x0001ff62,0x6700ff44 + .long 0x603e0480,0x00000018,0x0c000006,0x6610082e + .long 0x0004ff66,0x662a082e,0x0003ff66,0x66302f00 + .long 0x61ffffff,0xf1ee201f,0x3d7b0206,0xff6e602a + .long 0xe002e006,0xe004e005,0xe003e002,0xe001e001 + .long 0x61ffffff,0xf1ce3d7c,0xe005ff6e,0x600c61ff + .long 0xfffff1c0,0x3d7ce003,0xff6ef22e,0xd0c0ffdc + .long 0xf22e9c00,0xff604cee,0x0303ff9c,0xf36eff6c + .long 0x6000feee,0xe9c01283,0x0c010001,0x67000056 + .long 0x0c010007,0x66000078,0xe9c01343,0x0c010002 + .long 0x6d00006c,0x61ff0000,0x82780c2e,0x0002ff4a + .long 0x670000d2,0x0c2e0001,0xff4a6600,0x01002d6e + .long 0xff68000c,0x3d7c201c,0x000af22e,0xd0c0ffdc + .long 0xf22e9c00,0xff604cee,0x0303ff9c,0x4e5e60ff + .long 0xffffe2dc,0x206eff44,0x54aeff44,0x61ffffff + .long 0xe3524a81,0x6600047c,0x48c061ff,0x00007e60 + .long 0x0c2e0002,0xff4a6700,0x007c6000,0x00b061ff + .long 0x00008562,0x0c2e0002,0xff4a6700,0x0068082e + .long 0x00050004,0x660a206e,0xffd84e60,0x6000008e + .long 0x0c2e0008,0xff4a6600,0x0084f22e,0xd0c0ffdc + .long 0xf22e9c00,0xff604cee,0x0303ff9c,0x4e5e0817 + .long 0x00076612,0x558f2eaf,0x00022f6f,0x00060004 + .long 0x60ffffff,0xe17e558f,0x2eaf0002,0x3f6f0006 + .long 0x00043f7c,0x20240006,0xf22fa400,0x000860ff + .long 0xffffe252,0x3d7c00c0,0x000e2d6e,0xff68000a + .long 0x3d6e0004,0x00083d7c,0xe000ff6e,0xf22ed0c0 + .long 0xffdcf22e,0x9c00ff60,0x4cee0303,0xff9cf36e + .long 0xff6c4e5e,0x588f60ff,0xffffe180,0xf22ed0c0 + .long 0xffdcf22e,0x9c00ff60,0x4cee0303,0xff9c4e5e + .long 0x08170007,0x660660ff,0xffffe108,0xf22fa400 + .long 0x00081f7c,0x00240007,0x60ffffff,0xe1e84afc + .long 0x01c00000,0x00000000,0x00000000,0x00000000 + .long 0x00000000,0x00000000,0x00000000,0x00000000 + .long 0x000028a4,0x4b1e4b4c,0x4f4c2982,0x4f3c0000 + .long 0x00000000,0x00000000,0x00000000,0x00000000 + .long 0x00000000,0x00000000,0x00000000,0x00000000 + .long 0x00000000,0x00000000,0x00000000,0x00000000 + .long 0x000035c6,0x4b1e4b82,0x4f4c371a,0x4f3c0000 + .long 0x00000000,0x00000000,0x00000000,0x00000000 + .long 0x000024b0,0x4b1e4b8c,0x4f4c2766,0x4f3c0000 + .long 0x00002988,0x4b1e4b94,0x4f4c2af0,0x4f3c0000 + .long 0x00001ab8,0x4b1e4bd0,0x4f4c1cf6,0x4f3c0000 + .long 0x00000000,0x00000000,0x00000000,0x00000000 + .long 0x00001cfc,0x4b1e4744,0x4f4c1daa,0x4f3c0000 + .long 0x00003720,0x4b1e4744,0x4f4c37a2,0x4f3c0000 + .long 0x00000468,0x4b1e4744,0x4f4c064c,0x4f3c0000 + .long 0x00000f2a,0x4b1e4744,0x4f4c108e,0x4f3c0000 + .long 0x000022e0,0x4b9a4b7a,0x4f4c248c,0x4f3c0000 + .long 0x00003d02,0x4b9a4b7a,0x4f4c3ddc,0x4f3c0000 + .long 0x00003dfa,0x4b9a4b7a,0x4f4c3f2a,0x4f3c0000 + .long 0x00000000,0x00000000,0x00000000,0x00000000 + .long 0x00003386,0x47324b82,0x4f4c3538,0x4f3c0000 + .long 0x000037c8,0x47324b82,0x4f4c37f8,0x4f3c0000 + .long 0x00003818,0x47324b82,0x4f4c3872,0x4f3c0000 + .long 0x00000000,0x00000000,0x00000000,0x00000000 + .long 0x00000000,0x00000000,0x00000000,0x00000000 + .long 0x000027e6,0x4b9a4b52,0x4f4c288a,0x4f3c0000 + .long 0x00000000,0x00000000,0x00000000,0x00000000 + .long 0x00000000,0x00000000,0x00000000,0x00000000 + .long 0x00001db0,0x4bd64744,0x4f4c1e40,0x4f3c0000 + .long 0x00000472,0x4b9a4744,0x4f4c0652,0x4f3c0000 + .long 0x0000276c,0x4b1e4744,0x4f4c2788,0x4f3c0000 + .long 0x000027a0,0x4b1e4744,0x4f4c27ce,0x4f3c0000 + .long 0x00000000,0x00000000,0x00000000,0x00000000 + .long 0x00004ca4,0x4cda4d12,0x4ee24ca4,0x4ef40000 + .long 0x00000000,0x00000000,0x00000000,0x00000000 + .long 0x00000000,0x00000000,0x00000000,0x00000000 + .long 0x00000000,0x00000000,0x00000000,0x00000000 + .long 0x00004dac,0x4de24e1a,0x4ee24dac,0x4ef40000 + .long 0x00004e4e,0x4e864ebe,0x4ee24e4e,0x4ef40000 + .long 0x00000000,0x00000000,0x00000000,0x00000000 + .long 0x00000000,0x00000000,0x00000000,0x00000000 + .long 0x00000000,0x00000000,0x00000000,0x00000000 + .long 0x00000000,0x00000000,0x00000000,0x00000000 + .long 0x00000000,0x00000000,0x00000000,0x00000000 + .long 0x00000000,0x00000000,0x00000000,0x00000000 + .long 0x00000000,0x00000000,0x00000000,0x00000000 + .long 0x00000000,0x00000000,0x00000000,0x00000000 + .long 0x00000000,0x00000000,0x00000000,0x00000000 + .long 0x00000660,0x4bf24c20,0x4c3008f6,0x4c400000 + .long 0x00000660,0x4bf24c20,0x4c3008f6,0x4c400000 + .long 0x00000660,0x4bf24c20,0x4c3008f6,0x4c400000 + .long 0x00000660,0x4bf24c20,0x4c3008f6,0x4c400000 + .long 0x00000660,0x4bf24c20,0x4c3008f6,0x4c400000 + .long 0x00000660,0x4bf24c20,0x4c3008f6,0x4c400000 + .long 0x00000660,0x4bf24c20,0x4c3008f6,0x4c400000 + .long 0x00000660,0x4bf24c20,0x4c3008f6,0x4c400000 + .long 0x00004cee,0x0303ff9c,0xf22e9c00,0xff60f22e + .long 0xd0c0ffdc,0x2d6eff68,0x00064e5e,0x2f173f6f + .long 0x00080004,0x3f7c4008,0x00062f6f,0x00020008 + .long 0x2f7c0942,0x8001000c,0x08170005,0x670608ef + .long 0x0002000d,0x60ffffff,0xde32bd6a,0xaa77ccc9 + .long 0x94f53de6,0x12097aae,0x8da1be5a,0xe6452a11 + .long 0x8ae43ec7,0x1de3a534,0x1531bf2a,0x01a01a01 + .long 0x8b590000,0x00000000,0x00003ff8,0x00008888 + .long 0x88888888,0x59af0000,0x0000bffc,0x0000aaaa + .long 0xaaaaaaaa,0xaa990000,0x00003d2a,0xc4d0d601 + .long 0x1ee3bda9,0x396f9f45,0xac193e21,0xeed90612 + .long 0xc972be92,0x7e4fb79d,0x9fcf3efa,0x01a01a01 + .long 0xd4230000,0x00000000,0x0000bff5,0x0000b60b + .long 0x60b60b61,0xd4380000,0x00003ffa,0x0000aaaa + .long 0xaaaaaaaa,0xab5ebf00,0x00002d7c,0x00000000 + .long 0xff5c6008,0x2d7c0000,0x0001ff5c,0xf2104800 + .long 0xf22e6800,0xff842210,0x32280004,0x02817fff + .long 0xffff0c81,0x3fd78000,0x6c046000,0x01780c81 + .long 0x4004bc7e,0x6d046000,0x0468f200,0x0080f23a + .long 0x54a3de7e,0x43fb0170,0x00000866,0xf22e6080 + .long 0xff58222e,0xff58e981,0xd3c1f219,0x4828f211 + .long 0x4428222e,0xff58d2ae,0xff5ce299,0x0c810000 + .long 0x00006d00,0x0088f227,0xe00cf22e,0x6800ff84 + .long 0xf2000023,0xf23a5580,0xfed2f23a,0x5500fed4 + .long 0xf2000080,0xf20004a3,0xe2990281,0x80000000 + .long 0xb3aeff84,0xf20005a3,0xf2000523,0xf23a55a2 + .long 0xfebaf23a,0x5522febc,0xf20005a3,0xf2000523 + .long 0xf23a55a2,0xfeb6f23a,0x4922fec0,0xf2000ca3 + .long 0xf2000123,0xf23a48a2,0xfec2f22e,0x4823ff84 + .long 0xf20008a2,0xf2000423,0xf21fd030,0xf2009000 + .long 0xf22e4822,0xff8460ff,0x00004364,0xf227e00c + .long 0xf2000023,0xf23a5500,0xfea2f23a,0x5580fea4 + .long 0xf2000080,0xf20004a3,0xf22e6800,0xff84e299 + .long 0x02818000,0x0000f200,0x0523b3ae,0xff840281 + .long 0x80000000,0xf20005a3,0x00813f80,0x00002d41 + .long 0xff54f23a,0x5522fe74,0xf23a55a2,0xfe76f200 + .long 0x0523f200,0x05a3f23a,0x5522fe70,0xf23a49a2 + .long 0xfe7af200,0x0523f200,0x0ca3f23a,0x4922fe7c + .long 0xf23a44a2,0xfe82f200,0x0823f200,0x0422f22e + .long 0x4823ff84,0xf21fd030,0xf2009000,0xf22e4422 + .long 0xff5460ff,0x000042c8,0x0c813fff,0x80006eff + .long 0x00000300,0x222eff5c,0x0c810000,0x00006e14 + .long 0xf2009000,0x123c0003,0xf22e4800,0xff8460ff + .long 0x0000428e,0xf23c4400,0x3f800000,0xf2009000 + .long 0xf23c4422,0x80800000,0x60ff0000,0x428a60ff + .long 0x00004110,0xf23c4400,0x3f800000,0x60ff0000 + .long 0x42762d7c,0x00000004,0xff5cf210,0x4800f22e + .long 0x6800ff84,0x22103228,0x00040281,0x7fffffff + .long 0x0c813fd7,0x80006c04,0x60000240,0x0c814004 + .long 0xbc7e6d04,0x6000027a,0xf2000080,0xf23a54a3 + .long 0xdc9043fb,0x01700000,0x0678f22e,0x6080ff58 + .long 0x222eff58,0xe981d3c1,0xf2194828,0xf2114428 + .long 0x222eff58,0xe2990c81,0x00000000,0x6c000106 + .long 0xf227e004,0xf22e6800,0xff84f200,0x0023f23a + .long 0x5480fce8,0xf23a5500,0xfd32f200,0x00a3f200 + .long 0x01232f02,0x2401e29a,0x02828000,0x0000b382 + .long 0x02828000,0x0000f23a,0x54a2fcc8,0xf23a5522 + .long 0xfd12f200,0x00a3b5ae,0xff84241f,0xf2000123 + .long 0xe2990281,0x80000000,0x2d7c3f80,0x0000ff54 + .long 0xb3aeff54,0xf23a54a2,0xfca2f23a,0x5522fcec + .long 0xf20000a3,0xf2000123,0xf22e6800,0xff90f23a + .long 0x54a2fc90,0xb3aeff90,0xf23a5522,0xfcd6f200 + .long 0x00a3f200,0x0123f23a,0x54a2fc80,0xf23a5522 + .long 0xfccaf200,0x00a3f200,0x0123f23a,0x48a2fc7c + .long 0xf23a4922,0xfcc6f200,0x00a3f200,0x0123f23a + .long 0x48a2fc78,0xf23a4922,0xfcc2f200,0x00a3f200 + .long 0x0823f22e,0x48a3ff84,0xf23a4422,0xfcbaf22e + .long 0x4823ff90,0xf21fd020,0xf2009000,0xf22e48a2 + .long 0xff8461ff,0x0000448e,0xf22e4422,0xff5460ff + .long 0x000040fc,0xf227e004,0xf22e6800,0xff84f200 + .long 0x0023f23a,0x5480fc34,0xf23a5500,0xfbdef200 + .long 0x00a3f22e,0x6800ff90,0xf2000123,0xe2990281 + .long 0x80000000,0xf23a54a2,0xfc1af23a,0x5522fbc4 + .long 0xb3aeff84,0xb3aeff90,0xf20000a3,0x00813f80 + .long 0x00002d41,0xff54f200,0x0123f23a,0x54a2fbfc + .long 0xf23a5522,0xfba6f200,0x00a3f200,0x0123f23a + .long 0x54a2fbf0,0xf23a5522,0xfb9af200,0x00a3f200 + .long 0x0123f23a,0x54a2fbe4,0xf23a5522,0xfb8ef200 + .long 0x00a3f200,0x0123f23a,0x48a2fbe0,0xf23a4922 + .long 0xfb8af200,0x00a3f200,0x0123f23a,0x48a2fbdc + .long 0xf23a4922,0xfb86f200,0x00a3f200,0x0823f23a + .long 0x44a2fbd4,0xf22e4823,0xff84f22e,0x48a3ff90 + .long 0xf21fd020,0xf2009000,0xf22e44a2,0xff5461ff + .long 0x000043a2,0xf22e4822,0xff8460ff,0x00004010 + .long 0x0c813fff,0x80006e00,0x0048f23c,0x44803f80 + .long 0x0000f200,0x9000f23c,0x44a80080,0x000061ff + .long 0x00004372,0xf200b000,0x123c0003,0xf22e4800 + .long 0xff8460ff,0x00003fca,0x2f00f23c,0x44803f80 + .long 0x000061ff,0x0000434e,0x201f60ff,0x00003e54 + .long 0xf227e03c,0x2f02f23c,0x44800000,0x00000c81 + .long 0x7ffeffff,0x66523d7c,0x7ffeff84,0x2d7cc90f + .long 0xdaa2ff88,0x42aeff8c,0x3d7c7fdc,0xff902d7c + .long 0x85a308d3,0xff9442ae,0xff98f200,0x003af294 + .long 0x000e002e,0x0080ff84,0x002e0080,0xff90f22e + .long 0x4822ff84,0xf2000080,0xf22e4822,0xff90f200 + .long 0x00a8f22e,0x48a2ff90,0xf22e6800,0xff84322e + .long 0xff842241,0x02810000,0x7fff0481,0x00003fff + .long 0x0c810000,0x001c6f0e,0x04810000,0x001b1d7c + .long 0x0000ff58,0x60084281,0x1d7c0001,0xff58243c + .long 0x00003ffe,0x94812d7c,0xa2f9836e,0xff882d7c + .long 0x4e44152a,0xff8c3d42,0xff84f200,0x0100f22e + .long 0x4923ff84,0x24094842,0x02828000,0x00000082 + .long 0x5f000000,0x2d42ff54,0xf22e4522,0xff54f22e + .long 0x4528ff54,0x24010682,0x00003fff,0x3d42ff84 + .long 0x2d7cc90f,0xdaa2ff88,0x42aeff8c,0x06810000 + .long 0x3fdd3d41,0xff902d7c,0x85a308d3,0xff9442ae + .long 0xff98122e,0xff58f200,0x0a00f22e,0x4a23ff84 + .long 0xf2000a80,0xf22e4aa3,0xff90f200,0x1180f200 + .long 0x15a2f200,0x0e28f200,0x0c28f200,0x1622f200 + .long 0x0180f200,0x10a8f200,0x04220c01,0x00006e00 + .long 0x000ef200,0x01a8f200,0x0ca26000,0xff0cf22e + .long 0x6100ff58,0x241ff21f,0xd03c222e,0xff5c0c81 + .long 0x00000004,0x6d00fa4c,0x6000fc36,0x3ea0b759 + .long 0xf50f8688,0xbef2baa5,0xa8924f04,0xbf346f59 + .long 0xb39ba65f,0x00000000,0x00000000,0x3ff60000 + .long 0xe073d3fc,0x199c4a00,0x00000000,0x3ff90000 + .long 0xd23cd684,0x15d95fa1,0x00000000,0xbffc0000 + .long 0x8895a6c5,0xfb423bca,0x00000000,0xbffd0000 + .long 0xeef57e0d,0xa84bc8ce,0x00000000,0x3ffc0000 + .long 0xa2f9836e,0x4e44152a,0x00000000,0x40010000 + .long 0xc90fdaa2,0x00000000,0x00000000,0x3fdf0000 + .long 0x85a308d4,0x00000000,0x00000000,0xc0040000 + .long 0xc90fdaa2,0x2168c235,0x21800000,0xc0040000 + .long 0xc2c75bcd,0x105d7c23,0xa0d00000,0xc0040000 + .long 0xbc7edcf7,0xff523611,0xa1e80000,0xc0040000 + .long 0xb6365e22,0xee46f000,0x21480000,0xc0040000 + .long 0xafeddf4d,0xdd3ba9ee,0xa1200000,0xc0040000 + .long 0xa9a56078,0xcc3063dd,0x21fc0000,0xc0040000 + .long 0xa35ce1a3,0xbb251dcb,0x21100000,0xc0040000 + .long 0x9d1462ce,0xaa19d7b9,0xa1580000,0xc0040000 + .long 0x96cbe3f9,0x990e91a8,0x21e00000,0xc0040000 + .long 0x90836524,0x88034b96,0x20b00000,0xc0040000 + .long 0x8a3ae64f,0x76f80584,0xa1880000,0xc0040000 + .long 0x83f2677a,0x65ecbf73,0x21c40000,0xc0030000 + .long 0xfb53d14a,0xa9c2f2c2,0x20000000,0xc0030000 + .long 0xeec2d3a0,0x87ac669f,0x21380000,0xc0030000 + .long 0xe231d5f6,0x6595da7b,0xa1300000,0xc0030000 + .long 0xd5a0d84c,0x437f4e58,0x9fc00000,0xc0030000 + .long 0xc90fdaa2,0x2168c235,0x21000000,0xc0030000 + .long 0xbc7edcf7,0xff523611,0xa1680000,0xc0030000 + .long 0xafeddf4d,0xdd3ba9ee,0xa0a00000,0xc0030000 + .long 0xa35ce1a3,0xbb251dcb,0x20900000,0xc0030000 + .long 0x96cbe3f9,0x990e91a8,0x21600000,0xc0030000 + .long 0x8a3ae64f,0x76f80584,0xa1080000,0xc0020000 + .long 0xfb53d14a,0xa9c2f2c2,0x1f800000,0xc0020000 + .long 0xe231d5f6,0x6595da7b,0xa0b00000,0xc0020000 + .long 0xc90fdaa2,0x2168c235,0x20800000,0xc0020000 + .long 0xafeddf4d,0xdd3ba9ee,0xa0200000,0xc0020000 + .long 0x96cbe3f9,0x990e91a8,0x20e00000,0xc0010000 + .long 0xfb53d14a,0xa9c2f2c2,0x1f000000,0xc0010000 + .long 0xc90fdaa2,0x2168c235,0x20000000,0xc0010000 + .long 0x96cbe3f9,0x990e91a8,0x20600000,0xc0000000 + .long 0xc90fdaa2,0x2168c235,0x1f800000,0xbfff0000 + .long 0xc90fdaa2,0x2168c235,0x1f000000,0x00000000 + .long 0x00000000,0x00000000,0x00000000,0x3fff0000 + .long 0xc90fdaa2,0x2168c235,0x9f000000,0x40000000 + .long 0xc90fdaa2,0x2168c235,0x9f800000,0x40010000 + .long 0x96cbe3f9,0x990e91a8,0xa0600000,0x40010000 + .long 0xc90fdaa2,0x2168c235,0xa0000000,0x40010000 + .long 0xfb53d14a,0xa9c2f2c2,0x9f000000,0x40020000 + .long 0x96cbe3f9,0x990e91a8,0xa0e00000,0x40020000 + .long 0xafeddf4d,0xdd3ba9ee,0x20200000,0x40020000 + .long 0xc90fdaa2,0x2168c235,0xa0800000,0x40020000 + .long 0xe231d5f6,0x6595da7b,0x20b00000,0x40020000 + .long 0xfb53d14a,0xa9c2f2c2,0x9f800000,0x40030000 + .long 0x8a3ae64f,0x76f80584,0x21080000,0x40030000 + .long 0x96cbe3f9,0x990e91a8,0xa1600000,0x40030000 + .long 0xa35ce1a3,0xbb251dcb,0xa0900000,0x40030000 + .long 0xafeddf4d,0xdd3ba9ee,0x20a00000,0x40030000 + .long 0xbc7edcf7,0xff523611,0x21680000,0x40030000 + .long 0xc90fdaa2,0x2168c235,0xa1000000,0x40030000 + .long 0xd5a0d84c,0x437f4e58,0x1fc00000,0x40030000 + .long 0xe231d5f6,0x6595da7b,0x21300000,0x40030000 + .long 0xeec2d3a0,0x87ac669f,0xa1380000,0x40030000 + .long 0xfb53d14a,0xa9c2f2c2,0xa0000000,0x40040000 + .long 0x83f2677a,0x65ecbf73,0xa1c40000,0x40040000 + .long 0x8a3ae64f,0x76f80584,0x21880000,0x40040000 + .long 0x90836524,0x88034b96,0xa0b00000,0x40040000 + .long 0x96cbe3f9,0x990e91a8,0xa1e00000,0x40040000 + .long 0x9d1462ce,0xaa19d7b9,0x21580000,0x40040000 + .long 0xa35ce1a3,0xbb251dcb,0xa1100000,0x40040000 + .long 0xa9a56078,0xcc3063dd,0xa1fc0000,0x40040000 + .long 0xafeddf4d,0xdd3ba9ee,0x21200000,0x40040000 + .long 0xb6365e22,0xee46f000,0xa1480000,0x40040000 + .long 0xbc7edcf7,0xff523611,0x21e80000,0x40040000 + .long 0xc2c75bcd,0x105d7c23,0x20d00000,0x40040000 + .long 0xc90fdaa2,0x2168c235,0xa1800000,0xf2104800 + .long 0x22103228,0x00040281,0x7fffffff,0x0c813fd7 + .long 0x80006c04,0x60000134,0x0c814004,0xbc7e6d04 + .long 0x60000144,0xf2000080,0xf23a54a3,0xd3d443fa + .long 0xfdbcf201,0x6080e981,0xd3c1f219,0x4828f211 + .long 0x4428ea99,0x02818000,0x0000f227,0xe00c0c81 + .long 0x00000000,0x6d000072,0xf2000080,0xf20004a3 + .long 0xf23a5580,0xfaf8f23a,0x5500fafa,0xf20005a3 + .long 0xf2000523,0xf23a55a2,0xfaf4f23a,0x4922fafe + .long 0xf20005a3,0xf2000523,0xf23a49a2,0xfb00f23a + .long 0x4922fb0a,0xf20005a3,0xf2000523,0xf23a49a2 + .long 0xfb0cf200,0x0123f200,0x0ca3f200,0x0822f23c + .long 0x44a23f80,0x0000f21f,0xd030f200,0x9000f200 + .long 0x042060ff,0x000038d8,0xf2000080,0xf2000023 + .long 0xf23a5580,0xfa88f23a,0x5500fa8a,0xf20001a3 + .long 0xf2000123,0xf23a55a2,0xfa84f23a,0x4922fa8e + .long 0xf20001a3,0xf2000123,0xf23a49a2,0xfa90f23a + .long 0x4922fa9a,0xf20001a3,0xf2000123,0xf23a49a2 + .long 0xfa9cf200,0x0523f200,0x0c23f200,0x08a2f23c + .long 0x44223f80,0x0000f21f,0xd030f227,0x68800a97 + .long 0x80000000,0xf2009000,0xf21f4820,0x60ff0000 + .long 0x385e0c81,0x3fff8000,0x6e1cf227,0x6800f200 + .long 0x9000123c,0x0003f21f,0x480060ff,0x00003832 + .long 0x60ff0000,0x36cef227,0xe03c2f02,0xf23c4480 + .long 0x00000000,0x0c817ffe,0xffff6652,0x3d7c7ffe + .long 0xff842d7c,0xc90fdaa2,0xff8842ae,0xff8c3d7c + .long 0x7fdcff90,0x2d7c85a3,0x08d3ff94,0x42aeff98 + .long 0xf200003a,0xf294000e,0x002e0080,0xff84002e + .long 0x0080ff90,0xf22e4822,0xff84f200,0x0080f22e + .long 0x4822ff90,0xf20000a8,0xf22e48a2,0xff90f22e + .long 0x6800ff84,0x322eff84,0x22410281,0x00007fff + .long 0x04810000,0x3fff0c81,0x0000001c,0x6f0e0481 + .long 0x0000001b,0x1d7c0000,0xff586008,0x42811d7c + .long 0x0001ff58,0x243c0000,0x3ffe9481,0x2d7ca2f9 + .long 0x836eff88,0x2d7c4e44,0x152aff8c,0x3d42ff84 + .long 0xf2000100,0xf22e4923,0xff842409,0x48420282 + .long 0x80000000,0x00825f00,0x00002d42,0xff54f22e + .long 0x4522ff54,0xf22e4528,0xff542401,0x06820000 + .long 0x3fff3d42,0xff842d7c,0xc90fdaa2,0xff8842ae + .long 0xff8c0681,0x00003fdd,0x3d41ff90,0x2d7c85a3 + .long 0x08d3ff94,0x42aeff98,0x122eff58,0xf2000a00 + .long 0xf22e4a23,0xff84f200,0x0a80f22e,0x4aa3ff90 + .long 0xf2001180,0xf20015a2,0xf2000e28,0xf2000c28 + .long 0xf2001622,0xf2000180,0xf20010a8,0xf2000422 + .long 0x0c010000,0x6e00000e,0xf20001a8,0xf2000ca2 + .long 0x6000ff0c,0xf22e6100,0xff54241f,0xf21fd03c + .long 0x222eff54,0xe2996000,0xfd72bff6,0x687e3149 + .long 0x87d84002,0xac6934a2,0x6db3bfc2,0x476f4e1d + .long 0xa28e3fb3,0x44447f87,0x6989bfb7,0x44ee7faf + .long 0x45db3fbc,0x71c64694,0x0220bfc2,0x49249218 + .long 0x72f93fc9,0x99999999,0x8fa9bfd5,0x55555555 + .long 0x5555bfb7,0x0bf39853,0x9e6a3fbc,0x7187962d + .long 0x1d7dbfc2,0x49248271,0x07b83fc9,0x99999996 + .long 0x263ebfd5,0x55555555,0x55363fff,0x0000c90f + .long 0xdaa22168,0xc2350000,0x0000bfff,0x0000c90f + .long 0xdaa22168,0xc2350000,0x00000001,0x00008000 + .long 0x00000000,0x00000000,0x00008001,0x00008000 + .long 0x00000000,0x00000000,0x00003ffb,0x000083d1 + .long 0x52c5060b,0x7a510000,0x00003ffb,0x00008bc8 + .long 0x54456549,0x8b8b0000,0x00003ffb,0x000093be + .long 0x40601762,0x6b0d0000,0x00003ffb,0x00009bb3 + .long 0x078d35ae,0xc2020000,0x00003ffb,0x0000a3a6 + .long 0x9a525ddc,0xe7de0000,0x00003ffb,0x0000ab98 + .long 0xe9436276,0x56190000,0x00003ffb,0x0000b389 + .long 0xe502f9c5,0x98620000,0x00003ffb,0x0000bb79 + .long 0x7e436b09,0xe6fb0000,0x00003ffb,0x0000c367 + .long 0xa5c739e5,0xf4460000,0x00003ffb,0x0000cb54 + .long 0x4c61cff7,0xd5c60000,0x00003ffb,0x0000d33f + .long 0x62f82488,0x533e0000,0x00003ffb,0x0000db28 + .long 0xda816240,0x4c770000,0x00003ffb,0x0000e310 + .long 0xa4078ad3,0x4f180000,0x00003ffb,0x0000eaf6 + .long 0xb0a8188e,0xe1eb0000,0x00003ffb,0x0000f2da + .long 0xf1949dbe,0x79d50000,0x00003ffb,0x0000fabd + .long 0x581361d4,0x7e3e0000,0x00003ffc,0x00008346 + .long 0xac210959,0xecc40000,0x00003ffc,0x00008b23 + .long 0x2a083042,0x82d80000,0x00003ffc,0x000092fb + .long 0x70b8d29a,0xe2f90000,0x00003ffc,0x00009acf + .long 0x476f5ccd,0x1cb40000,0x00003ffc,0x0000a29e + .long 0x76304954,0xf23f0000,0x00003ffc,0x0000aa68 + .long 0xc5d08ab8,0x52300000,0x00003ffc,0x0000b22d + .long 0xfffd9d53,0x9f830000,0x00003ffc,0x0000b9ed + .long 0xef453e90,0x0ea50000,0x00003ffc,0x0000c1a8 + .long 0x5f1cc75e,0x3ea50000,0x00003ffc,0x0000c95d + .long 0x1be82813,0x8de60000,0x00003ffc,0x0000d10b + .long 0xf300840d,0x2de40000,0x00003ffc,0x0000d8b4 + .long 0xb2ba6bc0,0x5e7a0000,0x00003ffc,0x0000e057 + .long 0x2a6bb423,0x35f60000,0x00003ffc,0x0000e7f3 + .long 0x2a70ea9c,0xaa8f0000,0x00003ffc,0x0000ef88 + .long 0x843264ec,0xefaa0000,0x00003ffc,0x0000f717 + .long 0x0a28ecc0,0x66660000,0x00003ffd,0x0000812f + .long 0xd288332d,0xad320000,0x00003ffd,0x000088a8 + .long 0xd1b1218e,0x4d640000,0x00003ffd,0x00009012 + .long 0xab3f23e4,0xaee80000,0x00003ffd,0x0000976c + .long 0xc3d411e7,0xf1b90000,0x00003ffd,0x00009eb6 + .long 0x89493889,0xa2270000,0x00003ffd,0x0000a5ef + .long 0x72c34487,0x361b0000,0x00003ffd,0x0000ad17 + .long 0x00baf07a,0x72270000,0x00003ffd,0x0000b42c + .long 0xbcfafd37,0xefb70000,0x00003ffd,0x0000bb30 + .long 0x3a940ba8,0x0f890000,0x00003ffd,0x0000c221 + .long 0x15c6fcae,0xbbaf0000,0x00003ffd,0x0000c8fe + .long 0xf3e68633,0x12210000,0x00003ffd,0x0000cfc9 + .long 0x8330b400,0x0c700000,0x00003ffd,0x0000d680 + .long 0x7aa1102c,0x5bf90000,0x00003ffd,0x0000dd23 + .long 0x99bc3125,0x2aa30000,0x00003ffd,0x0000e3b2 + .long 0xa8556b8f,0xc5170000,0x00003ffd,0x0000ea2d + .long 0x764f6431,0x59890000,0x00003ffd,0x0000f3bf + .long 0x5bf8bad1,0xa21d0000,0x00003ffe,0x0000801c + .long 0xe39e0d20,0x5c9a0000,0x00003ffe,0x00008630 + .long 0xa2dada1e,0xd0660000,0x00003ffe,0x00008c1a + .long 0xd445f3e0,0x9b8c0000,0x00003ffe,0x000091db + .long 0x8f1664f3,0x50e20000,0x00003ffe,0x00009773 + .long 0x1420365e,0x538c0000,0x00003ffe,0x00009ce1 + .long 0xc8e6a0b8,0xcdba0000,0x00003ffe,0x0000a228 + .long 0x32dbcada,0xae090000,0x00003ffe,0x0000a746 + .long 0xf2ddb760,0x22940000,0x00003ffe,0x0000ac3e + .long 0xc0fb997d,0xd6a20000,0x00003ffe,0x0000b110 + .long 0x688aebdc,0x6f6a0000,0x00003ffe,0x0000b5bc + .long 0xc49059ec,0xc4b00000,0x00003ffe,0x0000ba44 + .long 0xbc7dd470,0x782f0000,0x00003ffe,0x0000bea9 + .long 0x4144fd04,0x9aac0000,0x00003ffe,0x0000c2eb + .long 0x4abb6616,0x28b60000,0x00003ffe,0x0000c70b + .long 0xd54ce602,0xee140000,0x00003ffe,0x0000cd00 + .long 0x0549adec,0x71590000,0x00003ffe,0x0000d484 + .long 0x57d2d8ea,0x4ea30000,0x00003ffe,0x0000db94 + .long 0x8da712de,0xce3b0000,0x00003ffe,0x0000e238 + .long 0x55f969e8,0x096a0000,0x00003ffe,0x0000e877 + .long 0x1129c435,0x32590000,0x00003ffe,0x0000ee57 + .long 0xc16e0d37,0x9c0d0000,0x00003ffe,0x0000f3e1 + .long 0x0211a87c,0x37790000,0x00003ffe,0x0000f919 + .long 0x039d758b,0x8d410000,0x00003ffe,0x0000fe05 + .long 0x8b8f6493,0x5fb30000,0x00003fff,0x00008155 + .long 0xfb497b68,0x5d040000,0x00003fff,0x00008388 + .long 0x9e3549d1,0x08e10000,0x00003fff,0x0000859c + .long 0xfa76511d,0x724b0000,0x00003fff,0x00008795 + .long 0x2ecfff81,0x31e70000,0x00003fff,0x00008973 + .long 0x2fd19557,0x641b0000,0x00003fff,0x00008b38 + .long 0xcad10193,0x2a350000,0x00003fff,0x00008ce7 + .long 0xa8d8301e,0xe6b50000,0x00003fff,0x00008f46 + .long 0xa39e2eae,0x52810000,0x00003fff,0x0000922d + .long 0xa7d79188,0x84870000,0x00003fff,0x000094d1 + .long 0x9fcbdedf,0x52410000,0x00003fff,0x0000973a + .long 0xb94419d2,0xa08b0000,0x00003fff,0x0000996f + .long 0xf00e08e1,0x0b960000,0x00003fff,0x00009b77 + .long 0x3f951232,0x1da70000,0x00003fff,0x00009d55 + .long 0xcc320f93,0x56240000,0x00003fff,0x00009f10 + .long 0x0575006c,0xc5710000,0x00003fff,0x0000a0a9 + .long 0xc290d97c,0xc06c0000,0x00003fff,0x0000a226 + .long 0x59ebebc0,0x630a0000,0x00003fff,0x0000a388 + .long 0xb4aff6ef,0x0ec90000,0x00003fff,0x0000a4d3 + .long 0x5f1061d2,0x92c40000,0x00003fff,0x0000a608 + .long 0x95dcfbe3,0x187e0000,0x00003fff,0x0000a72a + .long 0x51dc7367,0xbeac0000,0x00003fff,0x0000a83a + .long 0x51530956,0x168f0000,0x00003fff,0x0000a93a + .long 0x20077539,0x546e0000,0x00003fff,0x0000aa9e + .long 0x7245023b,0x26050000,0x00003fff,0x0000ac4c + .long 0x84ba6fe4,0xd58f0000,0x00003fff,0x0000adce + .long 0x4a4a606b,0x97120000,0x00003fff,0x0000af2a + .long 0x2dcd8d26,0x3c9c0000,0x00003fff,0x0000b065 + .long 0x6f81f222,0x65c70000,0x00003fff,0x0000b184 + .long 0x65150f71,0x496a0000,0x00003fff,0x0000b28a + .long 0xaa156f9a,0xda350000,0x00003fff,0x0000b37b + .long 0x44ff3766,0xb8950000,0x00003fff,0x0000b458 + .long 0xc3dce963,0x04330000,0x00003fff,0x0000b525 + .long 0x529d5622,0x46bd0000,0x00003fff,0x0000b5e2 + .long 0xcca95f9d,0x88cc0000,0x00003fff,0x0000b692 + .long 0xcada7aca,0x1ada0000,0x00003fff,0x0000b736 + .long 0xaea7a692,0x58380000,0x00003fff,0x0000b7cf + .long 0xab287e9f,0x7b360000,0x00003fff,0x0000b85e + .long 0xcc66cb21,0x98350000,0x00003fff,0x0000b8e4 + .long 0xfd5a20a5,0x93da0000,0x00003fff,0x0000b99f + .long 0x41f64aff,0x9bb50000,0x00003fff,0x0000ba7f + .long 0x1e17842b,0xbe7b0000,0x00003fff,0x0000bb47 + .long 0x12857637,0xe17d0000,0x00003fff,0x0000bbfa + .long 0xbe8a4788,0xdf6f0000,0x00003fff,0x0000bc9d + .long 0x0fad2b68,0x9d790000,0x00003fff,0x0000bd30 + .long 0x6a39471e,0xcd860000,0x00003fff,0x0000bdb6 + .long 0xc731856a,0xf18a0000,0x00003fff,0x0000be31 + .long 0xcac502e8,0x0d700000,0x00003fff,0x0000bea2 + .long 0xd55ce331,0x94e20000,0x00003fff,0x0000bf0b + .long 0x10b7c031,0x28f00000,0x00003fff,0x0000bf6b + .long 0x7a18dacb,0x778d0000,0x00003fff,0x0000bfc4 + .long 0xea4663fa,0x18f60000,0x00003fff,0x0000c018 + .long 0x1bde8b89,0xa4540000,0x00003fff,0x0000c065 + .long 0xb066cfbf,0x64390000,0x00003fff,0x0000c0ae + .long 0x345f5634,0x0ae60000,0x00003fff,0x0000c0f2 + .long 0x22919cb9,0xe6a70000,0x0000f210,0x48002210 + .long 0x32280004,0xf22e6800,0xff840281,0x7fffffff + .long 0x0c813ffb,0x80006c04,0x600000d0,0x0c814002 + .long 0xffff6f04,0x6000014c,0x02aef800,0x0000ff88 + .long 0x00ae0400,0x0000ff88,0x2d7c0000,0x0000ff8c + .long 0xf2000080,0xf22e48a3,0xff84f22e,0x4828ff84 + .long 0xf23c44a2,0x3f800000,0xf2000420,0x2f022401 + .long 0x02810000,0x78000282,0x7fff0000,0x04823ffb + .long 0x0000e282,0xd282ee81,0x43faf780,0xd3c12d59 + .long 0xff902d59,0xff942d59,0xff98222e,0xff840281 + .long 0x80000000,0x83aeff90,0x241ff227,0xe004f200 + .long 0x0080f200,0x04a3f23a,0x5500f6a0,0xf2000522 + .long 0xf2000523,0xf20000a3,0xf23a5522,0xf696f23a + .long 0x54a3f698,0xf20008a3,0xf2000422,0xf21fd020 + .long 0xf2009000,0xf22e4822,0xff9060ff,0x00002d30 + .long 0x0c813fff,0x80006e00,0x008a0c81,0x3fd78000 + .long 0x6d00006c,0xf227e00c,0xf2000023,0xf2000080 + .long 0xf20004a3,0xf23a5500,0xf65af23a,0x5580f65c + .long 0xf2000523,0xf20005a3,0xf23a5522,0xf656f23a + .long 0x55a2f658,0xf2000523,0xf2000ca3,0xf23a5522 + .long 0xf652f23a,0x54a2f654,0xf2000123,0xf22e4823 + .long 0xff84f200,0x08a2f200,0x0423f21f,0xd030f200 + .long 0x9000f22e,0x4822ff84,0x60ff0000,0x2cb2f200 + .long 0x9000123c,0x0003f22e,0x4800ff84,0x60ff0000 + .long 0x2c900c81,0x40638000,0x6e00008e,0xf227e00c + .long 0xf23c4480,0xbf800000,0xf20000a0,0xf2000400 + .long 0xf2000023,0xf22e6880,0xff84f200,0x0080f200 + .long 0x04a3f23a,0x5580f5ec,0xf23a5500,0xf5eef200 + .long 0x05a3f200,0x0523f23a,0x55a2f5e8,0xf23a5522 + .long 0xf5eaf200,0x0ca3f200,0x0123f23a,0x54a2f5e4 + .long 0xf22e4823,0xff84f200,0x08a2f200,0x0423f22e + .long 0x4822ff84,0xf21fd030,0xf2009000,0x4a106a0c + .long 0xf23a4822,0xf5d660ff,0x00002c24,0xf23a4822 + .long 0xf5ba60ff,0x00002c10,0x4a106a16,0xf23a4800 + .long 0xf5baf200,0x9000f23a,0x4822f5c0,0x60ff0000 + .long 0x2bfef23a,0x4800f594,0xf2009000,0xf23a4822 + .long 0xf5ba60ff,0x00002be0,0x60ff0000,0x2a66f210 + .long 0x48002210,0x32280004,0x02817fff,0xffff0c81 + .long 0x3fff8000,0x6c4e0c81,0x3fd78000,0x6d00007c + .long 0xf23c4480,0x3f800000,0xf20000a8,0xf227e004 + .long 0xf23c4500,0x3f800000,0xf2000122,0xf20008a3 + .long 0xf21fd020,0xf2000484,0xf2000420,0xf227e001 + .long 0x41d761ff,0xfffffd66,0xdffc0000,0x000c60ff + .long 0x00002b6c,0xf2000018,0xf23c4438,0x3f800000 + .long 0xf2d20000,0x29d4f23a,0x4800c5a6,0x22100281 + .long 0x80000000,0x00813f80,0x00002f01,0xf2009000 + .long 0xf21f4423,0x60ff0000,0x2b36f200,0x9000123c + .long 0x0003f210,0x480060ff,0x00002b16,0x60ff0000 + .long 0x29b2f210,0x48002210,0x32280004,0x02817fff + .long 0xffff0c81,0x3fff8000,0x6c44f23c,0x44803f80 + .long 0x0000f200,0x00a2f200,0x001af23c,0x44223f80 + .long 0x0000f200,0x0420f200,0x00042f00,0x4280f227 + .long 0xe00141d7,0x61ffffff,0xfcc4dffc,0x0000000c + .long 0xf21f9000,0xf2000022,0x60ff0000,0x2acaf200 + .long 0x0018f23c,0x44383f80,0x0000f2d2,0x0000292a + .long 0x4a106a18,0xf23a4800,0xc4e8f200,0x9000f23c + .long 0x44220080,0x000060ff,0x00002a9c,0x60ff0000 + .long 0x2ce8f200,0x9000f23a,0x4800c4d6,0x60ff0000 + .long 0x2a863fdc,0x000082e3,0x08654361,0xc4c60000 + .long 0x00003fa5,0x55555555,0x4cc13fc5,0x55555555 + .long 0x4a543f81,0x11111117,0x43853fa5,0x55555555 + .long 0x4f5a3fc5,0x55555555,0x55550000,0x00000000 + .long 0x00003ec7,0x1de3a577,0x46823efa,0x01a019d7 + .long 0xcb683f2a,0x01a01a01,0x9df33f56,0xc16c16c1 + .long 0x70e23f81,0x11111111,0x11113fa5,0x55555555 + .long 0x55553ffc,0x0000aaaa,0xaaaaaaaa,0xaaab0000 + .long 0x000048b0,0x00000000,0x00003730,0x00000000 + .long 0x00003fff,0x00008000,0x00000000,0x00000000 + .long 0x00003fff,0x00008164,0xd1f3bc03,0x07749f84 + .long 0x1a9b3fff,0x000082cd,0x8698ac2b,0xa1d89fc1 + .long 0xd5b93fff,0x0000843a,0x28c3acde,0x4048a072 + .long 0x83693fff,0x000085aa,0xc367cc48,0x7b141fc5 + .long 0xc95c3fff,0x0000871f,0x61969e8d,0x10101ee8 + .long 0x5c9f3fff,0x00008898,0x0e8092da,0x85289fa2 + .long 0x07293fff,0x00008a14,0xd575496e,0xfd9ca07b + .long 0xf9af3fff,0x00008b95,0xc1e3ea8b,0xd6e8a002 + .long 0x0dcf3fff,0x00008d1a,0xdf5b7e5b,0xa9e4205a + .long 0x63da3fff,0x00008ea4,0x398b45cd,0x53c01eb7 + .long 0x00513fff,0x00009031,0xdc431466,0xb1dc1f6e + .long 0xb0293fff,0x000091c3,0xd373ab11,0xc338a078 + .long 0x14943fff,0x0000935a,0x2b2f13e6,0xe92c9eb3 + .long 0x19b03fff,0x000094f4,0xefa8fef7,0x09602017 + .long 0x457d3fff,0x00009694,0x2d372018,0x5a001f11 + .long 0xd5373fff,0x00009837,0xf0518db8,0xa9709fb9 + .long 0x52dd3fff,0x000099e0,0x459320b7,0xfa641fe4 + .long 0x30873fff,0x00009b8d,0x39b9d54e,0x55381fa2 + .long 0xa8183fff,0x00009d3e,0xd9a72cff,0xb7501fde + .long 0x494d3fff,0x00009ef5,0x326091a1,0x11ac2050 + .long 0x48903fff,0x0000a0b0,0x510fb971,0x4fc4a073 + .long 0x691c3fff,0x0000a270,0x43030c49,0x68181f9b + .long 0x7a053fff,0x0000a435,0x15ae09e6,0x80a0a079 + .long 0x71263fff,0x0000a5fe,0xd6a9b151,0x38eca071 + .long 0xa1403fff,0x0000a7cd,0x93b4e965,0x3568204f + .long 0x62da3fff,0x0000a9a1,0x5ab4ea7c,0x0ef81f28 + .long 0x3c4a3fff,0x0000ab7a,0x39b5a93e,0xd3389f9a + .long 0x7fdc3fff,0x0000ad58,0x3eea42a1,0x4ac8a05b + .long 0x3fac3fff,0x0000af3b,0x78ad690a,0x43741fdf + .long 0x26103fff,0x0000b123,0xf581d2ac,0x25909f70 + .long 0x5f903fff,0x0000b311,0xc412a911,0x2488201f + .long 0x678a3fff,0x0000b504,0xf333f9de,0x64841f32 + .long 0xfb133fff,0x0000b6fd,0x91e328d1,0x77902003 + .long 0x8b303fff,0x0000b8fb,0xaf4762fb,0x9ee8200d + .long 0xc3cc3fff,0x0000baff,0x5ab2133e,0x45fc9f8b + .long 0x2ae63fff,0x0000bd08,0xa39f580c,0x36c0a02b + .long 0xbf703fff,0x0000bf17,0x99b67a73,0x1084a00b + .long 0xf5183fff,0x0000c12c,0x4cca6670,0x9458a041 + .long 0xdd413fff,0x0000c346,0xccda2497,0x64089fdf + .long 0x137b3fff,0x0000c567,0x2a115506,0xdadc201f + .long 0x15683fff,0x0000c78d,0x74c8abb9,0xb15c1fc1 + .long 0x3a2e3fff,0x0000c9b9,0xbd866e2f,0x27a4a03f + .long 0x8f033fff,0x0000cbec,0x14fef272,0x7c5c1ff4 + .long 0x907d3fff,0x0000ce24,0x8c151f84,0x80e49e6e + .long 0x53e43fff,0x0000d063,0x33daef2b,0x25941fd6 + .long 0xd45c3fff,0x0000d2a8,0x1d91f12a,0xe45ca076 + .long 0xedb93fff,0x0000d4f3,0x5aabcfed,0xfa209fa6 + .long 0xde213fff,0x0000d744,0xfccad69d,0x6af41ee6 + .long 0x9a2f3fff,0x0000d99d,0x15c278af,0xd7b4207f + .long 0x439f3fff,0x0000dbfb,0xb797daf2,0x3754201e + .long 0xc2073fff,0x0000de60,0xf4825e0e,0x91249e8b + .long 0xe1753fff,0x0000e0cc,0xdeec2a94,0xe1102003 + .long 0x2c4b3fff,0x0000e33f,0x8972be8a,0x5a502004 + .long 0xdff53fff,0x0000e5b9,0x06e77c83,0x48a81e72 + .long 0xf47a3fff,0x0000e839,0x6a503c4b,0xdc681f72 + .long 0x2f223fff,0x0000eac0,0xc6e7dd24,0x3930a017 + .long 0xe9453fff,0x0000ed4f,0x301ed994,0x2b841f40 + .long 0x1a5b3fff,0x0000efe4,0xb99bdcda,0xf5cc9fb9 + .long 0xa9e33fff,0x0000f281,0x773c59ff,0xb1382074 + .long 0x4c053fff,0x0000f525,0x7d152486,0xcc2c1f77 + .long 0x3a193fff,0x0000f7d0,0xdf730ad1,0x3bb81ffe + .long 0x90d53fff,0x0000fa83,0xb2db722a,0x033ca041 + .long 0xed223fff,0x0000fd3e,0x0c0cf486,0xc1741f85 + .long 0x3f3a2210,0x02817fff,0x00000c81,0x3fbe0000 + .long 0x6c0660ff,0x00000108,0x32280004,0x0c81400c + .long 0xb1676d06,0x60ff0000,0x010cf210,0x4800f200 + .long 0x0080f23c,0x442342b8,0xaa3bf227,0xe00c2d7c + .long 0x00000000,0xff58f201,0x600043fa,0xfbb6f201 + .long 0x40002d41,0xff540281,0x0000003f,0xe989d3c1 + .long 0x222eff54,0xec810641,0x3fff3d7a,0xfb06ff54 + .long 0xf2000100,0xf23c4423,0xbc317218,0xf23a4923 + .long 0xfaf2f200,0x0422f200,0x0822f200,0x0080f200 + .long 0x04a3f23c,0x45003ab6,0x0b70f200,0x0523f200 + .long 0x0580f23c,0x45a33c08,0x8895f23a,0x5522fad4 + .long 0xf23a55a2,0xfad6f200,0x05233d41,0xff842d7c + .long 0x80000000,0xff8842ae,0xff8cf200,0x05a3f23c + .long 0x45223f00,0x0000f200,0x01a3f200,0x0523f200 + .long 0x0c22f219,0x4880f200,0x0822f200,0x0423f21f + .long 0xd030f211,0x4422f200,0x0422222e,0xff584a81 + .long 0x6706f22e,0x4823ff90,0xf2009000,0x123c0000 + .long 0xf22e4823,0xff8460ff,0x000024c6,0xf210d080 + .long 0xf2009000,0xf23c4422,0x3f800000,0x60ff0000 + .long 0x24c60c81,0x400cb27c,0x6e66f210,0x4800f200 + .long 0x0080f23c,0x442342b8,0xaa3bf227,0xe00c2d7c + .long 0x00000001,0xff58f201,0x600043fa,0xfaa6f201 + .long 0x40002d41,0xff540281,0x0000003f,0xe989d3c1 + .long 0x222eff54,0xec812d41,0xff54e281,0x93aeff54 + .long 0x06413fff,0x3d41ff90,0x2d7c8000,0x0000ff94 + .long 0x42aeff98,0x222eff54,0x06413fff,0x6000fed2 + .long 0x4a106bff,0x00002370,0x60ff0000,0x24122f10 + .long 0x02978000,0x00000097,0x00800000,0xf23c4400 + .long 0x3f800000,0xf2009000,0xf21f4422,0x60ff0000 + .long 0x24262210,0x02817fff,0x00000c81,0x3ffd0000 + .long 0x6c0660ff,0x0000015e,0x32280004,0x0c814004 + .long 0xc2156f06,0x60ff0000,0x026cf210,0x4800f200 + .long 0x0080f23c,0x442342b8,0xaa3bf227,0xe00cf201 + .long 0x600043fa,0xf9eef201,0x40002d41,0xff540281 + .long 0x0000003f,0xe989d3c1,0x222eff54,0xec812d41 + .long 0xff54f200,0x0100f23c,0x4423bc31,0x7218f23a + .long 0x4923f930,0xf2000422,0xf2000822,0x06413fff + .long 0xf2000080,0xf20004a3,0xf23c4500,0x3950097b + .long 0xf2000523,0xf2000580,0xf23c45a3,0x3ab60b6a + .long 0xf23a5522,0xf91ef23a,0x55a2f920,0x3d41ff84 + .long 0x2d7c8000,0x0000ff88,0x42aeff8c,0xf2000523 + .long 0x222eff54,0x4441f200,0x05a30641,0x3ffff23a + .long 0x5522f900,0xf23c45a2,0x3f000000,0xf2000523 + .long 0x00418000,0x3d41ff90,0x2d7c8000,0x0000ff94 + .long 0x42aeff98,0xf2000ca3,0xf2000123,0xf2000422 + .long 0xf2000822,0xf21fd030,0xf2114823,0x222eff54 + .long 0x0c810000,0x003f6f1a,0xf2294480,0x000cf22e + .long 0x48a2ff90,0xf2000422,0xf2114822,0x60ff0000 + .long 0x00340c81,0xfffffffd,0x6c16f229,0x4422000c + .long 0xf2114822,0xf22e4822,0xff9060ff,0x00000016 + .long 0xf2194880,0xf2114422,0xf22e48a2,0xff90f200 + .long 0x0422f200,0x9000f22e,0x4823ff84,0x60ff0000 + .long 0x22ae0c81,0x3fbe0000,0x6c6c0c81,0x00330000 + .long 0x6d2c2d7c,0x80010000,0xff842d7c,0x80000000 + .long 0xff8842ae,0xff8cf210,0x4800f200,0x9000123c + .long 0x0002f22e,0x4822ff84,0x60ff0000,0x2264f210 + .long 0x4800f23a,0x5423f86c,0x2d7c8001,0x0000ff84 + .long 0x2d7c8000,0x0000ff88,0x42aeff8c,0xf22e4822 + .long 0xff84f200,0x9000123c,0x0000f23a,0x5423f84c + .long 0x60ff0000,0x222cf210,0x4800f200,0x0023f227 + .long 0xe00cf23c,0x44802f30,0xcaa8f200,0x00a3f23c + .long 0x4500310f,0x8290f23c,0x44a232d7,0x3220f200 + .long 0x0123f200,0x00a3f23c,0x45223493,0xf281f23a + .long 0x54a2f7c0,0xf2000123,0xf20000a3,0xf23a5522 + .long 0xf7baf23a,0x54a2f7bc,0xf2000123,0xf20000a3 + .long 0xf23a5522,0xf7b6f23a,0x54a2f7b8,0xf2000123 + .long 0xf20000a3,0xf23a5522,0xf7b2f23a,0x48a2f7b4 + .long 0xf2000123,0xf20000a3,0xf2000123,0xf21048a3 + .long 0xf23c4423,0x3f000000,0xf20008a2,0xf21fd030 + .long 0xf2000422,0xf2009000,0xf2104822,0x60ff0000 + .long 0x218e2210,0x0c810000,0x00006e00,0xfbacf23c + .long 0x4400bf80,0x0000f200,0x9000f23c,0x44220080 + .long 0x000060ff,0x00002178,0x60ff0000,0x1ff63028 + .long 0x00000880,0x000f0440,0x3ffff200,0x50006d02 + .long 0x4e751d7c,0x0008ff64,0x4e7561ff,0x00007cfc + .long 0x44400440,0x3ffff200,0x50001d7c,0x0008ff64 + .long 0x4e753028,0x00000040,0x7fff0880,0x000e2d68 + .long 0x0004ff88,0x2d680008,0xff8c3d40,0xff84f22e + .long 0x4800ff84,0x6b024e75,0x1d7c0008,0xff644e75 + .long 0x61ff0000,0x7cb660ca,0x7ffb0000,0x80000000 + .long 0x00000000,0x00000000,0xf2104800,0x22103228 + .long 0x00040281,0x7fffffff,0x0c81400c,0xb1676e42 + .long 0xf2000018,0x2f004280,0xf227e001,0x41d761ff + .long 0xfffffad2,0xdffc0000,0x000cf23c,0x44233f00 + .long 0x0000201f,0xf23c4480,0x3e800000,0xf20000a0 + .long 0xf2009000,0x123c0002,0xf2000422,0x60ff0000 + .long 0x20800c81,0x400cb2b3,0x6e3cf200,0x0018f23a + .long 0x5428baae,0xf23a5428,0xbab02f00,0x4280f227 + .long 0xe00141d7,0x61ffffff,0xfa7cdffc,0x0000000c + .long 0x201ff200,0x9000123c,0x0000f23a,0x4823ff5a + .long 0x60ff0000,0x203c60ff,0x00002014,0xf23c4400 + .long 0x3f800000,0xf2009000,0xf23c4422,0x00800000 + .long 0x60ff0000,0x2032f210,0x48002210,0x32280004 + .long 0x22410281,0x7fffffff,0x0c81400c,0xb1676e62 + .long 0xf2000018,0x48e78040,0xf227e001,0x41d74280 + .long 0x61ffffff,0xfbe0dffc,0x0000000c,0xf23c9000 + .long 0x00000000,0x4cdf0201,0xf2000080,0xf23c44a2 + .long 0x3f800000,0xf2276800,0xf2000420,0x22090281 + .long 0x80000000,0x00813f00,0x0000f21f,0x48222f01 + .long 0xf2009000,0x123c0000,0xf21f4423,0x60ff0000 + .long 0x1fa00c81,0x400cb2b3,0x6eff0000,0x1f4cf200 + .long 0x0018f23a,0x5428b9ca,0x2f3c0000,0x00002f3c + .long 0x80000000,0x22090281,0x80000000,0x00817ffb + .long 0x00002f01,0xf23a5428,0xb9b02f00,0x4280f227 + .long 0xe00141d7,0x61ffffff,0xf97cdffc,0x0000000c + .long 0x201ff200,0x9000123c,0x0000f21f,0x482360ff + .long 0x00001f3e,0x60ff0000,0x1ddaf210,0x4800f22e + .long 0x6800ff84,0x22103228,0x00042d41,0xff840281 + .long 0x7fffffff,0x0c813fd7,0x80006d00,0x00740c81 + .long 0x3fffddce,0x6e00006a,0x222eff84,0x2d41ff5c + .long 0x02817fff,0x00000681,0x00010000,0x2d41ff84 + .long 0x02ae8000,0x0000ff5c,0xf22e4800,0xff842f00 + .long 0x4280f227,0xe00141d7,0x61ffffff,0xfac8dffc + .long 0x0000000c,0x201ff200,0x0080f23c,0x44a24000 + .long 0x0000222e,0xff5cf22e,0x6880ff84,0xb3aeff84 + .long 0xf2009000,0xf22e4820,0xff8460ff,0x00001eb0 + .long 0x0c813fff,0x80006d00,0x00880c81,0x40048aa1 + .long 0x6e000092,0x222eff84,0x2d41ff5c,0x02817fff + .long 0x00000681,0x00010000,0x2d41ff84,0x02ae8000 + .long 0x0000ff5c,0x222eff5c,0xf22e4800,0xff842f00 + .long 0x4280f227,0xe00141d7,0x61ffffff,0xf878dffc + .long 0x0000000c,0x201f222e,0xff5cf23c,0x44223f80 + .long 0x00000a81,0xc0000000,0xf2014480,0xf20000a0 + .long 0x222eff5c,0x00813f80,0x0000f201,0x4400f200 + .long 0x9000123c,0x0002f200,0x042260ff,0x00001e20 + .long 0xf2009000,0x123c0003,0xf22e4800,0xff8460ff + .long 0x00001dfe,0x222eff84,0x02818000,0x00000081 + .long 0x3f800000,0xf2014400,0x02818000,0x00000a81 + .long 0x80800000,0xf2009000,0xf2014422,0x60ff0000 + .long 0x1dde60ff,0x00001c6c,0x3ffe0000,0xb17217f7 + .long 0xd1cf79ac,0x00000000,0x3f800000,0x00000000 + .long 0x7f800000,0xbf800000,0x3fc2499a,0xb5e4040b + .long 0xbfc555b5,0x848cb7db,0x3fc99999,0x987d8730 + .long 0xbfcfffff,0xff6f7e97,0x3fd55555,0x555555a4 + .long 0xbfe00000,0x00000008,0x3f175496,0xadd7dad6 + .long 0x3f3c71c2,0xfe80c7e0,0x3f624924,0x928bccff + .long 0x3f899999,0x999995ec,0x3fb55555,0x55555555 + .long 0x40000000,0x00000000,0x3f990000,0x80000000 + .long 0x00000000,0x00000000,0x3ffe0000,0xfe03f80f + .long 0xe03f80fe,0x00000000,0x3ff70000,0xff015358 + .long 0x833c47e2,0x00000000,0x3ffe0000,0xfa232cf2 + .long 0x52138ac0,0x00000000,0x3ff90000,0xbdc8d83e + .long 0xad88d549,0x00000000,0x3ffe0000,0xf6603d98 + .long 0x0f6603da,0x00000000,0x3ffa0000,0x9cf43dcf + .long 0xf5eafd48,0x00000000,0x3ffe0000,0xf2b9d648 + .long 0x0f2b9d65,0x00000000,0x3ffa0000,0xda16eb88 + .long 0xcb8df614,0x00000000,0x3ffe0000,0xef2eb71f + .long 0xc4345238,0x00000000,0x3ffb0000,0x8b29b775 + .long 0x1bd70743,0x00000000,0x3ffe0000,0xebbdb2a5 + .long 0xc1619c8c,0x00000000,0x3ffb0000,0xa8d839f8 + .long 0x30c1fb49,0x00000000,0x3ffe0000,0xe865ac7b + .long 0x7603a197,0x00000000,0x3ffb0000,0xc61a2eb1 + .long 0x8cd907ad,0x00000000,0x3ffe0000,0xe525982a + .long 0xf70c880e,0x00000000,0x3ffb0000,0xe2f2a47a + .long 0xde3a18af,0x00000000,0x3ffe0000,0xe1fc780e + .long 0x1fc780e2,0x00000000,0x3ffb0000,0xff64898e + .long 0xdf55d551,0x00000000,0x3ffe0000,0xdee95c4c + .long 0xa037ba57,0x00000000,0x3ffc0000,0x8db956a9 + .long 0x7b3d0148,0x00000000,0x3ffe0000,0xdbeb61ee + .long 0xd19c5958,0x00000000,0x3ffc0000,0x9b8fe100 + .long 0xf47ba1de,0x00000000,0x3ffe0000,0xd901b203 + .long 0x6406c80e,0x00000000,0x3ffc0000,0xa9372f1d + .long 0x0da1bd17,0x00000000,0x3ffe0000,0xd62b80d6 + .long 0x2b80d62c,0x00000000,0x3ffc0000,0xb6b07f38 + .long 0xce90e46b,0x00000000,0x3ffe0000,0xd3680d36 + .long 0x80d3680d,0x00000000,0x3ffc0000,0xc3fd0329 + .long 0x06488481,0x00000000,0x3ffe0000,0xd0b69fcb + .long 0xd2580d0b,0x00000000,0x3ffc0000,0xd11de0ff + .long 0x15ab18ca,0x00000000,0x3ffe0000,0xce168a77 + .long 0x25080ce1,0x00000000,0x3ffc0000,0xde1433a1 + .long 0x6c66b150,0x00000000,0x3ffe0000,0xcb8727c0 + .long 0x65c393e0,0x00000000,0x3ffc0000,0xeae10b5a + .long 0x7ddc8add,0x00000000,0x3ffe0000,0xc907da4e + .long 0x871146ad,0x00000000,0x3ffc0000,0xf7856e5e + .long 0xe2c9b291,0x00000000,0x3ffe0000,0xc6980c69 + .long 0x80c6980c,0x00000000,0x3ffd0000,0x82012ca5 + .long 0xa68206d7,0x00000000,0x3ffe0000,0xc4372f85 + .long 0x5d824ca6,0x00000000,0x3ffd0000,0x882c5fcd + .long 0x7256a8c5,0x00000000,0x3ffe0000,0xc1e4bbd5 + .long 0x95f6e947,0x00000000,0x3ffd0000,0x8e44c60b + .long 0x4ccfd7de,0x00000000,0x3ffe0000,0xbfa02fe8 + .long 0x0bfa02ff,0x00000000,0x3ffd0000,0x944ad09e + .long 0xf4351af6,0x00000000,0x3ffe0000,0xbd691047 + .long 0x07661aa3,0x00000000,0x3ffd0000,0x9a3eecd4 + .long 0xc3eaa6b2,0x00000000,0x3ffe0000,0xbb3ee721 + .long 0xa54d880c,0x00000000,0x3ffd0000,0xa0218434 + .long 0x353f1de8,0x00000000,0x3ffe0000,0xb92143fa + .long 0x36f5e02e,0x00000000,0x3ffd0000,0xa5f2fcab + .long 0xbbc506da,0x00000000,0x3ffe0000,0xb70fbb5a + .long 0x19be3659,0x00000000,0x3ffd0000,0xabb3b8ba + .long 0x2ad362a5,0x00000000,0x3ffe0000,0xb509e68a + .long 0x9b94821f,0x00000000,0x3ffd0000,0xb1641795 + .long 0xce3ca97b,0x00000000,0x3ffe0000,0xb30f6352 + .long 0x8917c80b,0x00000000,0x3ffd0000,0xb7047551 + .long 0x5d0f1c61,0x00000000,0x3ffe0000,0xb11fd3b8 + .long 0x0b11fd3c,0x00000000,0x3ffd0000,0xbc952afe + .long 0xea3d13e1,0x00000000,0x3ffe0000,0xaf3addc6 + .long 0x80af3ade,0x00000000,0x3ffd0000,0xc2168ed0 + .long 0xf458ba4a,0x00000000,0x3ffe0000,0xad602b58 + .long 0x0ad602b6,0x00000000,0x3ffd0000,0xc788f439 + .long 0xb3163bf1,0x00000000,0x3ffe0000,0xab8f69e2 + .long 0x8359cd11,0x00000000,0x3ffd0000,0xccecac08 + .long 0xbf04565d,0x00000000,0x3ffe0000,0xa9c84a47 + .long 0xa07f5638,0x00000000,0x3ffd0000,0xd2420487 + .long 0x2dd85160,0x00000000,0x3ffe0000,0xa80a80a8 + .long 0x0a80a80b,0x00000000,0x3ffd0000,0xd7894992 + .long 0x3bc3588a,0x00000000,0x3ffe0000,0xa655c439 + .long 0x2d7b73a8,0x00000000,0x3ffd0000,0xdcc2c4b4 + .long 0x9887dacc,0x00000000,0x3ffe0000,0xa4a9cf1d + .long 0x96833751,0x00000000,0x3ffd0000,0xe1eebd3e + .long 0x6d6a6b9e,0x00000000,0x3ffe0000,0xa3065e3f + .long 0xae7cd0e0,0x00000000,0x3ffd0000,0xe70d785c + .long 0x2f9f5bdc,0x00000000,0x3ffe0000,0xa16b312e + .long 0xa8fc377d,0x00000000,0x3ffd0000,0xec1f392c + .long 0x5179f283,0x00000000,0x3ffe0000,0x9fd809fd + .long 0x809fd80a,0x00000000,0x3ffd0000,0xf12440d3 + .long 0xe36130e6,0x00000000,0x3ffe0000,0x9e4cad23 + .long 0xdd5f3a20,0x00000000,0x3ffd0000,0xf61cce92 + .long 0x346600bb,0x00000000,0x3ffe0000,0x9cc8e160 + .long 0xc3fb19b9,0x00000000,0x3ffd0000,0xfb091fd3 + .long 0x8145630a,0x00000000,0x3ffe0000,0x9b4c6f9e + .long 0xf03a3caa,0x00000000,0x3ffd0000,0xffe97042 + .long 0xbfa4c2ad,0x00000000,0x3ffe0000,0x99d722da + .long 0xbde58f06,0x00000000,0x3ffe0000,0x825efced + .long 0x49369330,0x00000000,0x3ffe0000,0x9868c809 + .long 0x868c8098,0x00000000,0x3ffe0000,0x84c37a7a + .long 0xb9a905c9,0x00000000,0x3ffe0000,0x97012e02 + .long 0x5c04b809,0x00000000,0x3ffe0000,0x87224c2e + .long 0x8e645fb7,0x00000000,0x3ffe0000,0x95a02568 + .long 0x095a0257,0x00000000,0x3ffe0000,0x897b8cac + .long 0x9f7de298,0x00000000,0x3ffe0000,0x94458094 + .long 0x45809446,0x00000000,0x3ffe0000,0x8bcf55de + .long 0xc4cd05fe,0x00000000,0x3ffe0000,0x92f11384 + .long 0x0497889c,0x00000000,0x3ffe0000,0x8e1dc0fb + .long 0x89e125e5,0x00000000,0x3ffe0000,0x91a2b3c4 + .long 0xd5e6f809,0x00000000,0x3ffe0000,0x9066e68c + .long 0x955b6c9b,0x00000000,0x3ffe0000,0x905a3863 + .long 0x3e06c43b,0x00000000,0x3ffe0000,0x92aade74 + .long 0xc7be59e0,0x00000000,0x3ffe0000,0x8f1779d9 + .long 0xfdc3a219,0x00000000,0x3ffe0000,0x94e9bff6 + .long 0x15845643,0x00000000,0x3ffe0000,0x8dda5202 + .long 0x37694809,0x00000000,0x3ffe0000,0x9723a1b7 + .long 0x20134203,0x00000000,0x3ffe0000,0x8ca29c04 + .long 0x6514e023,0x00000000,0x3ffe0000,0x995899c8 + .long 0x90eb8990,0x00000000,0x3ffe0000,0x8b70344a + .long 0x139bc75a,0x00000000,0x3ffe0000,0x9b88bdaa + .long 0x3a3dae2f,0x00000000,0x3ffe0000,0x8a42f870 + .long 0x5669db46,0x00000000,0x3ffe0000,0x9db4224f + .long 0xffe1157c,0x00000000,0x3ffe0000,0x891ac73a + .long 0xe9819b50,0x00000000,0x3ffe0000,0x9fdadc26 + .long 0x8b7a12da,0x00000000,0x3ffe0000,0x87f78087 + .long 0xf78087f8,0x00000000,0x3ffe0000,0xa1fcff17 + .long 0xce733bd4,0x00000000,0x3ffe0000,0x86d90544 + .long 0x7a34acc6,0x00000000,0x3ffe0000,0xa41a9e8f + .long 0x5446fb9f,0x00000000,0x3ffe0000,0x85bf3761 + .long 0x2cee3c9b,0x00000000,0x3ffe0000,0xa633cd7e + .long 0x6771cd8b,0x00000000,0x3ffe0000,0x84a9f9c8 + .long 0x084a9f9d,0x00000000,0x3ffe0000,0xa8489e60 + .long 0x0b435a5e,0x00000000,0x3ffe0000,0x83993052 + .long 0x3fbe3368,0x00000000,0x3ffe0000,0xaa59233c + .long 0xcca4bd49,0x00000000,0x3ffe0000,0x828cbfbe + .long 0xb9a020a3,0x00000000,0x3ffe0000,0xac656dae + .long 0x6bcc4985,0x00000000,0x3ffe0000,0x81848da8 + .long 0xfaf0d277,0x00000000,0x3ffe0000,0xae6d8ee3 + .long 0x60bb2468,0x00000000,0x3ffe0000,0x80808080 + .long 0x80808081,0x00000000,0x3ffe0000,0xb07197a2 + .long 0x3c46c654,0x00000000,0xf2104800,0x2d7c0000 + .long 0x0000ff54,0x22103228,0x00042d50,0xff842d68 + .long 0x0004ff88,0x2d680008,0xff8c0c81,0x00000000 + .long 0x6d000182,0x0c813ffe,0xf07d6d0a,0x0c813fff + .long 0x88416f00,0x00e2e081,0xe0810481,0x00003fff + .long 0xd2aeff54,0x41faf7b2,0xf2014080,0x2d7c3fff + .long 0x0000ff84,0x2d6eff88,0xff9402ae,0xfe000000 + .long 0xff9400ae,0x01000000,0xff94222e,0xff940281 + .long 0x7e000000,0xe081e081,0xe881d1c1,0xf22e4800 + .long 0xff842d7c,0x3fff0000,0xff9042ae,0xff98f22e + .long 0x4828ff90,0xf227e00c,0xf2104823,0xf23a48a3 + .long 0xf6c8f200,0x0100f200,0x0923f22e,0x6880ff84 + .long 0xf2000980,0xf2000880,0xf23a54a3,0xf6ccf23a + .long 0x5523f6ce,0xf23a54a2,0xf6d0f23a,0x5522f6d2 + .long 0xf2000ca3,0xf2000d23,0xf23a54a2,0xf6ccf23a + .long 0x5522f6ce,0xf2000ca3,0xd1fc0000,0x0010f200 + .long 0x0d23f200,0x00a3f200,0x0822f210,0x48a2f21f + .long 0xd030f200,0x0422f200,0x9000f22e,0x4822ff84 + .long 0x60ff0000,0x142af23c,0x58380001,0xf2c10000 + .long 0x1678f200,0x0080f23a,0x44a8f64e,0xf23a4422 + .long 0xf648f200,0x04a2f200,0x00a0f227,0xe00cf200 + .long 0x0400f200,0x0023f22e,0x6880ff84,0xf2000080 + .long 0xf20004a3,0xf23a5580,0xf660f23a,0x5500f662 + .long 0xf20005a3,0xf2000523,0xf23a55a2,0xf65cf23a + .long 0x5522f65e,0xf2000ca3,0xf2000123,0xf23a54a2 + .long 0xf658f22e,0x4823ff84,0xf20008a2,0xf21fd030 + .long 0xf2000423,0xf2009000,0xf22e4822,0xff8460ff + .long 0x0000139c,0x60ff0000,0x12102d7c,0xffffff9c + .long 0xff5448e7,0x3f002610,0x28280004,0x2a280008 + .long 0x42824a84,0x66342805,0x42857420,0x4286edc4 + .long 0x6000edac,0xd4862d43,0xff842d44,0xff882d45 + .long 0xff8c4482,0x2d42ff54,0xf22e4800,0xff844cdf + .long 0x00fc41ee,0xff846000,0xfe0c4286,0xedc46000 + .long 0x2406edac,0x2e05edad,0x44860686,0x00000020 + .long 0xecaf8887,0x2d43ff84,0x2d44ff88,0x2d45ff8c + .long 0x44822d42,0xff54f22e,0x4800ff84,0x4cdf00fc + .long 0x41eeff84,0x6000fdce,0xf2104800,0xf2000018 + .long 0xf23a4838,0xf5a4f292,0x0014f200,0x9000123c + .long 0x0003f210,0x480060ff,0x000012d6,0xf2104800 + .long 0x2d7c0000,0x0000ff54,0xf2000080,0xf23a4422 + .long 0xf508f22e,0x6800ff84,0x3d6eff88,0xff86222e + .long 0xff840c81,0x00000000,0x6f0000da,0x0c813ffe + .long 0x80006d00,0xfda20c81,0x3fffc000,0x6e00fd98 + .long 0x0c813ffe,0xf07d6d00,0x001a0c81,0x3fff8841 + .long 0x6e000010,0xf20004a2,0xf23a4422,0xf4bc6000 + .long 0xfe762d6e,0xff88ff94,0x02aefe00,0x0000ff94 + .long 0x00ae0100,0x0000ff94,0x0c813fff,0x80006c44 + .long 0xf23a4400,0xf4fc2d7c,0x3fff0000,0xff9042ae + .long 0xff98f22e,0x4828ff90,0x222eff94,0x02817e00 + .long 0x0000e081,0xe081e881,0xf20004a2,0xf227e00c + .long 0xf2000422,0x41faf4e2,0xd1c1f23a,0x4480f466 + .long 0x6000fd76,0xf23a4400,0xf4502d7c,0x3fff0000 + .long 0xff9042ae,0xff98f22e,0x4828ff90,0x222eff94 + .long 0x02817e00,0x0000e081,0xe081e881,0xf2000422 + .long 0xf227e00c,0x41faf4a2,0xd1c1f23a,0x4480f41e + .long 0x6000fd36,0x0c810000,0x00006d10,0xf23a4400 + .long 0xf414f200,0x900060ff,0x00001014,0xf23a4400 + .long 0xf3fcf200,0x900060ff,0x0000102e,0x60ff0000 + .long 0x10422210,0x32280004,0x02817fff,0xffff0c81 + .long 0x3fff8000,0x6c56f210,0x4818f200,0x0080f200 + .long 0x049af200,0x0022f23c,0x44a23f80,0x0000f200 + .long 0x04202210,0x02818000,0x00000081,0x3f000000 + .long 0x2f012f00,0x4280f227,0xe00141d7,0x61ffffff + .long 0xfe5adffc,0x0000000c,0x201ff200,0x9000123c + .long 0x0000f21f,0x442360ff,0x00001136,0xf2104818 + .long 0xf23c4438,0x3f800000,0xf2d20000,0x0fac60ff + .long 0x00000f7c,0x60ff0000,0x0fba3ffd,0x0000de5b + .long 0xd8a93728,0x71950000,0x00003fff,0x0000b8aa + .long 0x3b295c17,0xf0bc0000,0x0000f23c,0x58000001 + .long 0xf2104838,0xf2c10000,0x13502210,0x6d000090 + .long 0x2f004280,0x61ffffff,0xfba2f21f,0x9000f23a + .long 0x4823ffb8,0x60ff0000,0x10d62210,0x6d000070 + .long 0x2f004280,0x61ffffff,0xfd34f21f,0x9000f23a + .long 0x4823ff98,0x60ff0000,0x10c62210,0x6d000050 + .long 0x22280008,0x662e2228,0x00040281,0x7fffffff + .long 0x66223210,0x02810000,0x7fff0481,0x00003fff + .long 0x67ff0000,0x12e4f200,0x9000f201,0x400060ff + .long 0x0000107c,0x2f004280,0x61ffffff,0xfb2ef21f + .long 0x9000f23a,0x4823ff54,0x60ff0000,0x106260ff + .long 0x00000ed6,0x22106d00,0xfff62f00,0x428061ff + .long 0xfffffcba,0xf21f9000,0xf23a4823,0xff2e60ff + .long 0x0000104c,0x406a934f,0x0979a371,0x3f734413 + .long 0x509f8000,0xbfcd0000,0xc0219dc1,0xda994fd2 + .long 0x00000000,0x40000000,0x935d8ddd,0xaaa8ac17 + .long 0x00000000,0x3ffe0000,0xb17217f7,0xd1cf79ac + .long 0x00000000,0x3f56c16d,0x6f7bd0b2,0x3f811112 + .long 0x302c712c,0x3fa55555,0x55554cc1,0x3fc55555 + .long 0x55554a54,0x3fe00000,0x00000000,0x00000000 + .long 0x00000000,0x3fff0000,0x80000000,0x00000000 + .long 0x3f738000,0x3fff0000,0x8164d1f3,0xbc030773 + .long 0x3fbef7ca,0x3fff0000,0x82cd8698,0xac2ba1d7 + .long 0x3fbdf8a9,0x3fff0000,0x843a28c3,0xacde4046 + .long 0x3fbcd7c9,0x3fff0000,0x85aac367,0xcc487b15 + .long 0xbfbde8da,0x3fff0000,0x871f6196,0x9e8d1010 + .long 0x3fbde85c,0x3fff0000,0x88980e80,0x92da8527 + .long 0x3fbebbf1,0x3fff0000,0x8a14d575,0x496efd9a + .long 0x3fbb80ca,0x3fff0000,0x8b95c1e3,0xea8bd6e7 + .long 0xbfba8373,0x3fff0000,0x8d1adf5b,0x7e5ba9e6 + .long 0xbfbe9670,0x3fff0000,0x8ea4398b,0x45cd53c0 + .long 0x3fbdb700,0x3fff0000,0x9031dc43,0x1466b1dc + .long 0x3fbeeeb0,0x3fff0000,0x91c3d373,0xab11c336 + .long 0x3fbbfd6d,0x3fff0000,0x935a2b2f,0x13e6e92c + .long 0xbfbdb319,0x3fff0000,0x94f4efa8,0xfef70961 + .long 0x3fbdba2b,0x3fff0000,0x96942d37,0x20185a00 + .long 0x3fbe91d5,0x3fff0000,0x9837f051,0x8db8a96f + .long 0x3fbe8d5a,0x3fff0000,0x99e04593,0x20b7fa65 + .long 0xbfbcde7b,0x3fff0000,0x9b8d39b9,0xd54e5539 + .long 0xbfbebaaf,0x3fff0000,0x9d3ed9a7,0x2cffb751 + .long 0xbfbd86da,0x3fff0000,0x9ef53260,0x91a111ae + .long 0xbfbebedd,0x3fff0000,0xa0b0510f,0xb9714fc2 + .long 0x3fbcc96e,0x3fff0000,0xa2704303,0x0c496819 + .long 0xbfbec90b,0x3fff0000,0xa43515ae,0x09e6809e + .long 0x3fbbd1db,0x3fff0000,0xa5fed6a9,0xb15138ea + .long 0x3fbce5eb,0x3fff0000,0xa7cd93b4,0xe965356a + .long 0xbfbec274,0x3fff0000,0xa9a15ab4,0xea7c0ef8 + .long 0x3fbea83c,0x3fff0000,0xab7a39b5,0xa93ed337 + .long 0x3fbecb00,0x3fff0000,0xad583eea,0x42a14ac6 + .long 0x3fbe9301,0x3fff0000,0xaf3b78ad,0x690a4375 + .long 0xbfbd8367,0x3fff0000,0xb123f581,0xd2ac2590 + .long 0xbfbef05f,0x3fff0000,0xb311c412,0xa9112489 + .long 0x3fbdfb3c,0x3fff0000,0xb504f333,0xf9de6484 + .long 0x3fbeb2fb,0x3fff0000,0xb6fd91e3,0x28d17791 + .long 0x3fbae2cb,0x3fff0000,0xb8fbaf47,0x62fb9ee9 + .long 0x3fbcdc3c,0x3fff0000,0xbaff5ab2,0x133e45fb + .long 0x3fbee9aa,0x3fff0000,0xbd08a39f,0x580c36bf + .long 0xbfbeaefd,0x3fff0000,0xbf1799b6,0x7a731083 + .long 0xbfbcbf51,0x3fff0000,0xc12c4cca,0x66709456 + .long 0x3fbef88a,0x3fff0000,0xc346ccda,0x24976407 + .long 0x3fbd83b2,0x3fff0000,0xc5672a11,0x5506dadd + .long 0x3fbdf8ab,0x3fff0000,0xc78d74c8,0xabb9b15d + .long 0xbfbdfb17,0x3fff0000,0xc9b9bd86,0x6e2f27a3 + .long 0xbfbefe3c,0x3fff0000,0xcbec14fe,0xf2727c5d + .long 0xbfbbb6f8,0x3fff0000,0xce248c15,0x1f8480e4 + .long 0xbfbcee53,0x3fff0000,0xd06333da,0xef2b2595 + .long 0xbfbda4ae,0x3fff0000,0xd2a81d91,0xf12ae45a + .long 0x3fbc9124,0x3fff0000,0xd4f35aab,0xcfedfa1f + .long 0x3fbeb243,0x3fff0000,0xd744fcca,0xd69d6af4 + .long 0x3fbde69a,0x3fff0000,0xd99d15c2,0x78afd7b6 + .long 0xbfb8bc61,0x3fff0000,0xdbfbb797,0xdaf23755 + .long 0x3fbdf610,0x3fff0000,0xde60f482,0x5e0e9124 + .long 0xbfbd8be1,0x3fff0000,0xe0ccdeec,0x2a94e111 + .long 0x3fbacb12,0x3fff0000,0xe33f8972,0xbe8a5a51 + .long 0x3fbb9bfe,0x3fff0000,0xe5b906e7,0x7c8348a8 + .long 0x3fbcf2f4,0x3fff0000,0xe8396a50,0x3c4bdc68 + .long 0x3fbef22f,0x3fff0000,0xeac0c6e7,0xdd24392f + .long 0xbfbdbf4a,0x3fff0000,0xed4f301e,0xd9942b84 + .long 0x3fbec01a,0x3fff0000,0xefe4b99b,0xdcdaf5cb + .long 0x3fbe8cac,0x3fff0000,0xf281773c,0x59ffb13a + .long 0xbfbcbb3f,0x3fff0000,0xf5257d15,0x2486cc2c + .long 0x3fbef73a,0x3fff0000,0xf7d0df73,0x0ad13bb9 + .long 0xbfb8b795,0x3fff0000,0xfa83b2db,0x722a033a + .long 0x3fbef84b,0x3fff0000,0xfd3e0c0c,0xf486c175 + .long 0xbfbef581,0xf210d080,0x22103228,0x0004f22e + .long 0x6800ff84,0x02817fff,0xffff0c81,0x3fb98000 + .long 0x6c046000,0x00880c81,0x400d80c0,0x6f046000 + .long 0x007cf200,0x0080f23c,0x44a34280,0x0000f22e + .long 0x6080ff54,0x2f0243fa,0xfbbcf22e,0x4080ff54 + .long 0x222eff54,0x24010281,0x0000003f,0xe981d3c1 + .long 0xec822202,0xe2819481,0x06820000,0x3ffff227 + .long 0xe00cf23c,0x44a33c80,0x00002d59,0xff842d59 + .long 0xff882d59,0xff8c3d59,0xff90f200,0x04283d59 + .long 0xff94426e,0xff9642ae,0xff98d36e,0xff84f23a + .long 0x4823fb22,0xd36eff90,0x60000100,0x0c813fff + .long 0x80006e12,0xf2009000,0xf23c4422,0x3f800000 + .long 0x60ff0000,0x0b12222e,0xff840c81,0x00000000 + .long 0x6d0660ff,0x00000ac8,0x60ff0000,0x0a1af200 + .long 0x9000f23c,0x44003f80,0x00002210,0x00810080 + .long 0x0001f201,0x442260ff,0x00000adc,0xf210d080 + .long 0x22103228,0x0004f22e,0x6800ff84,0x02817fff + .long 0xffff0c81,0x3fb98000,0x6c046000,0xff900c81 + .long 0x400b9b07,0x6f046000,0xff84f200,0x0080f23a + .long 0x54a3fa62,0xf22e6080,0xff542f02,0x43fafac6 + .long 0xf22e4080,0xff54222e,0xff542401,0x02810000 + .long 0x003fe981,0xd3c1ec82,0x2202e281,0x94810682 + .long 0x00003fff,0xf227e00c,0xf2000500,0xf23a54a3 + .long 0xfa2c2d59,0xff84f23a,0x4923fa2a,0x2d59ff88 + .long 0x2d59ff8c,0xf2000428,0x3d59ff90,0xf2000828 + .long 0x3d59ff94,0x426eff96,0x42aeff98,0xf23a4823 + .long 0xfa14d36e,0xff84d36e,0xff90f200,0x0080f200 + .long 0x04a3f23a,0x5500fa1e,0xf23a5580,0xfa20f200 + .long 0x0523f200,0x05a3f23a,0x5522fa1a,0xf23a55a2 + .long 0xfa1cf200,0x0523f200,0x05a3f23a,0x5522fa16 + .long 0xf20001a3,0xf2000523,0xf2000c22,0xf2000822 + .long 0xf21fd030,0xf22e4823,0xff84f22e,0x4822ff90 + .long 0xf22e4822,0xff84f200,0x90003d42,0xff84241f + .long 0x2d7c8000,0x0000ff88,0x42aeff8c,0x123c0000 + .long 0xf22e4823,0xff8460ff,0x00000996,0xf2009000 + .long 0xf23c4400,0x3f800000,0x22100081,0x00800001 + .long 0xf2014422,0x60ff0000,0x098e2f01,0xe8082200 + .long 0x02410003,0x0240000c,0x48403001,0x221f4a01 + .long 0x671e0c01,0x000a6f12,0x0c01000e,0x6f3c0c01 + .long 0x002f6f06,0x0c01003f,0x6f6260ff,0x00000baa + .long 0x4a00660c,0x41fb0170,0x000000d6,0x60000086 + .long 0x0c000003,0x670a41fb,0x01700000,0x00d06074 + .long 0x41fb0170,0x000000d2,0x606a0401,0x000b4a00 + .long 0x661041fb,0x01700000,0x00cc0c01,0x00026f54 + .long 0x605a0c00,0x0003670a,0x41fb0170,0x000000f2 + .long 0x60e841fb,0x01700000,0x012460de,0x04010030 + .long 0x4a006616,0x41fb0170,0x0000014e,0x0c010001 + .long 0x6f220c01,0x00076f24,0x601a0c00,0x0003670a + .long 0x41fb0170,0x000001f2,0x60e241fb,0x01700000 + .long 0x02a860d8,0x00ae0000,0x0208ff64,0xc2fc000c + .long 0x48404a00,0x6608f230,0xd0801000,0x4e754840 + .long 0x3d701000,0xff902d70,0x1004ff94,0x2d701008 + .long 0xff982200,0x428041ee,0xff904268,0x000261ff + .long 0x000062c6,0xf210d080,0x4e7551fc,0x40000000 + .long 0xc90fdaa2,0x2168c235,0x40000000,0xc90fdaa2 + .long 0x2168c234,0x40000000,0xc90fdaa2,0x2168c235 + .long 0x3ffd0000,0x9a209a84,0xfbcff798,0x40000000 + .long 0xadf85458,0xa2bb4a9a,0x3fff0000,0xb8aa3b29 + .long 0x5c17f0bc,0x3ffd0000,0xde5bd8a9,0x37287195 + .long 0x00000000,0x00000000,0x00000000,0x3ffd0000 + .long 0x9a209a84,0xfbcff798,0x40000000,0xadf85458 + .long 0xa2bb4a9a,0x3fff0000,0xb8aa3b29,0x5c17f0bb + .long 0x3ffd0000,0xde5bd8a9,0x37287195,0x00000000 + .long 0x00000000,0x00000000,0x3ffd0000,0x9a209a84 + .long 0xfbcff799,0x40000000,0xadf85458,0xa2bb4a9b + .long 0x3fff0000,0xb8aa3b29,0x5c17f0bc,0x3ffd0000 + .long 0xde5bd8a9,0x37287195,0x00000000,0x00000000 + .long 0x00000000,0x3ffe0000,0xb17217f7,0xd1cf79ac + .long 0x40000000,0x935d8ddd,0xaaa8ac17,0x3fff0000 + .long 0x80000000,0x00000000,0x40020000,0xa0000000 + .long 0x00000000,0x40050000,0xc8000000,0x00000000 + .long 0x400c0000,0x9c400000,0x00000000,0x40190000 + .long 0xbebc2000,0x00000000,0x40340000,0x8e1bc9bf + .long 0x04000000,0x40690000,0x9dc5ada8,0x2b70b59e + .long 0x40d30000,0xc2781f49,0xffcfa6d5,0x41a80000 + .long 0x93ba47c9,0x80e98ce0,0x43510000,0xaa7eebfb + .long 0x9df9de8e,0x46a30000,0xe319a0ae,0xa60e91c7 + .long 0x4d480000,0xc9767586,0x81750c17,0x5a920000 + .long 0x9e8b3b5d,0xc53d5de5,0x75250000,0xc4605202 + .long 0x8a20979b,0x3ffe0000,0xb17217f7,0xd1cf79ab + .long 0x40000000,0x935d8ddd,0xaaa8ac16,0x3fff0000 + .long 0x80000000,0x00000000,0x40020000,0xa0000000 + .long 0x00000000,0x40050000,0xc8000000,0x00000000 + .long 0x400c0000,0x9c400000,0x00000000,0x40190000 + .long 0xbebc2000,0x00000000,0x40340000,0x8e1bc9bf + .long 0x04000000,0x40690000,0x9dc5ada8,0x2b70b59d + .long 0x40d30000,0xc2781f49,0xffcfa6d5,0x41a80000 + .long 0x93ba47c9,0x80e98cdf,0x43510000,0xaa7eebfb + .long 0x9df9de8d,0x46a30000,0xe319a0ae,0xa60e91c6 + .long 0x4d480000,0xc9767586,0x81750c17,0x5a920000 + .long 0x9e8b3b5d,0xc53d5de4,0x75250000,0xc4605202 + .long 0x8a20979a,0x3ffe0000,0xb17217f7,0xd1cf79ac + .long 0x40000000,0x935d8ddd,0xaaa8ac17,0x3fff0000 + .long 0x80000000,0x00000000,0x40020000,0xa0000000 + .long 0x00000000,0x40050000,0xc8000000,0x00000000 + .long 0x400c0000,0x9c400000,0x00000000,0x40190000 + .long 0xbebc2000,0x00000000,0x40340000,0x8e1bc9bf + .long 0x04000000,0x40690000,0x9dc5ada8,0x2b70b59e + .long 0x40d30000,0xc2781f49,0xffcfa6d6,0x41a80000 + .long 0x93ba47c9,0x80e98ce0,0x43510000,0xaa7eebfb + .long 0x9df9de8e,0x46a30000,0xe319a0ae,0xa60e91c7 + .long 0x4d480000,0xc9767586,0x81750c18,0x5a920000 + .long 0x9e8b3b5d,0xc53d5de5,0x75250000,0xc4605202 + .long 0x8a20979b,0x2f003229,0x00005bee,0xff540281 + .long 0x00007fff,0x30280000,0x02407fff,0x0c403fff + .long 0x6d0000c0,0x0c40400c,0x6e0000a4,0xf2284803 + .long 0x0000f200,0x6000f23c,0x88000000,0x00004a29 + .long 0x00046b5e,0x2f003d69,0x0000ff84,0x2d690004 + .long 0xff882d69,0x0008ff8c,0x41eeff84,0x61ff0000 + .long 0x60ba4480,0xd09ff22e,0xd080ff84,0x0c40c001 + .long 0x6c36f21f,0x9000223c,0x80000000,0x0480ffff + .long 0xc0014480,0x0c000020,0x6c0ae0a9,0x42a72f01 + .long 0x42a76028,0x04000020,0xe0a92f01,0x42a742a7 + .long 0x601af229,0xd0800000,0xf21f9000,0x06403fff + .long 0x484042a7,0x2f3c8000,0x00002f00,0xf200b000 + .long 0x123c0000,0xf21f4823,0x60ff0000,0x04ce201f + .long 0xc1494a29,0x00006bff,0x0000038c,0x60ff0000 + .long 0x03c44a29,0x00046a16,0x201ff200,0x9000123c + .long 0x0003f229,0x48000000,0x60ff0000,0x049e201f + .long 0x204960ff,0x000002e2,0x00010000,0x80000000 + .long 0x00000000,0x00000000,0x422eff65,0x2f00422e + .long 0xff5c600c,0x422eff65,0x2f001d7c,0x0001ff5c + .long 0x48e73f00,0x36280000,0x3d43ff58,0x02830000 + .long 0x7fff2828,0x00042a28,0x00084a83,0x663c263c + .long 0x00003ffe,0x4a846616,0x28054285,0x04830000 + .long 0x00204286,0xedc46000,0xedac9686,0x60224286 + .long 0xedc46000,0x9686edac,0x2e05edad,0x44860686 + .long 0x00000020,0xecaf8887,0x60060683,0x00003ffe + .long 0x30290000,0x3d40ff5a,0x322eff58,0xb1810281 + .long 0x00008000,0x3d41ff5e,0x02800000,0x7fff2229 + .long 0x00042429,0x00084a80,0x663c203c,0x00003ffe + .long 0x4a816616,0x22024282,0x04800000,0x00204286 + .long 0xedc16000,0xeda99086,0x60224286,0xedc16000 + .long 0x9086eda9,0x2e02edaa,0x44860686,0x00000020 + .long 0xecaf8287,0x60060680,0x00003ffe,0x2d43ff54 + .long 0x2f009083,0x42864283,0x227c0000,0x00004a80 + .long 0x6c06201f,0x6000006a,0x588f4a86,0x6e0eb284 + .long 0x6608b485,0x66046000,0x01366508,0x94859384 + .long 0x42865283,0x4a80670e,0xd683d482,0xe39155c6 + .long 0x52895380,0x60d4202e,0xff544a81,0x66162202 + .long 0x42820480,0x00000020,0x4286edc1,0x6000eda9 + .long 0x9086601c,0x4286edc1,0x60006b14,0x9086eda9 + .long 0x2e02edaa,0x44860686,0x00000020,0xecaf8287 + .long 0x0c800000,0x41fe6c2a,0x3d40ff90,0x2d41ff94 + .long 0x2d42ff98,0x2c2eff54,0x3d46ff84,0x2d44ff88 + .long 0x2d45ff8c,0xf22e4800,0xff901d7c,0x0001ff5d + .long 0x60362d41,0xff942d42,0xff980480,0x00003ffe + .long 0x3d40ff90,0x2c2eff54,0x04860000,0x3ffe2d46 + .long 0xff54f22e,0x4800ff90,0x3d46ff84,0x2d44ff88 + .long 0x2d45ff8c,0x422eff5d,0x4a2eff5c,0x67222c2e + .long 0xff545386,0xb0866d18,0x6e0eb284,0x6608b485 + .long 0x66046000,0x007a6508,0xf22e4828,0xff845283 + .long 0x3c2eff5a,0x6c04f200,0x001a4286,0x3c2eff5e + .long 0x7e08eeae,0x02830000,0x007f8686,0x1d43ff65 + .long 0x4cdf00fc,0x201ff200,0x90004a2e,0xff5d6710 + .long 0x123c0000,0xf23a4823,0xfdc060ff,0x0000024c + .long 0x123c0003,0xf2000000,0x60ff0000,0x023e5283 + .long 0x0c800000,0x00086c04,0xe1ab6002,0x4283f23c + .long 0x44000000,0x0000422e,0xff5d6000,0xff942c03 + .long 0x02860000,0x00014a86,0x6700ff86,0x52833c2e + .long 0xff5a0a86,0x00008000,0x3d46ff5a,0x6000ff72 + .long 0x7fff0000,0xffffffff,0xffffffff,0x4a280000 + .long 0x6b12f23c,0x44007f80,0x000000ae,0x02000410 + .long 0xff644e75,0xf23c4400,0xff800000,0x00ae0a00 + .long 0x0410ff64,0x4e7500ae,0x01002080,0xff64f23a + .long 0xd080ffbe,0x4e7500ae,0x00000800,0xff646008 + .long 0x00ae0000,0x0a28ff64,0x22482200,0x020100c0 + .long 0x660e4a28,0x00006a18,0x08ee0003,0xff646010 + .long 0x2f094a28,0x00005bc1,0x61ff0000,0x0196225f + .long 0xf210d080,0x102eff62,0x0200000a,0x66024e75 + .long 0x3d690000,0xff842d69,0x0004ff88,0x2d690008 + .long 0xff8c41ee,0xff8461ff,0x00005cd0,0x06800000 + .long 0x6000026e,0x8000ff84,0x816eff84,0xf22ed040 + .long 0xff844e75,0x00ae0000,0x0a28ff64,0x4a105bc1 + .long 0x61ff0000,0x013ef210,0xd080f23c,0x44800000 + .long 0x00004e75,0x00ae0000,0x0a28ff64,0x51c161ff + .long 0x00000120,0xf210d080,0xf23c4480,0x00000000 + .long 0x4e7500ae,0x00001048,0xff641200,0x020100c0 + .long 0x675c4a28,0x00046b24,0x3d680000,0xff842d68 + .long 0x0004ff88,0x2d680008,0xff8c41ee,0xff8448e7 + .long 0xc08061ff,0x00005c44,0x4cdf0103,0x0c010040 + .long 0x660e4aa8,0x00086614,0x4a280007,0x660e601e + .long 0x22280008,0x02810000,0x07ff6712,0x00ae0000 + .long 0x0200ff64,0x600800ae,0x00001248,0xff644a28 + .long 0x00005bc1,0x61ff0000,0x5f261d40,0xff64f210 + .long 0xd080f23c,0x44800000,0x00004e75,0x00ae0000 + .long 0x1248ff64,0x51c161ff,0x00005f04,0x1d40ff64 + .long 0xf210d080,0xf23c4480,0x00000000,0x4e75f327 + .long 0x4a2f0002,0x6b2edffc,0x0000000c,0xf294000e + .long 0xf2810014,0x006e0208,0xff664e75,0x00ae0800 + .long 0x0208ff64,0x4e751d7c,0x0004ff64,0x006e0208 + .long 0xff664e75,0x006e0208,0xff6661ff,0x00000bae + .long 0xdffc0000,0x000c4e75,0xf3274a2f,0x00026bea + .long 0xdffc0000,0x000cf200,0xa80081ae,0xff644e75 + .long 0x00ae0000,0x0a28ff64,0x02410010,0xe8080200 + .long 0x000f8001,0x2200e309,0x1d7b000a,0xff6441fb + .long 0x16204e75,0x04040400,0x04040400,0x04040400 + .long 0x00000000,0x0c0c080c,0x0c0c080c,0x0c0c080c + .long 0x00000000,0x00000000,0x00000000,0x00000000 + .long 0x00000000,0x00000000,0x00000000,0x00000000 + .long 0x00000000,0x00000000,0x00000000,0x00000000 + .long 0x00000000,0x00000000,0x00000001,0x00000000 + .long 0x3f810000,0x00000000,0x00000000,0x00000000 + .long 0x3f810000,0x00000000,0x00000000,0x00000000 + .long 0x3f810000,0x00000000,0x00000000,0x00000000 + .long 0x3f810000,0x00000100,0x00000000,0x00000000 + .long 0x3c010000,0x00000000,0x00000000,0x00000000 + .long 0x3c010000,0x00000000,0x00000000,0x00000000 + .long 0x3c010000,0x00000000,0x00000000,0x00000000 + .long 0x3c010000,0x00000000,0x00000800,0x00000000 + .long 0x00000000,0x00000000,0x00000000,0x00000000 + .long 0x00000000,0x00000000,0x00000000,0x00000000 + .long 0x00000000,0x00000000,0x00000000,0x00000000 + .long 0x00000000,0x00000000,0x00000000,0x00000000 + .long 0x80000000,0x00000000,0x00000000,0x00000000 + .long 0x80000000,0x00000000,0x00000000,0x00000000 + .long 0x80000000,0x00000000,0x00000001,0x00000000 + .long 0x80000000,0x00000000,0x00000000,0x00000000 + .long 0xbf810000,0x00000000,0x00000000,0x00000000 + .long 0xbf810000,0x00000000,0x00000000,0x00000000 + .long 0xbf810000,0x00000100,0x00000000,0x00000000 + .long 0xbf810000,0x00000000,0x00000000,0x00000000 + .long 0xbc010000,0x00000000,0x00000000,0x00000000 + .long 0xbc010000,0x00000000,0x00000000,0x00000000 + .long 0xbc010000,0x00000000,0x00000800,0x00000000 + .long 0xbc010000,0x00000000,0x00000000,0x00000000 + .long 0x4a280000,0x6b10f23c,0x44000000,0x00001d7c + .long 0x0004ff64,0x4e75f23c,0x44008000,0x00001d7c + .long 0x000cff64,0x4e754a29,0x00006bea,0x60d84a28 + .long 0x00006b10,0xf23c4400,0x7f800000,0x1d7c0002 + .long 0xff644e75,0xf23c4400,0xff800000,0x1d7c000a + .long 0xff644e75,0x4a290000,0x6bea60d8,0x4a280000 + .long 0x6ba460d0,0x4a280000,0x6b00fbbc,0x60c64a28 + .long 0x00006b16,0x60be4a28,0x00006b0e,0xf23c4400 + .long 0x3f800000,0x422eff64,0x4e75f23c,0x4400bf80 + .long 0x00001d7c,0x0008ff64,0x4e753fff,0x0000c90f + .long 0xdaa22168,0xc235bfff,0x0000c90f,0xdaa22168 + .long 0xc2354a28,0x00006b0e,0xf2009000,0xf23a4800 + .long 0xffda6000,0xfcf0f200,0x9000f23a,0x4800ffd8 + .long 0x6000fcea,0xf23c4480,0x3f800000,0x4a280000 + .long 0x6a10f23c,0x44008000,0x00001d7c,0x000cff64 + .long 0x6040f23c,0x44000000,0x00001d7c,0x0004ff64 + .long 0x6030f23a,0x4880faea,0x61ff0000,0x00286000 + .long 0xfb16f228,0x48800000,0x61ff0000,0x00186000 + .long 0x030ef228,0x48800000,0x61ff0000,0x00086000 + .long 0x02ee102e,0xff430240,0x0007303b,0x02064efb + .long 0x00020010,0x00180020,0x0026002c,0x00320038 + .long 0x003ef22e,0xf040ffdc,0x4e75f22e,0xf040ffe8 + .long 0x4e75f200,0x05004e75,0xf2000580,0x4e75f200 + .long 0x06004e75,0xf2000680,0x4e75f200,0x07004e75 + .long 0xf2000780,0x4e75122e,0xff4f67ff,0xfffff7dc + .long 0x0c010001,0x67000096,0x0c010002,0x67ffffff + .long 0xfa880c01,0x000467ff,0xfffff7c0,0x0c010005 + .long 0x67ff0000,0x024060ff,0x0000024a,0x122eff4f + .long 0x67ffffff,0xfa640c01,0x000167ff,0xfffffa5a + .long 0x0c010002,0x67ffffff,0xfa500c01,0x000467ff + .long 0xfffffa46,0x0c010003,0x67ff0000,0x021860ff + .long 0x00000202,0x122eff4f,0x67ff0000,0x004e0c01 + .long 0x000167ff,0x00000028,0x0c010002,0x67ffffff + .long 0xfa180c01,0x000467ff,0x00000030,0x0c010003 + .long 0x67ff0000,0x01e060ff,0x000001ca,0x12280000 + .long 0x10290000,0xb1010201,0x00801d41,0xff654a00 + .long 0x6a00fdc4,0x6000fdd0,0x422eff65,0x2f001228 + .long 0x00001029,0x0000b101,0x02010080,0x1d41ff65 + .long 0x0c2e0004,0xff4f660c,0x41e90000,0x201f60ff + .long 0xfffff9c6,0xf21f9000,0xf2294800,0x00004a29 + .long 0x00006b02,0x4e751d7c,0x0008ff64,0x4e75122e + .long 0xff4f67ff,0xfffff6e0,0x0c010001,0x6700ff8e + .long 0x0c010002,0x67ffffff,0xf9800c01,0x000467ff + .long 0xfffff6c4,0x0c010003,0x67ff0000,0x014860ff + .long 0x00000132,0x122eff4f,0x67ffffff,0xf95c0c01 + .long 0x000167ff,0xfffff952,0x0c010002,0x67ffffff + .long 0xf9480c01,0x000467ff,0xfffff93e,0x0c010003 + .long 0x67ff0000,0x011060ff,0x000000fa,0x122eff4f + .long 0x6700ff46,0x0c010001,0x6700ff22,0x0c010002 + .long 0x67ffffff,0xf9140c01,0x000467ff,0xffffff2c + .long 0x0c010003,0x67ff0000,0x00dc60ff,0x000000c6 + .long 0x122eff4f,0x67ffffff,0xf51e0c01,0x000167ff + .long 0xfffffce6,0x0c010002,0x67ffffff,0xfd0a0c01 + .long 0x000467ff,0xfffff500,0x0c010003,0x67ff0000 + .long 0x00a460ff,0x0000008e,0x122eff4f,0x67ffffff + .long 0xf4e60c01,0x000167ff,0xfffffcae,0x0c010002 + .long 0x67ffffff,0xfcd20c01,0x000467ff,0xfffff4c8 + .long 0x0c010003,0x67ff0000,0x006c60ff,0x00000056 + .long 0x122eff4f,0x67ffffff,0xf8800c01,0x000367ff + .long 0x00000052,0x0c010005,0x67ff0000,0x003860ff + .long 0xfffff866,0x122eff4f,0x0c010003,0x67340c01 + .long 0x0005671e,0x6058122e,0xff4f0c01,0x00036708 + .long 0x0c010005,0x670c6036,0x00ae0100,0x4080ff64 + .long 0x6010f229,0x48000000,0xf200a800,0x81aeff64 + .long 0x4e75f229,0x48000000,0x4a290000,0x6b081d7c + .long 0x0001ff64,0x4e751d7c,0x0009ff64,0x4e75f228 + .long 0x48000000,0xf200a800,0x81aeff64,0x4e75f228 + .long 0x48000000,0x4a280000,0x6bdc1d7c,0x0001ff64 + .long 0x4e751d7c,0x0009ff64,0x4e75122e,0xff4e67ff + .long 0xffffd936,0x0c010001,0x67ffffff,0xfba60c01 + .long 0x000267ff,0xfffffbca,0x0c010004,0x67ffffff + .long 0xd9f60c01,0x000367ff,0xffffffb6,0x60ffffff + .long 0xffa0122e,0xff4e67ff,0xffffe620,0x0c010001 + .long 0x67ffffff,0xfb6e0c01,0x000267ff,0xfffffbc8 + .long 0x0c010004,0x67ffffff,0xe7560c01,0x000367ff + .long 0xffffff7e,0x60ffffff,0xff68122e,0xff4e67ff + .long 0xffffd4d2,0x0c010001,0x67ffffff,0xfb360c01 + .long 0x000267ff,0xfffffb9a,0x0c010004,0x67ffffff + .long 0xd76a0c01,0x000367ff,0xffffff46,0x60ffffff + .long 0xff30122e,0xff4e67ff,0xffffd972,0x0c010001 + .long 0x67ffffff,0xfafe0c01,0x000267ff,0xfffffb6a + .long 0x0c010004,0x67ffffff,0xdabc0c01,0x000367ff + .long 0xffffff0e,0x60ffffff,0xfef8122e,0xff4e67ff + .long 0xffffca6a,0x0c010001,0x67ffffff,0xfac60c01 + .long 0x000267ff,0xfffffb6e,0x0c010004,0x67ffffff + .long 0xcc8a0c01,0x000367ff,0xfffffed6,0x60ffffff + .long 0xfec0122e,0xff4e67ff,0xffffcc76,0x0c010001 + .long 0x67ffffff,0xfa8e0c01,0x000267ff,0xfffff6aa + .long 0x0c010004,0x67ffffff,0xcd060c01,0x000367ff + .long 0xfffffe9e,0x60ffffff,0xfe88122e,0xff4e67ff + .long 0xffffe662,0x0c010001,0x67ffffff,0xfa560c01 + .long 0x000267ff,0xfffff672,0x0c010004,0x67ffffff + .long 0xe6c60c01,0x000367ff,0xfffffe66,0x60ffffff + .long 0xfe50122e,0xff4e67ff,0xffffb372,0x0c010001 + .long 0x67ffffff,0xfa1e0c01,0x000267ff,0xfffff63a + .long 0x0c010004,0x67ffffff,0xb5380c01,0x000367ff + .long 0xfffffe2e,0x60ffffff,0xfe18122e,0xff4e67ff + .long 0xffffbdfc,0x0c010001,0x67ffffff,0xf9e60c01 + .long 0x000267ff,0xfffff602,0x0c010004,0x67ffffff + .long 0xbf420c01,0x000367ff,0xfffffdf6,0x60ffffff + .long 0xfde0122e,0xff4e67ff,0xffffd17a,0x0c010001 + .long 0x67ffffff,0xfa2a0c01,0x000267ff,0xfffffa00 + .long 0x0c010004,0x67ffffff,0xd3080c01,0x000367ff + .long 0xfffffdbe,0x60ffffff,0xfda8122e,0xff4e67ff + .long 0xffffeb64,0x0c010001,0x67ffffff,0xf9f20c01 + .long 0x000267ff,0xfffff9c8,0x0c010004,0x67ffffff + .long 0xec200c01,0x000367ff,0xfffffd86,0x60ffffff + .long 0xfd70122e,0xff4e67ff,0xffffec24,0x0c010001 + .long 0x67ffffff,0xf9ba0c01,0x000267ff,0xfffff990 + .long 0x0c010004,0x67ffffff,0xed360c01,0x000367ff + .long 0xfffffd4e,0x60ffffff,0xfd38122e,0xff4e67ff + .long 0xffffe178,0x0c010001,0x67ffffff,0xf51a0c01 + .long 0x000267ff,0xfffff960,0x0c010004,0x67ffffff + .long 0xe30c0c01,0x000367ff,0xfffffd16,0x60ffffff + .long 0xfd00122e,0xff4e67ff,0xffffe582,0x0c010001 + .long 0x67ffffff,0xf4e20c01,0x000267ff,0xfffff928 + .long 0x0c010004,0x67ffffff,0xe5940c01,0x000367ff + .long 0xfffffcde,0x60ffffff,0xfcc8122e,0xff4e67ff + .long 0xffffe59a,0x0c010001,0x67ffffff,0xf4aa0c01 + .long 0x000267ff,0xfffff8f0,0x0c010004,0x67ffffff + .long 0xe5d60c01,0x000367ff,0xfffffca6,0x60ffffff + .long 0xfc90122e,0xff4e67ff,0xffffd530,0x0c010001 + .long 0x67ffffff,0xf8da0c01,0x000267ff,0xfffff888 + .long 0x0c010004,0x67ffffff,0xd5b60c01,0x000367ff + .long 0xfffffc6e,0x60ffffff,0xfc58122e,0xff4e67ff + .long 0xffffcac2,0x0c010001,0x67ffffff,0xf8de0c01 + .long 0x000267ff,0xfffff442,0x0c010004,0x67ffffff + .long 0xcb340c01,0x000367ff,0xfffffc36,0x60ffffff + .long 0xfc20122e,0xff4e67ff,0xffffb14c,0x0c010001 + .long 0x67ffffff,0xf86a0c01,0x000267ff,0xfffff40a + .long 0x0c010004,0x67ffffff,0xb30e0c01,0x000367ff + .long 0xfffffbfe,0x60ffffff,0xfbe8122e,0xff4e67ff + .long 0xffffd40e,0x0c010001,0x67ffffff,0xf7b60c01 + .long 0x000267ff,0xfffff3d2,0x0c010004,0x67ffffff + .long 0xd40c0c01,0x000367ff,0xfffffbc6,0x60ffffff + .long 0xfbb0122e,0xff4e67ff,0xffffd40a,0x0c010001 + .long 0x67ffffff,0xf77e0c01,0x000267ff,0xfffff39a + .long 0x0c010004,0x67ffffff,0xd41a0c01,0x000367ff + .long 0xfffffb8e,0x60ffffff,0xfb78122e,0xff4e67ff + .long 0xffffb292,0x0c010001,0x67ffffff,0xf81a0c01 + .long 0x000267ff,0xfffff83e,0x0c010004,0x67ffffff + .long 0xb50a0c01,0x000367ff,0xfffff83a,0x60ffffff + .long 0xf844122e,0xff4e67ff,0xfffff89e,0x0c010001 + .long 0x67ffffff,0xf8ca0c01,0x000267ff,0xfffff8f8 + .long 0x0c010004,0x67ffffff,0xf8800c01,0x000367ff + .long 0xfffffab4,0x60ffffff,0xfac0122e,0xff4e67ff + .long 0xfffff96e,0x0c010001,0x67ffffff,0xf99a0c01 + .long 0x000267ff,0xfffff9c8,0x0c010004,0x67ffffff + .long 0xf9500c01,0x000367ff,0xfffffa7c,0x60ffffff + .long 0xfa88122e,0xff4e67ff,0xfffff9d8,0x0c010001 + .long 0x67ffffff,0xfa060c01,0x000267ff,0xfffffa34 + .long 0x0c010004,0x67ffffff,0xf9ba0c01,0x000367ff + .long 0xfffffa44,0x60ffffff,0xfa500c2f,0x00070003 + .long 0x673e1d7c,0x0000ff4e,0x1d7c0000,0xff4ff22e + .long 0xf080ff78,0x41ef0004,0x43eeff78,0x0c010003 + .long 0x67160c01,0x00026708,0x61ff0000,0x02004e75 + .long 0x61ff0000,0x1b9e4e75,0x61ff0000,0x05e44e75 + .long 0x1d7c0004,0xff4e60c0,0x4afc006d,0x000005d2 + .long 0x00000fc8,0xfffffa6e,0x0000106c,0x00002314 + .long 0x00000000,0xfffffaa6,0x00000000,0xfffffade + .long 0xfffffb16,0xfffffb4e,0x00000000,0xfffffb86 + .long 0xfffffbbe,0xfffffbf6,0xfffffc2e,0xfffffc66 + .long 0xfffffc9e,0xfffffcd6,0x00000000,0xfffffd0e + .long 0xfffffd46,0xfffffd7e,0x00000000,0x00001112 + .long 0xfffffdb6,0x00000ca8,0x00000000,0xfffffdee + .long 0xfffffe26,0xfffffe5e,0xfffffe96,0x0000089e + .long 0xffffff06,0x00001b84,0x000001de,0x00001854 + .long 0xffffff3e,0xffffff76,0x00001512,0x00001f4c + .long 0x00000000,0x00000000,0x00000000,0x00000000 + .long 0x00000000,0x00000000,0x00000000,0xfffffece + .long 0xfffffece,0xfffffece,0xfffffece,0xfffffece + .long 0xfffffece,0xfffffece,0xfffffece,0x000013b0 + .long 0x00000000,0x00000f56,0x00000000,0x00000000 + .long 0x00000000,0x00000000,0x00000000,0x000005c0 + .long 0x00002302,0x00000000,0x00000000,0x000005ca + .long 0x0000230c,0x00000000,0x00000000,0x00000000 + .long 0x00000000,0x00000000,0x00000000,0x00000000 + .long 0x00000000,0x00000000,0x00000000,0x00000000 + .long 0x00000000,0x00000000,0x00000000,0x00000000 + .long 0x00000000,0x00000000,0x00000000,0x00001100 + .long 0x00000000,0x00000c96,0x00000000,0x0000110a + .long 0x00000000,0x00000ca0,0x00000000,0x0000088c + .long 0x00000000,0x00001b72,0x000001cc,0x00000896 + .long 0x00000000,0x00001b7c,0x000001d6,0x00001f3a + .long 0x00000000,0x00000000,0x00000000,0x00001f44 + .long 0xffffc001,0xffffff81,0xfffffc01,0x00004000 + .long 0x0000007f,0x000003ff,0x02000030,0x00000040 + .long 0x60080200,0x00300000,0x00802d40,0xff5c4241 + .long 0x122eff4f,0xe709822e,0xff4e6600,0x02e43d69 + .long 0x0000ff90,0x2d690004,0xff942d69,0x0008ff98 + .long 0x3d680000,0xff842d68,0x0004ff88,0x2d680008 + .long 0xff8c61ff,0x000024ce,0x2f0061ff,0x00002572 + .long 0xd197322e,0xff5eec09,0x201fb0bb,0x14846700 + .long 0x011e6d00,0x0062b0bb,0x14846700,0x021a6e00 + .long 0x014af22e,0xd080ff90,0xf22e9000,0xff5cf23c + .long 0x88000000,0x0000f22e,0x4823ff84,0xf201a800 + .long 0xf23c9000,0x00000000,0x83aeff64,0xf22ef080 + .long 0xff842f02,0x322eff84,0x24010281,0x00007fff + .long 0x02428000,0x92808242,0x3d41ff84,0x241ff22e + .long 0xd080ff84,0x4e75f22e,0xd080ff90,0xf22e9000 + .long 0xff5cf23c,0x88000000,0x0000f22e,0x4823ff84 + .long 0xf201a800,0xf23c9000,0x00000000,0x83aeff64 + .long 0x00ae0000,0x1048ff64,0x122eff62,0x02010013 + .long 0x661c082e,0x0003ff64,0x56c1202e,0xff5c61ff + .long 0x00004fcc,0x812eff64,0xf210d080,0x4e75222e + .long 0xff5c0201,0x00c06634,0xf22ef080,0xff842f02 + .long 0x322eff84,0x34010281,0x00007fff,0x92800481 + .long 0x00006000,0x02417fff,0x02428000,0x82423d41 + .long 0xff84241f,0xf22ed040,0xff8460a6,0xf22ed080 + .long 0xff90222e,0xff5c0201,0x0030f201,0x9000f22e + .long 0x4823ff84,0xf23c9000,0x00000000,0x60aaf22e + .long 0xd080ff90,0xf22e9000,0xff5cf23c,0x88000000 + .long 0x0000f22e,0x4823ff84,0xf201a800,0xf23c9000 + .long 0x00000000,0x83aeff64,0xf2000098,0xf23c58b8 + .long 0x0002f293,0xff3c6000,0xfee408ee,0x0003ff66 + .long 0xf22ed080,0xff90f23c,0x90000000,0x0010f23c + .long 0x88000000,0x0000f22e,0x4823ff84,0xf201a800 + .long 0xf23c9000,0x00000000,0x83aeff64,0x122eff62 + .long 0x0201000b,0x6620f22e,0xf080ff84,0x41eeff84 + .long 0x222eff5c,0x61ff0000,0x4dd8812e,0xff64f22e + .long 0xd080ff84,0x4e75f22e,0xd040ff90,0x222eff5c + .long 0x020100c0,0x6652f22e,0x9000ff5c,0xf23c8800 + .long 0x00000000,0xf22e48a3,0xff84f23c,0x90000000 + .long 0x0000f22e,0xf040ff84,0x2f02322e,0xff842401 + .long 0x02810000,0x7fff0242,0x80009280,0x06810000 + .long 0x60000241,0x7fff8242,0x3d41ff84,0x241ff22e + .long 0xd040ff84,0x6000ff80,0x222eff5c,0x02010030 + .long 0xf2019000,0x60a6f22e,0xd080ff90,0xf22e9000 + .long 0xff5cf23c,0x88000000,0x0000f22e,0x4823ff84 + .long 0xf201a800,0xf23c9000,0x00000000,0x83aeff64 + .long 0xf2000098,0xf23c58b8,0x0002f292,0xfde0f294 + .long 0xfefaf22e,0xd040ff90,0x222eff5c,0x020100c0 + .long 0x00010010,0xf2019000,0xf23c8800,0x00000000 + .long 0xf22e48a3,0xff84f23c,0x90000000,0x0000f200 + .long 0x0498f23c,0x58b80002,0xf293fda2,0x6000febc + .long 0x323b120a,0x4efb1006,0x4afc0030,0xfd120072 + .long 0x00cc006c,0xfd120066,0x00000000,0x00720072 + .long 0x0060006c,0x00720066,0x00000000,0x009e0060 + .long 0x009e006c,0x009e0066,0x00000000,0x006c006c + .long 0x006c006c,0x006c0066,0x00000000,0xfd120072 + .long 0x00cc006c,0xfd120066,0x00000000,0x00660066 + .long 0x00660066,0x00660066,0x00000000,0x60ff0000 + .long 0x230e60ff,0x00002284,0x60ff0000,0x227e1028 + .long 0x00001229,0x0000b101,0x6a10f23c,0x44008000 + .long 0x00001d7c,0x000cff64,0x4e75f23c,0x44000000 + .long 0x00001d7c,0x0004ff64,0x4e75f229,0xd0800000 + .long 0x10280000,0x12290000,0xb1016a10,0xf2000018 + .long 0xf200001a,0x1d7c000a,0xff644e75,0xf2000018 + .long 0x1d7c0002,0xff644e75,0xf228d080,0x00001028 + .long 0x00001229,0x0000b101,0x6ae260d0,0x02000030 + .long 0x00000040,0x60080200,0x00300000,0x00802d40 + .long 0xff5c122e,0xff4e6600,0x02620200,0x00c06600 + .long 0x007c4a28,0x00006a06,0x08ee0003,0xff64f228 + .long 0xd0800000,0x4e750200,0x00c06600,0x006008ee + .long 0x0003ff66,0x4a280000,0x6a0608ee,0x0003ff64 + .long 0xf228d080,0x0000082e,0x0003ff62,0x66024e75 + .long 0x3d680000,0xff842d68,0x0004ff88,0x2d680008 + .long 0xff8c41ee,0xff8461ff,0x00004950,0x44400640 + .long 0x6000322e,0xff840241,0x80000240,0x7fff8041 + .long 0x3d40ff84,0xf22ed040,0xff844e75,0x0c000040 + .long 0x667e3d68,0x0000ff84,0x2d680004,0xff882d68 + .long 0x0008ff8c,0x61ff0000,0x206c0c80,0x0000007f + .long 0x6c000092,0x0c80ffff,0xff816700,0x01786d00 + .long 0x00f4f23c,0x88000000,0x0000f22e,0x9000ff5c + .long 0xf22e4800,0xff84f201,0xa800f23c,0x90000000 + .long 0x000083ae,0xff642f02,0xf22ef080,0xff84322e + .long 0xff843401,0x02810000,0x7fff9280,0x02428000 + .long 0x84413d42,0xff84241f,0xf22ed080,0xff844e75 + .long 0x3d680000,0xff842d68,0x0004ff88,0x2d680008 + .long 0xff8c61ff,0x00001fee,0x0c800000,0x03ff6c00 + .long 0x00140c80,0xfffffc01,0x670000fa,0x6d000076 + .long 0x6000ff80,0x08ee0003,0xff664a2e,0xff846a06 + .long 0x08ee0003,0xff64122e,0xff620201,0x000b661a + .long 0x41eeff84,0x222eff5c,0x61ff0000,0x4a74812e + .long 0xff64f22e,0xd080ff84,0x4e752d6e,0xff88ff94 + .long 0x2d6eff8c,0xff98322e,0xff842f02,0x34010281 + .long 0x00007fff,0x92800242,0x80000681,0x00006000 + .long 0x02417fff,0x84413d42,0xff90f22e,0xd040ff90 + .long 0x241f60ac,0xf23c8800,0x00000000,0xf22e9000 + .long 0xff5cf22e,0x4800ff84,0xf23c9000,0x00000000 + .long 0xf201a800,0x83aeff64,0x00ae0000,0x1048ff64 + .long 0x122eff62,0x02010013,0x661c082e,0x0003ff64 + .long 0x56c1202e,0xff5c61ff,0x00004ae4,0x812eff64 + .long 0xf210d080,0x4e752f02,0x322eff84,0x24010281 + .long 0x00007fff,0x02428000,0x92800481,0x00006000 + .long 0x02417fff,0x82423d41,0xff84241f,0xf22ed040 + .long 0xff8460b6,0xf23c8800,0x00000000,0xf22e9000 + .long 0xff5cf22e,0x4800ff84,0xf201a800,0xf23c9000 + .long 0x00000000,0x83aeff64,0xf2000098,0xf23c58b8 + .long 0x0002f293,0xff746000,0xfe7e0c01,0x00046700 + .long 0xfdb60c01,0x000567ff,0x00001f98,0x0c010003 + .long 0x67ff0000,0x1fa2f228,0x48000000,0xf200a800 + .long 0xe1981d40,0xff644e75,0x51fc51fc,0x51fc51fc + .long 0x00003fff,0x0000007e,0x000003fe,0xffffc001 + .long 0xffffff81,0xfffffc01,0x02000030,0x00000040 + .long 0x60080200,0x00300000,0x00802d40,0xff5c4241 + .long 0x122eff4f,0xe709822e,0xff4e6600,0x02d63d69 + .long 0x0000ff90,0x2d690004,0xff942d69,0x0008ff98 + .long 0x3d680000,0xff842d68,0x0004ff88,0x2d680008 + .long 0xff8c61ff,0x00001e0e,0x2f0061ff,0x00001eb2 + .long 0x4497d197,0x322eff5e,0xec09201f,0xb0bb148e + .long 0x6f000074,0xb0bb1520,0xff7a6700,0x020c6e00 + .long 0x013cf22e,0xd080ff90,0xf22e9000,0xff5cf23c + .long 0x88000000,0x0000f22e,0x4820ff84,0xf201a800 + .long 0xf23c9000,0x00000000,0x83aeff64,0xf22ef080 + .long 0xff842f02,0x322eff84,0x24010281,0x00007fff + .long 0x02428000,0x92808242,0x3d41ff84,0x241ff22e + .long 0xd080ff84,0x4e750000,0x7fff0000,0x407f0000 + .long 0x43ff201f,0x60c62f00,0xf22ed080,0xff90f22e + .long 0x9000ff5c,0xf23c8800,0x00000000,0xf22e4820 + .long 0xff84f200,0xa800f23c,0x90000000,0x000081ae + .long 0xff64f227,0xe0013017,0xdffc0000,0x000c0280 + .long 0x00007fff,0x9097b0bb,0x14ae6db6,0x201f00ae + .long 0x00001048,0xff64122e,0xff620201,0x0013661c + .long 0x082e0003,0xff6456c1,0x202eff5c,0x61ff0000 + .long 0x48de812e,0xff64f210,0xd0804e75,0x222eff5c + .long 0x020100c0,0x6634f22e,0xf080ff84,0x2f02322e + .long 0xff843401,0x02810000,0x7fff9280,0x04810000 + .long 0x60000241,0x7fff0242,0x80008242,0x3d41ff84 + .long 0x241ff22e,0xd040ff84,0x60a6f22e,0xd080ff90 + .long 0x222eff5c,0x02010030,0xf2019000,0xf22e4820 + .long 0xff84f23c,0x90000000,0x000060aa,0x08ee0003 + .long 0xff66f22e,0xd080ff90,0xf23c9000,0x00000010 + .long 0xf23c8800,0x00000000,0xf22e4820,0xff84f201 + .long 0xa800f23c,0x90000000,0x000083ae,0xff64122e + .long 0xff620201,0x000b6620,0xf22ef080,0xff8441ee + .long 0xff84222e,0xff5c61ff,0x00004726,0x812eff64 + .long 0xf22ed080,0xff844e75,0xf22ed040,0xff90222e + .long 0xff5c0201,0x00c06652,0xf22e9000,0xff5cf23c + .long 0x88000000,0x0000f22e,0x48a0ff84,0xf23c9000 + .long 0x00000000,0xf22ef040,0xff842f02,0x322eff84 + .long 0x24010281,0x00007fff,0x02428000,0x92800681 + .long 0x00006000,0x02417fff,0x82423d41,0xff84241f + .long 0xf22ed040,0xff846000,0xff80222e,0xff5c0201 + .long 0x0030f201,0x900060a6,0xf22ed080,0xff90f22e + .long 0x9000ff5c,0xf23c8800,0x00000000,0xf22e4820 + .long 0xff84f201,0xa800f23c,0x90000000,0x000083ae + .long 0xff64f200,0x0098f23c,0x58b80001,0xf292fdee + .long 0xf294fefa,0xf22ed040,0xff90222e,0xff5c0201 + .long 0x00c00001,0x0010f201,0x9000f23c,0x88000000 + .long 0x0000f22e,0x48a0ff84,0xf23c9000,0x00000000 + .long 0xf2000498,0xf23c58b8,0x0001f293,0xfdb06000 + .long 0xfebc323b,0x120a4efb,0x10064afc,0x0030fd20 + .long 0x009e0072,0x0060fd20,0x00660000,0x00000072 + .long 0x006c0072,0x00600072,0x00660000,0x000000d0 + .long 0x00d0006c,0x006000d0,0x00660000,0x00000060 + .long 0x00600060,0x00600060,0x00660000,0x0000fd20 + .long 0x009e0072,0x0060fd20,0x00660000,0x00000066 + .long 0x00660066,0x00660066,0x00660000,0x000060ff + .long 0x00001bd8,0x60ff0000,0x1bd260ff,0x00001c50 + .long 0x10280000,0x12290000,0xb1016a10,0xf23c4400 + .long 0x80000000,0x1d7c000c,0xff644e75,0xf23c4400 + .long 0x00000000,0x1d7c0004,0xff644e75,0x006e0410 + .long 0xff661028,0x00001229,0x0000b101,0x6a10f23c + .long 0x4400ff80,0x00001d7c,0x000aff64,0x4e75f23c + .long 0x44007f80,0x00001d7c,0x0002ff64,0x4e751029 + .long 0x00001228,0x0000b101,0x6a16f229,0xd0800000 + .long 0xf2000018,0xf200001a,0x1d7c000a,0xff644e75 + .long 0xf229d080,0x0000f200,0x00181d7c,0x0002ff64 + .long 0x4e750200,0x00300000,0x00406008,0x02000030 + .long 0x00000080,0x2d40ff5c,0x122eff4e,0x66000276 + .long 0x020000c0,0x66000090,0x2d680004,0xff882d68 + .long 0x0008ff8c,0x30280000,0x0a408000,0x6a061d7c + .long 0x0008ff64,0x3d40ff84,0xf22ed080,0xff844e75 + .long 0x020000c0,0x666008ee,0x0003ff66,0x2d680004 + .long 0xff882d68,0x0008ff8c,0x30280000,0x0a408000 + .long 0x6a061d7c,0x0008ff64,0x3d40ff84,0xf22ed080 + .long 0xff84082e,0x0003ff62,0x66024e75,0x41eeff84 + .long 0x61ff0000,0x42664440,0x06406000,0x322eff84 + .long 0x02418000,0x02407fff,0x80413d40,0xff84f22e + .long 0xd040ff84,0x4e750c00,0x0040667e,0x3d680000 + .long 0xff842d68,0x0004ff88,0x2d680008,0xff8c61ff + .long 0x00001982,0x0c800000,0x007f6c00,0x00900c80 + .long 0xffffff81,0x67000178,0x6d0000f4,0xf23c8800 + .long 0x00000000,0xf22e9000,0xff5cf22e,0x481aff84 + .long 0xf201a800,0xf23c9000,0x00000000,0x83aeff64 + .long 0x2f02f22e,0xf080ff84,0x322eff84,0x34010281 + .long 0x00007fff,0x92800242,0x80008441,0x3d42ff84 + .long 0x241ff22e,0xd080ff84,0x4e753d68,0x0000ff84 + .long 0x2d680004,0xff882d68,0x0008ff8c,0x61ff0000 + .long 0x19040c80,0x000003ff,0x6c120c80,0xfffffc01 + .long 0x670000fc,0x6d000078,0x6000ff82,0x08ee0003 + .long 0xff660a2e,0x0080ff84,0x6a0608ee,0x0003ff64 + .long 0x122eff62,0x0201000b,0x661a41ee,0xff84222e + .long 0xff5c61ff,0x0000438a,0x812eff64,0xf22ed080 + .long 0xff844e75,0x2d6eff88,0xff942d6e,0xff8cff98 + .long 0x322eff84,0x2f022401,0x02810000,0x7fff0242 + .long 0x80009280,0x06810000,0x60000241,0x7fff8242 + .long 0x3d41ff90,0xf22ed040,0xff90241f,0x60acf23c + .long 0x88000000,0x0000f22e,0x9000ff5c,0xf22e481a + .long 0xff84f23c,0x90000000,0x0000f201,0xa80083ae + .long 0xff6400ae,0x00001048,0xff64122e,0xff620201 + .long 0x0013661c,0x082e0003,0xff6456c1,0x202eff5c + .long 0x61ff0000,0x43fa812e,0xff64f210,0xd0804e75 + .long 0x2f02322e,0xff842401,0x02810000,0x7fff0242 + .long 0x80009280,0x04810000,0x60000241,0x7fff8242 + .long 0x3d41ff84,0xf22ed040,0xff84241f,0x60b6f23c + .long 0x88000000,0x0000f22e,0x9000ff5c,0xf22e481a + .long 0xff84f201,0xa800f23c,0x90000000,0x000083ae + .long 0xff64f200,0x0098f23c,0x58b80002,0xf293ff74 + .long 0x6000fe7e,0x0c010004,0x6700fdb6,0x0c010005 + .long 0x67ff0000,0x18ae0c01,0x000367ff,0x000018b8 + .long 0xf228481a,0x0000f200,0xa800e198,0x1d40ff64 + .long 0x4e75122e,0xff4e6610,0x4a280000,0x6b024e75 + .long 0x1d7c0008,0xff644e75,0x0c010001,0x67400c01 + .long 0x00026724,0x0c010005,0x67ff0000,0x18660c01 + .long 0x000367ff,0x00001870,0x4a280000,0x6b024e75 + .long 0x1d7c0008,0xff644e75,0x4a280000,0x6b081d7c + .long 0x0002ff64,0x4e751d7c,0x000aff64,0x4e754a28 + .long 0x00006b08,0x1d7c0004,0xff644e75,0x1d7c000c + .long 0xff644e75,0x122eff4e,0x66280200,0x0030f200 + .long 0x9000f23c,0x88000000,0x0000f228,0x48010000 + .long 0xf23c9000,0x00000000,0xf200a800,0x81aeff64 + .long 0x4e750c01,0x0001672e,0x0c010002,0x674e0c01 + .long 0x00046710,0x0c010005,0x67ff0000,0x17d660ff + .long 0x000017e4,0x3d680000,0xff841d7c,0x0080ff88 + .long 0x41eeff84,0x60a44a28,0x00006b10,0xf23c4400 + .long 0x00000000,0x1d7c0004,0xff644e75,0xf23c4400 + .long 0x80000000,0x1d7c000c,0xff644e75,0xf228d080 + .long 0x00004a28,0x00006b08,0x1d7c0002,0xff644e75 + .long 0x1d7c000a,0xff644e75,0x122eff4e,0x6618f23c + .long 0x88000000,0x0000f228,0x48030000,0xf200a800 + .long 0x81aeff64,0x4e750c01,0x0001672e,0x0c010002 + .long 0x674e0c01,0x00046710,0x0c010005,0x67ff0000 + .long 0x174260ff,0x00001750,0x3d680000,0xff841d7c + .long 0x0080ff88,0x41eeff84,0x60b44a28,0x00006b10 + .long 0xf23c4400,0x00000000,0x1d7c0004,0xff644e75 + .long 0xf23c4400,0x80000000,0x1d7c000c,0xff644e75 + .long 0xf228d080,0x00004a28,0x00006b08,0x1d7c0002 + .long 0xff644e75,0x1d7c000a,0xff644e75,0x02000030 + .long 0x00000040,0x60080200,0x00300000,0x00802d40 + .long 0xff5c122e,0xff4e6600,0x025c0200,0x00c0667e + .long 0x2d680004,0xff882d68,0x0008ff8c,0x32280000 + .long 0x0881000f,0x3d41ff84,0xf22ed080,0xff844e75 + .long 0x020000c0,0x665808ee,0x0003ff66,0x2d680004 + .long 0xff882d68,0x0008ff8c,0x30280000,0x0880000f + .long 0x3d40ff84,0xf22ed080,0xff84082e,0x0003ff62 + .long 0x66024e75,0x41eeff84,0x61ff0000,0x3e0e4440 + .long 0x06406000,0x322eff84,0x02418000,0x02407fff + .long 0x80413d40,0xff84f22e,0xd040ff84,0x4e750c00 + .long 0x0040667e,0x3d680000,0xff842d68,0x0004ff88 + .long 0x2d680008,0xff8c61ff,0x0000152a,0x0c800000 + .long 0x007f6c00,0x00900c80,0xffffff81,0x67000170 + .long 0x6d0000ec,0xf23c8800,0x00000000,0xf22e9000 + .long 0xff5cf22e,0x4818ff84,0xf201a800,0xf23c9000 + .long 0x00000000,0x83aeff64,0x2f02f22e,0xf080ff84 + .long 0x322eff84,0x24010281,0x00007fff,0x92800242 + .long 0x80008441,0x3d42ff84,0x241ff22e,0xd080ff84 + .long 0x4e753d68,0x0000ff84,0x2d680004,0xff882d68 + .long 0x0008ff8c,0x61ff0000,0x14ac0c80,0x000003ff + .long 0x6c120c80,0xfffffc01,0x670000f4,0x6d000070 + .long 0x6000ff82,0x08ee0003,0xff6608ae,0x0007ff84 + .long 0x122eff62,0x0201000b,0x661a41ee,0xff84222e + .long 0xff5c61ff,0x00003f3a,0x812eff64,0xf22ed080 + .long 0xff844e75,0x2d6eff88,0xff942d6e,0xff8cff98 + .long 0x322eff84,0x2f022401,0x02810000,0x7fff0242 + .long 0x80009280,0x06810000,0x60000241,0x7fff8242 + .long 0x3d41ff90,0xf22ed040,0xff90241f,0x60acf23c + .long 0x88000000,0x0000f22e,0x9000ff5c,0xf22e4818 + .long 0xff84f23c,0x90000000,0x0000f201,0xa80083ae + .long 0xff6400ae,0x00001048,0xff64122e,0xff620201 + .long 0x0013661c,0x082e0003,0xff6456c1,0x202eff5c + .long 0x61ff0000,0x3faa812e,0xff64f210,0xd0804e75 + .long 0x2f02322e,0xff842401,0x02810000,0x7fff0242 + .long 0x80009280,0x04810000,0x60000241,0x7fff8242 + .long 0x3d41ff84,0xf22ed040,0xff84241f,0x60b6f23c + .long 0x88000000,0x0000f22e,0x9000ff5c,0xf22e4818 + .long 0xff84f201,0xa800f23c,0x90000000,0x000083ae + .long 0xff64f200,0x0098f23c,0x58b80002,0xf293ff74 + .long 0x6000fe86,0x0c010004,0x6700fdc6,0x0c010005 + .long 0x67ff0000,0x145e0c01,0x000367ff,0x00001468 + .long 0xf2284818,0x00000c01,0x00026708,0x1d7c0004 + .long 0xff644e75,0x1d7c0002,0xff644e75,0x4241122e + .long 0xff4fe709,0x822eff4e,0x6618f229,0xd0800000 + .long 0xf2284838,0x0000f200,0xa800e198,0x1d40ff64 + .long 0x4e75323b,0x120a4efb,0x10064afc,0x0030ffdc + .long 0xffdcffdc,0x006000f8,0x006e0000,0x0000ffdc + .long 0xffdcffdc,0x0060007c,0x006e0000,0x0000ffdc + .long 0xffdcffdc,0x0060007c,0x006e0000,0x00000060 + .long 0x00600060,0x00600060,0x006e0000,0x00000114 + .long 0x009c009c,0x006000bc,0x006e0000,0x0000006e + .long 0x006e006e,0x006e006e,0x006e0000,0x000061ff + .long 0x00001388,0x022e00f7,0xff644e75,0x61ff0000 + .long 0x137a022e,0x00f7ff64,0x4e753d68,0x0000ff84 + .long 0x20280004,0x08c0001f,0x2d40ff88,0x2d680008 + .long 0xff8c41ee,0xff846000,0xff422d69,0x0000ff84 + .long 0x20290004,0x08c0001f,0x2d40ff88,0x2d690008 + .long 0xff8c43ee,0xff846000,0xff223d69,0x0000ff90 + .long 0x3d680000,0xff842029,0x000408c0,0x001f2d40 + .long 0xff942028,0x000408c0,0x001f2d40,0xff882d69 + .long 0x0008ff98,0x2d680008,0xff8c43ee,0xff9041ee + .long 0xff846000,0xfee61028,0x00001229,0x0000b101 + .long 0x6b00ff78,0x4a006b02,0x4e751d7c,0x0008ff64 + .long 0x4e751028,0x00001229,0x0000b101,0x6b00ff7c + .long 0x4a006a02,0x4e751d7c,0x0008ff64,0x4e752d40 + .long 0xff5c4241,0x122eff4f,0xe709822e,0xff4e6600 + .long 0x02a03d69,0x0000ff90,0x2d690004,0xff942d69 + .long 0x0008ff98,0x3d680000,0xff842d68,0x0004ff88 + .long 0x2d680008,0xff8c61ff,0x0000119a,0x2f0061ff + .long 0x0000123e,0xd09f0c80,0xffffc001,0x670000f8 + .long 0x6d000064,0x0c800000,0x40006700,0x01da6e00 + .long 0x0122f22e,0xd080ff90,0xf22e9000,0xff5cf23c + .long 0x88000000,0x0000f22e,0x4827ff84,0xf201a800 + .long 0xf23c9000,0x00000000,0x83aeff64,0xf22ef080 + .long 0xff842f02,0x322eff84,0x24010281,0x00007fff + .long 0x02428000,0x92808242,0x3d41ff84,0x241ff22e + .long 0xd080ff84,0x4e75f22e,0xd080ff90,0xf22e9000 + .long 0xff5cf23c,0x88000000,0x0000f22e,0x4827ff84 + .long 0xf201a800,0xf23c9000,0x00000000,0x83aeff64 + .long 0x00ae0000,0x1048ff64,0x122eff62,0x02010013 + .long 0x6620082e,0x0003ff64,0x56c1202e,0xff5c0200 + .long 0x003061ff,0x00003c98,0x812eff64,0xf210d080 + .long 0x4e75f22e,0xf080ff84,0x2f02322e,0xff842401 + .long 0x02810000,0x7fff9280,0x04810000,0x60000241 + .long 0x7fff0242,0x80008242,0x3d41ff84,0x241ff22e + .long 0xd040ff84,0x60acf22e,0xd080ff90,0xf22e9000 + .long 0xff5cf23c,0x88000000,0x0000f22e,0x4827ff84 + .long 0xf201a800,0xf23c9000,0x00000000,0x83aeff64 + .long 0xf2000098,0xf23c58b8,0x0002f293,0xff646000 + .long 0xff0c08ee,0x0003ff66,0xf22ed080,0xff90f23c + .long 0x90000000,0x0010f23c,0x88000000,0x0000f22e + .long 0x4827ff84,0xf201a800,0xf23c9000,0x00000000 + .long 0x83aeff64,0x122eff62,0x0201000b,0x6620f22e + .long 0xf080ff84,0x41eeff84,0x222eff5c,0x61ff0000 + .long 0x3b56812e,0xff64f22e,0xd080ff84,0x4e75f22e + .long 0xd040ff90,0xf22e9000,0xff5cf23c,0x88000000 + .long 0x0000f22e,0x48a7ff84,0xf23c9000,0x00000000 + .long 0xf22ef040,0xff842f02,0x322eff84,0x24010281 + .long 0x00007fff,0x02428000,0x92800681,0x00006000 + .long 0x02417fff,0x82423d41,0xff84241f,0xf22ed040 + .long 0xff846000,0xff8af22e,0xd080ff90,0xf22e9000 + .long 0xff5cf23c,0x88000000,0x0000f22e,0x4827ff84 + .long 0xf201a800,0xf23c9000,0x00000000,0x83aeff64 + .long 0xf2000098,0xf23c58b8,0x0002f292,0xfe20f294 + .long 0xff12f22e,0xd040ff90,0x222eff5c,0x020100c0 + .long 0x00010010,0xf2019000,0xf23c8800,0x00000000 + .long 0xf22e48a7,0xff84f23c,0x90000000,0x0000f200 + .long 0x0498f23c,0x58b80002,0xf293fde2,0x6000fed4 + .long 0x323b120a,0x4efb1006,0x4afc0030,0xfd560072 + .long 0x0078006c,0xfd560066,0x00000000,0x00720072 + .long 0x0060006c,0x00720066,0x00000000,0x007e0060 + .long 0x007e006c,0x007e0066,0x00000000,0x006c006c + .long 0x006c006c,0x006c0066,0x00000000,0xfd560072 + .long 0x0078006c,0xfd560066,0x00000000,0x00660066 + .long 0x00660066,0x00660066,0x00000000,0x60ff0000 + .long 0x101e60ff,0x00000f94,0x60ff0000,0x0f8e60ff + .long 0xffffed0e,0x60ffffff,0xed6260ff,0xffffed2e + .long 0x2d40ff5c,0x4241122e,0xff4fe709,0x822eff4e + .long 0x6600027c,0x3d690000,0xff902d69,0x0004ff94 + .long 0x2d690008,0xff983d68,0x0000ff84,0x2d680004 + .long 0xff882d68,0x0008ff8c,0x61ff0000,0x0e582f00 + .long 0x61ff0000,0x0efc4497,0xd197322e,0xff5eec09 + .long 0x201f0c80,0xffffc001,0x6f000064,0x0c800000 + .long 0x3fff6700,0x01b66e00,0x0100f22e,0xd080ff90 + .long 0xf22e9000,0xff5cf23c,0x88000000,0x0000f22e + .long 0x4824ff84,0xf201a800,0xf23c9000,0x00000000 + .long 0x83aeff64,0xf22ef080,0xff842f02,0x322eff84 + .long 0x24010281,0x00007fff,0x02428000,0x92808242 + .long 0x3d41ff84,0x241ff22e,0xd080ff84,0x4e75f22e + .long 0xd080ff90,0xf22e9000,0xff5cf23c,0x88000000 + .long 0x0000f22e,0x4824ff84,0xf201a800,0xf23c9000 + .long 0x00000000,0x83aeff64,0xf227e001,0x3217dffc + .long 0x0000000c,0x02810000,0x7fff9280,0x0c810000 + .long 0x7fff6d90,0x006e1048,0xff66122e,0xff620201 + .long 0x00136620,0x082e0003,0xff6456c1,0x202eff5c + .long 0x02000030,0x61ff0000,0x3936812e,0xff64f210 + .long 0xd0804e75,0xf22ef080,0xff842f02,0x322eff84 + .long 0x24010281,0x00007fff,0x02428000,0x92800481 + .long 0x00006000,0x02417fff,0x82423d41,0xff84241f + .long 0xf22ed040,0xff8460ac,0x08ee0003,0xff66f22e + .long 0xd080ff90,0xf23c9000,0x00000010,0xf23c8800 + .long 0x00000000,0xf22e4824,0xff84f201,0xa800f23c + .long 0x90000000,0x000083ae,0xff64122e,0xff620201 + .long 0x000b6620,0xf22ef080,0xff8441ee,0xff84222e + .long 0xff5c61ff,0x00003830,0x812eff64,0xf22ed080 + .long 0xff844e75,0xf22ed040,0xff90f22e,0x9000ff5c + .long 0xf23c8800,0x00000000,0xf22e48a4,0xff84f23c + .long 0x90000000,0x0000f22e,0xf040ff84,0x2f02322e + .long 0xff842401,0x02810000,0x7fff0242,0x80009280 + .long 0x06810000,0x60000241,0x7fff8242,0x3d41ff84 + .long 0x241ff22e,0xd040ff84,0x608af22e,0xd080ff90 + .long 0xf22e9000,0xff5cf23c,0x88000000,0x0000f22e + .long 0x4824ff84,0xf201a800,0xf23c9000,0x00000000 + .long 0x83aeff64,0xf2000098,0xf23c58b8,0x0001f292 + .long 0xfe44f294,0xff14f22e,0xd040ff90,0x42810001 + .long 0x0010f201,0x9000f23c,0x88000000,0x0000f22e + .long 0x48a4ff84,0xf23c9000,0x00000000,0xf2000498 + .long 0xf23c58b8,0x0001f293,0xfe0c6000,0xfedc323b + .long 0x120a4efb,0x10064afc,0x0030fd7a,0x00720078 + .long 0x0060fd7a,0x00660000,0x00000078,0x006c0078 + .long 0x00600078,0x00660000,0x0000007e,0x007e006c + .long 0x0060007e,0x00660000,0x00000060,0x00600060 + .long 0x00600060,0x00660000,0x0000fd7a,0x00720078 + .long 0x0060fd7a,0x00660000,0x00000066,0x00660066 + .long 0x00660066,0x00660000,0x000060ff,0x00000c7c + .long 0x60ff0000,0x0c7660ff,0x00000cf4,0x60ffffff + .long 0xf0ce60ff,0xfffff09c,0x60ffffff,0xf0f40200 + .long 0x00300000,0x00406008,0x02000030,0x00000080 + .long 0x2d40ff5c,0x4241122e,0xff4fe709,0x822eff4e + .long 0x6600024c,0x61ff0000,0x0a5cf22e,0xd080ff90 + .long 0xf23c8800,0x00000000,0xf22e9000,0xff5cf22e + .long 0x4822ff84,0xf23c9000,0x00000000,0xf201a800 + .long 0x83aeff64,0xf281003c,0x2f02f227,0xe001322e + .long 0xff5eec09,0x34170282,0x00007fff,0x9480b4bb + .long 0x14246c38,0xb4bb142a,0x6d0000b8,0x67000184 + .long 0x32170241,0x80008242,0x3e81f21f,0xd080241f + .long 0x4e754e75,0x00007fff,0x0000407f,0x000043ff + .long 0x00000000,0x00003f81,0x00003c01,0x00ae0000 + .long 0x1048ff64,0x122eff62,0x02010013,0x6624dffc + .long 0x0000000c,0x082e0003,0xff6456c1,0x202eff5c + .long 0x61ff0000,0x366a812e,0xff64f210,0xd080241f + .long 0x4e75122e,0xff5c0201,0x00c0661a,0x32170241 + .long 0x80000482,0x00006000,0x02427fff,0x82423e81 + .long 0xf21fd040,0x60bef22e,0xd080ff90,0x222eff5c + .long 0x02010030,0xf2019000,0xf22e4822,0xff84f23c + .long 0x90000000,0x0000dffc,0x0000000c,0xf227e001 + .long 0x60ba08ee,0x0003ff66,0xdffc0000,0x000cf22e + .long 0xd080ff90,0xf23c9000,0x00000010,0xf23c8800 + .long 0x00000000,0xf22e4822,0xff84f23c,0x90000000 + .long 0x0000f201,0xa80083ae,0xff64122e,0xff620201 + .long 0x000b6622,0xf22ef080,0xff8441ee,0xff84222e + .long 0xff5c61ff,0x000034ba,0x812eff64,0xf22ed080 + .long 0xff84241f,0x4e75f22e,0xd040ff90,0x222eff5c + .long 0x020100c0,0x664ef22e,0x9000ff5c,0xf23c8800 + .long 0x00000000,0xf22e48a2,0xff84f23c,0x90000000 + .long 0x0000f22e,0xf040ff84,0x322eff84,0x24010281 + .long 0x00007fff,0x02428000,0x92800681,0x00006000 + .long 0x02417fff,0x82423d41,0xff84f22e,0xd040ff84 + .long 0x6000ff82,0x222eff5c,0x02010030,0xf2019000 + .long 0x60aa222e,0xff5c0201,0x00c06700,0xfe74222f + .long 0x00040c81,0x80000000,0x6600fe66,0x4aaf0008 + .long 0x6600fe5e,0x082e0001,0xff666700,0xfe54f22e + .long 0xd040ff90,0x222eff5c,0x020100c0,0x00010010 + .long 0xf2019000,0xf23c8800,0x00000000,0xf22e48a2 + .long 0xff84f23c,0x90000000,0x0000f200,0x0018f200 + .long 0x0498f200,0x0438f292,0xfeca6000,0xfe14323b + .long 0x120a4efb,0x10064afc,0x0030fdaa,0x00e4011c + .long 0x0060fdaa,0x00660000,0x000000bc,0x006c011c + .long 0x006000bc,0x00660000,0x00000130,0x0130010c + .long 0x00600130,0x00660000,0x00000060,0x00600060 + .long 0x00600060,0x00660000,0x0000fdaa,0x00e4011c + .long 0x0060fdaa,0x00660000,0x00000066,0x00660066 + .long 0x00660066,0x00660000,0x000060ff,0x0000097c + .long 0x60ff0000,0x09761028,0x00001229,0x0000b101 + .long 0x6b000016,0x4a006b2e,0xf23c4400,0x00000000 + .long 0x1d7c0004,0xff644e75,0x122eff5f,0x02010030 + .long 0x0c010020,0x6710f23c,0x44000000,0x00001d7c + .long 0x0004ff64,0x4e75f23c,0x44008000,0x00001d7c + .long 0x000cff64,0x4e753d68,0x0000ff84,0x2d680004 + .long 0xff882d68,0x0008ff8c,0x61ff0000,0x0828426e + .long 0xff9042ae,0xff9442ae,0xff986000,0xfcce3d69 + .long 0x0000ff90,0x2d690004,0xff942d69,0x0008ff98 + .long 0x61ff0000,0x08ac426e,0xff8442ae,0xff8842ae + .long 0xff8c6000,0xfca61028,0x00001229,0x0000b300 + .long 0x6bff0000,0x094af228,0xd0800000,0x4a280000 + .long 0x6a1c1d7c,0x000aff64,0x4e75f229,0xd0800000 + .long 0x4a290000,0x6a081d7c,0x000aff64,0x4e751d7c + .long 0x0002ff64,0x4e750200,0x00300000,0x00406008 + .long 0x02000030,0x00000080,0x2d40ff5c,0x4241122e + .long 0xff4fe709,0x822eff4e,0x6600024c,0x61ff0000 + .long 0x0694f22e,0xd080ff90,0xf23c8800,0x00000000 + .long 0xf22e9000,0xff5cf22e,0x4828ff84,0xf23c9000 + .long 0x00000000,0xf201a800,0x83aeff64,0xf281003c + .long 0x2f02f227,0xe001322e,0xff5eec09,0x34170282 + .long 0x00007fff,0x9480b4bb,0x14246c38,0xb4bb142a + .long 0x6d0000b8,0x67000184,0x32170241,0x80008242 + .long 0x3e81f21f,0xd080241f,0x4e754e75,0x00007fff + .long 0x0000407f,0x000043ff,0x00000000,0x00003f81 + .long 0x00003c01,0x00ae0000,0x1048ff64,0x122eff62 + .long 0x02010013,0x6624dffc,0x0000000c,0x082e0003 + .long 0xff6456c1,0x202eff5c,0x61ff0000,0x32a2812e + .long 0xff64f210,0xd080241f,0x4e75122e,0xff5c0201 + .long 0x00c0661a,0x32170241,0x80000482,0x00006000 + .long 0x02427fff,0x82423e81,0xf21fd040,0x60bef22e + .long 0xd080ff90,0x222eff5c,0x02010030,0xf2019000 + .long 0xf22e4828,0xff84f23c,0x90000000,0x0000dffc + .long 0x0000000c,0xf227e001,0x60ba08ee,0x0003ff66 + .long 0xdffc0000,0x000cf22e,0xd080ff90,0xf23c9000 + .long 0x00000010,0xf23c8800,0x00000000,0xf22e4828 + .long 0xff84f23c,0x90000000,0x0000f201,0xa80083ae + .long 0xff64122e,0xff620201,0x000b6622,0xf22ef080 + .long 0xff8441ee,0xff84222e,0xff5c61ff,0x000030f2 + .long 0x812eff64,0xf22ed080,0xff84241f,0x4e75f22e + .long 0xd040ff90,0x222eff5c,0x020100c0,0x664ef22e + .long 0x9000ff5c,0xf23c8800,0x00000000,0xf22e48a8 + .long 0xff84f23c,0x90000000,0x0000f22e,0xf040ff84 + .long 0x322eff84,0x24010281,0x00007fff,0x02428000 + .long 0x92800681,0x00006000,0x02417fff,0x82423d41 + .long 0xff84f22e,0xd040ff84,0x6000ff82,0x222eff5c + .long 0x02010030,0xf2019000,0x60aa222e,0xff5c0201 + .long 0x00c06700,0xfe74222f,0x00040c81,0x80000000 + .long 0x6600fe66,0x4aaf0008,0x6600fe5e,0x082e0001 + .long 0xff666700,0xfe54f22e,0xd040ff90,0x222eff5c + .long 0x020100c0,0x00010010,0xf2019000,0xf23c8800 + .long 0x00000000,0xf22e48a8,0xff84f23c,0x90000000 + .long 0x0000f200,0x0018f200,0x0498f200,0x0438f292 + .long 0xfeca6000,0xfe14323b,0x120a4efb,0x10064afc + .long 0x0030fdaa,0x00e2011a,0x0060fdaa,0x00660000 + .long 0x000000ba,0x006c011a,0x006000ba,0x00660000 + .long 0x00000130,0x0130010a,0x00600130,0x00660000 + .long 0x00000060,0x00600060,0x00600060,0x00660000 + .long 0x0000fdaa,0x00e2011a,0x0060fdaa,0x00660000 + .long 0x00000066,0x00660066,0x00660066,0x00660000 + .long 0x000060ff,0x000005b4,0x60ff0000,0x05ae1028 + .long 0x00001229,0x0000b300,0x6a144a00,0x6b2ef23c + .long 0x44000000,0x00001d7c,0x0004ff64,0x4e75122e + .long 0xff5f0201,0x00300c01,0x00206710,0xf23c4400 + .long 0x00000000,0x1d7c0004,0xff644e75,0xf23c4400 + .long 0x80000000,0x1d7c000c,0xff644e75,0x3d680000 + .long 0xff842d68,0x0004ff88,0x2d680008,0xff8c61ff + .long 0x00000462,0x426eff90,0x42aeff94,0x42aeff98 + .long 0x6000fcd0,0x3d690000,0xff902d69,0x0004ff94 + .long 0x2d690008,0xff9861ff,0x000004e6,0x426eff84 + .long 0x42aeff88,0x42aeff8c,0x6000fca8,0x10280000 + .long 0x12290000,0xb3006aff,0x00000584,0xf228d080 + .long 0x0000f200,0x001af293,0x001e1d7c,0x000aff64 + .long 0x4e75f229,0xd0800000,0x4a290000,0x6a081d7c + .long 0x000aff64,0x4e751d7c,0x0002ff64,0x4e750200 + .long 0x00300000,0x00406008,0x02000030,0x00000080 + .long 0x2d40ff5c,0x4241122e,0xff4e6600,0x02744a28 + .long 0x00006bff,0x00000528,0x020000c0,0x6648f22e + .long 0x9000ff5c,0xf23c8800,0x00000000,0xf2104804 + .long 0xf201a800,0x83aeff64,0x4e754a28,0x00006bff + .long 0x000004fc,0x020000c0,0x661c3d68,0x0000ff84 + .long 0x2d680004,0xff882d68,0x0008ff8c,0x61ff0000 + .long 0x03ae6000,0x003e0c00,0x00406600,0x00843d68 + .long 0x0000ff84,0x2d680004,0xff882d68,0x0008ff8c + .long 0x61ff0000,0x038a0c80,0x0000007e,0x67000098 + .long 0x6e00009e,0x0c80ffff,0xff806700,0x01a46d00 + .long 0x0120f23c,0x88000000,0x0000f22e,0x9000ff5c + .long 0xf22e4804,0xff84f201,0xa800f23c,0x90000000 + .long 0x000083ae,0xff642f02,0xf22ef080,0xff84322e + .long 0xff842401,0x02810000,0x7fff9280,0x02428000 + .long 0x84413d42,0xff84241f,0xf22ed080,0xff844e75 + .long 0x3d680000,0xff842d68,0x0004ff88,0x2d680008 + .long 0xff8c61ff,0x00000308,0x0c800000,0x03fe6700 + .long 0x00166e1c,0x0c80ffff,0xfc006700,0x01246d00 + .long 0x00a06000,0xff7e082e,0x0000ff85,0x6600ff74 + .long 0x08ee0003,0xff66f23c,0x90000000,0x0010f23c + .long 0x88000000,0x0000f22e,0x4804ff84,0xf201a800 + .long 0xf23c9000,0x00000000,0x83aeff64,0x122eff62 + .long 0x0201000b,0x6620f22e,0xf080ff84,0x41eeff84 + .long 0x222eff5c,0x61ff0000,0x2d28812e,0xff64f22e + .long 0xd080ff84,0x4e752d6e,0xff88ff94,0x2d6eff8c + .long 0xff98322e,0xff842f02,0x24010281,0x00007fff + .long 0x02428000,0x92800681,0x00006000,0x02417fff + .long 0x82423d41,0xff90f22e,0xd040ff90,0x241f60a6 + .long 0xf23c8800,0x00000000,0xf22e9000,0xff5cf22e + .long 0x4804ff84,0xf23c9000,0x00000000,0xf201a800 + .long 0x83aeff64,0x00ae0000,0x1048ff64,0x122eff62 + .long 0x02010013,0x661c082e,0x0003ff64,0x56c1202e + .long 0xff5c61ff,0x00002d98,0x812eff64,0xf210d080 + .long 0x4e752f02,0x322eff84,0x24010281,0x00007fff + .long 0x02428000,0x92800481,0x00006000,0x02417fff + .long 0x82423d41,0xff84f22e,0xd040ff84,0x241f60b6 + .long 0x082e0000,0xff856600,0xff78f23c,0x88000000 + .long 0x0000f22e,0x9000ff5c,0xf22e4804,0xff84f201 + .long 0xa800f23c,0x90000000,0x000083ae,0xff64f200 + .long 0x0080f23c,0x58b80001,0xf293ff6a,0x6000fe48 + .long 0x0c010004,0x6700fdb4,0x0c010001,0x67160c01 + .long 0x00026736,0x0c010005,0x67ff0000,0x023660ff + .long 0x00000244,0x4a280000,0x6b10f23c,0x44000000 + .long 0x00001d7c,0x0004ff64,0x4e75f23c,0x44008000 + .long 0x00001d7c,0x000cff64,0x4e754a28,0x00006bff + .long 0x0000026c,0xf228d080,0x00001d7c,0x0002ff64 + .long 0x4e752d68,0x0004ff88,0x2d690004,0xff942d68 + .long 0x0008ff8c,0x2d690008,0xff983028,0x00003229 + .long 0x00003d40,0xff843d41,0xff900240,0x7fff0241 + .long 0x7fff3d40,0xff543d41,0xff56b041,0x6cff0000 + .long 0x005c61ff,0x0000015a,0x2f000c2e,0x0004ff4e + .long 0x661041ee,0xff8461ff,0x00002940,0x44403d40 + .long 0xff54302e,0xff560440,0x0042b06e,0xff546c1a + .long 0x302eff54,0xd06f0002,0x322eff84,0x02418000 + .long 0x80413d40,0xff84201f,0x4e75026e,0x8000ff84 + .long 0x08ee0000,0xff85201f,0x4e7561ff,0x00000056 + .long 0x2f000c2e,0x0004ff4f,0x661041ee,0xff9061ff + .long 0x000028e8,0x44403d40,0xff56302e,0xff540440 + .long 0x0042b06e,0xff566c1a,0x302eff56,0xd06f0002 + .long 0x322eff90,0x02418000,0x80413d40,0xff90201f + .long 0x4e75026e,0x8000ff90,0x08ee0000,0xff91201f + .long 0x4e75322e,0xff843001,0x02810000,0x7fff0240 + .long 0x80000040,0x3fff3d40,0xff840c2e,0x0004ff4e + .long 0x670a203c,0x00003fff,0x90814e75,0x41eeff84 + .long 0x61ff0000,0x28764480,0x220060e6,0x0c2e0004 + .long 0xff4e673a,0x322eff84,0x02810000,0x7fff026e + .long 0x8000ff84,0x08010000,0x6712006e,0x3fffff84 + .long 0x203c0000,0x3fff9081,0xe2804e75,0x006e3ffe + .long 0xff84203c,0x00003ffe,0x9081e280,0x4e7541ee + .long 0xff8461ff,0x00002824,0x08000000,0x6710006e + .long 0x3fffff84,0x06800000,0x3fffe280,0x4e75006e + .long 0x3ffeff84,0x06800000,0x3ffee280,0x4e75322e + .long 0xff903001,0x02810000,0x7fff0240,0x80000040 + .long 0x3fff3d40,0xff900c2e,0x0004ff4f,0x670a203c + .long 0x00003fff,0x90814e75,0x41eeff90,0x61ff0000 + .long 0x27ca4480,0x220060e6,0x0c2e0005,0xff4f6732 + .long 0x0c2e0003,0xff4f673e,0x0c2e0003,0xff4e6714 + .long 0x08ee0006,0xff7000ae,0x01004080,0xff6441ee + .long 0xff6c6042,0x00ae0100,0x0000ff64,0x41eeff6c + .long 0x603400ae,0x01004080,0xff6408ee,0x0006ff7c + .long 0x41eeff78,0x602041ee,0xff780c2e,0x0005ff4e + .long 0x66ff0000,0x000c00ae,0x00004080,0xff6400ae + .long 0x01000000,0xff640828,0x00070000,0x670800ae + .long 0x08000000,0xff64f210,0xd0804e75,0x00ae0100 + .long 0x2080ff64,0xf23bd080,0x01700000,0x00084e75 + .long 0x7fff0000,0xffffffff,0xffffffff,0x2d40ff54 + .long 0x302eff42,0x4281122e,0xff64e099,0xf2018800 + .long 0x323b0206,0x4efb1002,0x02340040,0x02f8030c + .long 0x03200334,0x0348035c,0x03660352,0x033e032a + .long 0x03160302,0x004a0238,0x023a0276,0x0054009e + .long 0x0102014c,0x01b201fc,0x021801d8,0x018c0128 + .long 0x00de007a,0x02b6025a,0xf2810006,0x6000032a + .long 0x4e75f28e,0x00066000,0x03204e75,0xf2920022 + .long 0x082e0000,0xff646700,0x031000ae,0x00008080 + .long 0xff64082e,0x0007ff62,0x6600032c,0x600002fa + .long 0x4e75f29d,0x00066000,0x02f0082e,0x0000ff64 + .long 0x671200ae,0x00008080,0xff64082e,0x0007ff62 + .long 0x66000304,0x4e75f293,0x0022082e,0x0000ff64 + .long 0x670002c6,0x00ae0000,0x8080ff64,0x082e0007 + .long 0xff626600,0x02e26000,0x02b0082e,0x0000ff64 + .long 0x671200ae,0x00008080,0xff64082e,0x0007ff62 + .long 0x660002c4,0x4e75f29c,0x00066000,0x028c082e + .long 0x0000ff64,0x671200ae,0x00008080,0xff64082e + .long 0x0007ff62,0x660002a0,0x4e75f294,0x0022082e + .long 0x0000ff64,0x67000262,0x00ae0000,0x8080ff64 + .long 0x082e0007,0xff626600,0x027e6000,0x024c4e75 + .long 0xf29b0006,0x60000242,0x082e0000,0xff646712 + .long 0x00ae0000,0x8080ff64,0x082e0007,0xff626600 + .long 0x02564e75,0xf2950022,0x082e0000,0xff646700 + .long 0x021800ae,0x00008080,0xff64082e,0x0007ff62 + .long 0x66000234,0x60000202,0x082e0000,0xff646712 + .long 0x00ae0000,0x8080ff64,0x082e0007,0xff626600 + .long 0x02164e75,0xf29a0006,0x600001de,0x082e0000 + .long 0xff646700,0x001400ae,0x00008080,0xff64082e + .long 0x0007ff62,0x660001f0,0x4e75f296,0x0022082e + .long 0x0000ff64,0x670001b2,0x00ae0000,0x8080ff64 + .long 0x082e0007,0xff626600,0x01ce6000,0x019c4e75 + .long 0xf2990006,0x60000192,0x082e0000,0xff646712 + .long 0x00ae0000,0x8080ff64,0x082e0007,0xff626600 + .long 0x01a64e75,0xf2970018,0x00ae0000,0x8080ff64 + .long 0x082e0007,0xff626600,0x018e6000,0x015c4e75 + .long 0xf2980006,0x60000152,0x00ae0000,0x8080ff64 + .long 0x082e0007,0xff626600,0x016e4e75,0x6000013a + .long 0x4e75082e,0x0000ff64,0x6700012e,0x00ae0000 + .long 0x8080ff64,0x082e0007,0xff626600,0x014a6000 + .long 0x0118082e,0x0000ff64,0x671200ae,0x00008080 + .long 0xff64082e,0x0007ff62,0x6600012c,0x4e75f291 + .long 0x0022082e,0x0000ff64,0x670000ee,0x00ae0000 + .long 0x8080ff64,0x082e0007,0xff626600,0x010a6000 + .long 0x00d8082e,0x0000ff64,0x671200ae,0x00008080 + .long 0xff64082e,0x0007ff62,0x660000ec,0x4e75f29e + .long 0x0022082e,0x0000ff64,0x670000ae,0x00ae0000 + .long 0x8080ff64,0x082e0007,0xff626600,0x00ca6000 + .long 0x0098082e,0x0000ff64,0x67000014,0x00ae0000 + .long 0x8080ff64,0x082e0007,0xff626600,0x00aa4e75 + .long 0xf2820006,0x60000072,0x4e75f28d,0x00066000 + .long 0x00684e75,0xf2830006,0x6000005e,0x4e75f28c + .long 0x00066000,0x00544e75,0xf2840006,0x6000004a + .long 0x4e75f28b,0x00066000,0x00404e75,0xf2850006 + .long 0x60000036,0x4e75f28a,0x00066000,0x002c4e75 + .long 0xf2860006,0x60000022,0x4e75f289,0x00066000 + .long 0x00184e75,0xf2870006,0x6000000e,0x4e75f288 + .long 0x00066000,0x00044e75,0x122eff41,0x02410007 + .long 0x61ff0000,0x1d665340,0x61ff0000,0x1dd00c40 + .long 0xffff6602,0x4e75202e,0xff54d0ae,0xff685880 + .long 0x2d400006,0x4e751d7c,0x0002ff4a,0x4e75302e + .long 0xff424281,0x122eff64,0xe099f201,0x8800323b + .long 0x02064efb,0x1002021e,0x004002e4,0x02f002fc + .long 0x03080314,0x03200326,0x031a030e,0x030202f6 + .long 0x02ea0046,0x02200224,0x0260004c,0x009200f8 + .long 0x013e01a4,0x01ea0202,0x01c4017e,0x011800d2 + .long 0x006c02a2,0x0240f281,0x02ea4e75,0xf28e02e4 + .long 0x4e75f292,0x02de082e,0x0000ff64,0x671200ae + .long 0x00008080,0xff64082e,0x0007ff62,0x660002cc + .long 0x4e75f29d,0x00044e75,0x082e0000,0xff646700 + .long 0x02b200ae,0x00008080,0xff64082e,0x0007ff62 + .long 0x660002a8,0x6000029c,0xf293001e,0x082e0000 + .long 0xff646712,0x00ae0000,0x8080ff64,0x082e0007 + .long 0xff626600,0x02864e75,0x082e0000,0xff646700 + .long 0x027200ae,0x00008080,0xff64082e,0x0007ff62 + .long 0x66000268,0x6000025c,0xf29c0004,0x4e75082e + .long 0x0000ff64,0x6700024c,0x00ae0000,0x8080ff64 + .long 0x082e0007,0xff626600,0x02426000,0x0236f294 + .long 0x0232082e,0x0000ff64,0x671200ae,0x00008080 + .long 0xff64082e,0x0007ff62,0x66000220,0x4e75f29b + .long 0x00044e75,0x082e0000,0xff646700,0x020600ae + .long 0x00008080,0xff64082e,0x0007ff62,0x660001fc + .long 0x600001f0,0xf295001e,0x082e0000,0xff646712 + .long 0x00ae0000,0x8080ff64,0x082e0007,0xff626600 + .long 0x01da4e75,0x082e0000,0xff646700,0x01c600ae + .long 0x00008080,0xff64082e,0x0007ff62,0x660001bc + .long 0x600001b0,0xf29a0004,0x4e75082e,0x0000ff64 + .long 0x670001a0,0x00ae0000,0x8080ff64,0x082e0007 + .long 0xff626600,0x01966000,0x018af296,0x0186082e + .long 0x0000ff64,0x671200ae,0x00008080,0xff64082e + .long 0x0007ff62,0x66000174,0x4e75f299,0x00044e75 + .long 0x082e0000,0xff646700,0x015a00ae,0x00008080 + .long 0xff64082e,0x0007ff62,0x66000150,0x60000144 + .long 0xf2970140,0x00ae0000,0x8080ff64,0x082e0007 + .long 0xff626600,0x01364e75,0xf2980004,0x4e7500ae + .long 0x00008080,0xff64082e,0x0007ff62,0x6600011c + .long 0x60000110,0x4e756000,0x010a082e,0x0000ff64 + .long 0x671200ae,0x00008080,0xff64082e,0x0007ff62 + .long 0x660000f8,0x4e75082e,0x0000ff64,0x670000e4 + .long 0x00ae0000,0x8080ff64,0x082e0007,0xff626600 + .long 0x00da6000,0x00cef291,0x0020082e,0x0000ff64 + .long 0x67000014,0x00ae0000,0x8080ff64,0x082e0007 + .long 0xff626600,0x00b64e75,0x082e0000,0xff646700 + .long 0x00a200ae,0x00008080,0xff64082e,0x0007ff62 + .long 0x66000098,0x6000008c,0xf29e0020,0x082e0000 + .long 0xff646700,0x001400ae,0x00008080,0xff64082e + .long 0x0007ff62,0x66000074,0x4e75082e,0x0000ff64 + .long 0x67000060,0x00ae0000,0x8080ff64,0x082e0007 + .long 0xff626600,0x00566000,0x004af282,0x00464e75 + .long 0xf28d0040,0x4e75f283,0x003a4e75,0xf28c0034 + .long 0x4e75f284,0x002e4e75,0xf28b0028,0x4e75f285 + .long 0x00224e75,0xf28a001c,0x4e75f286,0x00164e75 + .long 0xf2890010,0x4e75f287,0x000a4e75,0xf2880004 + .long 0x4e751d7c,0x0001ff4a,0x4e751d7c,0x0002ff4a + .long 0x4e75302e,0xff424281,0x122eff64,0xe099f201 + .long 0x8800323b,0x02064efb,0x10020208,0x004002ac + .long 0x02cc02ec,0x030c032c,0x034c035c,0x033c031c + .long 0x02fc02dc,0x02bc0050,0x020e0214,0x02440060 + .long 0x00a400fa,0x013e0194,0x01d801f0,0x01b60172 + .long 0x011c00d8,0x00820278,0x022cf281,0x00084200 + .long 0x6000032e,0x50c06000,0x0328f28e,0x00084200 + .long 0x6000031e,0x50c06000,0x0318f292,0x001a4200 + .long 0x082e0000,0xff646700,0x030800ae,0x00008080 + .long 0xff646000,0x02f250c0,0x600002f6,0xf29d0008 + .long 0x42006000,0x02ec50c0,0x082e0000,0xff646700 + .long 0x02e000ae,0x00008080,0xff646000,0x02caf293 + .long 0x001a4200,0x082e0000,0xff646700,0x02c400ae + .long 0x00008080,0xff646000,0x02ae50c0,0x082e0000 + .long 0xff646700,0x02ac00ae,0x00008080,0xff646000 + .long 0x0296f29c,0x00084200,0x60000296,0x50c0082e + .long 0x0000ff64,0x6700028a,0x00ae0000,0x8080ff64 + .long 0x60000274,0xf294001a,0x4200082e,0x0000ff64 + .long 0x6700026e,0x00ae0000,0x8080ff64,0x60000258 + .long 0x50c06000,0x025cf29b,0x00084200,0x60000252 + .long 0x50c0082e,0x0000ff64,0x67000246,0x00ae0000 + .long 0x8080ff64,0x60000230,0xf295001a,0x4200082e + .long 0x0000ff64,0x6700022a,0x00ae0000,0x8080ff64 + .long 0x60000214,0x50c0082e,0x0000ff64,0x67000212 + .long 0x00ae0000,0x8080ff64,0x600001fc,0xf29a0008 + .long 0x42006000,0x01fc50c0,0x082e0000,0xff646700 + .long 0x01f000ae,0x00008080,0xff646000,0x01daf296 + .long 0x001a4200,0x082e0000,0xff646700,0x01d400ae + .long 0x00008080,0xff646000,0x01be50c0,0x600001c2 + .long 0xf2990008,0x42006000,0x01b850c0,0x082e0000 + .long 0xff646700,0x01ac00ae,0x00008080,0xff646000 + .long 0x0196f297,0x00104200,0x00ae0000,0x8080ff64 + .long 0x60000184,0x50c06000,0x0188f298,0x00084200 + .long 0x6000017e,0x50c000ae,0x00008080,0xff646000 + .long 0x01664200,0x6000016a,0x50c06000,0x01644200 + .long 0x082e0000,0xff646700,0x015800ae,0x00008080 + .long 0xff646000,0x014250c0,0x082e0000,0xff646700 + .long 0x014000ae,0x00008080,0xff646000,0x012af291 + .long 0x001a4200,0x082e0000,0xff646700,0x012400ae + .long 0x00008080,0xff646000,0x010e50c0,0x082e0000 + .long 0xff646700,0x010c00ae,0x00008080,0xff646000 + .long 0x00f6f29e,0x001a4200,0x082e0000,0xff646700 + .long 0x00f000ae,0x00008080,0xff646000,0x00da50c0 + .long 0x082e0000,0xff646700,0x00d800ae,0x00008080 + .long 0xff646000,0x00c2f282,0x00084200,0x600000c2 + .long 0x50c06000,0x00bcf28d,0x00084200,0x600000b2 + .long 0x50c06000,0x00acf283,0x00084200,0x600000a2 + .long 0x50c06000,0x009cf28c,0x00084200,0x60000092 + .long 0x50c06000,0x008cf284,0x00084200,0x60000082 + .long 0x50c06000,0x007cf28b,0x00084200,0x60000072 + .long 0x50c06000,0x006cf285,0x00084200,0x60000062 + .long 0x50c06000,0x005cf28a,0x00084200,0x60000052 + .long 0x50c06000,0x004cf286,0x00084200,0x60000042 + .long 0x50c06000,0x003cf289,0x00084200,0x60000032 + .long 0x50c06000,0x002cf287,0x00084200,0x60000022 + .long 0x50c06000,0x001cf288,0x00084200,0x60000012 + .long 0x50c06000,0x000c082e,0x0007ff62,0x66000088 + .long 0x2040122e,0xff412001,0x02010038,0x66102200 + .long 0x02410007,0x200861ff,0x0000172a,0x4e750c01 + .long 0x0018671a,0x0c010020,0x67382008,0x206e000c + .long 0x61ffffff,0x5a7c4a81,0x66000054,0x4e752008 + .long 0x206e000c,0x61ffffff,0x5a684a81,0x66000040 + .long 0x122eff41,0x02410007,0x700161ff,0x00001722 + .long 0x4e752008,0x206e000c,0x61ffffff,0x5a444a81 + .long 0x6600001c,0x122eff41,0x02410007,0x700161ff + .long 0x0000174e,0x4e751d7c,0x0002ff4a,0x4e753d7c + .long 0x00a1000a,0x60ff0000,0x2b86122e,0xff430241 + .long 0x0070e809,0x61ff0000,0x15b20280,0x000000ff + .long 0x2f00103b,0x09200148,0x2f0061ff,0x00000340 + .long 0x201f221f,0x67000134,0x082e0005,0xff426700 + .long 0x00b8082e,0x0004ff42,0x6600001a,0x123b1120 + .long 0x021e082e,0x00050004,0x670a0c2e,0x0008ff4a + .long 0x66024e75,0x22489fc0,0x41d74a01,0x6a0c20ee + .long 0xffdc20ee,0xffe020ee,0xffe4e309,0x6a0c20ee + .long 0xffe820ee,0xffec20ee,0xfff0e309,0x6a0af210 + .long 0xf020d1fc,0x0000000c,0xe3096a0a,0xf210f010 + .long 0xd1fc0000,0x000ce309,0x6a0af210,0xf008d1fc + .long 0x0000000c,0xe3096a0a,0xf210f004,0xd1fc0000 + .long 0x000ce309,0x6a0af210,0xf002d1fc,0x0000000c + .long 0xe3096a0a,0xf210f001,0xd1fc0000,0x000c2d49 + .long 0xff5441d7,0x2f0061ff,0xffff58b2,0x201fdfc0 + .long 0x4a816600,0x071e4e75,0x2d48ff54,0x9fc043d7 + .long 0x2f012f00,0x61ffffff,0x587e201f,0x4a816600 + .long 0x070e221f,0x41d74a01,0x6a0c2d58,0xffdc2d58 + .long 0xffe02d58,0xffe4e309,0x6a0c2d58,0xffe82d58 + .long 0xffec2d58,0xfff0e309,0x6a04f218,0xd020e309 + .long 0x6a04f218,0xd010e309,0x6a04f218,0xd008e309 + .long 0x6a04f218,0xd004e309,0x6a04f218,0xd002e309 + .long 0x6a04f218,0xd001dfc0,0x4e754e75,0x000c0c18 + .long 0x0c181824,0x0c181824,0x18242430,0x0c181824 + .long 0x18242430,0x18242430,0x2430303c,0x0c181824 + .long 0x18242430,0x18242430,0x2430303c,0x18242430 + .long 0x2430303c,0x2430303c,0x303c3c48,0x0c181824 + .long 0x18242430,0x18242430,0x2430303c,0x18242430 + .long 0x2430303c,0x2430303c,0x303c3c48,0x18242430 + .long 0x2430303c,0x2430303c,0x303c3c48,0x2430303c + .long 0x303c3c48,0x303c3c48,0x3c484854,0x0c181824 + .long 0x18242430,0x18242430,0x2430303c,0x18242430 + .long 0x2430303c,0x2430303c,0x303c3c48,0x18242430 + .long 0x2430303c,0x2430303c,0x303c3c48,0x2430303c + .long 0x303c3c48,0x303c3c48,0x3c484854,0x18242430 + .long 0x2430303c,0x2430303c,0x303c3c48,0x2430303c + .long 0x303c3c48,0x303c3c48,0x3c484854,0x2430303c + .long 0x303c3c48,0x303c3c48,0x3c484854,0x303c3c48 + .long 0x3c484854,0x3c484854,0x48545460,0x008040c0 + .long 0x20a060e0,0x109050d0,0x30b070f0,0x088848c8 + .long 0x28a868e8,0x189858d8,0x38b878f8,0x048444c4 + .long 0x24a464e4,0x149454d4,0x34b474f4,0x0c8c4ccc + .long 0x2cac6cec,0x1c9c5cdc,0x3cbc7cfc,0x028242c2 + .long 0x22a262e2,0x129252d2,0x32b272f2,0x0a8a4aca + .long 0x2aaa6aea,0x1a9a5ada,0x3aba7afa,0x068646c6 + .long 0x26a666e6,0x169656d6,0x36b676f6,0x0e8e4ece + .long 0x2eae6eee,0x1e9e5ede,0x3ebe7efe,0x018141c1 + .long 0x21a161e1,0x119151d1,0x31b171f1,0x098949c9 + .long 0x29a969e9,0x199959d9,0x39b979f9,0x058545c5 + .long 0x25a565e5,0x159555d5,0x35b575f5,0x0d8d4dcd + .long 0x2dad6ded,0x1d9d5ddd,0x3dbd7dfd,0x038343c3 + .long 0x23a363e3,0x139353d3,0x33b373f3,0x0b8b4bcb + .long 0x2bab6beb,0x1b9b5bdb,0x3bbb7bfb,0x078747c7 + .long 0x27a767e7,0x179757d7,0x37b777f7,0x0f8f4fcf + .long 0x2faf6fef,0x1f9f5fdf,0x3fbf7fff,0x2040302e + .long 0xff403200,0x0240003f,0x02810000,0x0007303b + .long 0x020a4efb,0x00064afc,0x00400000,0x00000000 + .long 0x00000000,0x00000000,0x00000000,0x00000000 + .long 0x00000000,0x00000000,0x00000080,0x0086008c + .long 0x00900094,0x0098009c,0x00a000a6,0x00b600c6 + .long 0x00d200de,0x00ea00f6,0x01020118,0x01260134 + .long 0x013e0148,0x0152015c,0x0166017a,0x019801b6 + .long 0x01d201ee,0x020a0226,0x02420260,0x02600260 + .long 0x02600260,0x02600260,0x026002c0,0x02da02f4 + .long 0x03140000,0x00000000,0x0000206e,0xffa44e75 + .long 0x206effa8,0x4e75204a,0x4e75204b,0x4e75204c + .long 0x4e75204d,0x4e752056,0x4e75206e,0xffd84e75 + .long 0x202effa4,0x2200d288,0x2d41ffa4,0x20404e75 + .long 0x202effa8,0x2200d288,0x2d41ffa8,0x20404e75 + .long 0x200a2200,0xd2882441,0x20404e75,0x200b2200 + .long 0xd2882641,0x20404e75,0x200c2200,0xd2882841 + .long 0x20404e75,0x200d2200,0xd2882a41,0x20404e75 + .long 0x20162200,0xd2882c81,0x20404e75,0x1d7c0004 + .long 0xff4a202e,0xffd82200,0xd2882d41,0xffd82040 + .long 0x4e75202e,0xffa49088,0x2d40ffa4,0x20404e75 + .long 0x202effa8,0x90882d40,0xffa82040,0x4e75200a + .long 0x90882440,0x20404e75,0x200b9088,0x26402040 + .long 0x4e75200c,0x90882840,0x20404e75,0x200d9088 + .long 0x2a402040,0x4e752016,0x90882c80,0x20404e75 + .long 0x1d7c0008,0xff4a202e,0xffd89088,0x2d40ffd8 + .long 0x20404e75,0x206eff44,0x54aeff44,0x61ffffff + .long 0x54a24a81,0x66ffffff,0x68203040,0xd1eeffa4 + .long 0x4e75206e,0xff4454ae,0xff4461ff,0xffff5484 + .long 0x4a8166ff,0xffff6802,0x3040d1ee,0xffa84e75 + .long 0x206eff44,0x54aeff44,0x61ffffff,0x54664a81 + .long 0x66ffffff,0x67e43040,0xd1ca4e75,0x206eff44 + .long 0x54aeff44,0x61ffffff,0x544a4a81,0x66ffffff + .long 0x67c83040,0xd1cb4e75,0x206eff44,0x54aeff44 + .long 0x61ffffff,0x542e4a81,0x66ffffff,0x67ac3040 + .long 0xd1cc4e75,0x206eff44,0x54aeff44,0x61ffffff + .long 0x54124a81,0x66ffffff,0x67903040,0xd1cd4e75 + .long 0x206eff44,0x54aeff44,0x61ffffff,0x53f64a81 + .long 0x66ffffff,0x67743040,0xd1d64e75,0x206eff44 + .long 0x54aeff44,0x61ffffff,0x53da4a81,0x66ffffff + .long 0x67583040,0xd1eeffd8,0x4e755081,0x61ff0000 + .long 0x0fda2f00,0x206eff44,0x54aeff44,0x61ffffff + .long 0x53b24a81,0x66ffffff,0x6730205f,0x08000008 + .long 0x660000e6,0x2d40ff54,0x2200e959,0x0241000f + .long 0x61ff0000,0x0fa62f02,0x242eff54,0x0802000b + .long 0x660248c0,0x2202ef59,0x02810000,0x0003e3a8 + .long 0x49c2d082,0xd1c0241f,0x4e75206e,0xff4454ae + .long 0xff4461ff,0xffff535c,0x4a8166ff,0xffff66da + .long 0x30404e75,0x206eff44,0x58aeff44,0x61ffffff + .long 0x53584a81,0x66ffffff,0x66c02040,0x4e75206e + .long 0xff4454ae,0xff4461ff,0xffff5328,0x4a8166ff + .long 0xffff66a6,0x3040d1ee,0xff445588,0x4e75206e + .long 0xff4454ae,0xff4461ff,0xffff5308,0x4a8166ff + .long 0xffff6686,0x206eff44,0x55880800,0x00086600 + .long 0x00382d40,0xff542200,0xe9590241,0x000f61ff + .long 0x00000ef8,0x2f02242e,0xff540802,0x000b6602 + .long 0x48c02202,0xef590281,0x00000003,0xe3a849c2 + .long 0xd082d1c0,0x241f4e75,0x08000006,0x670c48e7 + .long 0x3c002a00,0x26084282,0x60282d40,0xff54e9c0 + .long 0x140461ff,0x00000eb4,0x48e73c00,0x24002a2e + .long 0xff542608,0x0805000b,0x660248c2,0xe9c50542 + .long 0xe1aa0805,0x00076702,0x4283e9c5,0x06820c00 + .long 0x00026d34,0x6718206e,0xff4458ae,0xff4461ff + .long 0xffff5276,0x4a8166ff,0x000000b0,0x6018206e + .long 0xff4454ae,0xff4461ff,0xffff5248,0x4a8166ff + .long 0x00000098,0x48c0d680,0xe9c50782,0x6700006e + .long 0x0c000002,0x6d346718,0x206eff44,0x58aeff44 + .long 0x61ffffff,0x52344a81,0x66ff0000,0x006e601c + .long 0x206eff44,0x54aeff44,0x61ffffff,0x52064a81 + .long 0x66ff0000,0x005648c0,0x60024280,0x28000805 + .long 0x00026714,0x204361ff,0xffff5240,0x4a816600 + .long 0x0028d082,0xd0846018,0xd6822043,0x61ffffff + .long 0x522a4a81,0x66000012,0xd0846004,0xd6822003 + .long 0x20404cdf,0x003c4e75,0x20434cdf,0x003c303c + .long 0x010160ff,0xffff6582,0x4cdf003c,0x60ffffff + .long 0x652861ff,0x000023c6,0x303c00e1,0x600a61ff + .long 0x000023ba,0x303c0161,0x206eff54,0x60ffffff + .long 0x6558102e,0xff420c00,0x009c6700,0x00b20c00 + .long 0x00986700,0x00740c00,0x00946736,0x206eff44 + .long 0x58aeff44,0x61ffffff,0x51704a81,0x66ffffff + .long 0x64d82d40,0xff64206e,0xff4458ae,0xff4461ff + .long 0xffff5156,0x4a8166ff,0xffff64be,0x2d40ff68 + .long 0x4e75206e,0xff4458ae,0xff4461ff,0xffff513a + .long 0x4a8166ff,0xffff64a2,0x2d40ff60,0x206eff44 + .long 0x58aeff44,0x61ffffff,0x51204a81,0x66ffffff + .long 0x64882d40,0xff684e75,0x206eff44,0x58aeff44 + .long 0x61ffffff,0x51044a81,0x66ffffff,0x646c2d40 + .long 0xff60206e,0xff4458ae,0xff4461ff,0xffff50ea + .long 0x4a8166ff,0xffff6452,0x2d40ff64,0x4e75206e + .long 0xff4458ae,0xff4461ff,0xffff50ce,0x4a8166ff + .long 0xffff6436,0x2d40ff60,0x206eff44,0x58aeff44 + .long 0x61ffffff,0x50b44a81,0x66ffffff,0x641c2d40 + .long 0xff64206e,0xff4458ae,0xff4461ff,0xffff509a + .long 0x4a8166ff,0xffff6402,0x2d40ff68,0x4e752040 + .long 0x102eff41,0x22000240,0x00380281,0x00000007 + .long 0x0c000018,0x67240c00,0x0020672c,0x80410c00 + .long 0x003c6706,0x206e000c,0x4e751d7c,0x0080ff4a + .long 0x41f60162,0xff680004,0x4e752008,0x61ff0000 + .long 0x0d70206e,0x000c4e75,0x200861ff,0x00000db2 + .long 0x206e000c,0x0c00000c,0x67024e75,0x51882d48 + .long 0x000c4e75,0x102eff41,0x22000240,0x00380281 + .long 0x00000007,0x0c000018,0x670e0c00,0x00206700 + .long 0x0076206e,0x000c4e75,0x323b120e,0x206e000c + .long 0x4efb1006,0x4afc0008,0x0010001a,0x0024002c + .long 0x0034003c,0x0044004e,0x06ae0000,0x000cffa4 + .long 0x4e7506ae,0x0000000c,0xffa84e75,0xd5fc0000 + .long 0x000c4e75,0xd7fc0000,0x000c4e75,0xd9fc0000 + .long 0x000c4e75,0xdbfc0000,0x000c4e75,0x06ae0000 + .long 0x000cffd4,0x4e751d7c,0x0004ff4a,0x06ae0000 + .long 0x000cffd8,0x4e75323b,0x1214206e,0x000c5188 + .long 0x51ae000c,0x4efb1006,0x4afc0008,0x00100016 + .long 0x001c0020,0x00240028,0x002c0032,0x2d48ffa4 + .long 0x4e752d48,0xffa84e75,0x24484e75,0x26484e75 + .long 0x28484e75,0x2a484e75,0x2d48ffd4,0x4e752d48 + .long 0xffd81d7c,0x0008ff4a,0x4e75082e,0x0006ff42 + .long 0x6664102e,0xff430800,0x0005672c,0x08000004 + .long 0x670a0240,0x007f0c40,0x0038661c,0xe9ee0183 + .long 0xff4261ff,0x00000d6a,0x61ff0000,0x12060c00 + .long 0x00066722,0x1d40ff4f,0xe9ee00c3,0xff4261ff + .long 0x00000cbe,0x61ff0000,0x11ea0c00,0x0006670e + .long 0x1d40ff4e,0x4e7561ff,0x00001148,0x60d661ff + .long 0x00001140,0x60ea302e,0xff420800,0x0005672c + .long 0x08000004,0x670a0240,0x007f0c40,0x0038661c + .long 0xe9ee0183,0xff4261ff,0x00000d06,0x61ff0000 + .long 0x11a20c00,0x00066726,0x1d40ff4f,0xe9ee00c3 + .long 0xff42e9ee,0x1283ff40,0x660000be,0x422eff4e + .long 0xe9ee1343,0xff40303b,0x02124efb,0x000e61ff + .long 0x000010e0,0x60d24afc,0x00080010,0x006a0000 + .long 0x0000002e,0x0000004c,0x000061ff,0x00000a5c + .long 0xf2004000,0xf22ef080,0xff6cf281,0x00044e75 + .long 0x1d7c0001,0xff4e4e75,0x61ff0000,0x0a3ef200 + .long 0x5000f22e,0xf080ff6c,0xf2810004,0x4e751d7c + .long 0x0001ff4e,0x4e7561ff,0x00000a20,0xf2005800 + .long 0xf22ef080,0xff6cf281,0x00044e75,0x1d7c0001 + .long 0xff4e4e75,0x61ff0000,0x0a022d40,0xff5441ee + .long 0xff5461ff,0x000011de,0x1d40ff4e,0x0c000005 + .long 0x670001a4,0x0c000004,0x6700015e,0xf2104400 + .long 0xf22ef080,0xff6c4e75,0x422eff4e,0x303b020a + .long 0x4efb0006,0x4afc0008,0x001000e2,0x027202b0 + .long 0x005601a0,0x009c0000,0x700461ff,0xfffffd22 + .long 0x0c2e0080,0xff4a6726,0x61ffffff,0x4dde4a81 + .long 0x66ff0000,0x1eecf200,0x4000f22e,0xf080ff6c + .long 0xf2810004,0x4e751d7c,0x0001ff4e,0x4e7561ff + .long 0xffff4d76,0x4a8166ff,0xffff6e8a,0x60d87002 + .long 0x61ffffff,0xfcdc0c2e,0x0080ff4a,0x672661ff + .long 0xffff4d82,0x4a8166ff,0x00001e98,0xf2005000 + .long 0xf22ef080,0xff6cf281,0x00044e75,0x1d7c0001 + .long 0xff4e4e75,0x61ffffff,0x4d1a4a81,0x66ffffff + .long 0x6e4460d8,0x700161ff,0xfffffc96,0x0c2e0080 + .long 0xff4a6726,0x61ffffff,0x4d264a81,0x66ff0000 + .long 0x1e42f200,0x5800f22e,0xf080ff6c,0xf2810004 + .long 0x4e751d7c,0x0001ff4e,0x4e7561ff,0xffff4cd4 + .long 0x4a8166ff,0xffff6dfe,0x60d87004,0x61ffffff + .long 0xfc500c2e,0x0080ff4a,0x673e61ff,0xffff4d0c + .long 0x2d40ff54,0x4a8166ff,0x00001e16,0x41eeff54 + .long 0x61ff0000,0x10a01d40,0xff4e0c00,0x00046700 + .long 0x00280c00,0x00056700,0x005ef22e,0x4400ff54 + .long 0xf22ef080,0xff6c4e75,0x61ffffff,0x4c8c4a81 + .long 0x66ffffff,0x6da060c4,0x426eff6c,0xe9d00257 + .long 0xe1882d40,0xff7042ae,0xff74426e,0xff6c0810 + .long 0x00076706,0x08ee0007,0xff6c41ee,0xff6c61ff + .long 0x00000e78,0x323c3f81,0x9240836e,0xff6c1d7c + .long 0x0000ff4e,0x4e753d7c,0x7fffff6c,0xe9d00257 + .long 0xe1882d40,0xff7042ae,0xff740810,0x00076706 + .long 0x08ee0007,0xff6c4e75,0x700861ff,0xfffffb92 + .long 0x0c2e0080,0xff4a6740,0x43eeff54,0x700861ff + .long 0xffff4bc4,0x4a8166ff,0x00001d64,0x41eeff54 + .long 0x61ff0000,0x0f701d40,0xff4e0c00,0x00046700 + .long 0x002e0c00,0x00056700,0x0068f22e,0x5400ff54 + .long 0xf22ef080,0xff6c4e75,0x43eeff54,0x700861ff + .long 0xffff4b6e,0x4a8166ff,0xffff6cda,0x60be426e + .long 0xff6ce9d0,0x031f2d40,0xff70e9e8,0x02d50004 + .long 0x720be3a8,0x2d40ff74,0x08100007,0x670608ee + .long 0x0007ff6c,0x41eeff6c,0x61ff0000,0x0dae323c + .long 0x3c019240,0x836eff6c,0x1d7c0000,0xff4e4e75 + .long 0x3d7c7fff,0xff6ce9d0,0x031f2d40,0xff70e9e8 + .long 0x02d50004,0x720be3a8,0x2d40ff74,0x08100007 + .long 0x670608ee,0x0007ff6c,0x4e75700c,0x61ffffff + .long 0xfac043ee,0xff6c700c,0x61ffffff,0x4afa4a81 + .long 0x66ff0000,0x1ca841ee,0xff6c61ff,0x00000e24 + .long 0x0c000006,0x67061d40,0xff4e4e75,0x61ff0000 + .long 0x0d821d40,0xff4e4e75,0x61ff0000,0x125441ee + .long 0xff6c61ff,0x00000dfc,0x0c000006,0x67061d40 + .long 0xff4e4e75,0x61ff0000,0x0d5a1d40,0xff4e4e75 + .long 0xe9ee10c3,0xff42327b,0x120a4efb,0x98064afc + .long 0x000800e0,0x01e00148,0x06200078,0x041a0010 + .long 0x06204a2e,0xff4e664c,0xf228d080,0x0000f200 + .long 0x9000f200,0x7800f23c,0x90000000,0x0000f201 + .long 0xa800836e,0xff66122e,0xff410201,0x00386714 + .long 0x206e000c,0x61ffffff,0x4ae84a81,0x66ff0000 + .long 0x1c0a4e75,0x122eff41,0x02410007,0x61ff0000 + .long 0x07644e75,0x22280000,0x02818000,0x00000081 + .long 0x00800000,0xf2014400,0x60a44a2e,0xff4e664c + .long 0xf228d080,0x0000f200,0x9000f200,0x7000f23c + .long 0x90000000,0x0000f201,0xa800836e,0xff66122e + .long 0xff410201,0x00386714,0x206e000c,0x61ffffff + .long 0x4a964a81,0x66ff0000,0x1bb04e75,0x122eff41 + .long 0x02410007,0x61ff0000,0x06c04e75,0x22280000 + .long 0x02818000,0x00000081,0x00800000,0xf2014400 + .long 0x60a44a2e,0xff4e664c,0xf228d080,0x0000f200 + .long 0x9000f200,0x6000f23c,0x90000000,0x0000f201 + .long 0xa800836e,0xff66122e,0xff410201,0x00386714 + .long 0x206e000c,0x61ffffff,0x4a444a81,0x66ff0000 + .long 0x1b564e75,0x122eff41,0x02410007,0x61ff0000 + .long 0x061c4e75,0x22280000,0x02818000,0x00000081 + .long 0x00800000,0xf2014400,0x60a43d68,0x0000ff84 + .long 0x426eff86,0x2d680004,0xff882d68,0x0008ff8c + .long 0xf228d080,0x000061ff,0xfffff94c,0x224841ee + .long 0xff84700c,0x0c2e0008,0xff4a6726,0x61ffffff + .long 0x492c4a81,0x66000052,0x4a2eff4e,0x66024e75 + .long 0x08ee0003,0xff66102e,0xff620200,0x000a6616 + .long 0x4e7561ff,0xffff5788,0x4a816600,0x002c4a2e + .long 0xff4e66dc,0x4e7541ee,0xff8461ff,0x00000b3c + .long 0x44400240,0x7fff026e,0x8000ff84,0x816eff84 + .long 0xf22ed040,0xff844e75,0x2caeffd4,0x60ff0000 + .long 0x1ab20200,0x00300000,0x00402d40,0xff5c3028 + .long 0x00000240,0x7fff0c40,0x407e6e00,0x00e66700 + .long 0x01520c40,0x3f816d00,0x0058f228,0xd0800000 + .long 0xf22e9000,0xff5cf23c,0x88000000,0x0000f200 + .long 0x6400f23c,0x90000000,0x0000f201,0xa800836e + .long 0xff66122e,0xff410201,0x00386714,0x206e000c + .long 0x61ffffff,0x49184a81,0x66ff0000,0x1a2a4e75 + .long 0x122eff41,0x02410007,0x61ff0000,0x04f04e75 + .long 0x08ee0003,0xff663d68,0x0000ff84,0x2d680004 + .long 0xff882d68,0x0008ff8c,0x2f084280,0x0c2e0004 + .long 0xff4e660a,0x41eeff84,0x61ff0000,0x0a6e41ee + .long 0xff84222e,0xff5c61ff,0x00000c86,0x41eeff84 + .long 0x61ff0000,0x034c122e,0xff410201,0x00386714 + .long 0x206e000c,0x61ffffff,0x48a44a81,0x66ff0000 + .long 0x19b6600e,0x122eff41,0x02410007,0x61ff0000 + .long 0x047c122e,0xff620201,0x000a6600,0x00b8588f + .long 0x4e754a28,0x0007660e,0x4aa80008,0x6608006e + .long 0x1048ff66,0x6006006e,0x1248ff66,0x2f084a28 + .long 0x00005bc1,0x202eff5c,0x61ff0000,0x0d12f210 + .long 0xd080f200,0x6400122e,0xff410201,0x00386714 + .long 0x206e000c,0x61ffffff,0x48344a81,0x66ff0000 + .long 0x1946600e,0x122eff41,0x02410007,0x61ff0000 + .long 0x040c122e,0xff620201,0x000a6600,0x007c588f + .long 0x4e753228,0x00000241,0x80000041,0x3fff3d41 + .long 0xff842d68,0x0004ff88,0x2d680008,0xff8cf22e + .long 0x9000ff5c,0xf22e4800,0xff84f23c,0x90000000 + .long 0x0000f200,0x0018f23c,0x58380002,0xf294fe7c + .long 0x6000ff50,0x205f3d68,0x0000ff84,0x2d680004 + .long 0xff882d68,0x0008ff8c,0x0c2e0004,0xff4e662c + .long 0x41eeff84,0x61ff0000,0x09424480,0x02407fff + .long 0xefee004f,0xff846014,0x205f3d68,0x0000ff84 + .long 0x2d680004,0xff882d68,0x0008ff8c,0x08ae0007 + .long 0xff8456ee,0xff8641ee,0xff84122e,0xff5fe809 + .long 0x0241000c,0x4841122e,0xff5fe809,0x02410003 + .long 0x428061ff,0x00000782,0x4a2eff86,0x670608ee + .long 0x0007ff84,0xf22ed040,0xff844e75,0x02000030 + .long 0x00000080,0x2d40ff5c,0x30280000,0x02407fff + .long 0x0c4043fe,0x6e0000c8,0x67000120,0x0c403c01 + .long 0x6d000046,0xf228d080,0x0000f22e,0x9000ff5c + .long 0xf23c8800,0x00000000,0xf22e7400,0xff54f23c + .long 0x90000000,0x0000f200,0xa800816e,0xff66226e + .long 0x000c41ee,0xff547008,0x61ffffff,0x46304a81 + .long 0x66ff0000,0x18004e75,0x08ee0003,0xff663d68 + .long 0x0000ff84,0x2d680004,0xff882d68,0x0008ff8c + .long 0x2f084280,0x0c2e0004,0xff4e660a,0x41eeff84 + .long 0x61ff0000,0x084641ee,0xff84222e,0xff5c61ff + .long 0x00000a5e,0x41eeff84,0x61ff0000,0x00d22d40 + .long 0xff542d41,0xff58226e,0x000c41ee,0xff547008 + .long 0x61ffffff,0x45c84a81,0x66ff0000,0x1798122e + .long 0xff620201,0x000a6600,0xfe9c588f,0x4e753028 + .long 0x000a0240,0x07ff6608,0x006e1048,0xff666006 + .long 0x006e1248,0xff662f08,0x4a280000,0x5bc1202e + .long 0xff5c61ff,0x00000af8,0xf210d080,0xf22e7400 + .long 0xff54226e,0x000c41ee,0xff547008,0x61ffffff + .long 0x456c4a81,0x66ff0000,0x173c122e,0xff620201 + .long 0x000a6600,0xfe74588f,0x4e753228,0x00000241 + .long 0x80000041,0x3fff3d41,0xff842d68,0x0004ff88 + .long 0x2d680008,0xff8cf22e,0x9000ff5c,0xf22e4800 + .long 0xff84f23c,0x90000000,0x0000f200,0x0018f23c + .long 0x58380002,0xf294feae,0x6000ff64,0x42803028 + .long 0x00000440,0x3fff0640,0x03ff4a28,0x00046b02 + .long 0x53404840,0xe9884a28,0x00006a04,0x08c0001f + .long 0x22280004,0xe9c11054,0x80812d40,0xff542228 + .long 0x00047015,0xe1a92d41,0xff582228,0x0008e9c1 + .long 0x0015222e,0xff588280,0x202eff54,0x4e754280 + .long 0x30280000,0x04403fff,0x0640007f,0x4a280004 + .long 0x6b025340,0x4840ef88,0x4a280000,0x6a0408c0 + .long 0x001f2228,0x00040281,0x7fffff00,0xe0898081 + .long 0x4e7561ff,0xfffff490,0x2f08102e,0xff4e6600 + .long 0x0082082e,0x0004ff42,0x6712122e,0xff43e809 + .long 0x02410007,0x61ff0000,0x00926004,0x102eff43 + .long 0xebc00647,0x2f0041ee,0xff6c61ff,0x00000ed0 + .long 0x02aecfff,0xf00fff84,0x201f4a2e,0xff876616 + .long 0x4aaeff88,0x66104aae,0xff8c660a,0x4a806606 + .long 0x026ef000,0xff8441ee,0xff84225f,0x700c0c2e + .long 0x0008ff4a,0x670e61ff,0xffff4412,0x4a816600 + .long 0xfb384e75,0x61ffffff,0x52864a81,0x6600fb2a + .long 0x4e750c00,0x00046700,0xff7a41ee,0xff6c426e + .long 0xff6e0c00,0x00056702,0x60c0006e,0x4080ff66 + .long 0x08ee0006,0xff7060b2,0x303b1206,0x4efb0002 + .long 0x00200026,0x002c0030,0x00340038,0x003c0040 + .long 0x0044004a,0x00500054,0x0058005c,0x00600064 + .long 0x202eff9c,0x4e75202e,0xffa04e75,0x20024e75 + .long 0x20034e75,0x20044e75,0x20054e75,0x20064e75 + .long 0x20074e75,0x202effa4,0x4e75202e,0xffa84e75 + .long 0x200a4e75,0x200b4e75,0x200c4e75,0x200d4e75 + .long 0x20164e75,0x202effd8,0x4e75323b,0x12064efb + .long 0x10020010,0x0016001c,0x00200024,0x0028002c + .long 0x00302d40,0xff9c4e75,0x2d40ffa0,0x4e752400 + .long 0x4e752600,0x4e752800,0x4e752a00,0x4e752c00 + .long 0x4e752e00,0x4e75323b,0x12064efb,0x10020010 + .long 0x0016001c,0x00200024,0x0028002c,0x00303d40 + .long 0xff9e4e75,0x3d40ffa2,0x4e753400,0x4e753600 + .long 0x4e753800,0x4e753a00,0x4e753c00,0x4e753e00 + .long 0x4e75323b,0x12064efb,0x10020010,0x0016001c + .long 0x00200024,0x0028002c,0x00301d40,0xff9f4e75 + .long 0x1d40ffa3,0x4e751400,0x4e751600,0x4e751800 + .long 0x4e751a00,0x4e751c00,0x4e751e00,0x4e75323b + .long 0x12064efb,0x10020010,0x0016001c,0x00200024 + .long 0x0028002c,0x0030d1ae,0xffa44e75,0xd1aeffa8 + .long 0x4e75d5c0,0x4e75d7c0,0x4e75d9c0,0x4e75dbc0 + .long 0x4e75d196,0x4e751d7c,0x0004ff4a,0x0c000001 + .long 0x6706d1ae,0xffd84e75,0x54aeffd8,0x4e75323b + .long 0x12064efb,0x10020010,0x0016001c,0x00200024 + .long 0x0028002c,0x003091ae,0xffa44e75,0x91aeffa8 + .long 0x4e7595c0,0x4e7597c0,0x4e7599c0,0x4e759bc0 + .long 0x4e759196,0x4e751d7c,0x0008ff4a,0x0c000001 + .long 0x670691ae,0xffd84e75,0x55aeffd8,0x4e75303b + .long 0x02064efb,0x00020010,0x00280040,0x004c0058 + .long 0x00640070,0x007c2d6e,0xffdcff6c,0x2d6effe0 + .long 0xff702d6e,0xffe4ff74,0x41eeff6c,0x4e752d6e + .long 0xffe8ff6c,0x2d6effec,0xff702d6e,0xfff0ff74 + .long 0x41eeff6c,0x4e75f22e,0xf020ff6c,0x41eeff6c + .long 0x4e75f22e,0xf010ff6c,0x41eeff6c,0x4e75f22e + .long 0xf008ff6c,0x41eeff6c,0x4e75f22e,0xf004ff6c + .long 0x41eeff6c,0x4e75f22e,0xf002ff6c,0x41eeff6c + .long 0x4e75f22e,0xf001ff6c,0x41eeff6c,0x4e75303b + .long 0x02064efb,0x00020010,0x00280040,0x004c0058 + .long 0x00640070,0x007c2d6e,0xffdcff78,0x2d6effe0 + .long 0xff7c2d6e,0xffe4ff80,0x41eeff78,0x4e752d6e + .long 0xffe8ff78,0x2d6effec,0xff7c2d6e,0xfff0ff80 + .long 0x41eeff78,0x4e75f22e,0xf020ff78,0x41eeff78 + .long 0x4e75f22e,0xf010ff78,0x41eeff78,0x4e75f22e + .long 0xf008ff78,0x41eeff78,0x4e75f22e,0xf004ff78 + .long 0x41eeff78,0x4e75f22e,0xf002ff78,0x41eeff78 + .long 0x4e75f22e,0xf001ff78,0x41eeff78,0x4e75303b + .long 0x02064efb,0x00020010,0x00180020,0x002a0034 + .long 0x003e0048,0x0052f22e,0xf080ffdc,0x4e75f22e + .long 0xf080ffe8,0x4e75f227,0xe001f21f,0xd0204e75 + .long 0xf227e001,0xf21fd010,0x4e75f227,0xe001f21f + .long 0xd0084e75,0xf227e001,0xf21fd004,0x4e75f227 + .long 0xe001f21f,0xd0024e75,0xf227e001,0xf21fd001 + .long 0x4e750000,0x3f813c01,0xe408323b,0x02f63001 + .long 0x90680000,0x0c400042,0x6a164280,0x082e0001 + .long 0xff666704,0x08c0001d,0x61ff0000,0x001a4e75 + .long 0x203c2000,0x00003141,0x000042a8,0x000442a8 + .long 0x00084e75,0x2d680008,0xff542d40,0xff582001 + .long 0x92680000,0x6f100c41,0x00206d10,0x0c410040 + .long 0x6d506000,0x009a202e,0xff584e75,0x2f023140 + .long 0x00007020,0x90410c41,0x001d6d08,0x142eff58 + .long 0x852eff57,0xe9e82020,0x0004e9e8,0x18000004 + .long 0xe9ee0800,0xff542142,0x00042141,0x0008e8c0 + .long 0x009e6704,0x08c0001d,0x0280e000,0x0000241f + .long 0x4e752f02,0x31400000,0x04410020,0x70209041 + .long 0x142eff58,0x852eff57,0xe9e82020,0x0004e9e8 + .long 0x18000004,0xe8c1009e,0x660ce8ee,0x081fff54 + .long 0x66042001,0x60062001,0x08c0001d,0x42a80004 + .long 0x21420008,0x0280e000,0x0000241f,0x4e753140 + .long 0x00000c41,0x00416d12,0x672442a8,0x000442a8 + .long 0x0008203c,0x20000000,0x4e752028,0x00042200 + .long 0x0280c000,0x00000281,0x3fffffff,0x60122028 + .long 0x00040280,0x80000000,0xe2880281,0x7fffffff + .long 0x66164aa8,0x00086610,0x4a2eff58,0x660a42a8 + .long 0x000442a8,0x00084e75,0x08c0001d,0x42a80004 + .long 0x42a80008,0x4e7561ff,0x00000110,0x4a806700 + .long 0x00fa006e,0x0208ff66,0x327b1206,0x4efb9802 + .long 0x004000ea,0x00240008,0x4a280002,0x6b0000dc + .long 0x70ff4841,0x0c010004,0x6700003e,0x6e000094 + .long 0x60000064,0x4a280002,0x6a0000c0,0x70ff4841 + .long 0x0c010004,0x67000022,0x6e000078,0x60000048 + .long 0xe3806400,0x00a64841,0x0c010004,0x6700000a + .long 0x6e000060,0x60000030,0x06a80000,0x01000004 + .long 0x640ce4e8,0x0004e4e8,0x00065268,0x00004a80 + .long 0x66060268,0xfe000006,0x02a8ffff,0xff000004 + .long 0x42a80008,0x4e7552a8,0x0008641a,0x52a80004 + .long 0x6414e4e8,0x0004e4e8,0x0006e4e8,0x0008e4e8 + .long 0x000a5268,0x00004a80,0x66060228,0x00fe000b + .long 0x4e7506a8,0x00000800,0x0008641a,0x52a80004 + .long 0x6414e4e8,0x0004e4e8,0x0006e4e8,0x0008e4e8 + .long 0x000a5268,0x00004a80,0x66060268,0xf000000a + .long 0x02a8ffff,0xf8000008,0x4e754841,0x0c010004 + .long 0x6700ff86,0x6eea4e75,0x48414a01,0x66044841 + .long 0x4e7548e7,0x30000c01,0x00046622,0xe9e83602 + .long 0x0004741e,0xe5ab2428,0x00040282,0x0000003f + .long 0x66284aa8,0x00086622,0x4a80661e,0x6020e9e8 + .long 0x35420008,0x741ee5ab,0x24280008,0x02820000 + .long 0x01ff6606,0x4a806602,0x600408c3,0x001d2003 + .long 0x4cdf000c,0x48414e75,0x2f022f03,0x20280004 + .long 0x22280008,0xedc02000,0x671ae5a8,0xe9c13022 + .long 0x8083e5a9,0x21400004,0x21410008,0x2002261f + .long 0x241f4e75,0xedc12000,0xe5a90682,0x00000020 + .long 0x21410004,0x42a80008,0x2002261f,0x241f4e75 + .long 0xede80000,0x0004660e,0xede80000,0x00086700 + .long 0x00740640,0x00204281,0x32280000,0x02417fff + .long 0xb0416e1c,0x92403028,0x00000240,0x80008240 + .long 0x31410000,0x61ffffff,0xff82103c,0x00004e75 + .long 0x0c010020,0x6e20e9e8,0x08400004,0x21400004 + .long 0x20280008,0xe3a82140,0x00080268,0x80000000 + .long 0x103c0004,0x4e750441,0x00202028,0x0008e3a8 + .long 0x21400004,0x42a80008,0x02688000,0x0000103c + .long 0x00044e75,0x02688000,0x0000103c,0x00014e75 + .long 0x30280000,0x02407fff,0x0c407fff,0x67480828 + .long 0x00070004,0x6706103c,0x00004e75,0x4a406618 + .long 0x4aa80004,0x660c4aa8,0x00086606,0x103c0001 + .long 0x4e75103c,0x00044e75,0x4aa80004,0x66124aa8 + .long 0x0008660c,0x02688000,0x0000103c,0x00014e75 + .long 0x103c0006,0x4e754aa8,0x00086612,0x20280004 + .long 0x02807fff,0xffff6606,0x103c0002,0x4e750828 + .long 0x00060004,0x6706103c,0x00034e75,0x103c0005 + .long 0x4e752028,0x00002200,0x02807ff0,0x0000670e + .long 0x0c807ff0,0x00006728,0x103c0000,0x4e750281 + .long 0x000fffff,0x66ff0000,0x00144aa8,0x000466ff + .long 0x0000000a,0x103c0001,0x4e75103c,0x00044e75 + .long 0x0281000f,0xffff66ff,0x00000014,0x4aa80004 + .long 0x66ff0000,0x000a103c,0x00024e75,0x08010013 + .long 0x66ff0000,0x000a103c,0x00054e75,0x103c0003 + .long 0x4e752028,0x00002200,0x02807f80,0x0000670e + .long 0x0c807f80,0x0000671e,0x103c0000,0x4e750281 + .long 0x007fffff,0x66ff0000,0x000a103c,0x00014e75 + .long 0x103c0004,0x4e750281,0x007fffff,0x66ff0000 + .long 0x000a103c,0x00024e75,0x08010016,0x66ff0000 + .long 0x000a103c,0x00054e75,0x103c0003,0x4e752f01 + .long 0x08280007,0x000056e8,0x00023228,0x00000241 + .long 0x7fff9240,0x31410000,0x2f08202f,0x00040240 + .long 0x00c0e848,0x61ffffff,0xfae22057,0x322f0006 + .long 0x024100c0,0xe8494841,0x322f0006,0x02410030 + .long 0xe84961ff,0xfffffc22,0x205f08a8,0x00070000 + .long 0x4a280002,0x670a08e8,0x00070000,0x42280002 + .long 0x42804aa8,0x0004660a,0x4aa80008,0x660408c0 + .long 0x0002082e,0x0001ff66,0x670608ee,0x0005ff67 + .long 0x588f4e75,0x2f010828,0x00070000,0x56e80002 + .long 0x32280000,0x02417fff,0x92403141,0x00002f08 + .long 0x428061ff,0xfffffa64,0x2057323c,0x00044841 + .long 0x322f0006,0x02410030,0xe84961ff,0xfffffbaa + .long 0x205f08a8,0x00070000,0x4a280002,0x670a08e8 + .long 0x00070000,0x42280002,0x42804aa8,0x0004660a + .long 0x4aa80008,0x660408c0,0x0002082e,0x0001ff66 + .long 0x670608ee,0x0005ff67,0x588f4e75,0x02410010 + .long 0xe8088200,0x3001e309,0x600e0241,0x00108200 + .long 0x48408200,0x3001e309,0x103b0008,0x41fb1620 + .long 0x4e750200,0x00020200,0x00020200,0x00020000 + .long 0x00000a08,0x0a080a08,0x0a080a08,0x0a087fff + .long 0x00000000,0x00000000,0x00000000,0x00007ffe + .long 0x0000ffff,0xffffffff,0xffff0000,0x00007ffe + .long 0x0000ffff,0xffffffff,0xffff0000,0x00007fff + .long 0x00000000,0x00000000,0x00000000,0x00007fff + .long 0x00000000,0x00000000,0x00000000,0x0000407e + .long 0x0000ffff,0xff000000,0x00000000,0x0000407e + .long 0x0000ffff,0xff000000,0x00000000,0x00007fff + .long 0x00000000,0x00000000,0x00000000,0x00007fff + .long 0x00000000,0x00000000,0x00000000,0x000043fe + .long 0x0000ffff,0xffffffff,0xf8000000,0x000043fe + .long 0x0000ffff,0xffffffff,0xf8000000,0x00007fff + .long 0x00000000,0x00000000,0x00000000,0x00000000 + .long 0x00000000,0x00000000,0x00000000,0x00000000 + .long 0x00000000,0x00000000,0x00000000,0x00000000 + .long 0x00000000,0x00000000,0x00000000,0x00000000 + .long 0x00000000,0x00000000,0x00000000,0x0000ffff + .long 0x00000000,0x00000000,0x00000000,0x0000fffe + .long 0x0000ffff,0xffffffff,0xffff0000,0x0000ffff + .long 0x00000000,0x00000000,0x00000000,0x0000fffe + .long 0x0000ffff,0xffffffff,0xffff0000,0x0000ffff + .long 0x00000000,0x00000000,0x00000000,0x0000c07e + .long 0x0000ffff,0xff000000,0x00000000,0x0000ffff + .long 0x00000000,0x00000000,0x00000000,0x0000c07e + .long 0x0000ffff,0xff000000,0x00000000,0x0000ffff + .long 0x00000000,0x00000000,0x00000000,0x0000c3fe + .long 0x0000ffff,0xffffffff,0xf8000000,0x0000ffff + .long 0x00000000,0x00000000,0x00000000,0x0000c3fe + .long 0x0000ffff,0xffffffff,0xf8000000,0x0000700c + .long 0x61ffffff,0xe82c43ee,0xff6c700c,0x61ffffff + .long 0x38664a81,0x66ff0000,0x0a14e9ee,0x004fff6c + .long 0x0c407fff,0x66024e75,0x102eff6f,0x0200000f + .long 0x660e4aae,0xff706608,0x4aaeff74,0x66024e75 + .long 0x41eeff6c,0x61ff0000,0x001cf22e,0xf080ff6c + .long 0x4e750000,0x00000203,0x02030203,0x03020302 + .long 0x02032d68,0x0000ff84,0x2d680004,0xff882d68 + .long 0x0008ff8c,0x41eeff84,0x48e73c00,0xf227e001 + .long 0x74027604,0x28104281,0x4c3c1001,0x0000000a + .long 0xe9c408c4,0xd2805803,0x51caffee,0x0804001e + .long 0x67024481,0x04810000,0x00106c0e,0x44810084 + .long 0x40000000,0x00904000,0x00002f01,0x7201f23c + .long 0x44000000,0x0000e9d0,0x0704f200,0x58222830 + .long 0x1c007600,0x7407f23c,0x44234120,0x0000e9c4 + .long 0x08c4f200,0x58225803,0x51caffec,0x52810c81 + .long 0x00000002,0x6fd80810,0x001f6704,0xf200001a + .long 0x22170c81,0x0000001b,0x6f0000e4,0x0810001e + .long 0x66744281,0x2810e9c4,0x07046624,0x52817a01 + .long 0x28305c00,0x66085081,0x52852830,0x5c004283 + .long 0x7407e9c4,0x08c46608,0x58835281,0x51cafff4 + .long 0x20012217,0x92806c10,0x44812810,0x00844000 + .long 0x00000090,0x40000000,0x43fb0170,0x00000666 + .long 0x4283f23c,0x44803f80,0x00007403,0xe2806406 + .long 0xf23148a3,0x38000683,0x0000000c,0x4a8066ec + .long 0xf2000423,0x60684281,0x7a022830,0x5c006608 + .long 0x53855081,0x28305c00,0x761c7407,0xe9c408c4 + .long 0x66085983,0x528151ca,0xfff42001,0x22179280 + .long 0x6e104481,0x28100284,0xbfffffff,0x0290bfff + .long 0xffff43fb,0x01700000,0x05fc4283,0xf23c4480 + .long 0x3f800000,0x7403e280,0x6406f231,0x48a33800 + .long 0x06830000,0x000c4a80,0x66ecf200,0x0420262e + .long 0xff60e9c3,0x26822810,0xe582e9c4,0x0002d480 + .long 0x43fafe50,0x10312800,0x4283efc3,0x0682f203 + .long 0x9000e280,0x640a43fb,0x01700000,0x06446016 + .long 0xe280640a,0x43fb0170,0x000006d2,0x600843fb + .long 0x01700000,0x05902001,0x6a084480,0x00904000 + .long 0x00004283,0xf23c4480,0x3f800000,0xe2806406 + .long 0xf23148a3,0x38000683,0x0000000c,0x4a8066ec + .long 0x0810001e,0x6706f200,0x04206004,0xf2000423 + .long 0xf200a800,0x08800009,0x6706006e,0x0108ff66 + .long 0x588ff21f,0xd0404cdf,0x003cf23c,0x90000000 + .long 0x0000f23c,0x88000000,0x00004e75,0x3ffd0000 + .long 0x9a209a84,0xfbcff798,0x00000000,0x3ffd0000 + .long 0x9a209a84,0xfbcff799,0x00000000,0x3f800000 + .long 0x00000000,0x00000000,0x00000000,0x40000000 + .long 0x00000000,0x00000000,0x00000000,0x41200000 + .long 0x00000000,0x00000000,0x00000000,0x459a2800 + .long 0x00000000,0x00000000,0x00000000,0x00000000 + .long 0x03030202,0x03020203,0x02030302,0x48e73f20 + .long 0xf227e007,0xf23c9000,0x00000020,0x2d50ff58 + .long 0x2e00422e,0xff500c2e,0x0004ff4e,0x66000030 + .long 0x30100240,0x7fff2228,0x00042428,0x00085340 + .long 0xe38ae391,0x4a816cf6,0x4a406e04,0x50eeff50 + .long 0x02407fff,0x30802141,0x00042142,0x00082d50 + .long 0xff902d68,0x0004ff94,0x2d680008,0xff9802ae + .long 0x7fffffff,0xff904a2e,0xff506708,0x2c3cffff + .long 0xecbb6038,0x302eff90,0x3d7c3fff,0xff90f22e + .long 0x4800ff90,0x04403fff,0xf2005022,0xf23a4428 + .long 0xff1cf293,0x000ef23a,0x4823ff02,0xf2066000 + .long 0x600af23a,0x4823fee6,0xf2066000,0xf23c8800 + .long 0x00000000,0x42454a87,0x6f042807,0x60062806 + .long 0x98875284,0x4a846f18,0x0c840000,0x00116f12 + .long 0x78114a87,0x6f0c00ae,0x00002080,0xff646002 + .long 0x78014a87,0x6e06be86,0x6d022c07,0x20065280 + .long 0x90844845,0x42454242,0x4a806c14,0x52450c80 + .long 0xffffecd4,0x6e080680,0x00000018,0x74184480 + .long 0xf23a4480,0xfe98e9ee,0x1682ff60,0xe349d245 + .long 0xe3494aae,0xff586c02,0x528145fa,0xfec01632 + .long 0x1800e98b,0xf2039000,0xe88b4a03,0x660a43fb + .long 0x01700000,0x03706016,0xe20b640a,0x43fb0170 + .long 0x000003fe,0x600843fb,0x01700000,0x04904283 + .long 0xe2886406,0xf23148a3,0x38000683,0x0000000c + .long 0x4a8066ec,0xf23c8800,0x00000000,0xf23c9000 + .long 0x00000010,0xf2104800,0xf2000018,0x4a456608 + .long 0xf2000420,0x6000008e,0x4a2eff50,0x67000072 + .long 0xf227e002,0x36170243,0x7fff0050,0x8000d650 + .long 0x04433fff,0xd6690024,0x04433fff,0xd6690030 + .long 0x04433fff,0x6b000048,0x02578000,0x87570250 + .long 0x7fff2f28,0x00082f28,0x00042f3c,0x3fff0000 + .long 0xf21fd080,0xf21f4823,0x2f29002c,0x2f290028 + .long 0x2f3c3fff,0x00002f29,0x00382f29,0x00342f3c + .long 0x3fff0000,0xf21f4823,0xf21f4823,0x601660fe + .long 0x4a42670c,0xf2294823,0x0024f229,0x48230030 + .long 0xf2000423,0xf200a800,0xf22e6800,0xff9045ee + .long 0xff900800,0x0009670e,0x00aa0000,0x00010008 + .long 0xf22e4800,0xff902d6e,0xff60ff54,0x02ae0000 + .long 0x0030ff60,0x48e7c0c0,0x2f2eff54,0x2f2eff58 + .long 0x41eeff90,0xf2106800,0x4aaeff58,0x6c060090 + .long 0x80000000,0x2f2eff64,0xf22e9000,0xff60f23c + .long 0x88000000,0x0000f22e,0x4801ff90,0xf200a800 + .long 0x816eff66,0x1d57ff64,0x588f2d5f,0xff582d5f + .long 0xff544cdf,0x03032d6e,0xff58ff90,0x2d6eff54 + .long 0xff604845,0x4a4566ff,0x00000086,0xf23a4500 + .long 0xfcec2004,0x53804283,0xe2886406,0xf2314923 + .long 0x38000683,0x0000000c,0x4a8066ec,0x4a2eff50 + .long 0x670af200,0x001860ff,0x00000028,0xf2000018 + .long 0xf2000838,0xf293001a,0x53863a3c,0x0001f23c + .long 0x90000000,0x0020f23a,0x4523fcc2,0x6000fda8 + .long 0xf23a4523,0xfcb8f200,0x0838f294,0x005cf292 + .long 0x000cf23a,0x4420fca6,0x5286604c,0x52863a3c + .long 0x0001f23c,0x90000000,0x00206000,0xfd7af23a + .long 0x4500fc6a,0x20044283,0xe2886406,0xf2314923 + .long 0x38000683,0x0000000c,0x4a8066ec,0xf2000018 + .long 0xf2000838,0xf28e0012,0xf23a4420,0xfc605286 + .long 0x5284f23a,0x4523fc56,0xf23c9000,0x00000010 + .long 0xf2000820,0x41eeff84,0xf2106800,0x24280004 + .long 0x26280008,0x42a80004,0x42a80008,0x20104840 + .long 0x67140480,0x00003ffd,0x4a806e0a,0x4480e28a + .long 0xe29351c8,0xfffa4a82,0x66044a83,0x67104281 + .long 0x06830000,0x0080d581,0x0283ffff,0xff802004 + .long 0x568861ff,0x000002b0,0x4a2eff50,0x6728f200 + .long 0x003af281,0x000cf206,0x4000f200,0x0018602e + .long 0x4a876d08,0xf23a4400,0xfbe46022,0xf2064000 + .long 0xf2000018,0x6018f200,0x003af28e,0x000af23a + .long 0x4400fb9a,0x6008f206,0x4000f200,0x0018f229 + .long 0x48200018,0xf22e6800,0xff90242a,0x0004262a + .long 0x00083012,0x670e0440,0x3ffd4440,0xe28ae293 + .long 0x51c8fffa,0x42810683,0x00000080,0xd5810283 + .long 0xffffff80,0x700441ee,0xff5461ff,0x00000228 + .long 0x202eff54,0x720ce2a8,0xefee010c,0xff84e2a8 + .long 0xefee0404,0xff844a00,0x670800ae,0x00002080 + .long 0xff644280,0x022e000f,0xff844aae,0xff586c02 + .long 0x70024a86,0x6c025280,0xefee0002,0xff84f23c + .long 0x88000000,0x0000f21f,0xd0e04cdf,0x04fc4e75 + .long 0x40020000,0xa0000000,0x00000000,0x40050000 + .long 0xc8000000,0x00000000,0x400c0000,0x9c400000 + .long 0x00000000,0x40190000,0xbebc2000,0x00000000 + .long 0x40340000,0x8e1bc9bf,0x04000000,0x40690000 + .long 0x9dc5ada8,0x2b70b59e,0x40d30000,0xc2781f49 + .long 0xffcfa6d5,0x41a80000,0x93ba47c9,0x80e98ce0 + .long 0x43510000,0xaa7eebfb,0x9df9de8e,0x46a30000 + .long 0xe319a0ae,0xa60e91c7,0x4d480000,0xc9767586 + .long 0x81750c17,0x5a920000,0x9e8b3b5d,0xc53d5de5 + .long 0x75250000,0xc4605202,0x8a20979b,0x40020000 + .long 0xa0000000,0x00000000,0x40050000,0xc8000000 + .long 0x00000000,0x400c0000,0x9c400000,0x00000000 + .long 0x40190000,0xbebc2000,0x00000000,0x40340000 + .long 0x8e1bc9bf,0x04000000,0x40690000,0x9dc5ada8 + .long 0x2b70b59e,0x40d30000,0xc2781f49,0xffcfa6d6 + .long 0x41a80000,0x93ba47c9,0x80e98ce0,0x43510000 + .long 0xaa7eebfb,0x9df9de8e,0x46a30000,0xe319a0ae + .long 0xa60e91c7,0x4d480000,0xc9767586,0x81750c18 + .long 0x5a920000,0x9e8b3b5d,0xc53d5de5,0x75250000 + .long 0xc4605202,0x8a20979b,0x40020000,0xa0000000 + .long 0x00000000,0x40050000,0xc8000000,0x00000000 + .long 0x400c0000,0x9c400000,0x00000000,0x40190000 + .long 0xbebc2000,0x00000000,0x40340000,0x8e1bc9bf + .long 0x04000000,0x40690000,0x9dc5ada8,0x2b70b59d + .long 0x40d30000,0xc2781f49,0xffcfa6d5,0x41a80000 + .long 0x93ba47c9,0x80e98cdf,0x43510000,0xaa7eebfb + .long 0x9df9de8d,0x46a30000,0xe319a0ae,0xa60e91c6 + .long 0x4d480000,0xc9767586,0x81750c17,0x5a920000 + .long 0x9e8b3b5d,0xc53d5de4,0x75250000,0xc4605202 + .long 0x8a20979a,0x48e7ff00,0x7e015380,0x28022a03 + .long 0xe9c21003,0xe782e9c3,0x6003e783,0x8486e385 + .long 0xe3944846,0xd346d685,0x4e71d584,0x4e71d346 + .long 0x48464a47,0x67124847,0xe947de41,0x10c74847 + .long 0x424751c8,0xffc86012,0x48473e01,0x48475247 + .long 0x51c8ffba,0x4847e94f,0x10c74cdf,0x00ff4e75 + .long 0x70016100,0x00d63d7c,0x0121000a,0x6000007e + .long 0x70026100,0x00c63d7c,0x0141000a,0x606e7004 + .long 0x610000b8,0x3d7c0101,0x000a6060,0x70086100 + .long 0x00aa3d7c,0x0161000a,0x6052700c,0x6100009c + .long 0x3d7c0161,0x000a6044,0x70016100,0x008e3d7c + .long 0x00a1000a,0x60367002,0x61000080,0x3d7c00c1 + .long 0x000a6028,0x70046100,0x00723d7c,0x0081000a + .long 0x601a7008,0x61000064,0x3d7c00e1,0x000a600c + .long 0x700c6100,0x00563d7c,0x00e1000a,0x2d6eff68 + .long 0x0006f22e,0xd0c0ffdc,0xf22e9c00,0xff604cee + .long 0x0303ff9c,0x4e5e2f17,0x2f6f0008,0x00042f6f + .long 0x000c0008,0x2f7c0000,0x0001000c,0x3f6f0006 + .long 0x000c3f7c,0x40080006,0x08170005,0x670608ef + .long 0x0002000d,0x60ffffff,0x2d82122e,0xff410201 + .long 0x00380c01,0x00186700,0x000c0c01,0x00206700 + .long 0x00604e75,0x122eff41,0x02410007,0x323b1206 + .long 0x4efb1002,0x00100016,0x001c0020,0x00240028 + .long 0x002c0030,0x91aeffa4,0x4e7591ae,0xffa84e75 + .long 0x95c04e75,0x97c04e75,0x99c04e75,0x9bc04e75 + .long 0x91964e75,0x0c2e0030,0x000a6612,0x082e0005 + .long 0x0004660a,0x4e7a8800,0x91c04e7b,0x88004e75 + .long 0x448060a0,0x00000000,0x00000000,0x00000000 diff -u --recursive --new-file v1.3.93/linux/arch/m68k/ifpsp060/fskeleton.S linux/arch/m68k/ifpsp060/fskeleton.S --- v1.3.93/linux/arch/m68k/ifpsp060/fskeleton.S Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/ifpsp060/fskeleton.S Sun Feb 18 19:32:57 1996 @@ -0,0 +1,344 @@ +|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +|MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP +|M68000 Hi-Performance Microprocessor Division +|M68060 Software Package +|Production Release P1.00 -- October 10, 1994 +| +|M68060 Software Package Copyright © 1993, 1994 Motorola Inc. All rights reserved. +| +|THE SOFTWARE is provided on an "AS IS" basis and without warranty. +|To the maximum extent permitted by applicable law, +|MOTOROLA DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED, +|INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE +|and any warranty against infringement with regard to the SOFTWARE +|(INCLUDING ANY MODIFIED VERSIONS THEREOF) and any accompanying written materials. +| +|To the maximum extent permitted by applicable law, +|IN NO EVENT SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER +|(INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, +|BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY LOSS) +|ARISING OF THE USE OR INABILITY TO USE THE SOFTWARE. +|Motorola assumes no responsibility for the maintenance and support of the SOFTWARE. +| +|You are hereby granted a copyright license to use, modify, and distribute the SOFTWARE +|so long as this entire notice is retained without alteration in any modified and/or +|redistributed versions, and that such modified versions are clearly identified as such. +|No licenses are granted by implication, estoppel or otherwise under any patents +|or trademarks of Motorola, Inc. +|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +| fskeleton.s +| +| This file contains: +| (1) example "Call-out"s +| (2) example package entry code +| (3) example "Call-out" table +| + + +|################################ +| (1) EXAMPLE CALL-OUTS # +| # +| _060_fpsp_done() # +| _060_real_ovfl() # +| _060_real_unfl() # +| _060_real_operr() # +| _060_real_snan() # +| _060_real_dz() # +| _060_real_inex() # +| _060_real_bsun() # +| _060_real_fline() # +| _060_real_fpu_disabled() # +| _060_real_trap() # +|################################ + +| +| _060_fpsp_done(): +| +| This is the main exit point for the 68060 Floating-Point +| Software Package. For a normal exit, all 060FPSP routines call this +| routine. The operating system can do system dependent clean-up or +| simply execute an "rte" as with the sample code below. +| + .global _060_fpsp_done +_060_fpsp_done: + rte + +| +| _060_real_ovfl(): +| +| This is the exit point for the 060FPSP when an enabled overflow exception +| is present. The routine below should point to the operating system handler +| for enabled overflow conditions. The exception stack frame is an overflow +| stack frame. The FP state frame holds the EXCEPTIONAL OPERAND. +| +| The sample routine below simply clears the exception status bit and +| does an "rte". +| + .global _060_real_ovfl +_060_real_ovfl: + fsave -(%sp) + move.w #0x6000,0x2(%sp) + frestore (%sp)+ + rte + +| +| _060_real_unfl(): +| +| This is the exit point for the 060FPSP when an enabled underflow exception +| is present. The routine below should point to the operating system handler +| for enabled underflow conditions. The exception stack frame is an underflow +| stack frame. The FP state frame holds the EXCEPTIONAL OPERAND. +| +| The sample routine below simply clears the exception status bit and +| does an "rte". +| + .global _060_real_unfl +_060_real_unfl: + fsave -(%sp) + move.w #0x6000,0x2(%sp) + frestore (%sp)+ + rte + +| +| _060_real_operr(): +| +| This is the exit point for the 060FPSP when an enabled operand error exception +| is present. The routine below should point to the operating system handler +| for enabled operand error exceptions. The exception stack frame is an operand error +| stack frame. The FP state frame holds the source operand of the faulting +| instruction. +| +| The sample routine below simply clears the exception status bit and +| does an "rte". +| + .global _060_real_operr +_060_real_operr: + fsave -(%sp) + move.w #0x6000,0x2(%sp) + frestore (%sp)+ + rte + +| +| _060_real_snan(): +| +| This is the exit point for the 060FPSP when an enabled signalling NaN exception +| is present. The routine below should point to the operating system handler +| for enabled signalling NaN exceptions. The exception stack frame is a signalling NaN +| stack frame. The FP state frame holds the source operand of the faulting +| instruction. +| +| The sample routine below simply clears the exception status bit and +| does an "rte". +| + .global _060_real_snan +_060_real_snan: + fsave -(%sp) + move.w #0x6000,0x2(%sp) + frestore (%sp)+ + rte + +| +| _060_real_dz(): +| +| This is the exit point for the 060FPSP when an enabled divide-by-zero exception +| is present. The routine below should point to the operating system handler +| for enabled divide-by-zero exceptions. The exception stack frame is a divide-by-zero +| stack frame. The FP state frame holds the source operand of the faulting +| instruction. +| +| The sample routine below simply clears the exception status bit and +| does an "rte". +| + .global _060_real_dz +_060_real_dz: + fsave -(%sp) + move.w #0x6000,0x2(%sp) + frestore (%sp)+ + rte + +| +| _060_real_inex(): +| +| This is the exit point for the 060FPSP when an enabled inexact exception +| is present. The routine below should point to the operating system handler +| for enabled inexact exceptions. The exception stack frame is an inexact +| stack frame. The FP state frame holds the source operand of the faulting +| instruction. +| +| The sample routine below simply clears the exception status bit and +| does an "rte". +| + .global _060_real_inex +_060_real_inex: + fsave -(%sp) + move.w #0x6000,0x2(%sp) + frestore (%sp)+ + rte + +| +| _060_real_bsun(): +| +| This is the exit point for the 060FPSP when an enabled bsun exception +| is present. The routine below should point to the operating system handler +| for enabled bsun exceptions. The exception stack frame is a bsun +| stack frame. +| +| The sample routine below clears the exception status bit, clears the NaN +| bit in the FPSR, and does an "rte". The instruction that caused the +| bsun will now be re-executed but with the NaN FPSR bit cleared. +| + .global _060_real_bsun +_060_real_bsun: + fsave -(%sp) + + fmove.l %fpsr,-(%sp) + andi.b #0xfe,(%sp) + fmove.l (%sp)+,%fpsr + + add.l #0xc,%sp + rte + +| +| _060_real_fline(): +| +| This is the exit point for the 060FPSP when an F-Line Illegal exception is +| encountered. Three different types of exceptions can enter the F-Line exception +| vector number 11: FP Unimplemented Instructions, FP implemented instructions when +| the FPU is disabled, and F-Line Illegal instructions. The 060FPSP module +| _fpsp_fline() distinguishes between the three and acts appropriately. F-Line +| Illegals branch here. +| + .global _060_real_fline +_060_real_fline: + bras _060_real_fline + +| +| _060_real_fpu_disabled(): +| +| This is the exit point for the 060FPSP when an FPU disabled exception is +| encountered. Three different types of exceptions can enter the F-Line exception +| vector number 11: FP Unimplemented Instructions, FP implemented instructions when +| the FPU is disabled, and F-Line Illegal instructions. The 060FPSP module +| _fpsp_fline() distinguishes between the three and acts appropriately. FPU disabled +| exceptions branch here. +| +| The sample code below enables the FPU, sets the PC field in the exception stack +| frame to the PC of the instruction causing the exception, and does an "rte". +| The execution of the instruction then proceeds with an enabled floating-point +| unit. +| + .global _060_real_fpu_disabled +_060_real_fpu_disabled: + move.l %d0,-(%sp) | enabled the fpu + .long 0x4E7A0808 + |movec pcr,d0 + bclr #0x1,%d0 + .long 0x4E7B0808 + |movec %d0,pcr + move.l (%sp)+,%d0 + + move.l 0xc(%sp),0x2(%sp) | set "Current PC" + rte + +| +| _060_real_trap(): +| +| This is the exit point for the 060FPSP when an emulated "ftrapcc" instruction +| discovers that the trap condition is true and it should branch to the operating +| system handler for the trap exception vector number 7. +| +| The sample code below simply executes an "rte". +| + .global _060_real_trap +_060_real_trap: + rte + +|############################################################################ + +|################################# +| (2) EXAMPLE PACKAGE ENTRY CODE # +|################################# + + .global _060_fpsp_snan +_060_fpsp_snan: + bra.l _FP_CALL_TOP+0x80+0x00 + + .global _060_fpsp_operr +_060_fpsp_operr: + bra.l _FP_CALL_TOP+0x80+0x08 + + .global _060_fpsp_ovfl +_060_fpsp_ovfl: + bra.l _FP_CALL_TOP+0x80+0x10 + + .global _060_fpsp_unfl +_060_fpsp_unfl: + bra.l _FP_CALL_TOP+0x80+0x18 + + .global _060_fpsp_dz +_060_fpsp_dz: + bra.l _FP_CALL_TOP+0x80+0x20 + + .global _060_fpsp_inex +_060_fpsp_inex: + bra.l _FP_CALL_TOP+0x80+0x28 + + .global _060_fpsp_fline +_060_fpsp_fline: + bra.l _FP_CALL_TOP+0x80+0x30 + + .global _060_fpsp_unsupp +_060_fpsp_unsupp: + bra.l _FP_CALL_TOP+0x80+0x38 + + .global _060_fpsp_effadd +_060_fpsp_effadd: + bra.l _FP_CALL_TOP+0x80+0x40 + +|############################################################################ + +|############################### +| (3) EXAMPLE CALL-OUT SECTION # +|############################### + +| The size of this section MUST be 128 bytes!!! + + .global _FP_CALL_TOP +_FP_CALL_TOP: + .long _060_real_bsun - _FP_CALL_TOP + .long _060_real_snan - _FP_CALL_TOP + .long _060_real_operr - _FP_CALL_TOP + .long _060_real_ovfl - _FP_CALL_TOP + .long _060_real_unfl - _FP_CALL_TOP + .long _060_real_dz - _FP_CALL_TOP + .long _060_real_inex - _FP_CALL_TOP + .long _060_real_fline - _FP_CALL_TOP + .long _060_real_fpu_disabled - _FP_CALL_TOP + .long _060_real_trap - _FP_CALL_TOP + .long _060_real_trace - _FP_CALL_TOP + .long _060_real_access - _FP_CALL_TOP + .long _060_fpsp_done - _FP_CALL_TOP + + .long 0x00000000, 0x00000000, 0x00000000 + + .long _060_imem_read - _FP_CALL_TOP + .long _060_dmem_read - _FP_CALL_TOP + .long _060_dmem_write - _FP_CALL_TOP + .long _060_imem_read_word - _FP_CALL_TOP + .long _060_imem_read_long - _FP_CALL_TOP + .long _060_dmem_read_byte - _FP_CALL_TOP + .long _060_dmem_read_word - _FP_CALL_TOP + .long _060_dmem_read_long - _FP_CALL_TOP + .long _060_dmem_write_byte - _FP_CALL_TOP + .long _060_dmem_write_word - _FP_CALL_TOP + .long _060_dmem_write_long - _FP_CALL_TOP + + .long 0x00000000 + + .long 0x00000000, 0x00000000, 0x00000000, 0x00000000 + +|############################################################################ + +| 060 FPSP KERNEL PACKAGE NEEDS TO GO HERE!!! + + .include "fpsp.sa" diff -u --recursive --new-file v1.3.93/linux/arch/m68k/ifpsp060/ftest.sa linux/arch/m68k/ifpsp060/ftest.sa --- v1.3.93/linux/arch/m68k/ifpsp060/ftest.sa Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/ifpsp060/ftest.sa Mon Jan 8 22:08:17 1996 @@ -0,0 +1,371 @@ + dc.l $60ff0000,$00d40000,$60ff0000,$016c0000 + dc.l $60ff0000,$01a80000,$54657374,$696e6720 + dc.l $36383036,$30204650,$53502073,$74617274 + dc.l $65643a0a,$00546573,$74696e67,$20363830 + dc.l $36302046,$50535020,$756e696d,$706c656d + dc.l $656e7465,$6420696e,$73747275,$6374696f + dc.l $6e207374,$61727465,$643a0a00,$54657374 + dc.l $696e6720,$36383036,$30204650,$53502065 + dc.l $78636570,$74696f6e,$20656e61,$626c6564 + dc.l $20737461,$72746564,$3a0a0070,$61737365 + dc.l $640a0020,$6661696c,$65640a00,$4a80660e + dc.l $487affe9,$61ff0000,$1642588f,$4e752f01 + dc.l $61ff0000,$164c588f,$487affd9,$61ff0000 + dc.l $162a588f,$4e754e56,$fe8048e7,$3f3cf227 + dc.l $e0ff487a,$ff3461ff,$00001610,$588f42ae + dc.l $fea0487b,$01700000,$058061ff,$000015fc + dc.l $588f61ff,$00000588,$61ffffff,$ffa242ae + dc.l $fea0487b,$01700000,$126c61ff,$000015dc + dc.l $588f61ff,$00001280,$61ffffff,$ff8242ae + dc.l $fea0487b,$01700000,$0b6461ff,$000015bc + dc.l $61ff0000,$0b7261ff,$ffffff64,$42aefea0 + dc.l $487b0170,$00000de2,$61ff0000,$159e61ff + dc.l $00000df0,$61ffffff,$ff464cdf,$3cfcf21f + dc.l $d0ff4e5e,$4e754e56,$fe8048e7,$3f3cf227 + dc.l $e0ff487a,$feb161ff,$00001570,$588f42ae + dc.l $fea0487b,$01700000,$00fe61ff,$0000155c + dc.l $588f61ff,$00000110,$61ffffff,$ff024cdf + dc.l $3cfcf21f,$d0ff4e5e,$4e754e56,$fe8048e7 + dc.l $3f3cf227,$e0ff487a,$fea461ff,$0000152c + dc.l $588f42ae,$fea0487b,$01700000,$0f1461ff + dc.l $00001518,$61ff0000,$0f1a61ff,$fffffec0 + dc.l $42aefea0,$487b0170,$00000fd2,$61ff0000 + dc.l $14fa61ff,$00000fd8,$61ffffff,$fea242ae + dc.l $fea0487b,$01700000,$0b6061ff,$000014dc + dc.l $61ff0000,$0b6a61ff,$fffffe84,$42aefea0 + dc.l $487b0170,$00000c22,$61ff0000,$14be61ff + dc.l $00000c2c,$61ffffff,$fe6642ae,$fea0487b + dc.l $01700000,$105661ff,$000014a0,$61ff0000 + dc.l $105a61ff,$fffffe48,$42aefea0,$487b0170 + dc.l $00000da2,$61ff0000,$148261ff,$00000da8 + dc.l $61ffffff,$fe2a4cdf,$3cfcf21f,$d0ff4e5e + dc.l $4e750955,$6e696d70,$6c656d65,$6e746564 + dc.l $20465020,$696e7374,$72756374,$696f6e73 + dc.l $2e2e2e00,$52aefea0,$4cfb3fff,$01700000 + dc.l $1390f23b,$d0ff0170,$000013c6,$f23b9c00 + dc.l $01700000,$141c3d7c,$0000fea6,$48ee7fff + dc.l $ff80f22e,$f0ffff20,$f22ebc00,$feb42d7c + dc.l $40000000,$fe802d7c,$c90fdaa2,$fe842d7c + dc.l $2168c235,$fe8844fc,$0000f22e,$480efe80 + dc.l $42eefea4,$48ee7fff,$ffc0f22e,$f0fffec0 + dc.l $f22ebc00,$fea82d7c,$bfbf0000,$ff202d7c + dc.l $80000000,$ff242d7c,$00000000,$ff282d7c + dc.l $08000208,$feb841fa,$ffc22d48,$febc61ff + dc.l $00001288,$4a0066ff,$000012ae,$61ff0000 + dc.l $12b04a00,$66ff0000,$12a052ae,$fea04cfb + dc.l $3fff0170,$000012da,$f23bd0ff,$01700000 + dc.l $1310f23b,$9c000170,$00001366,$3d7c0000 + dc.l $fea648ee,$7fffff80,$f22ef0ff,$ff20f22e + dc.l $bc00feb4,$2d7c3ffe,$0000fe80,$2d7cc90f + dc.l $daa2fe84,$2d7c2168,$c235fe88,$44fc0000 + dc.l $f22e480f,$fe8042ee,$fea448ee,$7fffffc0 + dc.l $f22ef0ff,$fec0f22e,$bc00fea8,$2d7c3fff + dc.l $0000ff20,$2d7c8000,$0000ff24,$2d7c0000 + dc.l $0000ff28,$2d7c0000,$0208feb8,$41faffc2 + dc.l $2d48febc,$61ff0000,$11d24a00,$66ff0000 + dc.l $11f861ff,$000011fa,$4a0066ff,$000011ea + dc.l $52aefea0,$4cfb3fff,$01700000,$1224f23b + dc.l $d0ff0170,$0000125a,$f23b9c00,$01700000 + dc.l $12b03d7c,$0000fea6,$48ee7fff,$ff80f22e + dc.l $f0ffff20,$f22ebc00,$feb444fc,$0000f200 + dc.l $5c3142ee,$fea448ee,$7fffffc0,$f22ef0ff + dc.l $fec0f22e,$bc00fea8,$2d7c4000,$0000ff20 + dc.l $2d7c935d,$8dddff24,$2d7caaa8,$ac17ff28 + dc.l $2d7c0000,$0208feb8,$41faffc4,$2d48febc + dc.l $61ff0000,$11364a00,$66ff0000,$115c61ff + dc.l $0000115e,$4a0066ff,$0000114e,$52aefea0 + dc.l $4cfb3fff,$01700000,$1188f23b,$d0ff0170 + dc.l $000011be,$f23b9c00,$01700000,$1214f23c + dc.l $88000f00,$00007e00,$3d7c0000,$fea648ee + dc.l $7fffff80,$f22ef0ff,$ff20f22e,$bc00feb4 + dc.l $44fc0000,$f2470012,$42eefea4,$48ee7fff + dc.l $ffc0f22e,$f0fffec0,$f22ebc00,$fea82d7c + dc.l $0f008080,$feb841fa,$ffdc2d48,$febc61ff + dc.l $000010a8,$4a0066ff,$000010ce,$61ff0000 + dc.l $10d04a00,$66ff0000,$10c052ae,$fea04cfb + dc.l $3fff0170,$000010fa,$f23bd0ff,$01700000 + dc.l $1130f23b,$9c000170,$00001186,$f23c8800 + dc.l $0f000000,$7e023d7c,$0000fea6,$48ee7fff + dc.l $ff80f22e,$f0ffff20,$f22ebc00,$feb444fc + dc.l $0000f24f,$0012fffc,$42eefea4,$48ee7fff + dc.l $ffc0f22e,$f0fffec0,$f22ebc00,$fea83d7c + dc.l $ffffff9e,$2d7c0f00,$8080feb8,$41faffd4 + dc.l $2d48febc,$61ff0000,$10124a00,$66ff0000 + dc.l $103861ff,$0000103a,$4a0066ff,$0000102a + dc.l $52aefea0,$4cfb3fff,$01700000,$1064f23b + dc.l $d0ff0170,$0000109a,$f23b9c00,$01700000 + dc.l $10f0f23c,$88000f00,$00003d7c,$0000fea6 + dc.l $48ee7fff,$ff80f22e,$f0ffff20,$f22ebc00 + dc.l $feb444fc,$0000f27b,$0012abcd,$ef0142ee + dc.l $fea448ee,$7fffffc0,$f22ef0ff,$fec0f22e + dc.l $bc00fea8,$2d7c0f00,$8080feb8,$41faffd8 + dc.l $2d48febc,$61ff0000,$0f824a00,$66ff0000 + dc.l $0fa861ff,$00000faa,$4a0066ff,$00000f9a + dc.l $42804e75,$09556e69,$6d706c65,$6d656e74 + dc.l $6564203c,$65613e2e,$2e2e0000,$52aefea0 + dc.l $4cfb3fff,$01700000,$0fb8f23b,$d0ff0170 + dc.l $00000fee,$f23b9c00,$01700000,$10443d7c + dc.l $0000fea6,$48ee7fff,$ff80f22e,$f0ffff20 + dc.l $f22ebc00,$feb4f23c,$58000002,$44fc0000 + dc.l $f23c4823,$c0000000,$80000000,$00000000 + dc.l $42eefea4,$48ee7fff,$ffc0f22e,$f0fffec0 + dc.l $f22ebc00,$fea82d7c,$c0010000,$ff202d7c + dc.l $80000000,$ff242d7c,$00000000,$ff282d7c + dc.l $08000000,$feb841fa,$ffb82d48,$febc61ff + dc.l $00000eb8,$4a0066ff,$00000ede,$61ff0000 + dc.l $0ee04a00,$66ff0000,$0ed052ae,$fea04cfb + dc.l $3fff0170,$00000f0a,$f23bd0ff,$01700000 + dc.l $0f40f23b,$9c000170,$00000f96,$3d7c0000 + dc.l $fea648ee,$7fffff80,$f22ef0ff,$ff20f22e + dc.l $bc00feb4,$44fc0000,$f23c4c18,$c1230001 + dc.l $23456789,$12345678,$42eefea4,$48ee7fff + dc.l $ffc0f22e,$f0fffec0,$f22ebc00,$fea82d7c + dc.l $3e660000,$ff202d7c,$d0ed23e8,$ff242d7c + dc.l $d14035bc,$ff282d7c,$00000108,$feb841fa + dc.l $ffb82d48,$febc61ff,$00000e10,$4a0066ff + dc.l $00000e36,$61ff0000,$0e384a00,$66ff0000 + dc.l $0e2852ae,$fea04cfb,$3fff0170,$00000e62 + dc.l $f23bd0ff,$01700000,$0e98f23b,$9c000170 + dc.l $00000eee,$3d7c0000,$fea644fc,$000048ee + dc.l $7fffff80,$f22ef0ff,$ff20f22e,$bc00feb4 + dc.l $f23c9800,$ffffffff,$ffffffff,$42eefea4 + dc.l $48ee7fff,$ffc0f22e,$f0fffec0,$f22ebc00 + dc.l $fea82d7c,$0000fff0,$feb42d7c,$0ffffff8 + dc.l $feb861ff,$00000d84,$4a0066ff,$00000daa + dc.l $61ff0000,$0dac4a00,$66ff0000,$0d9c52ae + dc.l $fea04cfb,$3fff0170,$00000dd6,$f23bd0ff + dc.l $01700000,$0e0cf23b,$9c000170,$00000e62 + dc.l $3d7c0000,$fea644fc,$000048ee,$7fffff80 + dc.l $f22ef0ff,$ff20f22e,$bc00feb4,$f23c9400 + dc.l $ffffffff,$ffffffff,$42eefea4,$48ee7fff + dc.l $ffc0f22e,$f0fffec0,$f22ebc00,$fea82d7c + dc.l $0000fff0,$feb42d7c,$ffffffff,$febc61ff + dc.l $00000cf8,$4a0066ff,$00000d1e,$61ff0000 + dc.l $0d204a00,$66ff0000,$0d1052ae,$fea04cfb + dc.l $3fff0170,$00000d4a,$f23bd0ff,$01700000 + dc.l $0d80f23b,$9c000170,$00000dd6,$3d7c0000 + dc.l $fea644fc,$000048ee,$7fffff80,$f22ef0ff + dc.l $ff20f22e,$bc00feb4,$f23c8c00,$ffffffff + dc.l $ffffffff,$42eefea4,$48ee7fff,$ffc0f22e + dc.l $f0fffec0,$f22ebc00,$fea82d7c,$0ffffff8 + dc.l $feb82d7c,$ffffffff,$febc61ff,$00000c6c + dc.l $4a0066ff,$00000c92,$61ff0000,$0c944a00 + dc.l $66ff0000,$0c8452ae,$fea04cfb,$3fff0170 + dc.l $00000cbe,$f23bd0ff,$01700000,$0cf4f23b + dc.l $9c000170,$00000d4a,$3d7c0000,$fea644fc + dc.l $000048ee,$7fffff80,$f22ef0ff,$ff20f22e + dc.l $bc00feb4,$f23c9c00,$ffffffff,$ffffffff + dc.l $ffffffff,$42eefea4,$48ee7fff,$ffc0f22e + dc.l $f0fffec0,$f22ebc00,$fea82d7c,$0000fff0 + dc.l $feb42d7c,$0ffffff8,$feb82d7c,$ffffffff + dc.l $febc61ff,$00000bd4,$4a0066ff,$00000bfa + dc.l $61ff0000,$0bfc4a00,$66ff0000,$0bec52ae + dc.l $fea04cfb,$3fff0170,$00000c26,$f23bd0ff + dc.l $01700000,$0c5cf23b,$9c000170,$00000cb2 + dc.l $f23c5800,$0001f23c,$58800002,$f23c5900 + dc.l $0003f23c,$59800004,$f23c5a00,$0005f23c + dc.l $5a800006,$f23c5b00,$0007f23c,$5b800008 + dc.l $f23c8400,$00000000,$70aa3d7c,$0000fea6 + dc.l $48eeffff,$ff80f22e,$bc00feb4,$f22ef0ff + dc.l $ff2044fc,$0000f227,$e80042ee,$fea4f22e + dc.l $bc00fea8,$f23c4480,$7f800000,$f23c4580 + dc.l $7f800000,$f23c4680,$7f800000,$f23c4780 + dc.l $7f800000,$f21f4880,$f21f4980,$f21f4a80 + dc.l $f21f4b80,$48eeffff,$ffc0f22e,$f0fffec0 + dc.l $61ff0000,$0af64a00,$66ff0000,$0b1c61ff + dc.l $00000b1e,$4a0066ff,$00000b0e,$52aefea0 + dc.l $4cfb3fff,$01700000,$0b48f23b,$d0ff0170 + dc.l $00000b7e,$f23b9c00,$01700000,$0bd4f23c + dc.l $58000001,$f23c5880,$0002f23c,$59000003 + dc.l $f23c5980,$0004f23c,$5a000005,$f23c5a80 + dc.l $0006f23c,$5b000007,$f23c5b80,$0008f227 + dc.l $6b00f227,$6a00f227,$6900f227,$6800f22e + dc.l $f0ffff20,$f23c4700,$7f800000,$f23c4600 + dc.l $7f800000,$f23c4500,$7f800000,$f23c4400 + dc.l $7f800000,$f23c8400,$00000000,$f23c8800 + dc.l $00000000,$70aa3d7c,$0000fea6,$48eeffff + dc.l $ff80f22e,$bc00feb4,$44fc0000,$f21fd800 + dc.l $42eefea4,$f22ebc00,$fea848ee,$ffffffc0 + dc.l $f22ef0ff,$fec061ff,$00000a10,$4a0066ff + dc.l $00000a36,$61ff0000,$0a384a00,$66ff0000 + dc.l $0a2852ae,$fea04cfb,$3fff0170,$00000a62 + dc.l $f23bd0ff,$01700000,$0a98f23b,$9c000170 + dc.l $00000aee,$f23c5800,$0001f23c,$58800002 + dc.l $f23c5900,$0003f23c,$59800004,$f23c5a00 + dc.l $0005f23c,$5a800006,$f23c5b00,$0007f23c + dc.l $5b800008,$f23c8400,$00000000,$203cffff + dc.l $ff003d7c,$0000fea6,$48eeffff,$ff80f22e + dc.l $bc00feb4,$f22ef0ff,$ff2044fc,$0000f227 + dc.l $e80042ee,$fea4f22e,$bc00fea8,$48eeffff + dc.l $ffc0f22e,$f0fffec0,$61ff0000,$095e4a00 + dc.l $66ff0000,$098461ff,$00000986,$4a0066ff + dc.l $00000976,$42804e75,$094e6f6e,$2d6d6173 + dc.l $6b61626c,$65206f76,$6572666c,$6f772e2e + dc.l $2e0051fc,$52aefea0,$4cfb3fff,$01700000 + dc.l $0990f23b,$d0ff0170,$000009c6,$f23b9c00 + dc.l $01700000,$0a1c3d7c,$0000fea6,$48ee7fff + dc.l $ff80f22e,$f0ffff20,$f22ebc00,$feb4f23c + dc.l $58000002,$2d7c7ffe,$0000fe80,$2d7c8000 + dc.l $0000fe84,$2d7c0000,$0000fe88,$44fc0000 + dc.l $f22e4823,$fe8042ee,$fea448ee,$7fffffc0 + dc.l $f22ef0ff,$fec0f22e,$bc00fea8,$2d7c7fff + dc.l $0000ff20,$2d7c0000,$0000ff24,$2d7c0000 + dc.l $0000ff28,$2d7c0200,$1048feb8,$41faffc2 + dc.l $2d48febc,$61ff0000,$08824a00,$66ff0000 + dc.l $08a861ff,$000008aa,$4a0066ff,$0000089a + dc.l $42804e75,$09456e61,$626c6564,$206f7665 + dc.l $72666c6f,$772e2e2e,$000051fc,$52aefea0 + dc.l $4cfb3fff,$01700000,$08b8f23b,$d0ff0170 + dc.l $000008ee,$f23b9c00,$01700000,$09443d7c + dc.l $0000fea6,$48ee7fff,$ff80f22e,$f0ffff20 + dc.l $f23c9000,$00001000,$f22ebc00,$feb4f23c + dc.l $58000002,$2d7c7ffe,$0000fe80,$2d7c8000 + dc.l $0000fe84,$2d7c0000,$0000fe88,$44fc0000 + dc.l $f22e4823,$fe8042ee,$fea448ee,$7fffffc0 + dc.l $f22ef0ff,$fec0f22e,$bc00fea8,$2d7c7fff + dc.l $0000ff20,$2d7c0000,$0000ff24,$2d7c0000 + dc.l $0000ff28,$2d7c0200,$1048feb8,$41faffc2 + dc.l $2d48febc,$61ff0000,$07a24a00,$66ff0000 + dc.l $07c861ff,$000007ca,$4a0066ff,$000007ba + dc.l $42804e75,$09456e61,$626c6564,$20756e64 + dc.l $6572666c,$6f772e2e,$2e0051fc,$52aefea0 + dc.l $4cfb3fff,$01700000,$07d8f23b,$d0ff0170 + dc.l $0000080e,$f23b9c00,$01700000,$08643d7c + dc.l $0000fea6,$48ee7fff,$ff80f22e,$f0ffff20 + dc.l $f23c9000,$00000800,$f22ebc00,$feb42d7c + dc.l $00000000,$fe802d7c,$80000000,$fe842d7c + dc.l $00000000,$fe88f22e,$d080fe80,$44fc0000 + dc.l $f23c5820,$000242ee,$fea448ee,$7fffffc0 + dc.l $f22ef0ff,$fec0f22e,$bc00fea8,$2d7c0000 + dc.l $0000ff20,$2d7c4000,$0000ff24,$2d7c0000 + dc.l $0000ff28,$2d7c0000,$0800feb8,$41faffc2 + dc.l $2d48febc,$61ff0000,$06c24a00,$66ff0000 + dc.l $06e861ff,$000006ea,$4a0066ff,$000006da + dc.l $42804e75,$094e6f6e,$2d6d6173,$6b61626c + dc.l $6520756e,$64657266,$6c6f772e,$2e2e0000 + dc.l $52aefea0,$4cfb3fff,$01700000,$06f4f23b + dc.l $d0ff0170,$0000072a,$f23b9c00,$01700000 + dc.l $07803d7c,$0000fea6,$48ee7fff,$ff80f22e + dc.l $f0ffff20,$f22ebc00,$feb42d7c,$00000000 + dc.l $fe802d7c,$80000000,$fe842d7c,$00000000 + dc.l $fe88f22e,$d080fe80,$44fc0000,$f23c5820 + dc.l $000242ee,$fea448ee,$7fffffc0,$f22ef0ff + dc.l $fec0f22e,$bc00fea8,$2d7c0000,$0000ff20 + dc.l $2d7c4000,$0000ff24,$2d7c0000,$0000ff28 + dc.l $2d7c0000,$0800feb8,$41faffc2,$2d48febc + dc.l $61ff0000,$05e64a00,$66ff0000,$060c61ff + dc.l $0000060e,$4a0066ff,$000005fe,$42804e75 + dc.l $09456e61,$626c6564,$20696e65,$78616374 + dc.l $2e2e2e00,$52aefea0,$4cfb3fff,$01700000 + dc.l $0620f23b,$d0ff0170,$00000656,$f23b9c00 + dc.l $01700000,$06ac3d7c,$0000fea6,$48ee7fff + dc.l $ff80f22e,$f0ffff20,$f23c9000,$00000200 + dc.l $f22ebc00,$feb42d7c,$50000000,$fe802d7c + dc.l $80000000,$fe842d7c,$00000000,$fe88f22e + dc.l $d080fe80,$44fc0000,$f23c5822,$000242ee + dc.l $fea448ee,$7fffffc0,$f22ef0ff,$fec0f22e + dc.l $bc00fea8,$2d7c5000,$0000ff20,$2d7c8000 + dc.l $0000ff24,$2d7c0000,$0000ff28,$2d7c0000 + dc.l $0208feb8,$41faffc2,$2d48febc,$61ff0000 + dc.l $050a4a00,$66ff0000,$053061ff,$00000532 + dc.l $4a0066ff,$00000522,$42804e75,$09456e61 + dc.l $626c6564,$20534e41,$4e2e2e2e,$000051fc + dc.l $52aefea0,$4cfb3fff,$01700000,$0544f23b + dc.l $d0ff0170,$0000057a,$f23b9c00,$01700000 + dc.l $05d03d7c,$0000fea6,$48ee7fff,$ff80f22e + dc.l $f0ffff20,$f23c9000,$00004000,$f22ebc00 + dc.l $feb42d7c,$ffff0000,$fe802d7c,$00000000 + dc.l $fe842d7c,$00000001,$fe88f22e,$d080fe80 + dc.l $44fc0000,$f23c5822,$000242ee,$fea448ee + dc.l $7fffffc0,$f22ef0ff,$fec0f22e,$bc00fea8 + dc.l $2d7cffff,$0000ff20,$2d7c0000,$0000ff24 + dc.l $2d7c0000,$0001ff28,$2d7c0900,$4080feb8 + dc.l $41faffc2,$2d48febc,$61ff0000,$042e4a00 + dc.l $66ff0000,$045461ff,$00000456,$4a0066ff + dc.l $00000446,$42804e75,$09456e61,$626c6564 + dc.l $204f5045,$52522e2e,$2e0051fc,$52aefea0 + dc.l $4cfb3fff,$01700000,$0468f23b,$d0ff0170 + dc.l $0000049e,$f23b9c00,$01700000,$04f43d7c + dc.l $0000fea6,$48ee7fff,$ff80f22e,$f0ffff20 + dc.l $f23c9000,$00002000,$f22ebc00,$feb42d7c + dc.l $ffff0000,$fe802d7c,$00000000,$fe842d7c + dc.l $00000000,$fe88f22e,$d080fe80,$44fc0000 + dc.l $f23c4422,$7f800000,$42eefea4,$48ee7fff + dc.l $ffc0f22e,$f0fffec0,$f22ebc00,$fea82d7c + dc.l $ffff0000,$ff202d7c,$00000000,$ff242d7c + dc.l $00000000,$ff282d7c,$01002080,$feb841fa + dc.l $ffc02d48,$febc61ff,$00000350,$4a0066ff + dc.l $00000376,$61ff0000,$03784a00,$66ff0000 + dc.l $03684280,$4e750945,$6e61626c,$65642044 + dc.l $5a2e2e2e,$000051fc,$52aefea0,$4cfb3fff + dc.l $01700000,$038cf23b,$d0ff0170,$000003c2 + dc.l $f23b9c00,$01700000,$04183d7c,$0000fea6 + dc.l $48ee7fff,$ff80f22e,$f0ffff20,$f23c9000 + dc.l $00000400,$f22ebc00,$feb42d7c,$40000000 + dc.l $fe802d7c,$80000000,$fe842d7c,$00000000 + dc.l $fe88f22e,$d080fe80,$44fc0000,$f23c5820 + dc.l $000042ee,$fea448ee,$7fffffc0,$f22ef0ff + dc.l $fec0f22e,$bc00fea8,$2d7c4000,$0000ff20 + dc.l $2d7c8000,$0000ff24,$2d7c0000,$0000ff28 + dc.l $2d7c0200,$0410feb8,$41faffc2,$2d48febc + dc.l $61ff0000,$02764a00,$66ff0000,$029c61ff + dc.l $0000029e,$4a0066ff,$0000028e,$42804e75 + dc.l $09556e69,$6d706c65,$6d656e74,$65642064 + dc.l $61746120,$74797065,$2f666f72,$6d61742e + dc.l $2e2e0000,$52aefea0,$4cfb3fff,$01700000 + dc.l $02a0f23b,$d0ff0170,$000002d6,$f23b9c00 + dc.l $01700000,$032c3d7c,$0000fea6,$48ee7fff + dc.l $ff80f22e,$f0ffff20,$f22ebc00,$feb42d7c + dc.l $c03f0000,$fe802d7c,$00000000,$fe842d7c + dc.l $00000001,$fe88f23c,$58000002,$44fc0000 + dc.l $f22e4823,$fe8042ee,$fea448ee,$7fffffc0 + dc.l $f22ef0ff,$fec0f22e,$bc00fea8,$2d7cc001 + dc.l $0000ff20,$2d7c8000,$0000ff24,$2d7c0000 + dc.l $0000ff28,$2d7c0800,$0000feb8,$41faffc2 + dc.l $2d48febc,$61ff0000,$01924a00,$66ff0000 + dc.l $01b861ff,$000001ba,$4a0066ff,$000001aa + dc.l $52aefea0,$4cfb3fff,$01700000,$01e4f23b + dc.l $d0ff0170,$0000021a,$f23b9c00,$01700000 + dc.l $02703d7c,$0000fea6,$48ee7fff,$ff80f22e + dc.l $f0ffff20,$f22ebc00,$feb42d7c,$80000000 + dc.l $fe802d7c,$01000000,$fe842d7c,$00000000 + dc.l $fe88f23c,$40007fff,$ffff44fc,$0000f22e + dc.l $4823fe80,$42eefea4,$48ee7fff,$ffc0f22e + dc.l $f0fffec0,$f22ebc00,$fea82d7c,$80170000 + dc.l $ff202d7c,$fffffffe,$ff242d7c,$00000000 + dc.l $ff282d7c,$08000000,$feb841fa,$ffc22d48 + dc.l $febc61ff,$000000d4,$4a0066ff,$000000fa + dc.l $61ff0000,$00fc4a00,$66ff0000,$00ec52ae + dc.l $fea04cfb,$3fff0170,$00000126,$f23bd0ff + dc.l $01700000,$015cf23b,$9c000170,$000001b2 + dc.l $3d7c0000,$fea648ee,$7fffff80,$f22ef0ff + dc.l $ff20f22e,$bc00feb4,$2d7cc123,$0001fe80 + dc.l $2d7c2345,$6789fe84,$2d7c1234,$5678fe88 + dc.l $44fc0000,$f22e4c18,$fe8042ee,$fea448ee + dc.l $7fffffc0,$f22ef0ff,$fec0f22e,$bc00fea8 + dc.l $2d7c3e66,$0000ff20,$2d7cd0ed,$23e8ff24 + dc.l $2d7cd140,$35bcff28,$2d7c0000,$0108feb8 + dc.l $41faffc2,$2d48febc,$61ff0000,$001e4a00 + dc.l $66ff0000,$004461ff,$00000046,$4a0066ff + dc.l $00000036,$42804e75,$41eeff80,$43eeffc0 + dc.l $700eb189,$66ff0000,$001c51c8,$fff6302e + dc.l $fea6322e,$fea4b041,$66ff0000,$00084280 + dc.l $4e757001,$4e75222e,$fea07001,$4e7541ee + dc.l $ff2043ee,$fec07017,$b18966ff,$0000002c + dc.l $51c8fff6,$41eefeb4,$43eefea8,$b18966ff + dc.l $00000018,$b18966ff,$00000010,$b18966ff + dc.l $00000008,$42804e75,$70014e75,$acacacac + dc.l $acacacac,$acacacac,$acacacac,$acacacac + dc.l $acacacac,$acacacac,$acacacac,$acacacac + dc.l $acacacac,$acacacac,$acacacac,$acacacac + dc.l $acacacac,$acacacac,$acacacac,$7fff0000 + dc.l $ffffffff,$ffffffff,$7fff0000,$ffffffff + dc.l $ffffffff,$7fff0000,$ffffffff,$ffffffff + dc.l $7fff0000,$ffffffff,$ffffffff,$7fff0000 + dc.l $ffffffff,$ffffffff,$7fff0000,$ffffffff + dc.l $ffffffff,$7fff0000,$ffffffff,$ffffffff + dc.l $7fff0000,$ffffffff,$ffffffff,$00000000 + dc.l $00000000,$00000000,$2f00203a,$e884487b + dc.l $0930ffff,$e880202f,$00044e74,$00042f00 + dc.l $203ae872,$487b0930,$ffffe86a,$202f0004 + dc.l $4e740004,$00000000,$00000000,$00000000 diff -u --recursive --new-file v1.3.93/linux/arch/m68k/ifpsp060/ilsp.doc linux/arch/m68k/ifpsp060/ilsp.doc --- v1.3.93/linux/arch/m68k/ifpsp060/ilsp.doc Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/ifpsp060/ilsp.doc Mon Jan 8 22:08:17 1996 @@ -0,0 +1,150 @@ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP +M68000 Hi-Performance Microprocessor Division +M68060 Software Package +Production Release P1.00 -- October 10, 1994 + +M68060 Software Package Copyright © 1993, 1994 Motorola Inc. All rights reserved. + +THE SOFTWARE is provided on an "AS IS" basis and without warranty. +To the maximum extent permitted by applicable law, +MOTOROLA DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED, +INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE +and any warranty against infringement with regard to the SOFTWARE +(INCLUDING ANY MODIFIED VERSIONS THEREOF) and any accompanying written materials. + +To the maximum extent permitted by applicable law, +IN NO EVENT SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER +(INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, +BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY LOSS) +ARISING OF THE USE OR INABILITY TO USE THE SOFTWARE. +Motorola assumes no responsibility for the maintenance and support of the SOFTWARE. + +You are hereby granted a copyright license to use, modify, and distribute the SOFTWARE +so long as this entire notice is retained without alteration in any modified and/or +redistributed versions, and that such modified versions are clearly identified as such. +No licenses are granted by implication, estoppel or otherwise under any patents +or trademarks of Motorola, Inc. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +68060 INTEGER SOFTWARE PACKAGE (Library version) +------------------------------------------------- + +The file ilsp.s contains the "Library version" of the +68060 Integer Software Package. Routines included in this +module can be used to emulate 64-bit divide and multiply, +and the "cmp2" instruction. These instructions are not +implemented in hardware on the 68060 and normally take +exception vector #61 "Unimplemented Integer Instruction". + +By re-compiling a program that uses these instructions, and +making subroutine calls in place of the unimplemented +instructions, a program can avoid the overhead associated with +taking the exception. + +Release file format: +-------------------- +The file ilsp.sa is essentially a hexadecimal image of the +release package. This is the ONLY format which will be supported. +The hex image was created by assembling the source code and +then converting the resulting binary output image into an +ASCII text file. The hexadecimal numbers are listed +using the Motorola Assembly Syntax assembler directive "dc.l" +(define constant longword). The file can be converted to other +assembly syntaxes by using any word processor with a global +search and replace function. + +To assist in assembling and linking this module with other modules, +the installer should add a symbolic label to the top of the file. +This will allow calling routines to access the entry points +of this package. + +The source code ilsp.s has also been included but only for +documentation purposes. + +Release file structure: +----------------------- +The file ilsp.sa contains an "Entry-Point" section and a +code section. The ILSP has no "Call-Out" section. The first section +is the "Entry-Point" section. In order to access a function in the +package, a program must "bsr" or "jsr" to the location listed +below in "68060ILSP Entry Points" that corresponds to the desired +function. A branch instruction located at the selected entry point +within the package will then enter the correct emulation code routine. + +The entry point addresses at the beginning of the package will remain +fixed so that a program calling the routines will not have to be +re-compiled with every new 68060ILSP release. + +For example, to use a 64-bit multiply instruction, +do a "bsr" or "jsr" to the entry point defined by +the 060ILSP entry table. A compiler generated code sequence +for unsigned multiply could look like: + +# mulu.l ,Dh:Dl +# mulu.l _multiplier,%d1:%d0 + + subq.l &0x8,%sp # make room for result on stack + pea (%sp) # pass: result addr on stack + mov.l %d0,-(%sp) # pass: multiplicand on stack + mov.l _multiplier,-(%sp) # pass: multiplier on stack + bsr.l _060LISP_TOP+0x18 # branch to multiply routine + add.l &0xc,%sp # clear arguments from stack + mov.l (%sp)+,%d1 # load result[63:32] + mov.l (%sp)+,%d0 # load result[31:0] + +For a divide: + +# divu.l ,Dr:Dq +# divu.l _divisor,%d1:%d0 + + subq.l &0x8,%sp # make room for result on stack + pea (%sp) # pass: result addr on stack + mov.l %d0,-(%sp) # pass: dividend hi on stack + mov.l %d1,-(%sp) # pass: dividend hi on stack + mov.l _divisor,-(%sp) # pass: divisor on stack + bsr.l _060LISP_TOP+0x08 # branch to divide routine + add.l &0xc,%sp # clear arguments from stack + mov.l (%sp)+,%d1 # load remainder + mov.l (%sp)+,%d0 # load quotient + +The library routines also return the correct condition code +register value. If this is important, then the caller of the library +routine must make sure that the value isn't lost while popping +other items off of the stack. + +An example of using the "cmp2" instruction is as follows: + +# cmp2.l ,Rn +# cmp2.l _bounds,%d0 + + pea _bounds # pass ptr to bounds + mov.l %d0,-(%sp) # pass Rn + bsr.l _060LSP_TOP_+0x48 # branch to "cmp2" routine + mov.w %cc,_tmp # save off condition codes + addq.l &0x8,%sp # clear arguments from stack + +Exception reporting: +-------------------- +If the instruction being emulated is a divide and the source +operand is a zero, then the library routine, as it's last +instruction, executes an implemented divide using a zero +source operand so that an "Integer Divide-by-Zero" exception +will be taken. Although the exception stack frame will not +point to the correct instruction, the user will at least be able +to record that such an event occurred if desired. + +68060ILSP entry points: +----------------------- +_060ILSP_TOP: +0x000: _060LSP__idivs64_ +0x008: _060LSP__idivu64_ + +0x010: _060LSP__imuls64_ +0x018: _060LSP__imulu64_ + +0x020: _060LSP__cmp2_Ab_ +0x028: _060LSP__cmp2_Aw_ +0x030: _060LSP__cmp2_Al_ +0x038: _060LSP__cmp2_Db_ +0x040: _060LSP__cmp2_Dw_ +0x048: _060LSP__cmp2_Dl_ diff -u --recursive --new-file v1.3.93/linux/arch/m68k/ifpsp060/ilsp.sa linux/arch/m68k/ifpsp060/ilsp.sa --- v1.3.93/linux/arch/m68k/ifpsp060/ilsp.sa Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/ifpsp060/ilsp.sa Mon Jan 8 22:08:18 1996 @@ -0,0 +1,101 @@ + dc.l $60ff0000,$01fe0000,$60ff0000,$02080000 + dc.l $60ff0000,$04900000,$60ff0000,$04080000 + dc.l $60ff0000,$051e0000,$60ff0000,$053c0000 + dc.l $60ff0000,$055a0000,$60ff0000,$05740000 + dc.l $60ff0000,$05940000,$60ff0000,$05b40000 + dc.l $51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc + dc.l $51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc + dc.l $51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc + dc.l $51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc + dc.l $51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc + dc.l $51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc + dc.l $51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc + dc.l $51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc + dc.l $51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc + dc.l $51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc + dc.l $51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc + dc.l $51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc + dc.l $51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc + dc.l $51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc + dc.l $51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc + dc.l $51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc + dc.l $51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc + dc.l $51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc + dc.l $51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc + dc.l $51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc + dc.l $51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc + dc.l $51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc + dc.l $51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc + dc.l $51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc + dc.l $51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc + dc.l $51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc + dc.l $51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc + dc.l $4e56fff0,$48e73f00,$42eefff0,$50eeffff + dc.l $60104e56,$fff048e7,$3f0042ee,$fff051ee + dc.l $ffff2e2e,$00086700,$00ae2a2e,$000c2c2e + dc.l $00104a2e,$ffff671a,$4a875dee,$fffe6a02 + dc.l $44874a85,$5deefffd,$6a0844fc,$00004086 + dc.l $40854a85,$66164a86,$67000046,$be866306 + dc.l $cb466000,$00124c47,$6005600a,$be85634c + dc.l $61ff0000,$00864a2e,$ffff6724,$4a2efffd + dc.l $67024485,$102efffe,$b12efffd,$670c0c86 + dc.l $80000000,$62264486,$60060806,$001f661c + dc.l $026e0010,$fff044ee,$fff04a86,$48f60060 + dc.l $01610014,$4cdf00fc,$4e5e4e75,$2a2e000c + dc.l $2c2e0010,$026e001c,$fff0006e,$0002fff0 + dc.l $44eefff0,$60d62dae,$000c0161,$00142dae + dc.l $00100162,$00140004,$44eefff0,$4cdf00fc + dc.l $4e5e80fc,$00004e75,$0c870000,$ffff621e + dc.l $42814845,$48463a06,$8ac73205,$48463a06 + dc.l $8ac74841,$32054245,$48452c01,$4e7542ae + dc.l $fff8422e,$fffc4281,$0807001f,$660e52ae + dc.l $fff8e38f,$e38ee395,$6000ffee,$26072405 + dc.l $48424843,$b4436606,$323cffff,$600a2205 + dc.l $82c30281,$0000ffff,$2f064246,$48462607 + dc.l $2401c4c7,$4843c6c1,$28059883,$48443004 + dc.l $38064a40,$6600000a,$b4846304,$538160de + dc.l $2f052c01,$48462a07,$61ff0000,$006a2405 + dc.l $26062a1f,$2c1f9c83,$9b8264ff,$0000001a + dc.l $53814282,$26074843,$4243dc83,$db822607 + dc.l $42434843,$da834a2e,$fffc6616,$3d41fff4 + dc.l $42814845,$48463a06,$424650ee,$fffc6000 + dc.l $ff6c3d41,$fff63c05,$48464845,$2e2efff8 + dc.l $670a5387,$e28de296,$51cffffa,$2a062c2e + dc.l $fff44e75,$24062606,$28054843,$4844ccc5 + dc.l $cac3c4c4,$c6c44284,$4846dc45,$d744dc42 + dc.l $d7444846,$42454242,$48454842,$da82da83 + dc.l $4e754e56,$fffc48e7,$380042ee,$fffc202e + dc.l $00086700,$005a222e,$000c6700,$00522400 + dc.l $26002801,$48434844,$c0c1c2c3,$c4c4c6c4 + dc.l $42844840,$d041d784,$d042d784,$48404241 + dc.l $42424841,$4842d282,$d283382e,$fffc0204 + dc.l $00104a81,$6a040004,$000844c4,$c34048f6 + dc.l $00030161,$00104cdf,$001c4e5e,$4e754280 + dc.l $4281382e,$fffc0204,$00100004,$000444c4 + dc.l $60da4e56,$fffc48e7,$3c0042ee,$fffc202e + dc.l $000867da,$222e000c,$67d44205,$4a806c06 + dc.l $44800005,$00014a81,$6c064481,$0a050001 + dc.l $24002600,$28014843,$4844c0c1,$c2c3c4c4 + dc.l $c6c44284,$4840d041,$d784d042,$d7844840 + dc.l $42414242,$48414842,$d282d283,$4a056708 + dc.l $46804681,$5280d384,$382efffc,$02040010 + dc.l $4a816a04,$00040008,$44c4c340,$48f60003 + dc.l $01610010,$4cdf003c,$4e5e4e75,$42804281 + dc.l $382efffc,$02040010,$00040004,$44c460da + dc.l $4e56fffc,$48e73800,$42eefffc,$242e0008 + dc.l $10360161,$000c1236,$0162000c,$000149c0 + dc.l $49c16000,$00b84e56,$fffc48e7,$380042ee + dc.l $fffc242e,$00083036,$0161000c,$32360162 + dc.l $000c0002,$48c048c1,$60000092,$4e56fffc + dc.l $48e73800,$42eefffc,$242e0008,$20360161 + dc.l $000c2236,$0162000c,$00046000,$00704e56 + dc.l $fffc48e7,$380042ee,$fffc242e,$00081036 + dc.l $0161000c,$12360162,$000c0001,$49c049c1 + dc.l $49c26000,$00484e56,$fffc48e7,$380042ee + dc.l $fffc242e,$00083036,$0161000c,$32360162 + dc.l $000c0002,$48c048c1,$48c26000,$00204e56 + dc.l $fffc48e7,$380042ee,$fffc242e,$00082036 + dc.l $0161000c,$22360162,$000c0004,$948042c3 + dc.l $02030004,$9280b282,$42c48604,$02030005 + dc.l $382efffc,$0204001a,$880344c4,$4cdf001c + dc.l $4e5e4e75,$00000000,$00000000,$00000000 diff -u --recursive --new-file v1.3.93/linux/arch/m68k/ifpsp060/iskeleton.S linux/arch/m68k/ifpsp060/iskeleton.S --- v1.3.93/linux/arch/m68k/ifpsp060/iskeleton.S Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/ifpsp060/iskeleton.S Sun Feb 18 19:33:27 1996 @@ -0,0 +1,282 @@ +|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +|MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP +|M68000 Hi-Performance Microprocessor Division +|M68060 Software Package +|Production Release P1.00 -- October 10, 1994 +| +|M68060 Software Package Copyright © 1993, 1994 Motorola Inc. All rights reserved. +| +|THE SOFTWARE is provided on an "AS IS" basis and without warranty. +|To the maximum extent permitted by applicable law, +|MOTOROLA DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED, +|INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE +|and any warranty against infringement with regard to the SOFTWARE +|(INCLUDING ANY MODIFIED VERSIONS THEREOF) and any accompanying written materials. +| +|To the maximum extent permitted by applicable law, +|IN NO EVENT SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER +|(INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, +|BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY LOSS) +|ARISING OF THE USE OR INABILITY TO USE THE SOFTWARE. +|Motorola assumes no responsibility for the maintenance and support of the SOFTWARE. +| +|You are hereby granted a copyright license to use, modify, and distribute the SOFTWARE +|so long as this entire notice is retained without alteration in any modified and/or +|redistributed versions, and that such modified versions are clearly identified as such. +|No licenses are granted by implication, estoppel or otherwise under any patents +|or trademarks of Motorola, Inc. +|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +| iskeleton.s +| +| This file contains: +| (1) example "Call-out"s +| (2) example package entry code +| (3) example "Call-out" table +| + + +|################################ +| (1) EXAMPLE CALL-OUTS # +| # +| _060_isp_done() # +| _060_real_chk() # +| _060_real_divbyzero() # +| # +| _060_real_cas() # +| _060_real_cas2() # +| _060_real_lock_page() # +| _060_real_unlock_page() # +|################################ + +| +| _060_isp_done(): +| +| This is and example main exit point for the Unimplemented Integer +| Instruction exception handler. For a normal exit, the +| _isp_unimp() branches to here so that the operating system +| can do any clean-up desired. The stack frame is the +| Unimplemented Integer Instruction stack frame with +| the PC pointing to the instruction following the instruction +| just emulated. +| To simply continue execution at the next instruction, just +| do an "rte". +| + .global _060_isp_done +_060_isp_done: + rte + +| +| _060_real_chk(): +| +| This is an alternate exit point for the Unimplemented Integer +| Instruction exception handler. If the instruction was a "chk2" +| and the operand was out of bounds, then _isp_unimp() creates +| a CHK exception stack frame from the Unimplemented Integer Instrcution +| stack frame and branches to this routine. +| + .global _060_real_chk +_060_real_chk: + tst.b (%sp) | is tracing enabled? + bpls real_chk_end | no + +| +| CHK FRAME TRACE FRAME +| ***************** ***************** +| * Current PC * * Current PC * +| ***************** ***************** +| * 0x2 * 0x018 * * 0x2 * 0x024 * +| ***************** ***************** +| * Next * * Next * +| * PC * * PC * +| ***************** ***************** +| * SR * * SR * +| ***************** ***************** +| + move.b #0x24,0x7(%sp) | set trace vecno + bral _060_real_trace + +real_chk_end: + rte + +| +| _060_real_divbyzero: +| +| This is an alternate exit point for the Unimplemented Integer +| Instruction exception handler isp_unimp(). If the instruction is a 64-bit +| integer divide where the source operand is a zero, then the _isp_unimp() +| creates a Divide-by-zero exception stack frame from the Unimplemented +| Integer Instruction stack frame and branches to this routine. +| +| Remember that a trace exception may be pending. The code below performs +| no action associated with the "chk" exception. If tracing is enabled, +| then it create a Trace exception stack frame from the "chk" exception +| stack frame and branches to the _real_trace() entry point. +| + .global _060_real_divbyzero +_060_real_divbyzero: + tst.b (%sp) | is tracing enabled? + bpls real_divbyzero_end | no + +| +| DIVBYZERO FRAME TRACE FRAME +| ***************** ***************** +| * Current PC * * Current PC * +| ***************** ***************** +| * 0x2 * 0x014 * * 0x2 * 0x024 * +| ***************** ***************** +| * Next * * Next * +| * PC * * PC * +| ***************** ***************** +| * SR * * SR * +| ***************** ***************** +| + move.b #0x24,0x7(%sp) | set trace vecno + bral _060_real_trace + +real_divbyzero_end: + rte + +|########################## + +| +| _060_real_cas(): +| +| Entry point for the selected cas emulation code implementation. +| If the implementation provided by the 68060ISP is sufficient, +| then this routine simply re-enters the package through _isp_cas. +| + .global _060_real_cas +_060_real_cas: + bral _I_CALL_TOP+0x80+0x08 + +| +| _060_real_cas2(): +| +| Entry point for the selected cas2 emulation code implementation. +| If the implementation provided by the 68060ISP is sufficient, +| then this routine simply re-enters the package through _isp_cas2. +| + .global _060_real_cas2 +_060_real_cas2: + bral _I_CALL_TOP+0x80+0x10 + +| +| _060_lock_page(): +| +| Entry point for the operating system's routine to "lock" a page +| from being paged out. This routine is needed by the cas/cas2 +| algorithms so that no page faults occur within the "core" code +| region. Note: the routine must lock two pages if the operand +| spans two pages. +| NOTE: THE ROUTINE SHOULD RETURN AN FSLW VALUE IN D0 ON FAILURE +| SO THAT THE 060SP CAN CREATE A PROPER ACCESS ERROR FRAME. +| Arguments: +| a0 = operand address +| d0 = `xxxxxxff -> supervisor; `xxxxxx00 -> user +| d1 = `xxxxxxff -> longword; `xxxxxx00 -> word +| Expected outputs: +| d0 = 0 -> success; non-zero -> failure +| + .global _060_real_lock_page +_060_real_lock_page: + clr.l %d0 + rts + +| +| _060_unlock_page(): +| +| Entry point for the operating system's routine to "unlock" a +| page that has been "locked" previously with _real_lock_page. +| Note: the routine must unlock two pages if the operand spans +| two pages. +| Arguments: +| a0 = operand address +| d0 = `xxxxxxff -> supervisor; `xxxxxx00 -> user +| d1 = `xxxxxxff -> longword; `xxxxxx00 -> word +| + .global _060_real_unlock_page +_060_real_unlock_page: + clr.l %d0 + rts + +|########################################################################### + +|################################# +| (2) EXAMPLE PACKAGE ENTRY CODE # +|################################# + + .global _060_isp_unimp +_060_isp_unimp: + bral _I_CALL_TOP+0x80+0x00 + + .global _060_isp_cas +_060_isp_cas: + bral _I_CALL_TOP+0x80+0x08 + + .global _060_isp_cas2 +_060_isp_cas2: + bral _I_CALL_TOP+0x80+0x10 + + .global _060_isp_cas_finish +_060_isp_cas_finish: + bra.l _I_CALL_TOP+0x80+0x18 + + .global _060_isp_cas2_finish +_060_isp_cas2_finish: + bral _I_CALL_TOP+0x80+0x20 + + .global _060_isp_cas_inrange +_060_isp_cas_inrange: + bral _I_CALL_TOP+0x80+0x28 + + .global _060_isp_cas_terminate +_060_isp_cas_terminate: + bral _I_CALL_TOP+0x80+0x30 + + .global _060_isp_cas_restart +_060_isp_cas_restart: + bral _I_CALL_TOP+0x80+0x38 + +|########################################################################### + +|############################### +| (3) EXAMPLE CALL-OUT SECTION # +|############################### + +| The size of this section MUST be 128 bytes!!! + + .global _I_CALL_TOP +_I_CALL_TOP: + .long _060_real_chk - _I_CALL_TOP + .long _060_real_divbyzero - _I_CALL_TOP + .long _060_real_trace - _I_CALL_TOP + .long _060_real_access - _I_CALL_TOP + .long _060_isp_done - _I_CALL_TOP + + .long _060_real_cas - _I_CALL_TOP + .long _060_real_cas2 - _I_CALL_TOP + .long _060_real_lock_page - _I_CALL_TOP + .long _060_real_unlock_page - _I_CALL_TOP + + .long 0x00000000, 0x00000000, 0x00000000, 0x00000000 + .long 0x00000000, 0x00000000, 0x00000000 + + .long _060_imem_read - _I_CALL_TOP + .long _060_dmem_read - _I_CALL_TOP + .long _060_dmem_write - _I_CALL_TOP + .long _060_imem_read_word - _I_CALL_TOP + .long _060_imem_read_long - _I_CALL_TOP + .long _060_dmem_read_byte - _I_CALL_TOP + .long _060_dmem_read_word - _I_CALL_TOP + .long _060_dmem_read_long - _I_CALL_TOP + .long _060_dmem_write_byte - _I_CALL_TOP + .long _060_dmem_write_word - _I_CALL_TOP + .long _060_dmem_write_long - _I_CALL_TOP + + .long 0x00000000 + .long 0x00000000, 0x00000000, 0x00000000, 0x00000000 + +|########################################################################### + +| 060 INTEGER KERNEL PACKAGE MUST GO HERE!!! + .include "isp.sa" diff -u --recursive --new-file v1.3.93/linux/arch/m68k/ifpsp060/isp.doc linux/arch/m68k/ifpsp060/isp.doc --- v1.3.93/linux/arch/m68k/ifpsp060/isp.doc Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/ifpsp060/isp.doc Mon Jan 8 22:08:19 1996 @@ -0,0 +1,218 @@ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP +M68000 Hi-Performance Microprocessor Division +M68060 Software Package +Production Release P1.00 -- October 10, 1994 + +M68060 Software Package Copyright © 1993, 1994 Motorola Inc. All rights reserved. + +THE SOFTWARE is provided on an "AS IS" basis and without warranty. +To the maximum extent permitted by applicable law, +MOTOROLA DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED, +INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE +and any warranty against infringement with regard to the SOFTWARE +(INCLUDING ANY MODIFIED VERSIONS THEREOF) and any accompanying written materials. + +To the maximum extent permitted by applicable law, +IN NO EVENT SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER +(INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, +BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY LOSS) +ARISING OF THE USE OR INABILITY TO USE THE SOFTWARE. +Motorola assumes no responsibility for the maintenance and support of the SOFTWARE. + +You are hereby granted a copyright license to use, modify, and distribute the SOFTWARE +so long as this entire notice is retained without alteration in any modified and/or +redistributed versions, and that such modified versions are clearly identified as such. +No licenses are granted by implication, estoppel or otherwise under any patents +or trademarks of Motorola, Inc. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +68060 INTEGER SOFTWARE PACKAGE (Kernel version) +------------------------------------------------ + +The file isp.sa contains the 68060 Integer Software Package. +This package is essentially an exception handler that can be +integrated into an operating system to handle the "Unimplemented +Integer Instruction" exception vector #61. +This exception is taken when any of the integer instructions +not hardware implemented on the 68060 are encountered. The +isp.sa provides full emulation support for these instructions. + +The unimplemented integer instructions are: + 64-bit divide + 64-bit multiply + movep + cmp2 + chk2 + cas (w/ a misaligned effective address) + cas2 + +Release file format: +-------------------- +The file isp.sa is essentially a hexadecimal image of the +release package. This is the ONLY format which will be supported. +The hex image was created by assembling the source code and +then converting the resulting binary output image into an +ASCII text file. The hexadecimal numbers are listed +using the Motorola Assembly Syntax assembler directive "dc.l" +(define constant longword). The file can be converted to other +assembly syntaxes by using any word processor with a global +search and replace function. + +To assist in assembling and linking this module with other modules, +the installer should add a symbolic label to the top of the file. +This will allow calling routines to access the entry points +of this package. + +The source code isp.s has also been included but only for +documentation purposes. + +Release file structure: +----------------------- + +(top of module) + ----------------- + | | - 128 byte-sized section + (1) | Call-Out | - 4 bytes per entry (user fills these in) + | | - example routines in iskeleton.s + ----------------- + | | - 8 bytes per entry + (2) | Entry Point | - user does a "bra" or "jmp" to this address + | | + ----------------- + | | - code section + (3) ~ ~ + | | + ----------------- +(bottom of module) + +The first section of this module is the "Call-out" section. This section +is NOT INCLUDED in isp.sa (an example "Call-out" section is provided at +the end of the file iskeleton.s). The purpose of this section is to allow +the ISP routines to reference external functions that must be provided +by the host operating system. This section MUST be exactly 128 bytes in +size. There are 32 fields, each 4 bytes in size. Each field corresponds +to a function required by the ISP (these functions and their location are +listed in "68060ISP call-outs" below). Each field entry should contain +the address of the corresponding function RELATIVE to the starting address +of the "call-out" section. The "Call-out" section must sit adjacent to the +isp.sa image in memory. + +The second section, the "Entry-point" section, is used by external routines +to access the functions within the ISP. Since the isp.sa hex file contains +no symbol names, this section contains function entry points that are fixed +with respect to the top of the package. The currently defined entry-points +are listed in section "68060 ISP entry points" below. A calling routine +would simply execute a "bra" or "jmp" that jumped to the selected function +entry-point. + +For example, if the 68060 hardware took a "Unimplemented Integer Instruction" +exception (vector #61), the operating system should execute something +similar to: + + bra _060ISP_TOP+128+0 + +(_060ISP_TOP is the starting address of the "Call-out" section; the "Call-out" +section is 128 bytes long; and the Unimplemented Integer ISP handler entry +point is located 0 bytes from the top of the "Entry-point" section.) + +The third section is the code section. After entering through an "Entry-point", +the entry code jumps to the appropriate emulation code within the code section. + +68060ISP call-outs: (details in iskeleton.s) +-------------------- +0x000: _060_real_chk +0x004: _060_real_divbyzero +0x008: _060_real_trace +0x00c: _060_real_access +0x010: _060_isp_done + +0x014: _060_real_cas +0x018: _060_real_cas2 +0x01c: _060_real_lock_page +0x020: _060_real_unlock_page + +0x024: (Motorola reserved) +0x028: (Motorola reserved) +0x02c: (Motorola reserved) +0x030: (Motorola reserved) +0x034: (Motorola reserved) +0x038: (Motorola reserved) +0x03c: (Motorola reserved) + +0x040: _060_imem_read +0x044: _060_dmem_read +0x048: _060_dmem_write +0x04c: _060_imem_read_word +0x050: _060_imem_read_long +0x054: _060_dmem_read_byte +0x058: _060_dmem_read_word +0x05c: _060_dmem_read_long +0x060: _060_dmem_write_byte +0x064: _060_dmem_write_word +0x068: _060_dmem_write_long + +0x06c: (Motorola reserved) +0x070: (Motorola reserved) +0x074: (Motorola reserved) +0x078: (Motorola reserved) +0x07c: (Motorola reserved) + +68060ISP entry points: +----------------------- +0x000: _060_isp_unimp + +0x008: _060_isp_cas +0x010: _060_isp_cas2 +0x018: _060_isp_cas_finish +0x020: _060_isp_cas2_finish +0x028: _060_isp_cas_inrange +0x030: _060_isp_cas_terminate +0x038: _060_isp_cas_restart + +Integrating cas/cas2: +--------------------- +The instructions "cas2" and "cas" (when used with a misaligned effective +address) take the Unimplemented Integer Instruction exception. When the +060ISP is installed properly, these instructions will enter through the +_060_isp_unimp() entry point of the ISP. + +After the 060ISP decodes the instruction type and fetches the appropriate +data registers, and BEFORE the actual emulated transfers occur, the +package calls either the "Call-out" _060_real_cas() or _060_real_cas2(). +If the emulation code provided by the 060ISP is sufficient for the +host system (see isp.s source code), then these "Call-out"s should be +made, by the system integrator, to point directly back into the package +through the "Entry-point"s _060_isp_cas() or _060_isp_cas2(). + +One other necessary action by the integrator is to supply the routines +_060_real_lock_page() and _060_real_unlock_page(). These functions are +defined further in iskeleton.s and the 68060 Software Package Specification. + +If the "core" emulation routines of either "cas" or "cas2" perform some +actions which are too system-specific, then the system integrator must +supply new emulation code. This new emulation code should reside within +the functions _060_real_cas() or _060_real_cas2(). When this new emulation +code has completed, then it should re-enter the 060ISP package through the +"Entry-point" _060_isp_cas_finish() or _060_isp_cas2_finish(). +To see what the register state is upon entering _060_real_cas() or +_060_real_cas2() and what it should be upon return to the package through +_060_isp_cas_finish() or _060_isp_cas2_finish(), please refer to the +source code in isp.s. + +Miscellaneous: +-------------- + +_060_isp_unimp: +---------------- +- documented in 2.2 in spec. +- Basic flow: + exception taken ---> enter _060_isp_unimp --| + | + | + may exit through _060_real_itrace <----| + or | + may exit through _060_real_chk <----| + or | + may exit through _060_real_divbyzero <----| + or | + may exit through _060_isp_done <----| diff -u --recursive --new-file v1.3.93/linux/arch/m68k/ifpsp060/isp.sa linux/arch/m68k/ifpsp060/isp.sa --- v1.3.93/linux/arch/m68k/ifpsp060/isp.sa Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/ifpsp060/isp.sa Mon Jan 8 22:08:19 1996 @@ -0,0 +1,392 @@ + .long 0x60ff0000,0x02360000,0x60ff0000,0x16260000 + .long 0x60ff0000,0x12dc0000,0x60ff0000,0x11ea0000 + .long 0x60ff0000,0x10de0000,0x60ff0000,0x12a40000 + .long 0x60ff0000,0x12560000,0x60ff0000,0x122a0000 + .long 0x51fc51fc,0x51fc51fc,0x51fc51fc,0x51fc51fc + .long 0x51fc51fc,0x51fc51fc,0x51fc51fc,0x51fc51fc + .long 0x51fc51fc,0x51fc51fc,0x51fc51fc,0x51fc51fc + .long 0x51fc51fc,0x51fc51fc,0x51fc51fc,0x51fc51fc + .long 0x2f00203a,0xfefc487b,0x0930ffff,0xfef8202f + .long 0x00044e74,0x00042f00,0x203afeea,0x487b0930 + .long 0xfffffee2,0x202f0004,0x4e740004,0x2f00203a + .long 0xfed8487b,0x0930ffff,0xfecc202f,0x00044e74 + .long 0x00042f00,0x203afec6,0x487b0930,0xfffffeb6 + .long 0x202f0004,0x4e740004,0x2f00203a,0xfeb4487b + .long 0x0930ffff,0xfea0202f,0x00044e74,0x00042f00 + .long 0x203afea2,0x487b0930,0xfffffe8a,0x202f0004 + .long 0x4e740004,0x2f00203a,0xfe90487b,0x0930ffff + .long 0xfe74202f,0x00044e74,0x00042f00,0x203afe7e + .long 0x487b0930,0xfffffe5e,0x202f0004,0x4e740004 + .long 0x2f00203a,0xfe6c487b,0x0930ffff,0xfe48202f + .long 0x00044e74,0x00042f00,0x203afe76,0x487b0930 + .long 0xfffffe32,0x202f0004,0x4e740004,0x2f00203a + .long 0xfe64487b,0x0930ffff,0xfe1c202f,0x00044e74 + .long 0x00042f00,0x203afe52,0x487b0930,0xfffffe06 + .long 0x202f0004,0x4e740004,0x2f00203a,0xfe40487b + .long 0x0930ffff,0xfdf0202f,0x00044e74,0x00042f00 + .long 0x203afe2e,0x487b0930,0xfffffdda,0x202f0004 + .long 0x4e740004,0x2f00203a,0xfe1c487b,0x0930ffff + .long 0xfdc4202f,0x00044e74,0x00042f00,0x203afe0a + .long 0x487b0930,0xfffffdae,0x202f0004,0x4e740004 + .long 0x2f00203a,0xfdf8487b,0x0930ffff,0xfd98202f + .long 0x00044e74,0x00042f00,0x203afde6,0x487b0930 + .long 0xfffffd82,0x202f0004,0x4e740004,0x2f00203a + .long 0xfdd4487b,0x0930ffff,0xfd6c202f,0x00044e74 + .long 0x00042f00,0x203afdc2,0x487b0930,0xfffffd56 + .long 0x202f0004,0x4e740004,0x4e56ffa0,0x48ee3fff + .long 0xffc02d56,0xfff8082e,0x00050004,0x66084e68 + .long 0x2d48fffc,0x600841ee,0x000c2d48,0xfffc422e + .long 0xffaa3d6e,0x0004ffa8,0x2d6e0006,0xffa4206e + .long 0xffa458ae,0xffa461ff,0xffffff26,0x2d40ffa0 + .long 0x0800001e,0x67680800,0x00166628,0x61ff0000 + .long 0x0cb0082e,0x00050004,0x670000ac,0x082e0002 + .long 0xffaa6700,0x00a2082e,0x00070004,0x66000186 + .long 0x600001b0,0x61ff0000,0x0a28082e,0x0002ffaa + .long 0x660e082e,0x0005ffaa,0x6600010a,0x60000078 + .long 0x082e0005,0x000467ea,0x082e0005,0xffaa6600 + .long 0x01264a2e,0x00046b00,0x014c6000,0x01760800 + .long 0x0018670a,0x61ff0000,0x07ae6000,0x004a0800 + .long 0x001b6730,0x48400c00,0x00fc670a,0x61ff0000 + .long 0x0e926000,0x0032206e,0xffa454ae,0xffa461ff + .long 0xfffffe68,0x4a816600,0x019861ff,0x00000d20 + .long 0x60000014,0x61ff0000,0x08c40c2e,0x0010ffaa + .long 0x66000004,0x605c1d6e,0xffa90005,0x082e0005 + .long 0x00046606,0x206efffc,0x4e604cee,0x3fffffc0 + .long 0x082e0007,0x00046612,0x2d6effa4,0x00062cae + .long 0xfff84e5e,0x60ffffff,0xfd622d6e,0xfff8fffc + .long 0x3d6e0004,0x00002d6e,0x00060008,0x2d6effa4 + .long 0x00023d7c,0x20240006,0x598e4e5e,0x60ffffff + .long 0xfd0e1d6e,0xffa90005,0x4cee3fff,0xffc03cae + .long 0x00042d6e,0x00060008,0x2d6effa4,0x00023d7c + .long 0x20180006,0x2c6efff8,0xdffc0000,0x006060ff + .long 0xfffffcb0,0x1d6effa9,0x00054cee,0x3fffffc0 + .long 0x3cae0004,0x2d6e0006,0x00082d6e,0xffa40002 + .long 0x3d7c2014,0x00062c6e,0xfff8dffc,0x00000060 + .long 0x60ffffff,0xfc941d6e,0xffa90005,0x4cee3fff + .long 0xffc02d6e,0x0006000c,0x3d7c2014,0x000a2d6e + .long 0xffa40006,0x2c6efff8,0xdffc0000,0x006460ff + .long 0xfffffc66,0x1d6effa9,0x00054cee,0x3fffffc0 + .long 0x2d6e0006,0x000c3d7c,0x2024000a,0x2d6effa4 + .long 0x00062c6e,0xfff8dffc,0x00000064,0x60ffffff + .long 0xfc4e1d6e,0xffa90005,0x4cee3fff,0xffc03d7c + .long 0x00f4000e,0x2d6effa4,0x000a3d6e,0x00040008 + .long 0x2c6efff8,0xdffc0000,0x006860ff,0xfffffc4c + .long 0x2c882d40,0xfffc4fee,0xffc04cdf,0x7fff2f2f + .long 0x000c2f6f,0x00040010,0x2f6f000c,0x00042f6f + .long 0x0008000c,0x2f5f0004,0x3f7c4008,0x00066028 + .long 0x4cee3fff,0xffc04e5e,0x514f2eaf,0x00083f6f + .long 0x000c0004,0x3f7c4008,0x00062f6f,0x00020008 + .long 0x2f7c0942,0x8001000c,0x08170005,0x670608ef + .long 0x0002000d,0x60ffffff,0xfbcc0c2e,0x0040ffaa + .long 0x660c4280,0x102effab,0x2daeffac,0x0ce04e75 + .long 0x2040302e,0xffa03200,0x0240003f,0x02810000 + .long 0x0007303b,0x020a4efb,0x00064afc,0x00400000 + .long 0x00000000,0x00000000,0x00000000,0x00000000 + .long 0x00000000,0x00000000,0x00000000,0x00000080 + .long 0x0086008c,0x00920098,0x009e00a4,0x00aa00b0 + .long 0x00ce00ec,0x010a0128,0x01460164,0x01820196 + .long 0x01b401d2,0x01f0020e,0x022c024a,0x0268027c + .long 0x029a02b8,0x02d602f4,0x03120330,0x034e036c + .long 0x036c036c,0x036c036c,0x036c036c,0x036c03d6 + .long 0x03f0040a,0x042a03ca,0x00000000,0x0000206e + .long 0xffe04e75,0x206effe4,0x4e75206e,0xffe84e75 + .long 0x206effec,0x4e75206e,0xfff04e75,0x206efff4 + .long 0x4e75206e,0xfff84e75,0x206efffc,0x4e752008 + .long 0x206effe0,0xd0882d40,0xffe02d48,0xffac1d7c + .long 0x0000ffab,0x1d7c0040,0xffaa4e75,0x2008206e + .long 0xffe4d088,0x2d40ffe4,0x2d48ffac,0x1d7c0001 + .long 0xffab1d7c,0x0040ffaa,0x4e752008,0x206effe8 + .long 0xd0882d40,0xffe82d48,0xffac1d7c,0x0002ffab + .long 0x1d7c0040,0xffaa4e75,0x2008206e,0xffecd088 + .long 0x2d40ffec,0x2d48ffac,0x1d7c0003,0xffab1d7c + .long 0x0040ffaa,0x4e752008,0x206efff0,0xd0882d40 + .long 0xfff02d48,0xffac1d7c,0x0004ffab,0x1d7c0040 + .long 0xffaa4e75,0x2008206e,0xfff4d088,0x2d40fff4 + .long 0x2d48ffac,0x1d7c0005,0xffab1d7c,0x0040ffaa + .long 0x4e752008,0x206efff8,0xd0882d40,0xfff82d48 + .long 0xffac1d7c,0x0006ffab,0x1d7c0040,0xffaa4e75 + .long 0x1d7c0004,0xffaa2008,0x206efffc,0xd0882d40 + .long 0xfffc4e75,0x202effe0,0x2d40ffac,0x90882d40 + .long 0xffe02040,0x1d7c0000,0xffab1d7c,0x0040ffaa + .long 0x4e75202e,0xffe42d40,0xffac9088,0x2d40ffe4 + .long 0x20401d7c,0x0001ffab,0x1d7c0040,0xffaa4e75 + .long 0x202effe8,0x2d40ffac,0x90882d40,0xffe82040 + .long 0x1d7c0002,0xffab1d7c,0x0040ffaa,0x4e75202e + .long 0xffec2d40,0xffac9088,0x2d40ffec,0x20401d7c + .long 0x0003ffab,0x1d7c0040,0xffaa4e75,0x202efff0 + .long 0x2d40ffac,0x90882d40,0xfff02040,0x1d7c0004 + .long 0xffab1d7c,0x0040ffaa,0x4e75202e,0xfff42d40 + .long 0xffac9088,0x2d40fff4,0x20401d7c,0x0005ffab + .long 0x1d7c0040,0xffaa4e75,0x202efff8,0x2d40ffac + .long 0x90882d40,0xfff82040,0x1d7c0006,0xffab1d7c + .long 0x0040ffaa,0x4e751d7c,0x0008ffaa,0x202efffc + .long 0x90882d40,0xfffc2040,0x4e75206e,0xffa454ae + .long 0xffa461ff,0xfffff9d4,0x4a8166ff,0xfffffd04 + .long 0x3040d1ee,0xffe04e75,0x206effa4,0x54aeffa4 + .long 0x61ffffff,0xf9b64a81,0x66ffffff,0xfce63040 + .long 0xd1eeffe4,0x4e75206e,0xffa454ae,0xffa461ff + .long 0xfffff998,0x4a8166ff,0xfffffcc8,0x3040d1ee + .long 0xffe84e75,0x206effa4,0x54aeffa4,0x61ffffff + .long 0xf97a4a81,0x66ffffff,0xfcaa3040,0xd1eeffec + .long 0x4e75206e,0xffa454ae,0xffa461ff,0xfffff95c + .long 0x4a8166ff,0xfffffc8c,0x3040d1ee,0xfff04e75 + .long 0x206effa4,0x54aeffa4,0x61ffffff,0xf93e4a81 + .long 0x66ffffff,0xfc6e3040,0xd1eefff4,0x4e75206e + .long 0xffa454ae,0xffa461ff,0xfffff920,0x4a8166ff + .long 0xfffffc50,0x3040d1ee,0xfff84e75,0x206effa4 + .long 0x54aeffa4,0x61ffffff,0xf9024a81,0x66ffffff + .long 0xfc323040,0xd1eefffc,0x4e752f01,0x206effa4 + .long 0x54aeffa4,0x61ffffff,0xf8e24a81,0x66ffffff + .long 0xfc12221f,0x207614e0,0x08000008,0x670e48e7 + .long 0x3c002a00,0x260860ff,0x000000ec,0x2f022200 + .long 0xe9590241,0x000f2236,0x14c00800,0x000b6602 + .long 0x48c12400,0xef5a0282,0x00000003,0xe5a949c0 + .long 0xd081d1c0,0x241f4e75,0x1d7c0080,0xffaa206e + .long 0xffa44e75,0x206effa4,0x54aeffa4,0x61ffffff + .long 0xf87a4a81,0x66ffffff,0xfbaa3040,0x4e75206e + .long 0xffa458ae,0xffa461ff,0xfffff876,0x4a8166ff + .long 0xfffffb90,0x20404e75,0x206effa4,0x54aeffa4 + .long 0x61ffffff,0xf8464a81,0x66ffffff,0xfb763040 + .long 0xd1eeffa4,0x55884e75,0x206effa4,0x54aeffa4 + .long 0x61ffffff,0xf8264a81,0x66ffffff,0xfb56206e + .long 0xffa45588,0x08000008,0x670e48e7,0x3c002a00 + .long 0x260860ff,0x00000030,0x2f022200,0xe9590241 + .long 0x000f2236,0x14c00800,0x000b6602,0x48c12400 + .long 0xef5a0282,0x00000003,0xe5a949c0,0xd081d1c0 + .long 0x241f4e75,0x08050006,0x67044282,0x6016e9c5 + .long 0x24042436,0x24c00805,0x000b6602,0x48c2e9c5 + .long 0x0542e1aa,0x08050007,0x67024283,0xe9c50682 + .long 0x0c000002,0x6d346718,0x206effa4,0x58aeffa4 + .long 0x61ffffff,0xf7ac4a81,0x66ffffff,0xfac66018 + .long 0x206effa4,0x54aeffa4,0x61ffffff,0xf77e4a81 + .long 0x66ffffff,0xfaae48c0,0xd680e9c5,0x07826700 + .long 0x006a0c00,0x00026d34,0x6718206e,0xffa458ae + .long 0xffa461ff,0xfffff76a,0x4a8166ff,0xfffffa84 + .long 0x601c206e,0xffa454ae,0xffa461ff,0xfffff73c + .long 0x4a8166ff,0xfffffa6c,0x48c06002,0x42802800 + .long 0x08050002,0x67122043,0x61ffffff,0xf7764a81 + .long 0x6624d082,0xd0846016,0xd6822043,0x61ffffff + .long 0xf7624a81,0x6610d084,0x6004d682,0x20032040 + .long 0x4cdf003c,0x4e752043,0x203c0101,0x000160ff + .long 0xfffff9f0,0x322effa0,0x10010240,0x00072076 + .long 0x04e0d0ee,0xffa20801,0x00076700,0x008c3001 + .long 0xef580240,0x00072036,0x04c00801,0x00066752 + .long 0x24002448,0xe19a2002,0x61ffffff,0xf71c4a81 + .long 0x660000fc,0x544a204a,0xe19a2002,0x61ffffff + .long 0xf7084a81,0x660000e8,0x544a204a,0xe19a2002 + .long 0x61ffffff,0xf6f44a81,0x660000d4,0x544a204a + .long 0xe19a2002,0x61ffffff,0xf6e04a81,0x660000c0 + .long 0x4e752400,0x2448e048,0x61ffffff,0xf6cc4a81 + .long 0x660000ac,0x544a204a,0x200261ff,0xfffff6ba + .long 0x4a816600,0x009a4e75,0x08010006,0x675c2448 + .long 0x61ffffff,0xf6624a81,0x66000092,0x2400544a + .long 0x204a61ff,0xfffff650,0x4a816600,0x0080e14a + .long 0x1400544a,0x204a61ff,0xfffff63c,0x4a816600 + .long 0x006ce18a,0x1400544a,0x204a61ff,0xfffff628 + .long 0x4a816600,0x0058e18a,0x1400122e,0xffa0e209 + .long 0x02410007,0x2d8214c0,0x4e752448,0x61ffffff + .long 0xf6064a81,0x66000036,0x2400544a,0x204a61ff + .long 0xfffff5f4,0x4a816600,0x0024e14a,0x1400122e + .long 0xffa0e209,0x02410007,0x3d8214c2,0x4e75204a + .long 0x203c00a1,0x000160ff,0xfffff8a8,0x204a203c + .long 0x01210001,0x60ffffff,0xf89a61ff,0xfffff914 + .long 0x102effa2,0xe9180240,0x000f2436,0x04c00c2e + .long 0x0002ffa0,0x6d506728,0x244861ff,0xfffff5c4 + .long 0x4a816600,0x009e2600,0x588a204a,0x61ffffff + .long 0xf5b24a81,0x6600008c,0x22002003,0x60000048 + .long 0x244861ff,0xfffff59c,0x4a816600,0x00763200 + .long 0x484048c0,0x48c1082e,0x0007ffa2,0x66000028 + .long 0x48c26000,0x00222448,0x61ffffff,0xf5604a81 + .long 0x6600005e,0x1200e048,0x49c049c1,0x082e0007 + .long 0xffa26602,0x49c29480,0x42c30203,0x00049280 + .long 0xb28242c4,0x86040203,0x0005382e,0xffa80204 + .long 0x001a8803,0x3d44ffa8,0x082e0003,0xffa26602 + .long 0x4e750804,0x00006602,0x4e751d7c,0x0010ffaa + .long 0x4e75204a,0x203c0101,0x000160ff,0xfffff7c4 + .long 0x204a203c,0x01410001,0x60ffffff,0xf7b6102e + .long 0xffa10200,0x00386600,0x0208102e,0xffa10240 + .long 0x00072e36,0x04c06700,0x00c0102e,0xffa3122e + .long 0xffa20240,0x0007e809,0x02410007,0x3d40ffb2 + .long 0x3d41ffb4,0x2a3604c0,0x2c3614c0,0x082e0003 + .long 0xffa2671a,0x4a875dee,0xffb06a02,0x44874a85 + .long 0x5deeffb1,0x6a0844fc,0x00004086,0x40854a85 + .long 0x66164a86,0x67000048,0xbe866306,0xcb466000 + .long 0x00124c47,0x6005600a,0xbe85634e,0x61ff0000 + .long 0x0068082e,0x0003ffa2,0x67244a2e,0xffb16702 + .long 0x4485102e,0xffb0b12e,0xffb1670c,0x0c868000 + .long 0x00006226,0x44866006,0x0806001f,0x661c44ee + .long 0xffa84a86,0x42eeffa8,0x302effb2,0x322effb4 + .long 0x2d8504c0,0x2d8614c0,0x4e7508ee,0x0001ffa9 + .long 0x08ae0000,0xffa94e75,0x022e001e,0xffa9002e + .long 0x0020ffaa,0x4e750c87,0x0000ffff,0x621e4281 + .long 0x48454846,0x3a068ac7,0x32054846,0x3a068ac7 + .long 0x48413205,0x42454845,0x2c014e75,0x42aeffbc + .long 0x422effb6,0x42810807,0x001f660e,0x52aeffbc + .long 0xe38fe38e,0xe3956000,0xffee2607,0x24054842 + .long 0x4843b443,0x6606323c,0xffff600a,0x220582c3 + .long 0x02810000,0xffff2f06,0x42464846,0x26072401 + .long 0xc4c74843,0xc6c12805,0x98834844,0x30043806 + .long 0x4a406600,0x000ab484,0x63045381,0x60de2f05 + .long 0x2c014846,0x2a0761ff,0x0000006a,0x24052606 + .long 0x2a1f2c1f,0x9c839b82,0x64ff0000,0x001a5381 + .long 0x42822607,0x48434243,0xdc83db82,0x26074243 + .long 0x4843da83,0x4a2effb6,0x66163d41,0xffb84281 + .long 0x48454846,0x3a064246,0x50eeffb6,0x6000ff6c + .long 0x3d41ffba,0x3c054846,0x48452e2e,0xffbc670a + .long 0x5387e28d,0xe29651cf,0xfffa2a06,0x2c2effb8 + .long 0x4e752406,0x26062805,0x48434844,0xccc5cac3 + .long 0xc4c4c6c4,0x42844846,0xdc45d744,0xdc42d744 + .long 0x48464245,0x42424845,0x4842da82,0xda834e75 + .long 0x700461ff,0xfffff61c,0x0c2e0080,0xffaa6712 + .long 0x244861ff,0xfffff2dc,0x4a81661e,0x2e006000 + .long 0xfde658ae,0xffa461ff,0xfffff286,0x4a8166ff + .long 0xfffff5a0,0x2e006000,0xfdce61ff,0xfffff5ce + .long 0x204a203c,0x01010001,0x60ffffff,0xf556102e + .long 0xffa10c00,0x00076e00,0x00b40240,0x00072636 + .long 0x04c0342e,0xffa24241,0x1202e95a,0x02420007 + .long 0x283624c0,0x4a846700,0x00884a83,0x67000082 + .long 0x422effb0,0x082e0003,0xffa26718,0x4a836c08 + .long 0x4483002e,0x0001ffb0,0x4a846c08,0x44840a2e + .long 0x0001ffb0,0x2a032c03,0x2e044846,0x4847c6c4 + .long 0xc8c6cac7,0xccc74287,0x4843d644,0xdd87d645 + .long 0xdd874843,0x42444245,0x48444845,0xd885d886 + .long 0x4a2effb0,0x67084683,0x46845283,0xd9872d83 + .long 0x24c044fc,0x00002d84,0x14c042c7,0x02070008 + .long 0x1c2effa9,0x02060010,0x8c071d46,0xffa94e75 + .long 0x42b624c0,0x42b614c0,0x7e0460e4,0x700461ff + .long 0xfffff510,0x0c2e0080,0xffaa6714,0x244861ff + .long 0xfffff1d0,0x4a816600,0x00202600,0x6000ff34 + .long 0x58aeffa4,0x61ffffff,0xf1784a81,0x66ffffff + .long 0xf4922600,0x6000ff1c,0x61ffffff,0xf4c0204a + .long 0x203c0101,0x000160ff,0xfffff448,0x2d40ffb4 + .long 0x2200e958,0x0240000f,0x227604c0,0x2d49ffb0 + .long 0x2001ec49,0x02410007,0x2a3614c0,0x02400007 + .long 0x263604c0,0x3d40ffba,0x302effa2,0x2200e958 + .long 0x0240000f,0x207604c0,0x2d48ffbc,0x2001ec49 + .long 0x02410007,0x283614c0,0x02400007,0x243604c0 + .long 0x3d40ffb8,0x082e0001,0xffa056c7,0x082e0005 + .long 0x000456c6,0x24482649,0x22072006,0x61ffffff + .long 0xf05c204a,0x4a8066ff,0x000001c8,0x22072006 + .long 0x204b61ff,0xfffff046,0x204b4a80,0x660a204a + .long 0x224b60ff,0xfffff020,0x2f002207,0x2006204a + .long 0x61ffffff,0xf03e201f,0x204b60ff,0x00000194 + .long 0x082e0001,0xffa06648,0x44eeffa8,0xb0426602 + .long 0xb24342ee,0xffa84a04,0x6610362e,0xffba3d81 + .long 0x34c2342e,0xffb83d80,0x24c2082e,0x00050004 + .long 0x56c22002,0x51c1206e,0xffbc61ff,0xffffeff4 + .long 0x200251c1,0x206effb0,0x61ffffff,0xefe64e75 + .long 0x44eeffa8,0xb0826602,0xb28342ee,0xffa84a04 + .long 0x6610362e,0xffba2d81,0x34c0342e,0xffb82d80 + .long 0x24c0082e,0x00050004,0x56c22002,0x50c1206e + .long 0xffbc61ff,0xffffefac,0x200250c1,0x206effb0 + .long 0x61ffffff,0xef9e4e75,0x202effb4,0x6000feae + .long 0x082e0001,0xffa06610,0x700261ff,0xfffff364 + .long 0x2d48ffb4,0x51c7600e,0x700461ff,0xfffff354 + .long 0x2d48ffb4,0x50c7302e,0xffa22200,0xec480240 + .long 0x00072436,0x04c00241,0x00072836,0x14c03d41 + .long 0xffb8082e,0x00050004,0x56c62448,0x22072006 + .long 0x61ffffff,0xef284a80,0x66000096,0x204a60ff + .long 0xffffeeee,0x082e0001,0xffa0662c,0x44eeffa8 + .long 0xb04442ee,0xffa84a01,0x6608362e,0xffb83d80 + .long 0x34c2206e,0xffb451c1,0x082e0005,0x000456c0 + .long 0x61ffffff,0xeefe4e75,0x44eeffa8,0xb08442ee + .long 0xffa84a01,0x6608362e,0xffb82d80,0x34c0206e + .long 0xffb450c1,0x082e0005,0x000456c0,0x61ffffff + .long 0xeed24e75,0x4e7b6000,0x4e7b6001,0x0c2e00fc + .long 0xffa167ff,0xffffff24,0x206effb4,0x082e0001 + .long 0xffa056c7,0x6000ff40,0x4e7b6000,0x4e7b6001 + .long 0x24482f00,0x61ffffff,0xf264201f,0x588f518f + .long 0x518e721a,0x41ef0008,0x43ef0000,0x22d851c9 + .long 0xfffc3d7c,0x4008000a,0x2d4a000c,0x2d400010 + .long 0x4cee3fff,0xffc04e5e,0x60ffffff,0xedf84280 + .long 0x43fb0170,0x000005ae,0xb3c86d0e,0x43fb0170 + .long 0x00000010,0xb1c96d02,0x4e7570ff,0x4e754a06 + .long 0x66047001,0x60027005,0x4a076700,0x01e42448 + .long 0x26492848,0x2a49568c,0x568d220a,0x40c7007c + .long 0x07004e7a,0x60004e7b,0x00004e7b,0x0001f58a + .long 0xf58cf58b,0xf58df46a,0xf46cf46b,0xf46d2441 + .long 0x56812841,0xf5caf5cc,0x247c8000,0x0000267c + .long 0xa0000000,0x287c0000,0x00002008,0x02000003 + .long 0x671c0c00,0x00026700,0x00966000,0x010251fc + .long 0x4e7ba008,0x0e911000,0x0e900000,0x6002600e + .long 0xb082661c,0xb2836618,0x0e915800,0x6002600e + .long 0x4e7bb008,0x0e904800,0x4e7bc008,0x6034600e + .long 0x4e7bb008,0x0e900800,0x4e7bc008,0x6012600e + .long 0x4e714e71,0x4e714e71,0x4e714e71,0x4e7160b0 + .long 0x4e7b6000,0x4e7b6001,0x46c751c4,0x60ffffff + .long 0xfd424e7b,0x60004e7b,0x600146c7,0x50c460ff + .long 0xfffffd30,0x51fc51fc,0x51fc51fc,0x51fc51fc + .long 0x4e7ba008,0x0e911000,0x0e900000,0x6002600e + .long 0xb082662c,0xb2836628,0x0e915800,0x6002600e + .long 0x48440e58,0x48004e7b,0xb0084844,0x6002600e + .long 0x0e504800,0x4e7bc008,0x6000ffa8,0x4e71600e + .long 0x48400e58,0x08004e7b,0xb0084840,0x6002600e + .long 0x0e500800,0x4e7bc008,0x6000ff76,0x4e71600e + .long 0x4e714e71,0x4e714e71,0x4e714e71,0x4e716090 + .long 0x4e7ba008,0x0e911000,0x0e900000,0x6002600e + .long 0xb082663c,0xb2836638,0x0e915800,0x6002600e + .long 0xe19c0e18,0x48004844,0x0e584800,0x6002600e + .long 0xe19c4e7b,0xb0080e10,0x48006004,0x4e71600e + .long 0x4e7bc008,0x6000ff2c,0x4e714e71,0x4e71600e + .long 0xe1980e18,0x08004840,0x0e580800,0x6002600e + .long 0xe1984e7b,0xb0080e10,0x08006004,0x4e71600e + .long 0x4e7bc008,0x6000feea,0x4e714e71,0x4e71600c + .long 0x4e714e71,0x4e714e71,0x4e714e71,0x6000ff72 + .long 0x24482649,0x28482a49,0x528c528d,0x220a40c7 + .long 0x007c0700,0x4e7a6000,0x4e7b0000,0x4e7b0001 + .long 0xf58af58c,0xf58bf58d,0xf46af46c,0xf46bf46d + .long 0x24415681,0x2841f5ca,0xf5cc247c,0x80000000 + .long 0x267ca000,0x0000287c,0x00000000,0x20080800 + .long 0x00006600,0x009a6016,0x51fc51fc,0x51fc51fc + .long 0x4e7ba008,0x0e511000,0x0e500000,0x6002600e + .long 0xb042661c,0xb2436618,0x0e515800,0x6002600e + .long 0x4e7bb008,0x0e504800,0x4e7bc008,0x6034600e + .long 0x4e7bb008,0x0e500800,0x4e7bc008,0x6012600e + .long 0x4e714e71,0x4e714e71,0x4e714e71,0x4e7160b0 + .long 0x4e7b6000,0x4e7b6001,0x46c751c4,0x60ffffff + .long 0xfb624e7b,0x60004e7b,0x600146c7,0x50c460ff + .long 0xfffffb50,0x51fc51fc,0x51fc51fc,0x51fc51fc + .long 0x4e7ba008,0x0e511000,0x0e500000,0x6002600e + .long 0xb042662c,0xb2436628,0x0e515800,0x6002600e + .long 0xe09c0e18,0x48004e7b,0xb008e19c,0x6002600e + .long 0x0e104800,0x4e7bc008,0x6000ffa8,0x4e71600e + .long 0xe0980e18,0x08004e7b,0xb008e198,0x6002600e + .long 0x0e100800,0x4e7bc008,0x6000ff76,0x4e71600e + .long 0x4e714e71,0x4e714e71,0x4e714e71,0x4e716090 + .long 0x4a066604,0x70016002,0x70054a07,0x660000c6 + .long 0x22482448,0x528a2602,0xe04a40c7,0x007c0700 + .long 0x4e7a6000,0x4e7b0000,0x4e7b0001,0xf589f58a + .long 0xf469f46a,0x227c8000,0x0000247c,0xa0000000 + .long 0x267c0000,0x00006016,0x51fc51fc,0x51fc51fc + .long 0x4e7b9008,0x0e500000,0xb0446624,0x6002600e + .long 0x0e182800,0x4e7ba008,0x0e103800,0x6002600e + .long 0x4e7bb008,0x604c4e71,0x4e714e71,0x4e71600e + .long 0xe0980e18,0x08004e7b,0xa008e198,0x6002600e + .long 0x0e100800,0x4e7bb008,0x60164e71,0x4e71600e + .long 0x4e714e71,0x4e714e71,0x4e714e71,0x4e7160a0 + .long 0x4e7b6000,0x4e7b6001,0x46c751c1,0x60ffffff + .long 0xfb164e7b,0x60004e7b,0x600146c7,0x50c160ff + .long 0xfffffb04,0x22482448,0x568a2208,0x08010000 + .long 0x660000c2,0x26024842,0x40c7007c,0x07004e7a + .long 0x60004e7b,0x00004e7b,0x0001f589,0xf58af469 + .long 0xf46a227c,0x80000000,0x247ca000,0x0000267c + .long 0x00000000,0x601851fc,0x51fc51fc,0x51fc51fc + .long 0x4e7b9008,0x0e900000,0xb0846624,0x6002600e + .long 0x0e582800,0x4e7ba008,0x0e503800,0x6002600e + .long 0x4e7bb008,0x604c4e71,0x4e714e71,0x4e71600e + .long 0x48400e58,0x08004840,0x4e7ba008,0x6002600e + .long 0x0e500800,0x4e7bb008,0x60164e71,0x4e71600e + .long 0x4e714e71,0x4e714e71,0x4e714e71,0x4e7160a0 + .long 0x4e7b6000,0x4e7b6001,0x46c751c1,0x60ffffff + .long 0xfa464e7b,0x60004e7b,0x600146c7,0x50c160ff + .long 0xfffffa34,0x2a02e08a,0x26024842,0x40c7007c + .long 0x07004e7a,0x60004e7b,0x00004e7b,0x0001f589 + .long 0xf58af469,0xf46a227c,0x80000000,0x247ca000 + .long 0x0000267c,0x00000000,0x601451fc,0x51fc51fc + .long 0x4e7b9008,0x0e900000,0xb0846624,0x6002600e + .long 0x0e182800,0x0e583800,0x4e7ba008,0x6002600e + .long 0x0e105800,0x4e7bb008,0x6000ff88,0x4e71600e + .long 0xe1980e18,0x08004840,0x0e580800,0x6002600e + .long 0xe1984e7b,0xa0080e10,0x08006004,0x4e71600e + .long 0x4e7bb008,0x6000ff4a,0x4e714e71,0x4e71600e + .long 0x4e714e71,0x4e714e71,0x4e714e71,0x4e716090 diff -u --recursive --new-file v1.3.93/linux/arch/m68k/ifpsp060/itest.sa linux/arch/m68k/ifpsp060/itest.sa --- v1.3.93/linux/arch/m68k/ifpsp060/itest.sa Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/ifpsp060/itest.sa Mon Jan 8 22:08:20 1996 @@ -0,0 +1,1281 @@ + dc.l $60ff0000,$005c5465,$7374696e,$67203638 + dc.l $30363020,$49535020,$73746172,$7465643a + dc.l $0a007061,$73736564,$0a002066,$61696c65 + dc.l $640a0000,$4a80660e,$487affe8,$61ff0000 + dc.l $4f9a588f,$4e752f01,$61ff0000,$4fa4588f + dc.l $487affd8,$61ff0000,$4f82588f,$4e754e56 + dc.l $ff6048e7,$3f3c487a,$ff9e61ff,$00004f6c + dc.l $588f42ae,$ff78487b,$01700000,$00ea61ff + dc.l $00004f58,$588f61ff,$000000f0,$61ffffff + dc.l $ffa642ae,$ff78487b,$01700000,$0af661ff + dc.l $00004f38,$588f61ff,$00000af8,$61ffffff + dc.l $ff8642ae,$ff78487b,$01700000,$179c61ff + dc.l $00004f18,$588f61ff,$0000179c,$61ffffff + dc.l $ff6642ae,$ff78487b,$01700000,$038661ff + dc.l $00004ef8,$588f61ff,$00000380,$61ffffff + dc.l $ff4642ae,$ff78487b,$01700000,$202c61ff + dc.l $00004ed8,$588f2d7c,$00000002,$ff7461ff + dc.l $0000202c,$61ffffff,$ff1e42ae,$ff78487b + dc.l $01700000,$0d7c61ff,$00004eb0,$588f61ff + dc.l $00000d74,$61ffffff,$fefe42ae,$ff78487b + dc.l $01700000,$0f8e61ff,$00004e90,$588f61ff + dc.l $00000f88,$61ffffff,$fede4cdf,$3cfc4e5e + dc.l $4e750936,$342d6269,$74206d75,$6c746970 + dc.l $6c792e2e,$2e0051fc,$52aeff78,$4cfb3fff + dc.l $01700000,$4e184281,$243c9999,$9999263c + dc.l $88888888,$3d7c0004,$ff7c44fc,$000048ee + dc.l $7fffff80,$4c013402,$42eeff7e,$48ee7fff + dc.l $ffc042ae,$ff8842ae,$ff8c61ff,$00004da6 + dc.l $4a0066ff,$00004dcc,$52aeff78,$4cfb3fff + dc.l $01700000,$4dc8223c,$77777777,$243c9999 + dc.l $99997600,$3d7c0004,$ff7c44fc,$000048ee + dc.l $7fffff80,$4c013402,$42eeff7e,$48ee7fff + dc.l $ffc042ae,$ff8842ae,$ff8c61ff,$00004d56 + dc.l $4a0066ff,$00004d7c,$52aeff78,$4cfb3fff + dc.l $01700000,$4d787210,$243c6666,$66663d7c + dc.l $0000ff7c,$44fc0000,$48ee7fff,$ff804c01 + dc.l $240242ee,$ff7e48ee,$7fffffc0,$2d7c0000 + dc.l $0006ff88,$61ff0000,$4d0c4a00,$66ff0000 + dc.l $4d3252ae,$ff784cfb,$3fff0170,$00004d2e + dc.l $223c5555,$55557400,$76033d7c,$0000ff7c + dc.l $44fc0000,$48ee7fff,$ff804c01,$340242ee + dc.l $ff7e48ee,$7fffffc0,$2d7c0000,$0000ff88 + dc.l $2d7cffff,$ffffff8c,$61ff0000,$4cb84a00 + dc.l $66ff0000,$4cde52ae,$ff784cfb,$3fff0170 + dc.l $00004cda,$223c4000,$00007400,$76043d7c + dc.l $0000ff7c,$44fc0000,$48ee7fff,$ff804c01 + dc.l $340242ee,$ff7e48ee,$7fffffc0,$2d7c0000 + dc.l $0001ff88,$2d7c0000,$0000ff8c,$61ff0000 + dc.l $4c644a00,$66ff0000,$4c8a52ae,$ff784cfb + dc.l $3fff0170,$00004c86,$72ff7400,$76ff3d7c + dc.l $0008ff7c,$44fc0000,$48ee7fff,$ff804c01 + dc.l $340242ee,$ff7e48ee,$7fffffc0,$2d7cffff + dc.l $fffeff88,$2d7c0000,$0001ff8c,$61ff0000 + dc.l $4c144a00,$66ff0000,$4c3a52ae,$ff784cfb + dc.l $3fff0170,$00004c36,$223c8000,$00007400 + dc.l $76ff3d7c,$0000ff7c,$44fc0000,$48ee7fff + dc.l $ff804c01,$3c0242ee,$ff7e48ee,$7fffffc0 + dc.l $2d7c0000,$0000ff88,$2d7c8000,$0000ff8c + dc.l $61ff0000,$4bc04a00,$66ff0000,$4be652ae + dc.l $ff784cfb,$3fff0170,$00004be2,$223c8000 + dc.l $00007400,$76013d7c,$0008ff7c,$44fc0000 + dc.l $48ee7fff,$ff804c01,$3c0242ee,$ff7e48ee + dc.l $7fffffc0,$2d7cffff,$ffffff88,$2d7c8000 + dc.l $0000ff8c,$61ff0000,$4b6c4a00,$66ff0000 + dc.l $4b9252ae,$ff784cfb,$3fff0170,$00004b8e + dc.l $72017400,$263c8000,$00003d7c,$0008ff7c + dc.l $44fc0000,$48ee7fff,$ff804c01,$3c0242ee + dc.l $ff7e48ee,$7fffffc0,$2d7cffff,$ffffff88 + dc.l $2d7c8000,$0000ff8c,$61ff0000,$4b184a00 + dc.l $66ff0000,$4b3e222e,$ff784280,$4e75096d + dc.l $6f766570,$2e2e2e00,$52aeff78,$4cfb3fff + dc.l $01700000,$4b2841ee,$ff60303c,$aaaa4228 + dc.l $00004228,$00023d7c,$001fff7c,$44fc001f + dc.l $48ee7fff,$ff800188,$000042ee,$ff7e48ee + dc.l $7fffffc0,$12280002,$e1491228,$0000b041 + dc.l $66ff0000,$4ade61ff,$00004aaa,$4a0066ff + dc.l $00004ad0,$52aeff78,$4cfb3fff,$01700000 + dc.l $4acc41ee,$ff64303c,$aaaa42a8,$fffc4290 + dc.l $42a80004,$3d7c001f,$ff7c44fc,$001f48ee + dc.l $7fffff80,$01880000,$42eeff7e,$48ee7fff + dc.l $ffc04aa8,$fffc66ff,$00004a88,$4aa80004 + dc.l $66ff0000,$4a7e0c90,$aa00aa00,$66ff0000 + dc.l $4a7261ff,$00004a3e,$4a0066ff,$00004a64 + dc.l $52aeff78,$4cfb3fff,$01700000,$4a6041ee + dc.l $ff60303c,$aaaa4228,$00004228,$00023d7c + dc.l $0000ff7c,$44fc0000,$48ee7fff,$ff800188 + dc.l $000042ee,$ff7e48ee,$7fffffc0,$12280002 + dc.l $e1491228,$0000b041,$66ff0000,$4a1661ff + dc.l $000049e2,$4a0066ff,$00004a08,$52aeff78 + dc.l $4cfb3fff,$01700000,$4a0441ee,$ff60117c + dc.l $00aa0000,$117c00aa,$00023d7c,$001fff7c + dc.l $44fc001f,$48ee7fff,$ff800108,$000042ee + dc.l $ff7e48ee,$7fffffc0,$3d7caaaa,$ff82323c + dc.l $aaaab041,$66ff0000,$49ba61ff,$00004986 + dc.l $4a0066ff,$000049ac,$52aeff78,$4cfb3fff + dc.l $01700000,$49a841ee,$ff60203c,$aaaaaaaa + dc.l $42280000,$42280002,$42280004,$42280006 + dc.l $3d7c001f,$ff7c44fc,$001f48ee,$7fffff80 + dc.l $01c80000,$42eeff7e,$48ee7fff,$ffc01228 + dc.l $0006e189,$12280004,$e1891228,$0002e189 + dc.l $12280000,$b08166ff,$00004948,$61ff0000 + dc.l $49144a00,$66ff0000,$493a52ae,$ff784cfb + dc.l $3fff0170,$00004936,$41eeff64,$203caaaa + dc.l $aaaa42a8,$fffc4290,$42a80004,$42a80008 + dc.l $3d7c001f,$ff7c44fc,$001f48ee,$7fffff80 + dc.l $01c80000,$42eeff7e,$48ee7fff,$ffc04aa8 + dc.l $fffc66ff,$000048ec,$4aa80008,$66ff0000 + dc.l $48e20c90,$aa00aa00,$66ff0000,$48d60ca8 + dc.l $aa00aa00,$000466ff,$000048c8,$61ff0000 + dc.l $48944a00,$66ff0000,$48ba52ae,$ff784cfb + dc.l $3fff0170,$000048b6,$41eeff60,$117c00aa + dc.l $0000117c,$00aa0002,$117c00aa,$0004117c + dc.l $00aa0006,$3d7c001f,$ff7c44fc,$001f48ee + dc.l $7fffff80,$01480000,$42eeff7e,$48ee7fff + dc.l $ffc02d7c,$aaaaaaaa,$ff80223c,$aaaaaaaa + dc.l $b08166ff,$0000485c,$61ff0000,$48284a00 + dc.l $66ff0000,$484e52ae,$ff784cfb,$3fff0170 + dc.l $0000484a,$41eeff60,$3e3caaaa,$42280000 + dc.l $42280002,$3d7c001f,$ff7c44fc,$001f48ee + dc.l $7fffff80,$0f880000,$42eeff7e,$48ee7fff + dc.l $ffc01228,$0002e149,$12280000,$be4166ff + dc.l $00004800,$61ff0000,$47cc4a00,$66ff0000 + dc.l $47f252ae,$ff784cfb,$3fff0170,$000047ee + dc.l $41eeff60,$117c00aa,$0000117c,$00aa0002 + dc.l $3d7c001f,$ff7c44fc,$001f48ee,$7fffff80 + dc.l $0f080000,$42eeff7e,$48ee7fff,$ffc03d7c + dc.l $aaaaff9e,$323caaaa,$be4166ff,$000047a4 + dc.l $61ff0000,$47704a00,$66ff0000,$479652ae + dc.l $ff784cfb,$3fff0170,$00004792,$41eeff60 + dc.l $303caaaa,$42280000,$42280002,$3d7c001f + dc.l $ff7c44fc,$001f48ee,$7fffff80,$01880000 + dc.l $42eeff7e,$48ee7fff,$ffc01228,$0002e149 + dc.l $12280000,$b04166ff,$00004748,$61ff0000 + dc.l $47144a00,$66ff0000,$473a52ae,$ff784cfb + dc.l $3fff0170,$00004736,$41eeff60,$303caaaa + dc.l $42280008,$4228000a,$3d7c001f,$ff7c44fc + dc.l $001f48ee,$7fffff80,$01880008,$42eeff7e + dc.l $48ee7fff,$ffc01228,$000ae149,$12280008 + dc.l $b04166ff,$000046ec,$61ff0000,$46b84a00 + dc.l $66ff0000,$46de52ae,$ff784cfb,$3fff0170 + dc.l $000046da,$41eeff60,$117c00aa,$0008117c + dc.l $00aa000a,$3d7c001f,$ff7c44fc,$001f48ee + dc.l $7fffff80,$01080008,$42eeff7e,$48ee7fff + dc.l $ffc03d7c,$aaaaff82,$323caaaa,$b04166ff + dc.l $00004690,$61ff0000,$465c4a00,$66ff0000 + dc.l $468252ae,$ff784cfb,$3fff0170,$0000467e + dc.l $41eeff60,$203caaaa,$aaaa4228,$00084228 + dc.l $000a4228,$000c4228,$000e3d7c,$001fff7c + dc.l $44fc001f,$48ee7fff,$ff8001c8,$000842ee + dc.l $ff7e48ee,$7fffffc0,$1228000e,$e1891228 + dc.l $000ce189,$1228000a,$e1891228,$0008b081 + dc.l $66ff0000,$461e61ff,$000045ea,$4a0066ff + dc.l $00004610,$52aeff78,$4cfb3fff,$01700000 + dc.l $460c41ee,$ff60117c,$00aa0008,$117c00aa + dc.l $000a117c,$00aa000c,$117c00aa,$000e3d7c + dc.l $001fff7c,$44fc001f,$48ee7fff,$ff800148 + dc.l $000842ee,$ff7e48ee,$7fffffc0,$2d7caaaa + dc.l $aaaaff80,$223caaaa,$aaaab081,$66ff0000 + dc.l $45b261ff,$0000457e,$4a0066ff,$000045a4 + dc.l $52aeff78,$4cfb3fff,$01700000,$45a041ee + dc.l $ff68303c,$aaaa4228,$fff84228,$fffa3d7c + dc.l $001fff7c,$44fc001f,$48ee7fff,$ff800188 + dc.l $fff842ee,$ff7e48ee,$7fffffc0,$1228fffa + dc.l $e1491228,$fff8b041,$66ff0000,$455661ff + dc.l $00004522,$4a0066ff,$00004548,$52aeff78 + dc.l $4cfb3fff,$01700000,$454441ee,$ff68117c + dc.l $00aafff8,$117c00aa,$fffa3d7c,$001fff7c + dc.l $44fc001f,$48ee7fff,$ff800108,$fff842ee + dc.l $ff7e48ee,$7fffffc0,$3d7caaaa,$ff82323c + dc.l $aaaab041,$66ff0000,$44fa61ff,$000044c6 + dc.l $4a0066ff,$000044ec,$52aeff78,$4cfb3fff + dc.l $01700000,$44e841ee,$ff68203c,$aaaaaaaa + dc.l $4228fff8,$4228fffa,$4228fffc,$42280000 + dc.l $3d7c001f,$ff7c44fc,$001f48ee,$7fffff80 + dc.l $01c8fff8,$42eeff7e,$48ee7fff,$ffc01228 + dc.l $fffee189,$1228fffc,$e1891228,$fffae189 + dc.l $1228fff8,$b08166ff,$00004488,$61ff0000 + dc.l $44544a00,$66ff0000,$447a52ae,$ff784cfb + dc.l $3fff0170,$00004476,$41eeff68,$117c00aa + dc.l $fff8117c,$00aafffa,$117c00aa,$fffc117c + dc.l $00aa0000,$3d7c001f,$ff7c44fc,$001f48ee + dc.l $7fffff80,$0148fff8,$42eeff7e,$48ee7fff + dc.l $ffc02d7c,$aaaaaaaa,$ff80223c,$aaaaaaaa + dc.l $b08166ff,$0000441c,$61ff0000,$43e84a00 + dc.l $66ff0000,$440e222e,$ff784280,$4e750936 + dc.l $342d6269,$74206469,$76696465,$2e2e2e00 + dc.l $52aeff78,$52aeff78,$4cfb3fff,$01700000 + dc.l $43ec7201,$74007600,$3d7c0014,$ff7c44fc + dc.l $001f48ee,$7fffff80,$4c413402,$42eeff7e + dc.l $48ee7fff,$ffc061ff,$0000438a,$4a0066ff + dc.l $000043b0,$52aeff78,$4cfb3fff,$01700000 + dc.l $43ac223c,$44444444,$7400263c,$55555555 + dc.l $3d7c0010,$ff7c44fc,$001f48ee,$7fffff80 + dc.l $4c413402,$42eeff7e,$48ee7fff,$ffc02d7c + dc.l $11111111,$ff882d7c,$00000001,$ff8c61ff + dc.l $00004332,$4a0066ff,$00004358,$52aeff78 + dc.l $4cfb3fff,$01700000,$4354223c,$55555555 + dc.l $7400263c,$44444444,$3d7c0014,$ff7c44fc + dc.l $001f48ee,$7fffff80,$4c413402,$42eeff7e + dc.l $48ee7fff,$ffc02d7c,$44444444,$ff882d7c + dc.l $00000000,$ff8c61ff,$000042da,$4a0066ff + dc.l $00004300,$52aeff78,$4cfb3fff,$01700000 + dc.l $42fc223c,$11111111,$243c4444,$4444263c + dc.l $44444444,$3d7c001e,$ff7c44fc,$001d48ee + dc.l $7fffff80,$4c413402,$42eeff7e,$48ee7fff + dc.l $ffc061ff,$0000428e,$4a0066ff,$000042b4 + dc.l $52aeff78,$4cfb3fff,$01700000,$42b072fe + dc.l $74017602,$3d7c001e,$ff7c44fc,$001d48ee + dc.l $7fffff80,$4c413c02,$42eeff7e,$48ee7fff + dc.l $ffc061ff,$0000424e,$4a0066ff,$00004274 + dc.l $52aeff78,$4cfb3fff,$01700000,$427072fe + dc.l $74017600,$3d7c0018,$ff7c44fc,$001d48ee + dc.l $7fffff80,$4c413c02,$42eeff7e,$48ee7fff + dc.l $ffc02d7c,$00000000,$ff882d7c,$80000000 + dc.l $ff8c61ff,$000041fe,$4a0066ff,$00004224 + dc.l $52aeff78,$4cfb3fff,$01700000,$42207202 + dc.l $74017600,$3d7c001e,$ff7c44fc,$001d48ee + dc.l $7fffff80,$4c413c02,$42eeff7e,$48ee7fff + dc.l $ffc061ff,$000041be,$4a0066ff,$000041e4 + dc.l $52aeff78,$4cfb3fff,$01700000,$41e072ff + dc.l $74fe76ff,$3d7c0008,$ff7c44fc,$000048ee + dc.l $7fffff80,$4c413402,$42eeff7e,$48ee7fff + dc.l $ffc061ff,$0000417e,$4a0066ff,$000041a4 + dc.l $52aeff78,$4cfb3fff,$01700000,$41a072ff + dc.l $74fe76ff,$3d7c0008,$ff7c44fc,$000048ee + dc.l $7fffff80,$4c7c2402,$ffffffff,$42eeff7e + dc.l $48ee7fff,$ffc02d7c,$ffffffff,$ff8861ff + dc.l $00004132,$4a0066ff,$00004158,$52aeff78 + dc.l $4cfb3fff,$01700000,$4154223c,$0000ffff + dc.l $7401263c,$55555555,$3d7c0000,$ff7c44fc + dc.l $000048ee,$7fffff80,$4c413402,$42eeff7e + dc.l $48ee7fff,$ffc02d7c,$0000aaab,$ff882d7c + dc.l $00015556,$ff8c61ff,$000040da,$4a0066ff + dc.l $00004100,$222eff78,$42804e75,$09636173 + dc.l $2e2e2e00,$52aeff78,$4cfb3fff,$01700000 + dc.l $40ec41ee,$ff6130bc,$aaaa323c,$aaaa343c + dc.l $bbbb3d7c,$0014ff7c,$44fc0010,$48ee7fff + dc.l $ff800cd0,$008142ee,$ff7e3610,$3d7cbbbb + dc.l $ff8e48ee,$7fffffc0,$61ff0000,$40784a00 + dc.l $66ff0000,$409e52ae,$ff784cfb,$3fff0170 + dc.l $0000409a,$41eeff61,$30bceeee,$323caaaa + dc.l $343cbbbb,$3d7c0000,$ff7c44fc,$000048ee + dc.l $7fffff80,$0cd00081,$42eeff7e,$36103d7c + dc.l $eeeeff86,$3d7ceeee,$ff8e48ee,$7fffffc0 + dc.l $61ff0000,$40204a00,$66ff0000,$404652ae + dc.l $ff784cfb,$3fff0170,$00004042,$41eeff62 + dc.l $20bcaaaa,$aaaa223c,$aaaaaaaa,$243cbbbb + dc.l $bbbb3d7c,$0004ff7c,$44fc0000,$48ee7fff + dc.l $ff800ed0,$008142ee,$ff7e2610,$2d7cbbbb + dc.l $bbbbff8c,$48ee7fff,$ffc061ff,$00003fc6 + dc.l $4a0066ff,$00003fec,$52aeff78,$4cfb3fff + dc.l $01700000,$3fe841ee,$ff6220bc,$eeeeeeee + dc.l $223caaaa,$aaaa243c,$bbbbbbbb,$3d7c0000 + dc.l $ff7c44fc,$000048ee,$7fffff80,$0ed00081 + dc.l $42eeff7e,$26102d7c,$eeeeeeee,$ff842d7c + dc.l $eeeeeeee,$ff8c48ee,$7fffffc0,$61ff0000 + dc.l $3f644a00,$66ff0000,$3f8a52ae,$ff784cfb + dc.l $3fff0170,$00003f86,$41eeff61,$20bcaaaa + dc.l $aaaa223c,$aaaaaaaa,$243cbbbb,$bbbb3d7c + dc.l $0004ff7c,$44fc0000,$48ee7fff,$ff800ed0 + dc.l $008142ee,$ff7e2610,$2d7cbbbb,$bbbbff8c + dc.l $48ee7fff,$ffc061ff,$00003f0a,$4a0066ff + dc.l $00003f30,$52aeff78,$4cfb3fff,$01700000 + dc.l $3f2c41ee,$ff6120bc,$7fffffff,$223c8000 + dc.l $0000243c,$bbbbbbbb,$3d7c001b,$ff7c44fc + dc.l $001048ee,$7fffff80,$0ed00081,$42eeff7e + dc.l $26102d7c,$7fffffff,$ff842d7c,$7fffffff + dc.l $ff8c48ee,$7fffffc0,$61ff0000,$3ea84a00 + dc.l $66ff0000,$3ece222e,$ff784280,$4e750963 + dc.l $6173322e,$2e2e0000,$52aeff78,$4cfb3fff + dc.l $01700000,$3eb841ee,$ff6043ee,$ff6420bc + dc.l $aaaaaaaa,$22bcbbbb,$bbbb223c,$aaaaaaaa + dc.l $243cbbbb,$bbbb263c,$cccccccc,$283cdddd + dc.l $dddd3d7c,$0014ff7c,$44fc0010,$48ee7fff + dc.l $ff800efc,$80c19102,$42eeff7e,$2a102c11 + dc.l $2d7ccccc,$ccccff94,$2d7cdddd,$ddddff98 + dc.l $48ee7fff,$ffc061ff,$00003e1a,$4a0066ff + dc.l $00003e40,$52aeff78,$4cfb3fff,$01700000 + dc.l $3e3c41ee,$ff6143ee,$ff6520bc,$aaaaaaaa + dc.l $22bcbbbb,$bbbb223c,$aaaaaaaa,$243cbbbb + dc.l $bbbb263c,$cccccccc,$283cdddd,$dddd3d7c + dc.l $0014ff7c,$44fc0010,$48ee7fff,$ff800efc + dc.l $80c19102,$42eeff7e,$2a102c11,$2d7ccccc + dc.l $ccccff94,$2d7cdddd,$ddddff98,$48ee7fff + dc.l $ffc061ff,$00003d9e,$4a0066ff,$00003dc4 + dc.l $52aeff78,$4cfb3fff,$01700000,$3dc041ee + dc.l $ff6243ee,$ff6620bc,$aaaaaaaa,$22bcbbbb + dc.l $bbbb223c,$aaaaaaaa,$243cbbbb,$bbbb263c + dc.l $cccccccc,$283cdddd,$dddd3d7c,$0014ff7c + dc.l $44fc0010,$48ee7fff,$ff800efc,$80c19102 + dc.l $42eeff7e,$2a102c11,$2d7ccccc,$ccccff94 + dc.l $2d7cdddd,$ddddff98,$48ee7fff,$ffc061ff + dc.l $00003d22,$4a0066ff,$00003d48,$52aeff78 + dc.l $4cfb3fff,$01700000,$3d4441ee,$ff6043ee + dc.l $ff6420bc,$eeeeeeee,$22bcbbbb,$bbbb223c + dc.l $aaaaaaaa,$243cbbbb,$bbbb263c,$cccccccc + dc.l $283cdddd,$dddd3d7c,$0000ff7c,$44fc0000 + dc.l $48ee7fff,$ff800efc,$80c19102,$42eeff7e + dc.l $2a102c11,$2d7ceeee,$eeeeff84,$2d7cbbbb + dc.l $bbbbff88,$2d7ceeee,$eeeeff94,$2d7cbbbb + dc.l $bbbbff98,$48ee7fff,$ffc061ff,$00003c96 + dc.l $4a0066ff,$00003cbc,$52aeff78,$4cfb3fff + dc.l $01700000,$3cb841ee,$ff6143ee,$ff6520bc + dc.l $eeeeeeee,$22bcbbbb,$bbbb223c,$aaaaaaaa + dc.l $243cbbbb,$bbbb263c,$cccccccc,$283cdddd + dc.l $dddd3d7c,$0000ff7c,$44fc0000,$48ee7fff + dc.l $ff800efc,$80c19102,$42eeff7e,$2a102c11 + dc.l $2d7ceeee,$eeeeff84,$2d7cbbbb,$bbbbff88 + dc.l $2d7ceeee,$eeeeff94,$2d7cbbbb,$bbbbff98 + dc.l $48ee7fff,$ffc061ff,$00003c0a,$4a0066ff + dc.l $00003c30,$52aeff78,$4cfb3fff,$01700000 + dc.l $3c2c41ee,$ff6243ee,$ff6620bc,$eeeeeeee + dc.l $22bcbbbb,$bbbb223c,$aaaaaaaa,$243cbbbb + dc.l $bbbb263c,$cccccccc,$283cdddd,$dddd3d7c + dc.l $0000ff7c,$44fc0000,$48ee7fff,$ff800efc + dc.l $80c19102,$42eeff7e,$2a102c11,$2d7ceeee + dc.l $eeeeff84,$2d7cbbbb,$bbbbff88,$2d7ceeee + dc.l $eeeeff94,$2d7cbbbb,$bbbbff98,$48ee7fff + dc.l $ffc061ff,$00003b7e,$4a0066ff,$00003ba4 + dc.l $52aeff78,$4cfb3fff,$01700000,$3ba041ee + dc.l $ff6043ee,$ff6420bc,$aaaaaaaa,$22bceeee + dc.l $eeee223c,$aaaaaaaa,$243cbbbb,$bbbb263c + dc.l $cccccccc,$283cdddd,$dddd3d7c,$0000ff7c + dc.l $44fc0000,$48ee7fff,$ff800efc,$80c19102 + dc.l $42eeff7e,$2a102c11,$2d7caaaa,$aaaaff84 + dc.l $2d7ceeee,$eeeeff88,$2d7caaaa,$aaaaff94 + dc.l $2d7ceeee,$eeeeff98,$48ee7fff,$ffc061ff + dc.l $00003af2,$4a0066ff,$00003b18,$52aeff78 + dc.l $4cfb3fff,$01700000,$3b1441ee,$ff6143ee + dc.l $ff6520bc,$aaaaaaaa,$22bceeee,$eeee223c + dc.l $aaaaaaaa,$243cbbbb,$bbbb263c,$cccccccc + dc.l $283cdddd,$dddd3d7c,$0000ff7c,$44fc0000 + dc.l $48ee7fff,$ff800efc,$80c19102,$42eeff7e + dc.l $2a102c11,$2d7caaaa,$aaaaff84,$2d7ceeee + dc.l $eeeeff88,$2d7caaaa,$aaaaff94,$2d7ceeee + dc.l $eeeeff98,$48ee7fff,$ffc061ff,$00003a66 + dc.l $4a0066ff,$00003a8c,$52aeff78,$4cfb3fff + dc.l $01700000,$3a8841ee,$ff6243ee,$ff6620bc + dc.l $aaaaaaaa,$22bc7fff,$ffff223c,$aaaaaaaa + dc.l $243c8000,$0000263c,$cccccccc,$283cdddd + dc.l $dddd3d7c,$000bff7c,$44fc0000,$48ee7fff + dc.l $ff800efc,$80c19102,$42eeff7e,$2a102c11 + dc.l $2d7caaaa,$aaaaff84,$2d7c7fff,$ffffff88 + dc.l $2d7caaaa,$aaaaff94,$2d7c7fff,$ffffff98 + dc.l $48ee7fff,$ffc061ff,$000039da,$4a0066ff + dc.l $00003a00,$52aeff78,$4cfb3fff,$01700000 + dc.l $39fc41ee,$ff6043ee,$ff6430bc,$aaaa32bc + dc.l $bbbb323c,$aaaa343c,$bbbb363c,$cccc383c + dc.l $dddd3d7c,$0014ff7c,$44fc0010,$48ee7fff + dc.l $ff800cfc,$80c19102,$42eeff7e,$3a103c11 + dc.l $3d7ccccc,$ff963d7c,$ddddff9a,$48ee7fff + dc.l $ffc061ff,$0000396e,$4a0066ff,$00003994 + dc.l $52aeff78,$4cfb3fff,$01700000,$399041ee + dc.l $ff6143ee,$ff6530bc,$aaaa32bc,$bbbb323c + dc.l $aaaa343c,$bbbb363c,$cccc383c,$dddd3d7c + dc.l $0004ff7c,$44fc0000,$48ee7fff,$ff800cfc + dc.l $80c19102,$42eeff7e,$3a103c11,$3d7ccccc + dc.l $ff963d7c,$ddddff9a,$48ee7fff,$ffc061ff + dc.l $00003902,$4a0066ff,$00003928,$52aeff78 + dc.l $4cfb3fff,$01700000,$392441ee,$ff6043ee + dc.l $ff6430bc,$eeee32bc,$bbbb323c,$aaaa343c + dc.l $bbbb363c,$cccc383c,$dddd3d7c,$0000ff7c + dc.l $44fc0000,$48ee7fff,$ff800cfc,$80c19102 + dc.l $42eeff7e,$3a103c11,$3d7ceeee,$ff863d7c + dc.l $bbbbff8a,$3d7ceeee,$ff963d7c,$bbbbff9a + dc.l $48ee7fff,$ffc061ff,$0000388a,$4a0066ff + dc.l $000038b0,$52aeff78,$4cfb3fff,$01700000 + dc.l $38ac41ee,$ff6143ee,$ff6530bc,$eeee32bc + dc.l $bbbb323c,$aaaa343c,$bbbb363c,$cccc383c + dc.l $dddd3d7c,$0000ff7c,$44fc0000,$48ee7fff + dc.l $ff800cfc,$80c19102,$42eeff7e,$3a103c11 + dc.l $3d7ceeee,$ff863d7c,$bbbbff8a,$3d7ceeee + dc.l $ff963d7c,$bbbbff9a,$48ee7fff,$ffc061ff + dc.l $00003812,$4a0066ff,$00003838,$52aeff78 + dc.l $4cfb3fff,$01700000,$383441ee,$ff6043ee + dc.l $ff6430bc,$aaaa32bc,$eeee323c,$aaaa343c + dc.l $bbbb363c,$cccc383c,$dddd3d7c,$0000ff7c + dc.l $44fc0000,$48ee7fff,$ff800cfc,$80c19102 + dc.l $42eeff7e,$3a103c11,$3d7caaaa,$ff863d7c + dc.l $eeeeff8a,$3d7caaaa,$ff963d7c,$eeeeff9a + dc.l $48ee7fff,$ffc061ff,$0000379a,$4a0066ff + dc.l $000037c0,$52aeff78,$4cfb3fff,$01700000 + dc.l $37bc41ee,$ff6143ee,$ff6530bc,$aaaa32bc + dc.l $7fff323c,$aaaa343c,$8000363c,$cccc383c + dc.l $dddd3d7c,$001bff7c,$44fc0010,$48ee7fff + dc.l $ff800cfc,$80c19102,$42eeff7e,$3a103c11 + dc.l $3d7caaaa,$ff863d7c,$7fffff8a,$3d7caaaa + dc.l $ff963d7c,$7fffff9a,$48ee7fff,$ffc061ff + dc.l $00003722,$4a0066ff,$00003748,$222eff78 + dc.l $42804e75,$09636d70,$322c6368,$6b322e2e + dc.l $2e0051fc,$52aeff78,$4cfb3fff,$01700000 + dc.l $372c3d7c,$2040ff60,$223c1111,$11203d7c + dc.l $0004ff7c,$44fc0000,$48ee7fff,$ff8000ee + dc.l $1000ff60,$42eeff7e,$48ee7fff,$ffc061ff + dc.l $000036c2,$4a0066ff,$000036e8,$52aeff78 + dc.l $4cfb3fff,$01700000,$36e43d7c,$2040ff60 + dc.l $227c0000,$00403d7c,$0004ff7c,$44fc0000 + dc.l $48ee7fff,$ff8000ee,$9000ff60,$42eeff7e + dc.l $48ee7fff,$ffc061ff,$0000367a,$4a0066ff + dc.l $000036a0,$52aeff78,$4cfb3fff,$01700000 + dc.l $369c3d7c,$2040ff60,$223c1111,$11303d7c + dc.l $0000ff7c,$44fc0000,$48ee7fff,$ff8000ee + dc.l $1800ff60,$42eeff7e,$48ee7fff,$ffc061ff + dc.l $00003632,$4a0066ff,$00003658,$52aeff78 + dc.l $4cfb3fff,$01700000,$36543d7c,$2040ff60 + dc.l $227c0000,$00103d7c,$0001ff7c,$44fc0000 + dc.l $48ee7fff,$ff8000ee,$9000ff60,$42eeff7e + dc.l $48ee7fff,$ffc061ff,$000035ea,$4a0066ff + dc.l $00003610,$52aeff78,$4cfb3fff,$01700000 + dc.l $360c3d7c,$2040ff60,$223c1111,$11503d7c + dc.l $0001ff7c,$44fc0000,$48ee7fff,$ff8000ee + dc.l $1000ff60,$42eeff7e,$48ee7fff,$ffc061ff + dc.l $000035a2,$4a0066ff,$000035c8,$52aeff78 + dc.l $4cfb3fff,$01700000,$35c43d7c,$2040ff60 + dc.l $227c0000,$00903d7c,$0001ff7c,$44fc0000 + dc.l $48ee7fff,$ff8000ee,$9000ff60,$42eeff7e + dc.l $48ee7fff,$ffc061ff,$0000355a,$4a0066ff + dc.l $00003580,$52aeff78,$4cfb3fff,$01700000 + dc.l $357c2d7c,$2000a000,$ff60223c,$11112000 + dc.l $3d7c0004,$ff7c44fc,$000048ee,$7fffff80 + dc.l $02ee1000,$ff6042ee,$ff7e48ee,$7fffffc0 + dc.l $61ff0000,$35104a00,$66ff0000,$353652ae + dc.l $ff784cfb,$3fff0170,$00003532,$2d7c2000 + dc.l $a000ff60,$227cffff,$a0003d7c,$0004ff7c + dc.l $44fc0000,$48ee7fff,$ff8002ee,$9000ff60 + dc.l $42eeff7e,$48ee7fff,$ffc061ff,$000034c6 + dc.l $4a0066ff,$000034ec,$52aeff78,$4cfb3fff + dc.l $01700000,$34e82d7c,$2000a000,$ff60223c + dc.l $11113000,$3d7c0000,$ff7c44fc,$000048ee + dc.l $7fffff80,$02ee1800,$ff6042ee,$ff7e48ee + dc.l $7fffffc0,$61ff0000,$347c4a00,$66ff0000 + dc.l $34a252ae,$ff784cfb,$3fff0170,$0000349e + dc.l $2d7c2000,$a000ff60,$227cffff,$90003d7c + dc.l $0000ff7c,$44fc0000,$48ee7fff,$ff8002ee + dc.l $9000ff60,$42eeff7e,$48ee7fff,$ffc061ff + dc.l $00003432,$4a0066ff,$00003458,$52aeff78 + dc.l $4cfb3fff,$01700000,$34542d7c,$2000a000 + dc.l $ff60223c,$11111000,$3d7c0001,$ff7c44fc + dc.l $000048ee,$7fffff80,$02ee1000,$ff6042ee + dc.l $ff7e48ee,$7fffffc0,$61ff0000,$33e84a00 + dc.l $66ff0000,$340e52ae,$ff784cfb,$3fff0170 + dc.l $0000340a,$2d7c2000,$a000ff60,$227cffff + dc.l $b0003d7c,$0001ff7c,$44fc0000,$48ee7fff + dc.l $ff8002ee,$9000ff60,$42eeff7e,$48ee7fff + dc.l $ffc061ff,$0000339e,$4a0066ff,$000033c4 + dc.l $52aeff78,$4cfb3fff,$01700000,$33c02d7c + dc.l $a0000000,$ff602d7c,$c0000000,$ff64223c + dc.l $a0000000,$3d7c000c,$ff7c44fc,$000848ee + dc.l $7fffff80,$04ee1000,$ff6042ee,$ff7e48ee + dc.l $7fffffc0,$61ff0000,$334c4a00,$66ff0000 + dc.l $337252ae,$ff784cfb,$3fff0170,$0000336e + dc.l $2d7ca000,$0000ff60,$2d7cc000,$0000ff64 + dc.l $227cc000,$00003d7c,$000cff7c,$44fc0008 + dc.l $48ee7fff,$ff8004ee,$9000ff60,$42eeff7e + dc.l $48ee7fff,$ffc061ff,$000032fa,$4a0066ff + dc.l $00003320,$52aeff78,$4cfb3fff,$01700000 + dc.l $331c2d7c,$a0000000,$ff602d7c,$c0000000 + dc.l $ff64223c,$b0000000,$3d7c0008,$ff7c44fc + dc.l $000848ee,$7fffff80,$04ee1800,$ff6042ee + dc.l $ff7e48ee,$7fffffc0,$61ff0000,$32a84a00 + dc.l $66ff0000,$32ce52ae,$ff784cfb,$3fff0170 + dc.l $000032ca,$2d7ca000,$0000ff60,$2d7cc000 + dc.l $0000ff64,$227c1000,$00003d7c,$0009ff7c + dc.l $44fc0008,$48ee7fff,$ff8004ee,$9000ff60 + dc.l $42eeff7e,$48ee7fff,$ffc061ff,$00003256 + dc.l $4a0066ff,$0000327c,$52aeff78,$4cfb3fff + dc.l $01700000,$32782d7c,$a0000000,$ff602d7c + dc.l $c0000000,$ff64223c,$90000000,$3d7c0009 + dc.l $ff7c44fc,$000848ee,$7fffff80,$04ee1000 + dc.l $ff6042ee,$ff7e48ee,$7fffffc0,$61ff0000 + dc.l $32044a00,$66ff0000,$322a52ae,$ff784cfb + dc.l $3fff0170,$00003226,$2d7ca000,$0000ff60 + dc.l $2d7cc000,$0000ff64,$227cd000,$00003d7c + dc.l $0009ff7c,$44fc0008,$48ee7fff,$ff8004ee + dc.l $9000ff60,$42eeff7e,$48ee7fff,$ffc061ff + dc.l $000031b2,$4a0066ff,$000031d8,$52aeff78 + dc.l $4cfb3fff,$01700000,$31d43d7c,$a040ff60 + dc.l $223c1111,$11a03d7c,$0004ff7c,$44fc0000 + dc.l $48ee7fff,$ff8000ee,$1000ff60,$42eeff7e + dc.l $48ee7fff,$ffc061ff,$0000316a,$4a0066ff + dc.l $00003190,$52aeff78,$4cfb3fff,$01700000 + dc.l $318c3d7c,$a040ff60,$227c0000,$00403d7c + dc.l $0004ff7c,$44fc0000,$48ee7fff,$ff8000ee + dc.l $9800ff60,$42eeff7e,$48ee7fff,$ffc061ff + dc.l $00003122,$4a0066ff,$00003148,$52aeff78 + dc.l $4cfb3fff,$01700000,$31443d7c,$a040ff60 + dc.l $223c1111,$11b03d7c,$0000ff7c,$44fc0000 + dc.l $48ee7fff,$ff8000ee,$1000ff60,$42eeff7e + dc.l $48ee7fff,$ffc061ff,$000030da,$4a0066ff + dc.l $00003100,$52aeff78,$4cfb3fff,$01700000 + dc.l $30fc3d7c,$a040ff60,$227c0000,$00103d7c + dc.l $0000ff7c,$44fc0000,$48ee7fff,$ff8000ee + dc.l $9000ff60,$42eeff7e,$48ee7fff,$ffc061ff + dc.l $00003092,$4a0066ff,$000030b8,$52aeff78 + dc.l $4cfb3fff,$01700000,$30b43d7c,$a040ff60 + dc.l $223c1111,$11903d7c,$0001ff7c,$44fc0000 + dc.l $48ee7fff,$ff8000ee,$1000ff60,$42eeff7e + dc.l $48ee7fff,$ffc061ff,$0000304a,$4a0066ff + dc.l $00003070,$52aeff78,$4cfb3fff,$01700000 + dc.l $306c3d7c,$a040ff60,$227c0000,$00503d7c + dc.l $0001ff7c,$44fc0000,$48ee7fff,$ff8000ee + dc.l $9000ff60,$42eeff7e,$48ee7fff,$ffc061ff + dc.l $00003002,$4a0066ff,$00003028,$52aeff78 + dc.l $4cfb3fff,$01700000,$30243d7c,$a0c0ff60 + dc.l $223c1111,$11a03d7c,$0004ff7c,$44fc0000 + dc.l $48ee7fff,$ff8000ee,$1000ff60,$42eeff7e + dc.l $48ee7fff,$ffc061ff,$00002fba,$4a0066ff + dc.l $00002fe0,$52aeff78,$4cfb3fff,$01700000 + dc.l $2fdc3d7c,$a0c0ff60,$227cffff,$ffc03d7c + dc.l $0004ff7c,$44fc0000,$48ee7fff,$ff8000ee + dc.l $9000ff60,$42eeff7e,$48ee7fff,$ffc061ff + dc.l $00002f72,$4a0066ff,$00002f98,$52aeff78 + dc.l $4cfb3fff,$01700000,$2f943d7c,$a0c0ff60 + dc.l $223c1111,$11b03d7c,$0000ff7c,$44fc0000 + dc.l $48ee7fff,$ff8000ee,$1800ff60,$42eeff7e + dc.l $48ee7fff,$ffc061ff,$00002f2a,$4a0066ff + dc.l $00002f50,$52aeff78,$4cfb3fff,$01700000 + dc.l $2f4c3d7c,$a0c0ff60,$227c1111,$11903d7c + dc.l $0001ff7c,$44fc0000,$48ee7fff,$ff8000ee + dc.l $9000ff60,$42eeff7e,$48ee7fff,$ffc061ff + dc.l $00002ee2,$4a0066ff,$00002f08,$52aeff78 + dc.l $4cfb3fff,$01700000,$2f043d7c,$a0c0ff60 + dc.l $223c1111,$11d03d7c,$0001ff7c,$44fc0000 + dc.l $48ee7fff,$ff8000ee,$1000ff60,$42eeff7e + dc.l $48ee7fff,$ffc061ff,$00002e9a,$4a0066ff + dc.l $00002ec0,$52aeff78,$4cfb3fff,$01700000 + dc.l $2ebc3d7c,$a0c0ff60,$227c0000,$00503d7c + dc.l $001bff7c,$44fc001f,$48ee7fff,$ff8000ee + dc.l $9000ff60,$42eeff7e,$48ee7fff,$ffc061ff + dc.l $00002e52,$4a0066ff,$00002e78,$222eff78 + dc.l $42804e75,$09456666,$65637469,$76652061 + dc.l $64647265,$73736573,$2e2e2e00,$52aeff78 + dc.l $4cfb3fff,$01700000,$2e544282,$760241ee + dc.l $ff743d7c,$0000ff7c,$44fc0000,$48eeffff + dc.l $ff804c10,$340242ee,$ff7e48ee,$ffffffc0 + dc.l $2d7c0000,$0004ff8c,$61ff0000,$2de84a00 + dc.l $66ff0000,$2e0e52ae,$ff784cfb,$3fff0170 + dc.l $00002e0a,$42827602,$41eeff74,$3d7c0000 + dc.l $ff7c44fc,$000048ee,$ffffff80,$4c183402 + dc.l $42eeff7e,$48eeffff,$ffc02d7c,$00000004 + dc.l $ff8c41ee,$ff782d48,$ffa061ff,$00002d96 + dc.l $4a0066ff,$00002dbc,$52aeff78,$4cfb3fff + dc.l $01700000,$2db84282,$760241ee,$ff783d7c + dc.l $0000ff7c,$44fc0000,$48eeffff,$ff804c20 + dc.l $340242ee,$ff7e48ee,$ffffffc0,$2d7c0000 + dc.l $0004ff8c,$41eeff74,$2d48ffa0,$61ff0000 + dc.l $2d444a00,$66ff0000,$2d6a52ae,$ff784cfb + dc.l $3fff0170,$00002d66,$42827602,$41ee0f74 + dc.l $3d7c0000,$ff7c44fc,$000048ee,$ffffff80 + dc.l $4c283402,$f00042ee,$ff7e48ee,$ffffffc0 + dc.l $2d7c0000,$0004ff8c,$61ff0000,$2cf84a00 + dc.l $66ff0000,$2d1e52ae,$ff784cfb,$3fff0170 + dc.l $00002d1a,$42827602,$41eeef74,$3d7c0000 + dc.l $ff7c44fc,$000048ee,$ffffff80,$4c283402 + dc.l $100042ee,$ff7e48ee,$ffffffc0,$2d7c0000 + dc.l $0004ff8c,$61ff0000,$2cac4a00,$66ff0000 + dc.l $2cd252ae,$ff7852ae,$ff7852ae,$ff784cfb + dc.l $3fff0170,$00002cc6,$42827602,$3d7c0000 + dc.l $ff7c44fc,$000048ee,$ffffff80,$4c3c3402 + dc.l $00000002,$42eeff7e,$48eeffff,$ffc02d7c + dc.l $00000004,$ff8c61ff,$00002c5a,$4a0066ff + dc.l $00002c80,$52aeff78,$60040000,$00024cfb + dc.l $3fff0170,$00002c76,$42827602,$3d7c0000 + dc.l $ff7c44fc,$000048ee,$ffffff80,$4c3a3402 + dc.l $ffda42ee,$ff7e48ee,$ffffffc0,$2d7c0000 + dc.l $0004ff8c,$61ff0000,$2c0c4a00,$66ff0000 + dc.l $2c3252ae,$ff784cfb,$3fff0170,$00002c2e + dc.l $42827602,$43eeff78,$3d7c0000,$ff7c44fc + dc.l $000048ee,$ffffff80,$4c213402,$42eeff7e + dc.l $48eeffff,$ffc02d7c,$00000004,$ff8c41ee + dc.l $ff742d48,$ffa461ff,$00002bba,$4a0066ff + dc.l $00002be0,$52aeff78,$4cfb3fff,$01700000 + dc.l $2bdc4282,$760245ee,$ff783d7c,$0000ff7c + dc.l $44fc0000,$48eeffff,$ff804c22,$340242ee + dc.l $ff7e48ee,$ffffffc0,$2d7c0000,$0004ff8c + dc.l $41eeff74,$2d48ffa8,$61ff0000,$2b684a00 + dc.l $66ff0000,$2b8e52ae,$ff784cfb,$3fff0170 + dc.l $00002b8a,$42827602,$47eeff78,$3d7c0000 + dc.l $ff7c44fc,$000048ee,$ffffff80,$4c233402 + dc.l $42eeff7e,$48eeffff,$ffc02d7c,$00000004 + dc.l $ff8c41ee,$ff742d48,$ffac61ff,$00002b16 + dc.l $4a0066ff,$00002b3c,$52aeff78,$4cfb3fff + dc.l $01700000,$2b384282,$760249ee,$ff783d7c + dc.l $0000ff7c,$44fc0000,$48eeffff,$ff804c24 + dc.l $340242ee,$ff7e48ee,$ffffffc0,$2d7c0000 + dc.l $0004ff8c,$41eeff74,$2d48ffb0,$61ff0000 + dc.l $2ac44a00,$66ff0000,$2aea52ae,$ff784cfb + dc.l $3fff0170,$00002ae6,$42827602,$4beeff78 + dc.l $3d7c0000,$ff7c44fc,$000048ee,$ffffff80 + dc.l $4c253402,$42eeff7e,$48eeffff,$ffc02d7c + dc.l $00000004,$ff8c41ee,$ff742d48,$ffb461ff + dc.l $00002a72,$4a0066ff,$00002a98,$52aeff78 + dc.l $4cfb3fff,$01700000,$2a94224e,$42827602 + dc.l $4de9ff78,$337c0000,$ff7c44fc,$000048e9 + dc.l $ffffff80,$4c263402,$42e9ff7e,$48e9ffff + dc.l $ffc0237c,$00000004,$ff8c41e9,$ff742348 + dc.l $ffb82c49,$61ff0000,$2a1c4a00,$66ff0000 + dc.l $2a4252ae,$ff784cfb,$3fff0170,$00002a3e + dc.l $42827602,$204f4fee,$ff783d7c,$0000ff7c + dc.l $44fc0000,$48eeffff,$ff804c27,$340242ee + dc.l $ff7e48ee,$ffffffc0,$2d7c0000,$0004ff8c + dc.l $43eeff74,$2d49ffbc,$2e4861ff,$000029c6 + dc.l $4a0066ff,$000029ec,$52aeff78,$4cfb3fff + dc.l $01700000,$29e84282,$760241ee,$ff7478f0 + dc.l $3d7c0000,$ff7c44fc,$000048ee,$ffffff80 + dc.l $4c303402,$401042ee,$ff7e48ee,$ffffffc0 + dc.l $2d7c0000,$0004ff8c,$61ff0000,$29784a00 + dc.l $66ff0000,$299e52ae,$ff784cfb,$3fff0170 + dc.l $0000299a,$42827602,$41eeff74,$78f83d7c + dc.l $0000ff7c,$44fc0000,$48eeffff,$ff804c30 + dc.l $34024210,$42eeff7e,$48eeffff,$ffc02d7c + dc.l $00000004,$ff8c61ff,$0000292a,$4a0066ff + dc.l $00002950,$52aeff78,$4cfb3fff,$01700000 + dc.l $294c4282,$760241ee,$ff7478fc,$3d7c0000 + dc.l $ff7c44fc,$000048ee,$ffffff80,$4c303402 + dc.l $441042ee,$ff7e48ee,$ffffffc0,$2d7c0000 + dc.l $0004ff8c,$61ff0000,$28dc4a00,$66ff0000 + dc.l $290252ae,$ff784cfb,$3fff0170,$000028fe + dc.l $42827602,$41eeff74,$78fe3d7c,$0000ff7c + dc.l $44fc0000,$48eeffff,$ff804c30,$34024610 + dc.l $42eeff7e,$48eeffff,$ffc02d7c,$00000004 + dc.l $ff8c61ff,$0000288e,$4a0066ff,$000028b4 + dc.l $52aeff78,$4cfb3fff,$01700000,$28b04282 + dc.l $760241ee,$ff7478f0,$3d7c0000,$ff7c44fc + dc.l $000048ee,$ffffff80,$4c303402,$481042ee + dc.l $ff7e48ee,$ffffffc0,$2d7c0000,$0004ff8c + dc.l $61ff0000,$28404a00,$66ff0000,$286652ae + dc.l $ff784cfb,$3fff0170,$00002862,$42827602 + dc.l $41eeff74,$78f83d7c,$0000ff7c,$44fc0000 + dc.l $48eeffff,$ff804c30,$34024a10,$42eeff7e + dc.l $48eeffff,$ffc02d7c,$00000004,$ff8c61ff + dc.l $000027f2,$4a0066ff,$00002818,$52aeff78 + dc.l $4cfb3fff,$01700000,$28144282,$760241ee + dc.l $ff7478fc,$3d7c0000,$ff7c44fc,$000048ee + dc.l $ffffff80,$4c303402,$4c1042ee,$ff7e48ee + dc.l $ffffffc0,$2d7c0000,$0004ff8c,$61ff0000 + dc.l $27a44a00,$66ff0000,$27ca52ae,$ff784cfb + dc.l $3fff0170,$000027c6,$42827602,$41eeff74 + dc.l $78fe3d7c,$0000ff7c,$44fc0000,$48eeffff + dc.l $ff804c30,$34024e10,$42eeff7e,$48eeffff + dc.l $ffc02d7c,$00000004,$ff8c61ff,$00002756 + dc.l $4a0066ff,$0000277c,$52aeff78,$4cfb3fff + dc.l $01700000,$27784282,$760241ee,$ff74287c + dc.l $fffffffe,$3d7c0000,$ff7c44fc,$000048ee + dc.l $ffffff80,$4c303402,$ce1042ee,$ff7e48ee + dc.l $ffffffc0,$2d7c0000,$0004ff8c,$61ff0000 + dc.l $27044a00,$66ff0000,$272a52ae,$ff784cfb + dc.l $3fff0170,$00002726,$42827602,$41eeff74 + dc.l $287c0000,$00023d7c,$0000ff7c,$44fc0000 + dc.l $48eeffff,$ff804c30,$3402cef0,$42eeff7e + dc.l $48eeffff,$ffc02d7c,$00000004,$ff8c61ff + dc.l $000026b2,$4a0066ff,$000026d8,$52aeff78 + dc.l $4cfb3fff,$01700000,$26d44282,$760243ee + dc.l $ff7478f0,$3d7c0000,$ff7c44fc,$000048ee + dc.l $ffffff80,$4c313402,$401042ee,$ff7e48ee + dc.l $ffffffc0,$2d7c0000,$0004ff8c,$61ff0000 + dc.l $26644a00,$66ff0000,$268a52ae,$ff784cfb + dc.l $3fff0170,$00002686,$42827602,$45eeff74 + dc.l $78f03d7c,$0000ff7c,$44fc0000,$48eeffff + dc.l $ff804c32,$34024010,$42eeff7e,$48eeffff + dc.l $ffc02d7c,$00000004,$ff8c61ff,$00002616 + dc.l $4a0066ff,$0000263c,$52aeff78,$4cfb3fff + dc.l $01700000,$26384282,$760247ee,$ff7478f0 + dc.l $3d7c0000,$ff7c44fc,$000048ee,$ffffff80 + dc.l $4c333402,$401042ee,$ff7e48ee,$ffffffc0 + dc.l $2d7c0000,$0004ff8c,$61ff0000,$25c84a00 + dc.l $66ff0000,$25ee52ae,$ff784cfb,$3fff0170 + dc.l $000025ea,$42827602,$49eeff74,$78f03d7c + dc.l $0000ff7c,$44fc0000,$48eeffff,$ff804c34 + dc.l $34024010,$42eeff7e,$48eeffff,$ffc02d7c + dc.l $00000004,$ff8c61ff,$0000257a,$4a0066ff + dc.l $000025a0,$52aeff78,$4cfb3fff,$01700000 + dc.l $259c4282,$76024bee,$ff7478f0,$3d7c0000 + dc.l $ff7c44fc,$000048ee,$ffffff80,$4c353402 + dc.l $401042ee,$ff7e48ee,$ffffffc0,$2d7c0000 + dc.l $0004ff8c,$61ff0000,$252c4a00,$66ff0000 + dc.l $255252ae,$ff784cfb,$3fff0170,$0000254e + dc.l $224e4282,$76024de9,$ff7478f0,$337c0000 + dc.l $ff7c44fc,$000048e9,$ffffff80,$4c363402 + dc.l $401042e9,$ff7e48e9,$ffffffc0,$237c0000 + dc.l $0004ff8c,$2c4961ff,$000024da,$4a0066ff + dc.l $00002500,$52aeff78,$4cfb3fff,$01700000 + dc.l $24fc4282,$7602204f,$4feeff74,$78f03d7c + dc.l $0000ff7c,$44fc0000,$48eeffff,$ff804c37 + dc.l $34024010,$42eeff7e,$48eeffff,$ffc02d7c + dc.l $00000004,$ff8c2e48,$61ff0000,$24884a00 + dc.l $66ff0000,$24ae52ae,$ff784cfb,$3fff0170 + dc.l $000024aa,$42827602,$43eeff74,$3d7c0000 + dc.l $ff7c44fc,$000048ee,$ffffff80,$4c113402 + dc.l $42eeff7e,$48eeffff,$ffc02d7c,$00000004 + dc.l $ff8c61ff,$0000243e,$4a0066ff,$00002464 + dc.l $52aeff78,$4cfb3fff,$01700000,$24604282 + dc.l $760245ee,$ff743d7c,$0000ff7c,$44fc0000 + dc.l $48eeffff,$ff804c12,$340242ee,$ff7e48ee + dc.l $ffffffc0,$2d7c0000,$0004ff8c,$61ff0000 + dc.l $23f44a00,$66ff0000,$241a52ae,$ff784cfb + dc.l $3fff0170,$00002416,$42827602,$47eeff74 + dc.l $3d7c0000,$ff7c44fc,$000048ee,$ffffff80 + dc.l $4c133402,$42eeff7e,$48eeffff,$ffc02d7c + dc.l $00000004,$ff8c61ff,$000023aa,$4a0066ff + dc.l $000023d0,$52aeff78,$4cfb3fff,$01700000 + dc.l $23cc4282,$760249ee,$ff743d7c,$0000ff7c + dc.l $44fc0000,$48eeffff,$ff804c14,$340242ee + dc.l $ff7e48ee,$ffffffc0,$2d7c0000,$0004ff8c + dc.l $61ff0000,$23604a00,$66ff0000,$238652ae + dc.l $ff784cfb,$3fff0170,$00002382,$42827602 + dc.l $4beeff74,$3d7c0000,$ff7c44fc,$000048ee + dc.l $ffffff80,$4c153402,$42eeff7e,$48eeffff + dc.l $ffc02d7c,$00000004,$ff8c61ff,$00002316 + dc.l $4a0066ff,$0000233c,$52aeff78,$4cfb3fff + dc.l $01700000,$2338224e,$42827602,$4de9ff74 + dc.l $337c0000,$ff7c44fc,$000048e9,$ffffff80 + dc.l $4c163402,$42e9ff7e,$48e9ffff,$ffc0237c + dc.l $00000004,$ff8c2c49,$61ff0000,$22c84a00 + dc.l $66ff0000,$22ee52ae,$ff784cfb,$3fff0170 + dc.l $000022ea,$42827602,$204f4fee,$ff743d7c + dc.l $0000ff7c,$44fc0000,$48eeffff,$ff804c17 + dc.l $340242ee,$ff7e48ee,$ffffffc0,$2d7c0000 + dc.l $0004ff8c,$2e4861ff,$0000227a,$4a0066ff + dc.l $000022a0,$52aeff78,$4cfb3fff,$01700000 + dc.l $229c4282,$760243ee,$ff743d7c,$0000ff7c + dc.l $44fc0000,$48eeffff,$ff804c19,$340242ee + dc.l $ff7e48ee,$ffffffc0,$2d7c0000,$0004ff8c + dc.l $41eeff78,$2d48ffa4,$61ff0000,$22284a00 + dc.l $66ff0000,$224e52ae,$ff784cfb,$3fff0170 + dc.l $0000224a,$42827602,$45eeff74,$3d7c0000 + dc.l $ff7c44fc,$000048ee,$ffffff80,$4c1a3402 + dc.l $42eeff7e,$48eeffff,$ffc02d7c,$00000004 + dc.l $ff8c41ee,$ff782d48,$ffa861ff,$000021d6 + dc.l $4a0066ff,$000021fc,$52aeff78,$4cfb3fff + dc.l $01700000,$21f84282,$760247ee,$ff743d7c + dc.l $0000ff7c,$44fc0000,$48eeffff,$ff804c1b + dc.l $340242ee,$ff7e48ee,$ffffffc0,$2d7c0000 + dc.l $0004ff8c,$41eeff78,$2d48ffac,$61ff0000 + dc.l $21844a00,$66ff0000,$21aa52ae,$ff784cfb + dc.l $3fff0170,$000021a6,$42827602,$49eeff74 + dc.l $3d7c0000,$ff7c44fc,$000048ee,$ffffff80 + dc.l $4c1c3402,$42eeff7e,$48eeffff,$ffc02d7c + dc.l $00000004,$ff8c41ee,$ff782d48,$ffb061ff + dc.l $00002132,$4a0066ff,$00002158,$52aeff78 + dc.l $4cfb3fff,$01700000,$21544282,$76024bee + dc.l $ff743d7c,$0000ff7c,$44fc0000,$48eeffff + dc.l $ff804c1d,$340242ee,$ff7e48ee,$ffffffc0 + dc.l $2d7c0000,$0004ff8c,$41eeff78,$2d48ffb4 + dc.l $61ff0000,$20e04a00,$66ff0000,$210652ae + dc.l $ff784cfb,$3fff0170,$00002102,$224e4282 + dc.l $76024de9,$ff74337c,$0000ff7c,$44fc0000 + dc.l $48e9ffff,$ff804c1e,$340242e9,$ff7e48e9 + dc.l $ffffffc0,$237c0000,$0004ff8c,$41e9ff78 + dc.l $2348ffb8,$2c4961ff,$0000208a,$4a0066ff + dc.l $000020b0,$52aeff78,$4cfb3fff,$01700000 + dc.l $20ac4282,$7602204f,$4feeff74,$3d7c0000 + dc.l $ff7c44fc,$000048ee,$ffffff80,$4c1f3402 + dc.l $42eeff7e,$48eeffff,$ffc02d7c,$00000004 + dc.l $ff8c43ee,$ff782d49,$ffbc2e48,$61ff0000 + dc.l $20344a00,$66ff0000,$205a52ae,$ff784cfb + dc.l $3fff0170,$00002056,$42827602,$43eeef74 + dc.l $3d7c0000,$ff7c44fc,$000048ee,$ffffff80 + dc.l $4c293402,$100042ee,$ff7e48ee,$ffffffc0 + dc.l $2d7c0000,$0004ff8c,$61ff0000,$1fe84a00 + dc.l $66ff0000,$200e52ae,$ff784cfb,$3fff0170 + dc.l $0000200a,$42827602,$45eeef74,$3d7c0000 + dc.l $ff7c44fc,$000048ee,$ffffff80,$4c2a3402 + dc.l $100042ee,$ff7e48ee,$ffffffc0,$2d7c0000 + dc.l $0004ff8c,$61ff0000,$1f9c4a00,$66ff0000 + dc.l $1fc252ae,$ff784cfb,$3fff0170,$00001fbe + dc.l $42827602,$47eeef74,$3d7c0000,$ff7c44fc + dc.l $000048ee,$ffffff80,$4c2b3402,$100042ee + dc.l $ff7e48ee,$ffffffc0,$2d7c0000,$0004ff8c + dc.l $61ff0000,$1f504a00,$66ff0000,$1f7652ae + dc.l $ff784cfb,$3fff0170,$00001f72,$42827602 + dc.l $49eeef74,$3d7c0000,$ff7c44fc,$000048ee + dc.l $ffffff80,$4c2c3402,$100042ee,$ff7e48ee + dc.l $ffffffc0,$2d7c0000,$0004ff8c,$61ff0000 + dc.l $1f044a00,$66ff0000,$1f2a52ae,$ff784cfb + dc.l $3fff0170,$00001f26,$42827602,$4beeef74 + dc.l $3d7c0000,$ff7c44fc,$000048ee,$ffffff80 + dc.l $4c2d3402,$100042ee,$ff7e48ee,$ffffffc0 + dc.l $2d7c0000,$0004ff8c,$61ff0000,$1eb84a00 + dc.l $66ff0000,$1ede52ae,$ff784cfb,$3fff0170 + dc.l $00001eda,$224e4282,$76024de9,$ef74337c + dc.l $0000ff7c,$44fc0000,$48e9ffff,$ff804c2e + dc.l $34021000,$42e9ff7e,$48e9ffff,$ffc0237c + dc.l $00000004,$ff8c2c49,$61ff0000,$1e684a00 + dc.l $66ff0000,$1e8e52ae,$ff784cfb,$3fff0170 + dc.l $00001e8a,$42827602,$204f4fee,$ef743d7c + dc.l $0000ff7c,$44fc0000,$48eeffff,$ff804c2f + dc.l $34021000,$42eeff7e,$48eeffff,$ffc02d7c + dc.l $00000004,$ff8c2e48,$61ff0000,$1e184a00 + dc.l $66ff0000,$1e3e52ae,$ff784cfb,$3fff0170 + dc.l $00001e3a,$42827602,$41ee0f74,$3d7c0000 + dc.l $ff7c44fc,$000048ee,$ffffff80,$4c283402 + dc.l $f00042ee,$ff7e48ee,$ffffffc0,$2d7c0000 + dc.l $0004ff8c,$61ff0000,$1dcc4a00,$66ff0000 + dc.l $1df252ae,$ff786004,$00000002,$4cfb3fff + dc.l $01700000,$1de84282,$76023d7c,$0000ff7c + dc.l $44fc0000,$48eeffff,$ff804c3a,$3402ffda + dc.l $42eeff7e,$48eeffff,$ffc02d7c,$00000004 + dc.l $ff8c61ff,$00001d7e,$4a0066ff,$00001da4 + dc.l $52aeff78,$4cfb3fff,$01700000,$1da04282 + dc.l $760247ee,$ff7478f0,$3d7c0000,$ff7c44fc + dc.l $000048ee,$ffffff80,$4c333402,$401042ee + dc.l $ff7e48ee,$ffffffc0,$2d7c0000,$0004ff8c + dc.l $61ff0000,$1d304a00,$66ff0000,$1d5652ae + dc.l $ff784cfb,$3fff0170,$00001d52,$42827602 + dc.l $47eeff74,$78f83d7c,$0000ff7c,$44fc0000 + dc.l $48eeffff,$ff804c33,$34024210,$42eeff7e + dc.l $48eeffff,$ffc02d7c,$00000004,$ff8c61ff + dc.l $00001ce2,$4a0066ff,$00001d08,$52aeff78 + dc.l $4cfb3fff,$01700000,$1d044282,$760247ee + dc.l $ff7478fc,$3d7c0000,$ff7c44fc,$000048ee + dc.l $ffffff80,$4c333402,$441042ee,$ff7e48ee + dc.l $ffffffc0,$2d7c0000,$0004ff8c,$61ff0000 + dc.l $1c944a00,$66ff0000,$1cba52ae,$ff784cfb + dc.l $3fff0170,$00001cb6,$42827602,$47eeff74 + dc.l $78fe3d7c,$0000ff7c,$44fc0000,$48eeffff + dc.l $ff804c33,$34024610,$42eeff7e,$48eeffff + dc.l $ffc02d7c,$00000004,$ff8c61ff,$00001c46 + dc.l $4a0066ff,$00001c6c,$52aeff78,$4cfb3fff + dc.l $01700000,$1c684282,$760247ee,$ff7478f0 + dc.l $3d7c0000,$ff7c44fc,$000048ee,$ffffff80 + dc.l $4c333402,$481042ee,$ff7e48ee,$ffffffc0 + dc.l $2d7c0000,$0004ff8c,$61ff0000,$1bf84a00 + dc.l $66ff0000,$1c1e52ae,$ff784cfb,$3fff0170 + dc.l $00001c1a,$42827602,$47eeff74,$78f83d7c + dc.l $0000ff7c,$44fc0000,$48eeffff,$ff804c33 + dc.l $34024a10,$42eeff7e,$48eeffff,$ffc02d7c + dc.l $00000004,$ff8c61ff,$00001baa,$4a0066ff + dc.l $00001bd0,$52aeff78,$4cfb3fff,$01700000 + dc.l $1bcc4282,$760247ee,$ff7478fc,$3d7c0000 + dc.l $ff7c44fc,$000048ee,$ffffff80,$4c333402 + dc.l $4c1042ee,$ff7e48ee,$ffffffc0,$2d7c0000 + dc.l $0004ff8c,$61ff0000,$1b5c4a00,$66ff0000 + dc.l $1b8252ae,$ff784cfb,$3fff0170,$00001b7e + dc.l $42827602,$47eeff74,$78fe3d7c,$0000ff7c + dc.l $44fc0000,$48eeffff,$ff804c33,$34024e10 + dc.l $42eeff7e,$48eeffff,$ffc02d7c,$00000004 + dc.l $ff8c61ff,$00001b0e,$4a0066ff,$00001b34 + dc.l $52aeff78,$4cfb3fff,$01700000,$1b304282 + dc.l $760247ee,$ff74287c,$00000002,$3d7c0000 + dc.l $ff7c44fc,$000048ee,$ffffff80,$4c333402 + dc.l $cef042ee,$ff7e48ee,$ffffffc0,$2d7c0000 + dc.l $0004ff8c,$61ff0000,$1abc4a00,$66ff0000 + dc.l $1ae252ae,$ff784cfb,$3fff0170,$00001ade + dc.l $42827602,$47eeff74,$287c0000,$00023d7c + dc.l $0000ff7c,$44fc0000,$48eeffff,$ff804c33 + dc.l $34020750,$42eeff7e,$48eeffff,$ffc02d7c + dc.l $00000004,$ff8c61ff,$00001a6a,$4a0066ff + dc.l $00001a90,$52aeff78,$4cfb3fff,$01700000 + dc.l $1a8c4282,$760247ee,$ff74284b,$d9fc0000 + dc.l $00103d7c,$0000ff7c,$44fc0000,$48eeffff + dc.l $ff804c30,$3402c9a0,$fff042ee,$ff7e48ee + dc.l $ffffffc0,$2d7c0000,$0004ff8c,$61ff0000 + dc.l $1a144a00,$66ff0000,$1a3a52ae,$ff784cfb + dc.l $3fff0170,$00001a36,$42827602,$47eeff74 + dc.l $287c0000,$00023d7c,$0000ff7c,$44fc0000 + dc.l $48eeffff,$ff804c33,$3402cef0,$42eeff7e + dc.l $48eeffff,$ffc02d7c,$00000004,$ff8c61ff + dc.l $000019c2,$4a0066ff,$000019e8,$52aeff78 + dc.l $60040000,$00024cfb,$3fff0170,$000019de + dc.l $42827602,$47eeff74,$78f03d7c,$0000ff7c + dc.l $44fc0000,$48eeffff,$ff804c3b,$340240e4 + dc.l $42eeff7e,$48eeffff,$ffc02d7c,$00000004 + dc.l $ff8c61ff,$0000196e,$4a0066ff,$00001994 + dc.l $52aeff78,$60040000,$00024cfb,$3fff0170 + dc.l $0000198a,$42827602,$41eeff74,$78f83d7c + dc.l $0000ff7c,$44fc0000,$48ee7fff,$ff804c3b + dc.l $340242e4,$42eeff7e,$48ee7fff,$ffc02d7c + dc.l $00000004,$ff8c61ff,$0000191a,$4a0066ff + dc.l $00001940,$52aeff78,$60040000,$00024cfb + dc.l $3fff0170,$00001936,$42827602,$41eeff74 + dc.l $78fc3d7c,$0000ff7c,$44fc0000,$48ee7fff + dc.l $ff804c3b,$340244e4,$42eeff7e,$48ee7fff + dc.l $ffc02d7c,$00000004,$ff8c61ff,$000018c6 + dc.l $4a0066ff,$000018ec,$52aeff78,$60040000 + dc.l $00024cfb,$3fff0170,$000018e2,$42827602 + dc.l $41eeff74,$78fe3d7c,$0000ff7c,$44fc0000 + dc.l $48ee7fff,$ff804c3b,$340246e4,$42eeff7e + dc.l $48ee7fff,$ffc02d7c,$00000004,$ff8c61ff + dc.l $00001872,$4a0066ff,$00001898,$52aeff78 + dc.l $60040000,$00024cfb,$3fff0170,$0000188e + dc.l $42827602,$41eeff74,$78f03d7c,$0000ff7c + dc.l $44fc0000,$48ee7fff,$ff804c3b,$340248e4 + dc.l $42eeff7e,$48ee7fff,$ffc02d7c,$00000004 + dc.l $ff8c61ff,$0000181e,$4a0066ff,$00001844 + dc.l $52aeff78,$60040000,$00024cfb,$3fff0170 + dc.l $0000183a,$42827602,$41eeff74,$78f83d7c + dc.l $0000ff7c,$44fc0000,$48ee7fff,$ff804c3b + dc.l $34024ae4,$42eeff7e,$48ee7fff,$ffc02d7c + dc.l $00000004,$ff8c61ff,$000017ca,$4a0066ff + dc.l $000017f0,$52aeff78,$60040000,$00024cfb + dc.l $3fff0170,$000017e6,$42827602,$41eeff74 + dc.l $78fc3d7c,$0000ff7c,$44fc0000,$48ee7fff + dc.l $ff804c3b,$34024ce4,$42eeff7e,$48ee7fff + dc.l $ffc02d7c,$00000004,$ff8c61ff,$00001776 + dc.l $4a0066ff,$0000179c,$52aeff78,$60040000 + dc.l $00024cfb,$3fff0170,$00001792,$42827602 + dc.l $41eeff74,$78fe3d7c,$0000ff7c,$44fc0000 + dc.l $48ee7fff,$ff804c3b,$34024ee4,$42eeff7e + dc.l $48ee7fff,$ffc02d7c,$00000004,$ff8c61ff + dc.l $00001722,$4a0066ff,$00001748,$52aeff78 + dc.l $60040000,$00024cfb,$3fff0170,$0000173e + dc.l $42827602,$47eeff74,$287cffff,$fffe3d7c + dc.l $0000ff7c,$44fc0000,$48eeffff,$ff804c3b + dc.l $3402cee0,$42eeff7e,$48eeffff,$ffc02d7c + dc.l $00000004,$ff8c61ff,$000016ca,$4a0066ff + dc.l $000016f0,$52aeff78,$60040000,$00024cfb + dc.l $3fff0170,$000016e6,$42827602,$47eeff74 + dc.l $287c0000,$00023d7c,$0000ff7c,$44fc0000 + dc.l $48eeffff,$ff804c3b,$34020760,$ffd042ee + dc.l $ff7e48ee,$ffffffc0,$2d7c0000,$0004ff8c + dc.l $61ff0000,$16704a00,$66ff0000,$169652ae + dc.l $ff7852ae,$ff784cfb,$3fff0170,$0000168e + dc.l $42827602,$47f9ffff,$ff74287c,$00000002 + dc.l $3d7c0000,$ff7c44fc,$000048ee,$ffffff80 + dc.l $4c3b3402,$cf300000,$000a42ee,$ff7e48ee + dc.l $ffffffc0,$2d7c0000,$0004ff8c,$60040000 + dc.l $000261ff,$0000160e,$4a0066ff,$00001634 + dc.l $52aeff78,$60040000,$00024cfb,$3fff0170 + dc.l $0000162a,$42827602,$43eeff74,$78f03d7c + dc.l $0000ff7c,$44fc0000,$48eeffff,$ff804c3b + dc.l $340240e4,$42eeff7e,$48eeffff,$ffc02d7c + dc.l $00000004,$ff8c61ff,$000015ba,$4a0066ff + dc.l $000015e0,$52aeff78,$60040000,$00024cfb + dc.l $3fff0170,$000015d6,$42827602,$41eeff74 + dc.l $78f83d7c,$0000ff7c,$44fc0000,$48eeffff + dc.l $ff804c3b,$340242e4,$42eeff7e,$48eeffff + dc.l $ffc02d7c,$00000004,$ff8c61ff,$00001566 + dc.l $4a0066ff,$0000158c,$52aeff78,$60040000 + dc.l $00024cfb,$3fff0170,$00001582,$42827602 + dc.l $41eeff74,$78fc3d7c,$0000ff7c,$44fc0000 + dc.l $48eeffff,$ff804c3b,$340244e4,$42eeff7e + dc.l $48eeffff,$ffc02d7c,$00000004,$ff8c61ff + dc.l $00001512,$4a0066ff,$00001538,$52aeff78 + dc.l $60040000,$00024cfb,$3fff0170,$0000152e + dc.l $42827602,$41eeff74,$78fe3d7c,$0000ff7c + dc.l $44fc0000,$48eeffff,$ff804c3b,$340246e4 + dc.l $42eeff7e,$48eeffff,$ffc02d7c,$00000004 + dc.l $ff8c61ff,$000014be,$4a0066ff,$000014e4 + dc.l $52aeff78,$60040000,$00024cfb,$3fff0170 + dc.l $000014da,$42827602,$41eeff74,$78f03d7c + dc.l $0000ff7c,$44fc0000,$48eeffff,$ff804c3b + dc.l $340248e4,$42eeff7e,$48eeffff,$ffc02d7c + dc.l $00000004,$ff8c61ff,$0000146a,$4a0066ff + dc.l $00001490,$52aeff78,$60040000,$00024cfb + dc.l $3fff0170,$00001486,$42827602,$41eeff74 + dc.l $78f83d7c,$0000ff7c,$44fc0000,$48eeffff + dc.l $ff804c3b,$34024ae4,$42eeff7e,$48eeffff + dc.l $ffc02d7c,$00000004,$ff8c61ff,$00001416 + dc.l $4a0066ff,$0000143c,$52aeff78,$60040000 + dc.l $00024cfb,$3fff0170,$00001432,$42827602 + dc.l $41eeff74,$78fc3d7c,$0000ff7c,$44fc0000 + dc.l $48eeffff,$ff804c3b,$34024ce4,$42eeff7e + dc.l $48eeffff,$ffc02d7c,$00000004,$ff8c61ff + dc.l $000013c2,$4a0066ff,$000013e8,$52aeff78 + dc.l $60040000,$00024cfb,$3fff0170,$000013de + dc.l $42827602,$41eeff74,$78fe3d7c,$0000ff7c + dc.l $44fc0000,$48eeffff,$ff804c3b,$34024ee4 + dc.l $42eeff7e,$48eeffff,$ffc02d7c,$00000004 + dc.l $ff8c61ff,$0000136e,$4a0066ff,$00001394 + dc.l $52aeff78,$4cfb3fff,$01700000,$13904282 + dc.l $760241ee,$ff7478fe,$3d7c0000,$ff7c44fc + dc.l $000048ee,$ffffff80,$4c3b3402,$4e2642ee + dc.l $ff7e48ee,$ffffffc0,$2d7c0000,$0004ff8c + dc.l $60040000,$000261ff,$0000131a,$4a0066ff + dc.l $00001340,$52aeff78,$4cfb3fff,$01700000 + dc.l $133c4282,$760247ee,$ef7449ee,$ff70288b + dc.l $78f03d7c,$0000ff7c,$44fc0000,$48eeffff + dc.l $ff804c34,$34024122,$00101000,$42eeff7e + dc.l $48eeffff,$ffc02d7c,$00000004,$ff8c61ff + dc.l $000012c2,$4a0066ff,$000012e8,$52aeff78 + dc.l $4cfb3fff,$01700000,$12e44282,$760247ee + dc.l $ef7449ee,$ff70288b,$78f83d7c,$0000ff7c + dc.l $44fc0000,$48eeffff,$ff804c34,$34024322 + dc.l $00101000,$42eeff7e,$48eeffff,$ffc02d7c + dc.l $00000004,$ff8c61ff,$0000126a,$4a0066ff + dc.l $00001290,$52aeff78,$4cfb3fff,$01700000 + dc.l $128c4282,$760247ee,$ef7449ee,$ff70288b + dc.l $78fc3d7c,$0000ff7c,$44fc0000,$48eeffff + dc.l $ff804c34,$34024522,$00101000,$42eeff7e + dc.l $48eeffff,$ffc02d7c,$00000004,$ff8c61ff + dc.l $00001212,$4a0066ff,$00001238,$52aeff78 + dc.l $4cfb3fff,$01700000,$12344282,$760247ee + dc.l $ef7449ee,$ff70288b,$78fe3d7c,$0000ff7c + dc.l $44fc0000,$48eeffff,$ff804c34,$34024722 + dc.l $00101000,$42eeff7e,$48eeffff,$ffc02d7c + dc.l $00000004,$ff8c61ff,$000011ba,$4a0066ff + dc.l $000011e0,$52aeff78,$4cfb3fff,$01700000 + dc.l $11dc4282,$760247ee,$ef7449ee,$ff70288b + dc.l $78f03d7c,$0000ff7c,$44fc0000,$48eeffff + dc.l $ff804c34,$34024922,$00101000,$42eeff7e + dc.l $48eeffff,$ffc02d7c,$00000004,$ff8c61ff + dc.l $00001162,$4a0066ff,$00001188,$52aeff78 + dc.l $4cfb3fff,$01700000,$11844282,$760247ee + dc.l $ef7449ee,$ff70288b,$78f83d7c,$0000ff7c + dc.l $44fc0000,$48eeffff,$ff804c34,$34024b22 + dc.l $00101000,$42eeff7e,$48eeffff,$ffc02d7c + dc.l $00000004,$ff8c61ff,$0000110a,$4a0066ff + dc.l $00001130,$52aeff78,$4cfb3fff,$01700000 + dc.l $112c4282,$760247ee,$ef7449ee,$ff70288b + dc.l $78fc3d7c,$0000ff7c,$44fc0000,$48eeffff + dc.l $ff804c34,$34024d22,$00101000,$42eeff7e + dc.l $48eeffff,$ffc02d7c,$00000004,$ff8c61ff + dc.l $000010b2,$4a0066ff,$000010d8,$52aeff78 + dc.l $4cfb3fff,$01700000,$10d44282,$760247ee + dc.l $ef7449ee,$ff70288b,$78fe3d7c,$0000ff7c + dc.l $44fc0000,$48eeffff,$ff804c34,$34024f22 + dc.l $00101000,$42eeff7e,$48eeffff,$ffc02d7c + dc.l $00000004,$ff8c61ff,$0000105a,$4a0066ff + dc.l $00001080,$52aeff78,$4cfb3fff,$01700000 + dc.l $107c4282,$760247ee,$ef7449ee,$ff70288b + dc.l $78fe3d7c,$0000ff7c,$44fc0000,$48eeffff + dc.l $ff804c34,$34024f33,$00000010,$00001000 + dc.l $42eeff7e,$48eeffff,$ffc02d7c,$00000004 + dc.l $ff8c61ff,$00000ffe,$4a0066ff,$00001024 + dc.l $52aeff78,$4cfb3fff,$01700000,$10204282 + dc.l $760247ee,$ef7449ee,$ff70288b,$78fe3d7c + dc.l $0000ff7c,$44fc0000,$48eeffff,$ff804c34 + dc.l $34020753,$00001000,$42eeff7e,$48eeffff + dc.l $ffc02d7c,$00000004,$ff8c61ff,$00000fa6 + dc.l $4a0066ff,$00000fcc,$52aeff78,$4cfb3fff + dc.l $01700000,$0fc84282,$760247ee,$ef7449ee + dc.l $ff70288b,$78fe3d7c,$0000ff7c,$44fc0000 + dc.l $48eeffff,$ff804c34,$34020753,$00001000 + dc.l $42eeff7e,$48eeffff,$ffc02d7c,$00000004 + dc.l $ff8c61ff,$00000f4e,$4a0066ff,$00000f74 + dc.l $52aeff78,$4cfb3fff,$01700000,$0f704282 + dc.l $760247ee,$ef7449ee,$ff70288b,$78f0d88c + dc.l $3d7c0000,$ff7c44fc,$000048ee,$ffffff80 + dc.l $4c303402,$49b30000,$00100000,$100042ee + dc.l $ff7e48ee,$ffffffc0,$2d7c0000,$0004ff8c + dc.l $61ff0000,$0ef04a00,$66ff0000,$0f1652ae + dc.l $ff7852ae,$ff784cfb,$3fff0170,$00000f0e + dc.l $224e4282,$760247e9,$0f7449e9,$ff70288b + dc.l $2c7cffff,$fffe337c,$0000ff7c,$44fc0000 + dc.l $48e9ffff,$ff804c34,$3402ef22,$0010f000 + dc.l $42e9ff7e,$48e9ffff,$ffc0237c,$00000004 + dc.l $ff8c2c49,$61ff0000,$0e8c4a00,$66ff0000 + dc.l $0eb252ae,$ff784cfb,$3fff0170,$00000eae + dc.l $224e4282,$760247e9,$0f7449e9,$ff70288b + dc.l $2c7c0000,$0002337c,$0000ff7c,$44fc0000 + dc.l $48e9ffff,$ff804c34,$3402ef22,$fff0f000 + dc.l $42e9ff7e,$48e9ffff,$ffc0237c,$00000004 + dc.l $ff8c2c49,$61ff0000,$0e2c4a00,$66ff0000 + dc.l $0e5252ae,$ff784cfb,$3fff0170,$00000e4e + dc.l $42827602,$47eeff54,$49eeff70,$288b99fc + dc.l $00000010,$78103d7c,$0000ff7c,$44fc0000 + dc.l $48eeffff,$ff804c34,$34024126,$00100010 + dc.l $42eeff7e,$48eeffff,$ffc02d7c,$00000004 + dc.l $ff8c61ff,$00000dce,$4a0066ff,$00000df4 + dc.l $52aeff78,$4cfb3fff,$01700000,$0df04282 + dc.l $760247ee,$ff5449ee,$ff70288b,$99fc0000 + dc.l $00107808,$3d7c0000,$ff7c44fc,$000048ee + dc.l $ffffff80,$4c343402,$43260010,$001042ee + dc.l $ff7e48ee,$ffffffc0,$2d7c0000,$0004ff8c + dc.l $61ff0000,$0d704a00,$66ff0000,$0d9652ae + dc.l $ff784cfb,$3fff0170,$00000d92,$42827602 + dc.l $47eeff54,$49eeff70,$288b99fc,$00000010 + dc.l $78043d7c,$0000ff7c,$44fc0000,$48eeffff + dc.l $ff804c34,$34024526,$00100010,$42eeff7e + dc.l $48eeffff,$ffc02d7c,$00000004,$ff8c61ff + dc.l $00000d12,$4a0066ff,$00000d38,$52aeff78 + dc.l $4cfb3fff,$01700000,$0d344282,$760247ee + dc.l $ff5449ee,$ff70288b,$99fc0000,$00107802 + dc.l $3d7c0000,$ff7c44fc,$000048ee,$ffffff80 + dc.l $4c343402,$47260010,$001042ee,$ff7e48ee + dc.l $ffffffc0,$2d7c0000,$0004ff8c,$61ff0000 + dc.l $0cb44a00,$66ff0000,$0cda52ae,$ff784cfb + dc.l $3fff0170,$00000cd6,$42827602,$47eeff54 + dc.l $49eeff70,$288b99fc,$00000010,$78103d7c + dc.l $0000ff7c,$44fc0000,$48eeffff,$ff804c34 + dc.l $34024926,$00100010,$42eeff7e,$48eeffff + dc.l $ffc02d7c,$00000004,$ff8c61ff,$00000c56 + dc.l $4a0066ff,$00000c7c,$52aeff78,$4cfb3fff + dc.l $01700000,$0c784282,$760247ee,$ff5449ee + dc.l $ff70288b,$99fc0000,$00107808,$3d7c0000 + dc.l $ff7c44fc,$000048ee,$ffffff80,$4c343402 + dc.l $43260010,$001042ee,$ff7e48ee,$ffffffc0 + dc.l $2d7c0000,$0004ff8c,$61ff0000,$0bf84a00 + dc.l $66ff0000,$0c1e52ae,$ff784cfb,$3fff0170 + dc.l $00000c1a,$42827602,$47eeff54,$49eeff70 + dc.l $288b99fc,$00000010,$78043d7c,$0000ff7c + dc.l $44fc0000,$48eeffff,$ff804c34,$34024d26 + dc.l $00100010,$42eeff7e,$48eeffff,$ffc02d7c + dc.l $00000004,$ff8c61ff,$00000b9a,$4a0066ff + dc.l $00000bc0,$52aeff78,$4cfb3fff,$01700000 + dc.l $0bbc4282,$760247ee,$ff5449ee,$ff70288b + dc.l $99fc0000,$00107802,$3d7c0000,$ff7c44fc + dc.l $000048ee,$ffffff80,$4c343402,$4f260010 + dc.l $001042ee,$ff7e48ee,$ffffffc0,$2d7c0000 + dc.l $0004ff8c,$61ff0000,$0b3c4a00,$66ff0000 + dc.l $0b6252ae,$ff784cfb,$3fff0170,$00000b5e + dc.l $42827602,$47eeff54,$49eeff70,$288b99fc + dc.l $00000010,$78023d7c,$0000ff7c,$44fc0000 + dc.l $48eeffff,$ff804c34,$34024f37,$00000010 + dc.l $00000010,$42eeff7e,$48eeffff,$ffc02d7c + dc.l $00000004,$ff8c61ff,$00000ada,$4a0066ff + dc.l $00000b00,$52aeff78,$4cfb3fff,$01700000 + dc.l $0afc4282,$760247ee,$ff5449ee,$ff70288b + dc.l $78023d7c,$0000ff7c,$44fc0000,$48eeffff + dc.l $ff804c34,$34020753,$00000020,$42eeff7e + dc.l $48eeffff,$ffc02d7c,$00000004,$ff8c61ff + dc.l $00000a82,$4a0066ff,$00000aa8,$52aeff78 + dc.l $4cfb3fff,$01700000,$0aa4204f,$42827602 + dc.l $47eeff54,$4feeff70,$2e8b7820,$3d7c0000 + dc.l $ff7c44fc,$000048ee,$ffffff80,$4c373402 + dc.l $491542ee,$ff7e48ee,$ffffffc0,$2d7c0000 + dc.l $0004ff8c,$2e4861ff,$00000a2a,$4a0066ff + dc.l $00000a50,$52aeff78,$52aeff78,$4cfb3fff + dc.l $01700000,$0a48224e,$42827602,$47e9ff74 + dc.l $4de9ff70,$2c8bddfc,$00000010,$2a7cffff + dc.l $fffe337c,$0000ff7c,$44fc0000,$48e9ffff + dc.l $ff804c36,$3402df27,$fff00000,$001042e9 + dc.l $ff7e48e9,$ffffffc0,$237c0000,$0004ff8c + dc.l $2c4961ff,$000009be,$4a0066ff,$000009e4 + dc.l $222eff78,$42804e75,$52aeff78,$4cfb3fff + dc.l $01700000,$09d84282,$760247fa,$ef7449fa + dc.l $ff70288b,$78f03d7c,$0000ff7c,$44fc0000 + dc.l $48eeffff,$ff804c3b,$34024122,$ff801000 + dc.l $42eeff7e,$48eeffff,$ffc02d7c,$00000004 + dc.l $ff8c61ff,$0000095e,$4a0066ff,$00000984 + dc.l $52aeff78,$4cfb3fff,$01700000,$09804282 + dc.l $760247fa,$ef7449fa,$ff70288b,$78f83d7c + dc.l $0000ff7c,$44fc0000,$48eeffff,$ff804c3b + dc.l $34024322,$ff801000,$42eeff7e,$48eeffff + dc.l $ffc02d7c,$00000004,$ff8c61ff,$00000906 + dc.l $4a0066ff,$0000092c,$52aeff78,$4cfb3fff + dc.l $01700000,$09284282,$760247fa,$ef7449fa + dc.l $ff70288b,$78fc3d7c,$0000ff7c,$44fc0000 + dc.l $48eeffff,$ff804c3b,$34024522,$ff801000 + dc.l $42eeff7e,$48eeffff,$ffc02d7c,$00000004 + dc.l $ff8c61ff,$000008ae,$4a0066ff,$000008d4 + dc.l $52aeff78,$4cfb3fff,$01700000,$08d04282 + dc.l $760247fa,$ef7449fa,$ff70288b,$78fe3d7c + dc.l $0000ff7c,$44fc0000,$48eeffff,$ff804c3b + dc.l $34024722,$ff801000,$42eeff7e,$48eeffff + dc.l $ffc02d7c,$00000004,$ff8c61ff,$00000856 + dc.l $4a0066ff,$0000087c,$52aeff78,$4cfb3fff + dc.l $01700000,$08784282,$760247fa,$ef7449fa + dc.l $ff70288b,$78f03d7c,$0000ff7c,$44fc0000 + dc.l $48eeffff,$ff804c3b,$34024922,$ff801000 + dc.l $42eeff7e,$48eeffff,$ffc02d7c,$00000004 + dc.l $ff8c61ff,$000007fe,$4a0066ff,$00000824 + dc.l $52aeff78,$4cfb3fff,$01700000,$08204282 + dc.l $760247fa,$ef7449fa,$ff70288b,$78f83d7c + dc.l $0000ff7c,$44fc0000,$48eeffff,$ff804c3b + dc.l $34024b22,$ff801000,$42eeff7e,$48eeffff + dc.l $ffc02d7c,$00000004,$ff8c61ff,$000007a6 + dc.l $4a0066ff,$000007cc,$52aeff78,$4cfb3fff + dc.l $01700000,$07c84282,$760247fa,$ef7449fa + dc.l $ff70288b,$78fc3d7c,$0000ff7c,$44fc0000 + dc.l $48eeffff,$ff804c3b,$34024d22,$ff801000 + dc.l $42eeff7e,$48eeffff,$ffc02d7c,$00000004 + dc.l $ff8c61ff,$0000074e,$4a0066ff,$00000774 + dc.l $52aeff78,$4cfb3fff,$01700000,$07704282 + dc.l $760247fa,$ef7449fa,$ff70288b,$78fe3d7c + dc.l $0000ff7c,$44fc0000,$48eeffff,$ff804c3b + dc.l $34024f22,$ff801000,$42eeff7e,$48eeffff + dc.l $ffc02d7c,$00000004,$ff8c61ff,$000006f6 + dc.l $4a0066ff,$0000071c,$52aeff78,$4cfb3fff + dc.l $01700000,$07184282,$760247fa,$ef7449fa + dc.l $ff70288b,$78fe3d7c,$0000ff7c,$44fc0000 + dc.l $48eeffff,$ff804c3b,$34024f33,$ffffff80 + dc.l $00001000,$42eeff7e,$48eeffff,$ffc02d7c + dc.l $00000004,$ff8c61ff,$0000069a,$4a0066ff + dc.l $000006c0,$52aeff78,$4cfb3fff,$01700000 + dc.l $06bc4282,$760247fa,$ef7449fa,$ff70288b + dc.l $78fe3d7c,$0000ff7c,$44fc0000,$48eeffff + dc.l $ff804c3b,$34020773,$ffffff70,$00001000 + dc.l $42eeff7e,$48eeffff,$ffc02d7c,$00000004 + dc.l $ff8c61ff,$0000063e,$4a0066ff,$00000664 + dc.l $52aeff78,$4cfb3fff,$01700000,$06604282 + dc.l $760247fa,$ef7449fa,$ff70288b,$280c3d7c + dc.l $0000ff7c,$44fc0000,$48eeffff,$ff804c30 + dc.l $34024993,$00001000,$42eeff7e,$48eeffff + dc.l $ffc02d7c,$00000004,$ff8c61ff,$000005e6 + dc.l $4a0066ff,$0000060c,$52aeff78,$4cfb3fff + dc.l $01700000,$06084282,$760247fa,$ef7449fa + dc.l $ff70288b,$78f0d88c,$3d7c0000,$ff7c44fc + dc.l $000048ee,$ffffff80,$4c303402,$49b30000 + dc.l $00100000,$100042ee,$ff7e48ee,$ffffffc0 + dc.l $2d7c0000,$0004ff8c,$61ff0000,$05884a00 + dc.l $66ff0000,$05ae52ae,$ff784282,$760247fa + dc.l $ff7449fa,$ff70288b,$78f03d7c,$0000ff7c + dc.l $44fc0000,$48eeffff,$ff804c30,$340201f1 + dc.l $ffffff70,$42eeff7e,$48eeffff,$ffc02d7c + dc.l $00000004,$ff8c61ff,$0000053a,$4a0066ff + dc.l $00000560,$52aeff78,$4cfb3fff,$01700000 + dc.l $055c4282,$760247fa,$0f7449fa,$ff70288b + dc.l $2c7c0000,$00023d7c,$0000ff7c,$44fc0000 + dc.l $48eeffff,$ff804c3b,$3402ef22,$ff60f000 + dc.l $42eeff7e,$48eeffff,$ffc02d7c,$00000004 + dc.l $ff8c61ff,$000004de,$4a0066ff,$00000504 + dc.l $52aeff78,$4cfb3fff,$01700000,$0500204f + dc.l $42827602,$47fa0f74,$49faff70,$288b2e7c + dc.l $00000002,$3d7c0000,$ff7c44fc,$000048ee + dc.l $ffffff80,$4c3b3402,$ff22ff60,$f00042ee + dc.l $ff7e48ee,$ffffffc0,$2d7c0000,$0004ff8c + dc.l $2e4861ff,$0000047e,$4a0066ff,$000004a4 + dc.l $52aeff78,$4cfb3fff,$01700000,$04a04282 + dc.l $760247fa,$ff5449fa,$ff70288b,$99fc0000 + dc.l $00107810,$3d7c0000,$ff7c44fc,$000048ee + dc.l $ffffff80,$4c3b3402,$4126ff70,$001042ee + dc.l $ff7e48ee,$ffffffc0,$2d7c0000,$0004ff8c + dc.l $61ff0000,$04204a00,$66ff0000,$044652ae + dc.l $ff784cfb,$3fff0170,$00000442,$42827602 + dc.l $47faff54,$49faff70,$288b99fc,$00000010 + dc.l $78083d7c,$0000ff7c,$44fc0000,$48eeffff + dc.l $ff804c3b,$34024326,$ff700010,$42eeff7e + dc.l $48eeffff,$ffc02d7c,$00000004,$ff8c61ff + dc.l $000003c2,$4a0066ff,$000003e8,$52aeff78 + dc.l $4cfb3fff,$01700000,$03e44282,$760247fa + dc.l $ff5449fa,$ff70288b,$99fc0000,$00107804 + dc.l $3d7c0000,$ff7c44fc,$000048ee,$ffffff80 + dc.l $4c3b3402,$4526ff70,$001042ee,$ff7e48ee + dc.l $ffffffc0,$2d7c0000,$0004ff8c,$61ff0000 + dc.l $03644a00,$66ff0000,$038a52ae,$ff784cfb + dc.l $3fff0170,$00000386,$42827602,$47faff54 + dc.l $49faff70,$288b99fc,$00000010,$78023d7c + dc.l $0000ff7c,$44fc0000,$48eeffff,$ff804c3b + dc.l $34024726,$ff700010,$42eeff7e,$48eeffff + dc.l $ffc02d7c,$00000004,$ff8c61ff,$00000306 + dc.l $4a0066ff,$0000032c,$52aeff78,$4cfb3fff + dc.l $01700000,$03284282,$760247fa,$ff5449fa + dc.l $ff70288b,$99fc0000,$00107810,$3d7c0000 + dc.l $ff7c44fc,$000048ee,$ffffff80,$4c3b3402 + dc.l $4926ff70,$001042ee,$ff7e48ee,$ffffffc0 + dc.l $2d7c0000,$0004ff8c,$61ff0000,$02a84a00 + dc.l $66ff0000,$02ce52ae,$ff784cfb,$3fff0170 + dc.l $000002ca,$42827602,$47faff54,$49faff70 + dc.l $288b99fc,$00000010,$78083d7c,$0000ff7c + dc.l $44fc0000,$48eeffff,$ff804c3b,$34024326 + dc.l $ff700010,$42eeff7e,$48eeffff,$ffc02d7c + dc.l $00000004,$ff8c61ff,$0000024a,$4a0066ff + dc.l $00000270,$52aeff78,$4cfb3fff,$01700000 + dc.l $026c4282,$760247fa,$ff5449fa,$ff70288b + dc.l $99fc0000,$00107804,$3d7c0000,$ff7c44fc + dc.l $000048ee,$ffffff80,$4c3b3402,$4d26ff70 + dc.l $001042ee,$ff7e48ee,$ffffffc0,$2d7c0000 + dc.l $0004ff8c,$61ff0000,$01ec4a00,$66ff0000 + dc.l $021252ae,$ff784cfb,$3fff0170,$0000020e + dc.l $42827602,$47faff54,$49faff70,$288b99fc + dc.l $00000010,$78023d7c,$0000ff7c,$44fc0000 + dc.l $48eeffff,$ff804c3b,$34024f26,$ff700010 + dc.l $42eeff7e,$48eeffff,$ffc02d7c,$00000004 + dc.l $ff8c61ff,$0000018e,$4a0066ff,$000001b4 + dc.l $52aeff78,$4cfb3fff,$01700000,$01b04282 + dc.l $760247fa,$ff5449fa,$ff70288b,$99fc0000 + dc.l $00107802,$3d7c0000,$ff7c44fc,$000048ee + dc.l $ffffff80,$4c3b3402,$4f37ffff,$ff700000 + dc.l $001042ee,$ff7e48ee,$ffffffc0,$2d7c0000 + dc.l $0004ff8c,$61ff0000,$012c4a00,$66ff0000 + dc.l $015252ae,$ff784cfb,$3fff0170,$0000014e + dc.l $42827602,$47faff54,$49faff70,$288b7802 + dc.l $3d7c0000,$ff7c44fc,$000048ee,$ffffff80 + dc.l $4c3b3402,$0773ffff,$ff700000,$002042ee + dc.l $ff7e48ee,$ffffffc0,$2d7c0000,$0004ff8c + dc.l $61ff0000,$00d04a00,$66ff0000,$00f652ae + dc.l $ff784cfb,$3fff0170,$000000f2,$42827602 + dc.l $47faff54,$49faff70,$288b7804,$3d7c0000 + dc.l $ff7c44fc,$000048ee,$ffffff80,$4c303402 + dc.l $4fb5ffff,$ff7042ee,$ff7e48ee,$ffffffc0 + dc.l $2d7c0000,$0004ff8c,$61ff0000,$00784a00 + dc.l $66ff0000,$009e52ae,$ff784cfb,$3fff0170 + dc.l $0000009a,$204f4282,$760247fa,$ff744dfa + dc.l $ff702c8b,$ddfc0000,$00102e7c,$fffffffe + dc.l $3d7c0000,$ff7c44fc,$000048ee,$ffffff80 + dc.l $4c3b3402,$ff27ff70,$00000010,$42eeff7e + dc.l $48eeffff,$ffc02d7c,$00000004,$ff8c2e48 + dc.l $61ff0000,$00104a00,$66ff0000,$00364280 + dc.l $4e7541ee,$ff8043ee,$ffc0700e,$b18966ff + dc.l $0000001c,$51c8fff6,$302eff7c,$322eff7e + dc.l $b04166ff,$00000008,$42804e75,$70014e75 + dc.l $222eff78,$70014e75,$acacacac,$acacacac + dc.l $acacacac,$acacacac,$acacacac,$acacacac + dc.l $acacacac,$acacacac,$acacacac,$acacacac + dc.l $acacacac,$acacacac,$acacacac,$acacacac + dc.l $acacacac,$acacacac,$2f00203a,$afa4487b + dc.l $0930ffff,$afa0202f,$00044e74,$00042f00 + dc.l $203aaf92,$487b0930,$ffffaf8a,$202f0004 + dc.l $4e740004,$00000000,$00000000,$00000000 diff -u --recursive --new-file v1.3.93/linux/arch/m68k/ifpsp060/os.S linux/arch/m68k/ifpsp060/os.S --- v1.3.93/linux/arch/m68k/ifpsp060/os.S Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/ifpsp060/os.S Sun Feb 18 19:33:51 1996 @@ -0,0 +1,432 @@ +|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +|MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP +|M68000 Hi-Performance Microprocessor Division +|M68060 Software Package +|Production Release P1.00 -- October 10, 1994 +| +|M68060 Software Package Copyright © 1993, 1994 Motorola Inc. All rights reserved. +| +|THE SOFTWARE is provided on an "AS IS" basis and without warranty. +|To the maximum extent permitted by applicable law, +|MOTOROLA DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED, +|INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE +|and any warranty against infringement with regard to the SOFTWARE +|(INCLUDING ANY MODIFIED VERSIONS THEREOF) and any accompanying written materials. +| +|To the maximum extent permitted by applicable law, +|IN NO EVENT SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER +|(INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, +|BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY LOSS) +|ARISING OF THE USE OR INABILITY TO USE THE SOFTWARE. +|Motorola assumes no responsibility for the maintenance and support of the SOFTWARE. +| +|You are hereby granted a copyright license to use, modify, and distribute the SOFTWARE +|so long as this entire notice is retained without alteration in any modified and/or +|redistributed versions, and that such modified versions are clearly identified as such. +|No licenses are granted by implication, estoppel or otherwise under any patents +|or trademarks of Motorola, Inc. +|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +| os.s +| +| This file contains: +| - example "Call-Out"s required by both the ISP and FPSP. +| + + +|################################ +| EXAMPLE CALL-OUTS # +| # +| _060_dmem_write() # +| _060_dmem_read() # +| _060_imem_read() # +| _060_dmem_read_byte() # +| _060_dmem_read_word() # +| _060_dmem_read_long() # +| _060_imem_read_word() # +| _060_imem_read_long() # +| _060_dmem_write_byte() # +| _060_dmem_write_word() # +| _060_dmem_write_long() # +| # +| _060_real_trace() # +| _060_real_access() # +|################################ + +| +| Each IO routine checks to see if the memory write/read is to/from user +| or supervisor application space. The examples below use simple "move" +| instructions for supervisor mode applications and call _copyin()/_copyout() +| for user mode applications. +| When installing the 060SP, the _copyin()/_copyout() equivalents for a +| given operating system should be substituted. +| +| The addresses within the 060SP are guaranteed to be on the stack. +| The result is that Unix processes are allowed to sleep as a consequence +| of a page fault during a _copyout. +| + +| +| _060_dmem_write(): +| +| Writes to data memory while in supervisor mode. +| +| INPUTS: +| a0 - supervisor source address +| a1 - user destination address +| d0 - number of bytes to write +| 0x4(%a6),bit5 - 1 = supervisor mode, 0 = user mode +| OUTPUTS: +| d1 - 0 = success, !0 = failure +| + .global _060_dmem_write +_060_dmem_write: + btst #0x5,0x4(%a6) | check for supervisor state + beqs user_write +super_write: + move.b (%a0)+,(%a1)+ | copy 1 byte + subq.l #0x1,%d0 | decr byte counter + bnes super_write | quit if ctr = 0 + clr.l %d1 | return success + rts +user_write: + move.l %d0,-(%sp) | pass: counter + move.l %a1,-(%sp) | pass: user dst + move.l %a0,-(%sp) | pass: supervisor src + bsr.l _copyout | write byte to user mem + move.l %d0,%d1 | return success + add.l #0xc, %sp | clear 3 lw params + rts + +| +| _060_imem_read(), _060_dmem_read(): +| +| Reads from data/instruction memory while in supervisor mode. +| +| INPUTS: +| a0 - user source address +| a1 - supervisor destination address +| d0 - number of bytes to read +| 0x4(%a6),bit5 - 1 = supervisor mode, 0 = user mode +| OUTPUTS: +| d1 - 0 = success, !0 = failure +| + .global _060_imem_read + .global _060_dmem_read +_060_imem_read: +_060_dmem_read: + btst #0x5,0x4(%a6) | check for supervisor state + beqs user_read +super_read: + move.b (%a0)+,(%a1)+ | copy 1 byte + subq.l #0x1,%d0 | decr byte counter + bnes super_read | quit if ctr = 0 + clr.l %d1 | return success + rts +user_read: + move.l %d0,-(%sp) | pass: counter + move.l %a1,-(%sp) | pass: super dst + move.l %a0,-(%sp) | pass: user src + bsr.l _copyin | read byte from user mem + move.l %d0,%d1 | return success + add.l #0xc,%sp | clear 3 lw params + rts + +| +| _060_dmem_read_byte(): +| +| Read a data byte from user memory. +| +| INPUTS: +| a0 - user source address +| 0x4(%a6),bit5 - 1 = supervisor mode, 0 = user mode +| OUTPUTS: +| d0 - data byte in d0 +| d1 - 0 = success, !0 = failure +| + .global _060_dmem_read_byte +_060_dmem_read_byte: + btst #0x5,0x4(%a6) | check for supervisor state + bnes dmrbs | supervisor +dmrbu: clr.l -(%sp) | clear space on stack for result + move.l #0x1,-(%sp) | pass: # bytes to copy + pea 0x7(%sp) | pass: dst addr (stack) + move.l %a0,-(%sp) | pass: src addr (user mem) + bsr.l _copyin | "copy in" the data + move.l %d0,%d1 | return success + add.l #0xc,%sp | delete params + move.l (%sp)+,%d0 | put answer in d0 + rts +dmrbs: clr.l %d0 | clear whole longword + move.b (%a0),%d0 | fetch super byte + clr.l %d1 | return success + rts + +| +| _060_dmem_read_word(): +| +| Read a data word from user memory. +| +| INPUTS: +| a0 - user source address +| 0x4(%a6),bit5 - 1 = supervisor mode, 0 = user mode +| OUTPUTS: +| d0 - data word in d0 +| d1 - 0 = success, !0 = failure +| + .global _060_dmem_read_word +_060_dmem_read_word: + btst #0x5,0x4(%a6) | check for supervisor state + bnes dmrws | supervisor +dmrwu: clr.l -(%sp) | clear space on stack for result + move.l #0x2,-(%sp) | pass: # bytes to copy + pea 0x6(%sp) | pass: dst addr (stack) + move.l %a0,-(%sp) | pass: src addr (user mem) + bsr.l _copyin | "copy in" the data + move.l %d0,%d1 | return success + add.l #0xc,%sp | delete params + move.l (%sp)+,%d0 | put answer in d0 + rts +dmrws: clr.l %d0 | clear whole longword + move.w (%a0), %d0 | fetch super word + clr.l %d1 | return success + rts + +| +| _060_dmem_read_long(): +| + +| +| INPUTS: +| a0 - user source address +| 0x4(%a6),bit5 - 1 = supervisor mode, 0 = user mode +| OUTPUTS: +| d0 - data longword in d0 +| d1 - 0 = success, !0 = failure +| + .global _060_dmem_read_long +_060_dmem_read_long: + btst #0x5,0x4(%a6) | check for supervisor state + bnes dmrls | supervisor +dmrlu: subq.l #0x4,%sp | clear space on stack for result + move.l #0x4,-(%sp) | pass: # bytes to copy + pea 0x4(%sp) | pass: dst addr (stack) + move.l %a0,-(%sp) | pass: src addr (user mem) + bsr.l _copyin | "copy in" the data + move.l %d0,%d1 | return success + add.l #0xc,%sp | delete params + move.l (%sp)+,%d0 | put answer in d0 + rts +dmrls: move.l (%a0),%d0 | fetch super longword + clr.l %d1 | return success + rts + +| +| _060_dmem_write_byte(): +| +| Write a data byte to user memory. +| +| INPUTS: +| a0 - user destination address +| d0 - data byte in d0 +| 0x4(%a6),bit5 - 1 = supervisor mode, 0 = user mode +| OUTPUTS: +| d1 - 0 = success, !0 = failure +| + .global _060_dmem_write_byte +_060_dmem_write_byte: + btst #0x5,0x4(%a6) | check for supervisor state + bnes dmwbs | supervisor +dmwbu: move.l %d0,-(%sp) | put src on stack + move.l #0x1,-(%sp) | pass: # bytes to copy + move.l %a0,-(%sp) | pass: dst addr (user mem) + pea 0xb(%sp) | pass: src addr (stack) + bsr.l _copyout | "copy out" the data + move.l %d0,%d1 | return success + add.l #0x10,%sp | delete params + src + rts +dmwbs: move.b %d0,(%a0) | store super byte + clr.l %d1 | return success + rts + +| +| _060_dmem_write_word(): +| +| Write a data word to user memory. +| +| INPUTS: +| a0 - user destination address +| d0 - data word in d0 +| 0x4(%a6),bit5 - 1 = supervisor mode, 0 = user mode +| OUTPUTS: +| d1 - 0 = success, !0 = failure +| + .global _060_dmem_write_word +_060_dmem_write_word: + btst #0x5,0x4(%a6) | check for supervisor state + bnes dmwws | supervisor +dmwwu: move.l %d0,-(%sp) | put src on stack + move.l #0x2,-(%sp) | pass: # bytes to copy + move.l %a0,-(%sp) | pass: dst addr (user mem) + pea 0xa(%sp) | pass: src addr (stack) + bsr.l _copyout | "copy out" the data + move.l %d0,%d1 | return success + add.l #0x10,%sp | delete params + src + rts +dmwws: move.w %d0,(%a0) | store super word + clr.l %d1 | return success + rts + +| +| _060_dmem_write_long(): +| +| Write a data longword to user memory. +| +| INPUTS: +| a0 - user destination address +| d0 - data longword in d0 +| 0x4(%a6),bit5 - 1 = supervisor mode, 0 = user mode +| OUTPUTS: +| d1 - 0 = success, !0 = failure +| + .global _060_dmem_write_long +_060_dmem_write_long: + btst #0x5,0x4(%a6) | check for supervisor state + bnes dmwls | supervisor +dmwlu: move.l %d0,-(%sp) | put src on stack + move.l #0x4,-(%sp) | pass: # bytes to copy + move.l %a0,-(%sp) | pass: dst addr (user mem) + pea 0x8(%sp) | pass: src addr (stack) + bsr.l _copyout | "copy out" the data + move.l %d0,%d1 | return success + add.l #0x10,%sp | delete params + src + rts +dmwls: move.l %d0,(%a0) | store super longword + clr.l %d1 | return success + rts + +| +| _060_imem_read_word(): +| +| Read an instruction word from user memory. +| +| INPUTS: +| a0 - user source address +| 0x4(%a6),bit5 - 1 = supervisor mode, 0 = user mode +| OUTPUTS: +| d0 - instruction word in d0 +| d1 - 0 = success, !0 = failure +| + .global _060_imem_read_word +_060_imem_read_word: + btst #0x5,0x4(%a6) | check for supervisor state + bnes imrws | supervisor +imrwu: clr.l -(%sp) | clear space on stack for result + move.l #0x2,-(%sp) | pass: # bytes to copy + pea 0x6(%sp) | pass: dst addr (stack) + move.l %a0,-(%sp) | pass: src addr (user mem) + bsr.l _copyin | "copy in" the data + move.l %d0,%d1 | return success + add.l #0xc,%sp | delete params + move.l (%sp)+,%d0 | put answer in d0 + rts +imrws: move.w (%a0),%d0 | fetch super word + clr.l %d1 | return success + rts + +| +| _060_imem_read_long(): +| +| Read an instruction longword from user memory. +| +| INPUTS: +| a0 - user source address +| 0x4(%a6),bit5 - 1 = supervisor mode, 0 = user mode +| OUTPUTS: +| d0 - instruction longword in d0 +| d1 - 0 = success, !0 = failure +| + .global _060_imem_read_long +_060_imem_read_long: + btst #0x5,0x4(%a6) | check for supervisor state + bnes imrls | supervisor +imrlu: subq.l #0x4,%sp | clear space on stack for result + move.l #0x4,-(%sp) | pass: # bytes to copy + pea 0x4(%sp) | pass: dst addr (stack) + move.l %a0,-(%sp) | pass: src addr (user mem) + bsr.l _copyin | "copy in" the data + move.l %d0,%d1 | return success + add.l #0xc,%sp | delete params + move.l (%sp)+,%d0 | put answer in d0 + rts +imrls: move.l (%a0),%d0 | fetch super longword + clr.l %d1 | return success + rts + +|############################################### + +| +| Use these routines if your kernel doesn't have _copyout/_copyin equivalents. +| Assumes that D0/D1/A0/A1 are scratch registers. The _copyin/_copyout +| below assume that the SFC/DFC have been set previously. +| + +| +| int _copyout(supervisor_addr, user_addr, nbytes) +| + .global _copyout +_copyout: + move.l 4(%sp),%a0 | source + move.l 8(%sp),%a1 | destination + move.l 12(%sp),%d0 | count +moreout: + move.b (%a0)+,%d1 | fetch supervisor byte + movs.b %d1,(%a1)+ | store user byte + subq.l #0x1,%d0 | are we through yet? + bne moreout | no; so, continue + rts + +| +| int _copyin(user_addr, supervisor_addr, nbytes) +| + .global _copyin +_copyin: + move.l 4(%sp),%a0 | source + move.l 8(%sp),%a1 | destination + move.l 12(%sp),%d0 | count +morein: + movs.b (%a0)+,%d1 | fetch user byte + move.b %d1,(%a1)+ | write supervisor byte + subq.l #0x1,%d0 | are we through yet? + bne morein | no; so, continue + rts + +|########################################################################### + +| +| _060_real_trace(): +| +| This is the exit point for the 060FPSP when an instruction is being traced +| and there are no other higher priority exceptions pending for this instruction +| or they have already been processed. +| +| The sample code below simply executes an "rte". +| + .global _060_real_trace +_060_real_trace: + rte + +| +| _060_real_access(): +| +| This is the exit point for the 060FPSP when an access error exception +| is encountered. The routine below should point to the operating system +| handler for access error exceptions. The exception stack frame is an +| 8-word access error frame. +| +| The sample routine below simply executes an "rte" instruction which +| is most likely the incorrect thing to do and could put the system +| into an infinite loop. +| + .global _060_real_access +_060_real_access: + rte diff -u --recursive --new-file v1.3.93/linux/arch/m68k/ifpsp060/pfpsp.sa linux/arch/m68k/ifpsp060/pfpsp.sa --- v1.3.93/linux/arch/m68k/ifpsp060/pfpsp.sa Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/ifpsp060/pfpsp.sa Mon Jan 8 22:08:22 1996 @@ -0,0 +1,1730 @@ + dc.l $60ff0000,$17400000,$60ff0000,$15f40000 + dc.l $60ff0000,$02b60000,$60ff0000,$04700000 + dc.l $60ff0000,$1b100000,$60ff0000,$19aa0000 + dc.l $60ff0000,$1b5a0000,$60ff0000,$062e0000 + dc.l $60ff0000,$102c0000,$51fc51fc,$51fc51fc + dc.l $51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc + dc.l $51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc + dc.l $51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc + dc.l $2f00203a,$ff2c487b,$0930ffff,$fef8202f + dc.l $00044e74,$00042f00,$203afef2,$487b0930 + dc.l $fffffee2,$202f0004,$4e740004,$2f00203a + dc.l $fee0487b,$0930ffff,$fecc202f,$00044e74 + dc.l $00042f00,$203afed2,$487b0930,$fffffeb6 + dc.l $202f0004,$4e740004,$2f00203a,$fea4487b + dc.l $0930ffff,$fea0202f,$00044e74,$00042f00 + dc.l $203afe96,$487b0930,$fffffe8a,$202f0004 + dc.l $4e740004,$2f00203a,$fe7c487b,$0930ffff + dc.l $fe74202f,$00044e74,$00042f00,$203afe76 + dc.l $487b0930,$fffffe5e,$202f0004,$4e740004 + dc.l $2f00203a,$fe68487b,$0930ffff,$fe48202f + dc.l $00044e74,$00042f00,$203afe56,$487b0930 + dc.l $fffffe32,$202f0004,$4e740004,$2f00203a + dc.l $fe44487b,$0930ffff,$fe1c202f,$00044e74 + dc.l $00042f00,$203afe32,$487b0930,$fffffe06 + dc.l $202f0004,$4e740004,$2f00203a,$fe20487b + dc.l $0930ffff,$fdf0202f,$00044e74,$00042f00 + dc.l $203afe1e,$487b0930,$fffffdda,$202f0004 + dc.l $4e740004,$2f00203a,$fe0c487b,$0930ffff + dc.l $fdc4202f,$00044e74,$00042f00,$203afdfa + dc.l $487b0930,$fffffdae,$202f0004,$4e740004 + dc.l $2f00203a,$fde8487b,$0930ffff,$fd98202f + dc.l $00044e74,$00042f00,$203afdd6,$487b0930 + dc.l $fffffd82,$202f0004,$4e740004,$2f00203a + dc.l $fdc4487b,$0930ffff,$fd6c202f,$00044e74 + dc.l $00042f00,$203afdb2,$487b0930,$fffffd56 + dc.l $202f0004,$4e740004,$2f00203a,$fda0487b + dc.l $0930ffff,$fd40202f,$00044e74,$00042f00 + dc.l $203afd8e,$487b0930,$fffffd2a,$202f0004 + dc.l $4e740004,$2f00203a,$fd7c487b,$0930ffff + dc.l $fd14202f,$00044e74,$00042f00,$203afd6a + dc.l $487b0930,$fffffcfe,$202f0004,$4e740004 + dc.l $40c62d38,$d3d64634,$3d6f90ae,$b1e75cc7 + dc.l $40000000,$c90fdaa2,$2168c235,$00000000 + dc.l $3fff0000,$c90fdaa2,$2168c235,$00000000 + dc.l $3fe45f30,$6dc9c883,$4e56ff40,$f32eff6c + dc.l $48ee0303,$ff9cf22e,$bc00ff60,$f22ef0c0 + dc.l $ffdc2d6e,$ff68ff44,$206eff44,$58aeff44 + dc.l $61ffffff,$ff042d40,$ff40082e,$0005ff42 + dc.l $66000116,$41eeff6c,$61ff0000,$051c41ee + dc.l $ff6c61ff,$00002aec,$1d40ff4e,$082e0005 + dc.l $ff436726,$e9ee0183,$ff4261ff,$00005cac + dc.l $41eeff78,$61ff0000,$2aca0c00,$00066606 + dc.l $61ff0000,$2a2e1d40,$ff4f4280,$102eff63 + dc.l $122eff43,$0241007f,$02ae00ff,$01ffff64 + dc.l $f23c9000,$00000000,$f23c8800,$00000000 + dc.l $41eeff6c,$43eeff78,$223b1530,$00001974 + dc.l $4ebb1930,$0000196c,$e9ee0183,$ff4261ff + dc.l $00005cd8,$082e0004,$ff626622,$082e0001 + dc.l $ff626644,$f22ed0c0,$ffdcf22e,$9c00ff60 + dc.l $4cee0303,$ff9c4e5e,$60ffffff,$fcc6f22e + dc.l $f040ff6c,$3d7ce005,$ff6ef22e,$d0c0ffdc + dc.l $f22e9c00,$ff604cee,$0303ff9c,$f36eff6c + dc.l $4e5e60ff,$fffffcb2,$f22ef040,$ff6c1d7c + dc.l $00c4000b,$3d7ce001,$ff6ef22e,$d0c0ffdc + dc.l $f22e9c00,$ff604cee,$0303ff9c,$f36eff6c + dc.l $4e5e60ff,$fffffcae,$1d7c0000,$ff4e4280 + dc.l $102eff63,$02aeffff,$00ffff64,$f23c9000 + dc.l $00000000,$f23c8800,$00000000,$41eeff6c + dc.l $61ff0000,$2e0c082e,$0004ff62,$6600ff70 + dc.l $082e0001,$ff626600,$ff90f22e,$d0c0ffdc + dc.l $f22e9c00,$ff604cee,$0303ff9c,$4e5e0817 + dc.l $000767ff,$fffffc0c,$f22fa400,$00083f7c + dc.l $20240006,$60ffffff,$fcec4e56,$ff40f32e + dc.l $ff6c48ee,$0303ff9c,$f22ebc00,$ff60f22e + dc.l $f0c0ffdc,$2d6eff68,$ff44206e,$ff4458ae + dc.l $ff4461ff,$fffffd42,$2d40ff40,$082e0005 + dc.l $ff426600,$013241ee,$ff6c61ff,$0000035a + dc.l $41eeff6c,$61ff0000,$292a1d40,$ff4e082e + dc.l $0005ff43,$672e082e,$0004ff43,$6626e9ee + dc.l $0183ff42,$61ff0000,$5ae241ee,$ff7861ff + dc.l $00002900,$0c000006,$660661ff,$00002864 + dc.l $1d40ff4f,$4280102e,$ff63122e,$ff430241 + dc.l $007f02ae,$00ff01ff,$ff64f23c,$90000000 + dc.l $0000f23c,$88000000,$000041ee,$ff6c43ee + dc.l $ff78223b,$15300000,$17aa4ebb,$19300000 + dc.l $17a2e9ee,$0183ff42,$61ff0000,$5b0e082e + dc.l $0003ff62,$6622082e,$0001ff62,$664ef22e + dc.l $d0c0ffdc,$f22e9c00,$ff604cee,$0303ff9c + dc.l $4e5e60ff,$fffffafc,$082e0003,$ff666700 + dc.l $ffd6f22e,$f040ff6c,$3d7ce003,$ff6ef22e + dc.l $d0c0ffdc,$f22e9c00,$ff604cee,$0303ff9c + dc.l $f36eff6c,$4e5e60ff,$fffffaf4,$082e0001 + dc.l $ff666700,$ffaaf22e,$f040ff6c,$1d7c00c4 + dc.l $000b3d7c,$e001ff6e,$f22ed0c0,$ffdcf22e + dc.l $9c00ff60,$4cee0303,$ff9cf36e,$ff6c4e5e + dc.l $60ffffff,$fad01d7c,$0000ff4e,$4280102e + dc.l $ff6302ae,$ffff00ff,$ff64f23c,$90000000 + dc.l $0000f23c,$88000000,$000041ee,$ff6c61ff + dc.l $00002c2e,$082e0003,$ff626600,$ff66082e + dc.l $0001ff62,$6600ff90,$f22ed0c0,$ffdcf22e + dc.l $9c00ff60,$4cee0303,$ff9c4e5e,$08170007 + dc.l $67ffffff,$fa2ef22f,$a4000008,$3f7c2024 + dc.l $000660ff,$fffffb0e,$4e56ff40,$f32eff6c + dc.l $48ee0303,$ff9cf22e,$bc00ff60,$f22ef0c0 + dc.l $ffdc082e,$00050004,$66084e68,$2d48ffd8 + dc.l $600841ee,$00102d48,$ffd82d6e,$ff68ff44 + dc.l $206eff44,$58aeff44,$61ffffff,$fb4c2d40 + dc.l $ff40422e,$ff4a082e,$0005ff42,$66000208 + dc.l $e9ee0006,$ff420c00,$00136700,$049e02ae + dc.l $00ff00ff,$ff64f23c,$90000000,$0000f23c + dc.l $88000000,$000041ee,$ff6c61ff,$0000013a + dc.l $41eeff6c,$61ff0000,$270a0c00,$00066606 + dc.l $61ff0000,$266e1d40,$ff4ee9ee,$0183ff42 + dc.l $082e0005,$ff436728,$0c2e003a,$ff436720 + dc.l $61ff0000,$58b641ee,$ff7861ff,$000026d4 + dc.l $0c000006,$660661ff,$00002638,$1d40ff4f + dc.l $4280102e,$ff63e9ee,$1047ff43,$41eeff6c + dc.l $43eeff78,$223b1d30,$00001598,$4ebb1930 + dc.l $00001590,$102eff62,$6634102e,$ff430200 + dc.l $00380c00,$0038670c,$e9ee0183,$ff4261ff + dc.l $000058e8,$f22ed0c0,$ffdcf22e,$9c00ff60 + dc.l $4cee0303,$ff9c4e5e,$60ffffff,$f8e6c02e + dc.l $ff66edc0,$06086614,$082e0004,$ff6667ba + dc.l $082e0001,$ff6267b2,$60000066,$04800000 + dc.l $00180c00,$00066614,$082e0003,$ff666600 + dc.l $004a082e,$0004ff66,$66000046,$2f0061ff + dc.l $000007e0,$201f3d7b,$0222ff6e,$f22ed0c0 + dc.l $ffdcf22e,$9c00ff60,$4cee0303,$ff9cf36e + dc.l $ff6c4e5e,$60ffffff,$f87ae000,$e006e004 + dc.l $e005e003,$e002e001,$e001303c,$000460bc + dc.l $303c0003,$60b6e9ee,$0006ff42,$0c000011 + dc.l $67080c00,$00156750,$4e753028,$00000240 + dc.l $7fff0c40,$3f806708,$0c40407f,$672c4e75 + dc.l $02a87fff,$ffff0004,$671861ff,$000024cc + dc.l $44400640,$3f810268,$80000000,$81680000 + dc.l $4e750268,$80000000,$4e750228,$007f0004 + dc.l $00687fff,$00004e75,$30280000,$02407fff + dc.l $0c403c00,$67080c40,$43ff67de,$4e7502a8 + dc.l $7fffffff,$00046606,$4aa80008,$67c461ff + dc.l $00002478,$44400640,$3c010268,$80000000 + dc.l $81680000,$4e75e9ee,$00c3ff42,$0c000003 + dc.l $670004a2,$0c000007,$6700049a,$02aeffff + dc.l $00ffff64,$f23c9000,$00000000,$f23c8800 + dc.l $00000000,$302eff6c,$02407fff,$671041ee + dc.l $ff6c61ff,$0000246c,$1d40ff4e,$60061d7c + dc.l $0004ff4e,$4280102e,$ff6341ee,$ff6c2d56 + dc.l $ffd461ff,$0000292a,$102eff62,$66000086 + dc.l $2caeffd4,$082e0005,$00046626,$206effd8 + dc.l $4e60f22e,$d0c0ffdc,$f22e9c00,$ff604cee + dc.l $0303ff9c,$4e5e0817,$0007667a,$60ffffff + dc.l $f7220c2e,$0008ff4a,$66d8f22e,$f080ff6c + dc.l $f22ed0c0,$ffdcf22e,$9c00ff60,$4cee0303 + dc.l $ff9c2c56,$2f6f00c4,$00b82f6f,$00c800bc + dc.l $2f6f002c,$00c42f6f,$003000c8,$2f6f0034 + dc.l $00ccdffc,$000000b8,$08170007,$662860ff + dc.l $fffff6d0,$c02eff66,$edc00608,$662a082e + dc.l $0004ff66,$6700ff6a,$082e0001,$ff626700 + dc.l $ff606000,$01663f7c,$20240006,$f22fa400 + dc.l $000860ff,$fffff78e,$04800000,$0018303b + dc.l $020a4efb,$00064afc,$00080000,$0000003a + dc.l $00640094,$00000140,$0000f22e,$d0c0ffdc + dc.l $f22e9c00,$ff604cee,$0303ff9c,$3d7c30d8 + dc.l $000a3d7c,$e006ff6e,$f36eff6c,$4e5e60ff + dc.l $fffff6d4,$f22ed0c0,$ffdcf22e,$9c00ff60 + dc.l $4cee0303,$ff9c3d7c,$30d0000a,$3d7ce004 + dc.l $ff6ef36e,$ff6c4e5e,$60ffffff,$f694f22e + dc.l $f040ff6c,$f22ed0c0,$ffdcf22e,$9c00ff60 + dc.l $4cee0303,$ff9c3d7c,$30d4000a,$3d7ce005 + dc.l $ff6ef36e,$ff6c4e5e,$60ffffff,$f60c2cae + dc.l $ffd4082e,$00050004,$66000038,$206effd8 + dc.l $4e60f22e,$f040ff6c,$f22ed0c0,$ffdcf22e + dc.l $9c00ff60,$4cee0303,$ff9c3d7c,$30cc000a + dc.l $3d7ce003,$ff6ef36e,$ff6c4e5e,$60ffffff + dc.l $f5de0c2e,$0008ff4a,$66c8f22e,$f080ff6c + dc.l $f22ef040,$ff78f22e,$d0c0ffdc,$f22e9c00 + dc.l $ff604cee,$0303ff9c,$3d7c30cc,$000a3d7c + dc.l $e003ff7a,$f36eff78,$2c562f6f,$00c400b8 + dc.l $2f6f00c8,$00bc2f6f,$00cc00c0,$2f6f002c + dc.l $00c42f6f,$003000c8,$2f6f0034,$00ccdffc + dc.l $000000b8,$60ffffff,$f576f22e,$f040ff6c + dc.l $f22ed0c0,$ffdcf22e,$9c00ff60,$4cee0303 + dc.l $ff9c3d7c,$30c4000a,$3d7ce001,$ff6ef36e + dc.l $ff6c4e5e,$60ffffff,$f55c02ae,$00ff00ff + dc.l $ff64f23c,$90000000,$0000f23c,$88000000 + dc.l $000061ff,$00005548,$41eeff6c,$61ff0000 + dc.l $22721d40,$ff4ee9ee,$0183ff42,$082e0005 + dc.l $ff436728,$0c2e003a,$ff436720,$61ff0000 + dc.l $542a41ee,$ff7861ff,$00002248,$0c000006 + dc.l $660661ff,$000021ac,$1d40ff4f,$4280102e + dc.l $ff63e9ee,$1047ff43,$41eeff6c,$43eeff78 + dc.l $223b1d30,$0000110c,$4ebb1930,$00001104 + dc.l $102eff62,$6600008a,$102eff43,$02000038 + dc.l $0c000038,$670ce9ee,$0183ff42,$61ff0000 + dc.l $545a082e,$00050004,$6600002a,$206effd8 + dc.l $4e60f22e,$d0c0ffdc,$f22e9c00,$ff604cee + dc.l $0303ff9c,$4e5e0817,$00076600,$012660ff + dc.l $fffff440,$082e0002,$ff4a67d6,$f22ed0c0 + dc.l $ffdcf22e,$9c00ff60,$4cee0303,$ff9c4e5e + dc.l $2f6f0004,$00102f6f,$0000000c,$dffc0000 + dc.l $000c0817,$00076600,$00ea60ff,$fffff404 + dc.l $c02eff66,$edc00608,$6618082e,$0004ff66 + dc.l $6700ff66,$082e0001,$ff626700,$ff5c6000 + dc.l $006e0480,$00000018,$0c000006,$6d14082e + dc.l $0003ff66,$66000060,$082e0004,$ff666600 + dc.l $004e082e,$00050004,$66000054,$206effd8 + dc.l $4e603d7b,$022aff6e,$f22ed0c0,$ffdcf22e + dc.l $9c00ff60,$4cee0303,$ff9cf36e,$ff6c4e5e + dc.l $08170007,$6600006c,$60ffffff,$f386e000 + dc.l $e006e004,$e005e003,$e002e001,$e001303c + dc.l $00036000,$ffae303c,$00046000,$ffa6082e + dc.l $0002ff4a,$67ac3d7b,$02d6ff6e,$f22ed0c0 + dc.l $ffdcf22e,$9c00ff60,$4cee0303,$ff9cf36e + dc.l $ff6c4e5e,$2f6f0004,$00102f6f,$0000000c + dc.l $dffc0000,$000c0817,$00076606,$60ffffff + dc.l $f3223f7c,$20240006,$f22fa400,$000860ff + dc.l $fffff402,$02aeffff,$00ffff64,$f23c9000 + dc.l $00000000,$f23c8800,$00000000,$e9ee0183 + dc.l $ff4261ff,$000051b4,$41eeff6c,$61ff0000 + dc.l $20620c00,$00066606,$61ff0000,$1fc61d40 + dc.l $ff4e4280,$102eff63,$41eeff6c,$2d56ffd4 + dc.l $61ff0000,$248c102e,$ff626600,$00842cae + dc.l $ffd4082e,$00050004,$6628206e,$ffd84e60 + dc.l $f22ed0c0,$ffdcf22e,$9c00ff60,$4cee0303 + dc.l $ff9c4e5e,$08170007,$6600ff68,$60ffffff + dc.l $f282082e,$0003ff4a,$67d6f22e,$d0c0ffdc + dc.l $f22e9c00,$ff604cee,$0303ff9c,$2c562f6f + dc.l $00c400b8,$2f6f00c8,$00bc2f6f,$003800c4 + dc.l $2f6f003c,$00c82f6f,$004000cc,$dffc0000 + dc.l $00b80817,$00076600,$ff1a60ff,$fffff234 + dc.l $c02eff66,$edc00608,$6700ff74,$2caeffd4 + dc.l $0c00001a,$6e0000e8,$67000072,$082e0005 + dc.l $0004660a,$206effd8,$4e606000,$fb8e0c2e + dc.l $0008ff4a,$6600fb84,$f22ed0c0,$ffdcf22e + dc.l $9c00ff60,$4cee0303,$ff9c3d7c,$30d8000a + dc.l $3d7ce006,$ff6ef36e,$ff6c2c56,$2f6f00c4 + dc.l $00b82f6f,$00c800bc,$2f6f00cc,$00c02f6f + dc.l $003800c4,$2f6f003c,$00c82f6f,$004000cc + dc.l $dffc0000,$00b860ff,$fffff22c,$082e0005 + dc.l $00046600,$000c206e,$ffd84e60,$6000fb46 + dc.l $0c2e0008,$ff4a6600,$fb3cf22e,$d0c0ffdc + dc.l $f22e9c00,$ff604cee,$0303ff9c,$3d7c30d0 + dc.l $000a3d7c,$e004ff6e,$f36eff6c,$2c562f6f + dc.l $00c400b8,$2f6f00c8,$00bc2f6f,$00cc00c0 + dc.l $2f6f0038,$00c42f6f,$003c00c8,$2f6f0040 + dc.l $00ccdffc,$000000b8,$60ffffff,$f1a4082e + dc.l $00050004,$6600000c,$206effd8,$4e606000 + dc.l $fbda0c2e,$0008ff4a,$6600fbd0,$f22ed0c0 + dc.l $ffdcf22e,$9c00ff60,$4cee0303,$ff9c3d7c + dc.l $30c4000a,$3d7ce001,$ff6ef36e,$ff6c2c56 + dc.l $2f6f00c4,$00b82f6f,$00c800bc,$2f6f00cc + dc.l $00c02f6f,$003800c4,$2f6f003c,$00c82f6f + dc.l $004000cc,$dffc0000,$00b860ff,$fffff106 + dc.l $e9ee00c3,$ff420c00,$00016708,$0c000005 + dc.l $67344e75,$302eff6c,$02407fff,$67260c40 + dc.l $3f806e20,$44400640,$3f81222e,$ff70e0a9 + dc.l $08c1001f,$2d41ff70,$026e8000,$ff6c006e + dc.l $3f80ff6c,$4e75302e,$ff6c0240,$7fff673a + dc.l $0c403c00,$6e344a2e,$ff6c5bee,$ff6e3d40 + dc.l $ff6c4280,$41eeff6c,$323c3c01,$61ff0000 + dc.l $1a66303c,$3c004a2e,$ff6e6704,$08c0000f + dc.l $08ee0007,$ff703d40,$ff6c4e75,$082e0005 + dc.l $000467ff,$fffff176,$2d680000,$ff782d68 + dc.l $0004ff7c,$2d680008,$ff804281,$4e752f00 + dc.l $4e7a0808,$08000001,$66000460,$201f4e56 + dc.l $ff4048ee,$0303ff9c,$f22ebc00,$ff60f22e + dc.l $f0c0ffdc,$2d6e0006,$ff44206e,$ff4458ae + dc.l $ff4461ff,$fffff152,$2d40ff40,$4a406b00 + dc.l $020e02ae,$00ff00ff,$ff640800,$000a6618 + dc.l $206eff44,$43eeff6c,$700c61ff,$fffff0d2 + dc.l $4a816600,$04926048,$206eff44,$43eeff6c + dc.l $700c61ff,$fffff0ba,$4a816600,$047ae9ee + dc.l $004fff6c,$0c407fff,$6726102e,$ff6f0200 + dc.l $000f660c,$4aaeff70,$66064aae,$ff746710 + dc.l $41eeff6c,$61ff0000,$501af22e,$f080ff6c + dc.l $06ae0000,$000cff44,$41eeff6c,$61ff0000 + dc.l $1cd21d40,$ff4e0c00,$0006660a,$61ff0000 + dc.l $1c321d40,$ff4e422e,$ff53082e,$0005ff43 + dc.l $6748082e,$0004ff43,$662ce9ee,$0183ff42 + dc.l $61ff0000,$4e7641ee,$ff7861ff,$00001c94 + dc.l $1d40ff4f,$0c000006,$662061ff,$00001bf4 + dc.l $1d40ff4f,$6014082e,$0003ff43,$670c50ee + dc.l $ff53082e,$0001ff43,$67c04280,$102eff63 + dc.l $122eff43,$0241007f,$f23c9000,$00000000 + dc.l $f23c8800,$00000000,$41eeff6c,$43eeff78 + dc.l $223b1530,$00000b2c,$4ebb1930,$00000b24 + dc.l $102eff62,$66404a2e,$ff53660c,$e9ee0183 + dc.l $ff4261ff,$00004e84,$2d6e0006,$ff682d6e + dc.l $ff440006,$f22ed0c0,$ffdcf22e,$9c00ff60 + dc.l $4cee0303,$ff9c4e5e,$08170007,$66000096 + dc.l $60ffffff,$ee6ec02e,$ff66edc0,$06086612 + dc.l $082e0004,$ff6667ae,$082e0001,$ff6267ac + dc.l $60340480,$00000018,$0c000006,$6610082e + dc.l $0004ff66,$6620082e,$0003ff66,$66203d7b + dc.l $0206ff6e,$601ee002,$e006e004,$e005e003 + dc.l $e002e001,$e0013d7c,$e005ff6e,$60063d7c + dc.l $e003ff6e,$2d6e0006,$ff682d6e,$ff440006 + dc.l $f22ed0c0,$ffdcf22e,$9c00ff60,$4cee0303 + dc.l $ff9cf36e,$ff6c4e5e,$08170007,$660660ff + dc.l $ffffede0,$2f173f6f,$00080004,$3f7c2024 + dc.l $0006f22f,$a4000008,$60ffffff,$eeb80800 + dc.l $000e6700,$01c2082e,$00050004,$66164e68 + dc.l $2d48ffd8,$61ff0000,$0bce206e,$ffd84e60 + dc.l $600001aa,$422eff4a,$41ee000c,$2d48ffd8 + dc.l $61ff0000,$0bb20c2e,$0008ff4a,$67000086 + dc.l $0c2e0004,$ff4a6600,$0184082e,$00070004 + dc.l $66363dae,$00040804,$2daeff44,$08063dbc + dc.l $00f0080a,$41f60804,$2d480004,$f22ed0c0 + dc.l $ffdcf22e,$9c00ff60,$4cee0303,$ff9c4e5e + dc.l $2e5f60ff,$ffffed3c,$3dae0004,$08002dae + dc.l $ff440802,$3dbc2024,$08062dae,$00060808 + dc.l $41f60800,$2d480004,$f22ed0c0,$ffdcf22e + dc.l $9c00ff60,$4cee0303,$ff9c4e5e,$2e5f60ff + dc.l $ffffedf2,$1d41000a,$1d40000b,$f22ed0c0 + dc.l $ffdcf22e,$9c00ff60,$4cee0303,$ff9c2f16 + dc.l $2f002f01,$2f2eff44,$4280102e,$000b4480 + dc.l $082e0007,$0004671c,$3dae0004,$08002dae + dc.l $00060808,$2d9f0802,$3dbc2024,$08064876 + dc.l $08006014,$3dae0004,$08042d9f,$08063dbc + dc.l $00f0080a,$48760804,$4281122e,$000a4a01 + dc.l $6a0cf236,$f080080c,$06800000,$000ce309 + dc.l $6a0cf236,$f040080c,$06800000,$000ce309 + dc.l $6a0cf236,$f020080c,$06800000,$000ce309 + dc.l $6a0cf236,$f010080c,$06800000,$000ce309 + dc.l $6a0cf236,$f008080c,$06800000,$000ce309 + dc.l $6a0cf236,$f004080c,$06800000,$000ce309 + dc.l $6a0cf236,$f002080c,$06800000,$000ce309 + dc.l $6a06f236,$f001080c,$222f0004,$202f0008 + dc.l $2c6f000c,$2e5f0817,$000767ff,$ffffec04 + dc.l $60ffffff,$ecf061ff,$00001244,$f22ed0c0 + dc.l $ffdcf22e,$9c00ff60,$4cee0303,$ff9c082e + dc.l $00070004,$660e2d6e,$ff440006,$4e5e60ff + dc.l $ffffebd0,$2c563f6f,$00c400c0,$2f6f00c6 + dc.l $00c82f6f,$000400c2,$3f7c2024,$00c6dffc + dc.l $000000c0,$60ffffff,$ec9c201f,$4e56ff40 + dc.l $48ee0303,$ff9c2d6e,$0006ff44,$206eff44 + dc.l $58aeff44,$61ffffff,$ed002d40,$ff404a40 + dc.l $6b047010,$60260800,$000e6610,$e9c014c3 + dc.l $700c0c01,$00076614,$58806010,$428061ff + dc.l $00000ce6,$202eff44,$90ae0006,$3d40000a + dc.l $4cee0303,$ff9c4e5e,$518f2f00,$3f6f000c + dc.l $00042f6f,$000e0006,$4280302f,$00122f6f + dc.l $00060010,$d1af0006,$3f7c402c,$000a201f + dc.l $60ffffff,$ebe44e7a,$08080800,$0001660c + dc.l $f22e9c00,$ff60f22e,$d0c0ffdc,$4cee0303 + dc.l $ff9c4e5e,$514f2eaf,$00083f6f,$000c0004 + dc.l $3f7c4008,$00062f6f,$00020008,$2f7c0942 + dc.l $8001000c,$08170005,$670608ef,$0002000d + dc.l $60ffffff,$ebd64fee,$ff404e7a,$18080801 + dc.l $0001660c,$f22ed0c0,$ffdcf22f,$9c000020 + dc.l $2c562f6f,$00c400bc,$3f6f00c8,$00c03f7c + dc.l $400800c2,$2f4800c4,$3f4000c8,$3f7c0001 + dc.l $00ca4cef,$0303005c,$defc00bc,$60a64e56 + dc.l $ff40f32e,$ff6c48ee,$0303ff9c,$f22ebc00 + dc.l $ff60f22e,$f0c0ffdc,$2d6eff68,$ff44206e + dc.l $ff4458ae,$ff4461ff,$ffffebce,$2d40ff40 + dc.l $0800000d,$662841ee,$ff6c61ff,$fffff1ea + dc.l $f22ed0c0,$ffdcf22e,$9c00ff60,$4cee0303 + dc.l $ff9cf36e,$ff6c4e5e,$60ffffff,$ea94322e + dc.l $ff6c0241,$7fff0c41,$7fff661a,$4aaeff74 + dc.l $660c222e,$ff700281,$7fffffff,$67082d6e + dc.l $ff70ff54,$6012223c,$7fffffff,$4a2eff6c + dc.l $6a025281,$2d41ff54,$e9c004c3,$122eff41 + dc.l $307b0206,$4efb8802,$006c0000,$0000ff98 + dc.l $003e0000,$00100000,$102eff54,$0c010007 + dc.l $6f16206e,$000c61ff,$ffffeb86,$4a8166ff + dc.l $00005436,$6000ff6a,$02410007,$61ff0000 + dc.l $478e6000,$ff5c302e,$ff540c01,$00076f16 + dc.l $206e000c,$61ffffff,$eb6e4a81,$66ff0000 + dc.l $54166000,$ff3c0241,$000761ff,$00004724 + dc.l $6000ff2e,$202eff54,$0c010007,$6f16206e + dc.l $000c61ff,$ffffeb56,$4a8166ff,$000053f6 + dc.l $6000ff0e,$02410007,$61ff0000,$46ba6000 + dc.l $ff004e56,$ff40f32e,$ff6c48ee,$0303ff9c + dc.l $f22ebc00,$ff60f22e,$f0c0ffdc,$2d6eff68 + dc.l $ff44206e,$ff4458ae,$ff4461ff,$ffffea8a + dc.l $2d40ff40,$0800000d,$6600002a,$41eeff6c + dc.l $61ffffff,$f0a4f22e,$d0c0ffdc,$f22e9c00 + dc.l $ff604cee,$0303ff9c,$f36eff6c,$4e5e60ff + dc.l $ffffe964,$e9c004c3,$122eff41,$307b0206 + dc.l $4efb8802,$007400a6,$015a0000,$00420104 + dc.l $00100000,$102eff70,$08c00006,$0c010007 + dc.l $6f16206e,$000c61ff,$ffffea76,$4a8166ff + dc.l $00005326,$6000ffa0,$02410007,$61ff0000 + dc.l $467e6000,$ff92302e,$ff7008c0,$000e0c01 + dc.l $00076f16,$206e000c,$61ffffff,$ea5a4a81 + dc.l $66ff0000,$53026000,$ff6e0241,$000761ff + dc.l $00004610,$6000ff60,$202eff70,$08c0001e + dc.l $0c010007,$6f16206e,$000c61ff,$ffffea3e + dc.l $4a8166ff,$000052de,$6000ff3c,$02410007 + dc.l $61ff0000,$45a26000,$ff2e0c01,$00076f2e + dc.l $202eff6c,$02808000,$00000080,$7fc00000 + dc.l $222eff70,$e0898081,$206e000c,$61ffffff + dc.l $e9fc4a81,$66ff0000,$529c6000,$fefa202e + dc.l $ff6c0280,$80000000,$00807fc0,$00002f01 + dc.l $222eff70,$e0898081,$221f0241,$000761ff + dc.l $00004544,$6000fed0,$202eff6c,$02808000 + dc.l $00000080,$7ff80000,$222eff70,$2d40ff84 + dc.l $700be0a9,$83aeff84,$222eff70,$02810000 + dc.l $07ffe0b9,$2d41ff88,$222eff74,$e0a983ae + dc.l $ff8841ee,$ff84226e,$000c7008,$61ffffff + dc.l $e8cc4a81,$66ff0000,$522a6000,$fe7a422e + dc.l $ff4a3d6e,$ff6cff84,$426eff86,$202eff70 + dc.l $08c0001e,$2d40ff88,$2d6eff74,$ff8c082e + dc.l $00050004,$66384e68,$2d48ffd8,$2d56ffd4 + dc.l $61ff0000,$02c22248,$2d48000c,$206effd8 + dc.l $4e602cae,$ffd441ee,$ff84700c,$61ffffff + dc.l $e86c4a81,$66ff0000,$51d86000,$fe1a2d56 + dc.l $ffd461ff,$00000290,$22482d48,$000c2cae + dc.l $ffd40c2e,$0008ff4a,$66ccf22e,$d0c0ffdc + dc.l $f22e9c00,$ff604cee,$0303ff9c,$f36eff6c + dc.l $2c6effd4,$2f6f00c4,$00b82f6f,$00c800bc + dc.l $2f6f00cc,$00c02f6f,$004400c4,$2f6f0048 + dc.l $00c82f6f,$004c00cc,$dffc0000,$00b860ff + dc.l $ffffe734,$4e56ff40,$f32eff6c,$48ee0303 + dc.l $ff9cf22e,$bc00ff60,$f22ef0c0,$ffdc2d6e + dc.l $ff68ff44,$206eff44,$58aeff44,$61ffffff + dc.l $e7f82d40,$ff400800,$000d6600,$0106e9c0 + dc.l $04c36622,$0c6e401e,$ff6c661a,$f23c9000 + dc.l $00000000,$f22e4000,$ff70f22e,$6800ff6c + dc.l $3d7ce001,$ff6e41ee,$ff6c61ff,$ffffedea + dc.l $02ae00ff,$01ffff64,$f23c9000,$00000000 + dc.l $f23c8800,$00000000,$e9ee1006,$ff420c01 + dc.l $00176700,$009641ee,$ff6c61ff,$00001394 + dc.l $1d40ff4e,$082e0005,$ff43672e,$082e0004 + dc.l $ff436626,$e9ee0183,$ff4261ff,$0000454c + dc.l $41eeff78,$61ff0000,$136a0c00,$00066606 + dc.l $61ff0000,$12ce1d40,$ff4f4280,$102eff63 + dc.l $122eff43,$0241007f,$41eeff6c,$43eeff78 + dc.l $223b1530,$0000022c,$4ebb1930,$00000224 + dc.l $e9ee0183,$ff4261ff,$00004590,$f22ed0c0 + dc.l $ffdcf22e,$9c00ff60,$4cee0303,$ff9cf36e + dc.l $ff6c4e5e,$60ffffff,$e5cc4280,$102eff63 + dc.l $122eff43,$02810000,$007f61ff,$00000396 + dc.l $60be1d7c,$0000ff4e,$4280102e,$ff6302ae + dc.l $ffff00ff,$ff6441ee,$ff6c61ff,$00001722 + dc.l $60aa4e56,$ff40f32e,$ff6c48ee,$0303ff9c + dc.l $f22ebc00,$ff60f22e,$f0c0ffdc,$2d6eff68 + dc.l $ff44206e,$ff4458ae,$ff4461ff,$ffffe69a + dc.l $2d40ff40,$41eeff6c,$61ffffff,$ecbcf22e + dc.l $d0c0ffdc,$f22e9c00,$ff604cee,$0303ff9c + dc.l $f36eff6c,$4e5e60ff,$ffffe592,$0c6f402c + dc.l $000667ff,$ffffe5b2,$60ffffff,$e5962040 + dc.l $102eff41,$22000240,$00380281,$00000007 + dc.l $0c000018,$67240c00,$0020672c,$80410c00 + dc.l $003c6706,$206e000c,$4e751d7c,$0080ff4a + dc.l $41f60162,$ff680004,$4e752008,$61ff0000 + dc.l $42ca206e,$000c4e75,$200861ff,$0000430c + dc.l $206e000c,$0c00000c,$67024e75,$51882d48 + dc.l $000c4e75,$102eff41,$22000240,$00380281 + dc.l $00000007,$0c000018,$670e0c00,$00206700 + dc.l $0076206e,$000c4e75,$323b120e,$206e000c + dc.l $4efb1006,$4afc0008,$0010001a,$0024002c + dc.l $0034003c,$0044004e,$06ae0000,$000cffa4 + dc.l $4e7506ae,$0000000c,$ffa84e75,$d5fc0000 + dc.l $000c4e75,$d7fc0000,$000c4e75,$d9fc0000 + dc.l $000c4e75,$dbfc0000,$000c4e75,$06ae0000 + dc.l $000cffd4,$4e751d7c,$0004ff4a,$06ae0000 + dc.l $000cffd8,$4e75323b,$1214206e,$000c5188 + dc.l $51ae000c,$4efb1006,$4afc0008,$00100016 + dc.l $001c0020,$00240028,$002c0032,$2d48ffa4 + dc.l $4e752d48,$ffa84e75,$24484e75,$26484e75 + dc.l $28484e75,$2a484e75,$2d48ffd4,$4e752d48 + dc.l $ffd81d7c,$0008ff4a,$4e754afc,$006d0000 + dc.l $20700000,$2a660000,$00000000,$2b0a0000 + dc.l $3db20000,$00000000,$00000000,$00000000 + dc.l $00000000,$00000000,$00000000,$00000000 + dc.l $00000000,$00000000,$00000000,$00000000 + dc.l $00000000,$00000000,$00000000,$00000000 + dc.l $00000000,$00000000,$00000000,$00000000 + dc.l $2bb00000,$00000000,$27460000,$00000000 + dc.l $00000000,$00000000,$00000000,$00000000 + dc.l $233c0000,$00000000,$36220000,$1c7c0000 + dc.l $32f20000,$00000000,$00000000,$2fb00000 + dc.l $39ea0000,$00000000,$00000000,$00000000 + dc.l $00000000,$00000000,$00000000,$00000000 + dc.l $00000000,$00000000,$00000000,$00000000 + dc.l $00000000,$00000000,$00000000,$00000000 + dc.l $2e4e0000,$00000000,$29f40000,$00000000 + dc.l $00000000,$00000000,$00000000,$00000000 + dc.l $205e0000,$3da00000,$00000000,$00000000 + dc.l $20680000,$3daa0000,$00000000,$00000000 + dc.l $00000000,$00000000,$00000000,$00000000 + dc.l $00000000,$00000000,$00000000,$00000000 + dc.l $00000000,$00000000,$00000000,$00000000 + dc.l $00000000,$00000000,$00000000,$00000000 + dc.l $2b9e0000,$00000000,$27340000,$00000000 + dc.l $2ba80000,$00000000,$273e0000,$00000000 + dc.l $232a0000,$00000000,$36100000,$1c6a0000 + dc.l $23340000,$00000000,$361a0000,$1c740000 + dc.l $39d80000,$00000000,$00000000,$00000000 + dc.l $39e260fe,$122eff43,$02410070,$e80961ff + dc.l $00003ed2,$02800000,$00ff2f00,$103b0920 + dc.l $01482f00,$61ff0000,$0340201f,$221f6700 + dc.l $0134082e,$0005ff42,$670000b8,$082e0004 + dc.l $ff426600,$001a123b,$1120021e,$082e0005 + dc.l $0004670a,$0c2e0008,$ff4a6602,$4e752248 + dc.l $9fc041d7,$4a016a0c,$20eeffdc,$20eeffe0 + dc.l $20eeffe4,$e3096a0c,$20eeffe8,$20eeffec + dc.l $20eefff0,$e3096a0a,$f210f020,$d1fc0000 + dc.l $000ce309,$6a0af210,$f010d1fc,$0000000c + dc.l $e3096a0a,$f210f008,$d1fc0000,$000ce309 + dc.l $6a0af210,$f004d1fc,$0000000c,$e3096a0a + dc.l $f210f002,$d1fc0000,$000ce309,$6a0af210 + dc.l $f001d1fc,$0000000c,$2d49ff54,$41d72f00 + dc.l $61ffffff,$e248201f,$dfc04a81,$6600071e + dc.l $4e752d48,$ff549fc0,$43d72f01,$2f0061ff + dc.l $ffffe214,$201f4a81,$6600070e,$221f41d7 + dc.l $4a016a0c,$2d58ffdc,$2d58ffe0,$2d58ffe4 + dc.l $e3096a0c,$2d58ffe8,$2d58ffec,$2d58fff0 + dc.l $e3096a04,$f218d020,$e3096a04,$f218d010 + dc.l $e3096a04,$f218d008,$e3096a04,$f218d004 + dc.l $e3096a04,$f218d002,$e3096a04,$f218d001 + dc.l $dfc04e75,$4e75000c,$0c180c18,$18240c18 + dc.l $18241824,$24300c18,$18241824,$24301824 + dc.l $24302430,$303c0c18,$18241824,$24301824 + dc.l $24302430,$303c1824,$24302430,$303c2430 + dc.l $303c303c,$3c480c18,$18241824,$24301824 + dc.l $24302430,$303c1824,$24302430,$303c2430 + dc.l $303c303c,$3c481824,$24302430,$303c2430 + dc.l $303c303c,$3c482430,$303c303c,$3c48303c + dc.l $3c483c48,$48540c18,$18241824,$24301824 + dc.l $24302430,$303c1824,$24302430,$303c2430 + dc.l $303c303c,$3c481824,$24302430,$303c2430 + dc.l $303c303c,$3c482430,$303c303c,$3c48303c + dc.l $3c483c48,$48541824,$24302430,$303c2430 + dc.l $303c303c,$3c482430,$303c303c,$3c48303c + dc.l $3c483c48,$48542430,$303c303c,$3c48303c + dc.l $3c483c48,$4854303c,$3c483c48,$48543c48 + dc.l $48544854,$54600080,$40c020a0,$60e01090 + dc.l $50d030b0,$70f00888,$48c828a8,$68e81898 + dc.l $58d838b8,$78f80484,$44c424a4,$64e41494 + dc.l $54d434b4,$74f40c8c,$4ccc2cac,$6cec1c9c + dc.l $5cdc3cbc,$7cfc0282,$42c222a2,$62e21292 + dc.l $52d232b2,$72f20a8a,$4aca2aaa,$6aea1a9a + dc.l $5ada3aba,$7afa0686,$46c626a6,$66e61696 + dc.l $56d636b6,$76f60e8e,$4ece2eae,$6eee1e9e + dc.l $5ede3ebe,$7efe0181,$41c121a1,$61e11191 + dc.l $51d131b1,$71f10989,$49c929a9,$69e91999 + dc.l $59d939b9,$79f90585,$45c525a5,$65e51595 + dc.l $55d535b5,$75f50d8d,$4dcd2dad,$6ded1d9d + dc.l $5ddd3dbd,$7dfd0383,$43c323a3,$63e31393 + dc.l $53d333b3,$73f30b8b,$4bcb2bab,$6beb1b9b + dc.l $5bdb3bbb,$7bfb0787,$47c727a7,$67e71797 + dc.l $57d737b7,$77f70f8f,$4fcf2faf,$6fef1f9f + dc.l $5fdf3fbf,$7fff2040,$302eff40,$32000240 + dc.l $003f0281,$00000007,$303b020a,$4efb0006 + dc.l $4afc0040,$00000000,$00000000,$00000000 + dc.l $00000000,$00000000,$00000000,$00000000 + dc.l $00000000,$00800086,$008c0090,$00940098 + dc.l $009c00a0,$00a600b6,$00c600d2,$00de00ea + dc.l $00f60102,$01180126,$0134013e,$01480152 + dc.l $015c0166,$017a0198,$01b601d2,$01ee020a + dc.l $02260242,$02600260,$02600260,$02600260 + dc.l $02600260,$02c002da,$02f40314,$00000000 + dc.l $00000000,$206effa4,$4e75206e,$ffa84e75 + dc.l $204a4e75,$204b4e75,$204c4e75,$204d4e75 + dc.l $20564e75,$206effd8,$4e75202e,$ffa42200 + dc.l $d2882d41,$ffa42040,$4e75202e,$ffa82200 + dc.l $d2882d41,$ffa82040,$4e75200a,$2200d288 + dc.l $24412040,$4e75200b,$2200d288,$26412040 + dc.l $4e75200c,$2200d288,$28412040,$4e75200d + dc.l $2200d288,$2a412040,$4e752016,$2200d288 + dc.l $2c812040,$4e751d7c,$0004ff4a,$202effd8 + dc.l $2200d288,$2d41ffd8,$20404e75,$202effa4 + dc.l $90882d40,$ffa42040,$4e75202e,$ffa89088 + dc.l $2d40ffa8,$20404e75,$200a9088,$24402040 + dc.l $4e75200b,$90882640,$20404e75,$200c9088 + dc.l $28402040,$4e75200d,$90882a40,$20404e75 + dc.l $20169088,$2c802040,$4e751d7c,$0008ff4a + dc.l $202effd8,$90882d40,$ffd82040,$4e75206e + dc.l $ff4454ae,$ff4461ff,$ffffde38,$4a8166ff + dc.l $fffff1b6,$3040d1ee,$ffa44e75,$206eff44 + dc.l $54aeff44,$61ffffff,$de1a4a81,$66ffffff + dc.l $f1983040,$d1eeffa8,$4e75206e,$ff4454ae + dc.l $ff4461ff,$ffffddfc,$4a8166ff,$fffff17a + dc.l $3040d1ca,$4e75206e,$ff4454ae,$ff4461ff + dc.l $ffffdde0,$4a8166ff,$fffff15e,$3040d1cb + dc.l $4e75206e,$ff4454ae,$ff4461ff,$ffffddc4 + dc.l $4a8166ff,$fffff142,$3040d1cc,$4e75206e + dc.l $ff4454ae,$ff4461ff,$ffffdda8,$4a8166ff + dc.l $fffff126,$3040d1cd,$4e75206e,$ff4454ae + dc.l $ff4461ff,$ffffdd8c,$4a8166ff,$fffff10a + dc.l $3040d1d6,$4e75206e,$ff4454ae,$ff4461ff + dc.l $ffffdd70,$4a8166ff,$fffff0ee,$3040d1ee + dc.l $ffd84e75,$508161ff,$000038fa,$2f00206e + dc.l $ff4454ae,$ff4461ff,$ffffdd48,$4a8166ff + dc.l $fffff0c6,$205f0800,$00086600,$00e62d40 + dc.l $ff542200,$e9590241,$000f61ff,$000038c6 + dc.l $2f02242e,$ff540802,$000b6602,$48c02202 + dc.l $ef590281,$00000003,$e3a849c2,$d082d1c0 + dc.l $241f4e75,$206eff44,$54aeff44,$61ffffff + dc.l $dcf24a81,$66ffffff,$f0703040,$4e75206e + dc.l $ff4458ae,$ff4461ff,$ffffdcee,$4a8166ff + dc.l $fffff056,$20404e75,$206eff44,$54aeff44 + dc.l $61ffffff,$dcbe4a81,$66ffffff,$f03c3040 + dc.l $d1eeff44,$55884e75,$206eff44,$54aeff44 + dc.l $61ffffff,$dc9e4a81,$66ffffff,$f01c206e + dc.l $ff445588,$08000008,$66000038,$2d40ff54 + dc.l $2200e959,$0241000f,$61ff0000,$38182f02 + dc.l $242eff54,$0802000b,$660248c0,$2202ef59 + dc.l $02810000,$0003e3a8,$49c2d082,$d1c0241f + dc.l $4e750800,$0006670c,$48e73c00,$2a002608 + dc.l $42826028,$2d40ff54,$e9c01404,$61ff0000 + dc.l $37d448e7,$3c002400,$2a2eff54,$26080805 + dc.l $000b6602,$48c2e9c5,$0542e1aa,$08050007 + dc.l $67024283,$e9c50682,$0c000002,$6d346718 + dc.l $206eff44,$58aeff44,$61ffffff,$dc0c4a81 + dc.l $66ff0000,$00b06018,$206eff44,$54aeff44 + dc.l $61ffffff,$dbde4a81,$66ff0000,$009848c0 + dc.l $d680e9c5,$07826700,$006e0c00,$00026d34 + dc.l $6718206e,$ff4458ae,$ff4461ff,$ffffdbca + dc.l $4a8166ff,$0000006e,$601c206e,$ff4454ae + dc.l $ff4461ff,$ffffdb9c,$4a8166ff,$00000056 + dc.l $48c06002,$42802800,$08050002,$67142043 + dc.l $61ffffff,$dbd64a81,$66000028,$d082d084 + dc.l $6018d682,$204361ff,$ffffdbc0,$4a816600 + dc.l $0012d084,$6004d682,$20032040,$4cdf003c + dc.l $4e752043,$4cdf003c,$303c0101,$60ffffff + dc.l $ef184cdf,$003c60ff,$ffffeebe,$61ff0000 + dc.l $44ea303c,$00e1600a,$61ff0000,$44de303c + dc.l $0161206e,$ff5460ff,$ffffeeee,$102eff42 + dc.l $0c00009c,$670000b2,$0c000098,$67000074 + dc.l $0c000094,$6736206e,$ff4458ae,$ff4461ff + dc.l $ffffdb06,$4a8166ff,$ffffee6e,$2d40ff64 + dc.l $206eff44,$58aeff44,$61ffffff,$daec4a81 + dc.l $66ffffff,$ee542d40,$ff684e75,$206eff44 + dc.l $58aeff44,$61ffffff,$dad04a81,$66ffffff + dc.l $ee382d40,$ff60206e,$ff4458ae,$ff4461ff + dc.l $ffffdab6,$4a8166ff,$ffffee1e,$2d40ff68 + dc.l $4e75206e,$ff4458ae,$ff4461ff,$ffffda9a + dc.l $4a8166ff,$ffffee02,$2d40ff60,$206eff44 + dc.l $58aeff44,$61ffffff,$da804a81,$66ffffff + dc.l $ede82d40,$ff644e75,$206eff44,$58aeff44 + dc.l $61ffffff,$da644a81,$66ffffff,$edcc2d40 + dc.l $ff60206e,$ff4458ae,$ff4461ff,$ffffda4a + dc.l $4a8166ff,$ffffedb2,$2d40ff64,$206eff44 + dc.l $58aeff44,$61ffffff,$da304a81,$66ffffff + dc.l $ed982d40,$ff684e75,$2d680004,$ff882d69 + dc.l $0004ff94,$2d680008,$ff8c2d69,$0008ff98 + dc.l $30280000,$32290000,$3d40ff84,$3d41ff90 + dc.l $02407fff,$02417fff,$3d40ff54,$3d41ff56 + dc.l $b0416cff,$0000005c,$61ff0000,$015a2f00 + dc.l $0c2e0004,$ff4e6610,$41eeff84,$61ff0000 + dc.l $04fa4440,$3d40ff54,$302eff56,$04400042 + dc.l $b06eff54,$6c1a302e,$ff54d06f,$0002322e + dc.l $ff840241,$80008041,$3d40ff84,$201f4e75 + dc.l $026e8000,$ff8408ee,$0000ff85,$201f4e75 + dc.l $61ff0000,$00562f00,$0c2e0004,$ff4f6610 + dc.l $41eeff90,$61ff0000,$04a24440,$3d40ff56 + dc.l $302eff54,$04400042,$b06eff56,$6c1a302e + dc.l $ff56d06f,$0002322e,$ff900241,$80008041 + dc.l $3d40ff90,$201f4e75,$026e8000,$ff9008ee + dc.l $0000ff91,$201f4e75,$322eff84,$30010281 + dc.l $00007fff,$02408000,$00403fff,$3d40ff84 + dc.l $0c2e0004,$ff4e670a,$203c0000,$3fff9081 + dc.l $4e7541ee,$ff8461ff,$00000430,$44802200 + dc.l $60e60c2e,$0004ff4e,$673a322e,$ff840281 + dc.l $00007fff,$026e8000,$ff840801,$00006712 + dc.l $006e3fff,$ff84203c,$00003fff,$9081e280 + dc.l $4e75006e,$3ffeff84,$203c0000,$3ffe9081 + dc.l $e2804e75,$41eeff84,$61ff0000,$03de0800 + dc.l $00006710,$006e3fff,$ff840680,$00003fff + dc.l $e2804e75,$006e3ffe,$ff840680,$00003ffe + dc.l $e2804e75,$322eff90,$30010281,$00007fff + dc.l $02408000,$00403fff,$3d40ff90,$0c2e0004 + dc.l $ff4f670a,$203c0000,$3fff9081,$4e7541ee + dc.l $ff9061ff,$00000384,$44802200,$60e60c2e + dc.l $0005ff4f,$67320c2e,$0003ff4f,$673e0c2e + dc.l $0003ff4e,$671408ee,$0006ff70,$00ae0100 + dc.l $4080ff64,$41eeff6c,$604200ae,$01000000 + dc.l $ff6441ee,$ff6c6034,$00ae0100,$4080ff64 + dc.l $08ee0006,$ff7c41ee,$ff786020,$41eeff78 + dc.l $0c2e0005,$ff4e66ff,$0000000c,$00ae0000 + dc.l $4080ff64,$00ae0100,$0000ff64,$08280007 + dc.l $00006708,$00ae0800,$0000ff64,$f210d080 + dc.l $4e7500ae,$01002080,$ff64f23b,$d0800170 + dc.l $00000008,$4e757fff,$0000ffff,$ffffffff + dc.l $ffff0000,$3f813c01,$e408323b,$02f63001 + dc.l $90680000,$0c400042,$6a164280,$082e0001 + dc.l $ff666704,$08c0001d,$61ff0000,$001a4e75 + dc.l $203c2000,$00003141,$000042a8,$000442a8 + dc.l $00084e75,$2d680008,$ff542d40,$ff582001 + dc.l $92680000,$6f100c41,$00206d10,$0c410040 + dc.l $6d506000,$009a202e,$ff584e75,$2f023140 + dc.l $00007020,$90410c41,$001d6d08,$142eff58 + dc.l $852eff57,$e9e82020,$0004e9e8,$18000004 + dc.l $e9ee0800,$ff542142,$00042141,$0008e8c0 + dc.l $009e6704,$08c0001d,$0280e000,$0000241f + dc.l $4e752f02,$31400000,$04410020,$70209041 + dc.l $142eff58,$852eff57,$e9e82020,$0004e9e8 + dc.l $18000004,$e8c1009e,$660ce8ee,$081fff54 + dc.l $66042001,$60062001,$08c0001d,$42a80004 + dc.l $21420008,$0280e000,$0000241f,$4e753140 + dc.l $00000c41,$00416d12,$672442a8,$000442a8 + dc.l $0008203c,$20000000,$4e752028,$00042200 + dc.l $0280c000,$00000281,$3fffffff,$60122028 + dc.l $00040280,$80000000,$e2880281,$7fffffff + dc.l $66164aa8,$00086610,$4a2eff58,$660a42a8 + dc.l $000442a8,$00084e75,$08c0001d,$42a80004 + dc.l $42a80008,$4e7561ff,$00000110,$4a806700 + dc.l $00fa006e,$0208ff66,$327b1206,$4efb9802 + dc.l $004000ea,$00240008,$4a280002,$6b0000dc + dc.l $70ff4841,$0c010004,$6700003e,$6e000094 + dc.l $60000064,$4a280002,$6a0000c0,$70ff4841 + dc.l $0c010004,$67000022,$6e000078,$60000048 + dc.l $e3806400,$00a64841,$0c010004,$6700000a + dc.l $6e000060,$60000030,$06a80000,$01000004 + dc.l $640ce4e8,$0004e4e8,$00065268,$00004a80 + dc.l $66060268,$fe000006,$02a8ffff,$ff000004 + dc.l $42a80008,$4e7552a8,$0008641a,$52a80004 + dc.l $6414e4e8,$0004e4e8,$0006e4e8,$0008e4e8 + dc.l $000a5268,$00004a80,$66060228,$00fe000b + dc.l $4e7506a8,$00000800,$0008641a,$52a80004 + dc.l $6414e4e8,$0004e4e8,$0006e4e8,$0008e4e8 + dc.l $000a5268,$00004a80,$66060268,$f000000a + dc.l $02a8ffff,$f8000008,$4e754841,$0c010004 + dc.l $6700ff86,$6eea4e75,$48414a01,$66044841 + dc.l $4e7548e7,$30000c01,$00046622,$e9e83602 + dc.l $0004741e,$e5ab2428,$00040282,$0000003f + dc.l $66284aa8,$00086622,$4a80661e,$6020e9e8 + dc.l $35420008,$741ee5ab,$24280008,$02820000 + dc.l $01ff6606,$4a806602,$600408c3,$001d2003 + dc.l $4cdf000c,$48414e75,$2f022f03,$20280004 + dc.l $22280008,$edc02000,$671ae5a8,$e9c13022 + dc.l $8083e5a9,$21400004,$21410008,$2002261f + dc.l $241f4e75,$edc12000,$e5a90682,$00000020 + dc.l $21410004,$42a80008,$2002261f,$241f4e75 + dc.l $ede80000,$0004660e,$ede80000,$00086700 + dc.l $00740640,$00204281,$32280000,$02417fff + dc.l $b0416e1c,$92403028,$00000240,$80008240 + dc.l $31410000,$61ffffff,$ff82103c,$00004e75 + dc.l $0c010020,$6e20e9e8,$08400004,$21400004 + dc.l $20280008,$e3a82140,$00080268,$80000000 + dc.l $103c0004,$4e750441,$00202028,$0008e3a8 + dc.l $21400004,$42a80008,$02688000,$0000103c + dc.l $00044e75,$02688000,$0000103c,$00014e75 + dc.l $30280000,$02407fff,$0c407fff,$67480828 + dc.l $00070004,$6706103c,$00004e75,$4a406618 + dc.l $4aa80004,$660c4aa8,$00086606,$103c0001 + dc.l $4e75103c,$00044e75,$4aa80004,$66124aa8 + dc.l $0008660c,$02688000,$0000103c,$00014e75 + dc.l $103c0006,$4e754aa8,$00086612,$20280004 + dc.l $02807fff,$ffff6606,$103c0002,$4e750828 + dc.l $00060004,$6706103c,$00034e75,$103c0005 + dc.l $4e752028,$00002200,$02807ff0,$0000670e + dc.l $0c807ff0,$00006728,$103c0000,$4e750281 + dc.l $000fffff,$66ff0000,$00144aa8,$000466ff + dc.l $0000000a,$103c0001,$4e75103c,$00044e75 + dc.l $0281000f,$ffff66ff,$00000014,$4aa80004 + dc.l $66ff0000,$000a103c,$00024e75,$08010013 + dc.l $66ff0000,$000a103c,$00054e75,$103c0003 + dc.l $4e752028,$00002200,$02807f80,$0000670e + dc.l $0c807f80,$0000671e,$103c0000,$4e750281 + dc.l $007fffff,$66ff0000,$000a103c,$00014e75 + dc.l $103c0004,$4e750281,$007fffff,$66ff0000 + dc.l $000a103c,$00024e75,$08010016,$66ff0000 + dc.l $000a103c,$00054e75,$103c0003,$4e752f01 + dc.l $08280007,$000056e8,$00023228,$00000241 + dc.l $7fff9240,$31410000,$2f08202f,$00040240 + dc.l $00c0e848,$61ffffff,$fae22057,$322f0006 + dc.l $024100c0,$e8494841,$322f0006,$02410030 + dc.l $e84961ff,$fffffc22,$205f08a8,$00070000 + dc.l $4a280002,$670a08e8,$00070000,$42280002 + dc.l $42804aa8,$0004660a,$4aa80008,$660408c0 + dc.l $0002082e,$0001ff66,$670608ee,$0005ff67 + dc.l $588f4e75,$2f010828,$00070000,$56e80002 + dc.l $32280000,$02417fff,$92403141,$00002f08 + dc.l $428061ff,$fffffa64,$2057323c,$00044841 + dc.l $322f0006,$02410030,$e84961ff,$fffffbaa + dc.l $205f08a8,$00070000,$4a280002,$670a08e8 + dc.l $00070000,$42280002,$42804aa8,$0004660a + dc.l $4aa80008,$660408c0,$0002082e,$0001ff66 + dc.l $670608ee,$0005ff67,$588f4e75,$02410010 + dc.l $e8088200,$3001e309,$600e0241,$00108200 + dc.l $48408200,$3001e309,$103b0008,$41fb1620 + dc.l $4e750200,$00020200,$00020200,$00020000 + dc.l $00000a08,$0a080a08,$0a080a08,$0a087fff + dc.l $00000000,$00000000,$00000000,$00007ffe + dc.l $0000ffff,$ffffffff,$ffff0000,$00007ffe + dc.l $0000ffff,$ffffffff,$ffff0000,$00007fff + dc.l $00000000,$00000000,$00000000,$00007fff + dc.l $00000000,$00000000,$00000000,$0000407e + dc.l $0000ffff,$ff000000,$00000000,$0000407e + dc.l $0000ffff,$ff000000,$00000000,$00007fff + dc.l $00000000,$00000000,$00000000,$00007fff + dc.l $00000000,$00000000,$00000000,$000043fe + dc.l $0000ffff,$ffffffff,$f8000000,$000043fe + dc.l $0000ffff,$ffffffff,$f8000000,$00007fff + dc.l $00000000,$00000000,$00000000,$00000000 + dc.l $00000000,$00000000,$00000000,$00000000 + dc.l $00000000,$00000000,$00000000,$00000000 + dc.l $00000000,$00000000,$00000000,$00000000 + dc.l $00000000,$00000000,$00000000,$0000ffff + dc.l $00000000,$00000000,$00000000,$0000fffe + dc.l $0000ffff,$ffffffff,$ffff0000,$0000ffff + dc.l $00000000,$00000000,$00000000,$0000fffe + dc.l $0000ffff,$ffffffff,$ffff0000,$0000ffff + dc.l $00000000,$00000000,$00000000,$0000c07e + dc.l $0000ffff,$ff000000,$00000000,$0000ffff + dc.l $00000000,$00000000,$00000000,$0000c07e + dc.l $0000ffff,$ff000000,$00000000,$0000ffff + dc.l $00000000,$00000000,$00000000,$0000c3fe + dc.l $0000ffff,$ffffffff,$f8000000,$0000ffff + dc.l $00000000,$00000000,$00000000,$0000c3fe + dc.l $0000ffff,$ffffffff,$f8000000,$0000e9ee + dc.l $10c3ff42,$327b120a,$4efb9806,$4afc0008 + dc.l $00e001e0,$01480620,$0078041a,$00100620 + dc.l $4a2eff4e,$664cf228,$d0800000,$f2009000 + dc.l $f2007800,$f23c9000,$00000000,$f201a800 + dc.l $836eff66,$122eff41,$02010038,$6714206e + dc.l $000c61ff,$ffffcfaa,$4a8166ff,$0000385a + dc.l $4e75122e,$ff410241,$000761ff,$00002bb0 + dc.l $4e752228,$00000281,$80000000,$00810080 + dc.l $0000f201,$440060a4,$4a2eff4e,$664cf228 + dc.l $d0800000,$f2009000,$f2007000,$f23c9000 + dc.l $00000000,$f201a800,$836eff66,$122eff41 + dc.l $02010038,$6714206e,$000c61ff,$ffffcf58 + dc.l $4a8166ff,$00003800,$4e75122e,$ff410241 + dc.l $000761ff,$00002b0c,$4e752228,$00000281 + dc.l $80000000,$00810080,$0000f201,$440060a4 + dc.l $4a2eff4e,$664cf228,$d0800000,$f2009000 + dc.l $f2006000,$f23c9000,$00000000,$f201a800 + dc.l $836eff66,$122eff41,$02010038,$6714206e + dc.l $000c61ff,$ffffcf06,$4a8166ff,$000037a6 + dc.l $4e75122e,$ff410241,$000761ff,$00002a68 + dc.l $4e752228,$00000281,$80000000,$00810080 + dc.l $0000f201,$440060a4,$3d680000,$ff84426e + dc.l $ff862d68,$0004ff88,$2d680008,$ff8cf228 + dc.l $d0800000,$61ffffff,$e83e2248,$41eeff84 + dc.l $700c0c2e,$0008ff4a,$672661ff,$ffffcdee + dc.l $4a816600,$00524a2e,$ff4e6602,$4e7508ee + dc.l $0003ff66,$102eff62,$0200000a,$66164e75 + dc.l $61ffffff,$dc4a4a81,$6600002c,$4a2eff4e + dc.l $66dc4e75,$41eeff84,$61ffffff,$f90e4440 + dc.l $02407fff,$026e8000,$ff84816e,$ff84f22e + dc.l $d040ff84,$4e752cae,$ffd460ff,$00003702 + dc.l $02000030,$00000040,$2d40ff5c,$30280000 + dc.l $02407fff,$0c40407e,$6e0000e6,$67000152 + dc.l $0c403f81,$6d000058,$f228d080,$0000f22e + dc.l $9000ff5c,$f23c8800,$00000000,$f2006400 + dc.l $f23c9000,$00000000,$f201a800,$836eff66 + dc.l $122eff41,$02010038,$6714206e,$000c61ff + dc.l $ffffcdda,$4a8166ff,$0000367a,$4e75122e + dc.l $ff410241,$000761ff,$0000293c,$4e7508ee + dc.l $0003ff66,$3d680000,$ff842d68,$0004ff88 + dc.l $2d680008,$ff8c2f08,$42800c2e,$0004ff4e + dc.l $660a41ee,$ff8461ff,$fffff840,$41eeff84 + dc.l $222eff5c,$61ffffff,$fa5841ee,$ff8461ff + dc.l $0000034c,$122eff41,$02010038,$6714206e + dc.l $000c61ff,$ffffcd66,$4a8166ff,$00003606 + dc.l $600e122e,$ff410241,$000761ff,$000028c8 + dc.l $122eff62,$0201000a,$660000b8,$588f4e75 + dc.l $4a280007,$660e4aa8,$00086608,$006e1048 + dc.l $ff666006,$006e1248,$ff662f08,$4a280000 + dc.l $5bc1202e,$ff5c61ff,$fffffae4,$f210d080 + dc.l $f2006400,$122eff41,$02010038,$6714206e + dc.l $000c61ff,$ffffccf6,$4a8166ff,$00003596 + dc.l $600e122e,$ff410241,$000761ff,$00002858 + dc.l $122eff62,$0201000a,$6600007c,$588f4e75 + dc.l $32280000,$02418000,$00413fff,$3d41ff84 + dc.l $2d680004,$ff882d68,$0008ff8c,$f22e9000 + dc.l $ff5cf22e,$4800ff84,$f23c9000,$00000000 + dc.l $f2000018,$f23c5838,$0002f294,$fe7c6000 + dc.l $ff50205f,$3d680000,$ff842d68,$0004ff88 + dc.l $2d680008,$ff8c0c2e,$0004ff4e,$662c41ee + dc.l $ff8461ff,$fffff714,$44800240,$7fffefee + dc.l $004fff84,$6014205f,$3d680000,$ff842d68 + dc.l $0004ff88,$2d680008,$ff8c08ae,$0007ff84 + dc.l $56eeff86,$41eeff84,$122eff5f,$e8090241 + dc.l $000c4841,$122eff5f,$e8090241,$00034280 + dc.l $61ffffff,$f5544a2e,$ff866706,$08ee0007 + dc.l $ff84f22e,$d040ff84,$4e750200,$00300000 + dc.l $00802d40,$ff5c3028,$00000240,$7fff0c40 + dc.l $43fe6e00,$00c86700,$01200c40,$3c016d00 + dc.l $0046f228,$d0800000,$f22e9000,$ff5cf23c + dc.l $88000000,$0000f22e,$7400ff54,$f23c9000 + dc.l $00000000,$f200a800,$816eff66,$226e000c + dc.l $41eeff54,$700861ff,$ffffcaf2,$4a8166ff + dc.l $00003450,$4e7508ee,$0003ff66,$3d680000 + dc.l $ff842d68,$0004ff88,$2d680008,$ff8c2f08 + dc.l $42800c2e,$0004ff4e,$660a41ee,$ff8461ff + dc.l $fffff618,$41eeff84,$222eff5c,$61ffffff + dc.l $f83041ee,$ff8461ff,$000000d2,$2d40ff54 + dc.l $2d41ff58,$226e000c,$41eeff54,$700861ff + dc.l $ffffca8a,$4a8166ff,$000033e8,$122eff62 + dc.l $0201000a,$6600fe9c,$588f4e75,$3028000a + dc.l $024007ff,$6608006e,$1048ff66,$6006006e + dc.l $1248ff66,$2f084a28,$00005bc1,$202eff5c + dc.l $61ffffff,$f8caf210,$d080f22e,$7400ff54 + dc.l $226e000c,$41eeff54,$700861ff,$ffffca2e + dc.l $4a8166ff,$0000338c,$122eff62,$0201000a + dc.l $6600fe74,$588f4e75,$32280000,$02418000 + dc.l $00413fff,$3d41ff84,$2d680004,$ff882d68 + dc.l $0008ff8c,$f22e9000,$ff5cf22e,$4800ff84 + dc.l $f23c9000,$00000000,$f2000018,$f23c5838 + dc.l $0002f294,$feae6000,$ff644280,$30280000 + dc.l $04403fff,$064003ff,$4a280004,$6b025340 + dc.l $4840e988,$4a280000,$6a0408c0,$001f2228 + dc.l $0004e9c1,$10548081,$2d40ff54,$22280004 + dc.l $7015e1a9,$2d41ff58,$22280008,$e9c10015 + dc.l $222eff58,$8280202e,$ff544e75,$42803028 + dc.l $00000440,$3fff0640,$007f4a28,$00046b02 + dc.l $53404840,$ef884a28,$00006a04,$08c0001f + dc.l $22280004,$02817fff,$ff00e089,$80814e75 + dc.l $61ffffff,$e3822f08,$102eff4e,$66000082 + dc.l $082e0004,$ff426712,$122eff43,$e8090241 + dc.l $000761ff,$000024de,$6004102e,$ff43ebc0 + dc.l $06472f00,$41eeff6c,$61ff0000,$2b2002ae + dc.l $cffff00f,$ff84201f,$4a2eff87,$66164aae + dc.l $ff886610,$4aaeff8c,$660a4a80,$6606026e + dc.l $f000ff84,$41eeff84,$225f700c,$0c2e0008 + dc.l $ff4a670e,$61ffffff,$c8d44a81,$6600fb38 + dc.l $4e7561ff,$ffffd748,$4a816600,$fb2a4e75 + dc.l $0c000004,$6700ff7a,$41eeff6c,$426eff6e + dc.l $0c000005,$670260c0,$006e4080,$ff6608ee + dc.l $0006ff70,$60b251fc,$51fc51fc,$51fc51fc + dc.l $ffffc001,$ffffff81,$fffffc01,$00004000 + dc.l $0000007f,$000003ff,$02000030,$00000040 + dc.l $60080200,$00300000,$00802d40,$ff5c4241 + dc.l $122eff4f,$e709822e,$ff4e6600,$02e43d69 + dc.l $0000ff90,$2d690004,$ff942d69,$0008ff98 + dc.l $3d680000,$ff842d68,$0004ff88,$2d680008 + dc.l $ff8c61ff,$ffffef24,$2f0061ff,$ffffefc8 + dc.l $d197322e,$ff5eec09,$201fb0bb,$14846700 + dc.l $011e6d00,$0062b0bb,$14846700,$021a6e00 + dc.l $014af22e,$d080ff90,$f22e9000,$ff5cf23c + dc.l $88000000,$0000f22e,$4823ff84,$f201a800 + dc.l $f23c9000,$00000000,$83aeff64,$f22ef080 + dc.l $ff842f02,$322eff84,$24010281,$00007fff + dc.l $02428000,$92808242,$3d41ff84,$241ff22e + dc.l $d080ff84,$4e75f22e,$d080ff90,$f22e9000 + dc.l $ff5cf23c,$88000000,$0000f22e,$4823ff84 + dc.l $f201a800,$f23c9000,$00000000,$83aeff64 + dc.l $00ae0000,$1048ff64,$122eff62,$02010013 + dc.l $661c082e,$0003ff64,$56c1202e,$ff5c61ff + dc.l $fffff5dc,$812eff64,$f210d080,$4e75222e + dc.l $ff5c0201,$00c06634,$f22ef080,$ff842f02 + dc.l $322eff84,$34010281,$00007fff,$92800481 + dc.l $00006000,$02417fff,$02428000,$82423d41 + dc.l $ff84241f,$f22ed040,$ff8460a6,$f22ed080 + dc.l $ff90222e,$ff5c0201,$0030f201,$9000f22e + dc.l $4823ff84,$f23c9000,$00000000,$60aaf22e + dc.l $d080ff90,$f22e9000,$ff5cf23c,$88000000 + dc.l $0000f22e,$4823ff84,$f201a800,$f23c9000 + dc.l $00000000,$83aeff64,$f2000098,$f23c58b8 + dc.l $0002f293,$ff3c6000,$fee408ee,$0003ff66 + dc.l $f22ed080,$ff90f23c,$90000000,$0010f23c + dc.l $88000000,$0000f22e,$4823ff84,$f201a800 + dc.l $f23c9000,$00000000,$83aeff64,$122eff62 + dc.l $0201000b,$6620f22e,$f080ff84,$41eeff84 + dc.l $222eff5c,$61ffffff,$f3e8812e,$ff64f22e + dc.l $d080ff84,$4e75f22e,$d040ff90,$222eff5c + dc.l $020100c0,$6652f22e,$9000ff5c,$f23c8800 + dc.l $00000000,$f22e48a3,$ff84f23c,$90000000 + dc.l $0000f22e,$f040ff84,$2f02322e,$ff842401 + dc.l $02810000,$7fff0242,$80009280,$06810000 + dc.l $60000241,$7fff8242,$3d41ff84,$241ff22e + dc.l $d040ff84,$6000ff80,$222eff5c,$02010030 + dc.l $f2019000,$60a6f22e,$d080ff90,$f22e9000 + dc.l $ff5cf23c,$88000000,$0000f22e,$4823ff84 + dc.l $f201a800,$f23c9000,$00000000,$83aeff64 + dc.l $f2000098,$f23c58b8,$0002f292,$fde0f294 + dc.l $fefaf22e,$d040ff90,$222eff5c,$020100c0 + dc.l $00010010,$f2019000,$f23c8800,$00000000 + dc.l $f22e48a3,$ff84f23c,$90000000,$0000f200 + dc.l $0498f23c,$58b80002,$f293fda2,$6000febc + dc.l $323b120a,$4efb1006,$4afc0030,$fd120072 + dc.l $00cc006c,$fd120066,$00000000,$00720072 + dc.l $0060006c,$00720066,$00000000,$009e0060 + dc.l $009e006c,$009e0066,$00000000,$006c006c + dc.l $006c006c,$006c0066,$00000000,$fd120072 + dc.l $00cc006c,$fd120066,$00000000,$00660066 + dc.l $00660066,$00660066,$00000000,$60ffffff + dc.l $ed6460ff,$ffffecda,$60ffffff,$ecd41028 + dc.l $00001229,$0000b101,$6a10f23c,$44008000 + dc.l $00001d7c,$000cff64,$4e75f23c,$44000000 + dc.l $00001d7c,$0004ff64,$4e75f229,$d0800000 + dc.l $10280000,$12290000,$b1016a10,$f2000018 + dc.l $f200001a,$1d7c000a,$ff644e75,$f2000018 + dc.l $1d7c0002,$ff644e75,$f228d080,$00001028 + dc.l $00001229,$0000b101,$6ae260d0,$02000030 + dc.l $00000040,$60080200,$00300000,$00802d40 + dc.l $ff5c122e,$ff4e6600,$02620200,$00c06600 + dc.l $007c4a28,$00006a06,$08ee0003,$ff64f228 + dc.l $d0800000,$4e750200,$00c06600,$006008ee + dc.l $0003ff66,$4a280000,$6a0608ee,$0003ff64 + dc.l $f228d080,$0000082e,$0003ff62,$66024e75 + dc.l $3d680000,$ff842d68,$0004ff88,$2d680008 + dc.l $ff8c41ee,$ff8461ff,$ffffef60,$44400640 + dc.l $6000322e,$ff840241,$80000240,$7fff8041 + dc.l $3d40ff84,$f22ed040,$ff844e75,$0c000040 + dc.l $667e3d68,$0000ff84,$2d680004,$ff882d68 + dc.l $0008ff8c,$61ffffff,$eac20c80,$0000007f + dc.l $6c000092,$0c80ffff,$ff816700,$01786d00 + dc.l $00f4f23c,$88000000,$0000f22e,$9000ff5c + dc.l $f22e4800,$ff84f201,$a800f23c,$90000000 + dc.l $000083ae,$ff642f02,$f22ef080,$ff84322e + dc.l $ff843401,$02810000,$7fff9280,$02428000 + dc.l $84413d42,$ff84241f,$f22ed080,$ff844e75 + dc.l $3d680000,$ff842d68,$0004ff88,$2d680008 + dc.l $ff8c61ff,$ffffea44,$0c800000,$03ff6c00 + dc.l $00140c80,$fffffc01,$670000fa,$6d000076 + dc.l $6000ff80,$08ee0003,$ff664a2e,$ff846a06 + dc.l $08ee0003,$ff64122e,$ff620201,$000b661a + dc.l $41eeff84,$222eff5c,$61ffffff,$f084812e + dc.l $ff64f22e,$d080ff84,$4e752d6e,$ff88ff94 + dc.l $2d6eff8c,$ff98322e,$ff842f02,$34010281 + dc.l $00007fff,$92800242,$80000681,$00006000 + dc.l $02417fff,$84413d42,$ff90f22e,$d040ff90 + dc.l $241f60ac,$f23c8800,$00000000,$f22e9000 + dc.l $ff5cf22e,$4800ff84,$f23c9000,$00000000 + dc.l $f201a800,$83aeff64,$00ae0000,$1048ff64 + dc.l $122eff62,$02010013,$661c082e,$0003ff64 + dc.l $56c1202e,$ff5c61ff,$fffff0f4,$812eff64 + dc.l $f210d080,$4e752f02,$322eff84,$24010281 + dc.l $00007fff,$02428000,$92800481,$00006000 + dc.l $02417fff,$82423d41,$ff84241f,$f22ed040 + dc.l $ff8460b6,$f23c8800,$00000000,$f22e9000 + dc.l $ff5cf22e,$4800ff84,$f201a800,$f23c9000 + dc.l $00000000,$83aeff64,$f2000098,$f23c58b8 + dc.l $0002f293,$ff746000,$fe7e0c01,$00046700 + dc.l $fdb60c01,$000567ff,$ffffe9ee,$0c010003 + dc.l $67ffffff,$e9f8f228,$48000000,$f200a800 + dc.l $e1981d40,$ff644e75,$51fc51fc,$51fc51fc + dc.l $00003fff,$0000007e,$000003fe,$ffffc001 + dc.l $ffffff81,$fffffc01,$02000030,$00000040 + dc.l $60080200,$00300000,$00802d40,$ff5c4241 + dc.l $122eff4f,$e709822e,$ff4e6600,$02d63d69 + dc.l $0000ff90,$2d690004,$ff942d69,$0008ff98 + dc.l $3d680000,$ff842d68,$0004ff88,$2d680008 + dc.l $ff8c61ff,$ffffe864,$2f0061ff,$ffffe908 + dc.l $4497d197,$322eff5e,$ec09201f,$b0bb148e + dc.l $6f000074,$b0bb1520,$ff7a6700,$020c6e00 + dc.l $013cf22e,$d080ff90,$f22e9000,$ff5cf23c + dc.l $88000000,$0000f22e,$4820ff84,$f201a800 + dc.l $f23c9000,$00000000,$83aeff64,$f22ef080 + dc.l $ff842f02,$322eff84,$24010281,$00007fff + dc.l $02428000,$92808242,$3d41ff84,$241ff22e + dc.l $d080ff84,$4e750000,$7fff0000,$407f0000 + dc.l $43ff201f,$60c62f00,$f22ed080,$ff90f22e + dc.l $9000ff5c,$f23c8800,$00000000,$f22e4820 + dc.l $ff84f200,$a800f23c,$90000000,$000081ae + dc.l $ff64f227,$e0013017,$dffc0000,$000c0280 + dc.l $00007fff,$9097b0bb,$14ae6db6,$201f00ae + dc.l $00001048,$ff64122e,$ff620201,$0013661c + dc.l $082e0003,$ff6456c1,$202eff5c,$61ffffff + dc.l $eeee812e,$ff64f210,$d0804e75,$222eff5c + dc.l $020100c0,$6634f22e,$f080ff84,$2f02322e + dc.l $ff843401,$02810000,$7fff9280,$04810000 + dc.l $60000241,$7fff0242,$80008242,$3d41ff84 + dc.l $241ff22e,$d040ff84,$60a6f22e,$d080ff90 + dc.l $222eff5c,$02010030,$f2019000,$f22e4820 + dc.l $ff84f23c,$90000000,$000060aa,$08ee0003 + dc.l $ff66f22e,$d080ff90,$f23c9000,$00000010 + dc.l $f23c8800,$00000000,$f22e4820,$ff84f201 + dc.l $a800f23c,$90000000,$000083ae,$ff64122e + dc.l $ff620201,$000b6620,$f22ef080,$ff8441ee + dc.l $ff84222e,$ff5c61ff,$ffffed36,$812eff64 + dc.l $f22ed080,$ff844e75,$f22ed040,$ff90222e + dc.l $ff5c0201,$00c06652,$f22e9000,$ff5cf23c + dc.l $88000000,$0000f22e,$48a0ff84,$f23c9000 + dc.l $00000000,$f22ef040,$ff842f02,$322eff84 + dc.l $24010281,$00007fff,$02428000,$92800681 + dc.l $00006000,$02417fff,$82423d41,$ff84241f + dc.l $f22ed040,$ff846000,$ff80222e,$ff5c0201 + dc.l $0030f201,$900060a6,$f22ed080,$ff90f22e + dc.l $9000ff5c,$f23c8800,$00000000,$f22e4820 + dc.l $ff84f201,$a800f23c,$90000000,$000083ae + dc.l $ff64f200,$0098f23c,$58b80001,$f292fdee + dc.l $f294fefa,$f22ed040,$ff90222e,$ff5c0201 + dc.l $00c00001,$0010f201,$9000f23c,$88000000 + dc.l $0000f22e,$48a0ff84,$f23c9000,$00000000 + dc.l $f2000498,$f23c58b8,$0001f293,$fdb06000 + dc.l $febc323b,$120a4efb,$10064afc,$0030fd20 + dc.l $009e0072,$0060fd20,$00660000,$00000072 + dc.l $006c0072,$00600072,$00660000,$000000d0 + dc.l $00d0006c,$006000d0,$00660000,$00000060 + dc.l $00600060,$00600060,$00660000,$0000fd20 + dc.l $009e0072,$0060fd20,$00660000,$00000066 + dc.l $00660066,$00660066,$00660000,$000060ff + dc.l $ffffe62e,$60ffffff,$e62860ff,$ffffe6a6 + dc.l $10280000,$12290000,$b1016a10,$f23c4400 + dc.l $80000000,$1d7c000c,$ff644e75,$f23c4400 + dc.l $00000000,$1d7c0004,$ff644e75,$006e0410 + dc.l $ff661028,$00001229,$0000b101,$6a10f23c + dc.l $4400ff80,$00001d7c,$000aff64,$4e75f23c + dc.l $44007f80,$00001d7c,$0002ff64,$4e751029 + dc.l $00001228,$0000b101,$6a16f229,$d0800000 + dc.l $f2000018,$f200001a,$1d7c000a,$ff644e75 + dc.l $f229d080,$0000f200,$00181d7c,$0002ff64 + dc.l $4e750200,$00300000,$00406008,$02000030 + dc.l $00000080,$2d40ff5c,$122eff4e,$66000276 + dc.l $020000c0,$66000090,$2d680004,$ff882d68 + dc.l $0008ff8c,$30280000,$0a408000,$6a061d7c + dc.l $0008ff64,$3d40ff84,$f22ed080,$ff844e75 + dc.l $020000c0,$666008ee,$0003ff66,$2d680004 + dc.l $ff882d68,$0008ff8c,$30280000,$0a408000 + dc.l $6a061d7c,$0008ff64,$3d40ff84,$f22ed080 + dc.l $ff84082e,$0003ff62,$66024e75,$41eeff84 + dc.l $61ffffff,$e8764440,$06406000,$322eff84 + dc.l $02418000,$02407fff,$80413d40,$ff84f22e + dc.l $d040ff84,$4e750c00,$0040667e,$3d680000 + dc.l $ff842d68,$0004ff88,$2d680008,$ff8c61ff + dc.l $ffffe3d8,$0c800000,$007f6c00,$00900c80 + dc.l $ffffff81,$67000178,$6d0000f4,$f23c8800 + dc.l $00000000,$f22e9000,$ff5cf22e,$481aff84 + dc.l $f201a800,$f23c9000,$00000000,$83aeff64 + dc.l $2f02f22e,$f080ff84,$322eff84,$34010281 + dc.l $00007fff,$92800242,$80008441,$3d42ff84 + dc.l $241ff22e,$d080ff84,$4e753d68,$0000ff84 + dc.l $2d680004,$ff882d68,$0008ff8c,$61ffffff + dc.l $e35a0c80,$000003ff,$6c120c80,$fffffc01 + dc.l $670000fc,$6d000078,$6000ff82,$08ee0003 + dc.l $ff660a2e,$0080ff84,$6a0608ee,$0003ff64 + dc.l $122eff62,$0201000b,$661a41ee,$ff84222e + dc.l $ff5c61ff,$ffffe99a,$812eff64,$f22ed080 + dc.l $ff844e75,$2d6eff88,$ff942d6e,$ff8cff98 + dc.l $322eff84,$2f022401,$02810000,$7fff0242 + dc.l $80009280,$06810000,$60000241,$7fff8242 + dc.l $3d41ff90,$f22ed040,$ff90241f,$60acf23c + dc.l $88000000,$0000f22e,$9000ff5c,$f22e481a + dc.l $ff84f23c,$90000000,$0000f201,$a80083ae + dc.l $ff6400ae,$00001048,$ff64122e,$ff620201 + dc.l $0013661c,$082e0003,$ff6456c1,$202eff5c + dc.l $61ffffff,$ea0a812e,$ff64f210,$d0804e75 + dc.l $2f02322e,$ff842401,$02810000,$7fff0242 + dc.l $80009280,$04810000,$60000241,$7fff8242 + dc.l $3d41ff84,$f22ed040,$ff84241f,$60b6f23c + dc.l $88000000,$0000f22e,$9000ff5c,$f22e481a + dc.l $ff84f201,$a800f23c,$90000000,$000083ae + dc.l $ff64f200,$0098f23c,$58b80002,$f293ff74 + dc.l $6000fe7e,$0c010004,$6700fdb6,$0c010005 + dc.l $67ffffff,$e3040c01,$000367ff,$ffffe30e + dc.l $f228481a,$0000f200,$a800e198,$1d40ff64 + dc.l $4e75122e,$ff4e6610,$4a280000,$6b024e75 + dc.l $1d7c0008,$ff644e75,$0c010001,$67400c01 + dc.l $00026724,$0c010005,$67ffffff,$e2bc0c01 + dc.l $000367ff,$ffffe2c6,$4a280000,$6b024e75 + dc.l $1d7c0008,$ff644e75,$4a280000,$6b081d7c + dc.l $0002ff64,$4e751d7c,$000aff64,$4e754a28 + dc.l $00006b08,$1d7c0004,$ff644e75,$1d7c000c + dc.l $ff644e75,$122eff4e,$66280200,$0030f200 + dc.l $9000f23c,$88000000,$0000f228,$48010000 + dc.l $f23c9000,$00000000,$f200a800,$81aeff64 + dc.l $4e750c01,$0001672e,$0c010002,$674e0c01 + dc.l $00046710,$0c010005,$67ffffff,$e22c60ff + dc.l $ffffe23a,$3d680000,$ff841d7c,$0080ff88 + dc.l $41eeff84,$60a44a28,$00006b10,$f23c4400 + dc.l $00000000,$1d7c0004,$ff644e75,$f23c4400 + dc.l $80000000,$1d7c000c,$ff644e75,$f228d080 + dc.l $00004a28,$00006b08,$1d7c0002,$ff644e75 + dc.l $1d7c000a,$ff644e75,$122eff4e,$6618f23c + dc.l $88000000,$0000f228,$48030000,$f200a800 + dc.l $81aeff64,$4e750c01,$0001672e,$0c010002 + dc.l $674e0c01,$00046710,$0c010005,$67ffffff + dc.l $e19860ff,$ffffe1a6,$3d680000,$ff841d7c + dc.l $0080ff88,$41eeff84,$60b44a28,$00006b10 + dc.l $f23c4400,$00000000,$1d7c0004,$ff644e75 + dc.l $f23c4400,$80000000,$1d7c000c,$ff644e75 + dc.l $f228d080,$00004a28,$00006b08,$1d7c0002 + dc.l $ff644e75,$1d7c000a,$ff644e75,$02000030 + dc.l $00000040,$60080200,$00300000,$00802d40 + dc.l $ff5c122e,$ff4e6600,$025c0200,$00c0667e + dc.l $2d680004,$ff882d68,$0008ff8c,$32280000 + dc.l $0881000f,$3d41ff84,$f22ed080,$ff844e75 + dc.l $020000c0,$665808ee,$0003ff66,$2d680004 + dc.l $ff882d68,$0008ff8c,$30280000,$0880000f + dc.l $3d40ff84,$f22ed080,$ff84082e,$0003ff62 + dc.l $66024e75,$41eeff84,$61ffffff,$e41e4440 + dc.l $06406000,$322eff84,$02418000,$02407fff + dc.l $80413d40,$ff84f22e,$d040ff84,$4e750c00 + dc.l $0040667e,$3d680000,$ff842d68,$0004ff88 + dc.l $2d680008,$ff8c61ff,$ffffdf80,$0c800000 + dc.l $007f6c00,$00900c80,$ffffff81,$67000170 + dc.l $6d0000ec,$f23c8800,$00000000,$f22e9000 + dc.l $ff5cf22e,$4818ff84,$f201a800,$f23c9000 + dc.l $00000000,$83aeff64,$2f02f22e,$f080ff84 + dc.l $322eff84,$24010281,$00007fff,$92800242 + dc.l $80008441,$3d42ff84,$241ff22e,$d080ff84 + dc.l $4e753d68,$0000ff84,$2d680004,$ff882d68 + dc.l $0008ff8c,$61ffffff,$df020c80,$000003ff + dc.l $6c120c80,$fffffc01,$670000f4,$6d000070 + dc.l $6000ff82,$08ee0003,$ff6608ae,$0007ff84 + dc.l $122eff62,$0201000b,$661a41ee,$ff84222e + dc.l $ff5c61ff,$ffffe54a,$812eff64,$f22ed080 + dc.l $ff844e75,$2d6eff88,$ff942d6e,$ff8cff98 + dc.l $322eff84,$2f022401,$02810000,$7fff0242 + dc.l $80009280,$06810000,$60000241,$7fff8242 + dc.l $3d41ff90,$f22ed040,$ff90241f,$60acf23c + dc.l $88000000,$0000f22e,$9000ff5c,$f22e4818 + dc.l $ff84f23c,$90000000,$0000f201,$a80083ae + dc.l $ff6400ae,$00001048,$ff64122e,$ff620201 + dc.l $0013661c,$082e0003,$ff6456c1,$202eff5c + dc.l $61ffffff,$e5ba812e,$ff64f210,$d0804e75 + dc.l $2f02322e,$ff842401,$02810000,$7fff0242 + dc.l $80009280,$04810000,$60000241,$7fff8242 + dc.l $3d41ff84,$f22ed040,$ff84241f,$60b6f23c + dc.l $88000000,$0000f22e,$9000ff5c,$f22e4818 + dc.l $ff84f201,$a800f23c,$90000000,$000083ae + dc.l $ff64f200,$0098f23c,$58b80002,$f293ff74 + dc.l $6000fe86,$0c010004,$6700fdc6,$0c010005 + dc.l $67ffffff,$deb40c01,$000367ff,$ffffdebe + dc.l $f2284818,$00000c01,$00026708,$1d7c0004 + dc.l $ff644e75,$1d7c0002,$ff644e75,$4241122e + dc.l $ff4fe709,$822eff4e,$6618f229,$d0800000 + dc.l $f2284838,$0000f200,$a800e198,$1d40ff64 + dc.l $4e75323b,$120a4efb,$10064afc,$0030ffdc + dc.l $ffdcffdc,$006000f8,$006e0000,$0000ffdc + dc.l $ffdcffdc,$0060007c,$006e0000,$0000ffdc + dc.l $ffdcffdc,$0060007c,$006e0000,$00000060 + dc.l $00600060,$00600060,$006e0000,$00000114 + dc.l $009c009c,$006000bc,$006e0000,$0000006e + dc.l $006e006e,$006e006e,$006e0000,$000061ff + dc.l $ffffddde,$022e00f7,$ff644e75,$61ffffff + dc.l $ddd0022e,$00f7ff64,$4e753d68,$0000ff84 + dc.l $20280004,$08c0001f,$2d40ff88,$2d680008 + dc.l $ff8c41ee,$ff846000,$ff422d69,$0000ff84 + dc.l $20290004,$08c0001f,$2d40ff88,$2d690008 + dc.l $ff8c43ee,$ff846000,$ff223d69,$0000ff90 + dc.l $3d680000,$ff842029,$000408c0,$001f2d40 + dc.l $ff942028,$000408c0,$001f2d40,$ff882d69 + dc.l $0008ff98,$2d680008,$ff8c43ee,$ff9041ee + dc.l $ff846000,$fee61028,$00001229,$0000b101 + dc.l $6b00ff78,$4a006b02,$4e751d7c,$0008ff64 + dc.l $4e751028,$00001229,$0000b101,$6b00ff7c + dc.l $4a006a02,$4e751d7c,$0008ff64,$4e752d40 + dc.l $ff5c4241,$122eff4f,$e709822e,$ff4e6600 + dc.l $02a03d69,$0000ff90,$2d690004,$ff942d69 + dc.l $0008ff98,$3d680000,$ff842d68,$0004ff88 + dc.l $2d680008,$ff8c61ff,$ffffdbf0,$2f0061ff + dc.l $ffffdc94,$d09f0c80,$ffffc001,$670000f8 + dc.l $6d000064,$0c800000,$40006700,$01da6e00 + dc.l $0122f22e,$d080ff90,$f22e9000,$ff5cf23c + dc.l $88000000,$0000f22e,$4827ff84,$f201a800 + dc.l $f23c9000,$00000000,$83aeff64,$f22ef080 + dc.l $ff842f02,$322eff84,$24010281,$00007fff + dc.l $02428000,$92808242,$3d41ff84,$241ff22e + dc.l $d080ff84,$4e75f22e,$d080ff90,$f22e9000 + dc.l $ff5cf23c,$88000000,$0000f22e,$4827ff84 + dc.l $f201a800,$f23c9000,$00000000,$83aeff64 + dc.l $00ae0000,$1048ff64,$122eff62,$02010013 + dc.l $6620082e,$0003ff64,$56c1202e,$ff5c0200 + dc.l $003061ff,$ffffe2a8,$812eff64,$f210d080 + dc.l $4e75f22e,$f080ff84,$2f02322e,$ff842401 + dc.l $02810000,$7fff9280,$04810000,$60000241 + dc.l $7fff0242,$80008242,$3d41ff84,$241ff22e + dc.l $d040ff84,$60acf22e,$d080ff90,$f22e9000 + dc.l $ff5cf23c,$88000000,$0000f22e,$4827ff84 + dc.l $f201a800,$f23c9000,$00000000,$83aeff64 + dc.l $f2000098,$f23c58b8,$0002f293,$ff646000 + dc.l $ff0c08ee,$0003ff66,$f22ed080,$ff90f23c + dc.l $90000000,$0010f23c,$88000000,$0000f22e + dc.l $4827ff84,$f201a800,$f23c9000,$00000000 + dc.l $83aeff64,$122eff62,$0201000b,$6620f22e + dc.l $f080ff84,$41eeff84,$222eff5c,$61ffffff + dc.l $e166812e,$ff64f22e,$d080ff84,$4e75f22e + dc.l $d040ff90,$f22e9000,$ff5cf23c,$88000000 + dc.l $0000f22e,$48a7ff84,$f23c9000,$00000000 + dc.l $f22ef040,$ff842f02,$322eff84,$24010281 + dc.l $00007fff,$02428000,$92800681,$00006000 + dc.l $02417fff,$82423d41,$ff84241f,$f22ed040 + dc.l $ff846000,$ff8af22e,$d080ff90,$f22e9000 + dc.l $ff5cf23c,$88000000,$0000f22e,$4827ff84 + dc.l $f201a800,$f23c9000,$00000000,$83aeff64 + dc.l $f2000098,$f23c58b8,$0002f292,$fe20f294 + dc.l $ff12f22e,$d040ff90,$222eff5c,$020100c0 + dc.l $00010010,$f2019000,$f23c8800,$00000000 + dc.l $f22e48a7,$ff84f23c,$90000000,$0000f200 + dc.l $0498f23c,$58b80002,$f293fde2,$6000fed4 + dc.l $323b120a,$4efb1006,$4afc0030,$fd560072 + dc.l $0078006c,$fd560066,$00000000,$00720072 + dc.l $0060006c,$00720066,$00000000,$007e0060 + dc.l $007e006c,$007e0066,$00000000,$006c006c + dc.l $006c006c,$006c0066,$00000000,$fd560072 + dc.l $0078006c,$fd560066,$00000000,$00660066 + dc.l $00660066,$00660066,$00000000,$60ffffff + dc.l $da7460ff,$ffffd9ea,$60ffffff,$d9e460ff + dc.l $ffffed0e,$60ffffff,$ed6260ff,$ffffed2e + dc.l $2d40ff5c,$4241122e,$ff4fe709,$822eff4e + dc.l $6600027c,$3d690000,$ff902d69,$0004ff94 + dc.l $2d690008,$ff983d68,$0000ff84,$2d680004 + dc.l $ff882d68,$0008ff8c,$61ffffff,$d8ae2f00 + dc.l $61ffffff,$d9524497,$d197322e,$ff5eec09 + dc.l $201f0c80,$ffffc001,$6f000064,$0c800000 + dc.l $3fff6700,$01b66e00,$0100f22e,$d080ff90 + dc.l $f22e9000,$ff5cf23c,$88000000,$0000f22e + dc.l $4824ff84,$f201a800,$f23c9000,$00000000 + dc.l $83aeff64,$f22ef080,$ff842f02,$322eff84 + dc.l $24010281,$00007fff,$02428000,$92808242 + dc.l $3d41ff84,$241ff22e,$d080ff84,$4e75f22e + dc.l $d080ff90,$f22e9000,$ff5cf23c,$88000000 + dc.l $0000f22e,$4824ff84,$f201a800,$f23c9000 + dc.l $00000000,$83aeff64,$f227e001,$3217dffc + dc.l $0000000c,$02810000,$7fff9280,$0c810000 + dc.l $7fff6d90,$006e1048,$ff66122e,$ff620201 + dc.l $00136620,$082e0003,$ff6456c1,$202eff5c + dc.l $02000030,$61ffffff,$df46812e,$ff64f210 + dc.l $d0804e75,$f22ef080,$ff842f02,$322eff84 + dc.l $24010281,$00007fff,$02428000,$92800481 + dc.l $00006000,$02417fff,$82423d41,$ff84241f + dc.l $f22ed040,$ff8460ac,$08ee0003,$ff66f22e + dc.l $d080ff90,$f23c9000,$00000010,$f23c8800 + dc.l $00000000,$f22e4824,$ff84f201,$a800f23c + dc.l $90000000,$000083ae,$ff64122e,$ff620201 + dc.l $000b6620,$f22ef080,$ff8441ee,$ff84222e + dc.l $ff5c61ff,$ffffde40,$812eff64,$f22ed080 + dc.l $ff844e75,$f22ed040,$ff90f22e,$9000ff5c + dc.l $f23c8800,$00000000,$f22e48a4,$ff84f23c + dc.l $90000000,$0000f22e,$f040ff84,$2f02322e + dc.l $ff842401,$02810000,$7fff0242,$80009280 + dc.l $06810000,$60000241,$7fff8242,$3d41ff84 + dc.l $241ff22e,$d040ff84,$608af22e,$d080ff90 + dc.l $f22e9000,$ff5cf23c,$88000000,$0000f22e + dc.l $4824ff84,$f201a800,$f23c9000,$00000000 + dc.l $83aeff64,$f2000098,$f23c58b8,$0001f292 + dc.l $fe44f294,$ff14f22e,$d040ff90,$42810001 + dc.l $0010f201,$9000f23c,$88000000,$0000f22e + dc.l $48a4ff84,$f23c9000,$00000000,$f2000498 + dc.l $f23c58b8,$0001f293,$fe0c6000,$fedc323b + dc.l $120a4efb,$10064afc,$0030fd7a,$00720078 + dc.l $0060fd7a,$00660000,$00000078,$006c0078 + dc.l $00600078,$00660000,$0000007e,$007e006c + dc.l $0060007e,$00660000,$00000060,$00600060 + dc.l $00600060,$00660000,$0000fd7a,$00720078 + dc.l $0060fd7a,$00660000,$00000066,$00660066 + dc.l $00660066,$00660000,$000060ff,$ffffd6d2 + dc.l $60ffffff,$d6cc60ff,$ffffd74a,$60ffffff + dc.l $f0ce60ff,$fffff09c,$60ffffff,$f0f40200 + dc.l $00300000,$00406008,$02000030,$00000080 + dc.l $2d40ff5c,$4241122e,$ff4fe709,$822eff4e + dc.l $6600024c,$61ffffff,$d4b2f22e,$d080ff90 + dc.l $f23c8800,$00000000,$f22e9000,$ff5cf22e + dc.l $4822ff84,$f23c9000,$00000000,$f201a800 + dc.l $83aeff64,$f281003c,$2f02f227,$e001322e + dc.l $ff5eec09,$34170282,$00007fff,$9480b4bb + dc.l $14246c38,$b4bb142a,$6d0000b8,$67000184 + dc.l $32170241,$80008242,$3e81f21f,$d080241f + dc.l $4e754e75,$00007fff,$0000407f,$000043ff + dc.l $00000000,$00003f81,$00003c01,$00ae0000 + dc.l $1048ff64,$122eff62,$02010013,$6624dffc + dc.l $0000000c,$082e0003,$ff6456c1,$202eff5c + dc.l $61ffffff,$dc7a812e,$ff64f210,$d080241f + dc.l $4e75122e,$ff5c0201,$00c0661a,$32170241 + dc.l $80000482,$00006000,$02427fff,$82423e81 + dc.l $f21fd040,$60bef22e,$d080ff90,$222eff5c + dc.l $02010030,$f2019000,$f22e4822,$ff84f23c + dc.l $90000000,$0000dffc,$0000000c,$f227e001 + dc.l $60ba08ee,$0003ff66,$dffc0000,$000cf22e + dc.l $d080ff90,$f23c9000,$00000010,$f23c8800 + dc.l $00000000,$f22e4822,$ff84f23c,$90000000 + dc.l $0000f201,$a80083ae,$ff64122e,$ff620201 + dc.l $000b6622,$f22ef080,$ff8441ee,$ff84222e + dc.l $ff5c61ff,$ffffdaca,$812eff64,$f22ed080 + dc.l $ff84241f,$4e75f22e,$d040ff90,$222eff5c + dc.l $020100c0,$664ef22e,$9000ff5c,$f23c8800 + dc.l $00000000,$f22e48a2,$ff84f23c,$90000000 + dc.l $0000f22e,$f040ff84,$322eff84,$24010281 + dc.l $00007fff,$02428000,$92800681,$00006000 + dc.l $02417fff,$82423d41,$ff84f22e,$d040ff84 + dc.l $6000ff82,$222eff5c,$02010030,$f2019000 + dc.l $60aa222e,$ff5c0201,$00c06700,$fe74222f + dc.l $00040c81,$80000000,$6600fe66,$4aaf0008 + dc.l $6600fe5e,$082e0001,$ff666700,$fe54f22e + dc.l $d040ff90,$222eff5c,$020100c0,$00010010 + dc.l $f2019000,$f23c8800,$00000000,$f22e48a2 + dc.l $ff84f23c,$90000000,$0000f200,$0018f200 + dc.l $0498f200,$0438f292,$feca6000,$fe14323b + dc.l $120a4efb,$10064afc,$0030fdaa,$00e4011c + dc.l $0060fdaa,$00660000,$000000bc,$006c011c + dc.l $006000bc,$00660000,$00000130,$0130010c + dc.l $00600130,$00660000,$00000060,$00600060 + dc.l $00600060,$00660000,$0000fdaa,$00e4011c + dc.l $0060fdaa,$00660000,$00000066,$00660066 + dc.l $00660066,$00660000,$000060ff,$ffffd3d2 + dc.l $60ffffff,$d3cc1028,$00001229,$0000b101 + dc.l $6b000016,$4a006b2e,$f23c4400,$00000000 + dc.l $1d7c0004,$ff644e75,$122eff5f,$02010030 + dc.l $0c010020,$6710f23c,$44000000,$00001d7c + dc.l $0004ff64,$4e75f23c,$44008000,$00001d7c + dc.l $000cff64,$4e753d68,$0000ff84,$2d680004 + dc.l $ff882d68,$0008ff8c,$61ffffff,$d27e426e + dc.l $ff9042ae,$ff9442ae,$ff986000,$fcce3d69 + dc.l $0000ff90,$2d690004,$ff942d69,$0008ff98 + dc.l $61ffffff,$d302426e,$ff8442ae,$ff8842ae + dc.l $ff8c6000,$fca61028,$00001229,$0000b300 + dc.l $6bffffff,$d3a0f228,$d0800000,$4a280000 + dc.l $6a1c1d7c,$000aff64,$4e75f229,$d0800000 + dc.l $4a290000,$6a081d7c,$000aff64,$4e751d7c + dc.l $0002ff64,$4e750200,$00300000,$00406008 + dc.l $02000030,$00000080,$2d40ff5c,$4241122e + dc.l $ff4fe709,$822eff4e,$6600024c,$61ffffff + dc.l $d0eaf22e,$d080ff90,$f23c8800,$00000000 + dc.l $f22e9000,$ff5cf22e,$4828ff84,$f23c9000 + dc.l $00000000,$f201a800,$83aeff64,$f281003c + dc.l $2f02f227,$e001322e,$ff5eec09,$34170282 + dc.l $00007fff,$9480b4bb,$14246c38,$b4bb142a + dc.l $6d0000b8,$67000184,$32170241,$80008242 + dc.l $3e81f21f,$d080241f,$4e754e75,$00007fff + dc.l $0000407f,$000043ff,$00000000,$00003f81 + dc.l $00003c01,$00ae0000,$1048ff64,$122eff62 + dc.l $02010013,$6624dffc,$0000000c,$082e0003 + dc.l $ff6456c1,$202eff5c,$61ffffff,$d8b2812e + dc.l $ff64f210,$d080241f,$4e75122e,$ff5c0201 + dc.l $00c0661a,$32170241,$80000482,$00006000 + dc.l $02427fff,$82423e81,$f21fd040,$60bef22e + dc.l $d080ff90,$222eff5c,$02010030,$f2019000 + dc.l $f22e4828,$ff84f23c,$90000000,$0000dffc + dc.l $0000000c,$f227e001,$60ba08ee,$0003ff66 + dc.l $dffc0000,$000cf22e,$d080ff90,$f23c9000 + dc.l $00000010,$f23c8800,$00000000,$f22e4828 + dc.l $ff84f23c,$90000000,$0000f201,$a80083ae + dc.l $ff64122e,$ff620201,$000b6622,$f22ef080 + dc.l $ff8441ee,$ff84222e,$ff5c61ff,$ffffd702 + dc.l $812eff64,$f22ed080,$ff84241f,$4e75f22e + dc.l $d040ff90,$222eff5c,$020100c0,$664ef22e + dc.l $9000ff5c,$f23c8800,$00000000,$f22e48a8 + dc.l $ff84f23c,$90000000,$0000f22e,$f040ff84 + dc.l $322eff84,$24010281,$00007fff,$02428000 + dc.l $92800681,$00006000,$02417fff,$82423d41 + dc.l $ff84f22e,$d040ff84,$6000ff82,$222eff5c + dc.l $02010030,$f2019000,$60aa222e,$ff5c0201 + dc.l $00c06700,$fe74222f,$00040c81,$80000000 + dc.l $6600fe66,$4aaf0008,$6600fe5e,$082e0001 + dc.l $ff666700,$fe54f22e,$d040ff90,$222eff5c + dc.l $020100c0,$00010010,$f2019000,$f23c8800 + dc.l $00000000,$f22e48a8,$ff84f23c,$90000000 + dc.l $0000f200,$0018f200,$0498f200,$0438f292 + dc.l $feca6000,$fe14323b,$120a4efb,$10064afc + dc.l $0030fdaa,$00e2011a,$0060fdaa,$00660000 + dc.l $000000ba,$006c011a,$006000ba,$00660000 + dc.l $00000130,$0130010a,$00600130,$00660000 + dc.l $00000060,$00600060,$00600060,$00660000 + dc.l $0000fdaa,$00e2011a,$0060fdaa,$00660000 + dc.l $00000066,$00660066,$00660066,$00660000 + dc.l $000060ff,$ffffd00a,$60ffffff,$d0041028 + dc.l $00001229,$0000b300,$6a144a00,$6b2ef23c + dc.l $44000000,$00001d7c,$0004ff64,$4e75122e + dc.l $ff5f0201,$00300c01,$00206710,$f23c4400 + dc.l $00000000,$1d7c0004,$ff644e75,$f23c4400 + dc.l $80000000,$1d7c000c,$ff644e75,$3d680000 + dc.l $ff842d68,$0004ff88,$2d680008,$ff8c61ff + dc.l $ffffceb8,$426eff90,$42aeff94,$42aeff98 + dc.l $6000fcd0,$3d690000,$ff902d69,$0004ff94 + dc.l $2d690008,$ff9861ff,$ffffcf3c,$426eff84 + dc.l $42aeff88,$42aeff8c,$6000fca8,$10280000 + dc.l $12290000,$b3006aff,$ffffcfda,$f228d080 + dc.l $0000f200,$001af293,$001e1d7c,$000aff64 + dc.l $4e75f229,$d0800000,$4a290000,$6a081d7c + dc.l $000aff64,$4e751d7c,$0002ff64,$4e750200 + dc.l $00300000,$00406008,$02000030,$00000080 + dc.l $2d40ff5c,$4241122e,$ff4e6600,$02744a28 + dc.l $00006bff,$ffffcf7e,$020000c0,$6648f22e + dc.l $9000ff5c,$f23c8800,$00000000,$f2104804 + dc.l $f201a800,$83aeff64,$4e754a28,$00006bff + dc.l $ffffcf52,$020000c0,$661c3d68,$0000ff84 + dc.l $2d680004,$ff882d68,$0008ff8c,$61ffffff + dc.l $ce046000,$003e0c00,$00406600,$00843d68 + dc.l $0000ff84,$2d680004,$ff882d68,$0008ff8c + dc.l $61ffffff,$cde00c80,$0000007e,$67000098 + dc.l $6e00009e,$0c80ffff,$ff806700,$01a46d00 + dc.l $0120f23c,$88000000,$0000f22e,$9000ff5c + dc.l $f22e4804,$ff84f201,$a800f23c,$90000000 + dc.l $000083ae,$ff642f02,$f22ef080,$ff84322e + dc.l $ff842401,$02810000,$7fff9280,$02428000 + dc.l $84413d42,$ff84241f,$f22ed080,$ff844e75 + dc.l $3d680000,$ff842d68,$0004ff88,$2d680008 + dc.l $ff8c61ff,$ffffcd5e,$0c800000,$03fe6700 + dc.l $00166e1c,$0c80ffff,$fc006700,$01246d00 + dc.l $00a06000,$ff7e082e,$0000ff85,$6600ff74 + dc.l $08ee0003,$ff66f23c,$90000000,$0010f23c + dc.l $88000000,$0000f22e,$4804ff84,$f201a800 + dc.l $f23c9000,$00000000,$83aeff64,$122eff62 + dc.l $0201000b,$6620f22e,$f080ff84,$41eeff84 + dc.l $222eff5c,$61ffffff,$d338812e,$ff64f22e + dc.l $d080ff84,$4e752d6e,$ff88ff94,$2d6eff8c + dc.l $ff98322e,$ff842f02,$24010281,$00007fff + dc.l $02428000,$92800681,$00006000,$02417fff + dc.l $82423d41,$ff90f22e,$d040ff90,$241f60a6 + dc.l $f23c8800,$00000000,$f22e9000,$ff5cf22e + dc.l $4804ff84,$f23c9000,$00000000,$f201a800 + dc.l $83aeff64,$00ae0000,$1048ff64,$122eff62 + dc.l $02010013,$661c082e,$0003ff64,$56c1202e + dc.l $ff5c61ff,$ffffd3a8,$812eff64,$f210d080 + dc.l $4e752f02,$322eff84,$24010281,$00007fff + dc.l $02428000,$92800481,$00006000,$02417fff + dc.l $82423d41,$ff84f22e,$d040ff84,$241f60b6 + dc.l $082e0000,$ff856600,$ff78f23c,$88000000 + dc.l $0000f22e,$9000ff5c,$f22e4804,$ff84f201 + dc.l $a800f23c,$90000000,$000083ae,$ff64f200 + dc.l $0080f23c,$58b80001,$f293ff6a,$6000fe48 + dc.l $0c010004,$6700fdb4,$0c010001,$67160c01 + dc.l $00026736,$0c010005,$67ffffff,$cc8c60ff + dc.l $ffffcc9a,$4a280000,$6b10f23c,$44000000 + dc.l $00001d7c,$0004ff64,$4e75f23c,$44008000 + dc.l $00001d7c,$000cff64,$4e754a28,$00006bff + dc.l $ffffccc2,$f228d080,$00001d7c,$0002ff64 + dc.l $4e75303b,$12064efb,$00020020,$0026002c + dc.l $00300034,$0038003c,$00400044,$004a0050 + dc.l $00540058,$005c0060,$0064202e,$ff9c4e75 + dc.l $202effa0,$4e752002,$4e752003,$4e752004 + dc.l $4e752005,$4e752006,$4e752007,$4e75202e + dc.l $ffa44e75,$202effa8,$4e75200a,$4e75200b + dc.l $4e75200c,$4e75200d,$4e752016,$4e75202e + dc.l $ffd84e75,$323b1206,$4efb1002,$00100016 + dc.l $001c0020,$00240028,$002c0030,$2d40ff9c + dc.l $4e752d40,$ffa04e75,$24004e75,$26004e75 + dc.l $28004e75,$2a004e75,$2c004e75,$2e004e75 + dc.l $323b1206,$4efb1002,$00100016,$001c0020 + dc.l $00240028,$002c0030,$3d40ff9e,$4e753d40 + dc.l $ffa24e75,$34004e75,$36004e75,$38004e75 + dc.l $3a004e75,$3c004e75,$3e004e75,$323b1206 + dc.l $4efb1002,$00100016,$001c0020,$00240028 + dc.l $002c0030,$1d40ff9f,$4e751d40,$ffa34e75 + dc.l $14004e75,$16004e75,$18004e75,$1a004e75 + dc.l $1c004e75,$1e004e75,$323b1206,$4efb1002 + dc.l $00100016,$001c0020,$00240028,$002c0030 + dc.l $d1aeffa4,$4e75d1ae,$ffa84e75,$d5c04e75 + dc.l $d7c04e75,$d9c04e75,$dbc04e75,$d1964e75 + dc.l $1d7c0004,$ff4a0c00,$00016706,$d1aeffd8 + dc.l $4e7554ae,$ffd84e75,$323b1206,$4efb1002 + dc.l $00100016,$001c0020,$00240028,$002c0030 + dc.l $91aeffa4,$4e7591ae,$ffa84e75,$95c04e75 + dc.l $97c04e75,$99c04e75,$9bc04e75,$91964e75 + dc.l $1d7c0008,$ff4a0c00,$00016706,$91aeffd8 + dc.l $4e7555ae,$ffd84e75,$303b0206,$4efb0002 + dc.l $00100028,$0040004c,$00580064,$0070007c + dc.l $2d6effdc,$ff6c2d6e,$ffe0ff70,$2d6effe4 + dc.l $ff7441ee,$ff6c4e75,$2d6effe8,$ff6c2d6e + dc.l $ffecff70,$2d6efff0,$ff7441ee,$ff6c4e75 + dc.l $f22ef020,$ff6c41ee,$ff6c4e75,$f22ef010 + dc.l $ff6c41ee,$ff6c4e75,$f22ef008,$ff6c41ee + dc.l $ff6c4e75,$f22ef004,$ff6c41ee,$ff6c4e75 + dc.l $f22ef002,$ff6c41ee,$ff6c4e75,$f22ef001 + dc.l $ff6c41ee,$ff6c4e75,$303b0206,$4efb0002 + dc.l $00100028,$0040004c,$00580064,$0070007c + dc.l $2d6effdc,$ff782d6e,$ffe0ff7c,$2d6effe4 + dc.l $ff8041ee,$ff784e75,$2d6effe8,$ff782d6e + dc.l $ffecff7c,$2d6efff0,$ff8041ee,$ff784e75 + dc.l $f22ef020,$ff7841ee,$ff784e75,$f22ef010 + dc.l $ff7841ee,$ff784e75,$f22ef008,$ff7841ee + dc.l $ff784e75,$f22ef004,$ff7841ee,$ff784e75 + dc.l $f22ef002,$ff7841ee,$ff784e75,$f22ef001 + dc.l $ff7841ee,$ff784e75,$303b0206,$4efb0002 + dc.l $00100018,$0020002a,$0034003e,$00480052 + dc.l $f22ef080,$ffdc4e75,$f22ef080,$ffe84e75 + dc.l $f227e001,$f21fd020,$4e75f227,$e001f21f + dc.l $d0104e75,$f227e001,$f21fd008,$4e75f227 + dc.l $e001f21f,$d0044e75,$f227e001,$f21fd002 + dc.l $4e75f227,$e001f21f,$d0014e75,$700c61ff + dc.l $ffffbace,$43eeff6c,$700c61ff,$ffffa0d8 + dc.l $4a8166ff,$00000a14,$e9ee004f,$ff6c0c40 + dc.l $7fff6602,$4e75102e,$ff6f0200,$000f660e + dc.l $4aaeff70,$66084aae,$ff746602,$4e7541ee + dc.l $ff6c61ff,$0000001c,$f22ef080,$ff6c4e75 + dc.l $00000000,$02030203,$02030302,$03020203 + dc.l $2d680000,$ff842d68,$0004ff88,$2d680008 + dc.l $ff8c41ee,$ff8448e7,$3c00f227,$e0017402 + dc.l $76042810,$42814c3c,$10010000,$000ae9c4 + dc.l $08c4d280,$580351ca,$ffee0804,$001e6702 + dc.l $44810481,$00000010,$6c0e4481,$00844000 + dc.l $00000090,$40000000,$2f017201,$f23c4400 + dc.l $00000000,$e9d00704,$f2005822,$28301c00 + dc.l $76007407,$f23c4423,$41200000,$e9c408c4 + dc.l $f2005822,$580351ca,$ffec5281,$0c810000 + dc.l $00026fd8,$0810001f,$6704f200,$001a2217 + dc.l $0c810000,$001b6f00,$00e40810,$001e6674 + dc.l $42812810,$e9c40704,$66245281,$7a012830 + dc.l $5c006608,$50815285,$28305c00,$42837407 + dc.l $e9c408c4,$66085883,$528151ca,$fff42001 + dc.l $22179280,$6c104481,$28100084,$40000000 + dc.l $00904000,$000043fb,$01700000,$06664283 + dc.l $f23c4480,$3f800000,$7403e280,$6406f231 + dc.l $48a33800,$06830000,$000c4a80,$66ecf200 + dc.l $04236068,$42817a02,$28305c00,$66085385 + dc.l $50812830,$5c00761c,$7407e9c4,$08c46608 + dc.l $59835281,$51cafff4,$20012217,$92806e10 + dc.l $44812810,$0284bfff,$ffff0290,$bfffffff + dc.l $43fb0170,$000005fc,$4283f23c,$44803f80 + dc.l $00007403,$e2806406,$f23148a3,$38000683 + dc.l $0000000c,$4a8066ec,$f2000420,$262eff60 + dc.l $e9c32682,$2810e582,$e9c40002,$d48043fa + dc.l $fe501031,$28004283,$efc30682,$f2039000 + dc.l $e280640a,$43fb0170,$00000644,$6016e280 + dc.l $640a43fb,$01700000,$06d26008,$43fb0170 + dc.l $00000590,$20016a08,$44800090,$40000000 + dc.l $4283f23c,$44803f80,$0000e280,$6406f231 + dc.l $48a33800,$06830000,$000c4a80,$66ec0810 + dc.l $001e6706,$f2000420,$6004f200,$0423f200 + dc.l $a8000880,$00096706,$006e0108,$ff66588f + dc.l $f21fd040,$4cdf003c,$f23c9000,$00000000 + dc.l $f23c8800,$00000000,$4e753ffd,$00009a20 + dc.l $9a84fbcf,$f7980000,$00003ffd,$00009a20 + dc.l $9a84fbcf,$f7990000,$00003f80,$00000000 + dc.l $00000000,$00000000,$00004000,$00000000 + dc.l $00000000,$00000000,$00004120,$00000000 + dc.l $00000000,$00000000,$0000459a,$28000000 + dc.l $00000000,$00000000,$00000000,$00000303 + dc.l $02020302,$02030203,$030248e7,$3f20f227 + dc.l $e007f23c,$90000000,$00202d50,$ff582e00 + dc.l $422eff50,$0c2e0004,$ff4e6600,$00303010 + dc.l $02407fff,$22280004,$24280008,$5340e38a + dc.l $e3914a81,$6cf64a40,$6e0450ee,$ff500240 + dc.l $7fff3080,$21410004,$21420008,$2d50ff90 + dc.l $2d680004,$ff942d68,$0008ff98,$02ae7fff + dc.l $ffffff90,$4a2eff50,$67082c3c,$ffffecbb + dc.l $6038302e,$ff903d7c,$3fffff90,$f22e4800 + dc.l $ff900440,$3ffff200,$5022f23a,$4428ff1c + dc.l $f293000e,$f23a4823,$ff02f206,$6000600a + dc.l $f23a4823,$fee6f206,$6000f23c,$88000000 + dc.l $00004245,$4a876f04,$28076006,$28069887 + dc.l $52844a84,$6f180c84,$00000011,$6f127811 + dc.l $4a876f0c,$00ae0000,$2080ff64,$60027801 + dc.l $4a876e06,$be866d02,$2c072006,$52809084 + dc.l $48454245,$42424a80,$6c145245,$0c80ffff + dc.l $ecd46e08,$06800000,$00187418,$4480f23a + dc.l $4480fe98,$e9ee1682,$ff60e349,$d245e349 + dc.l $4aaeff58,$6c025281,$45fafec0,$16321800 + dc.l $e98bf203,$9000e88b,$4a03660a,$43fb0170 + dc.l $00000370,$6016e20b,$640a43fb,$01700000 + dc.l $03fe6008,$43fb0170,$00000490,$4283e288 + dc.l $6406f231,$48a33800,$06830000,$000c4a80 + dc.l $66ecf23c,$88000000,$0000f23c,$90000000 + dc.l $0010f210,$4800f200,$00184a45,$6608f200 + dc.l $04206000,$008e4a2e,$ff506700,$0072f227 + dc.l $e0023617,$02437fff,$00508000,$d6500443 + dc.l $3fffd669,$00240443,$3fffd669,$00300443 + dc.l $3fff6b00,$00480257,$80008757,$02507fff + dc.l $2f280008,$2f280004,$2f3c3fff,$0000f21f + dc.l $d080f21f,$48232f29,$002c2f29,$00282f3c + dc.l $3fff0000,$2f290038,$2f290034,$2f3c3fff + dc.l $0000f21f,$4823f21f,$48236016,$60fe4a42 + dc.l $670cf229,$48230024,$f2294823,$0030f200 + dc.l $0423f200,$a800f22e,$6800ff90,$45eeff90 + dc.l $08000009,$670e00aa,$00000001,$0008f22e + dc.l $4800ff90,$2d6eff60,$ff5402ae,$00000030 + dc.l $ff6048e7,$c0c02f2e,$ff542f2e,$ff5841ee + dc.l $ff90f210,$68004aae,$ff586c06,$00908000 + dc.l $00002f2e,$ff64f22e,$9000ff60,$f23c8800 + dc.l $00000000,$f22e4801,$ff90f200,$a800816e + dc.l $ff661d57,$ff64588f,$2d5fff58,$2d5fff54 + dc.l $4cdf0303,$2d6eff58,$ff902d6e,$ff54ff60 + dc.l $48454a45,$66ff0000,$0086f23a,$4500fcec + dc.l $20045380,$4283e288,$6406f231,$49233800 + dc.l $06830000,$000c4a80,$66ec4a2e,$ff50670a + dc.l $f2000018,$60ff0000,$0028f200,$0018f200 + dc.l $0838f293,$001a5386,$3a3c0001,$f23c9000 + dc.l $00000020,$f23a4523,$fcc26000,$fda8f23a + dc.l $4523fcb8,$f2000838,$f294005c,$f292000c + dc.l $f23a4420,$fca65286,$604c5286,$3a3c0001 + dc.l $f23c9000,$00000020,$6000fd7a,$f23a4500 + dc.l $fc6a2004,$4283e288,$6406f231,$49233800 + dc.l $06830000,$000c4a80,$66ecf200,$0018f200 + dc.l $0838f28e,$0012f23a,$4420fc60,$52865284 + dc.l $f23a4523,$fc56f23c,$90000000,$0010f200 + dc.l $082041ee,$ff84f210,$68002428,$00042628 + dc.l $000842a8,$000442a8,$00082010,$48406714 + dc.l $04800000,$3ffd4a80,$6e0a4480,$e28ae293 + dc.l $51c8fffa,$4a826604,$4a836710,$42810683 + dc.l $00000080,$d5810283,$ffffff80,$20045688 + dc.l $61ff0000,$02b04a2e,$ff506728,$f200003a + dc.l $f281000c,$f2064000,$f2000018,$602e4a87 + dc.l $6d08f23a,$4400fbe4,$6022f206,$4000f200 + dc.l $00186018,$f200003a,$f28e000a,$f23a4400 + dc.l $fb9a6008,$f2064000,$f2000018,$f2294820 + dc.l $0018f22e,$6800ff90,$242a0004,$262a0008 + dc.l $3012670e,$04403ffd,$4440e28a,$e29351c8 + dc.l $fffa4281,$06830000,$0080d581,$0283ffff + dc.l $ff807004,$41eeff54,$61ff0000,$0228202e + dc.l $ff54720c,$e2a8efee,$010cff84,$e2a8efee + dc.l $0404ff84,$4a006708,$00ae0000,$2080ff64 + dc.l $4280022e,$000fff84,$4aaeff58,$6c027002 + dc.l $4a866c02,$5280efee,$0002ff84,$f23c8800 + dc.l $00000000,$f21fd0e0,$4cdf04fc,$4e754002 + dc.l $0000a000,$00000000,$00004005,$0000c800 + dc.l $00000000,$0000400c,$00009c40,$00000000 + dc.l $00004019,$0000bebc,$20000000,$00004034 + dc.l $00008e1b,$c9bf0400,$00004069,$00009dc5 + dc.l $ada82b70,$b59e40d3,$0000c278,$1f49ffcf + dc.l $a6d541a8,$000093ba,$47c980e9,$8ce04351 + dc.l $0000aa7e,$ebfb9df9,$de8e46a3,$0000e319 + dc.l $a0aea60e,$91c74d48,$0000c976,$75868175 + dc.l $0c175a92,$00009e8b,$3b5dc53d,$5de57525 + dc.l $0000c460,$52028a20,$979b4002,$0000a000 + dc.l $00000000,$00004005,$0000c800,$00000000 + dc.l $0000400c,$00009c40,$00000000,$00004019 + dc.l $0000bebc,$20000000,$00004034,$00008e1b + dc.l $c9bf0400,$00004069,$00009dc5,$ada82b70 + dc.l $b59e40d3,$0000c278,$1f49ffcf,$a6d641a8 + dc.l $000093ba,$47c980e9,$8ce04351,$0000aa7e + dc.l $ebfb9df9,$de8e46a3,$0000e319,$a0aea60e + dc.l $91c74d48,$0000c976,$75868175,$0c185a92 + dc.l $00009e8b,$3b5dc53d,$5de57525,$0000c460 + dc.l $52028a20,$979b4002,$0000a000,$00000000 + dc.l $00004005,$0000c800,$00000000,$0000400c + dc.l $00009c40,$00000000,$00004019,$0000bebc + dc.l $20000000,$00004034,$00008e1b,$c9bf0400 + dc.l $00004069,$00009dc5,$ada82b70,$b59d40d3 + dc.l $0000c278,$1f49ffcf,$a6d541a8,$000093ba + dc.l $47c980e9,$8cdf4351,$0000aa7e,$ebfb9df9 + dc.l $de8d46a3,$0000e319,$a0aea60e,$91c64d48 + dc.l $0000c976,$75868175,$0c175a92,$00009e8b + dc.l $3b5dc53d,$5de47525,$0000c460,$52028a20 + dc.l $979a48e7,$ff007e01,$53802802,$2a03e9c2 + dc.l $1003e782,$e9c36003,$e7838486,$e385e394 + dc.l $4846d346,$d6854e71,$d5844e71,$d3464846 + dc.l $4a476712,$4847e947,$de4110c7,$48474247 + dc.l $51c8ffc8,$60124847,$3e014847,$524751c8 + dc.l $ffba4847,$e94f10c7,$4cdf00ff,$4e757001 + dc.l $610000d6,$3d7c0121,$000a6000,$007e7002 + dc.l $610000c6,$3d7c0141,$000a606e,$70046100 + dc.l $00b83d7c,$0101000a,$60607008,$610000aa + dc.l $3d7c0161,$000a6052,$700c6100,$009c3d7c + dc.l $0161000a,$60447001,$6100008e,$3d7c00a1 + dc.l $000a6036,$70026100,$00803d7c,$00c1000a + dc.l $60287004,$61000072,$3d7c0081,$000a601a + dc.l $70086100,$00643d7c,$00e1000a,$600c700c + dc.l $61000056,$3d7c00e1,$000a2d6e,$ff680006 + dc.l $f22ed0c0,$ffdcf22e,$9c00ff60,$4cee0303 + dc.l $ff9c4e5e,$2f172f6f,$00080004,$2f6f000c + dc.l $00082f7c,$00000001,$000c3f6f,$0006000c + dc.l $3f7c4008,$00060817,$00056706,$08ef0002 + dc.l $000d60ff,$ffff95f4,$122eff41,$02010038 + dc.l $0c010018,$6700000c,$0c010020,$67000060 + dc.l $4e75122e,$ff410241,$0007323b,$12064efb + dc.l $10020010,$0016001c,$00200024,$0028002c + dc.l $003091ae,$ffa44e75,$91aeffa8,$4e7595c0 + dc.l $4e7597c0,$4e7599c0,$4e759bc0,$4e759196 + dc.l $4e750c2e,$0030000a,$6612082e,$00050004 + dc.l $660a4e7a,$880091c0,$4e7b8800,$4e754480 + dc.l $60a051fc,$00000000,$00000000,$00000000 diff -u --recursive --new-file v1.3.93/linux/arch/m68k/kernel/Makefile linux/arch/m68k/kernel/Makefile --- v1.3.93/linux/arch/m68k/kernel/Makefile Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/kernel/Makefile Mon Apr 1 21:46:31 1996 @@ -0,0 +1,21 @@ +# +# Makefile for the linux kernel. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now in the main makefile... + +.S.o: + $(CC) -D__ASSEMBLY__ -traditional -Wa,-m68030 -c $< -o $*.o + +all: kernel.o head.o +O_TARGET := kernel.o +O_OBJS := entry.o process.o traps.o ints.o signal.o ptrace.o \ + setup.o bios32.o sys_m68k.o console.o time.o +OX_OBJS = ksyms.o + +head.o: head.S + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.93/linux/arch/m68k/kernel/bios32.c linux/arch/m68k/kernel/bios32.c --- v1.3.93/linux/arch/m68k/kernel/bios32.c Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/kernel/bios32.c Wed Dec 27 22:46:21 1995 @@ -0,0 +1,7 @@ +/* + * bios 32 replacement + */ +unsigned long bios32_init(unsigned long memory_start, unsigned long memory_end) +{ + return memory_start; +} diff -u --recursive --new-file v1.3.93/linux/arch/m68k/kernel/console.c linux/arch/m68k/kernel/console.c --- v1.3.93/linux/arch/m68k/kernel/console.c Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/kernel/console.c Thu Apr 18 02:05:46 1996 @@ -0,0 +1,2561 @@ +/* + * linux/drivers/char/console.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ +/* + * console.c + * + * This module exports the console io functions: + * + * 'void do_keyboard_interrupt(void)' + * + * 'int vc_allocate(unsigned int console)' + * 'int vc_cons_allocated(unsigned int console)' + * 'int vc_resize(unsigned long lines, unsigned long cols)' + * 'int vc_resize_con(unsigned long lines, unsigned long cols, + * unsigned int currcons)' + * 'void vc_disallocate(unsigned int currcons)' + * + * 'unsigned long con_init(unsigned long)' + * 'int con_open(struct tty_struct *tty, struct file * filp)' + * 'void con_write(struct tty_struct * tty)' + * 'void console_print(const char * b)' + * 'void update_screen(int new_console)' + * + * 'void do_blank_screen(int)' + * 'void do_unblank_screen(void)' + * 'void poke_blanked_console(void)' + * + * 'unsigned short *screen_pos(int currcons, int w_offset, int viewed)' + * 'void complement_pos(int currcons, int offset)' + * 'void invert_screen(int currcons, int offset, int count, int shift)' + * + * 'void scrollback(int lines)' + * 'void scrollfront(int lines)' + * + * 'int con_get_font(char *)' + * 'int con_set_font(char *)' + * + * 'void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry)' + * 'int mouse_reporting(void)' + * + * 'unsigned long get_video_num_lines(unsigned int console)' + * 'unsigned long get_video_num_columns(unsigned int console)' + * 'unsigned long get_video_size_row(unsigned int console)' + * + * Hopefully this will be a rather complete VT102 implementation. + * + * Beeping thanks to John T Kohl. + * + * Virtual Consoles, Screen Blanking, Screen Dumping, Color, Graphics + * Chars, and VT100 enhancements by Peter MacDonald. + * + * Copy and paste function by Andrew Haylett, + * some enhancements by Alessandro Rubini. + * + * User definable mapping table and font loading by Eugene G. Crosser, + * + * + * Code to check for different video-cards mostly by Galen Hunt, + * + * + * Rudimentary ISO 10646/Unicode/UTF-8 character set support by + * Markus Kuhn, . + * + * Dynamic allocation of consoles, aeb@cwi.nl, May 1994 + * Resizing of consoles, aeb, 940926 + * + * Code for xterm like mouse click reporting by Peter Orbaek 20-Jul-94 + * + * + * 680x0 LINUX support by Arno Griffioen (arno@usn.nl) + * + * 9-Apr-94: Arno Griffioen: fixed scrolling and delete-char bug. + * Scrolling code moved to amicon.c + * + * 18-Apr-94: David Carter [carter@cs.bris.ac.uk]. 680x0 LINUX modified + * Integrated support for new low level driver `amicon_ocs.c' + * + */ + +#define BLANK 0x0020 +#undef CAN_LOAD_EGA_FONTS /* undefine if the user must not do this */ + +/* A bitmap for codes <32. A bit of 1 indicates that the code + * corresponding to that bit number invokes some special action + * (such as cursor movement) and should not be displayed as a + * glyph unless the disp_ctrl mode is explicitly enabled. + */ +#define CTRL_ACTION 0x0d00ff81 +#define CTRL_ALWAYS 0x0800f501 /* Cannot be overridden by disp_ctrl */ + +/* + * Here is the default bell parameters: 750HZ, 1/8th of a second + */ +#define DEFAULT_BELL_PITCH 750 +#define DEFAULT_BELL_DURATION (HZ/8) + +/* + * NOTE!!! We sometimes disable and enable interrupts for a short while + * (to put a word in video IO), but this will work even for keyboard + * interrupts. We know interrupts aren't enabled when getting a keyboard + * interrupt, as we use trap-gates. Hopefully all is well. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "../../../drivers/char/kbd_kern.h" +#include "../../../drivers/char/vt_kern.h" +#include "../../../drivers/char/consolemap.h" +#include "../../../drivers/char/selection.h" + + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +struct tty_driver console_driver; +static int console_refcount; +static struct tty_struct *console_table[MAX_NR_CONSOLES]; +static struct termios *console_termios[MAX_NR_CONSOLES]; +static struct termios *console_termios_locked[MAX_NR_CONSOLES]; + +static void vc_init(unsigned int console, int do_clear); + +static void update_attr(int currcons); +static void gotoxy(int currcons, int new_x, int new_y); +static void save_cur(int currcons); +static void blank_screen(void); +static void unblank_screen(void); +extern void change_console(unsigned int); +static inline void set_cursor(int currcons); +static void reset_terminal(int currcons, int do_clear); +extern void reset_vc(unsigned int new_console); +extern void vt_init(void); +extern void register_console(void (*proc)(const char *)); +extern void vesa_blank(void); +extern void vesa_unblank(void); +extern void compute_shiftstate(void); +void poke_blanked_console(void); +void do_blank_screen(int); + +unsigned long video_num_lines; +unsigned long video_num_columns; +unsigned long video_size_row; + +static int printable = 0; /* Is console ready for printing? */ +unsigned long video_font_height; /* Height of current screen font */ +unsigned long video_scan_lines; /* Number of scan lines on screen */ +unsigned long default_font_height; /* Height of default screen font */ +int video_mode_512ch = 0; /* 512-character mode */ +static unsigned short console_charmask = 0x0ff; + +static unsigned short *vc_scrbuf[MAX_NR_CONSOLES]; + +/* used by kbd_bh - set by keyboard_interrupt */ + int do_poke_blanked_console = 0; + int console_blanked = 0; +static int blankinterval = 10*60*HZ; + +static struct vc { + struct vc_data *d; + + /* might add scrmem, vt_struct, kbd at some time, + to have everything in one place - the disadvantage + would be that vc_cons etc can no longer be static */ +} vc_cons [MAX_NR_CONSOLES]; +struct consw *conswitchp; + +#define cols (vc_cons[currcons].d->vc_cols) +#define rows (vc_cons[currcons].d->vc_rows) +#define size_row (vc_cons[currcons].d->vc_size_row) +#define screenbuf_size (vc_cons[currcons].d->vc_screenbuf_size) +#define cons_num (vc_cons[currcons].d->vc_num) +#define origin (vc_cons[currcons].d->vc_origin) +#define scr_end (vc_cons[currcons].d->vc_scr_end) +#define pos (vc_cons[currcons].d->vc_pos) +#define top (vc_cons[currcons].d->vc_top) +#define bottom (vc_cons[currcons].d->vc_bottom) +#define x (vc_cons[currcons].d->vc_x) +#define y (vc_cons[currcons].d->vc_y) +#define vc_state (vc_cons[currcons].d->vc_state) +#define npar (vc_cons[currcons].d->vc_npar) +#define par (vc_cons[currcons].d->vc_par) +#define ques (vc_cons[currcons].d->vc_ques) +#define attr (vc_cons[currcons].d->vc_attr) +#define saved_x (vc_cons[currcons].d->vc_saved_x) +#define saved_y (vc_cons[currcons].d->vc_saved_y) +#define translate (vc_cons[currcons].d->vc_translate) +#define G0_charset (vc_cons[currcons].d->vc_G0_charset) +#define G1_charset (vc_cons[currcons].d->vc_G1_charset) +#define saved_G0 (vc_cons[currcons].d->vc_saved_G0) +#define saved_G1 (vc_cons[currcons].d->vc_saved_G1) +#define utf (vc_cons[currcons].d->vc_utf) +#define utf_count (vc_cons[currcons].d->vc_utf_count) +#define utf_char (vc_cons[currcons].d->vc_utf_char) +#define video_mem_start (vc_cons[currcons].d->vc_video_mem_start) +#define video_mem_end (vc_cons[currcons].d->vc_video_mem_end) +#define video_erase_char (vc_cons[currcons].d->vc_video_erase_char) +#define disp_ctrl (vc_cons[currcons].d->vc_disp_ctrl) +#define toggle_meta (vc_cons[currcons].d->vc_toggle_meta) +#define decscnm (vc_cons[currcons].d->vc_decscnm) +#define decom (vc_cons[currcons].d->vc_decom) +#define decawm (vc_cons[currcons].d->vc_decawm) +#define deccm (vc_cons[currcons].d->vc_deccm) +#define decim (vc_cons[currcons].d->vc_decim) +#define deccolm (vc_cons[currcons].d->vc_deccolm) +#define need_wrap (vc_cons[currcons].d->vc_need_wrap) +#define has_scrolled (vc_cons[currcons].d->vc_has_scrolled) +#define kmalloced (vc_cons[currcons].d->vc_kmalloced) +#define report_mouse (vc_cons[currcons].d->vc_report_mouse) +#define can_do_color (vc_cons[currcons].d->vc_can_do_color) +#define color (vc_cons[currcons].d->vc_color) +#define s_color (vc_cons[currcons].d->vc_s_color) +#define def_color (vc_cons[currcons].d->vc_def_color) +#define foreground (color & 0x0f) +#define background (color & 0xf0) +#define charset (vc_cons[currcons].d->vc_charset) +#define s_charset (vc_cons[currcons].d->vc_s_charset) +#define intensity (vc_cons[currcons].d->vc_intensity) +#define underline (vc_cons[currcons].d->vc_underline) +#define blink (vc_cons[currcons].d->vc_blink) +#define reverse (vc_cons[currcons].d->vc_reverse) +#define s_intensity (vc_cons[currcons].d->vc_s_intensity) +#define s_underline (vc_cons[currcons].d->vc_s_underline) +#define s_blink (vc_cons[currcons].d->vc_s_blink) +#define s_reverse (vc_cons[currcons].d->vc_s_reverse) +#define ulcolor (vc_cons[currcons].d->vc_ulcolor) +#define halfcolor (vc_cons[currcons].d->vc_halfcolor) +#define tab_stop (vc_cons[currcons].d->vc_tab_stop) +#define bell_pitch (vc_cons[currcons].d->vc_bell_pitch) +#define bell_duration (vc_cons[currcons].d->vc_bell_duration) +#define sw (vc_cons[currcons].d->vc_sw) + +#define vcmode (vt_cons[currcons]->vc_mode) +#if 0 /* XXX */ +#define vtmode (vt_cons[currcons]->vt_mode) +#define vtpid (vt_cons[currcons]->vt_pid) +#define vtnewvt (vt_cons[currcons]->vt_newvt) +#endif + +#define structsize (sizeof(struct vc_data) + sizeof(struct vt_struct)) + +int vc_cons_allocated(unsigned int i) +{ + return (i < MAX_NR_CONSOLES && vc_cons[i].d); +} + +int vc_allocate(unsigned int currcons) /* return 0 on success */ +{ + if (currcons >= MAX_NR_CONSOLES) + return -ENODEV; + if (!vc_cons[currcons].d) { + long p, q; + + /* prevent users from taking too much memory */ + if (currcons >= MAX_NR_USER_CONSOLES && !suser()) + return -EPERM; + + /* due to the granularity of kmalloc, we waste some memory here */ + /* the alloc is done in two steps, to optimize the common situation + of a 25x80 console (structsize=216, screenbuf_size=4000) */ + p = (long) kmalloc(structsize, GFP_KERNEL); + if (!p) + return -ENOMEM; + vc_cons[currcons].d = (struct vc_data *) p; + vt_cons[currcons] = (struct vt_struct *)(p+sizeof(struct vc_data)); + + /* ++Geert: sw->con_init determines console size */ + sw = conswitchp; + cons_num = currcons; + sw->con_init (vc_cons[currcons].d); + size_row = cols<<1; + screenbuf_size = rows*size_row; + + q = (long) kmalloc(screenbuf_size, GFP_KERNEL); + if (!q) { + kfree_s((char *) p, structsize); + vc_cons[currcons].d = NULL; + return -ENOMEM; + } + vc_scrbuf[currcons] = (unsigned short *) q; + kmalloced = 1; + vc_init (currcons, 1); + } + return 0; +} + +/* + * Change # of rows and columns (0 means the size of fg_console) + * [this is to be used together with some user program + * like resize that changes the hardware videomode] + */ +int vc_resize(unsigned long lines, unsigned long columns) +{ + unsigned long cc, ll, ss, sr; + unsigned long occ, oll, oss, osr; + unsigned short *p; + unsigned int currcons = fg_console, i; + unsigned short *newscreens[MAX_NR_CONSOLES]; + long ol, nl, rlth, rrem; + + cc = (columns ? columns : cols); + ll = (lines ? lines : rows); + sr = cc << 1; + ss = sr * ll; + + /* + * Some earlier version had all consoles of potentially + * different sizes, but that was really messy. + * So now we only change if there is room for all consoles + * of the same size. + */ + for (currcons = 0; currcons < MAX_NR_CONSOLES; currcons++) { + if (!vc_cons_allocated(currcons)) + newscreens[currcons] = 0; + else { + p = (unsigned short *) kmalloc(ss, GFP_USER); + if (!p) { + for (i = 0; i< currcons; i++) + if (newscreens[i]) + kfree_s(newscreens[i], ss); + return -ENOMEM; + } + newscreens[currcons] = p; + } + } + +#if 0 /* XXX */ + get_scrmem(fg_console); +#endif + + for (currcons = 0; currcons < MAX_NR_CONSOLES; currcons++) { + if (!vc_cons_allocated(currcons)) + continue; + + oll = rows; + occ = cols; + osr = size_row; + oss = screenbuf_size; + + rows = ll; + cols = cc; + size_row = sr; + screenbuf_size = ss; + + rlth = MIN(osr, sr); + rrem = sr - rlth; + ol = origin; + nl = (long) newscreens[currcons]; + if (ll < oll) + ol += (oll - ll) * osr; + + update_attr(currcons); + while (ol < scr_end) { + /* ++Geert: TODO: Because the attributes have different meanings + on monochrome and color, they should really be converted if + can_do_color changes... */ + memcpyw((unsigned short *) nl, (unsigned short *) ol, rlth); + if (rrem) + memsetw((void *)(nl + rlth), video_erase_char, rrem); + ol += osr; + nl += sr; + } + + if (kmalloced) + kfree_s(vc_scrbuf[currcons], oss); + vc_scrbuf[currcons] = newscreens[currcons]; + kmalloced = 1; + screenbuf_size = ss; + + origin = (long) video_mem_start = vc_scrbuf[currcons]; + scr_end = video_mem_end = ((long) video_mem_start) + ss; + + if (scr_end > nl) + memsetw((void *) nl, video_erase_char, scr_end - nl); + + /* do part of a reset_terminal() */ + top = 0; + bottom = rows; + gotoxy(currcons, x, y); + save_cur(currcons); + } + +#if 0 /* XXX */ + set_scrmem(fg_console, 0); + set_origin(fg_console); +#endif /* XXX */ + update_screen(fg_console); + set_cursor(fg_console); + + return 0; +} + +/* + * ++Geert: Change # of rows and columns for one specific console. + * Of course it's not messy to have all consoles of potentially different sizes, + * except on PCish hardware :-) + * + * This is called by the low level console driver (arch/m68k/console/fbcon.c or + * arch/m68k/console/txtcon.c) + */ +void vc_resize_con(unsigned long lines, unsigned long columns, + unsigned int currcons) +{ + unsigned long cc, ll, ss, sr; + unsigned long occ, oll, oss, osr; + unsigned short *newscreen; + long ol, nl, rlth, rrem; + struct winsize ws; + + if (!columns || !lines || currcons >= MAX_NR_CONSOLES) + return; + + cc = columns; + ll = lines; + sr = cc << 1; + ss = sr * ll; + + if (!vc_cons_allocated(currcons)) + newscreen = 0; + else if (!(newscreen = (unsigned short *) kmalloc(ss, GFP_USER))) + return; + + if (vc_cons_allocated(currcons)) { + oll = rows; + occ = cols; + osr = size_row; + oss = screenbuf_size; + + rows = ll; + cols = cc; + size_row = sr; + screenbuf_size = ss; + + rlth = MIN(osr, sr); + rrem = sr - rlth; + ol = origin; + nl = (long) newscreen; + if (ll < oll) + ol += (oll - ll) * osr; + + update_attr(currcons); + while (ol < scr_end) { + /* ++Geert: TODO: Because the attributes have different meanings + on monochrome and color, they should really be converted if + can_do_color changes... */ + memcpyw((unsigned short *) nl, (unsigned short *) ol, rlth); + if (rrem) + memsetw((void *)(nl + rlth), video_erase_char, rrem); + ol += osr; + nl += sr; + } + + if (kmalloced) + kfree_s(vc_scrbuf[currcons], oss); + vc_scrbuf[currcons] = newscreen; + kmalloced = 1; + screenbuf_size = ss; + + origin = (long) video_mem_start = vc_scrbuf[currcons]; + scr_end = video_mem_end = ((long)video_mem_start) + ss; + + if (scr_end > nl) + memsetw((void *) nl, video_erase_char, scr_end - nl); + + /* do part of a reset_terminal() */ + top = 0; + bottom = rows; + gotoxy(currcons, x, y); + save_cur(currcons); + + ws.ws_row = rows; + ws.ws_col = cols; + if (memcmp(&ws, &console_table[currcons]->winsize, sizeof (struct winsize)) && + console_table[currcons]->pgrp > 0) + kill_pg(console_table[currcons]->pgrp, SIGWINCH, 1); + console_table[currcons]->winsize = ws; + } + + if (currcons == fg_console) + update_screen(fg_console); +} + +void vc_disallocate(unsigned int currcons) +{ + if (vc_cons_allocated(currcons)) { + if (kmalloced) + kfree_s(vc_scrbuf[currcons], screenbuf_size); + if (currcons >= MIN_NR_CONSOLES) + kfree_s(vc_cons[currcons].d, structsize); + vc_cons[currcons].d = 0; + } +} + + +#define set_kbd(x) set_vc_kbd_mode(kbd_table+currcons,x) +#define clr_kbd(x) clr_vc_kbd_mode(kbd_table+currcons,x) +#define is_kbd(x) vc_kbd_mode(kbd_table+currcons,x) + +#define decarm VC_REPEAT +#define decckm VC_CKMODE +#define kbdapplic VC_APPLIC +#define lnm VC_CRLF + +/* + * this is what the terminal answers to a ESC-Z or csi0c query. + */ +#define VT100ID "\033[?1;2c" +#define VT102ID "\033[?6c" + +static unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7, + 8,12,10,14, 9,13,11,15 }; + +/* + * gotoxy() must verify all boundaries, because the arguments + * might also be negative. If the given position is out of + * bounds, the cursor is placed at the nearest margin. + */ +static void gotoxy(int currcons, int new_x, int new_y) +{ + int max_y; + + if (new_x < 0) + x = 0; + else + if (new_x >= cols) + x = cols - 1; + else + x = new_x; + if (decom) { + new_y += top; + max_y = bottom; + } else + max_y = rows; + if (new_y < 0) + y = 0; + else + if (new_y >= max_y) + y = max_y - 1; + else + y = new_y; + pos = video_mem_start + y * cols + x; + need_wrap = 0; +} + +static void hide_cursor(int currcons) +{ + sw->con_cursor(vc_cons[currcons].d,CM_ERASE); + return; +} + +static void set_cursor(int currcons) +{ + if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS) + return; + if (deccm) + sw->con_cursor(vc_cons[currcons].d,CM_DRAW); + else + hide_cursor(currcons); + return; +} + +void no_scroll(char *str, int *ints) +{ + /* + * no_scroll currently does nothing on the m68k. + */ +} + +/* + * Arno: + * Why do we need these? The keyboard code doesn't seem to do anything + * with them either... + */ +void scrollfront(int l) +{ + return; +} + +void scrollback(int l) +{ + return; +} + +static void scrup(int currcons, unsigned int t, unsigned int b, + int nr) +{ + unsigned short *p; + int i; + + if (b > rows || t >= b) + return; + + memmove (video_mem_start + t * cols, + video_mem_start + (t + nr) * cols, + (b - t - nr) * cols * 2); + + p = video_mem_start + (b - nr) * cols; + for (i = nr * cols; i > 0; i--) + *p++ = video_erase_char; + + if (currcons != fg_console) + return; +/* + * Arno: + * Scrolling has now been moved to amicon.c where it should have + * been all along. + */ + sw->con_scroll(vc_cons[currcons].d, t, b, SM_UP, nr); + + return; + +} + +static void scrdown(int currcons, unsigned int t, unsigned int b, + int nr) +{ + unsigned short *p; + int i; + + if (b > rows || t >= b) + return; + + memmove (video_mem_start + (t + nr) * cols, + video_mem_start + t * cols, + (b - t - nr) * cols * 2); + + p = video_mem_start + t * cols; + for (i = nr * cols; i > 0; i--) + *p++ = video_erase_char; + + if (currcons != fg_console) + return; +/* + * Arno: + * Scrolling has now been moved to amicon.c where it should have + * been all along. + */ + sw->con_scroll(vc_cons[currcons].d, t, b, SM_DOWN, nr); + + return; +} + +static void lf(int currcons) +{ + /* don't scroll if above bottom of scrolling region, or + * if below scrolling region + */ + if (y+1 == bottom) + scrup(currcons,top,bottom, 1); + else if (y < rows-1) { + y++; + pos += cols; + } + need_wrap = 0; +} + +static void ri(int currcons) +{ + /* don't scroll if below top of scrolling region, or + * if above scrolling region + */ + if (y == top) + scrdown(currcons,top,bottom, 1); + else if (y > 0) { + y--; + pos -= cols; + } + need_wrap = 0; +} + +static inline void cr(int currcons) +{ + pos -= x; + need_wrap = x = 0; +} + +static inline void bs(int currcons) +{ + if (x) { + pos--; + x--; + need_wrap = 0; + } +} + +static inline void del(int currcons) +{ + /* ignored */ +} + +static void csi_J(int currcons, int vpar) +{ + unsigned long count; + unsigned short *start; + + switch (vpar) { + case 0: /* erase from cursor to end of display */ + count = (video_mem_start + + cols * rows + - pos); + start = pos; + if (currcons != fg_console) + break; + /* 680x0 do in two stages */ + sw->con_clear(vc_cons[currcons].d,y,x,1,cols-x); + sw->con_clear(vc_cons[currcons].d,y+1,0,rows-y-1, cols); + break; + case 1: /* erase from start to cursor */ + count = pos - video_mem_start + 1; + start = video_mem_start; + if (currcons != fg_console) + break; + /* 680x0 do in two stages */ + sw->con_clear(vc_cons[currcons].d,0,0,y, cols); + sw->con_clear(vc_cons[currcons].d,y,0,1,x + 1); + break; + case 2: /* erase whole display */ + count = cols * rows; + start = video_mem_start; + if (currcons != fg_console) + break; + sw->con_clear(vc_cons[currcons].d,0,0,rows, cols); + break; + default: + return; + } + while (count-- > 0) + *start++ = video_erase_char; + need_wrap = 0; +} + +static void csi_K(int currcons, int vpar) +{ + unsigned long count; + unsigned short *start; + + switch (vpar) { + case 0: /* erase from cursor to end of line */ + count = cols - x; + start = pos; + if (currcons != fg_console) + break; + sw->con_clear(vc_cons[currcons].d,y,x,1,cols-x); + break; + case 1: /* erase from start of line to cursor */ + start = pos - x; + count = x + 1; + if (currcons != fg_console) + break; + sw->con_clear(vc_cons[currcons].d,y,0,1,x + 1); + break; + case 2: /* erase whole line */ + start = pos - x; + count = cols; + if (currcons != fg_console) + break; + sw->con_clear(vc_cons[currcons].d,y,0,1,cols); + break; + default: + return; + } + while (count-- > 0) + *start++ = video_erase_char; + need_wrap = 0; +} + +static void csi_X(int currcons, int vpar) /* erase the following vpar positions */ +{ /* not vt100? */ + unsigned long count; + unsigned short * start; + + if (!vpar) + vpar++; + + start=pos; + count=(vpar > cols-x) ? (cols-x) : vpar; + + if (currcons == fg_console) + sw->con_clear(vc_cons[currcons].d,y,x,1,count); + + while (count-- > 0) + *start++ = video_erase_char; + need_wrap = 0; +} + +/* + * Arno: + * On 680x0 attributes are currently not used. This piece of code + * seems hardware independent, but uses the EGA/VGA way of representing + * attributes. + * TODO: modify for 680x0 and add attribute processing to putc code. + * + * ++roman: I completely changed the attribute format for monochrome + * mode (!can_do_color). The formerly used MDA (monochrome display + * adapter) format didn't allow the combination of certain effects. + * Now the attribute is just a bit vector: + * Bit 0..1: intensity (0..2) + * Bit 2 : underline + * Bit 3 : reverse + * Bit 7 : blink + */ +static void update_attr(int currcons) +{ + if (!can_do_color) { + /* Special treatment for monochrome */ + attr = intensity | + (underline ? 4 : 0) | + ((reverse ^ decscnm) ? 8 : 0) | + (blink ? 0x80 : 0); + video_erase_char = ' ' | ((reverse ^ decscnm) ? 0x800 : 0); + return; + } + + attr = color; + if (underline) + attr = (attr & 0xf0) | ulcolor; + else if (intensity == 0) + attr = (attr & 0xf0) | halfcolor; + if (reverse ^ decscnm) + attr = reverse_video_char(attr); + if (blink) + attr ^= 0x80; + if (intensity == 2) + attr ^= 0x08; + if (decscnm) + video_erase_char = (reverse_video_char(color) << 8) | ' '; + else + video_erase_char = (color << 8) | ' '; +} + +static void default_attr(int currcons) +{ + intensity = 1; + underline = 0; + reverse = 0; + blink = 0; + color = def_color; +} + +static void csi_m(int currcons) +{ + int i; + + for (i=0;i<=npar;i++) + switch (par[i]) { + case 0: /* all attributes off */ + default_attr(currcons); + break; + case 1: + intensity = 2; + break; + case 2: + intensity = 0; + break; + case 4: + underline = 1; + break; + case 5: + blink = 1; + break; + case 7: + reverse = 1; + break; + case 10: /* ANSI X3.64-1979 (SCO-ish?) + * Select primary font, don't display + * control chars if defined, don't set + * bit 8 on output. + */ + translate = set_translate(charset == 0 + ? G0_charset + : G1_charset); + disp_ctrl = 0; + toggle_meta = 0; + break; + case 11: /* ANSI X3.64-1979 (SCO-ish?) + * Select first alternate font, let's + * chars < 32 be displayed as ROM chars. + */ + translate = set_translate(IBMPC_MAP); + disp_ctrl = 1; + toggle_meta = 0; + break; + case 12: /* ANSI X3.64-1979 (SCO-ish?) + * Select second alternate font, toggle + * high bit before displaying as ROM char. + */ + translate = set_translate(IBMPC_MAP); + disp_ctrl = 1; + toggle_meta = 1; + break; + case 21: + case 22: + intensity = 1; + break; + case 24: + underline = 0; + break; + case 25: + blink = 0; + break; + case 27: + reverse = 0; + break; + case 38: /* ANSI X3.64-1979 (SCO-ish?) + * Enables underscore, white foreground + * with white underscore (Linux - use + * default foreground). + */ + color = (def_color & 0x0f) | background; + underline = 1; + break; + case 39: /* ANSI X3.64-1979 (SCO-ish?) + * Disable underline option. + * Reset colour to default? It did this + * before... + */ + color = (def_color & 0x0f) | background; + underline = 0; + break; + case 49: + color = (def_color & 0xf0) | foreground; + break; + default: + if (par[i] >= 30 && par[i] <= 37) + color = color_table[par[i]-30] + | background; + else if (par[i] >= 40 && par[i] <= 47) + color = (color_table[par[i]-40]<<4) + | foreground; + break; + } + update_attr(currcons); +} + +static void respond_string(const char * p, struct tty_struct * tty) +{ + while (*p) { + tty_insert_flip_char(tty, *p, 0); + p++; + } + tty_schedule_flip(tty); +} + +static void cursor_report(int currcons, struct tty_struct * tty) +{ + char buf[40]; + + sprintf(buf, "\033[%ld;%ldR", y + (decom ? top+1 : 1), x+1); + respond_string(buf, tty); +} + +static inline void status_report(struct tty_struct * tty) +{ + respond_string("\033[0n", tty); /* Terminal ok */ +} + +static inline void respond_ID(struct tty_struct * tty) +{ + respond_string(VT102ID, tty); +} + +void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry) +{ + char buf[8]; + + sprintf(buf, "\033[M%c%c%c", (char)(' ' + butt), (char)('!' + mrx), + (char)('!' + mry)); + respond_string(buf, tty); +} + +/* invoked via ioctl(TIOCLINUX) */ +int mouse_reporting(void) +{ + int currcons = fg_console; + + return report_mouse; +} + +static inline unsigned short *screenpos(int currcons, int offset, int viewed) +{ + unsigned short *p = (unsigned short *)(origin + offset); +#if 0 + if (viewed && currcons == fg_console) + p -= (__real_origin - __origin); +#endif + return p; +} + +/* Note: inverting the screen twice should revert to the original state */ +void invert_screen(int currcons, int offset, int count, int viewed) +{ + unsigned short *p; + unsigned short xx, yy, oldattr; + + count /= 2; + p = screenpos(currcons, offset, viewed); + xx = (offset >> 1) % cols; + yy = (offset >> 1) / cols; + oldattr = attr; + if (can_do_color) + while (count--) { + unsigned short old = scr_readw(p); + unsigned short new = reverse_video_short(old); + scr_writew(new, p); + p++; + if (currcons != fg_console) + continue; + attr = new >> 8; + sw->con_putc(vc_cons[currcons].d, new & 0xff, yy, xx); + if (++xx == cols) + xx = 0, ++yy; + } + else + while (count--) { + unsigned short old = scr_readw(p); + unsigned short new = old ^ 0x800; + scr_writew(new, p); + p++; + if (currcons != fg_console) + continue; + attr = new >> 8; + sw->con_putc(vc_cons[currcons].d, new & 0xff, yy, xx); + if (++xx == cols) + xx = 0, ++yy; + } + attr = oldattr; +} + +/* used by selection: complement pointer position */ +void complement_pos(int currcons, int offset) +{ + static unsigned short *p = NULL; + static unsigned short old = 0; + static unsigned short oldx = 0, oldy = 0; + unsigned short new, oldattr; + + oldattr = attr; + if (p) { + scr_writew(old, p); + if (currcons == fg_console) { + attr = old >> 8; + sw->con_putc(vc_cons[currcons].d, old & 0xff, oldy, oldx); + attr = oldattr; + } + } + if (offset == -1) + p = NULL; + else { + p = screenpos(currcons, offset, 1); + old = scr_readw(p); + oldx = (offset >> 1) % cols; + oldy = (offset >> 1) / cols; + if (can_do_color) + new = old ^ 0x7700; + else + new = old ^ 0x800; + scr_writew(new, p); + if (currcons == fg_console) { + attr = new >> 8; + sw->con_putc(vc_cons[currcons].d, new & 0xff, oldy, oldx); + attr = oldattr; + } + } +} + +/* used by selection */ +unsigned short screen_word(int currcons, int offset, int viewed) +{ + return scr_readw(screenpos(currcons, offset, viewed)); +} + +/* used by selection - convert a screen word to a glyph number */ +int scrw2glyph(unsigned short scr_word) +{ + return ( video_mode_512ch ) + ? ((scr_word & 0x0800) >> 3) + (scr_word & 0x00ff) + : scr_word & 0x00ff; +} + +/* used by vcs - note the word offset */ +unsigned short *screen_pos(int currcons, int w_offset, int viewed) +{ + return screenpos(currcons, 2 * w_offset, viewed); +} + +void getconsxy(int currcons, char *p) +{ + p[0] = x; + p[1] = y; +} + +void putconsxy(int currcons, char *p) +{ + gotoxy(currcons, p[0], p[1]); + set_cursor(currcons); +} + +static void set_mode(int currcons, int on_off) +{ + int i; + + for (i=0; i<=npar; i++) + if (ques) switch(par[i]) { /* DEC private modes set/reset */ + case 1: /* Cursor keys send ^[Ox/^[[x */ + if (on_off) + set_kbd(decckm); + else + clr_kbd(decckm); + break; + case 3: /* 80/132 mode switch unimplemented */ + deccolm = on_off; +#if 0 + (void) vc_resize(rows, deccolm ? 132 : 80); + /* this alone does not suffice; some user mode + utility has to change the hardware regs */ +#endif + break; + case 5: /* Inverted screen on/off */ + if (decscnm != on_off) { + decscnm = on_off; + invert_screen(currcons, 0, screenbuf_size, 0); + update_attr(currcons); + } + break; + case 6: /* Origin relative/absolute */ + decom = on_off; + gotoxy(currcons,0,0); + break; + case 7: /* Autowrap on/off */ + decawm = on_off; + break; + case 8: /* Autorepeat on/off */ + if (on_off) + set_kbd(decarm); + else + clr_kbd(decarm); + break; + case 9: + report_mouse = on_off ? 1 : 0; + break; + case 25: /* Cursor on/off */ + deccm = on_off; + set_cursor(currcons); + break; + case 1000: + report_mouse = on_off ? 2 : 0; + break; + } else switch(par[i]) { /* ANSI modes set/reset */ + case 3: /* Monitor (display ctrls) */ + disp_ctrl = on_off; + break; + case 4: /* Insert Mode on/off */ + decim = on_off; + break; + case 20: /* Lf, Enter == CrLf/Lf */ + if (on_off) + set_kbd(lnm); + else + clr_kbd(lnm); + break; + } +} + +static void setterm_command(int currcons) +{ + switch(par[0]) { + case 1: /* set color for underline mode */ + if (can_do_color && par[1] < 16) { + ulcolor = color_table[par[1]]; + if (underline) + update_attr(currcons); + } + break; + case 2: /* set color for half intensity mode */ + if (can_do_color && par[1] < 16) { + halfcolor = color_table[par[1]]; + if (intensity == 0) + update_attr(currcons); + } + break; + case 8: /* store colors as defaults */ + def_color = attr; + default_attr(currcons); + update_attr(currcons); + break; + case 9: /* set blanking interval */ + blankinterval = ((par[1] < 60) ? par[1] : 60) * 60 * HZ; + poke_blanked_console(); + break; + case 10: /* set bell frequency in Hz */ + if (npar >= 1) + bell_pitch = par[1]; + else + bell_pitch = DEFAULT_BELL_PITCH; + break; + case 11: /* set bell duration in msec */ + if (npar >= 1) + bell_duration = (par[1] < 2000) ? + par[1]*HZ/1000 : 0; + else + bell_duration = DEFAULT_BELL_DURATION; + break; + case 12: /* bring specified console to the front */ + if (par[1] >= 1 && vc_cons_allocated(par[1]-1)) + update_screen(par[1]-1); + break; + case 13: /* unblank the screen */ + unblank_screen(); + break; + } +} + +static void insert_char(int currcons) +{ + int i; + unsigned short *p = pos; + + for (i = cols - x - 2; i >= 0; i--) + p[i + 1] = p[i]; + *pos = video_erase_char; + need_wrap = 0; + + if (currcons != fg_console) + return; + + /* Arno: + * Move the remainder of the line (-1 character) one spot to the right + */ + sw->con_bmove(vc_cons[currcons].d,y,x,y,x+1,1,(cols-x-1)); + /* + * Print the erase char on the current position + */ + sw->con_putc(vc_cons[currcons].d,(video_erase_char & 0x00ff),y,x); +} + +static void csi_at(int currcons, unsigned int nr) +{ + int i; + unsigned short *p; + + if (nr > cols - x) + nr = cols - x; + else if (!nr) + nr = 1; + + p = pos + cols - x - nr; + while (--p >= pos) + p[nr] = *p; + for (i = 0; i < nr; i++) + *++p = video_erase_char; + need_wrap = 0; + + if (currcons != fg_console) + return; + + sw->con_bmove (vc_cons[currcons].d, y, x, y, x + nr, + 1, cols - x - nr); + while (nr--) + sw->con_putc (vc_cons[currcons].d, video_erase_char & 0x00ff, + y, x + nr); +} + +static void csi_L(int currcons, unsigned int nr) +{ + if (nr > rows) + nr = rows; + else if (!nr) + nr = 1; + scrdown (currcons, y, bottom, nr); + need_wrap = 0; +} + +static void csi_P(int currcons, unsigned int nr) +{ + int i; + unsigned short *p, *end; + + if (nr > cols - x) + nr = cols - x; + else if (!nr) + nr = 1; + + p = pos; + end = pos + cols - x - nr; + while (p < end) + *p = p[nr], p++; + for (i = 0; i < nr; i++) + *p++ = video_erase_char; + need_wrap = 0; + + if (currcons != fg_console) + return; + + sw->con_bmove (vc_cons[currcons].d, y, x + nr, y, x, + 1, cols - x - nr); + + while (nr--) + sw->con_putc (vc_cons[currcons].d, video_erase_char & 0x00ff, + y, cols - 1 - nr); +} + +static void csi_M(int currcons, unsigned int nr) +{ + if (nr > rows) + nr = rows; + else if (!nr) + nr=1; + scrup (currcons, y, bottom, nr); + need_wrap = 0; +} + +static void save_cur(int currcons) +{ + saved_x = x; + saved_y = y; + s_intensity = intensity; + s_underline = underline; + s_blink = blink; + s_reverse = reverse; + s_charset = charset; + s_color = color; + saved_G0 = G0_charset; + saved_G1 = G1_charset; +} + +static void restore_cur(int currcons) +{ + gotoxy(currcons,saved_x,saved_y); + intensity = s_intensity; + underline = s_underline; + blink = s_blink; + reverse = s_reverse; + charset = s_charset; + color = s_color; + G0_charset = saved_G0; + G1_charset = saved_G1; + translate = set_translate(charset ? G1_charset : G0_charset); + update_attr(currcons); + need_wrap = 0; +} + +enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey, + EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd, + ESpalette }; + +static void reset_terminal(int currcons, int do_clear) +{ + top = 0; + bottom = rows; + vc_state = ESnormal; + ques = 0; + translate = set_translate(LAT1_MAP); + G0_charset = LAT1_MAP; + G1_charset = GRAF_MAP; + charset = 0; + need_wrap = 0; + report_mouse = 0; + utf = 0; + utf_count = 0; + + disp_ctrl = 0; + toggle_meta = 0; + + decscnm = 0; + decom = 0; + decawm = 1; + deccm = 1; + decim = 0; + + set_kbd(decarm); + clr_kbd(decckm); + clr_kbd(kbdapplic); + clr_kbd(lnm); + kbd_table[currcons].lockstate = 0; + kbd_table[currcons].slockstate = 0; + kbd_table[currcons].ledmode = LED_SHOW_FLAGS; + kbd_table[currcons].ledflagstate = kbd_table[currcons].default_ledflagstate; + set_leds(); + + default_attr(currcons); + update_attr(currcons); + + tab_stop[0] = 0x01010100; + tab_stop[1] = + tab_stop[2] = + tab_stop[3] = + tab_stop[4] = 0x01010101; + + bell_pitch = DEFAULT_BELL_PITCH; + bell_duration = DEFAULT_BELL_DURATION; + + gotoxy(currcons,0,0); + save_cur(currcons); + if (do_clear) + csi_J(currcons,2); +} + +/* + * Turn the Scroll-Lock LED on when the tty is stopped + */ +static void con_stop(struct tty_struct *tty) +{ + int console_num; + if (!tty) + return; + console_num = MINOR(tty->device) - (tty->driver.minor_start); + if (!vc_cons_allocated(console_num)) + return; + set_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK); + set_leds(); +} + +/* + * Turn the Scroll-Lock LED off when the console is started + */ +static void con_start(struct tty_struct *tty) +{ + int console_num; + if (!tty) + return; + console_num = MINOR(tty->device) - (tty->driver.minor_start); + if (!vc_cons_allocated(console_num)) + return; + clr_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK); + set_leds(); +} + +static int con_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) +{ + int c, tc, ok, n = 0; + unsigned int currcons; + struct vt_struct *vt = (struct vt_struct *)tty->driver_data; + + currcons = vt->vc_num; + if (!vc_cons_allocated(currcons)) { + /* could this happen? */ + static int error = 0; + if (!error) { + error = 1; + printk("con_write: tty %d not allocated\n", currcons+1); + } + return 0; + } + + /* undraw cursor first */ + if (currcons == fg_console) + hide_cursor(currcons); + + /* clear the selection */ + if (currcons == sel_cons) + clear_selection(); + + disable_bh(CONSOLE_BH); + while (count) { + enable_bh(CONSOLE_BH); + c = from_user ? get_user(buf) : *buf; + buf++; n++; count--; + disable_bh(CONSOLE_BH); + + if (utf) { + /* Combine UTF-8 into Unicode */ + /* Incomplete characters silently ignored */ + if(c > 0x7f) { + if (utf_count > 0 && (c & 0xc0) == 0x80) { + utf_char = (utf_char << 6) | (c & 0x3f); + utf_count--; + if (utf_count == 0) + tc = c = utf_char; + else continue; + } else { + if ((c & 0xe0) == 0xc0) { + utf_count = 1; + utf_char = (c & 0x1f); + } else if ((c & 0xf0) == 0xe0) { + utf_count = 2; + utf_char = (c & 0x0f); + } else if ((c & 0xf8) == 0xf0) { + utf_count = 3; + utf_char = (c & 0x07); + } else if ((c & 0xfc) == 0xf8) { + utf_count = 4; + utf_char = (c & 0x03); + } else if ((c & 0xfe) == 0xfc) { + utf_count = 5; + utf_char = (c & 0x01); + } else + utf_count = 0; + continue; + } + } else { + tc = c; + utf_count = 0; + } + } else { /* no utf */ + tc = translate[toggle_meta ? (c|0x80) : c]; + } + + /* If the original code was < 32 we only allow a + * glyph to be displayed if the code is not normally + * used (such as for cursor movement) or if the + * disp_ctrl mode has been explicitly enabled. + * Note: ESC is *never* allowed to be displayed as + * that would disable all escape sequences! + * To display font position 0x1B, go into UTF mode + * and display character U+F01B, or change the mapping. + */ + ok = (tc && (c >= 32 || (!utf && !(((disp_ctrl ? CTRL_ALWAYS + : CTRL_ACTION) >> c) & 1)))); + + if (vc_state == ESnormal && ok) { + /* Now try to find out how to display it */ + tc = conv_uni_to_pc(tc); + if ( tc == -4 ) + { + /* If we got -4 (not found) then see if we have + defined a replacement character (U+FFFD) */ + tc = conv_uni_to_pc(0xfffd); + } + else if ( tc == -3 ) + { + /* Bad hash table -- hope for the best */ + tc = c; + } + if (tc & ~console_charmask) + continue; /* Conversion failed */ + + if (need_wrap) { + cr(currcons); + lf(currcons); + } + +#if 1 /* XXX */ + /* DPC: 1994-04-12 + * Speed up overstrike mode, using new putcs. + * + * P.S. I hate 8 spaces per tab! Use Emacs! + */ + + /* Only use this for the foreground console, + where we really draw the chars */ + + if (count > 2 && + !decim && currcons == fg_console) { + static char putcs_buf[256]; + char *p = putcs_buf; + int putcs_count = 1; + ushort nextx = x + 1; + + *p++ = tc; + *pos++ = tc | (attr << 8); + + if (nextx == cols) { + sw->con_putc(vc_cons[currcons].d, + *putcs_buf, y, x); + pos--; + need_wrap = decawm; + continue; + } + + /* TAB TAB TAB - Arghh!!!! */ + + while (count) + { + c = from_user ? get_user(buf) : *buf; + tc = translate[toggle_meta ? (c|0x80) : c]; + if (!tc || + !(c >= 32 + || (disp_ctrl && c != 0x1b) + || !((CTRL_ACTION >> c) & 1))) + break; + buf++; n++; count--; + *p++ = tc; + *pos++ = tc | (attr << 8); + ++putcs_count; + ++nextx; + if (nextx == cols || + putcs_count == sizeof (putcs_buf)) + break; + } + + sw->con_putcs(vc_cons[currcons].d, + putcs_buf, putcs_count, y, x); + if (nextx == cols) { + pos--; + x = cols-1; + need_wrap = decawm; + } else + x += putcs_count; + continue; + } + + /* DPC: End of putcs support */ +#endif + + if (decim) + insert_char(currcons); + *pos = (attr << 8) + tc; + if (currcons == fg_console) + sw->con_putc(vc_cons[currcons].d,tc,y,x); + if (x == cols - 1) + need_wrap = decawm; + else { + pos++; + x++; + } + continue; + } + + /* + * Control characters can be used in the _middle_ + * of an escape sequence. + */ + switch (c) { + case 7: + if (bell_duration) + kd_mksound(bell_pitch, bell_duration); + continue; + case 8: + bs(currcons); + continue; + case 9: + pos -= x; + while (x < cols - 1) { + x++; + if (tab_stop[x >> 5] & (1 << (x & 31))) + break; + } + pos += x; + continue; + case 10: case 11: case 12: + lf(currcons); + if (!is_kbd(lnm)) + continue; + case 13: + cr(currcons); + continue; + case 14: + charset = 1; + translate = set_translate(G1_charset); + disp_ctrl = 1; + continue; + case 15: + charset = 0; + translate = set_translate(G0_charset); + disp_ctrl = 0; + continue; + case 24: case 26: + vc_state = ESnormal; + continue; + case 27: + vc_state = ESesc; + continue; + case 127: + del(currcons); + continue; + case 128+27: + vc_state = ESsquare; + continue; + } + switch(vc_state) { + case ESesc: + vc_state = ESnormal; + switch (c) { + case '[': + vc_state = ESsquare; + continue; + case ']': + vc_state = ESnonstd; + continue; + case '%': + vc_state = ESpercent; + continue; + case 'E': + cr(currcons); + lf(currcons); + continue; + case 'M': + ri(currcons); + continue; + case 'D': + lf(currcons); + continue; + case 'H': + tab_stop[x >> 5] |= (1 << (x & 31)); + continue; + case 'Z': + respond_ID(tty); + continue; + case '7': + save_cur(currcons); + continue; + case '8': + restore_cur(currcons); + continue; + case '(': + vc_state = ESsetG0; + continue; + case ')': + vc_state = ESsetG1; + continue; + case '#': + vc_state = EShash; + continue; + case 'c': + reset_terminal(currcons,1); + continue; + case '>': /* Numeric keypad */ + clr_kbd(kbdapplic); + continue; + case '=': /* Appl. keypad */ + set_kbd(kbdapplic); + continue; + } + continue; + case ESnonstd: + if (c=='P') { /* palette escape sequence */ + for (npar=0; npar='0'&&c<='9') || (c>='A'&&c<='F') || (c>='a'&&c<='f') ) { + par[npar++] = (c>'9' ? (c&0xDF)-'A'+10 : c-'0') ; + if (npar==7) { +#if 0 + int i = par[0]*3, j = 1; + palette[i] = 16*par[j++]; + palette[i++] += par[j++]; + palette[i] = 16*par[j++]; + palette[i++] += par[j++]; + palette[i] = 16*par[j++]; + palette[i] += par[j]; + set_palette() ; +#endif + vc_state = ESnormal; + } + } else + vc_state = ESnormal; + continue; + case ESsquare: + for(npar = 0 ; npar < NPAR ; npar++) + par[npar] = 0; + npar = 0; + vc_state = ESgetpars; + if (c == '[') { /* Function key */ + vc_state=ESfunckey; + continue; + } + ques = (c=='?'); + if (ques) + continue; + case ESgetpars: + if (c==';' && npar='0' && c<='9') { + par[npar] *= 10; + par[npar] += c-'0'; + continue; + } else vc_state=ESgotpars; + case ESgotpars: + vc_state = ESnormal; + switch(c) { + case 'h': + set_mode(currcons,1); + continue; + case 'l': + set_mode(currcons,0); + continue; + case 'n': + if (!ques) + if (par[0] == 5) + status_report(tty); + else if (par[0] == 6) + cursor_report(currcons,tty); + continue; + } + if (ques) { + ques = 0; + continue; + } + switch(c) { + case 'G': case '`': + if (par[0]) par[0]--; + gotoxy(currcons,par[0],y); + continue; + case 'A': + if (!par[0]) par[0]++; + gotoxy(currcons,x,y-par[0]); + continue; + case 'B': case 'e': + if (!par[0]) par[0]++; + gotoxy(currcons,x,y+par[0]); + continue; + case 'C': case 'a': + if (!par[0]) par[0]++; + gotoxy(currcons,x+par[0],y); + continue; + case 'D': + if (!par[0]) par[0]++; + gotoxy(currcons,x-par[0],y); + continue; + case 'E': + if (!par[0]) par[0]++; + gotoxy(currcons,0,y+par[0]); + continue; + case 'F': + if (!par[0]) par[0]++; + gotoxy(currcons,0,y-par[0]); + continue; + case 'd': + if (par[0]) par[0]--; + gotoxy(currcons,x,par[0]); + continue; + case 'H': case 'f': + if (par[0]) par[0]--; + if (par[1]) par[1]--; + gotoxy(currcons,par[1],par[0]); + continue; + case 'J': + csi_J(currcons,par[0]); + continue; + case 'K': + csi_K(currcons,par[0]); + continue; + case 'L': + csi_L(currcons,par[0]); + continue; + case 'M': + csi_M(currcons,par[0]); + continue; + case 'P': + csi_P(currcons,par[0]); + continue; + case 'c': + if (!par[0]) + respond_ID(tty); + continue; + case 'g': + if (!par[0]) + tab_stop[x >> 5] &= ~(1 << (x & 31)); + else if (par[0] == 3) { + tab_stop[0] = + tab_stop[1] = + tab_stop[2] = + tab_stop[3] = + tab_stop[4] = 0; + } + continue; + case 'm': + csi_m(currcons); + continue; + case 'q': /* DECLL - but only 3 leds */ + /* map 0,1,2,3 to 0,1,2,4 */ + if (par[0] < 4) + setledstate(kbd_table + currcons, + (par[0] < 3) ? par[0] : 4); + continue; + case 'r': + if (!par[0]) + par[0]++; + if (!par[1]) + par[1] = rows; + /* Minimum allowed region is 2 lines */ + if (par[0] < par[1] && + par[1] <= rows) { + top=par[0]-1; + bottom=par[1]; + gotoxy(currcons,0,0); + } + continue; + case 's': + save_cur(currcons); + continue; + case 'u': + restore_cur(currcons); + continue; + case 'X': + csi_X(currcons, par[0]); + continue; + case '@': + csi_at(currcons,par[0]); + continue; + case ']': /* setterm functions */ + setterm_command(currcons); + continue; + } + continue; + case ESpercent: + vc_state = ESnormal; + switch (c) { + case '@': /* defined in ISO 2022 */ + utf = 0; + continue; + case 'G': /* prelim official escape code */ + case '8': /* retained for compatibility */ + utf = 1; + continue; + } + continue; + case ESfunckey: + vc_state = ESnormal; + continue; + case EShash: + vc_state = ESnormal; + if (c == '8') { + /* DEC screen alignment test. kludge :-) */ + video_erase_char = + (video_erase_char & 0xff00) | 'E'; + /* Arno: + * Doesn't work, because csi_J(c,2) + * calls con_clear and doesn't print + * the erase char.. + */ + csi_J(currcons, 2); + video_erase_char = + (video_erase_char & 0xff00) | ' '; + } + continue; + case ESsetG0: + if (c == '0') + G0_charset = GRAF_MAP; + else if (c == 'B') + G0_charset = LAT1_MAP; + else if (c == 'U') + G0_charset = IBMPC_MAP; + else if (c == 'K') + G0_charset = USER_MAP; + if (charset == 0) + translate = set_translate(G0_charset); + vc_state = ESnormal; + continue; + case ESsetG1: + if (c == '0') + G1_charset = GRAF_MAP; + else if (c == 'B') + G1_charset = LAT1_MAP; + else if (c == 'U') + G1_charset = IBMPC_MAP; + else if (c == 'K') + G1_charset = USER_MAP; + if (charset == 1) + translate = set_translate(G1_charset); + vc_state = ESnormal; + continue; + default: + vc_state = ESnormal; + } + } + if (vcmode != KD_GRAPHICS) + set_cursor(currcons); + enable_bh(CONSOLE_BH); + return n; +} + +static int con_write_room(struct tty_struct *tty) +{ + if (tty->stopped) + return 0; + return 4096; /* No limit, really; we're not buffering */ +} + +static int con_chars_in_buffer(struct tty_struct *tty) +{ + return 0; /* we're not buffering */ +} + +void poke_blanked_console(void) +{ + timer_active &= ~(1<vc_mode == KD_GRAPHICS) + return; + if (console_blanked) { + timer_table[BLANK_TIMER].fn = unblank_screen; + timer_table[BLANK_TIMER].expires = 0; + timer_active |= 1< 0) { + sw->con_putcs(vc_cons[currcons].d, start, count , + y, x); + x += count; + if (need_wrap) + x--; + } + + if (c == 8) { /* backspace */ + bs(currcons); + start = b; + myx = x; + continue; + } + if (c != 13) + lf(currcons); + cr(currcons); + + if (c == 10 || c == 13) { + start = b; myx = x; continue; + } + + start = b-1; myx = x; + } + + *pos = c | (attr << 8); + if (myx == cols - 1) { + need_wrap = 1; + continue; + } + pos++; + myx++; + } + + if ((count = b - start -1) > 0) { + sw->con_putcs(vc_cons[currcons].d, start, count , + y, x); + x += count; + if (x == cols) + { + x--; + need_wrap = 1; + } + } + + set_cursor(currcons); + poke_blanked_console(); + printing = 0; +} + + +/* + * con_throttle and con_unthrottle are only used for + * paste_selection(), which has to stuff in a large number of + * characters... + */ +static void con_throttle(struct tty_struct *tty) +{ +} + +static void con_unthrottle(struct tty_struct *tty) +{ + struct vt_struct *vt = (struct vt_struct *) tty->driver_data; + + wake_up_interruptible(&vt->paste_wait); +} + +static void vc_init(unsigned int currcons, int do_clear) +{ + long base = (long) vc_scrbuf[currcons]; + + pos = (unsigned short *)(origin = (ulong)video_mem_start = base); + scr_end = base + screenbuf_size; + video_mem_end = base + screenbuf_size; + reset_vc(currcons); + def_color = 0x07; /* white */ + ulcolor = 0x0f; /* bold white */ + halfcolor = 0x08; /* grey */ + vt_cons[currcons]->paste_wait = 0; + reset_terminal(currcons, do_clear); +} + +/* + * This is the console switching bottom half handler. + * + * Doing console switching in a bottom half handler allows + * us to do the switches asynchronously (needed when we want + * to switch due to a keyboard interrupt), while still giving + * us the option to easily disable it to avoid races when we + * need to write to the console. + */ +static void console_bh(void) +{ + if (want_console >= 0) { + if (want_console != fg_console) { + change_console(want_console); + /* we only changed when the console had already + been allocated - a new console is not created + in an interrupt routine */ + } + want_console = -1; + } + if (do_poke_blanked_console) { /* do not unblank for a LED change */ + do_poke_blanked_console = 0; + poke_blanked_console(); + } +} + +/* + * unsigned long con_init(unsigned long); + * + * This routine initializes console interrupts, and does nothing + * else. If you want the screen to clear, call tty_write with + * the appropriate escape-sequence. + * + * Reads the information preserved by setup.s to determine the current display + * type and sets everything accordingly. + */ +unsigned long con_init(unsigned long kmem_start) +{ + char *display_desc = "????"; + unsigned int currcons = 0; + extern int serial_debug; + + memset(&console_driver, 0, sizeof(struct tty_driver)); + console_driver.magic = TTY_DRIVER_MAGIC; + console_driver.name = "tty"; + console_driver.name_base = 1; + console_driver.major = TTY_MAJOR; + console_driver.minor_start = 1; + console_driver.num = MAX_NR_CONSOLES; + console_driver.type = TTY_DRIVER_TYPE_CONSOLE; + console_driver.init_termios = tty_std_termios; + console_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS; + console_driver.refcount = &console_refcount; + console_driver.table = console_table; + console_driver.termios = console_termios; + console_driver.termios_locked = console_termios_locked; + + console_driver.open = con_open; + console_driver.write = con_write; + console_driver.write_room = con_write_room; + console_driver.chars_in_buffer = con_chars_in_buffer; + console_driver.ioctl = vt_ioctl; + console_driver.stop = con_stop; + console_driver.start = con_start; + console_driver.throttle = con_throttle; + console_driver.unthrottle = con_unthrottle; + + if (tty_register_driver(&console_driver)) + panic("Couldn't register console driver\n"); + + kmem_start = conswitchp->con_startup (kmem_start, &display_desc); + + timer_table[BLANK_TIMER].fn = blank_screen; + timer_table[BLANK_TIMER].expires = 0; + if (blankinterval) { + timer_table[BLANK_TIMER].expires = jiffies + blankinterval; + timer_active |= 1<con_init determines console size */ + sw = conswitchp; + cons_num = currcons; + sw->con_init (vc_cons[currcons].d); + size_row = cols<<1; + screenbuf_size = rows*size_row; + + vc_scrbuf[currcons] = (unsigned short *) kmem_start; + kmem_start += screenbuf_size; + kmalloced = 0; + vc_init(currcons, currcons); + } + + currcons = fg_console = 0; + + gotoxy(currcons,0,0); + csi_J(currcons, 0); + printable = 1; + update_screen(fg_console); + sw->con_cursor(vc_cons[currcons].d, CM_DRAW); + printable = 1; + + /* If "serdebug" cmd line option was present, don't register for printk */ + if (!serial_debug) + register_console(console_print); + printk("Console: %s %s %ldx%ld, %d virtual console%s (max %d)\n", + can_do_color ? "colour":"mono", + display_desc, + cols,rows, + MIN_NR_CONSOLES, (MIN_NR_CONSOLES == 1) ? "" : "s", MAX_NR_CONSOLES); + + init_bh(CONSOLE_BH, console_bh); + return kmem_start; +} + +void do_blank_screen(int nopowersave) +{ + int currcons; + + if (console_blanked) + return; + + if (!vc_cons_allocated(fg_console)) { + /* impossible */ + printk("blank_screen: tty %d not allocated ??\n", fg_console+1); + return; + } + + /* don't blank graphics */ + if (vt_cons[fg_console]->vc_mode == KD_TEXT) { + timer_active &= ~(1<con_blank (1); + } + else + hide_cursor(fg_console); + console_blanked = fg_console + 1; +} + +void do_unblank_screen(void) +{ + int currcons; + + if (!console_blanked) + return; + if (!vc_cons_allocated(fg_console)) { + /* impossible */ + printk("unblank_screen: tty %d not allocated ??\n", fg_console+1); + return; + } + timer_table[BLANK_TIMER].fn = blank_screen; + if (blankinterval) { + timer_table[BLANK_TIMER].expires = jiffies + blankinterval; + timer_active |= 1<con_blank (0)) + /* Low-level driver cannot restore -> do it ourselves */ + update_screen( fg_console ); + set_cursor (fg_console); +} + +void update_screen(int new_console) +{ + int currcons = fg_console; + int xx, yy, startx, attr_save; + char buf[256], *bufp; + unsigned short *p; + static int lock = 0; + + if (/* new_console == fg_console || */ lock) + return; + if (!vc_cons_allocated(new_console)) { + /* strange ... */ + printk("update_screen: tty %d not allocated ??\n", new_console+1); + return; + } + lock = 1; + + clear_selection(); + + currcons = fg_console = new_console; + sw->con_cursor (vc_cons[currcons].d, CM_ERASE); + sw->con_switch (vc_cons[new_console].d); + /* Update the screen contents */ + p = video_mem_start; + attr_save = attr; + for (yy = 0; yy < rows; yy++) + { + bufp = buf; + for (startx = xx = 0; xx < cols; xx++) + { + if (attr != ((*p >> 8) & 0xff)) + { + if (bufp > buf) + sw->con_putcs (vc_cons[currcons].d, buf, bufp - buf, + yy, startx); + startx = xx; + bufp = buf; + attr = (*p >> 8) & 0xff; + } + *bufp++ = *p++; + if (bufp == buf + sizeof (buf)) + { + sw->con_putcs (vc_cons[currcons].d, buf, bufp - buf, + yy, startx); + startx = xx + 1; + bufp = buf; + } + } + if (bufp > buf) + sw->con_putcs (vc_cons[currcons].d, buf, bufp - buf, + yy, startx); + } + set_cursor (currcons); + attr = attr_save; + set_leds(); + compute_shiftstate(); + lock = 0; +} + +/* + * If a blank_screen is due to a timer, then a power save is allowed. + * If it is related to console_switching, then avoid vesa_blank(). + */ +static void blank_screen(void) +{ + do_blank_screen(0); +} + +static void unblank_screen(void) +{ + do_unblank_screen(); +} + +/* + * Allocate the console screen memory. + */ +int con_open(struct tty_struct *tty, struct file * filp) +{ + unsigned int currcons; + int i; + + currcons = MINOR(tty->device) - tty->driver.minor_start; + + i = vc_allocate(currcons); + if (i) + return i; + + vt_cons[currcons]->vc_num = currcons; + tty->driver_data = vt_cons[currcons]; + + if (!tty->winsize.ws_row && !tty->winsize.ws_col) { + tty->winsize.ws_row = rows; + tty->winsize.ws_col = cols; + } + + return 0; +} + +/* + * PIO_FONT support. + * + * The font loading code goes back to the codepage package by + * Joel Hoffman (joel@wam.umd.edu). (He reports that the original + * reference is: "From: p. 307 of _Programmer's Guide to PC & PS/2 + * Video Systems_ by Richard Wilton. 1987. Microsoft Press".) + * + * Change for certain monochrome monitors by Yury Shevchuck + * (sizif@botik.yaroslavl.su). + */ + +#define colourmap ((char *)0xa0000) +/* Pauline Middelink reports that we + should use 0xA0000 for the bwmap as well.. */ +#define blackwmap ((char *)0xa0000) +#define cmapsz 8192 +#define seq_port_reg (0x3c4) +#define seq_port_val (0x3c5) +#define gr_port_reg (0x3ce) +#define gr_port_val (0x3cf) + +static int set_get_font(char * arg, int set) +{ +#ifdef CAN_LOAD_EGA_FONTS + int i; + char *charmap; + int beg; + + /* no use to "load" CGA... */ + + if (video_type == VIDEO_TYPE_EGAC) { + charmap = colourmap; + beg = 0x0e; + } else if (video_type == VIDEO_TYPE_EGAM) { + charmap = blackwmap; + beg = 0x0a; + } else + return -EINVAL; + + i = verify_area(set ? VERIFY_READ : VERIFY_WRITE, (void *)arg, cmapsz); + if (i) + return i; + + cli(); + outb_p( 0x00, seq_port_reg ); /* First, the sequencer */ + outb_p( 0x01, seq_port_val ); /* Synchronous reset */ + outb_p( 0x02, seq_port_reg ); + outb_p( 0x04, seq_port_val ); /* CPU writes only to map 2 */ + outb_p( 0x04, seq_port_reg ); + outb_p( 0x07, seq_port_val ); /* Sequential addressing */ + outb_p( 0x00, seq_port_reg ); + outb_p( 0x03, seq_port_val ); /* Clear synchronous reset */ + + outb_p( 0x04, gr_port_reg ); /* Now, the graphics controller */ + outb_p( 0x02, gr_port_val ); /* select map 2 */ + outb_p( 0x05, gr_port_reg ); + outb_p( 0x00, gr_port_val ); /* disable odd-even addressing */ + outb_p( 0x06, gr_port_reg ); + outb_p( 0x00, gr_port_val ); /* map start at A000:0000 */ + sti(); + + if (set) + memcpy_fromfs (charmap, arg, cmapsz); + else + memcpy_tofs (arg, charmap, cmapsz); + + cli(); + outb_p( 0x00, seq_port_reg ); /* First, the sequencer */ + outb_p( 0x01, seq_port_val ); /* Synchronous reset */ + outb_p( 0x02, seq_port_reg ); + outb_p( 0x03, seq_port_val ); /* CPU writes to maps 0 and 1 */ + outb_p( 0x04, seq_port_reg ); + outb_p( 0x03, seq_port_val ); /* odd-even addressing */ + outb_p( 0x00, seq_port_reg ); + outb_p( 0x03, seq_port_val ); /* clear synchronous reset */ + + outb_p( 0x04, gr_port_reg ); /* Now, the graphics controller */ + outb_p( 0x00, gr_port_val ); /* select map 0 for CPU */ + outb_p( 0x05, gr_port_reg ); + outb_p( 0x10, gr_port_val ); /* enable even-odd addressing */ + outb_p( 0x06, gr_port_reg ); + outb_p( beg, gr_port_val ); /* map starts at b800:0 or b000:0 */ + sti(); + + return 0; +#else + return -EINVAL; +#endif +} + +/* + * Load palette into the EGA/VGA DAC registers. arg points to a colour + * map, 3 bytes per colour, 16 colours, range from 0 to 255. + */ + +int con_set_cmap (unsigned char *arg) +{ + return -EINVAL; +} + +int con_get_cmap (unsigned char *arg) +{ + return -EINVAL; +} + +void reset_palette(int currcons) +{ +} + +void set_palette(void) +{ +} + +/* + * Load font into the EGA/VGA character generator. arg points to a 8192 + * byte map, 32 bytes per character. Only first H of them are used for + * 8xH fonts (0 < H <= 32). + */ + +int con_set_font (char *arg) +{ + hashtable_contents_valid = 0; + return set_get_font (arg,1); +} + +int con_get_font (char *arg) +{ + return set_get_font (arg,0); +} + +/* + * Adjust the screen to fit a font of a certain height + * + * Returns < 0 for error, 0 if nothing changed, and the number + * of lines on the adjusted console if changed. + */ +int con_adjust_height(unsigned long fontheight) +{ + return -EINVAL; +} + +void set_vesa_blanking(int arg) +{ +} + +unsigned long get_video_num_lines(unsigned int currcons) +{ + return(rows); +} + +unsigned long get_video_num_columns(unsigned int currcons) +{ + return(cols); +} + +unsigned long get_video_size_row(unsigned int currcons) +{ + return(size_row); +} diff -u --recursive --new-file v1.3.93/linux/arch/m68k/kernel/entry.S linux/arch/m68k/kernel/entry.S --- v1.3.93/linux/arch/m68k/kernel/entry.S Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/kernel/entry.S Sat Apr 13 17:53:59 1996 @@ -0,0 +1,641 @@ +/* -*- mode: asm -*- + * + * linux/arch/m68k/kernel/entry.S + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file README.legal in the main directory of this archive + * for more details. + * + * 680x0 support by Hamish Macdonald + * + */ + +/* + * entry.S contains the system-call and fault low-level handling routines. + * This also contains the timer-interrupt handler, as well as all interrupts + * and faults that can result in a task-switch. + * + * NOTE: This code handles signal-recognition, which happens every time + * after a timer-interrupt and after each system call. + * + * Stack layout in 'ret_from_exception': + * + * This allows access to the syscall arguments in registers d1-d5 + * + * 0(sp) - d1 + * 4(sp) - d2 + * 8(sp) - d3 + * C(sp) - d4 + * 10(sp) - d5 + * 14(sp) - a0 + * 18(sp) - a1 + * 1C(sp) - d0 + * 20(sp) - orig_d0 + * 24(sp) - stack adjustment + * 28(sp) - sr + * 2A(sp) - pc + * 2E(sp) - format & vector + */ + +/* + * 12/03/96 Jes: Currently we only support m68k single-cpu systems, so + * all pointers that used to be 'current' are now entry + * number 0 in the 'current_set' list. + */ + +#include + +#include + +LCF_MASK = 0x0001 + +LENOSYS = 38 + +/* + * these are offsets into the task-struct + */ +LTASK_STATE = 0 +LTASK_COUNTER = 4 +LTASK_PRIORITY = 8 +LTASK_SIGNAL = 12 +LTASK_BLOCKED = 16 +LTASK_FLAGS = 20 +LTASK_ERRNO = 24 + +#include +#include + +/* the following macro is used when enabling interrupts */ +#if defined(CONFIG_ATARI) && !defined(CONFIG_AMIGA) && !defined(CONFIG_MAC) + /* block out HSYNC on the atari */ +#define ALLOWINT 0xfbff +#else + /* portable version */ +#define ALLOWINT 0xf8ff +#endif /* machine compilation types */ + +LD0 = 0x1C +LORIG_D0 = 0x20 +LSR = 0x28 +LFORMATVEC = 0x2E + +/* + * This defines the normal kernel pt-regs layout. + * + * regs are a2-a6 and d6-d7 preserved by C code + * the kernel doesn't mess with usp unless it needs to + */ +#define SAVE_ALL \ + clrl %sp@-; /* stk_adj */ \ + movel %d0,%sp@-; /* orig d0 */ \ + movel %d0,%sp@-; /* d0 */ \ + moveml %d1-%d5/%a0-%a1,%sp@- + +#define RESTORE_ALL \ + moveml %sp@+,%a0-%a1/%d1-%d5; \ + movel %sp@+,%d0; \ + addql #4,%sp; /* orig d0 */ \ + addl %sp@+,%sp; /* stk adj */ \ + rte + +#define SWITCH_STACK_SIZE (7*4+4) /* includes return address */ + +#define SAVE_SWITCH_STACK \ + moveml %a2-%a6/%d6-%d7,%sp@- + +#define RESTORE_SWITCH_STACK \ + moveml %sp@+,%a2-%a6/%d6-%d7 + +.globl SYMBOL_NAME(system_call), SYMBOL_NAME(buserr), SYMBOL_NAME(trap) +.globl SYMBOL_NAME(resume), SYMBOL_NAME(ret_from_exception) +.globl SYMBOL_NAME(ret_from_signal) +.globl SYMBOL_NAME(inthandler), SYMBOL_NAME(sys_call_table) +.globl SYMBOL_NAME(sys_fork), SYMBOL_NAME(sys_clone) +.globl SYMBOL_NAME(ret_from_interrupt), SYMBOL_NAME(bad_interrupt) + +.text +ENTRY(buserr) + SAVE_ALL + moveq #-1,%d0 + movel %d0,%sp@(LORIG_D0) | a -1 in the ORIG_D0 field + | signifies that the stack frame + | is NOT for syscall + + movel %sp,%sp@- | stack frame pointer argument + bsrl SYMBOL_NAME(buserr_c) + addql #4,%sp + jra SYMBOL_NAME(ret_from_exception) + +ENTRY(trap) + SAVE_ALL + moveq #-1,%d0 + movel %d0,%sp@(LORIG_D0) | a -1 in the ORIG_D0 field + | signifies that the stack frame + | is NOT for syscall + movel %sp,%sp@- | stack frame pointer argument + bsrl SYMBOL_NAME(trap_c) + addql #4,%sp + jra SYMBOL_NAME(ret_from_exception) + +ENTRY(reschedule) + | save top of frame + pea %sp@ + jbsr SYMBOL_NAME(set_esp0) + addql #4,%sp + + pea SYMBOL_NAME(ret_from_exception) + jmp SYMBOL_NAME(schedule) + +ENTRY(system_call) + SAVE_ALL + movel #-LENOSYS,LD0(%sp) | default return value in d0 + | original D0 is in orig_d0 + movel %d0,%d2 + + | save top of frame + pea %sp@ + jbsr SYMBOL_NAME(set_esp0) + addql #4,%sp + + cmpl #NR_syscalls,%d2 + jcc SYMBOL_NAME(ret_from_exception) + lea SYMBOL_NAME(sys_call_table),%a0 + movel %a0@(%d2:l:4),%d3 + jeq SYMBOL_NAME(ret_from_exception) + andw #~LCF_MASK,%sp@(LSR) | assume syscall success + movel SYMBOL_NAME(current_set),%a0 + clrl %a0@(LTASK_ERRNO) + btst #5,%a0@(LTASK_FLAGS+3) | PF_TRACESYS + bnes 1f + movel %d3,%a0 + jbsr %a0@ + movel %d0,%sp@(LD0) | save the return value + jpl 2f + orw #LCF_MASK,%sp@(LSR) | set carry to indicate error +2: + movel SYMBOL_NAME(current_set),%a0 + movel %a0@(LTASK_ERRNO),%d1 + negl %d1 + jeq SYMBOL_NAME(ret_from_exception) + movel %d1,%sp@(LD0) + orw #LCF_MASK,%sp@(LSR) | set carry to indicate error + jra SYMBOL_NAME(ret_from_exception) +1: + subql #4,%sp + SAVE_SWITCH_STACK + jbsr SYMBOL_NAME(syscall_trace) + RESTORE_SWITCH_STACK + addql #4,%sp + movel %d3,%a0 + jbsr %a0@ + movel %d0,%sp@(LD0) | save the return value + jpl 2f + orw #LCF_MASK,%sp@(LSR) | set carry to indicate error +2: + movel SYMBOL_NAME(current_set),%a0 + movel %a0@(LTASK_ERRNO),%d1 + negl %d1 + jeq 2f + movel %d1,%sp@(LD0) + orw #LCF_MASK,%sp@(LSR) | set carry to indicate error +2: subql #4,%sp | dummy return address + SAVE_SWITCH_STACK + jbsr SYMBOL_NAME(syscall_trace) + +SYMBOL_NAME_LABEL(ret_from_signal) + RESTORE_SWITCH_STACK + addql #4,%sp + +SYMBOL_NAME_LABEL(ret_from_exception) + btst #5,%sp@(LSR) | check if returning to kernel + bnes 2f | if so, skip resched, signals + tstl SYMBOL_NAME(need_resched) + jne SYMBOL_NAME(reschedule) + movel SYMBOL_NAME(current_set),%a0 + cmpl #SYMBOL_NAME(task),%a0 | task[0] cannot have signals + jeq 2f + bclr #5,%a0@(LTASK_FLAGS+1) | check for delayed trace + jeq 1f + bclr #7,%sp@(LSR) | clear trace bit in SR + pea 1 | send SIGTRAP + movel %a0,%sp@- + pea 5 + jbsr SYMBOL_NAME(send_sig) + addql #8,%sp + addql #4,%sp + +1: + moveq #0,%d0 + movel SYMBOL_NAME(current_set),%a0 + cmpl %a0@(LTASK_STATE),%d0 | state + jne SYMBOL_NAME(reschedule) + cmpl %a0@(LTASK_COUNTER),%d0 | counter + jeq SYMBOL_NAME(reschedule) + + .word 0xf4f8 + movel %a0@(LTASK_BLOCKED),%d0 + movel %d0,%d1 | save blocked in d1 for sig handling + notl %d0 + andl %a0@(LTASK_SIGNAL),%d0 + jne Lsignal_return +2: RESTORE_ALL + +Lsignal_return: + subql #4,%sp | dummy return address + SAVE_SWITCH_STACK + pea %sp@(SWITCH_STACK_SIZE) + movel %d1,%sp@- + bsrl SYMBOL_NAME(do_signal) + addql #8,%sp + RESTORE_SWITCH_STACK + addql #4,%sp + RESTORE_ALL + +/* +** This is the main interrupt handler, responsible for calling process_int() +*/ +SYMBOL_NAME_LABEL(inthandler) + SAVE_ALL + moveq #-1,%d0 + movel %d0,%sp@(LORIG_D0) | a -1 in the ORIG_D0 field + | signifies that the stack frame + | is NOT for syscall + + addql #1,SYMBOL_NAME(intr_count) + + movew %sp@(LFORMATVEC),%d0 | put exception # in d0 + andil #0xfff,%d0 | mask out format nybble + + movel %sp,%sp@- + movel %d0,%sp@- | put vector # on stack + jbsr SYMBOL_NAME(process_int)| process the IRQ + addql #8,%sp | pop parameters off stack + +SYMBOL_NAME_LABEL(ret_from_interrupt) + /* check if we need to do software interrupts */ +1: + movel SYMBOL_NAME(intr_count),%d2 + subql #1,%d2 + jne 2f + + movel SYMBOL_NAME(bh_active),%d0 + andl SYMBOL_NAME(bh_mask),%d0 + jne 3f + + movel %d2,SYMBOL_NAME(intr_count) + + jra SYMBOL_NAME(ret_from_exception) + | deliver signals, reschedule etc.. + +2: movel %d2,SYMBOL_NAME(intr_count) + RESTORE_ALL +3: + movew %sr,%sp@- + andiw #(ALLOWINT),%sr | allow interrupts + jbsr SYMBOL_NAME(do_bottom_half) + movew %sp@+,%sr + jra 1b + + +/* Handler for uninitialized and spurious interrupts */ + +SYMBOL_NAME_LABEL(bad_interrupt) + addql #1,SYMBOL_NAME(num_spurious) + rte + +ENTRY(sys_fork) + SAVE_SWITCH_STACK + pea %sp@(SWITCH_STACK_SIZE) + jbsr SYMBOL_NAME(m68k_fork) + addql #4,%sp + RESTORE_SWITCH_STACK + rts + +ENTRY(sys_clone) + SAVE_SWITCH_STACK + pea %sp@(SWITCH_STACK_SIZE) + jbsr SYMBOL_NAME(m68k_clone) + addql #4,%sp + RESTORE_SWITCH_STACK + rts + +ENTRY(sys_sigsuspend) + SAVE_SWITCH_STACK + pea %sp@(SWITCH_STACK_SIZE) + jbsr SYMBOL_NAME(do_sigsuspend) + addql #4,%sp + RESTORE_SWITCH_STACK + rts + +ENTRY(sys_sigreturn) + SAVE_SWITCH_STACK + jbsr SYMBOL_NAME(do_sigreturn) + RESTORE_SWITCH_STACK + rts + +LFLUSH_I_AND_D = 0x00000808 +LBI_CPU = 4 +LTSS_KSP = 0 +LTSS_USP = 4 +LTSS_SR = 8 +LTSS_FS = 10 +LTSS_CRP = 20 +LTSS_FPCTXT = 32 + +SYMBOL_NAME_LABEL(resume) + /* + * Beware - when entering resume, offset of tss is in a1 and + * next (the new task) is in d1, so don't chance these + * registers before their contents have been used. + */ + + /* current tasks task_struct */ + movel SYMBOL_NAME(current_set),%a0 + + /* offset of tss struct (processor state) from beginning + of task struct */ +/* + movel %sp@(8),%a1 +*/ + addl %a1,%a0 + + /* save sr */ + movew %sr,%a0@(LTSS_SR) + + /* disable interrupts */ + oriw #0x0700,%sr + + /* save fs (sfc,%dfc) (may be pointing to kernel memory) */ + movec %sfc,%d0 + movew %d0,%a0@(LTSS_FS) + + /* save usp */ + /* it is better to use a movel here instead of a movew 8*) */ + movec %usp,%d0 + movel %d0,%a0@(LTSS_USP) + + /* load new task (before adjusting stack) */ + /* The task has already been put in d1 by switch_to (Jes) */ +/* + movel %sp@(4),%d1 +*/ + /* save non-scratch registers on stack */ + SAVE_SWITCH_STACK + + /* save current kernel stack pointer */ + movel %sp,%a0@(LTSS_KSP) + + /* save floating point context */ + fsave %a0@(LTSS_FPCTXT+27*4) + tstb %a0@(LTSS_FPCTXT+27*4) + jeq 1f + fmovemx %fp0-%fp7,%a0@(LTSS_FPCTXT) + fmoveml %fpcr/%fpsr/%fpiar,%a0@(LTSS_FPCTXT+24*4) +1: + + /* get pointer to tss struct (d1 contains new task) */ + movel %d1,SYMBOL_NAME(current_set) + movel %d1,%a0 + addl %a1,%a0 + + /* 68040 or 68060 ? */ + btst #2,SYMBOL_NAME(boot_info)+LBI_CPU+3 + bnes 1f + btst #3,SYMBOL_NAME(boot_info)+LBI_CPU+3 + bnes 1f + + /* + * switch address space + */ + + /* flush MC68030/MC68020 caches (they are virtually addressed) */ + movec %cacr,%d0 + oril #LFLUSH_I_AND_D,%d0 + movec %d0,%cacr + + /* switch the root pointer */ + pmove %a0@(LTSS_CRP),%crp + + /* flush address translation cache (probably not needed */ + pflusha + + jra 2f /* skip m68040 stuff */ + +1: + /* + * switch address space + */ + + /* flush address translation cache (user entries) */ + .word 0xf510 /* pflushan */ + + /* switch the root pointer */ + movel %a0@(LTSS_CRP+4),%d0 + .long 0x4e7b0806 /* movec d0,urp */ + + /* is it a '060 ? */ + btst #3,SYMBOL_NAME(boot_info)+LBI_CPU+3 + beqs 2f + /* clear user entries in the branch cache */ + movec %cacr,%d0 + orl #0x00200000,%d0 + movec %d0,%cacr + +2: + /* restore floating point context */ + tstb %a0@(LTSS_FPCTXT+27*4) + jeq 1f + fmovemx %a0@(LTSS_FPCTXT),%fp0-%fp7 + fmoveml %a0@(LTSS_FPCTXT+24*4),%fpcr/%fpsr/%fpiar +1: frestore %a0@(LTSS_FPCTXT+27*4) + + /* restore the kernel stack pointer */ + movel %a0@(LTSS_KSP),%sp + + /* restore non-scratch registers */ + RESTORE_SWITCH_STACK + + /* restore user stack pointer */ + movel %a0@(LTSS_USP),%d0 + movec %d0,%usp + + /* restore fs (sfc,%dfc) */ + movew %a0@(LTSS_FS),%a1 + movec %a1,%sfc + movec %a1,%dfc + + /* restore status register */ + movew %a0@(LTSS_SR),%sr + + rts + +.data +ALIGN +SYMBOL_NAME_LABEL(sys_call_table) + .long SYMBOL_NAME(sys_setup) /* 0 */ + .long SYMBOL_NAME(sys_exit) + .long SYMBOL_NAME(sys_fork) + .long SYMBOL_NAME(sys_read) + .long SYMBOL_NAME(sys_write) + .long SYMBOL_NAME(sys_open) /* 5 */ + .long SYMBOL_NAME(sys_close) + .long SYMBOL_NAME(sys_waitpid) + .long SYMBOL_NAME(sys_creat) + .long SYMBOL_NAME(sys_link) + .long SYMBOL_NAME(sys_unlink) /* 10 */ + .long SYMBOL_NAME(sys_execve) + .long SYMBOL_NAME(sys_chdir) + .long SYMBOL_NAME(sys_time) + .long SYMBOL_NAME(sys_mknod) + .long SYMBOL_NAME(sys_chmod) /* 15 */ + .long SYMBOL_NAME(sys_chown) + .long SYMBOL_NAME(sys_break) + .long SYMBOL_NAME(sys_stat) + .long SYMBOL_NAME(sys_lseek) + .long SYMBOL_NAME(sys_getpid) /* 20 */ + .long SYMBOL_NAME(sys_mount) + .long SYMBOL_NAME(sys_umount) + .long SYMBOL_NAME(sys_setuid) + .long SYMBOL_NAME(sys_getuid) + .long SYMBOL_NAME(sys_stime) /* 25 */ + .long SYMBOL_NAME(sys_ptrace) + .long SYMBOL_NAME(sys_alarm) + .long SYMBOL_NAME(sys_fstat) + .long SYMBOL_NAME(sys_pause) + .long SYMBOL_NAME(sys_utime) /* 30 */ + .long SYMBOL_NAME(sys_stty) + .long SYMBOL_NAME(sys_gtty) + .long SYMBOL_NAME(sys_access) + .long SYMBOL_NAME(sys_nice) + .long SYMBOL_NAME(sys_ftime) /* 35 */ + .long SYMBOL_NAME(sys_sync) + .long SYMBOL_NAME(sys_kill) + .long SYMBOL_NAME(sys_rename) + .long SYMBOL_NAME(sys_mkdir) + .long SYMBOL_NAME(sys_rmdir) /* 40 */ + .long SYMBOL_NAME(sys_dup) + .long SYMBOL_NAME(sys_pipe) + .long SYMBOL_NAME(sys_times) + .long SYMBOL_NAME(sys_prof) + .long SYMBOL_NAME(sys_brk) /* 45 */ + .long SYMBOL_NAME(sys_setgid) + .long SYMBOL_NAME(sys_getgid) + .long SYMBOL_NAME(sys_signal) + .long SYMBOL_NAME(sys_geteuid) + .long SYMBOL_NAME(sys_getegid) /* 50 */ + .long SYMBOL_NAME(sys_acct) + .long SYMBOL_NAME(sys_phys) + .long SYMBOL_NAME(sys_lock) + .long SYMBOL_NAME(sys_ioctl) + .long SYMBOL_NAME(sys_fcntl) /* 55 */ + .long SYMBOL_NAME(sys_mpx) + .long SYMBOL_NAME(sys_setpgid) + .long SYMBOL_NAME(sys_ulimit) + .long SYMBOL_NAME(sys_olduname) + .long SYMBOL_NAME(sys_umask) /* 60 */ + .long SYMBOL_NAME(sys_chroot) + .long SYMBOL_NAME(sys_ustat) + .long SYMBOL_NAME(sys_dup2) + .long SYMBOL_NAME(sys_getppid) + .long SYMBOL_NAME(sys_getpgrp) /* 65 */ + .long SYMBOL_NAME(sys_setsid) + .long SYMBOL_NAME(sys_sigaction) + .long SYMBOL_NAME(sys_sgetmask) + .long SYMBOL_NAME(sys_ssetmask) + .long SYMBOL_NAME(sys_setreuid) /* 70 */ + .long SYMBOL_NAME(sys_setregid) + .long SYMBOL_NAME(sys_sigsuspend) + .long SYMBOL_NAME(sys_sigpending) + .long SYMBOL_NAME(sys_sethostname) + .long SYMBOL_NAME(sys_setrlimit) /* 75 */ + .long SYMBOL_NAME(sys_getrlimit) + .long SYMBOL_NAME(sys_getrusage) + .long SYMBOL_NAME(sys_gettimeofday) + .long SYMBOL_NAME(sys_settimeofday) + .long SYMBOL_NAME(sys_getgroups) /* 80 */ + .long SYMBOL_NAME(sys_setgroups) + .long SYMBOL_NAME(old_select) + .long SYMBOL_NAME(sys_symlink) + .long SYMBOL_NAME(sys_lstat) + .long SYMBOL_NAME(sys_readlink) /* 85 */ + .long SYMBOL_NAME(sys_uselib) + .long SYMBOL_NAME(sys_swapon) + .long SYMBOL_NAME(sys_reboot) + .long SYMBOL_NAME(old_readdir) + .long SYMBOL_NAME(old_mmap) /* 90 */ + .long SYMBOL_NAME(sys_munmap) + .long SYMBOL_NAME(sys_truncate) + .long SYMBOL_NAME(sys_ftruncate) + .long SYMBOL_NAME(sys_fchmod) + .long SYMBOL_NAME(sys_fchown) /* 95 */ + .long SYMBOL_NAME(sys_getpriority) + .long SYMBOL_NAME(sys_setpriority) + .long SYMBOL_NAME(sys_profil) + .long SYMBOL_NAME(sys_statfs) + .long SYMBOL_NAME(sys_fstatfs) /* 100 */ + .long SYMBOL_NAME(sys_ioperm) + .long SYMBOL_NAME(sys_socketcall) + .long SYMBOL_NAME(sys_syslog) + .long SYMBOL_NAME(sys_setitimer) + .long SYMBOL_NAME(sys_getitimer) /* 105 */ + .long SYMBOL_NAME(sys_newstat) + .long SYMBOL_NAME(sys_newlstat) + .long SYMBOL_NAME(sys_newfstat) + .long SYMBOL_NAME(sys_uname) + .long SYMBOL_NAME(sys_ni_syscall) /* iopl for i386 */ /* 110 */ + .long SYMBOL_NAME(sys_vhangup) + .long SYMBOL_NAME(sys_idle) + .long SYMBOL_NAME(sys_ni_syscall) /* vm86 for i386 */ + .long SYMBOL_NAME(sys_wait4) + .long SYMBOL_NAME(sys_swapoff) /* 115 */ + .long SYMBOL_NAME(sys_sysinfo) + .long SYMBOL_NAME(sys_ipc) + .long SYMBOL_NAME(sys_fsync) + .long SYMBOL_NAME(sys_sigreturn) + .long SYMBOL_NAME(sys_clone) /* 120 */ + .long SYMBOL_NAME(sys_setdomainname) + .long SYMBOL_NAME(sys_newuname) + .long SYMBOL_NAME(sys_ni_syscall) /* modify_ldt for i386 */ + .long SYMBOL_NAME(sys_adjtimex) + .long SYMBOL_NAME(sys_mprotect) /* 125 */ + .long SYMBOL_NAME(sys_sigprocmask) + .long SYMBOL_NAME(sys_create_module) + .long SYMBOL_NAME(sys_init_module) + .long SYMBOL_NAME(sys_delete_module) + .long SYMBOL_NAME(sys_get_kernel_syms) /* 130 */ + .long SYMBOL_NAME(sys_quotactl) + .long SYMBOL_NAME(sys_getpgid) + .long SYMBOL_NAME(sys_fchdir) + .long SYMBOL_NAME(sys_bdflush) + .long SYMBOL_NAME(sys_sysfs) /* 135 */ + .long SYMBOL_NAME(sys_personality) + .long SYMBOL_NAME(sys_ni_syscall) /* for afs_syscall */ + .long SYMBOL_NAME(sys_setfsuid) + .long SYMBOL_NAME(sys_setfsgid) + .long SYMBOL_NAME(sys_llseek) /* 140 */ + .long SYMBOL_NAME(sys_getdents) + .long SYMBOL_NAME(sys_select) + .long SYMBOL_NAME(sys_flock) + .long SYMBOL_NAME(sys_msync) + .long SYMBOL_NAME(sys_readv) /* 145 */ + .long SYMBOL_NAME(sys_writev) + .long SYMBOL_NAME(sys_getsid) + .long SYMBOL_NAME(sys_fdatasync) + .long SYMBOL_NAME(sys_sysctl) + .long SYMBOL_NAME(sys_mlock) /* 150 */ + .long SYMBOL_NAME(sys_munlock) + .long SYMBOL_NAME(sys_mlockall) + .long SYMBOL_NAME(sys_munlockall) + .long SYMBOL_NAME(sys_sched_setparam) + .long SYMBOL_NAME(sys_sched_getparam) /* 155 */ + .long SYMBOL_NAME(sys_sched_setscheduler) + .long SYMBOL_NAME(sys_sched_getscheduler) + .long SYMBOL_NAME(sys_sched_yield) + .long SYMBOL_NAME(sys_sched_get_priority_max) + .long SYMBOL_NAME(sys_sched_get_priority_min) /* 160 */ + .long SYMBOL_NAME(sys_sched_rr_get_interval) + .long SYMBOL_NAME(sys_nanosleep) + .long SYMBOL_NAME(sys_mremap) + .space (NR_syscalls-163)*4 diff -u --recursive --new-file v1.3.93/linux/arch/m68k/kernel/head.S linux/arch/m68k/kernel/head.S --- v1.3.93/linux/arch/m68k/kernel/head.S Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/kernel/head.S Fri Apr 19 02:19:14 1996 @@ -0,0 +1,1206 @@ +/* -*- mode: asm -*- +** +** head.S -- This file contains the initial boot code for the the +** Linux/68k kernel. +** +** Copyright 1993 by Hamish Macdonald +** +** 68040 fixes by Michael Rausch +** 68060 fixes by Roman Hodek +** +** Atari support by Andreas Schwab, using ideas of Robert de Vries +** and Bjoern Brauel +** +** 94/11/14 Andreas Schwab: put kernel at PAGESIZE +** 94/11/18 Andreas Schwab: remove identity mapping of STRAM for Atari +** ++ Bjoern & Roman: ATARI-68040 support for the Medusa +** +** This file is subject to the terms and conditions of the GNU General Public +** License. See the file README.legal in the main directory of this archive +** for more details. +** +*/ + +/* + * Linux startup code. + * + * At this point, the boot loader has: + * Disabled interrupts + * Disabled caches + * Put us in supervisor state. + * + * The kernel setup code takes the following steps: + * Raise interrupt level + * Set up initial kernel memory mapping. + * This sets up a mapping of the 4M of memory the kernel + * is located in. It also does a mapping of any initial + * machine specific areas. + * Note that the kernel is located at virtual address 0x1000 == _start + * Enable cache memories + * Jump to kernel startup + * + * Register d6 contains the CPU flags and d4 the machine type + * from the boot_info information for most of this file. + * The upper word of d6 contains a bit for '040 or '060, since these two + * are quite similar for initial mm setup. Another bit in d6 allows + * distinction of the '060. The lower word of d6 contains the cache mode + * that should be applied to pages containing descriptors. This mode is + * non-cached/non-serialized for the '040 and cacheable/write-through for + * the '060. + */ + +#include +#include + +.text +.globl SYMBOL_NAME(kernel_pg_dir), SYMBOL_NAME(kpt) +.globl SYMBOL_NAME(availmem), SYMBOL_NAME(is_medusa) +.globl SYMBOL_NAME(m68k_pgtable_cachemode) +.globl SYMBOL_NAME(kernel_pmd_table), SYMBOL_NAME(swapper_pg_dir) + +PAGESIZE = 4096 +BI_CPU = 4 +BI_MACH = 0 +BI_AMIGA_ECLK = 1234 +LF = 10 +CR = 13 +BI_BIT040 = 2 /* CPU bits in bootinfo */ +BI_BIT060 = 3 +BIT0460 = 16 /* indicates '0[46]0 in d6 */ +BIT060 = 17 /* indicates '060 in d6 */ +D6VAL_040 = 0x00010000 +D6VAL_060 = 0x00030000 +/* BIT040 = 2 */ + + /* Some definitions for the special registers of the 68040. + * (MMU, caches) + */ + +/* Translation control register */ +TC_ENABLE = 0x8000 +TC_PAGE8K = 0x4000 +TC_PAGE4K = 0x0000 + +/* Transparent translation registers */ +TTR_ENABLE = 0x8000 + +/* Some bits used in the page and table descriptors as well as in the + * special registers. + */ + +CM_CACHE_WT = 0x0000 /* cacheable, write-through */ +CM_CACHE_CB = 0x0020 /* cacheable, copyback */ +CM_NONCACHE_SER = 0x0040 /* noncacheable, serialized */ +CM_NONCACHE = 0x0060 /* noncacheable */ +CM_MASK = 0xffffff9f /* mask */ + +MODIFIED = 0x0010 +WRITE_PROT = 0x0004 +USED = 0x0008 +GLOBAL = 0x0400 +SV_ONLY = 0x0080 +PAGEDESC = 0x0001 +TABLEDESC = 0x0002 +INVALID = 0x0000 + +/* Cache enabling */ +I_HALF = 0x00002000 /* half-cache mode for I-cache ('060) */ +I_FREEZE = 0x00004000 /* freeze I-cache ('060) */ +I_ENABLE = 0x00008000 /* enable I-cache */ +BC_CLRU = 0x00200000 /* clear user entries in branch cache ('060) */ +BC_CLRA = 0x00400000 /* clear all entries in branch cache ('060) */ +BC_ENABLE = 0x00800000 /* enable branch cache ('060) */ +D_HALF = 0x08000000 /* half-cache mode for D-cache ('060) */ +PUSH_DPI = 0x10000000 /* disable CPUSH invalidation ('060) */ +SB_ENABLE = 0x20000000 /* enable store buffer ('060) */ +D_FREEZE = 0x40000000 /* freeze D-cache ('060) */ +D_ENABLE = 0x80000000 /* enable D-cache */ + +/* Miscellaneous definitions */ +PAGE_MASK = (~(PAGESIZE-1)) + +ROOT_TABLE_SIZE = 128 +PTR_TABLE_SIZE = 128 +PAGE_TABLE_SIZE = 64 +ROOT_INDEX_SHIFT = 25 +PAGE_INDEX_SHIFT = 12 + +ENTRY(_stext) +ENTRY(_start) + bras 1f /* Jump over bootinfo version numbers */ +/* + * Version numbers of the bootinfo interface + */ + + .long BOOTINFOV_MAGIC + .long MACH_AMIGA, AMIGA_BOOTI_VERSION + .long MACH_ATARI, ATARI_BOOTI_VERSION + .long 0 + +1: + +/* + * raise interrupt level + */ + + movew #0x2700,%sr + +/* + * Copy bootinfo from position after BSS to final resting place + */ + lea %pc@(SYMBOL_NAME(_end)),%a0 + lea %pc@(SYMBOL_NAME(boot_info)),%a1 + movel %pc@(SYMBOL_NAME(bisize)),%d0 + subql #1,%d0 +1: moveb %a0@+,%a1@+ + dbra %d0,1b + +/* + * Record the CPU and machine type. + */ + lea %pc@(SYMBOL_NAME(boot_info)),%a0 + movel %a0@(BI_MACH),%d4 + movel %a0@(BI_CPU),%d0 + movel %a0@(BI_CPU),%d6 /* !!!!!!!!!!!!!!!! */ + + btst #BI_BIT060,%d0 + beq 1f + /* '060: d6 := BIT0460|BIT060, cache mode 0x60 (no-cache/non-ser) */ + movel #(D6VAL_060+CM_NONCACHE),%d6 + bra 2f +1: btst #BI_BIT040,%d0 + beq 1f + /* '040: d6 := BIT0460, cache mode 0x00 (write-through) */ + movel #(D6VAL_040+CM_CACHE_WT),%d6 + bra 2f +1: /* '020 or '030: d6 := no CPU bit, cache mode unused */ + moveq #0,%d6 + +2: lea %pc@(SYMBOL_NAME(m68k_pgtable_cachemode)),%a0 + movel %d6,%a0@ /* save cache mode for page tables */ + andl #0x0000ffff,%a0@ + +/* + * Initialize serial port + */ + jbsr Lserial_init + + moveq #CR,%d7 + jbsr Lserial_putc + moveq #LF,%d7 + jbsr Lserial_putc + moveq #'A',%d7 + jbsr Lserial_putc + +/* + * Get address at end of kernel code/data/bss and + * mask off at a page boundary. + */ + lea %pc@(SYMBOL_NAME(_end)),%a0 + movel %a0,%d0 + addl #(PAGESIZE-1),%d0 + andl #PAGE_MASK,%d0 + movel %d0,%a6 + + moveq #'B',%d7 + jbsr Lserial_putc + +/* + * initialize the kernel root table. + */ + lea %pc@(SYMBOL_NAME(kernel_pg_dir)),%a4 + movel %a4,%a0 + moveq #0,%d0 + moveq #(ROOT_TABLE_SIZE-1),%d1 +1: movel %d0,%a0@+ + dbra %d1,1b + + /* + * Initialize root table descriptor pointing to the kernel pointer + * table. + */ + movel %a6,%a5 + addw #PAGESIZE,%a6 + + movel %a5,%a0 + addql #TABLEDESC,%a0 + movel %a0,%a4@ + + moveq #'C',%d7 + jbsr Lserial_putc + +/* + * Initialize the pointer tables referred to above. They either point + * to page tables in the case of the 680[46]0 or contain early + * termination page descriptors in the case of the 68851 or 68030. + * + * Each pointer table entry points to a 64 entry page table. 16 of these + * page tables are grouped to form a single 1024 entry page table which + * fits in a single 4096 byte page. + * + * Some register usages: + * a0 -> pointer table descriptor address + * a1 -> pointer table descriptor + * d1 -> counter + * d2 -> pointer table descriptor increment (varies according to CPU) + */ + + /* clear the kernel pointer table */ + movel %a5,%a0 + moveq #0,%d0 + moveq #(PTR_TABLE_SIZE-1),%d1 +1: movel %d0,%a0@+ + dbra %d1,1b + + movel %a5,%a0 + moveq #15,%d1 + + /* + * base value of pointer table descriptor is either + * the address of the first page table (680[46]0) + * or the base address of physical memory (68030). + */ + btst #BIT0460,%d6 + bne 1f + + /* 680[23]0 */ + lea %pc@(SYMBOL_NAME(_stext)-PAGESIZE:w),%a1 /* base address */ + addql #PAGEDESC,%a1 /* descriptor type */ + movel #0x40000,%d2 /* increment */ + bra 2f + +1: /* 680[46]0 */ + movel %a6,%a1 /* base address */ + addw #PAGESIZE,%a6 /* allocate the page table */ + lea %pc@(SYMBOL_NAME(kpt)),%a3 + movel %a1,%a3@ /* save address of page table */ + addql #TABLEDESC,%a1 /* descriptor type */ + movel #256,%d2 /* increment */ + +2: movel %a1,%a0@+ + addl %d2,%a1 + dbra %d1,2b + + moveq #'D',%d7 + jbsr Lserial_putc + +/* + * If we are running on a 680[46]0, we have a kernel page table and + * must initialize it. Make the entries point to the first + * 4M of physical memory (the memory we are residing in). + * Set the cache mode bits to Cacheable, Copyback. Set the Global bits + * in the descriptors also. + */ + + btst #BIT0460,%d6 + jeq Lnot040 + + moveq #'F',%d7 + jbsr Lserial_putc + + movel %pc@(SYMBOL_NAME(kpt)),%a0 + lea %pc@(SYMBOL_NAME(_stext)-PAGESIZE:w),%a1 + + addw #(GLOBAL+CM_CACHE_CB+PAGEDESC),%a1 + movew #((PAGESIZE/4)-1),%d1 + movel #PAGESIZE,%d2 + +1: movel %a1,%a0@+ + addl %d2,%a1 + dbra %d1,1b + + /* + * on the 68040, pages used to hold mmu tables should + * be initialized as noncachable; the '060 allows write-through. + * Do this for the root table page (which also contains + * all pointer tables utilitized thus far) and the + * kernel page table. + */ + lea %pc@(SYMBOL_NAME(_stext)-PAGESIZE:w),%a0 + movel %a4,%d0 /* address of root table */ + subl %a0,%d0 /* determine offset of root table page */ + moveq #PAGE_INDEX_SHIFT,%d1 /* determine offset into kernel page table */ + lsrl %d1,%d0 /* i.e. page number of the address offset */ + movel %pc@(SYMBOL_NAME(kpt)),%a0 + lea %a0@(%d0:l:4),%a0 + movel %a0@,%d1 + andl #CM_MASK,%d1 + orw %d6,%d1 + movel %d1,%a0@+ + + movel %a0@,%d1 /* do the same for the kernel page table */ + bclr #5,%d1 /* the kernel page table resides in the */ + bset #6,%d1 /* page after the page containing the */ + movel %d1,%a0@ /* root table */ + +Lnot040: +/* + * Do any machine specific page table initializations. + */ + moveq #MACH_AMIGA,%d0 + cmpl %d4,%d0 + bne Lnotami + +/* + * On the Amiga: + * Our current stack (in CHIP ram) may become invalid after the remapping + * of the kernel virtual address space, so set it to point to PAGE_SIZE. + * This will be in CHIP ram until after the remapping, and in the unused + * first page (temporarily) after that. + * + * Setup a mapping of the first 16M of physical address space at virtual + * address 0x80000000, using early termination page descriptors for the + * 68030, and proper page tables for the 680[46]0. Set this area as + * non-cacheable. + */ + + moveq #'H',%d7 + jbsr Lserial_putc + + move.w #PAGESIZE,%sp + + btst #BIT0460,%d6 + bne Lspami68040 + + + /* + * for the 68030, just setup a translation to map in the first + * 32M of physical address space at virtual address 0x80000000 + * using an early termination page descriptor. + */ + + moveq #'I',%d7 + jbsr Lserial_putc + + moveq #0x41,%d0 + movel %d0,%a4@(64*4) + + bra Lmapphys + +Lspami68040: + + /* + * for the 680[46]0, use another pointer table, and allocate 4 more + * page tables. Initialize the pointer table to point to the + * page tables. Then initialize the page tables to point to + * the first 16M of memory, with no caching (noncachable/serialized). + */ + + /* clear the amiga pointer table */ + lea %a5@(512),%a0 + moveq #0,%d0 + moveq #(PTR_TABLE_SIZE-1),%d1 +1: movel %d0,%a0@+ + dbra %d1,1b + + /* allocate 4 page tables */ + movel %a6,%a3 + addw #(4*PAGESIZE),%a6 + + /* initialize the pointer table */ + lea %a5@(512),%a0 + movel %a3,%a1 + addql #TABLEDESC,%a1 /* base descriptor */ + movel #256,%d2 /* increment */ + moveq #(PAGE_TABLE_SIZE-1),%d1 + +1: movel %a1,%a0@+ + addl %d2,%a1 + dbra %d1,1b + + /* ensure that the root table points to the pointer table */ + lea %a5@(512),%a0 + addql #TABLEDESC,%a0 + movel %a0,%a4@(256) /* 0x80000000>>(ROOT_INDEX_SHIFT-2) doesn't + work */ + + /* + * initialize the page tables + * descriptor bits include noncachable/serialized and global bits. + */ + movel %a3,%a0 + movew #(GLOBAL+CM_NONCACHE_SER+PAGEDESC),%a1 + movel #PAGESIZE,%d2 + movew #PAGESIZE-1,%d1 + +1: movel %a1,%a0@+ + addl %d2,%a1 + dbra %d1,1b + + /* + * Finally, since we just allocated 4 page tables, make sure that + * the virtual mapping of the 4 page tables indicates + * noncachable/serialized. + */ + movel %a3,%d0 /* ami page table start address */ + lea %pc@(SYMBOL_NAME(_stext)-PAGESIZE:w),%a0 + subl %a0,%d0 /* determine offset of root table page */ + moveq #PAGE_INDEX_SHIFT,%d1 /* determine offset into kernel page table */ + lsrl %d1,%d0 + movel %pc@(SYMBOL_NAME(kpt)),%a0 + movel #3,%d2 +1: lea %a0@(%d0:l:4),%a1 + movel %a1@,%d1 + bclr #5,%d1 + bset #6,%d1 + movel %d1,%a1@ + addql #1,%d0 + dbra %d2,1b + + bra Lmapphys + + +Lnotami: /* other machines specific mappings go here! */ + + moveq #MACH_ATARI,%d0 + cmpl %d4,%d0 + bne Lnotatari + + move.w #PAGESIZE,%sp + +/* On the Atari, we map the I/O region (phys. 0x00ffxxxx) by mapping + the last 16 MB of virtual address space to the first 16 MB (i.e. + 0xffxxxxxx -> 0x00xxxxxx). For this, an additional pointer table is + needed. I/O ranges are marked non-cachable. + + For the Medusa it is better to map the I/O region transparently + (i.e. 0xffxxxxxx -> 0xffxxxxxx), because some I/O registers are + accessible only in the high area. The test whether it is a Medusa + is done by writing to the byte at phys. 0x0. This should result + in a bus error on all other machines. + + ...should, but doesn't. The Atferburner040 for the Falcon has the + same behaviour (0x0..0x7 are no ROM shadow). So we have to do + another test to distinuish Medusa and AB040. This is a + read attempt for 0x00ff82fe phys. that should bus error on a Falcon + (+AB040), but is in the range where the Medusa always asserts DTACK. +*/ + + moveq #0,%d3 /* base addr for others: 0x00000000 */ + movec %d3,%vbr + lea %pc@(Ltest_berr),%a0 + movel %a0,0x8 + movel %sp,%a0 + moveb 0x0,%d1 + clrb 0x0 + nop + moveb %d1,0x0 + nop + tstb 0x00ff82fe + nop + movel #0xff000000,%d3 /* Medusa base addr: 0xff000000 */ +Ltest_berr: + movel %a0,%sp + lea %pc@(SYMBOL_NAME(is_medusa)),%a0 + movel %d3,%a0@ + + /* Let the root table point to the new pointer table */ + lea %a5@(512),%a0 + addl #TABLEDESC,%a0 + movel %a0,%a4@(508) /* 0xFE000000 - 0xFFFFFFFF */ + + /* clear lower half of the pointer table (0xfexxxxxx) */ + lea %a5@(512),%a0 + movel #0,%d0 + movel #63,%d2 +1: movel %d0,%a0@+ + dbra %d2,1b + + btst #BIT0460,%d6 + bne Lspata68040 + +/* Mapping of the last 16M of virtual address space to the first 16M + for efficient addressing of hardware registers */ + movel #0x40000,%d1 + movel #63,%d2 + movel %d3,%d0 + addl #PAGEDESC,%d0 +1: movel %d0,%a0@+ + addl %d1,%d0 + dbra %d2,1b + moveq #0x40,%d0 /* make non-cachable */ + addl %d0,%a5@(1020) /* 0xFFFC0000-0xFFFFFFFF (I/O space) */ +/* GK: 0xFFF00000-0xFFF3FFFF (IDE-bus) has to be non-cachable too */ + addl %d0,%a5@(1008) + + bra Lmapphys + +Lspata68040: + /* allocate 4 page tables */ + movel %a6,%a3 + addw #(4*PAGESIZE),%a6 + +/* Initialize the upper half of the pointer table (a0 is still valid) */ + movel %a3,%a1 + addql #TABLEDESC,%a1 + movel #256,%d2 + moveq #63,%d1 +1: movel %a1,%a0@+ + addl %d2,%a1 + dbra %d1,1b + + /* Initialize the page tables as noncacheable/serialized! */ + movel %a3,%a0 + movel %d3,%a1 + addw #(GLOBAL+CM_NONCACHE_SER+PAGEDESC),%a1 + movel #PAGESIZE,%d2 + movew #(PAGESIZE-1),%d1 +1: movel %a1,%a0@+ + addl %d2,%a1 + dbra %d1,1b + + /* + * Finally, since we just allocated 4 page tables, make sure that + * the virtual mapping of the 4 page tables indicates + * noncachable or write-through. + */ + movel %a3,%d0 /* page table start address */ + lea %pc@(SYMBOL_NAME(_stext)-PAGESIZE:w),%a0 + subl %a0,%d0 /* determine offset of root table page */ + moveq #PAGE_INDEX_SHIFT,%d1 /* determine offset into + kernel page table */ + lsrl %d1,%d0 + movel %pc@(SYMBOL_NAME(kpt)),%a0 + moveq #3,%d2 +1: lea %a0@(%d0:l:4),%a1 + movel %a1@,%d1 + andl #CM_MASK,%d1 + orw %d6,%d1 + movel %d1,%a1@ + addql #1,%d0 + dbra %d2,1b + +Lnotatari: + +/* + * Setup a transparent mapping of the physical memory we are executing in. + * + * Only do this if the physical memory is not in the first 16M Meg, or not on + * an Amiga since the first 16M is already identity mapped on the Amiga. + */ +Lmapphys: + moveq #'J',%d7 + jbsr Lserial_putc + + clrl %d5 /* indicate that no cleanup is required */ + + cmpl #MACH_AMIGA,%d4 + bne Lmapphysnotamiga /* other machines will probably have + * to put in code and jump to it here + */ + +/* + * The virtual address of the start of the kernel is 0x1000. On ALL + * Amigas, there is CHIP RAM in this area. Hence we will copy the MMU + * enabling code to CHIP RAM (to the same physical address as the kernel + * virtual address) and jump to it. When the MMU is enabled, we will be + * running from the code in the kernel virtual space, rather than the + * physical space. + */ + +/* + * Setup Supervisor Root Pointer register to point to page directory, + * setup translation register contents and enable translation. + */ + btst #BIT0460,%d6 + bne Lamimmu68040 + + moveq #'K',%d7 + jbsr Lserial_putc + + lea %pc@(mmu),%a0 + movel #0x80000002,%a0@ /* no limit, 4byte descriptors */ + movel %a4,%a0@(4) + pmove %a0@,%srp + pmove %a0@,%crp + /* + * enable,super root enable,4096 byte pages,7 bit root index, + * 7 bit pointer index, 6 bit page table index. + */ + movel #0x82c07760,%a0@ + + /* setup registers for jumping MMU enabling code */ + lea %pc@(Ldoit030ami),%a2 + lea Ldoit030ami,%a1 + + moveq #CR,%d7 + jbsr Lserial_putc + moveq #LF,%d7 + jbsr Lserial_putc + movel %a2,%d7 + jbsr Lserial_putnum + moveq #' ',%d7 + jbsr Lserial_putc + movel %a1,%d7 + jbsr Lserial_putnum + + bra LdoitAmiga + +#ifdef __ELF__ + .align 16 +#else + .align 4 +#endif +Ldoit030ami: + pmove %a0@,%tc /* enable the MMU */ + jra LdoneMMUenable /* branch to continuation of startup */ + +Lamimmu68040: + moveq #'L',%d7 + jbsr Lserial_putc + + .word 0xf4d8 /* CINVA I/D */ + .word 0xf518 /* pflusha */ + .long 0x4e7bc807 /* movec a5,srp */ + .long 0x4e7bc806 /* movec a5,urp */ + movel #(TC_ENABLE+TC_PAGE4K),%d0 + + /* setup registers for jumping MMU enabling code */ + lea Ldoit040ami,%a1 + lea %pc@(Ldoit040ami),%a2 + bra LdoitAmiga + +#ifdef __ELF__ + .align 16 +#else + .align 4 +#endif +Ldoit040ami: + .long 0x4e7b0003 /* movec d0,tc (enable the MMU) */ + jra LdoneMMUenable /* branch to continuation of startup */ + +LdoitAmiga: + /* copy the appropriate code (two longwords) to chipmem */ + movel %a2@,%a1@ + movel %a2@(4),%a1@(4) + + /* + * save physaddr of phys mem in register a3 + */ + lea %pc@(SYMBOL_NAME(_stext)-PAGESIZE:w),%a3 + + /* jump to the physical address in chipmem */ + jmp %a1@ + +Lmapphysnotamiga: + + cmpl #MACH_ATARI,%d4 + bne Lmapphysnotatari + + lea %pc@(SYMBOL_NAME(_stext)-PAGESIZE),%a0 + tstl %a0 + jeq Lnophys2 + + /* The kernel physical address is different from its virtual + address. Temporarily set up an identity mapping of the + 16MB chunk where the kernel is executing. */ + + /* 680[46]0? */ + btst #BIT0460,%d6 + jeq 1f + + /* + * For the 68040, we will use the transparent translation + * registers to identity map the 16M chunk that contains + * the physical memory. + */ + movel %a0,%d2 + andl #0xff000000,%d2 /* logical address base */ + orw #0xc040,%d2 /* add in magic bits */ + .long 0x4e7b2004 /* movec d2,ittr0 */ + .long 0x4e7b2006 /* movec d2,dttr0 */ + + /* d5 is kept 0 to do no cleanup. This didn't work in head.S, I don't + * know why... The transparent translation is turned off in + * atari/config.c instead. + */ + jra Lnophys2 + + /* Transparent translation for the 68030 via transparent translation + register */ + +1: + /* cleanup is needed; note it */ + moveq #1,%d5 + + movel %a0,%d2 + andl #0xff000000,%d2 /* logical address base */ + orw #0x8143,%d2 /* add in magic bits */ + lea %pc@(mmu),%a0 + movel %d2,%a0@ + pmove %a0@,%tt0 + +Lnophys2: + /* + * save physaddr of phys mem in register a3 + */ + lea %pc@(SYMBOL_NAME(_stext)-PAGESIZE:w),%a3 + + btst #BIT0460,%d6 + jne Latarimmu68040 + + moveq #'K',%d7 + jbsr Lserial_putc + + lea %pc@(mmu),%a0 + movel #0x80000002,%a0@ /* no limit, 4byte descriptors */ + movel %a4,%a0@(4) + pmove %a0@,%srp + pmove %a0@,%crp + /* + * enable,super root enable,4096 byte pages,7 bit root index, + * 7 bit pointer index, 6 bit page table index. + */ + movel #0x82c07760,%a0@ + pmove %a0@,%tc /* enable the MMU */ + + /* Jump to the virtual address of continuation of startup. */ + jmp LdoneMMUenable + +Latarimmu68040: + moveq #'L',%d7 + jbsr Lserial_putc + + .word 0xf4d8 /* CINVA I/D */ + .word 0xf518 /* pflusha */ + .long 0x4e7bc807 /* movec a4,srp */ + .long 0x4e7bc806 /* movec a4,urp */ + movel #(TC_ENABLE+TC_PAGE4K),%d0 + /* this value is also ok for the '060, we don't use the cache + * mode/protection defaults */ + .long 0x4e7b0003 /* movec d0,tc (enable the MMU) */ + jmp LdoneMMUenable /* jump to virtual address of + continuation of startup */ + +Lmapphysnotatari: + + +LdoneMMUenable: + +/* + * Fixup the addresses for the kernel pointer table and availmem. + * Convert them from physical addresses to virtual addresses. + */ + + /* + * fixup the Amiga custom register location before printing + */ + addl #0x80000000,Lcustom + + /* The same for the Atari */ + movel #0xff000000,Liobase + + moveq #'M',%d7 + jbsr Lserial_putc + + /* + * a3 contains physaddr of kernel start + */ + movel SYMBOL_NAME(kpt),%d1 + subl %a3,%d1 + movel %d1,SYMBOL_NAME(kpt) + + /* + * do the same conversion on the first available memory + * address (in a6). + */ + subl %a3,%a6 + + /* Allocate a page to be used by get_kpointer_table. */ + movel %a6,SYMBOL_NAME(kernel_pmd_table) + addl #PAGESIZE,%a6 + movel %a6,SYMBOL_NAME(availmem) /* first available memory address */ + + moveq #'N',%d7 + jbsr Lserial_putc + + /* + * Clean up the temporary physical mapping (if necessary) + */ + + tstl %d5 + jeq Lnoclean + + btst #BIT0460,%d6 + jne Loff040 + + /* clean up physical identity mapping for 68020/68030 */ + /* Is this needed for the Amiga anymore? */ + /* it's not in 1.2.13pl6 - Jes */ + cmpl #MACH_AMIGA,%d4 + jeq Lclean030 + cmpl #MACH_ATARI,%d4 + jne Lnoclean + + /* clear transparent translation register */ + lea %pc@(mmu),%a0 + clrl %a0@ + pmove %a0@,%tt0 + jra Lnoclean + +Lclean030: + movel %a0,%d2 /* a0 contains physical start address */ + moveq #25,%d3 /* find appropriate index in root table */ + lsrl %d3,%d2 + moveq #0,%d0 + movel %d0,%a4@(%d2:l:4) /* clear descriptor */ + + jra Lnoclean + +Loff040: + /* turn off transparent translation registers for '0[46]0 */ + moveq #0,%d0 + .long 0x4e7b0004 /* movec d0,ittr0 */ + .long 0x4e7b0006 /* movec d0,dttr0 */ + +Lnoclean: + moveq #'O',%d7 + jbsr Lserial_putc + + +/* + * Enable caches + */ + btst #BIT0460,%d6 + jne Lcache680460 + + movel #0x00001919,%d0 + movec %d0,%cacr + jra 1f + +Lcache680460: + btst #BIT060,%d6 + jne Lcache68060 + + .word 0xf4d8 /* CINVA I/D */ + movel #I_ENABLE+D_ENABLE,%d0 + /* MMU stuff works in copyback mode now, so enable the cache */ + movec %d0,%cacr + jra 1f + +Lcache68060: + .word 0xf4d8 /* CINVA I/D */ + movel #I_ENABLE+D_ENABLE+SB_ENABLE+PUSH_DPI+BC_ENABLE+BC_CLRA,%d0 + /* MMU stuff works in copyback mode now, so enable the cache */ + movec %d0,%cacr + /* enable superscalar dispatch in PCR */ + moveq #1,%d0 + .long 0x4e7b0808 /* movec d0,pcr */ + +1: + +/* + * Setup initial stack pointer + */ + lea SYMBOL_NAME(init_user_stack)+PAGESIZE,%sp + +/* jump to the kernel start */ + + jbsr SYMBOL_NAME(start_kernel) + +#if 0 +tmp_fault_handler: + lea %pc@(tfh_1st_str),%a0 + jbsr Lserial_puts + move.l %sp@(2),%d7 /* PC */ + jbsr Lserial_putnum + move.w %sp@(0xa),%d7 + swap %d7 + move.w %sp@(0x6),%d7 + jbsr Lserial_putnum + lea %pc@(tfh_2nd_str),%a0 + jbsr Lserial_puts + move.l %sp@(0x10),%d7 /* Fault address */ + jbsr Lserial_putnum + moveq #CR,%d7 + jbsr Lserial_putc + moveq #LF,%d7 + jbsr Lserial_putc +1: jra 1b + +tfh_1st_str: + .byte CR + .byte LF + .ascii "Access fault occurred. PC = " + .byte 0 + +tfh_2nd_str: + .byte CR + .byte LF + .ascii "FaultAddress = " + .byte 0 +#endif + +/* + * Serial port output support. + */ +LSERPER = 0xdff032 +LSERDAT = 0xdff030 +LSERDATR = 0xdff018 +LNTSC_PERIOD = 371 +LPAL_PERIOD = 368/2 /* /2 for 19200 baud */ +LNTSC_ECLOCK = 7159090 +LSERIAL_CNTRL = 0xbfd000 +LSERIAL_DTR = 7 + +/* + * Debug output support + * Atarians have a choice between the parallel port, the serial port + * from the MFP or a serial port of the SCC + */ + +/* #define USE_PRINTER */ +/* #define USE_SCC */ +#define USE_MFP + +#ifdef USE_PRINTER + +LPSG_SELECT = 0xff8800 +LPSG_READ = 0xff8800 +LPSG_WRITE = 0xff8802 +LPSG_IO_A = 14 +LPSG_IO_B = 15 +LPSG_CONTROL = 7 +LSTMFP_GPIP = 0xfffa01 +LSTMFP_DDR = 0xfffa05 +LSTMFP_IERB = 0xfffa09 + +#elif defined(USE_SCC) + +LSCC_CTRL_B = 0xff8c85 +LSCC_DATA_B = 0xff8c87 + +/* Initialisation table for SCC */ +scc_initable: + .byte 9,12 /* Reset */ + .byte 4,0x44 /* x16, 1 stopbit, no parity */ + .byte 3,0xc0 /* receiver: 8 bpc */ + .byte 5,0xe2 /* transmitter: 8 bpc, assert dtr/rts */ + .byte 9,0 /* no interrupts */ + .byte 10,0 /* NRZ */ + .byte 11,0x50 /* use baud rate generator */ + .byte 12,24,13,0 /* 9600 baud */ + .byte 14,2,14,3 /* use master clock for BRG, enable */ + .byte 3,0xc1 /* enable receiver */ + .byte 5,0xea /* enable transmitter */ + .byte -1 + .even + +#elif defined(USE_MFP) + +LMFP_UCR = 0xfffa29 +LMFP_TDCDR = 0xfffa1d +LMFP_TDDR = 0xfffa25 +LMFP_TSR = 0xfffa2d +LMFP_UDR = 0xfffa2f + +#endif + +/* + * Initialize serial port hardware for 9600/8/1 + * a0 thrashed + * Atari d0 trashed (a1 in case of SCC) + */ + .even +Lserial_init: + cmpil #MACH_AMIGA,%d4 + jne 1f + bclr #LSERIAL_DTR,LSERIAL_CNTRL + movew #LNTSC_PERIOD,LSERPER + cmpl #LNTSC_ECLOCK,%a0@(BI_AMIGA_ECLK) + jeq 9f + movew #LPAL_PERIOD,LSERPER + jra 9f +1: cmpil #MACH_ATARI,%d4 + jne 9f +#ifdef USE_PRINTER + bclr #0,LSTMFP_IERB + bclr #0,LSTMFP_DDR + moveb #LPSG_CONTROL,LPSG_SELECT + moveb #0xff,LPSG_WRITE + moveb #LPSG_IO_B,LPSG_SELECT + clrb LPSG_WRITE + moveb #LPSG_IO_A,LPSG_SELECT + moveb LPSG_READ,%d0 + bset #5,%d0 + moveb %d0,LPSG_WRITE +#elif defined(USE_SCC) + lea LSCC_CTRL_B,%a0 + lea %pc@(scc_initable:w),%a1 +2: moveb %a1@+,%d0 + jmi 3f + moveb %d0,%a0@ + moveb %a1@+,%a0@ + jra 2b +3: clrb %a0@ +#elif defined(USE_MFP) + bclr #1,LMFP_TSR + moveb #0x88,LMFP_UCR + andb #0x70,LMFP_TDCDR + moveb #2,LMFP_TDDR + orb #1,LMFP_TDCDR + bset #1,LMFP_TSR +#endif +9: + rts + +/* + * Output character in d7 on serial port. + * d7 thrashed. + */ +Lserial_putc: + moveml %a0/%a1,%sp@- + cmpil #MACH_AMIGA,%d4 + jne 2f + andw #0x00ff,%d7 + oriw #0x0100,%d7 + movel %pc@(Lcustom),%a1 + movew %d7,%a1@(LSERDAT) +1: movew %a1@(LSERDATR),%d7 + andw #0x2000,%d7 + jeq 1b + jra 9f +2: cmpil #MACH_ATARI,%d4 + jne 9f + movel %pc@(Liobase),%a1 +#ifdef USE_PRINTER +3: btst #0,%a1@(LSTMFP_GPIP) + jne 3b + moveb #LPSG_IO_B,%a1@(LPSG_SELECT) + moveb %d7,%a1@(LPSG_WRITE) + moveb #LPSG_IO_A,%a1@(LPSG_SELECT) + moveb %a1@(LPSG_READ),%d7 + bclr #5,%d7 + moveb %d7,%a1@(LPSG_WRITE) + nop + nop + bset #5,%d7 + moveb %d7,%a1@(LPSG_WRITE) +#elif defined(USE_SCC) +3: btst #2,%a1@(LSCC_CTRL_B) + jeq 3b + moveb %d7,%a1@(LSCC_DATA_B) +#elif defined(USE_MFP) +3: btst #7,%a1@(LMFP_TSR) + jeq 3b + moveb %d7,%a1@(LMFP_UDR) +#endif +9: + moveml %sp@+,%a0/%a1 + rts + +/* + * Output string pointed to by a0 to serial port. + * a0 trashed. + */ +Lserial_puts: + movel %d7,%sp@- +1: moveb %a0@+,%d7 + jeq 2f + jbsr Lserial_putc + jra 1b +2: movel %sp@+,%d7 + rts + +/* + * Output number in d7 in hex notation on serial port. + * d0-d2 trashed. + * d7 trashed. + */ + +Lserial_putnum: + moveml %d0-%d2/%d7,%sp@- + movel %d7,%d1 + moveq #4,%d0 + moveq #7,%d2 +L1: roll %d0,%d1 + moveb %d1,%d7 + andb #0x0f,%d7 + cmpb #0x0a,%d7 + bccs 1f + addb #'0',%d7 + jra 2f +1: addb #'A'-10,%d7 +2: jbsr Lserial_putc + dbra %d2,L1 + moveq #32,%d7 + jbsr Lserial_putc + moveml %sp@+,%d0-%d2/%d7 + rts +#if 0 +.globl showtest +showtest: + moveml %a1/%d7,%sp@- + moveq #'A',%d7 + jbsr Lserial_putc + moveq #'=',%d7 + jbsr Lserial_putc + movel %a0,%d7 + jbsr Lserial_putnum + + ptestr #5,%a0@,#7,%a1 + + moveq #'D',%d7 + jbsr Lserial_putc + moveq #'A',%d7 + jbsr Lserial_putc + moveq #'=',%d7 + jbsr Lserial_putc + + movel %a1,%d7 + jbsr Lserial_putnum + + moveq #'D',%d7 + jbsr Lserial_putc + moveq #'=',%d7 + jbsr Lserial_putc + movel %a1@,%d7 + jbsr Lserial_putnum + + moveq #'S',%d7 + jbsr Lserial_putc + moveq #'=',%d7 + jbsr Lserial_putc + + lea %pc@(mmu),%a1 + pmove %psr,%a1@ + clrl %d7 + movew %a1@,%d7 + jbsr Lserial_putnum + + moveq #CR,%d7 + jbsr Lserial_putc + moveq #LF,%d7 + jbsr Lserial_putc + + moveml %sp@+,%a1/%d7 + rts +#endif + + .align 512 /* + * MMU root-pointers need to be 512-byte + * aligned on the 680[46]0 - Jes + */ + +SYMBOL_NAME_LABEL(swapper_pg_dir) + .skip ROOT_TABLE_SIZE * 4 +SYMBOL_NAME_LABEL(kernel_pg_dir) + .skip ROOT_TABLE_SIZE * 4 + + .data + .even +Lcustom: + .long 0 +Liobase: + .long 0 +mmu: .quad 0 +SYMBOL_NAME_LABEL(kernel_pmd_table) + .long 0 +SYMBOL_NAME_LABEL(kpt) + .long 0 +SYMBOL_NAME_LABEL(availmem) + .long 0 +SYMBOL_NAME_LABEL(is_medusa) + .long 0 +SYMBOL_NAME_LABEL(m68k_pgtable_cachemode) + .long 0 diff -u --recursive --new-file v1.3.93/linux/arch/m68k/kernel/ints.c linux/arch/m68k/kernel/ints.c --- v1.3.93/linux/arch/m68k/kernel/ints.c Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/kernel/ints.c Sun Mar 31 14:03:24 1996 @@ -0,0 +1,236 @@ +/* + * ints.c -- 680x0 Linux general interrupt handling code + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file README.legal in the main directory of this archive + * for more details. + * + * 07/03/96: Timer initialization, and thus mach_sched_init(), + * removed from request_irq() and moved to init_time(). + * We should therefore consider renaming our add_isr() and + * remove_isr() to request_irq() and free_irq() + * respectively, so they are compliant with the other + * architectures. /Jes + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* list is accessed 0-6 for IRQs 1-7 */ +static isr_node_t *isr_list[7]; + +/* The number of spurious interrupts */ +volatile unsigned long num_spurious; +/* +unsigned long interrupt_stack[PAGE_SIZE/sizeof(long)]; +*/ + +/* + * void init_IRQ(void) + * + * Parameters: None + * + * Returns: Nothing + * + * This function should be called during kernel startup to initialize + * the IRQ handling routines. + */ + +void init_IRQ(void) +{ + /* Setup interrupt stack pointer */ + /* + asm ("movec %0,%/isp" + : : "r" (interrupt_stack + sizeof (interrupt_stack) / sizeof (long))); + */ + mach_init_INTS (); +} + +void insert_isr (isr_node_t **listp, isr_node_t *node) +{ + unsigned long spl; + isr_node_t *cur; + + save_flags(spl); + cli(); + + cur = *listp; + + while (cur && cur->pri <= node->pri) + { + listp = &cur->next; + cur = cur->next; + } + + node->next = cur; + *listp = node; + + restore_flags(spl); +} + +void delete_isr (isr_node_t **listp, isrfunc isr) +{ + unsigned long flags; + isr_node_t *np; + + save_flags(flags); + cli(); + for (np = *listp; np; listp = &np->next, np = *listp) { + if (np->isr == isr) { + *listp = np->next; + /* Mark it as free. */ + np->isr = NULL; + restore_flags(flags); + return; + } + } + restore_flags(flags); + printk ("delete_isr: isr %p not found on list!\n", isr); +} + +#define NUM_ISR_NODES 100 +static isr_node_t nodes[NUM_ISR_NODES]; + +isr_node_t *new_isr_node(void) +{ + isr_node_t *np; + + for (np = nodes; np < &nodes[NUM_ISR_NODES]; np++) + if (np->isr == NULL) + return np; + + printk ("new_isr_node: out of nodes"); + return NULL; +} + +int add_isr (unsigned long source, isrfunc isr, int pri, void *data, + char *name) +{ + isr_node_t *p; + + if (source & IRQ_MACHSPEC) + { + return mach_add_isr (source, isr, pri, data, name); + } + + if (source < IRQ1 || source > IRQ7) + panic ("add_isr: Incorrect IRQ source %ld from %s\n", source, name); + + p = new_isr_node(); + if (p == NULL) + return 0; + p->isr = isr; + p->pri = pri; + p->data = data; + p->name = name; + p->next = NULL; + + insert_isr (&isr_list[source-1], p); + + return 1; +} + +int remove_isr (unsigned long source, isrfunc isr) +{ + if (source & IRQ_MACHSPEC) + return mach_remove_isr (source, isr); + + if (source < IRQ1 || source > IRQ7) { + printk ("remove_isr: Incorrect IRQ source %ld\n", source); + return 0; + } + + delete_isr (&isr_list[source - 1], isr); + return 1; +} + +void call_isr_list(int irq, isr_node_t *p, struct pt_regs *fp) +{ + while (p) { + p->isr (irq, fp, p->data); + p = p->next; + } +} + +asmlinkage void process_int(int vec, struct pt_regs *regs) +{ + int level; + + if (vec >= VECOFF(VEC_INT1) && vec <= VECOFF(VEC_INT7)) + level = (vec - VECOFF(VEC_SPUR)) >> 2; + else { + if (mach_process_int) + mach_process_int(vec, regs); + else + panic("Can't process interrupt vector 0x%03x\n", vec); + return; + } + + kstat.interrupts[level]++; + call_isr_list (level, isr_list[level-1], regs); +} + +int request_irq(unsigned int irq, + void (*handler)(int, void *, struct pt_regs *), + unsigned long flags, const char * devname, void *dev_id) +{ + return -EINVAL; +} + +void free_irq(unsigned int irq, void *dev_id) +{ +} + +/* + * Do we need these probe functions on the m68k? + */ +unsigned long probe_irq_on (void) +{ + return 0; +} + +int probe_irq_off (unsigned long irqs) +{ + return 0; +} + +void enable_irq(unsigned int irq_nr) +{ + if ((irq_nr & IRQ_MACHSPEC) && mach_enable_irq) + mach_enable_irq(irq_nr); +} + +void disable_irq(unsigned int irq_nr) +{ + if ((irq_nr & IRQ_MACHSPEC) && mach_disable_irq) + mach_disable_irq(irq_nr); +} + +int get_irq_list(char *buf) +{ + int i, len = 0; + isr_node_t *p; + + /* autovector interrupts */ + for (i = IRQ1; i <= IRQ7; ++i) { + if (!isr_list[i-1]) + continue; + len += sprintf(buf+len, "auto %2d: %8d ", i, kstat.interrupts[i]); + for (p = isr_list[i-1]; p; p = p->next) { + len += sprintf(buf+len, "%s\n", p->name); + if (p->next) + len += sprintf(buf+len, " "); + } + } + + len = mach_get_irq_list(buf, len); + return len; +} diff -u --recursive --new-file v1.3.93/linux/arch/m68k/kernel/ksyms.c linux/arch/m68k/kernel/ksyms.c --- v1.3.93/linux/arch/m68k/kernel/ksyms.c Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/kernel/ksyms.c Tue Apr 9 17:28:13 1996 @@ -0,0 +1,69 @@ +#include +#include +#include +#include +#include + +#include +#include + +asmlinkage long long __ashrdi3 (long long, int); +extern char m68k_debug_device[]; + +#ifdef CONFIG_ATARI +extern void mach_atari_syms_export (void); +#endif +#ifdef CONFIG_AMIGA +extern void mach_amiga_syms_export (void); +#endif +#ifdef CONFIG_MAC +extern void mach_mac_syms_export (void); +#endif + +static struct symbol_table arch_symbol_table = { +#include + /* platform dependent support */ + + X(memcmp), + X(boot_info), + X(m68k_is040or060), + X(cache_push), + X(cache_clear), + X(mm_vtop), + X(mm_ptov), + X(m68k_debug_device), + + /* The following are special because they're not called + explicitly (the C compiler generates them). Fortunately, + their interface isn't gonna change any time soon now, so + it's OK to leave it out of version control. */ + XNOVERS(__ashrdi3), + XNOVERS(memcpy), + +#include +}; + +void arch_syms_export(void) +{ + register_symtab(&arch_symbol_table); + + switch (boot_info.machtype) { +#ifdef CONFIG_ATARI + case MACH_ATARI: + mach_atari_syms_export(); + break; +#endif +#ifdef CONFIG_AMIGA + case MACH_AMIGA: + mach_amiga_syms_export(); + break; +#endif +#ifdef CONFIG_MAC + case MACH_MAC: + mach_mac_syms_export(); + break; +#endif + default: + break; + } +} diff -u --recursive --new-file v1.3.93/linux/arch/m68k/kernel/process.c linux/arch/m68k/kernel/process.c --- v1.3.93/linux/arch/m68k/kernel/process.c Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/kernel/process.c Mon Apr 1 21:40:27 1996 @@ -0,0 +1,200 @@ +/* + * linux/arch/m68k/kernel/process.c + * + * Copyright (C) 1995 Hamish Macdonald + */ + +/* + * This file handles the architecture-dependent parts of process handling.. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +asmlinkage void ret_from_exception(void); + +/* + * The idle loop on an m68k.. + */ +asmlinkage int sys_idle(void) +{ + if (current->pid != 0) + return -EPERM; + + /* endless idle loop with no priority at all */ + current->counter = -100; + for (;;) + schedule(); +} + +void hard_reset_now(void) +{ + if (mach_reset) + mach_reset(); +} + +void show_regs(struct pt_regs * regs) +{ + printk("\n"); + printk("Format %02x Vector: %04x PC: %08lx Status: %04x\n", + regs->format, regs->vector, regs->pc, regs->sr); + printk("ORIG_D0: %08lx D0: %08lx A1: %08lx\n", + regs->orig_d0, regs->d0, regs->a1); + printk("A0: %08lx D5: %08lx D4: %08lx\n", + regs->a0, regs->d5, regs->d4); + printk("D3: %08lx D2: %08lx D1: %08lx\n", + regs->d3, regs->d2, regs->d1); + if (!(regs->sr & PS_S)) + printk("USP: %08lx\n", rdusp()); +} + +/* + * Free current thread data structures etc.. + */ +void exit_thread(void) +{ +} + +void flush_thread(void) +{ + set_fs(USER_DS); + current->tss.fs = USER_DS; +} + +/* + * "m68k_fork()".. By the time we get here, the + * non-volatile registers have also been saved on the + * stack. We do some ugly pointer stuff here.. (see + * also copy_thread) + */ + +asmlinkage int m68k_fork(struct pt_regs *regs) +{ + return do_fork(SIGCHLD, rdusp(), regs); +} + +asmlinkage int m68k_clone(struct pt_regs *regs) +{ + unsigned long clone_flags; + unsigned long newsp; + + /* syscall2 puts clone_flags in d1 and usp in d2 */ + clone_flags = regs->d1; + newsp = regs->d2; + if (!newsp) + newsp = rdusp(); + return do_fork(clone_flags, newsp, regs); +} + +void release_thread(struct task_struct *dead_task) +{ +} + +void copy_thread(int nr, unsigned long clone_flags, unsigned long usp, + struct task_struct * p, struct pt_regs * regs) +{ + struct pt_regs * childregs; + struct switch_stack * childstack, *stack; + unsigned long stack_offset, *retp; + + stack_offset = PAGE_SIZE - sizeof(struct pt_regs); + childregs = (struct pt_regs *) (p->kernel_stack_page + stack_offset); + + *childregs = *regs; + childregs->d0 = 0; + + retp = ((unsigned long *) regs); + stack = ((struct switch_stack *) retp) - 1; + + childstack = ((struct switch_stack *) childregs) - 1; + *childstack = *stack; + childstack->retpc = (unsigned long) ret_from_exception; + + p->tss.usp = usp; + p->tss.ksp = (unsigned long)childstack; + + /* Copy the current fpu state */ + asm volatile ("fsave %0" : : "m" (p->tss.fpstate[0]) : "memory"); + if (p->tss.fpstate[0]) + asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t" + "fmoveml %/fpiar/%/fpcr/%/fpsr,%1" + : : "m" (p->tss.fp[0]), "m" (p->tss.fpcntl[0]) + : "memory"); + /* Restore the state in case the fpu was busy */ + asm volatile ("frestore %0" : : "m" (p->tss.fpstate[0])); +} + +/* Fill in the fpu structure for a core dump. */ + +int dump_fpu (struct user_m68kfp_struct *fpu) +{ + char fpustate[216]; + + /* First dump the fpu context to avoid protocol violation. */ + asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory"); + if (!fpustate[0]) + return 0; + + asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0" + :: "m" (fpu->fpcntl[0]) + : "memory"); + asm volatile ("fmovemx %/fp0-%/fp7,%0" + :: "m" (fpu->fpregs[0]) + : "memory"); + return 1; +} + +/* + * fill in the user structure for a core dump.. + */ +void dump_thread(struct pt_regs * regs, struct user * dump) +{ +/* changed the size calculations - should hopefully work better. lbt */ + dump->magic = CMAGIC; + dump->start_code = 0; + dump->start_stack = rdusp() & ~(PAGE_SIZE - 1); + dump->u_tsize = ((unsigned long) current->mm->end_code) >> PAGE_SHIFT; + dump->u_dsize = ((unsigned long) (current->mm->brk + + (PAGE_SIZE-1))) >> PAGE_SHIFT; + dump->u_dsize -= dump->u_tsize; + dump->u_ssize = 0; + + if (dump->start_stack < TASK_SIZE) + dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> PAGE_SHIFT; + + dump->u_ar0 = (struct pt_regs *)(((int)(&dump->regs)) -((int)(dump))); + dump->regs = *regs; + dump->regs2 = ((struct switch_stack *)regs)[-1]; + /* dump floating point stuff */ + dump->u_fpvalid = dump_fpu (&dump->m68kfp); +} + +/* + * sys_execve() executes a new program. + */ +asmlinkage int sys_execve(char *name, char **argv, char **envp) +{ + int error; + char * filename; + struct pt_regs *regs = (struct pt_regs *) &name; + + error = getname(name, &filename); + if (error) + return error; + error = do_execve(filename, argv, envp, regs); + putname(filename); + return error; +} diff -u --recursive --new-file v1.3.93/linux/arch/m68k/kernel/ptrace.c linux/arch/m68k/kernel/ptrace.c --- v1.3.93/linux/arch/m68k/kernel/ptrace.c Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/kernel/ptrace.c Fri Apr 5 20:40:35 1996 @@ -0,0 +1,534 @@ +/* + * linux/arch/m68k/kernel/ptrace.c + * + * Copyright (C) 1994 by Hamish Macdonald + * Taken from linux/kernel/ptrace.c and modified for M680x0. + * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file README.legal in the main directory of + * this archive for more details. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* + * does not yet catch signals sent when the child dies. + * in exit.c or in signal.c. + */ + +/* determines which bits in the SR the user has access to. */ +/* 1 = access 0 = no access */ +#define SR_MASK 0x001f + +/* sets the trace bits. */ +#define TRACE_BITS 0x8000 + +/* Find the stack offset for a register, relative to tss.esp0. */ +#define PT_REG(reg) ((long)&((struct pt_regs *)0)->reg) +#define SW_REG(reg) ((long)&((struct switch_stack *)0)->reg \ + - sizeof(struct switch_stack)) +/* Mapping from PT_xxx to the stack offset at which the register is + saved. Notice that usp has no stack-slot and needs to be treated + specially (see get_reg/put_reg below). */ +static int regoff[] = { + PT_REG(d1), PT_REG(d2), PT_REG(d3), PT_REG(d4), + PT_REG(d5), SW_REG(d6), SW_REG(d7), PT_REG(a0), + PT_REG(a1), SW_REG(a2), SW_REG(a3), SW_REG(a4), + SW_REG(a5), SW_REG(a6), PT_REG(d0), -1, + PT_REG(orig_d0), PT_REG(sr), PT_REG(pc), +}; + +/* change a pid into a task struct. */ +static inline struct task_struct * get_task(int pid) +{ + int i; + + for (i = 1; i < NR_TASKS; i++) { + if (task[i] != NULL && (task[i]->pid == pid)) + return task[i]; + } + return NULL; +} + +/* + * Get contents of register REGNO in task TASK. + */ +static inline long get_reg(struct task_struct *task, int regno) +{ + unsigned long *addr; + + if (regno == PT_USP) + addr = &task->tss.usp; + else if (regno < sizeof(regoff)/sizeof(regoff[0])) + addr = (unsigned long *)(task->tss.esp0 + regoff[regno]); + else + return 0; + return *addr; +} + +/* + * Write contents of register REGNO in task TASK. + */ +static inline int put_reg(struct task_struct *task, int regno, + unsigned long data) +{ + unsigned long *addr; + + if (regno == PT_USP) + addr = &task->tss.usp; + else if (regno < sizeof(regoff)/sizeof(regoff[0])) + addr = (unsigned long *) (task->tss.esp0 + regoff[regno]); + else + return -1; + *addr = data; + return 0; +} + +/* + * This routine gets a long from any process space by following the page + * tables. NOTE! You should check that the long isn't on a page boundary, + * and that it is in the task area before calling this: this routine does + * no checking. + * + */ +static unsigned long get_long(struct task_struct * tsk, + struct vm_area_struct * vma, unsigned long addr) +{ + pgd_t * pgdir; + pmd_t * pgmiddle; + pte_t * pgtable; + unsigned long page; + +repeat: + pgdir = pgd_offset(vma->vm_mm, addr); + if (pgd_none(*pgdir)) { + do_no_page(tsk, vma, addr, 0); + goto repeat; + } + if (pgd_bad(*pgdir)) { + printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir)); + pgd_clear(pgdir); + return 0; + } + pgmiddle = pmd_offset(pgdir,addr); + if (pmd_none(*pgmiddle)) { + do_no_page(tsk, vma, addr, 0); + goto repeat; + } + if (pmd_bad(*pgmiddle)) { + printk("ptrace: bad page directory %08lx\n", + pmd_val(*pgmiddle)); + pmd_clear(pgmiddle); + return 0; + } + pgtable = pte_offset(pgmiddle, addr); + if (!pte_present(*pgtable)) { + do_no_page(tsk, vma, addr, 0); + goto repeat; + } + page = pte_page(*pgtable); +/* this is a hack for non-kernel-mapped video buffers and similar */ + if (page >= high_memory) + return 0; + page += addr & ~PAGE_MASK; + return *(unsigned long *) page; +} + +/* + * This routine puts a long into any process space by following the page + * tables. NOTE! You should check that the long isn't on a page boundary, + * and that it is in the task area before calling this: this routine does + * no checking. + * + * Now keeps R/W state of page so that a text page stays readonly + * even if a debugger scribbles breakpoints into it. -M.U- + */ +static void put_long(struct task_struct * tsk, struct vm_area_struct * vma, unsigned long addr, + unsigned long data) +{ + pgd_t *pgdir; + pmd_t *pgmiddle; + pte_t *pgtable; + unsigned long page; + +repeat: + pgdir = pgd_offset(vma->vm_mm, addr); + if (!pgd_present(*pgdir)) { + do_no_page(tsk, vma, addr, 1); + goto repeat; + } + if (pgd_bad(*pgdir)) { + printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir)); + pgd_clear(pgdir); + return; + } + pgmiddle = pmd_offset(pgdir,addr); + if (pmd_none(*pgmiddle)) { + do_no_page(tsk, vma, addr, 1); + goto repeat; + } + if (pmd_bad(*pgmiddle)) { + printk("ptrace: bad page directory %08lx\n", + pmd_val(*pgmiddle)); + pmd_clear(pgmiddle); + return; + } + pgtable = pte_offset(pgmiddle, addr); + if (!pte_present(*pgtable)) { + do_no_page(tsk, vma, addr, 1); + goto repeat; + } + page = pte_page(*pgtable); + if (!pte_write(*pgtable)) { + do_wp_page(tsk, vma, addr, 2); + goto repeat; + } +/* this is a hack for non-kernel-mapped video buffers and similar */ + if (page < high_memory) { + *(unsigned long *) (page + (addr & ~PAGE_MASK)) = data; + } +/* we're bypassing pagetables, so we have to set the dirty bit ourselves */ +/* this should also re-instate whatever read-only mode there was before */ + *pgtable = pte_mkdirty(mk_pte(page, vma->vm_page_prot)); + flush_tlb_all(); +} + +static struct vm_area_struct * find_extend_vma(struct task_struct * tsk, unsigned long addr) +{ + struct vm_area_struct * vma; + + addr &= PAGE_MASK; + vma = find_vma(tsk,addr); + if (!vma) + return NULL; + if (vma->vm_start <= addr) + return vma; + if (!(vma->vm_flags & VM_GROWSDOWN)) + return NULL; + if (vma->vm_end - addr > tsk->rlim[RLIMIT_STACK].rlim_cur) + return NULL; + vma->vm_offset -= vma->vm_start - addr; + vma->vm_start = addr; + return vma; +} + +/* + * This routine checks the page boundaries, and that the offset is + * within the task area. It then calls get_long() to read a long. + */ +static int read_long(struct task_struct * tsk, unsigned long addr, + unsigned long * result) +{ + struct vm_area_struct * vma = find_extend_vma(tsk, addr); + + if (!vma) + return -EIO; + if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) { + unsigned long low,high; + struct vm_area_struct * vma_low = vma; + + if (addr + sizeof(long) >= vma->vm_end) { + vma_low = vma->vm_next; + if (!vma_low || vma_low->vm_start != vma->vm_end) + return -EIO; + } + high = get_long(tsk, vma,addr & ~(sizeof(long)-1)); + low = get_long(tsk, vma_low,(addr+sizeof(long)) & ~(sizeof(long)-1)); + switch (addr & (sizeof(long)-1)) { + case 3: + low >>= 8; + low |= high << 24; + break; + case 2: + low >>= 16; + low |= high << 16; + break; + case 1: + low >>= 24; + low |= high << 8; + break; + } + *result = low; + } else + *result = get_long(tsk, vma,addr); + return 0; +} + +/* + * This routine checks the page boundaries, and that the offset is + * within the task area. It then calls put_long() to write a long. + */ +static int write_long(struct task_struct * tsk, unsigned long addr, + unsigned long data) +{ + struct vm_area_struct * vma = find_extend_vma(tsk, addr); + + if (!vma) + return -EIO; + if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) { + unsigned long low,high; + struct vm_area_struct * vma_low = vma; + + if (addr + sizeof(long) >= vma->vm_end) { + vma_low = vma->vm_next; + if (!vma_low || vma_low->vm_start != vma->vm_end) + return -EIO; + } + high = get_long(tsk, vma,addr & ~(sizeof(long)-1)); + low = get_long(tsk, vma_low,(addr+sizeof(long)) & ~(sizeof(long)-1)); + switch (addr & (sizeof(long)-1)) { + case 0: /* shouldn't happen, but safety first */ + high = data; + break; + case 3: + low &= 0x000000ff; + low |= data << 8; + high &= ~0xff; + high |= data >> 24; + break; + case 2: + low &= 0x0000ffff; + low |= data << 16; + high &= ~0xffff; + high |= data >> 16; + break; + case 1: + low &= 0x00ffffff; + low |= data << 24; + high &= ~0xffffff; + high |= data >> 8; + break; + } + put_long(tsk, vma,addr & ~(sizeof(long)-1),high); + put_long(tsk, vma_low,(addr+sizeof(long)) & ~(sizeof(long)-1),low); + } else + put_long(tsk, vma,addr,data); + return 0; +} + +asmlinkage int sys_ptrace(long request, long pid, long addr, long data) +{ + struct task_struct *child; + struct user * dummy; + + dummy = NULL; + + if (request == PTRACE_TRACEME) { + /* are we already being traced? */ + if (current->flags & PF_PTRACED) + return -EPERM; + /* set the ptrace bit in the process flags. */ + current->flags |= PF_PTRACED; + return 0; + } + if (pid == 1) /* you may not mess with init */ + return -EPERM; + if (!(child = get_task(pid))) + return -ESRCH; + if (request == PTRACE_ATTACH) { + if (child == current) + return -EPERM; + if ((!child->dumpable || + (current->uid != child->euid) || + (current->uid != child->uid) || + (current->gid != child->egid) || + (current->gid != child->gid)) && !suser()) + return -EPERM; + /* the same process cannot be attached many times */ + if (child->flags & PF_PTRACED) + return -EPERM; + child->flags |= PF_PTRACED; + if (child->p_pptr != current) { + REMOVE_LINKS(child); + child->p_pptr = current; + SET_LINKS(child); + } + send_sig(SIGSTOP, child, 1); + return 0; + } + if (!(child->flags & PF_PTRACED)) + return -ESRCH; + if (child->state != TASK_STOPPED) { + if (request != PTRACE_KILL) + return -ESRCH; + } + if (child->p_pptr != current) + return -ESRCH; + + switch (request) { + /* when I and D space are separate, these will need to be fixed. */ + case PTRACE_PEEKTEXT: /* read word at location addr. */ + case PTRACE_PEEKDATA: { + unsigned long tmp; + int res; + + res = read_long(child, addr, &tmp); + if (res < 0) + return res; + res = verify_area(VERIFY_WRITE, (void *) data, sizeof(long)); + if (!res) + put_user(tmp, (unsigned long *) data); + return res; + } + + /* read the word at location addr in the USER area. */ + case PTRACE_PEEKUSR: { + unsigned long tmp; + int res; + + if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) + return -EIO; + + res = verify_area(VERIFY_WRITE, (void *) data, + sizeof(long)); + if (res) + return res; + tmp = 0; /* Default return condition */ + addr = addr >> 2; /* temporary hack. */ + if (addr < 19) { + tmp = get_reg(child, addr); + if (addr == PT_SR) + tmp >>= 16; + } + else if (addr >= 21 && addr < 49) + tmp = child->tss.fp[addr - 21]; + else + return -EIO; + put_user(tmp,(unsigned long *) data); + return 0; + } + + /* when I and D space are separate, this will have to be fixed. */ + case PTRACE_POKETEXT: /* write the word at location addr. */ + case PTRACE_POKEDATA: + return write_long(child,addr,data); + + case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ + if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) + return -EIO; + + addr = addr >> 2; /* temporary hack. */ + + if (addr == PT_ORIG_D0) + return -EIO; + if (addr == PT_SR) { + data &= SR_MASK; + data <<= 16; + data |= get_reg(child, PT_SR) & ~(SR_MASK << 16); + } + if (addr < 19) { + if (put_reg(child, addr, data)) + return -EIO; + return 0; + } + if (addr >= 21 && addr < 48) + { + child->tss.fp[addr - 21] = data; + return 0; + } + return -EIO; + + case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ + case PTRACE_CONT: { /* restart after signal. */ + long tmp; + + if ((unsigned long) data >= NSIG) + return -EIO; + if (request == PTRACE_SYSCALL) + child->flags |= PF_TRACESYS; + else + child->flags &= ~PF_TRACESYS; + child->exit_code = data; + wake_up_process(child); + /* make sure the single step bit is not set. */ + tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16); + put_reg(child, PT_SR, tmp); + return 0; + } + +/* + * make the child exit. Best I can do is send it a sigkill. + * perhaps it should be put in the status that it wants to + * exit. + */ + case PTRACE_KILL: { + long tmp; + + if (child->state == TASK_ZOMBIE) /* already dead */ + return 0; + wake_up_process(child); + child->exit_code = SIGKILL; + /* make sure the single step bit is not set. */ + tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16); + put_reg(child, PT_SR, tmp); + return 0; + } + + case PTRACE_SINGLESTEP: { /* set the trap flag. */ + long tmp; + + if ((unsigned long) data >= NSIG) + return -EIO; + child->flags &= ~PF_TRACESYS; + tmp = get_reg(child, PT_SR) | (TRACE_BITS << 16); + put_reg(child, PT_SR, tmp); + + wake_up_process(child); + child->exit_code = data; + /* give it a chance to run. */ + return 0; + } + + case PTRACE_DETACH: { /* detach a process that was attached. */ + long tmp; + + if ((unsigned long) data >= NSIG) + return -EIO; + child->flags &= ~(PF_PTRACED|PF_TRACESYS); + wake_up_process(child); + child->exit_code = data; + REMOVE_LINKS(child); + child->p_pptr = child->p_opptr; + SET_LINKS(child); + /* make sure the single step bit is not set. */ + tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16); + put_reg(child, PT_SR, tmp); + return 0; + } + + default: + return -EIO; + } +} + +asmlinkage void syscall_trace(void) +{ + if ((current->flags & (PF_PTRACED|PF_TRACESYS)) + != (PF_PTRACED|PF_TRACESYS)) + return; + current->exit_code = SIGTRAP; + current->state = TASK_STOPPED; + notify_parent(current); + schedule(); + /* + * this isn't the same as continuing with a signal, but it will do + * for normal use. strace only continues with a signal if the + * stopping signal is not SIGTRAP. -brl + */ + if (current->exit_code) + current->signal |= (1 << (current->exit_code - 1)); + current->exit_code = 0; + return; +} diff -u --recursive --new-file v1.3.93/linux/arch/m68k/kernel/setup.c linux/arch/m68k/kernel/setup.c --- v1.3.93/linux/arch/m68k/kernel/setup.c Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/kernel/setup.c Fri Apr 19 02:41:14 1996 @@ -0,0 +1,355 @@ +/* + * linux/arch/m68k/kernel/setup.c + * + * Copyright (C) 1995 Hamish Macdonald + */ + +/* + * This file handles the architecture-dependent parts of system setup + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#ifdef CONFIG_BLK_DEV_INITRD +#include +#include +#endif + +struct bootinfo boot_info = {0,}; +int bisize = sizeof boot_info; + +int m68k_is040or060 = 0; + +char m68k_debug_device[6] = ""; + +extern int end; +extern unsigned long availmem; + +char saved_command_line[CL_SIZE]; + +/* setup some dummy routines */ +static void dummy_waitbut(void) +{ +} + +void (*mach_sched_init) (isrfunc); +int (*mach_keyb_init) (void); +int (*mach_kbdrate) (struct kbd_repeat *) = NULL; +void (*mach_kbd_leds) (unsigned int) = NULL; +void (*mach_init_INTS) (void); +int (*mach_add_isr) (unsigned long, isrfunc, int, void *, char *); +int (*mach_remove_isr) (unsigned long, isrfunc); +void (*mach_process_int) (int, struct pt_regs *) = NULL; +void (*mach_enable_irq) (unsigned) = NULL; +void (*mach_disable_irq) (unsigned) = NULL; +int (*mach_get_irq_list) (char *, int) = NULL; +unsigned long (*mach_gettimeoffset) (void); +void (*mach_gettod) (int*, int*, int*, int*, int*, int*); +int (*mach_hwclk) (int, struct hwclk_time*) = NULL; +int (*mach_set_clock_mmss) (unsigned long) = NULL; +void (*mach_check_partition) (struct gendisk *, unsigned int); +void (*mach_mksound)( unsigned int count, unsigned int ticks ); +void (*mach_reset)( void ); +void (*waitbut)(void) = dummy_waitbut; +struct fb_info *(*mach_fb_init)(long *); +long mach_max_dma_address = 0x00ffffff; /* default set to the lower 16MB */ +void (*mach_debug_init)(void); +void (*mach_video_setup) (char *, int *); +#ifdef CONFIG_BLK_DEV_FD +int (*mach_floppy_init) (void) = NULL; +void (*mach_floppy_setup) (char *, int *) = NULL; +#endif + +extern void config_amiga(void); +extern void config_atari(void); +extern void config_mac(void); + +extern void register_console(void (*proc)(const char *)); +extern void ami_serial_print (const char *str); +extern void ata_serial_print (const char *str); + +extern void (*kd_mksound)(unsigned int, unsigned int); + +extern void amiga_get_model(char *model); +extern void atari_get_model(char *model); +extern void mac_get_model(char *model); +extern int amiga_get_hardware_list(char *buffer); +extern int atari_get_hardware_list(char *buffer); +extern int mac_get_hardware_list(char *buffer); + +#define MASK_256K 0xfffc0000 + +void setup_arch(char **cmdline_p, + unsigned long * memory_start_p, unsigned long * memory_end_p) +{ + unsigned long memory_start, memory_end; + extern int _etext, _edata, _end; + int i; + char *p, *q; + +#ifdef CONFIG_AMIGA + if (MACH_IS_AMIGA) + register_console (ami_serial_print); +#endif +#ifdef CONFIG_ATARI + if (MACH_IS_ATARI) + register_console (ata_serial_print); +#endif + + if (boot_info.cputype & CPU_68040) + m68k_is040or060 = 4; + else if (boot_info.cputype & CPU_68060) + m68k_is040or060 = 6; + + memory_start = availmem; + memory_end = 0; + + for (i = 0; i < boot_info.num_memory; i++) + memory_end += boot_info.memory[i].size & MASK_256K; + + init_task.mm->start_code = 0; + init_task.mm->end_code = (unsigned long) &_etext; + init_task.mm->end_data = (unsigned long) &_edata; + init_task.mm->brk = (unsigned long) &_end; + + *cmdline_p = boot_info.command_line; + memcpy(saved_command_line, *cmdline_p, CL_SIZE); + + /* Parse the command line for arch-specific options. + * For the m68k, this is currently only "debug=xxx" to enable printing + * certain kernel messages to some machine-specific device. + */ + for( p = *cmdline_p; p && *p; ) { + i = 0; + if (!strncmp( p, "debug=", 6 )) { + strncpy( m68k_debug_device, p+6, sizeof(m68k_debug_device)-1 ); + m68k_debug_device[sizeof(m68k_debug_device)-1] = 0; + if ((q = strchr( m68k_debug_device, ' ' ))) *q = 0; + i = 1; + } + + if (i) { + /* option processed, delete it */ + if ((q = strchr( p, ' ' ))) + strcpy( p, q+1 ); + else + *p = 0; + } else { + if ((p = strchr( p, ' ' ))) ++p; + } + } + + *memory_start_p = memory_start; + *memory_end_p = memory_end; + + switch (boot_info.machtype) { +#ifdef CONFIG_AMIGA + case MACH_AMIGA: + config_amiga(); + break; +#endif +#ifdef CONFIG_ATARI + case MACH_ATARI: + config_atari(); + break; +#endif +#ifdef CONFIG_MAC + case MACH_MAC: + config_mac(); + break; +#endif + default: + panic ("No configuration setup"); + } + +#ifdef CONFIG_BLK_DEV_INITRD + if (boot_info.ramdisk_size) { + initrd_start = PTOV (boot_info.ramdisk_addr); + initrd_end = initrd_start + boot_info.ramdisk_size * 1024; + } +#endif +} + +int setkeycode(unsigned int scancode, unsigned int keycode) +{ + return -EOPNOTSUPP; +} + +int getkeycode(unsigned int scancode) +{ + return -EOPNOTSUPP; +} + +int get_cpuinfo(char * buffer) +{ + char *cpu, *mmu, *fpu; + u_long clockfreq, clockfactor; + +#define CLOCK_FACTOR_68020 (8046) /* 3107016 loops/s @ 25 MHz (Sun-3) */ +#define CLOCK_FACTOR_68030 (8010) /* 3994575 loops/s @ 32 MHz */ +#define CLOCK_FACTOR_68040 (3010) /* 8305552 loops/s @ 25 MHz */ +#define CLOCK_FACTOR_68060 (998) /* 50081241 loops/s @ 50 MHz */ + + if (boot_info.cputype & CPU_68020) { + cpu = "68020"; + mmu = "68851"; + clockfactor = CLOCK_FACTOR_68020; + } else if (boot_info.cputype & CPU_68030) { + cpu = mmu = "68030"; + clockfactor = CLOCK_FACTOR_68030; + } else if (boot_info.cputype & CPU_68040) { + cpu = mmu = "68040"; + clockfactor = CLOCK_FACTOR_68040; + } else if (boot_info.cputype & CPU_68060) { + cpu = mmu = "68060"; + clockfactor = CLOCK_FACTOR_68060; + } else { + cpu = mmu = "680x0"; + clockfactor = 0; + } + + if (boot_info.cputype & FPU_68881) + fpu = "68881"; + else if (boot_info.cputype & FPU_68882) + fpu = "68882"; + else if (boot_info.cputype & FPU_68040) + fpu = "68040"; + else if (boot_info.cputype & FPU_68060) + fpu = "68060"; + else + fpu = "none"; + + clockfreq = loops_per_sec/1000*clockfactor; + + return(sprintf(buffer, "CPU:\t\t%s\n" + "MMU:\t\t%s\n" + "FPU:\t\t%s\n" + "Clockspeed:\t%lu.%1luMHz\n" + "BogoMips:\t%lu.%02lu\n", + cpu, mmu, fpu, clockfreq/1000000, + ((clockfreq+50000)/100000)%10, loops_per_sec/500000, + (loops_per_sec/5000)%100)); +} + +int get_hardware_list(char *buffer) +{ + int len = 0; + char model[80]; + u_long mem; + int i; + + switch (boot_info.machtype) { +#ifdef CONFIG_AMIGA + case MACH_AMIGA: + amiga_get_model(model); + break; +#endif +#ifdef CONFIG_ATARI + case MACH_ATARI: + atari_get_model(model); + break; +#endif +#ifdef CONFIG_MAC + case MACH_MAC: + mac_get_model(model); + break; +#endif + default: + strcpy(model, "Unknown m68k"); + } /* boot_info.machtype */ + + len += sprintf(buffer+len, "Model:\t\t%s\n", model); + len += get_cpuinfo(buffer+len); + for (mem = 0, i = 0; i < boot_info.num_memory; i++) + mem += boot_info.memory[i].size; + len += sprintf(buffer+len, "System Memory:\t%ldK\n", mem>>10); + + switch (boot_info.machtype) { +#ifdef CONFIG_AMIGA + case MACH_AMIGA: + len += amiga_get_hardware_list(buffer+len); + break; +#endif +#ifdef CONFIG_ATARI + case MACH_ATARI: + len += atari_get_hardware_list(buffer+len); + break; +#endif +#ifdef CONFIG_MAC + case MACH_MAC: + break; +#endif + } /* boot_info.machtype */ + +#if 0 /* ++1.3++ */ + len += get_serial_list (buffer + len); +#endif /* ++1.3++ */ + + return(len); +} + +#ifdef CONFIG_BLK_DEV_FD +int floppy_init(void) +{ + if (mach_floppy_init) + return mach_floppy_init(); + else + return 0; +} + +void floppy_setup(char *str, int *ints) +{ + if (mach_floppy_setup) + mach_floppy_setup (str, ints); +} +#endif + +unsigned long arch_kbd_init(void) +{ + return mach_keyb_init(); +} + +int rs_init(void) +{ + return 0; +} + +struct serial_struct; +int register_serial(struct serial_struct *req) +{ + return -1; +} + +void unregister_serial(int line) +{ +} + +void arch_gettod(int *year, int *mon, int *day, int *hour, + int *min, int *sec) +{ + if (mach_gettod) + mach_gettod(year, mon, day, hour, min, sec); + else + *year = *mon = *day = *hour = *min = *sec = 0; +} + +void video_setup (char *options, int *ints) +{ + if (mach_video_setup) + mach_video_setup (options, ints); +} diff -u --recursive --new-file v1.3.93/linux/arch/m68k/kernel/signal.c linux/arch/m68k/kernel/signal.c --- v1.3.93/linux/arch/m68k/kernel/signal.c Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/kernel/signal.c Thu Apr 18 02:07:17 1996 @@ -0,0 +1,557 @@ +/* + * linux/arch/m68k/kernel/signal.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file README.legal in the main directory of this archive + * for more details. + */ + +/* + * 680x0 support by Hamish Macdonald + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define offsetof(type, member) ((size_t)(&((type *)0)->member)) + +#define _S(nr) (1<<((nr)-1)) + +#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) + +asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options); +asmlinkage int do_signal(unsigned long oldmask, struct pt_regs *regs); + +static const int extra_sizes[16] = { + 0, + -1, /* sizeof(((struct frame *)0)->un.fmt1), */ + sizeof(((struct frame *)0)->un.fmt2), + sizeof(((struct frame *)0)->un.fmt3), + sizeof(((struct frame *)0)->un.fmt4), + -1, /* sizeof(((struct frame *)0)->un.fmt5), */ + -1, /* sizeof(((struct frame *)0)->un.fmt6), */ + sizeof(((struct frame *)0)->un.fmt7), + -1, /* sizeof(((struct frame *)0)->un.fmt8), */ + sizeof(((struct frame *)0)->un.fmt9), + sizeof(((struct frame *)0)->un.fmta), + sizeof(((struct frame *)0)->un.fmtb), + -1, /* sizeof(((struct frame *)0)->un.fmtc), */ + -1, /* sizeof(((struct frame *)0)->un.fmtd), */ + -1, /* sizeof(((struct frame *)0)->un.fmte), */ + -1, /* sizeof(((struct frame *)0)->un.fmtf), */ +}; + +/* + * atomically swap in the new signal mask, and wait for a signal. + */ +asmlinkage int do_sigsuspend(struct pt_regs *regs) +{ + unsigned long oldmask = current->blocked; + unsigned long newmask = regs->d3; + + current->blocked = newmask & _BLOCKABLE; + regs->d0 = -EINTR; + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (do_signal(oldmask, regs)) + return -EINTR; + } +} + +static unsigned char fpu_version = 0; /* version number of fpu, set by setup_frame */ + +/* + * This sets regs->usp even though we don't actually use sigstacks yet.. + */ +asmlinkage int do_sigreturn(unsigned long __unused) +{ + struct sigcontext_struct context; + struct frame * regs; + struct switch_stack *sw; + int fsize = 0; + int formatvec = 0; + unsigned long fp; + unsigned long usp = rdusp(); + +#if 0 + printk("sys_sigreturn, usp=%08x\n", (unsigned) usp); +#endif + + /* get stack frame pointer */ + sw = (struct switch_stack *) &__unused; + regs = (struct frame *) (sw + 1); + + /* get previous context (including pointer to possible extra junk) */ + if (verify_area(VERIFY_READ, (void *)usp, sizeof(context))) + goto badframe; + + memcpy_fromfs(&context,(void *)usp, sizeof(context)); + + fp = usp + sizeof (context); + + /* restore signal mask */ + current->blocked = context.sc_mask & _BLOCKABLE; + + /* restore passed registers */ + regs->ptregs.d0 = context.sc_d0; + regs->ptregs.d1 = context.sc_d1; + regs->ptregs.a0 = context.sc_a0; + regs->ptregs.a1 = context.sc_a1; + regs->ptregs.sr = (regs->ptregs.sr & 0xff00)|(context.sc_sr & 0xff); + regs->ptregs.pc = context.sc_pc; + + wrusp(context.sc_usp); + formatvec = context.sc_formatvec; + regs->ptregs.format = formatvec >> 12; + regs->ptregs.vector = formatvec & 0xfff; + if (context.sc_fpstate[0]) + { + /* Verify the frame format. */ + if (context.sc_fpstate[0] != fpu_version){ +#if DEBUG + printk("fpregs=%08x fpcntl=%08x\n", context.sc_fpregs, + context.sc_fpcntl); + printk("Wrong fpu: sc_fpstate[0]=%02x fpu_version=%02x\n", + (unsigned) context.sc_fpstate[0], (unsigned) fpu_version); + { + int i; + printk("Saved fp_state: "); + for (i = 0; i < 216; i++){ + printk("%02x ", context.sc_fpstate[i]); + } + printk("\n"); + } +#endif + goto badframe; + } + if (boot_info.cputype & FPU_68881) + { + if (context.sc_fpstate[1] != 0x18 + && context.sc_fpstate[1] != 0xb4) + goto badframe; + } + else if (boot_info.cputype & FPU_68882) + { + if (context.sc_fpstate[1] != 0x38 + && context.sc_fpstate[1] != 0xd4){ +#if 0 + printk("Wrong 68882 fpu-state\n"); +#endif + goto badframe; + } + } + else if (boot_info.cputype & FPU_68040) + { + if (!((context.sc_fpstate[1] == 0x00)|| \ + (context.sc_fpstate[1] == 0x28)|| \ + (context.sc_fpstate[1] == 0x60))){ +#if 0 + printk("Wrong 68040 fpu-state\n"); +#endif + goto badframe; + } + } + else if (boot_info.cputype & FPU_68060) + { + if (!((context.sc_fpstate[1] == 0x00)|| \ + (context.sc_fpstate[1] == 0x60)|| \ + (context.sc_fpstate[1] == 0xe0))){ +#if 0 + printk("Wrong 68060 fpu-state\n"); +#endif + goto badframe; + } + } + __asm__ volatile ("fmovemx %0,%/fp0-%/fp1\n\t" + "fmoveml %1,%/fpcr/%/fpsr/%/fpiar" + : /* no outputs */ + : "m" (*context.sc_fpregs), + "m" (*context.sc_fpcntl)); + } + __asm__ volatile ("frestore %0" : : "m" (*context.sc_fpstate)); + + fsize = extra_sizes[regs->ptregs.format]; + if (fsize < 0) { + /* + * user process trying to return with weird frame format + */ +#if DEBUG + printk("user process returning with weird frame format\n"); +#endif + goto badframe; + } + + /* OK. Make room on the supervisor stack for the extra junk, + * if necessary. + */ + + if (fsize) { + if (verify_area(VERIFY_READ, (void *)fp, fsize)) + goto badframe; + +#define frame_offset (sizeof(struct pt_regs)+sizeof(struct switch_stack)) + __asm__ __volatile__ + ("movel %0,%/a0\n\t" + "subl %1,%/a0\n\t" /* make room on stack */ + "movel %/a0,%/sp\n\t" /* set stack pointer */ + /* move switch_stack and pt_regs */ + "1: movel %0@+,%/a0@+\n\t" + " dbra %2,1b\n\t" + "lea %/sp@(%c3),%/a0\n\t" /* add offset of fmt stuff */ + "lsrl #2,%1\n\t" + "subql #1,%1\n\t" + "2: movesl %4@+,%2\n\t" + " movel %2,%/a0@+\n\t" + " dbra %1,2b\n\t" + "bral " SYMBOL_NAME_STR(ret_from_signal) + : /* no outputs, it doesn't ever return */ + : "a" (sw), "d" (fsize), "d" (frame_offset/4-1), + "n" (frame_offset), "a" (fp) + : "a0"); +#undef frame_offset + goto badframe; + /* NOTREACHED */ + } + + return regs->ptregs.d0; +badframe: + do_exit(SIGSEGV); +} + +/* + * Set up a signal frame... + * + * This routine is somewhat complicated by the fact that if the + * kernel may be entered by an exception other than a system call; + * e.g. a bus error or other "bad" exception. If this is the case, + * then *all* the context on the kernel stack frame must be saved. + * + * For a large number of exceptions, the stack frame format is the same + * as that which will be created when the process traps back to the kernel + * when finished executing the signal handler. In this case, nothing + * must be done. This is exception frame format "0". For exception frame + * formats "2", "9", "A" and "B", the extra information on the frame must + * be saved. This information is saved on the user stack and restored + * when the signal handler is returned. + * + * The format of the user stack when executing the signal handler is: + * + * usp -> RETADDR (points to code below) + * signum (parm #1) + * sigcode (parm #2 ; vector number) + * scp (parm #3 ; sigcontext pointer, pointer to #1 below) + * code1 (addaw #20,sp) ; pop parms and code off stack + * code2 (moveq #119,d0; trap #0) ; sigreturn syscall + * #1| oldmask + * | old usp + * | d0 (first saved reg) + * | d1 + * | a0 + * | a1 + * | sr (saved status register) + * | pc (old pc; one to return to) + * | forvec (format and vector word of old supervisor stack frame) + * | floating point context + * + * These are optionally followed by some extra stuff, depending on the + * stack frame interrupted. This is 1 longword for format "2", 3 + * longwords for format "9", 6 longwords for format "A", and 21 + * longwords for format "B". + */ + +#define UFRAME_SIZE(fs) (sizeof(struct sigcontext_struct)/4 + 6 + fs/4) + +static void setup_frame (struct sigaction * sa, unsigned long **fp, + unsigned long pc, struct frame *regs, int + signr, unsigned long oldmask) +{ + struct sigcontext_struct context; + unsigned long *frame, *tframe; + int fsize = extra_sizes[regs->ptregs.format]; + + if (fsize < 0) { + printk ("setup_frame: Unknown frame format %#x\n", + regs->ptregs.format); + do_exit(SIGSEGV); + } + frame = *fp - UFRAME_SIZE(fsize); + if (verify_area(VERIFY_WRITE,frame,UFRAME_SIZE(fsize)*4)) + do_exit(SIGSEGV); + if (fsize) { + memcpy_tofs (frame + UFRAME_SIZE(0), ®s->un, fsize); + regs->ptregs.stkadj = fsize; + } + +/* set up the "normal" stack seen by the signal handler */ + tframe = frame; + + /* return address points to code on stack */ + put_user((ulong)(frame+4), tframe); tframe++; + if (current->exec_domain && current->exec_domain->signal_invmap) + put_user(current->exec_domain->signal_invmap[signr], tframe); + else + put_user(signr, tframe); + tframe++; + + put_user(regs->ptregs.vector, tframe); tframe++; + /* "scp" parameter. points to sigcontext */ + put_user((ulong)(frame+6), tframe); tframe++; + +/* set up the return code... */ + put_user(0xdefc0014,tframe); tframe++; /* addaw #20,sp */ + put_user(0x70774e40,tframe); tframe++; /* moveq #119,d0; trap #0 */ + +/* Flush caches so the instructions will be correctly executed. (MA) */ + cache_push_v ((unsigned long)frame, (int)tframe - (int)frame); + +/* setup and copy the sigcontext structure */ + context.sc_mask = oldmask; + context.sc_usp = (unsigned long)*fp; + context.sc_d0 = regs->ptregs.d0; + context.sc_d1 = regs->ptregs.d1; + context.sc_a0 = regs->ptregs.a0; + context.sc_a1 = regs->ptregs.a1; + context.sc_sr = regs->ptregs.sr; + context.sc_pc = pc; + context.sc_formatvec = (regs->ptregs.format << 12 | + regs->ptregs.vector); +#if DEBUG + printk("formatvec: %02x\n", (unsigned) context.sc_formatvec); +#endif + __asm__ volatile ("fsave %0" : : "m" (*context.sc_fpstate) : "memory"); + if (context.sc_fpstate[0]) + { + fpu_version = context.sc_fpstate[0]; +#if DEBUG + { + int i; + printk("Saved fp_state: "); + for (i = 0; i < 216; i++){ + printk("%02x ", context.sc_fpstate[i]); + } + printk("\n"); + } + printk("fpregs=%08x fpcntl=%08x\n", context.sc_fpregs, + context.sc_fpcntl); +#endif + __asm__ volatile ("fmovemx %/fp0-%/fp1,%0\n\t" + "fmoveml %/fpcr/%/fpsr/%/fpiar,%1" + : /* no outputs */ + : "m" (*context.sc_fpregs), + "m" (*context.sc_fpcntl) + : "memory"); + } +#if DEBUG + { + int i; + printk("Saved fp_state: "); + for (i = 0; i < 216; i++){ + printk("%02x ", context.sc_fpstate[i]); + } + printk("\n"); + } +#endif + memcpy_tofs (tframe, &context, sizeof(context)); + /* + * no matter what frame format we were using before, we + * will do the "RTE" using a normal 4 word frame. + */ + regs->ptregs.format = 0; + + /* "return" new usp to caller */ + *fp = frame; +} + +/* + * Note that 'init' is a special process: it doesn't get signals it doesn't + * want to handle. Thus you cannot kill init even with a SIGKILL even by + * mistake. + * + * Note that we go through the signals twice: once to check the signals + * that the kernel can handle, and then we build all the user-level signal + * handling stack-frames in one go after that. + */ +asmlinkage int do_signal(unsigned long oldmask, struct pt_regs *regs_in) +{ + unsigned long mask = ~current->blocked; + unsigned long handler_signal = 0; + unsigned long *frame = NULL; + unsigned long pc = 0; + unsigned long signr; + struct frame *regs = (struct frame *)regs_in; + struct sigaction * sa; + + current->tss.esp0 = (unsigned long) regs; + + while ((signr = current->signal & mask)) { + __asm__("bfffo %2,#0,#0,%1\n\t" + "bfclr %0,%1,#1\n\t" + "eorw #31,%1" + :"=m" (current->signal),"=r" (signr) + :"1" (signr)); + sa = current->sig->action + signr; + signr++; + + if ((current->flags & PF_PTRACED) && signr != SIGKILL) { + current->exit_code = signr; + current->state = TASK_STOPPED; + notify_parent(current); + schedule(); + if (!(signr = current->exit_code)) { + discard_frame: + /* Make sure that a faulted bus cycle + isn't restarted. */ + switch (regs->ptregs.format) { + case 7: + case 9: + case 10: + case 11: + regs->ptregs.stkadj = extra_sizes[regs->ptregs.format]; + regs->ptregs.format = 0; + break; + } + continue; + } + current->exit_code = 0; + if (signr == SIGSTOP) + goto discard_frame; + if (_S(signr) & current->blocked) { + current->signal |= _S(signr); + continue; + } + sa = current->sig->action + signr - 1; + } + if (sa->sa_handler == SIG_IGN) { + if (signr != SIGCHLD) + continue; + /* check for SIGCHLD: it's special */ + while (sys_waitpid(-1,NULL,WNOHANG) > 0) + /* nothing */; + continue; + } + if (sa->sa_handler == SIG_DFL) { + if (current->pid == 1) + continue; + switch (signr) { + case SIGCONT: case SIGCHLD: case SIGWINCH: + continue; + + case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU: + if (current->flags & PF_PTRACED) + continue; + current->state = TASK_STOPPED; + current->exit_code = signr; + if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags & + SA_NOCLDSTOP)) + notify_parent(current); + schedule(); + continue; + + case SIGQUIT: case SIGILL: case SIGTRAP: + case SIGIOT: case SIGFPE: case SIGSEGV: + if (current->binfmt && current->binfmt->core_dump) { + if (current->binfmt->core_dump(signr, (struct pt_regs *)regs)) + signr |= 0x80; + } + /* fall through */ + default: + current->signal |= _S(signr & 0x7f); + do_exit(signr); + } + } + /* + * OK, we're invoking a handler + */ + if (regs->ptregs.orig_d0 >= 0) { + if (regs->ptregs.d0 == -ERESTARTNOHAND || + (regs->ptregs.d0 == -ERESTARTSYS && + !(sa->sa_flags & SA_RESTART))) + regs->ptregs.d0 = -EINTR; + } + handler_signal |= 1 << (signr-1); + mask &= ~sa->sa_mask; + } + if (regs->ptregs.orig_d0 >= 0 && + (regs->ptregs.d0 == -ERESTARTNOHAND || + regs->ptregs.d0 == -ERESTARTSYS || + regs->ptregs.d0 == -ERESTARTNOINTR)) { + regs->ptregs.d0 = regs->ptregs.orig_d0; + regs->ptregs.pc -= 2; + } + if (!handler_signal) /* no handler will be called - return 0 */ + { + /* If we are about to discard some frame stuff we must + copy over the remaining frame. */ + if (regs->ptregs.stkadj) + { + struct frame *tregs = + (struct frame *) ((ulong) regs + regs->ptregs.stkadj); + + /* This must be copied with decreasing addresses to + handle overlaps. */ + tregs->ptregs.vector = regs->ptregs.vector; + tregs->ptregs.format = regs->ptregs.format; + tregs->ptregs.pc = regs->ptregs.pc; + tregs->ptregs.sr = regs->ptregs.sr; + } + return 0; + } + pc = regs->ptregs.pc; + frame = (unsigned long *)rdusp(); + signr = 1; + sa = current->sig->action; + for (mask = 1 ; mask ; sa++,signr++,mask += mask) { + if (mask > handler_signal) + break; + if (!(mask & handler_signal)) + continue; + setup_frame(sa,&frame,pc,regs,signr,oldmask); + pc = (unsigned long) sa->sa_handler; + if (sa->sa_flags & SA_ONESHOT) + sa->sa_handler = NULL; +/* force a supervisor-mode page-in of the signal handler to reduce races */ + __asm__ __volatile__("movesb %0,%/d0": :"m" (*(char *)pc):"d0"); + current->blocked |= sa->sa_mask; + oldmask |= sa->sa_mask; + } + wrusp((unsigned long)frame); + regs->ptregs.pc = pc; + + /* + * if setup_frame saved some extra frame junk, we need to + * skip over that stuff when doing the RTE. This means we have + * to move the machine portion of the stack frame to where the + * "RTE" instruction expects it. The signal that we need to + * do this is that regs->stkadj is nonzero. + */ + if (regs->ptregs.stkadj) { + struct frame *tregs = + (struct frame *)((ulong)regs + regs->ptregs.stkadj); +#if DEBUG + printk("Performing stackadjust=%04x\n", (unsigned) + regs->ptregs.stkadj); +#endif + /* This must be copied with decreasing addresses to + handle overlaps. */ + tregs->ptregs.vector = regs->ptregs.vector; + tregs->ptregs.format = regs->ptregs.format; + tregs->ptregs.pc = regs->ptregs.pc; + tregs->ptregs.sr = regs->ptregs.sr; + } + + return 1; +} diff -u --recursive --new-file v1.3.93/linux/arch/m68k/kernel/sys_m68k.c linux/arch/m68k/kernel/sys_m68k.c --- v1.3.93/linux/arch/m68k/kernel/sys_m68k.c Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/kernel/sys_m68k.c Wed Apr 10 23:44:37 1996 @@ -0,0 +1,185 @@ +/* + * linux/arch/m68k/kernel/sys_m68k.c + * + * This file contains various random system calls that + * have a non-standard calling sequence on the Linux/m68k + * platform. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* + * sys_pipe() is the normal C calling standard for creating + * a pipe. It's not the way unix tranditionally does this, though. + */ +asmlinkage int sys_pipe(unsigned long * fildes) +{ + int fd[2]; + int error; + + error = verify_area(VERIFY_WRITE,fildes,8); + if (error) + return error; + error = do_pipe(fd); + if (error) + return error; + put_user(fd[0],0+fildes); + put_user(fd[1],1+fildes); + return 0; +} + +/* + * Perform the select(nd, in, out, ex, tv) and mmap() system + * calls. Linux/m68k cloned Linux/i386, which didn't use to be able to + * handle more than 4 system call parameters, so these system calls + * used a memory block for parameter passing.. + */ + +asmlinkage int old_mmap(unsigned long *buffer) +{ + int error; + unsigned long flags; + struct file * file = NULL; + + error = verify_area(VERIFY_READ, buffer, 6*sizeof(long)); + if (error) + return error; + flags = get_user(buffer+3); + if (!(flags & MAP_ANONYMOUS)) { + unsigned long fd = get_user(buffer+4); + if (fd >= NR_OPEN || !(file = current->files->fd[fd])) + return -EBADF; + } + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + return do_mmap(file, get_user(buffer), get_user(buffer+1), + get_user(buffer+2), flags, get_user(buffer+5)); +} + + +extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *); + +asmlinkage int old_select(unsigned long *buffer) +{ + int n; + fd_set *inp; + fd_set *outp; + fd_set *exp; + struct timeval *tvp; + + n = verify_area(VERIFY_READ, buffer, 5*sizeof(unsigned long)); + if (n) + return n; + + n = get_user(buffer); + inp = (fd_set *) get_user(buffer+1); + outp = (fd_set *) get_user(buffer+2); + exp = (fd_set *) get_user(buffer+3); + tvp = (struct timeval *) get_user(buffer+4); + return sys_select(n, inp, outp, exp, tvp); +} + +/* + * sys_ipc() is the de-multiplexer for the SysV IPC calls.. + * + * This is really horribly ugly. + */ +asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth) +{ + int version; + + version = call >> 16; /* hack for backward compatibility */ + call &= 0xffff; + + if (call <= SEMCTL) + switch (call) { + case SEMOP: + return sys_semop (first, (struct sembuf *)ptr, second); + case SEMGET: + return sys_semget (first, second, third); + case SEMCTL: { + union semun fourth; + int err; + if (!ptr) + return -EINVAL; + if ((err = verify_area (VERIFY_READ, ptr, sizeof(long)))) + return err; + fourth.__pad = get_user((void **)ptr); + return sys_semctl (first, second, third, fourth); + } + default: + return -EINVAL; + } + if (call <= MSGCTL) + switch (call) { + case MSGSND: + return sys_msgsnd (first, (struct msgbuf *) ptr, + second, third); + case MSGRCV: + switch (version) { + case 0: { + struct ipc_kludge tmp; + int err; + if (!ptr) + return -EINVAL; + if ((err = verify_area (VERIFY_READ, ptr, sizeof(tmp)))) + return err; + memcpy_fromfs (&tmp,(struct ipc_kludge *) ptr, + sizeof (tmp)); + return sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third); + } + case 1: default: + return sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third); + } + case MSGGET: + return sys_msgget ((key_t) first, second); + case MSGCTL: + return sys_msgctl (first, second, (struct msqid_ds *) ptr); + default: + return -EINVAL; + } + if (call <= SHMCTL) + switch (call) { + case SHMAT: + switch (version) { + case 0: default: { + ulong raddr; + int err; + if ((err = verify_area(VERIFY_WRITE, (ulong*) third, sizeof(ulong)))) + return err; + err = sys_shmat (first, (char *) ptr, second, &raddr); + if (err) + return err; + put_user (raddr, (ulong *) third); + return 0; + } + case 1: /* iBCS2 emulator entry point */ + if (get_fs() != get_ds()) + return -EINVAL; + return sys_shmat (first, (char *) ptr, second, (ulong *) third); + } + case SHMDT: + return sys_shmdt ((char *)ptr); + case SHMGET: + return sys_shmget (first, second, third); + case SHMCTL: + return sys_shmctl (first, second, (struct shmid_ds *) ptr); + default: + return -EINVAL; + } + return -EINVAL; +} + +asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on) +{ + return -ENOSYS; +} diff -u --recursive --new-file v1.3.93/linux/arch/m68k/kernel/time.c linux/arch/m68k/kernel/time.c --- v1.3.93/linux/arch/m68k/kernel/time.c Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/kernel/time.c Sun Mar 17 18:12:32 1996 @@ -0,0 +1,143 @@ +/* + * linux/arch/m68k/kernel/time.c + * + * Copyright (C) 1991, 1992, 1995 Linus Torvalds + * + * This file contains the m68k-specific time handling details. + * Most of the stuff is located in the machine specific files. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + + +static inline int set_rtc_mmss(unsigned long nowtime) +{ + if (mach_set_clock_mmss) + return mach_set_clock_mmss (nowtime); + return -1; +} + +/* + * timer_interrupt() needs to keep up the real-time clock, + * as well as call the "do_timer()" routine every clocktick + */ +static void timer_interrupt(int irq, struct pt_regs * regs, void *dummy) +{ + /* last time the cmos clock got updated */ + static long last_rtc_update=0; + + do_timer(regs); + + /* + * If we have an externally synchronized Linux clock, then update + * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be + * called as close as possible to 500 ms before the new second starts. + */ + if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 && + xtime.tv_usec > 500000 - (tick >> 1) && + xtime.tv_usec < 500000 + (tick >> 1)) + if (set_rtc_mmss(xtime.tv_sec) == 0) + last_rtc_update = xtime.tv_sec; + else + last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */ +} + +/* Converts Gregorian date to seconds since 1970-01-01 00:00:00. + * Assumes input in normal date format, i.e. 1980-12-31 23:59:59 + * => year=1980, mon=12, day=31, hour=23, min=59, sec=59. + * + * [For the Julian calendar (which was used in Russia before 1917, + * Britain & colonies before 1752, anywhere else before 1582, + * and is still in use by some communities) leave out the + * -year/100+year/400 terms, and add 10.] + * + * This algorithm was first published by Gauss (I think). + * + * WARNING: this function will overflow on 2106-02-07 06:28:16 on + * machines were long is 32-bit! (However, as time_t is signed, we + * will already get problems at other places on 2038-01-19 03:14:08) + */ +static inline unsigned long mktime(unsigned int year, unsigned int mon, + unsigned int day, unsigned int hour, + unsigned int min, unsigned int sec) +{ + if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */ + mon += 12; /* Puts Feb last since it has leap day */ + year -= 1; + } + return ((( + (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) + + year*365 - 719499 + )*24 + hour /* now have hours */ + )*60 + min /* now have minutes */ + )*60 + sec; /* finally seconds */ +} + +void time_init(void) +{ + unsigned int year, mon, day, hour, min, sec; + + extern void arch_gettod(int *year, int *mon, int *day, int *hour, + int *min, int *sec); + + arch_gettod (&year, &mon, &day, &hour, &min, &sec); + + if ((year += 1900) < 1970) + year += 100; + xtime.tv_sec = mktime(year, mon, day, hour, min, sec); + xtime.tv_usec = 0; + + mach_sched_init(timer_interrupt); +} + +/* + * This version of gettimeofday has near microsecond resolution. + */ +void do_gettimeofday(struct timeval *tv) +{ + unsigned long flags; + + save_flags(flags); + cli(); + *tv = xtime; + tv->tv_usec += mach_gettimeoffset(); + if (tv->tv_usec >= 1000000) { + tv->tv_usec -= 1000000; + tv->tv_sec++; + } + restore_flags(flags); +} + +void do_settimeofday(struct timeval *tv) +{ + cli(); + /* This is revolting. We need to set the xtime.tv_usec + * correctly. However, the value in this location is + * is value at the last tick. + * Discover what correction gettimeofday + * would have done, and then undo it! + */ + tv->tv_usec -= mach_gettimeoffset(); + + if (tv->tv_usec < 0) { + tv->tv_usec += 1000000; + tv->tv_sec--; + } + + xtime = *tv; + time_state = TIME_BAD; + time_maxerror = 0x70000000; + time_esterror = 0x70000000; + sti(); +} diff -u --recursive --new-file v1.3.93/linux/arch/m68k/kernel/traps.c linux/arch/m68k/kernel/traps.c --- v1.3.93/linux/arch/m68k/kernel/traps.c Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/kernel/traps.c Thu Apr 18 03:01:27 1996 @@ -0,0 +1,901 @@ +/* + * linux/arch/m68k/kernel/traps.c + * + * Copyright (C) 1993, 1994 by Hamish Macdonald + * + * 68040 fixes by Michael Rausch + * 68040 fixes by Martin Apel + * 68060 fixes by Roman Hodek + * 68060 fixes by Jesper Skov + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file README.legal in the main directory of this archive + * for more details. + */ + +/* + * Sets up all exception vectors + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/* assembler routines */ +asmlinkage void system_call(void); +asmlinkage void buserr(void); +asmlinkage void trap(void); +asmlinkage void inthandler(void); +asmlinkage void nmihandler(void); + +e_vector vectors[256] = { + 0, 0, buserr, trap, trap, trap, trap, trap, + trap, trap, trap, trap, trap, trap, trap, trap, + trap, trap, trap, trap, trap, trap, trap, trap, + inthandler, inthandler, inthandler, inthandler, + inthandler, inthandler, inthandler, inthandler, + /* TRAP #0-15 */ + system_call, trap, trap, trap, trap, trap, trap, trap, + trap, trap, trap, trap, trap, trap, trap, trap, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +}; + +/* nmi handler for the Amiga */ +asm(".text\n" + __ALIGN_STR "\n" + SYMBOL_NAME_STR(nmihandler) ": rte"); + +void trap_init (void) +{ + int i; + + /* setup the exception vector table */ + __asm__ volatile ("movec %0,%/vbr" : : "r" ((void*)vectors)); + + for (i = 48; i < 64; i++) + vectors[i] = trap; + + for (i = 64; i < 256; i++) + vectors[i] = inthandler; + + /* if running on an amiga, make the NMI interrupt do nothing */ + if (MACH_IS_AMIGA) { + vectors[VEC_INT7] = nmihandler; + } + +#ifdef CONFIG_FPSP_040 + if (m68k_is040or060 == 4) { + /* set up FPSP entry points */ + asmlinkage void dz_vec(void) asm ("dz"); + asmlinkage void inex_vec(void) asm ("inex"); + asmlinkage void ovfl_vec(void) asm ("ovfl"); + asmlinkage void unfl_vec(void) asm ("unfl"); + asmlinkage void snan_vec(void) asm ("snan"); + asmlinkage void operr_vec(void) asm ("operr"); + asmlinkage void bsun_vec(void) asm ("bsun"); + asmlinkage void fline_vec(void) asm ("fline"); + asmlinkage void unsupp_vec(void) asm ("unsupp"); + + vectors[VEC_FPDIVZ] = dz_vec; + vectors[VEC_FPIR] = inex_vec; + vectors[VEC_FPOVER] = ovfl_vec; + vectors[VEC_FPUNDER] = unfl_vec; + vectors[VEC_FPNAN] = snan_vec; + vectors[VEC_FPOE] = operr_vec; + vectors[VEC_FPBRUC] = bsun_vec; + vectors[VEC_FPBRUC] = bsun_vec; + vectors[VEC_LINE11] = fline_vec; + vectors[VEC_FPUNSUP] = unsupp_vec; + } +#endif +#ifdef CONFIG_IFPSP_060 + if (m68k_is040or060 == 6) { + /* set up IFPSP entry points */ + asmlinkage void snan_vec(void) asm ("_060_fpsp_snan"); + asmlinkage void operr_vec(void) asm ("_060_fpsp_operr"); + asmlinkage void ovfl_vec(void) asm ("_060_fpsp_ovfl"); + asmlinkage void unfl_vec(void) asm ("_060_fpsp_unfl"); + asmlinkage void dz_vec(void) asm ("_060_fpsp_dz"); + asmlinkage void inex_vec(void) asm ("_060_fpsp_inex"); + asmlinkage void fline_vec(void) asm ("_060_fpsp_fline"); + asmlinkage void unsupp_vec(void) asm ("_060_fpsp_unsupp"); + asmlinkage void effadd_vec(void) asm ("_060_fpsp_effadd"); + + asmlinkage void unimp_vec(void) asm ("_060_isp_unimp"); + + vectors[VEC_FPNAN] = snan_vec; + vectors[VEC_FPOE] = operr_vec; + vectors[VEC_FPOVER] = ovfl_vec; + vectors[VEC_FPUNDER] = unfl_vec; + vectors[VEC_FPDIVZ] = dz_vec; + vectors[VEC_FPIR] = inex_vec; + vectors[VEC_LINE11] = fline_vec; + vectors[VEC_FPUNSUP] = unsupp_vec; + vectors[VEC_UNIMPEA] = effadd_vec; + + /* set up ISP entry points */ + + vectors[VEC_UNIMPII] = unimp_vec; + + } +#endif +} + +void set_evector(int vecnum, void (*handler)(void)) +{ + if (vecnum >= 0 && vecnum <= 256) + vectors[vecnum] = handler; +} + + +static inline void console_verbose(void) +{ + extern int console_loglevel; + console_loglevel = 15; + mach_debug_init(); +} + +char *vec_names[] = { + "RESET SP", "RESET PC", "BUS ERROR", "ADDRESS ERROR", + "ILLEGAL INSTRUCTION", "ZERO DIVIDE", "CHK", "TRAPcc", + "PRIVILEGE VIOLATION", "TRACE", "LINE 1010", "LINE 1111", + "UNASSIGNED RESERVED 12", "COPROCESSOR PROTOCOL VIOLATION", + "FORMAT ERROR", "UNINITIALIZED INTERRUPT", + "UNASSIGNED RESERVED 16", "UNASSIGNED RESERVED 17", + "UNASSIGNED RESERVED 18", "UNASSIGNED RESERVED 19", + "UNASSIGNED RESERVED 20", "UNASSIGNED RESERVED 21", + "UNASSIGNED RESERVED 22", "UNASSIGNED RESERVED 23", + "SPURIOUS INTERRUPT", "LEVEL 1 INT", "LEVEL 2 INT", "LEVEL 3 INT", + "LEVEL 4 INT", "LEVEL 5 INT", "LEVEL 6 INT", "LEVEL 7 INT", + "SYSCALL", "TRAP #1", "TRAP #2", "TRAP #3", + "TRAP #4", "TRAP #5", "TRAP #6", "TRAP #7", + "TRAP #8", "TRAP #9", "TRAP #10", "TRAP #11", + "TRAP #12", "TRAP #13", "TRAP #14", "TRAP #15" + }; + +char *space_names[] = { + "Space 0", "User Data", "User Program", "Space 3", + "Space 4", "Super Data", "Super Program", "CPU" + }; + + + +extern void die_if_kernel(char *,struct pt_regs *,int); +asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address, + unsigned long error_code); + +asmlinkage void trap_c(struct frame *fp); + +static inline void access_error060 (struct frame *fp) +{ + unsigned long fslw = fp->un.fmt4.pc; /* is really FSLW for access error */ + +#ifdef DEBUG + printk("fslw=%#lx, fa=%#lx\n", ssw, fp->un.fmt4.effaddr); +#endif + + if (fslw & MMU060_BPE) { + /* branch prediction error -> clear branch cache */ + __asm__ __volatile__ ("movec %/cacr,%/d0\n\t" + "orl #0x00400000,%/d0\n\t" + "movec %/d0,%/cacr" + : : : "d0" ); + /* return if there's no other error */ + if (!(fslw & MMU060_ERR_BITS)) + return; + } + + if (fslw & (MMU060_DESC_ERR | MMU060_WP)) { + unsigned long errorcode; + unsigned long addr = fp->un.fmt4.effaddr; + errorcode = ((fslw & MMU060_WP) ? 1 : 0) | + ((fslw & MMU060_W) ? 2 : 0); +#ifdef DEBUG + printk("errorcode = %d\n", errorcode ); +#endif + if (fslw & MMU060_MA) + addr = PAGE_ALIGN(addr); + do_page_fault( (struct pt_regs *)fp, addr, errorcode ); + } + else { + printk( "68060 access error, fslw=%lx\n", fslw ); + trap_c( fp ); + } +} + +static unsigned long probe040 (int iswrite, int fc, unsigned long addr) +{ + unsigned long mmusr; + unsigned long fs = get_fs(); + + set_fs (fc); + + if (iswrite) + /* write */ + asm volatile ("movel %1,%/a0\n\t" + ".word 0xf548\n\t" /* ptestw (a0) */ + ".long 0x4e7a8805\n\t" /* movec mmusr,a0 */ + "movel %/a0,%0" + : "=g" (mmusr) + : "g" (addr) + : "a0"); + else + asm volatile ("movel %1,%/a0\n\t" + ".word 0xf568\n\t" /* ptestr (a0) */ + ".long 0x4e7a8805\n\t" /* movec mmusr,a0 */ + "movel %/a0,%0" + : "=g" (mmusr) + : "g" (addr) + : "a0"); + + + set_fs (fs); + + return mmusr; +} + +static void do_040writeback (unsigned short ssw, + unsigned short wbs, + unsigned long wba, + unsigned long wbd, + struct frame *fp) +{ + unsigned long fs = get_fs (); + unsigned long mmusr; + unsigned long errorcode; + + /* + * No special handling for the second writeback anymore. + * It misinterpreted the misaligned status sometimes. + * This way an extra pgae-fault may be caused (Martin Apel). + */ + + mmusr = probe040 (1, wbs & WBTM_040, wba); + errorcode = (mmusr & MMU_R_040) ? 3 : 2; + if (do_page_fault ((struct pt_regs *)fp, wba, errorcode)) + /* just return if we can't perform the writeback */ + return; + + set_fs (wbs & WBTM_040); + switch (wbs & WBSIZ_040) { + case BA_SIZE_BYTE: + put_fs_byte (wbd & 0xff, (char *)wba); + break; + case BA_SIZE_WORD: + put_fs_word (wbd & 0xffff, (short *)wba); + break; + case BA_SIZE_LONG: + put_fs_long (wbd, (int *)wba); + break; + } + set_fs (fs); +} + +static inline void access_error040 (struct frame *fp) +{ + unsigned short ssw = fp->un.fmt7.ssw; + unsigned long mmusr; + +#ifdef DEBUG + printk("ssw=%#x, fa=%#lx\n", ssw, fp->un.fmt7.faddr); + printk("wb1s=%#x, wb2s=%#x, wb3s=%#x\n", fp->un.fmt7.wb1s, + fp->un.fmt7.wb2s, fp->un.fmt7.wb3s); + printk ("wb2a=%lx, wb3a=%lx, wb2d=%lx, wb3d=%lx\n", + fp->un.fmt7.wb2a, fp->un.fmt7.wb3a, + fp->un.fmt7.wb2d, fp->un.fmt7.wb3d); +#endif + + + if (ssw & ATC_040) { + unsigned long addr = fp->un.fmt7.faddr; + unsigned long errorcode; + + /* + * The MMU status has to be determined AFTER the address + * has been corrected if there was a misaligned access (MA). + */ + if (ssw & MA_040) + addr = PAGE_ALIGN (addr); + + /* MMU error, get the MMUSR info for this access */ + mmusr = probe040 (!(ssw & RW_040), ssw & TM_040, addr); + /* +#ifdef DEBUG + printk("mmusr = %lx\n", mmusr); +#endif +*/ + errorcode = ((mmusr & MMU_R_040) ? 1 : 0) | + ((ssw & RW_040) ? 0 : 2); + do_page_fault ((struct pt_regs *)fp, addr, errorcode); + } else { + printk ("68040 access error, ssw=%x\n", ssw); + trap_c (fp); + } + +#if 0 + if (fp->un.fmt7.wb1s & WBV_040) + printk("access_error040: cannot handle 1st writeback. oops.\n"); +#endif + +/* + * We may have to do a couple of writebacks here. + * + * MR: we can speed up the thing a little bit and let do_040writeback() + * not produce another page fault as wb2 corresponds to the address that + * caused the fault. on write faults no second fault is generated, but + * on read faults for security reasons (although per definitionem impossible) + */ + + if (fp->un.fmt7.wb2s & WBV_040 && (fp->un.fmt7.wb2s & + WBTT_040) != BA_TT_MOVE16) + do_040writeback (ssw, + fp->un.fmt7.wb2s, fp->un.fmt7.wb2a, + fp->un.fmt7.wb2d, fp); + + if (fp->un.fmt7.wb3s & WBV_040) + do_040writeback (ssw, fp->un.fmt7.wb3s, + fp->un.fmt7.wb3a, fp->un.fmt7.wb3d, + fp); +} + +static inline void bus_error030 (struct frame *fp) +{ + volatile unsigned short temp; + unsigned short mmusr; + unsigned long addr, desc, errorcode; + unsigned short ssw = fp->un.fmtb.ssw; + int user_space_fault = 1; + +#if DEBUG + printk ("pid = %x ", current->pid); + printk ("SSW=%#06x ", ssw); + + if (ssw & (FC | FB)) + printk ("Instruction fault at %#010lx\n", + ssw & FC ? + fp->ptregs.format == 0xa ? fp->ptregs.pc + 2 : fp->un.fmtb.baddr - 2 + : + fp->ptregs.format == 0xa ? fp->ptregs.pc + 4 : fp->un.fmtb.baddr); + if (ssw & DF) + printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n", + ssw & RW ? "read" : "write", + fp->un.fmtb.daddr, + space_names[ssw & DFC], fp->ptregs.pc); +#endif + + if (fp->ptregs.sr & PS_S) { + /* kernel fault must be a data fault to user space */ + if (! ((ssw & DF) && ((ssw & DFC) == USER_DATA))) { + /* instruction fault or kernel data fault! */ + if (ssw & (FC | FB)) + printk ("Instruction fault at %#010lx\n", + fp->ptregs.pc); + if (ssw & DF) { + printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n", + ssw & RW ? "read" : "write", + fp->un.fmtb.daddr, + space_names[ssw & DFC], fp->ptregs.pc); + } + printk ("BAD KERNEL BUSERR\n"); + die_if_kernel("Oops",&fp->ptregs,0); + send_sig(SIGSEGV, current, 1); + user_space_fault = 0; + } + } else { + /* user fault */ + if (!(ssw & (FC | FB)) && !(ssw & DF)) + /* not an instruction fault or data fault! BAD */ + panic ("USER BUSERR w/o instruction or data fault"); + user_space_fault = 1; +#if DEBUG + printk("User space bus-error\n"); +#endif + } + + /* ++andreas: If a data fault and an instruction fault happen + at the same time map in both pages. */ + + /* First handle the data fault, if any. */ + if (ssw & DF) + { + addr = fp->un.fmtb.daddr; + + if (user_space_fault) { + asm volatile ("ptestr #1,%2@,#7,%0\n\t" + "pmove %/psr,%1@" + : "=a&" (desc) + : "a" (&temp), "a" (addr)); + mmusr = temp; + } else + mmusr = MMU_I; + +#if DEBUG + printk ("mmusr is %#x for addr %#lx in task %p\n", + mmusr, addr, current); + printk ("descriptor address is %#lx, contents %#lx\n", + mm_ptov(desc), *(unsigned long *)mm_ptov(desc)); +#endif + + errorcode = (mmusr & MMU_I) ? 0 : 1; + /* if (!(ssw & RW)) updated to 1.2.13pl6 */ + if (!(ssw & RW) || ssw & RM) + errorcode |= 2; + + if (mmusr & MMU_I) + do_page_fault ((struct pt_regs *)fp, addr, errorcode); + + /* else if ((mmusr & MMU_WP) && !(ssw & RW)) */ + + else if ((mmusr & MMU_WP) && (!(ssw & RW) || ssw & RM)) + do_page_fault ((struct pt_regs *)fp, addr, errorcode); + else if (mmusr & (MMU_B|MMU_L|MMU_S)) { + printk ("invalid %s access at %#lx from pc %#lx\n", + !(ssw & RW) ? "write" : "read", addr, + fp->ptregs.pc); + die_if_kernel("Oops",&fp->ptregs,mmusr); + send_sig(SIGSEGV, current, 1); + return; + } else { +#ifdef DEBUG + static volatile long tlong; +#endif + + printk ("weird %s access at %#lx from pc %#lx (ssw is %#x)\n", + !(ssw & RW) ? "write" : "read", addr, + fp->ptregs.pc, ssw); + asm volatile ("ptestr #1,%1@,#0\n\t" + "pmove %/psr,%0@" + : /* no outputs */ + : "a" (&temp), "a" (addr)); + mmusr = temp; + + printk ("level 0 mmusr is %#x\n", mmusr); +#if 0 + asm volatile ("pmove %/tt0,%0@" + : /* no outputs */ + : "a" (&tlong)); + printk ("tt0 is %#lx, ", tlong); + asm volatile ("pmove %/tt1,%0@" + : /* no outputs */ + : "a" (&tlong)); + printk ("tt1 is %#lx\n", tlong); +#endif +#if DEBUG + printk("Unknown SIGSEGV - 1\n"); +#endif + die_if_kernel("Oops",&fp->ptregs,mmusr); + send_sig(SIGSEGV, current, 1); + return; + } + + /* setup an ATC entry for the access about to be retried */ + if (!(ssw & RW)) + asm volatile ("ploadw #1,%0@" : /* no outputs */ + : "a" (addr)); + else + asm volatile ("ploadr #1,%0@" : /* no outputs */ + : "a" (addr)); + + /* If this was a data fault due to an invalid page and a + prefetch is pending on the same page, simulate it (but + only if the page is now valid). Otherwise we'll get an + weird insn access. */ + if ((ssw & RB) && (mmusr & MMU_I)) + { + unsigned long iaddr; + + if ((fp->ptregs.format) == 0xB) + iaddr = fp->un.fmtb.baddr; + else + iaddr = fp->ptregs.pc + 4; + if (((addr ^ iaddr) & PAGE_MASK) == 0) + { + /* We only need to check the ATC as the entry has + already been set up above. */ + asm volatile ("ptestr #1,%1@,#0\n\t" + "pmove %/psr,%0@" + : : "a" (&temp), "a" (iaddr)); + mmusr = temp; +#ifdef DEBUG + printk ("prefetch iaddr=%#lx ssw=%#x mmusr=%#x\n", + iaddr, ssw, mmusr); +#endif + if (!(mmusr & MMU_I)) + { + unsigned short insn; + asm volatile ("movesw %1@,%0" + : "=r" (insn) + : "a" (iaddr)); + fp->un.fmtb.isb = insn; + fp->un.fmtb.ssw &= ~RB; + } + } + } + } + + /* Now handle the instruction fault. */ + + /* get the fault address */ + if ((fp->ptregs.format) == 0xA ) + if (ssw & FC) + addr = fp->ptregs.pc + 2; + else if (ssw & FB) + addr = fp->ptregs.pc + 4; + else + return; + else + if (ssw & FC) + addr = fp->un.fmtb.baddr - 2; + else if (ssw & FB) + addr = fp->un.fmtb.baddr; + else + return; + + if ((ssw & DF) && ((addr ^ fp->un.fmtb.daddr) & PAGE_MASK) == 0) + /* Insn fault on same page as data fault */ + return; + + if (user_space_fault) { + asm volatile ("ptestr #1,%2@,#7,%0\n\t" + "pmove %/psr,%1@" + : "=a&" (desc) + : "a" (&temp), "a" (addr)); + mmusr = temp; + } else + mmusr = MMU_I; + +#ifdef DEBUG + printk ("mmusr is %#x for addr %#lx in task %p\n", + mmusr, addr, current); + printk ("descriptor address is %#lx, contents %#lx\n", + mm_ptov(desc), *(unsigned long *)mm_ptov(desc)); +#endif + + errorcode = (mmusr & MMU_I) ? 0 : 1; + + if (mmusr & MMU_I) + do_page_fault ((struct pt_regs *)fp, addr, errorcode); + else if (mmusr & (MMU_B|MMU_L|MMU_S)) { + printk ("invalid insn access at %#lx from pc %#lx\n", + addr, fp->ptregs.pc); +#if DEBUG + printk("Unknown SIGSEGV - 2\n"); +#endif + die_if_kernel("Oops",&fp->ptregs,mmusr); + send_sig(SIGSEGV, current, 1); + return; + } else { +#ifdef DEBUG + static volatile long tlong; +#endif + + printk ("weird insn access at %#lx from pc %#lx (ssw is %#x)\n", + addr, fp->ptregs.pc, ssw); + asm volatile ("ptestr #1,%1@,#0\n\t" + "pmove %/psr,%0@" + : /* no outputs */ + : "a" (&temp), "a" (addr)); + mmusr = temp; + + printk ("level 0 mmusr is %#x\n", mmusr); +#ifdef DEBUG + if (boot_info.cputype & CPU_68030) { + asm volatile ("pmove %/tt0,%0@" + : /* no outputs */ + : "a" (&tlong)); + printk ("tt0 is %#lx, ", tlong); + asm volatile ("pmove %/tt1,%0@" + : /* no outputs */ + : "a" (&tlong)); + printk ("tt1 is %#lx\n", tlong); + } + +#endif +#if DEBUG + printk("Unknown SIGSEGV - 3\n"); +#endif + die_if_kernel("Oops",&fp->ptregs,mmusr); + send_sig(SIGSEGV, current, 1); + return; + } + + /* setup an ATC entry for the access about to be retried */ + asm volatile ("ploadr #1,%0@" : /* no outputs */ + : "a" (addr)); +} + +asmlinkage void buserr_c(struct frame *fp) +{ + /* Only set esp0 if coming from user mode */ + if (user_mode(&fp->ptregs)) + current->tss.esp0 = (unsigned long) fp; + +#if DEBUG + printk ("*** Bus Error *** Format is %x\n", fp->ptregs.format); +#endif + + switch (fp->ptregs.format) { + case 4: /* 68060 access error */ + access_error060 (fp); + break; + case 0x7: /* 68040 access error */ + access_error040 (fp); + break; + case 0xa: + case 0xb: + bus_error030 (fp); + break; + default: + die_if_kernel("bad frame format",&fp->ptregs,0); +#if DEBUG + printk("Unknown SIGSEGV - 4\n"); +#endif + send_sig(SIGSEGV, current, 1); + } +} + + +int kstack_depth_to_print = 48; + +/* MODULE_RANGE is a guess of how much space is likely to be + vmalloced. */ +#define MODULE_RANGE (8*1024*1024) + +static void dump_stack(struct frame *fp) +{ + unsigned long *stack, *endstack, addr, module_start, module_end; + extern char _start, _etext; + int i; + + addr = (unsigned long)&fp->un; + printk("Frame format=%X ", fp->ptregs.format); + switch (fp->ptregs.format) { + case 0x2: + printk("instr addr=%08lx\n", fp->un.fmt2.iaddr); + addr += sizeof(fp->un.fmt2); + break; + case 0x3: + printk("eff addr=%08lx\n", fp->un.fmt3.effaddr); + addr += sizeof(fp->un.fmt3); + break; + case 0x4: + printk((m68k_is040or060 == 6 ? "fault addr=%08lx fslw=%08lx\n" + : "eff addr=%08lx pc=%08lx\n"), + fp->un.fmt4.effaddr, fp->un.fmt4.pc); + addr += sizeof(fp->un.fmt4); + break; + case 0x7: + printk("eff addr=%08lx ssw=%04x faddr=%08lx\n", + fp->un.fmt7.effaddr, fp->un.fmt7.ssw, fp->un.fmt7.faddr); + printk("wb 1 stat/addr/data: %04x %08lx %08lx\n", + fp->un.fmt7.wb1s, fp->un.fmt7.wb1a, fp->un.fmt7.wb1dpd0); + printk("wb 2 stat/addr/data: %04x %08lx %08lx\n", + fp->un.fmt7.wb2s, fp->un.fmt7.wb2a, fp->un.fmt7.wb2d); + printk("wb 3 stat/addr/data: %04x %08lx %08lx\n", + fp->un.fmt7.wb3s, fp->un.fmt7.wb3a, fp->un.fmt7.wb3d); + printk("push data: %08lx %08lx %08lx %08lx\n", + fp->un.fmt7.wb1dpd0, fp->un.fmt7.pd1, fp->un.fmt7.pd2, + fp->un.fmt7.pd3); + addr += sizeof(fp->un.fmt7); + break; + case 0x9: + printk("instr addr=%08lx\n", fp->un.fmt9.iaddr); + addr += sizeof(fp->un.fmt9); + break; + case 0xa: + printk("ssw=%04x isc=%04x isb=%04x daddr=%08lx dobuf=%08lx\n", + fp->un.fmta.ssw, fp->un.fmta.isc, fp->un.fmta.isb, + fp->un.fmta.daddr, fp->un.fmta.dobuf); + addr += sizeof(fp->un.fmta); + break; + case 0xb: + printk("ssw=%04x isc=%04x isb=%04x daddr=%08lx dobuf=%08lx\n", + fp->un.fmtb.ssw, fp->un.fmtb.isc, fp->un.fmtb.isb, + fp->un.fmtb.daddr, fp->un.fmtb.dobuf); + printk("baddr=%08lx dibuf=%08lx ver=%x\n", + fp->un.fmtb.baddr, fp->un.fmtb.dibuf, fp->un.fmtb.ver); + addr += sizeof(fp->un.fmtb); + break; + default: + printk("\n"); + } + + stack = (unsigned long *)addr; + endstack = (unsigned long *)PAGE_ALIGN(addr); + + printk("Stack from %08lx:\n ", (unsigned long)stack); + for (i = 0; i < kstack_depth_to_print; i++) { + if (stack + 1 > endstack) + break; + if (i && ((i % 8) == 0)) + printk("\n "); + printk("%08lx ", *stack++); + } + + printk ("\nCall Trace: "); + stack = (unsigned long *) addr; + i = 1; + module_start = VMALLOC_START; + module_end = module_start + MODULE_RANGE; + while (stack + 1 <= endstack) { + addr = *stack++; + /* + * If the address is either in the text segment of the + * kernel, or in the region which contains vmalloc'ed + * memory, it *may* be the address of a calling + * routine; if so, print it so that someone tracing + * down the cause of the crash will be able to figure + * out the call path that was taken. + */ + if (((addr >= (unsigned long) &_start) && + (addr <= (unsigned long) &_etext)) || + ((addr >= module_start) && (addr <= module_end))) { + if (i && ((i % 8) == 0)) + printk("\n "); + printk("[<%08lx>] ", addr); + i++; + } + } + printk("\nCode: "); + for (i = 0; i < 10; i++) + printk("%04x ", 0xffff & ((short *) fp->ptregs.pc)[i]); + printk ("\n"); +} + +void bad_super_trap (struct frame *fp) +{ + console_verbose(); + if ((fp->ptregs.vector) < 48*4) + printk ("*** %s *** FORMAT=%X\n", + vec_names[(fp->ptregs.vector) >> 2], + fp->ptregs.format); + else + printk ("*** Exception %d *** FORMAT=%X\n", + (fp->ptregs.vector) >> 2, + fp->ptregs.format); + if (((fp->ptregs.vector) >> 2) == VEC_ADDRERR + && !m68k_is040or060) { + unsigned short ssw = fp->un.fmtb.ssw; + + printk ("SSW=%#06x ", ssw); + + if (ssw & RC) + printk ("Pipe stage C instruction fault at %#010lx\n", + (fp->ptregs.format) == 0xA ? + fp->ptregs.pc + 2 : fp->un.fmtb.baddr - 2); + if (ssw & RB) + printk ("Pipe stage B instruction fault at %#010lx\n", + (fp->ptregs.format) == 0xA ? + fp->ptregs.pc + 4 : fp->un.fmtb.baddr); + if (ssw & DF) + printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n", + ssw & RW ? "read" : "write", + fp->un.fmtb.daddr, space_names[ssw & DFC], + fp->ptregs.pc); + } + printk ("Current process id is %d\n", current->pid); + die_if_kernel("BAD KERNEL TRAP", &fp->ptregs, 0); +} + +asmlinkage void trap_c(struct frame *fp) +{ + int sig; + + if ((fp->ptregs.sr & PS_S) + && ((fp->ptregs.vector) >> 2) == VEC_TRACE + && !(fp->ptregs.sr & PS_T)) { + /* traced a trapping instruction */ + unsigned char *lp = ((unsigned char *)&fp->un.fmt2) + 4; + current->flags |= PF_DTRACE; + /* clear the trace bit */ + (*(unsigned short *)lp) &= ~PS_T; + return; + } else if (fp->ptregs.sr & PS_S) { + bad_super_trap(fp); + return; + } + + /* send the appropriate signal to the user program */ + switch ((fp->ptregs.vector) >> 2) { + case VEC_ADDRERR: + sig = SIGBUS; + break; + case VEC_BUSERR: + sig = SIGSEGV; + break; + case VEC_ILLEGAL: + case VEC_PRIV: + case VEC_LINE10: + case VEC_LINE11: + case VEC_COPROC: + case VEC_TRAP1: + case VEC_TRAP2: + case VEC_TRAP3: + case VEC_TRAP4: + case VEC_TRAP5: + case VEC_TRAP6: + case VEC_TRAP7: + case VEC_TRAP8: + case VEC_TRAP9: + case VEC_TRAP10: + case VEC_TRAP11: + case VEC_TRAP12: + case VEC_TRAP13: + case VEC_TRAP14: + sig = SIGILL; + break; + case VEC_FPBRUC: + case VEC_FPIR: + case VEC_FPDIVZ: + case VEC_FPUNDER: + case VEC_FPOE: + case VEC_FPOVER: + case VEC_FPNAN: + { + unsigned char fstate[216]; + + __asm__ __volatile__ ("fsave %0@" : : "a" (fstate) : "memory"); + /* Set the exception pending bit in the 68882 idle frame */ + if (*(unsigned short *) fstate == 0x1f38) + { + fstate[fstate[1]] |= 1 << 3; + __asm__ __volatile__ ("frestore %0@" : : "a" (fstate)); + } + } + /* fall through */ + case VEC_ZERODIV: + case VEC_TRAP: + sig = SIGFPE; + break; + case VEC_TRACE: /* ptrace single step */ + fp->ptregs.sr &= ~PS_T; + case VEC_TRAP15: /* breakpoint */ + sig = SIGTRAP; + break; + default: + sig = SIGILL; + break; + } + + send_sig (sig, current, 1); +} + +asmlinkage void set_esp0 (unsigned long ssp) +{ + current->tss.esp0 = ssp; +} + +void die_if_kernel (char *str, struct pt_regs *fp, int nr) +{ + if (!(fp->sr & PS_S)) + return; + + console_verbose(); + printk("%s: %08x\n",str,nr); + printk("PC: %08lx\nSR: %04x SP: %p\n", fp->pc, fp->sr, fp); + printk("d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n", + fp->d0, fp->d1, fp->d2, fp->d3); + printk("d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n", + fp->d4, fp->d5, fp->a0, fp->a1); + + if (STACK_MAGIC != *(unsigned long *)current->kernel_stack_page) + printk("Corrupted stack page\n"); + printk("Process %s (pid: %d, stackpage=%08lx)\n", + current->comm, current->pid, current->kernel_stack_page); + dump_stack((struct frame *)fp); + do_exit(SIGSEGV); +} diff -u --recursive --new-file v1.3.93/linux/arch/m68k/lib/Makefile linux/arch/m68k/lib/Makefile --- v1.3.93/linux/arch/m68k/lib/Makefile Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/lib/Makefile Mon Apr 1 21:37:48 1996 @@ -0,0 +1,8 @@ +# +# Makefile for m68k-specific library files.. +# + +L_TARGET = lib.a +L_OBJS = ashrdi3.o checksum.o memcpy.o memcmp.o + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.93/linux/arch/m68k/lib/ashrdi3.c linux/arch/m68k/lib/ashrdi3.c --- v1.3.93/linux/arch/m68k/lib/ashrdi3.c Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/lib/ashrdi3.c Mon Apr 1 21:37:48 1996 @@ -0,0 +1,63 @@ +/* ashrdi3.c extracted from gcc-2.7.2/libgcc2.c which is: */ +/* Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#define BITS_PER_UNIT 8 + +typedef int SItype __attribute__ ((mode (SI))); +typedef unsigned int USItype __attribute__ ((mode (SI))); +typedef int DItype __attribute__ ((mode (DI))); +typedef int word_type __attribute__ ((mode (__word__))); + +struct DIstruct {SItype high, low;}; + +typedef union +{ + struct DIstruct s; + DItype ll; +} DIunion; + +DItype +__ashrdi3 (DItype u, word_type b) +{ + DIunion w; + word_type bm; + DIunion uu; + + if (b == 0) + return u; + + uu.ll = u; + + bm = (sizeof (SItype) * BITS_PER_UNIT) - b; + if (bm <= 0) + { + /* w.s.high = 1..1 or 0..0 */ + w.s.high = uu.s.high >> (sizeof (SItype) * BITS_PER_UNIT - 1); + w.s.low = uu.s.high >> -bm; + } + else + { + USItype carries = (USItype)uu.s.high << bm; + w.s.high = uu.s.high >> b; + w.s.low = ((USItype)uu.s.low >> b) | carries; + } + + return w.ll; +} diff -u --recursive --new-file v1.3.93/linux/arch/m68k/lib/checksum.c linux/arch/m68k/lib/checksum.c --- v1.3.93/linux/arch/m68k/lib/checksum.c Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/lib/checksum.c Sat Apr 6 01:40:19 1996 @@ -0,0 +1,323 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * IP/TCP/UDP checksumming routines + * + * Authors: Jorge Cwik, + * Arnt Gulbrandsen, + * Tom May, + * Andreas Schwab, + * Lots of code moved from tcp.c and ip.c; see those files + * for more names. + * + * 03/02/96 Jes Sorensen, Andreas Schwab, Roman Hodek: + * Fixed some nasty bugs, causing some horrible crashes. + * A: At some points, the sum (%0) was used as + * length-counter instead of the length counter + * (%1). Thanks to Roman Hodek for pointing this out. + * B: GCC seems to mess up if one uses too many + * data-registers to hold input values and one tries to + * specify d0 and d1 as scratch registers. Letting gcc choose these + * registers itself solves the problem. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include + +/* + * computes a partial checksum, e.g. for TCP/UDP fragments + */ + +unsigned int +csum_partial (const unsigned char *buff, int len, unsigned int sum) +{ + unsigned long tmp1, tmp2; + /* + * Experiments with ethernet and slip connections show that buff + * is aligned on either a 2-byte or 4-byte boundary. + */ + __asm__("movel %2,%3\n\t" + "btst #1,%3\n\t" /* Check alignment */ + "jeq 2f\n\t" + "subql #2,%1\n\t" /* buff%4==2: treat first word */ + "jgt 1f\n\t" + "addql #2,%1\n\t" /* len was == 2, treat only rest */ + "jra 4f\n" + "1:\t" + "addw %2@+,%0\n\t" /* add first word to sum */ + "clrl %3\n\t" + "addxl %3,%0\n" /* add X bit */ + "2:\t" + /* unrolled loop for the main part: do 8 longs at once */ + "movel %1,%3\n\t" /* save len in tmp1 */ + "lsrl #5,%1\n\t" /* len/32 */ + "jeq 2f\n\t" /* not enough... */ + "subql #1,%1\n" + "1:\t" + "movel %2@+,%4\n\t" + "addxl %4,%0\n\t" + "movel %2@+,%4\n\t" + "addxl %4,%0\n\t" + "movel %2@+,%4\n\t" + "addxl %4,%0\n\t" + "movel %2@+,%4\n\t" + "addxl %4,%0\n\t" + "movel %2@+,%4\n\t" + "addxl %4,%0\n\t" + "movel %2@+,%4\n\t" + "addxl %4,%0\n\t" + "movel %2@+,%4\n\t" + "addxl %4,%0\n\t" + "movel %2@+,%4\n\t" + "addxl %4,%0\n\t" + "dbra %1,1b\n\t" + "clrl %4\n\t" + "addxl %4,%0\n\t" /* add X bit */ + "clrw %1\n\t" + "subql #1,%1\n\t" + "jcc 1b\n" + "2:\t" + "movel %3,%1\n\t" /* restore len from tmp1 */ + "andw #0x1c,%3\n\t" /* number of rest longs */ + "jeq 4f\n\t" + "lsrw #2,%3\n\t" + "subqw #1,%3\n" + "3:\t" + /* loop for rest longs */ + "movel %2@+,%4\n\t" + "addxl %4,%0\n\t" + "dbra %3,3b\n\t" + "clrl %4\n\t" + "addxl %4,%0\n" /* add X bit */ + "4:\t" + /* now check for rest bytes that do not fit into longs */ + "andw #3,%1\n\t" + "jeq 7f\n\t" + "clrl %4\n\t" /* clear tmp2 for rest bytes */ + "subqw #2,%1\n\t" + "jlt 5f\n\t" + "movew %2@+,%4\n\t" /* have rest >= 2: get word */ + "swap %4\n\t" /* into bits 16..31 */ + "tstw %1\n\t" /* another byte? */ + "jeq 6f\n" + "5:\t" + "moveb %2@,%4\n\t" /* have odd rest: get byte */ + "lslw #8,%4\n\t" /* into bits 8..15; 16..31 untouched */ + "6:\t" + "addl %4,%0\n\t" /* now add rest long to sum */ + "clrl %4\n\t" + "addxl %4,%0\n" /* add X bit */ + "7:\t" + : "=d" (sum), "=d" (len), "=a" (buff), + "=&d" (tmp1), "=&d" (tmp2) + : "0" (sum), "1" (len), "2" (buff) + ); + return(sum); +} + + + +/* + * copy from fs while checksumming, otherwise like csum_partial + */ + +unsigned int +csum_partial_copy_fromuser(const char *src, char *dst, int len, int sum) +{ + unsigned long tmp1, tmp2; + __asm__("movel %2,%4\n\t" + "btst #1,%4\n\t" /* Check alignment */ + "jeq 2f\n\t" + "subql #2,%1\n\t" /* buff%4==2: treat first word */ + "jgt 1f\n\t" + "addql #2,%1\n\t" /* len was == 2, treat only rest */ + "jra 4f\n" + "1:\t" + "movesw %2@+,%4\n\t" /* add first word to sum */ + "addw %4,%0\n\t" + "movew %4,%3@+\n\t" + "clrl %4\n\t" + "addxl %4,%0\n" /* add X bit */ + "2:\t" + /* unrolled loop for the main part: do 8 longs at once */ + "movel %1,%4\n\t" /* save len in tmp1 */ + "lsrl #5,%1\n\t" /* len/32 */ + "jeq 2f\n\t" /* not enough... */ + "subql #1,%1\n" + "1:\t" + "movesl %2@+,%5\n\t" + "addxl %5,%0\n\t" + "movel %5,%3@+\n\t" + "movesl %2@+,%5\n\t" + "addxl %5,%0\n\t" + "movel %5,%3@+\n\t" + "movesl %2@+,%5\n\t" + "addxl %5,%0\n\t" + "movel %5,%3@+\n\t" + "movesl %2@+,%5\n\t" + "addxl %5,%0\n\t" + "movel %5,%3@+\n\t" + "movesl %2@+,%5\n\t" + "addxl %5,%0\n\t" + "movel %5,%3@+\n\t" + "movesl %2@+,%5\n\t" + "addxl %5,%0\n\t" + "movel %5,%3@+\n\t" + "movesl %2@+,%5\n\t" + "addxl %5,%0\n\t" + "movel %5,%3@+\n\t" + "movesl %2@+,%5\n\t" + "addxl %5,%0\n\t" + "movel %5,%3@+\n\t" + "dbra %1,1b\n\t" + "clrl %5\n\t" + "addxl %5,%0\n\t" /* add X bit */ + "clrw %1\n\t" + "subql #1,%1\n\t" + "jcc 1b\n" + "2:\t" + "movel %4,%1\n\t" /* restore len from tmp1 */ + "andw #0x1c,%4\n\t" /* number of rest longs */ + "jeq 4f\n\t" + "lsrw #2,%4\n\t" + "subqw #1,%4\n" + "3:\t" + /* loop for rest longs */ + "movesl %2@+,%5\n\t" + "addxl %5,%0\n\t" + "movel %5,%3@+\n\t" + "dbra %4,3b\n\t" + "clrl %5\n\t" + "addxl %5,%0\n" /* add X bit */ + "4:\t" + /* now check for rest bytes that do not fit into longs */ + "andw #3,%1\n\t" + "jeq 7f\n\t" + "clrl %5\n\t" /* clear tmp2 for rest bytes */ + "subqw #2,%1\n\t" + "jlt 5f\n\t" + "movesw %2@+,%5\n\t" /* have rest >= 2: get word */ + "movew %5,%3@+\n\t" + "swap %5\n\t" /* into bits 16..31 */ + "tstw %1\n\t" /* another byte? */ + "jeq 6f\n" + "5:\t" + "movesb %2@,%5\n\t" /* have odd rest: get byte */ + "moveb %5,%3@+\n\t" + "lslw #8,%5\n\t" /* into bits 8..15; 16..31 untouched */ + "6:\t" + "addl %5,%0\n\t" /* now add rest long to sum */ + "clrl %5\n\t" + "addxl %5,%0\n" /* add X bit */ + "7:\t" + : "=d" (sum), "=d" (len), "=a" (src), "=a" (dst), + "=&d" (tmp1), "=&d" (tmp2) + : "0" (sum), "1" (len), "2" (src), "3" (dst) + ); + return(sum); +} +/* + * copy from ds while checksumming, otherwise like csum_partial + */ + +unsigned int +csum_partial_copy(const char *src, char *dst, int len, int sum) +{ + unsigned long tmp1, tmp2; + __asm__("movel %2,%4\n\t" + "btst #1,%4\n\t" /* Check alignment */ + "jeq 2f\n\t" + "subql #2,%1\n\t" /* buff%4==2: treat first word */ + "jgt 1f\n\t" + "addql #2,%1\n\t" /* len was == 2, treat only rest */ + "jra 4f\n" + "1:\t" + "movew %2@+,%4\n\t" /* add first word to sum */ + "addw %4,%0\n\t" + "movew %4,%3@+\n\t" + "clrl %4\n\t" + "addxl %4,%0\n" /* add X bit */ + "2:\t" + /* unrolled loop for the main part: do 8 longs at once */ + "movel %1,%4\n\t" /* save len in tmp1 */ + "lsrl #5,%1\n\t" /* len/32 */ + "jeq 2f\n\t" /* not enough... */ + "subql #1,%1\n" + "1:\t" + "movel %2@+,%5\n\t" + "addxl %5,%0\n\t" + "movel %5,%3@+\n\t" + "movel %2@+,%5\n\t" + "addxl %5,%0\n\t" + "movel %5,%3@+\n\t" + "movel %2@+,%5\n\t" + "addxl %5,%0\n\t" + "movel %5,%3@+\n\t" + "movel %2@+,%5\n\t" + "addxl %5,%0\n\t" + "movel %5,%3@+\n\t" + "movel %2@+,%5\n\t" + "addxl %5,%0\n\t" + "movel %5,%3@+\n\t" + "movel %2@+,%5\n\t" + "addxl %5,%0\n\t" + "movel %5,%3@+\n\t" + "movel %2@+,%5\n\t" + "addxl %5,%0\n\t" + "movel %5,%3@+\n\t" + "movel %2@+,%5\n\t" + "addxl %5,%0\n\t" + "movel %5,%3@+\n\t" + "dbra %1,1b\n\t" + "clrl %5\n\t" + "addxl %5,%0\n\t" /* add X bit */ + "clrw %1\n\t" + "subql #1,%1\n\t" + "jcc 1b\n" + "2:\t" + "movel %4,%1\n\t" /* restore len from tmp1 */ + "andw #0x1c,%4\n\t" /* number of rest longs */ + "jeq 4f\n\t" + "lsrw #2,%4\n\t" + "subqw #1,%4\n" + "3:\t" + /* loop for rest longs */ + "movel %2@+,%5\n\t" + "addxl %5,%0\n\t" + "movel %5,%3@+\n\t" + "dbra %4,3b\n\t" + "clrl %5\n\t" + "addxl %5,%0\n" /* add X bit */ + "4:\t" + /* now check for rest bytes that do not fit into longs */ + "andw #3,%1\n\t" + "jeq 7f\n\t" + "clrl %5\n\t" /* clear tmp2 for rest bytes */ + "subqw #2,%1\n\t" + "jlt 5f\n\t" + "movew %2@+,%5\n\t" /* have rest >= 2: get word */ + "movew %5,%3@+\n\t" + "swap %5\n\t" /* into bits 16..31 */ + "tstw %1\n\t" /* another byte? */ + "jeq 6f\n" + "5:\t" + "moveb %2@,%5\n\t" /* have odd rest: get byte */ + "moveb %5,%3@+\n\t" + "lslw #8,%5\n" /* into bits 8..15; 16..31 untouched */ + "6:\t" + "addl %5,%0\n\t" /* now add rest long to sum */ + "clrl %5\n\t" + "addxl %5,%0\n" /* add X bit */ + "7:\t" + : "=d" (sum), "=d" (len), "=a" (src), "=a" (dst), + "=&d" (tmp1), "=&d" (tmp2) + : "0" (sum), "1" (len), "2" (src), "3" (dst) + ); + return(sum); +} diff -u --recursive --new-file v1.3.93/linux/arch/m68k/lib/memcmp.c linux/arch/m68k/lib/memcmp.c --- v1.3.93/linux/arch/m68k/lib/memcmp.c Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/lib/memcmp.c Wed Dec 27 22:46:35 1995 @@ -0,0 +1,11 @@ +#include + +int memcmp(const void * cs,const void * ct,size_t count) +{ + const unsigned char *su1, *su2; + + for( su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--) + if (*su1 != *su2) + return((*su1 < *su2) ? -1 : +1); + return(0); +} diff -u --recursive --new-file v1.3.93/linux/arch/m68k/lib/memcpy.c linux/arch/m68k/lib/memcpy.c --- v1.3.93/linux/arch/m68k/lib/memcpy.c Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/lib/memcpy.c Wed Dec 27 22:46:35 1995 @@ -0,0 +1,55 @@ +#include + +void * memcpy(void * to, const void * from, size_t n) +{ + void *xto = to; + size_t temp; + + if (!n) + return xto; + if ((long) to & 1) + { + char *cto = to; + const char *cfrom = from; + *cto++ = *cfrom++; + to = cto; + from = cfrom; + n--; + } + if (n > 2 && (long) to & 2) + { + short *sto = to; + const short *sfrom = from; + *sto++ = *sfrom++; + to = sto; + from = sfrom; + n -= 2; + } + temp = n >> 2; + if (temp) + { + long *lto = to; + const long *lfrom = from; + temp--; + do + *lto++ = *lfrom++; + while (temp--); + to = lto; + from = lfrom; + } + if (n & 2) + { + short *sto = to; + const short *sfrom = from; + *sto++ = *sfrom++; + to = sto; + from = sfrom; + } + if (n & 1) + { + char *cto = to; + const char *cfrom = from; + *cto = *cfrom; + } + return xto; +} diff -u --recursive --new-file v1.3.93/linux/arch/m68k/mm/Makefile linux/arch/m68k/mm/Makefile --- v1.3.93/linux/arch/m68k/mm/Makefile Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/mm/Makefile Wed Dec 27 22:46:36 1995 @@ -0,0 +1,13 @@ +# +# Makefile for the linux m68k-specific parts of the memory manager. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definition is now in the main makefile... + +O_TARGET := mm.o +O_OBJS := init.o fault.o memory.o + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.93/linux/arch/m68k/mm/fault.c linux/arch/m68k/mm/fault.c --- v1.3.93/linux/arch/m68k/mm/fault.c Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/mm/fault.c Thu Apr 18 02:59:59 1996 @@ -0,0 +1,113 @@ +/* + * linux/arch/m68k/mm/fault.c + * + * Copyright (C) 1995 Hamish Macdonald + */ + +#include +#include +#include +#include + +#include +#include + +extern void die_if_kernel(char *, struct pt_regs *, long); + +/* + * This routine handles page faults. It determines the problem, and + * then passes it off to one of the appropriate routines. + * + * error_code: + * bit 0 == 0 means no page found, 1 means protection fault + * bit 1 == 0 means read, 1 means write + * + * If this routine detects a bad access, it returns 1, otherwise it + * returns 0. + */ +asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address, + unsigned long error_code) +{ + struct vm_area_struct * vma; + +#ifdef DEBUG + printk ("regs->sr=%#x, regs->pc=%#lx, address=%#lx, %ld, %p\n", + regs->sr, regs->pc, address, error_code, + current->tss.pagedir_v); +#endif + + vma = find_vma(current, address); + if (!vma) + goto bad_area; + if (vma->vm_start <= address) + goto good_area; + if (!(vma->vm_flags & VM_GROWSDOWN)) + goto bad_area; + if (user_mode(regs)) { + /* Accessing the stack below usp is always a bug. The + "+ 256" is there due to some instructions doing + pre-decrement on the stack and that doesn't show up + until later. */ + if (address + 256 < rdusp()) + goto bad_area; + } + if (expand_stack(vma, address)) + goto bad_area; + +/* + * Ok, we have a good vm_area for this memory access, so + * we can handle it.. + */ +good_area: + /* + * was it a write? + */ + if (error_code & 2) { + if (!(vma->vm_flags & VM_WRITE)) + goto bad_area; + } else { + /* read with protection fault? */ + if (error_code & 1) + goto bad_area; + if (!(vma->vm_flags & (VM_READ | VM_EXEC))) + goto bad_area; + } + if (error_code & 1) { + do_wp_page(current, vma, address, error_code & 2); + return 0; + } + do_no_page(current, vma, address, error_code & 2); + + /* There seems to be a missing invalidate somewhere in do_no_page. + * Until I found it, this one cures the problem and makes + * 1.2 run on the 68040 (Martin Apel). + */ + flush_tlb_all(); + + return 0; + +/* + * Something tried to access memory that isn't in our memory map.. + * Fix it, but check if it's kernel or user first.. + */ +bad_area: + if (user_mode(regs)) { + /* User memory access */ + send_sig (SIGSEGV, current, 1); + return 1; + } + +/* + * Oops. The kernel tried to access some bad page. We'll have to + * terminate things with extreme prejudice. + */ + if ((unsigned long) address < PAGE_SIZE) { + printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); + } else + printk(KERN_ALERT "Unable to handle kernel access"); + printk(" at virtual address %08lx\n",address); + die_if_kernel("Oops", regs, error_code); + do_exit(SIGKILL); + + return 1; +} diff -u --recursive --new-file v1.3.93/linux/arch/m68k/mm/init.c linux/arch/m68k/mm/init.c --- v1.3.93/linux/arch/m68k/mm/init.c Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/mm/init.c Thu Apr 18 03:00:00 1996 @@ -0,0 +1,545 @@ +/* + * linux/arch/m68k/mm/init.c + * + * Copyright (C) 1995 Hamish Macdonald + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_BLK_DEV_INITRD +#include +#endif + +#include +#include +#include +#include +#include +#include + +extern void die_if_kernel(char *,struct pt_regs *,long); +extern void show_net_buffers(void); +extern unsigned long mm_phys_to_virt (unsigned long addr); +extern char *rd_start; +extern int rd_doload; + +unsigned long ramdisk_length; + +/* + * BAD_PAGE is the page that is used for page faults when linux + * is out-of-memory. Older versions of linux just did a + * do_exit(), but using this instead means there is less risk + * for a process dying in kernel mode, possibly leaving a inode + * unused etc.. + * + * BAD_PAGETABLE is the accompanying page-table: it is initialized + * to point to BAD_PAGE entries. + * + * ZERO_PAGE is a special page that is used for zero-initialized + * data and COW. + */ +static unsigned long empty_bad_page_table; + +pte_t *__bad_pagetable(void) +{ + memset((void *)empty_bad_page_table, 0, PAGE_SIZE); + return (pte_t *)empty_bad_page_table; +} + +static unsigned long empty_bad_page; + +pte_t __bad_page(void) +{ + memset ((void *)empty_bad_page, 0, PAGE_SIZE); + return pte_mkdirty(mk_pte(empty_bad_page, PAGE_SHARED)); +} + +unsigned long empty_zero_page; + +void show_mem(void) +{ + unsigned long i; + int free = 0, total = 0, reserved = 0, nonshared = 0, shared = 0; + + printk("\nMem-info:\n"); + show_free_areas(); + printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10)); + i = high_memory >> PAGE_SHIFT; + while (i-- > 0) { + total++; + if (PageReserved(mem_map+i)) + reserved++; + else if (!mem_map[i].count) + free++; + else if (mem_map[i].count == 1) + nonshared++; + else + shared += mem_map[i].count-1; + } + printk("%d pages of RAM\n",total); + printk("%d free pages\n",free); + printk("%d reserved pages\n",reserved); + printk("%d pages nonshared\n",nonshared); + printk("%d pages shared\n",shared); + show_buffers(); +#ifdef CONFIG_NET + show_net_buffers(); +#endif +} + +#if 0 /* The 68030 doesn't care about reserved bits. */ +/* + * Bits to add to page descriptors for "normal" caching mode. + * For 68020/030 this is 0. + * For 68040, this is _PAGE_CACHE040 (cachable, copyback) + */ +unsigned long mm_cachebits; +#endif + +pte_t *kernel_page_table (unsigned long *memavailp) +{ + pte_t *ptablep; + + ptablep = (pte_t *)*memavailp; + *memavailp += PAGE_SIZE; + + nocache_page ((unsigned long)ptablep); + + return ptablep; +} + +static unsigned long map_chunk (unsigned long addr, + unsigned long size, + unsigned long *memavailp) +{ +#define ONEMEG (1024*1024) +#define L3TREESIZE (256*1024) + + int is040 = m68k_is040or060; + static unsigned long mem_mapped = 0; + static unsigned long virtaddr = 0; + static pte_t *ktablep = NULL; + unsigned long *kpointerp; + unsigned long physaddr; + extern pte_t *kpt; + int pindex; /* index into pointer table */ + pgd_t *page_dir = pgd_offset_k (virtaddr); + + if (!pgd_present (*page_dir)) { + /* we need a new pointer table */ + kpointerp = (unsigned long *) get_kpointer_table (); + pgd_set (page_dir, (pmd_t *) kpointerp); + memset (kpointerp, 0, PTRS_PER_PMD * sizeof (pmd_t)); + } + else + kpointerp = (unsigned long *) pgd_page (*page_dir); + + /* + * pindex is the offset into the pointer table for the + * descriptors for the current virtual address being mapped. + */ + pindex = (virtaddr >> 18) & 0x7f; + +#ifdef DEBUG + printk ("mm=%ld, kernel_pg_dir=%p, kpointerp=%p, pindex=%d\n", + mem_mapped, kernel_pg_dir, kpointerp, pindex); +#endif + + /* + * if this is running on an '040, we already allocated a page + * table for the first 4M. The address is stored in kpt by + * arch/head.S + * + */ + if (is040 && mem_mapped == 0) + ktablep = kpt; + + for (physaddr = addr; + physaddr < addr + size; + mem_mapped += L3TREESIZE, virtaddr += L3TREESIZE) { + +#ifdef DEBUG + printk ("pa=%#lx va=%#lx ", physaddr, virtaddr); +#endif + + if (pindex > 127 && mem_mapped >= 32*ONEMEG) { + /* we need a new pointer table every 32M */ +#ifdef DEBUG + printk ("[new pointer]"); +#endif + + kpointerp = (unsigned long *)get_kpointer_table (); + pgd_set(pgd_offset_k(virtaddr), (pmd_t *)kpointerp); + pindex = 0; + } + + if (is040) { + int i; + unsigned long ktable; + + /* Don't map the first 4 MB again. The pagetables + * for this range have already been initialized + * in boot/head.S. Otherwise the pages used for + * tables would be reinitialized to copyback mode. + */ + + if (mem_mapped < 4 * ONEMEG) + { +#ifdef DEBUG + printk ("Already initialized\n"); +#endif + physaddr += L3TREESIZE; + pindex++; + continue; + } +#ifdef DEBUG + printk ("[setup table]"); +#endif + + /* + * 68040, use page tables pointed to by the + * kernel pointer table. + */ + + if ((pindex & 15) == 0) { + /* Need new page table every 4M on the '040 */ +#ifdef DEBUG + printk ("[new table]"); +#endif + ktablep = kernel_page_table (memavailp); + } + + ktable = VTOP(ktablep); + + /* + * initialize section of the page table mapping + * this 256K portion. + */ + for (i = 0; i < 64; i++) { + pte_val(ktablep[i]) = physaddr | _PAGE_PRESENT + | _PAGE_CACHE040 | _PAGE_GLOBAL040; + physaddr += PAGE_SIZE; + } + ktablep += 64; + + /* + * make the kernel pointer table point to the + * kernel page table. Each entries point to a + * 64 entry section of the page table. + */ + + kpointerp[pindex++] = ktable | _PAGE_TABLE; + } else { + /* + * 68030, use early termination page descriptors. + * Each one points to 64 pages (256K). + */ +#ifdef DEBUG + printk ("[early term] "); +#endif + if (virtaddr == 0UL) { + /* map the first 256K using a 64 entry + * 3rd level page table. + * UNMAP the first entry to trap + * zero page (NULL pointer) references + */ + int i; + unsigned long *tbl; + + tbl = (unsigned long *)get_kpointer_table(); + + kpointerp[pindex++] = VTOP(tbl) | _PAGE_TABLE; + + for (i = 0; i < 64; i++, physaddr += PAGE_SIZE) + tbl[i] = physaddr | _PAGE_PRESENT; + + /* unmap the zero page */ + tbl[0] = 0; + } else { + /* not the first 256K */ + kpointerp[pindex++] = physaddr | _PAGE_PRESENT; +#ifdef DEBUG + printk ("%lx=%lx ", VTOP(&kpointerp[pindex-1]), + kpointerp[pindex-1]); +#endif + physaddr += 64 * PAGE_SIZE; + } + } +#ifdef DEBUG + printk ("\n"); +#endif + } + + return mem_mapped; +} + +extern unsigned long free_area_init(unsigned long, unsigned long); + +extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; + +/* + * paging_init() continues the virtual memory environment setup which + * was begun by the code in arch/head.S. + * The parameters are pointers to where to stick the starting and ending + * addresses of available kernel virtual memory. + */ +unsigned long paging_init(unsigned long start_mem, unsigned long end_mem) +{ + int chunk; + unsigned long mem_avail = 0; + /* pointer to page table for kernel stacks */ + extern unsigned long availmem; + +#ifdef DEBUG + { + extern pte_t *kpt; + printk ("start of paging_init (%p, %p, %lx, %lx, %lx)\n", + kernel_pg_dir, kpt, availmem, start_mem, end_mem); + } +#endif + +#if 0 + /* + * Setup cache bits + */ + mm_cachebits = m68k_is040or060 ? _PAGE_CACHE040 : 0; + + /* Initialize protection map. */ + protection_map[0] = PAGE_READONLY; + protection_map[1] = PAGE_READONLY; + protection_map[2] = PAGE_COPY; + protection_map[3] = PAGE_COPY; + protection_map[4] = PAGE_READONLY; + protection_map[5] = PAGE_READONLY; + protection_map[6] = PAGE_COPY; + protection_map[7] = PAGE_COPY; + protection_map[8] = PAGE_READONLY; + protection_map[9] = PAGE_READONLY; + protection_map[10] = PAGE_SHARED; + protection_map[11] = PAGE_SHARED; + protection_map[12] = PAGE_READONLY; + protection_map[13] = PAGE_READONLY; + protection_map[14] = PAGE_SHARED; + protection_map[15] = PAGE_SHARED; +#endif + + /* + * Map the physical memory available into the kernel virtual + * address space. It may allocate some memory for page + * tables and thus modify availmem. + */ + + for (chunk = 0; chunk < boot_info.num_memory; chunk++) { + mem_avail = map_chunk (boot_info.memory[chunk].addr, + boot_info.memory[chunk].size, + &availmem); + + } + flush_tlb_all(); +#ifdef DEBUG + printk ("memory available is %ldKB\n", mem_avail >> 10); +#endif + + /* + * virtual address after end of kernel + * "availmem" is setup by the code in head.S. + */ + start_mem = availmem; + +#ifdef DEBUG + printk ("start_mem is %#lx\nvirtual_end is %#lx\n", + start_mem, end_mem); +#endif + + /* + * initialize the bad page table and bad page to point + * to a couple of allocated pages + */ + empty_bad_page_table = start_mem; + start_mem += PAGE_SIZE; + empty_bad_page = start_mem; + start_mem += PAGE_SIZE; + empty_zero_page = start_mem; + start_mem += PAGE_SIZE; + memset((void *)empty_zero_page, 0, PAGE_SIZE); + +#if 0 + /* + * allocate the "swapper" page directory and + * record in task 0 (swapper) tss + */ + swapper_pg_dir = (pgd_t *)get_kpointer_table(); + + init_mm.pgd = swapper_pg_dir; +#endif + + memset (swapper_pg_dir, 0, sizeof(pgd_t)*PTRS_PER_PGD); + task[0]->tss.pagedir_v = (unsigned long *)swapper_pg_dir; + task[0]->tss.pagedir_p = VTOP (swapper_pg_dir); + +#ifdef DEBUG + printk ("task 0 pagedir at %p virt, %#lx phys\n", + task[0]->tss.pagedir_v, task[0]->tss.pagedir_p); +#endif + + /* setup CPU root pointer for swapper task */ + task[0]->tss.crp[0] = 0x80000000 | _PAGE_SHORT; + task[0]->tss.crp[1] = task[0]->tss.pagedir_p; + + if (m68k_is040or060) + asm ("movel %0,%/d0\n\t" + ".long 0x4e7b0806" /* movec d0,urp */ + : /* no outputs */ + : "g" (task[0]->tss.crp[1]) + : "d0"); + else + asm ("pmove %0@,%/crp" + : /* no outputs */ + : "a" (task[0]->tss.crp)); + +#ifdef DEBUG + printk ("set crp\n"); +#endif + + /* + * Set up SFC/DFC registers (user data space) + */ + set_fs (USER_DS); + +#ifdef DEBUG + printk ("before free_area_init\n"); +#endif + +#ifndef CONFIG_BLK_DEV_INITRD + /* + * Since the initialization of the ramdisk's has been changed + * so it fits the new driver initialization scheme, we have to + * make room for our preloaded image here, instead of doing it + * in rd_init() as we cannot kmalloc() a block large enough + * for the image. + */ + + ramdisk_length = boot_info.ramdisk_size * 1024; + + if ((ramdisk_length > 0) && (ROOT_DEV == 0)) { + char *rdp; /* current location of ramdisk */ + + rd_start = (char *) start_mem; + + /* get current address of ramdisk */ + rdp = (char *)mm_phys_to_virt (boot_info.ramdisk_addr); + + /* copy the ram disk image */ + memcpy (rd_start, rdp, ramdisk_length); + start_mem += ramdisk_length; + rd_doload = 1; /* tell rd_load to load this thing */ + } +#endif + + return free_area_init (start_mem, end_mem); +} + +void mem_init(unsigned long start_mem, unsigned long end_mem) +{ + int codepages = 0; + int reservedpages = 0; + int datapages = 0; + unsigned long tmp; + extern int _etext; + + end_mem &= PAGE_MASK; + high_memory = end_mem; + + start_mem = PAGE_ALIGN(start_mem); + while (start_mem < high_memory) { + clear_bit(PG_reserved, &mem_map[MAP_NR(start_mem)].flags); + start_mem += PAGE_SIZE; + } + +#ifdef CONFIG_ATARI + + if (MACH_IS_ATARI) { + + /* If the page with physical address 0 isn't the first kernel + * code page, it has to be reserved because the first 2 KB of + * ST-Ram can only be accessed from supervisor mode by + * hardware. + */ + + unsigned long virt0 = PTOV( 0 ), adr; + extern unsigned long rsvd_stram_beg, rsvd_stram_end; + + if (virt0 != 0) { + + set_bit(PG_reserved, &mem_map[MAP_NR(virt0)].flags); + + /* Also, reserve all pages that have been marked by + * stram_alloc() (e.g. for the screen memory). (This may + * treat the first ST-Ram page a second time, but that + * doesn't hurt...) */ + + rsvd_stram_end += PAGE_SIZE - 1; + rsvd_stram_end &= PAGE_MASK; + rsvd_stram_beg &= PAGE_MASK; + for( adr = rsvd_stram_beg; adr < rsvd_stram_end; adr += PAGE_SIZE ) + set_bit(PG_reserved, &mem_map[MAP_NR(adr)].flags); + } + } + +#endif +#ifdef DEBUG + printk ("task[0] root table is %p\n", task[0]->tss.pagedir_v); +#endif + + for (tmp = 0 ; tmp < end_mem ; tmp += PAGE_SIZE) { + if (VTOP (tmp) >= mach_max_dma_address) + clear_bit(PG_DMA, &mem_map[MAP_NR(tmp)].flags); + if (PageReserved(mem_map+MAP_NR(tmp))) { + if (tmp < (unsigned long)&_etext) + codepages++; + else + datapages++; + continue; + } + mem_map[MAP_NR(tmp)].count = 1; +#ifdef CONFIG_BLK_DEV_INITRD + if (!initrd_start || (tmp < initrd_start || tmp >= initrd_end)) +#endif + free_page(tmp); + } + tmp = nr_free_pages << PAGE_SHIFT; + printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data)\n", + tmp >> 10, + high_memory >> 10, + codepages << (PAGE_SHIFT-10), + reservedpages << (PAGE_SHIFT-10), + datapages << (PAGE_SHIFT-10)); +} + +void si_meminfo(struct sysinfo *val) +{ + unsigned long i; + + i = high_memory >> PAGE_SHIFT; + val->totalram = 0; + val->sharedram = 0; + val->freeram = nr_free_pages << PAGE_SHIFT; + val->bufferram = buffermem; + while (i-- > 0) { + if (PageReserved(mem_map+i)) + continue; + val->totalram++; + if (!mem_map[i].count) + continue; + val->sharedram += mem_map[i].count-1; + } + val->totalram <<= PAGE_SHIFT; + val->sharedram <<= PAGE_SHIFT; + return; +} diff -u --recursive --new-file v1.3.93/linux/arch/m68k/mm/memory.c linux/arch/m68k/mm/memory.c --- v1.3.93/linux/arch/m68k/mm/memory.c Thu Jan 1 02:00:00 1970 +++ linux/arch/m68k/mm/memory.c Thu Apr 18 03:00:00 1996 @@ -0,0 +1,753 @@ +/* + * linux/arch/m68k/mm/memory.c + * + * Copyright (C) 1995 Hamish Macdonald + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +extern pte_t *kernel_page_table (unsigned long *memavailp); + +static struct ptable_desc { + struct ptable_desc *prev; + struct ptable_desc *next; + unsigned long page; + unsigned char alloced; +} ptable_list = { &ptable_list, &ptable_list, 0, 0xff }; + +#define PD_NONEFREE(dp) ((dp)->alloced == 0xff) +#define PD_ALLFREE(dp) ((dp)->alloced == 0) +#define PD_TABLEFREE(dp,i) (!((dp)->alloced & (1<<(i)))) +#define PD_MARKUSED(dp,i) ((dp)->alloced |= (1<<(i))) +#define PD_MARKFREE(dp,i) ((dp)->alloced &= ~(1<<(i))) + +#define PTABLE_SIZE (PTRS_PER_PMD * sizeof(pmd_t)) + +pmd_t *get_pointer_table (void) +{ + pmd_t *pmdp = NULL; + unsigned long flags; + struct ptable_desc *dp = ptable_list.next; + int i; + + /* + * For a pointer table for a user process address space, a + * table is taken from a page allocated for the purpose. Each + * page can hold 8 pointer tables. The page is remapped in + * virtual address space to be noncacheable. + */ + if (PD_NONEFREE (dp)) { + + if (!(dp = kmalloc (sizeof(struct ptable_desc),GFP_KERNEL))) { + return 0; + } + + if (!(dp->page = __get_free_page (GFP_KERNEL))) { + kfree (dp); + return 0; + } + + nocache_page (dp->page); + + dp->alloced = 0; + /* put at head of list */ + save_flags(flags); + cli(); + dp->next = ptable_list.next; + dp->prev = ptable_list.next->prev; + ptable_list.next->prev = dp; + ptable_list.next = dp; + restore_flags(flags); + } + + for (i = 0; i < 8; i++) + if (PD_TABLEFREE (dp, i)) { + PD_MARKUSED (dp, i); + pmdp = (pmd_t *)(dp->page + PTABLE_SIZE*i); + break; + } + + if (PD_NONEFREE (dp)) { + /* move to end of list */ + save_flags(flags); + cli(); + dp->prev->next = dp->next; + dp->next->prev = dp->prev; + + dp->next = ptable_list.next->prev; + dp->prev = ptable_list.prev; + ptable_list.prev->next = dp; + ptable_list.prev = dp; + restore_flags(flags); + } + + memset (pmdp, 0, PTABLE_SIZE); + + return pmdp; +} + +void free_pointer_table (pmd_t *ptable) +{ + struct ptable_desc *dp; + unsigned long page = (unsigned long)ptable & PAGE_MASK; + int index = ((unsigned long)ptable - page)/PTABLE_SIZE; + unsigned long flags; + + for (dp = ptable_list.next; dp->page && dp->page != page; dp = dp->next) + ; + + if (!dp->page) + panic ("unable to find desc for ptable %p on list!", ptable); + + if (PD_TABLEFREE (dp, index)) + panic ("table already free!"); + + PD_MARKFREE (dp, index); + + if (PD_ALLFREE (dp)) { + /* all tables in page are free, free page */ + save_flags(flags); + cli(); + dp->prev->next = dp->next; + dp->next->prev = dp->prev; + restore_flags(flags); + cache_page (dp->page); + free_page (dp->page); + kfree (dp); + return; + } else { + /* + * move this descriptor the the front of the list, since + * it has one or more free tables. + */ + save_flags(flags); + cli(); + dp->prev->next = dp->next; + dp->next->prev = dp->prev; + + dp->next = ptable_list.next; + dp->prev = ptable_list.next->prev; + ptable_list.next->prev = dp; + ptable_list.next = dp; + restore_flags(flags); + } +} + +static unsigned char alloced = 0; +extern pmd_t (*kernel_pmd_table)[PTRS_PER_PMD]; /* initialized in head.S */ + +pmd_t *get_kpointer_table (void) +{ + /* For pointer tables for the kernel virtual address space, + * use a page that is allocated in head.S that can hold up to + * 8 pointer tables. This allows mapping of 8 * 32M = 256M of + * physical memory. This should be sufficient for now. + */ + pmd_t *ptable; + int i; + + for (i = 0; i < PAGE_SIZE/(PTRS_PER_PMD*sizeof(pmd_t)); i++) + if ((alloced & (1 << i)) == 0) { + ptable = kernel_pmd_table[i]; + memset (ptable, 0, PTRS_PER_PMD*sizeof(pmd_t)); + alloced |= (1 << i); + return ptable; + } + printk ("no space for kernel pointer table\n"); + return NULL; +} + +void free_kpointer_table (pmd_t *pmdp) +{ + int index = (pmd_t (*)[PTRS_PER_PMD])pmdp - kernel_pmd_table; + + if (index < 0 || index > 7 || + /* This works because kernel_pmd_table is page aligned. */ + ((unsigned long)pmdp & (sizeof(pmd_t) * PTRS_PER_PMD - 1))) + panic("attempt to free invalid kernel pointer table"); + else + alloced &= ~(1 << index); +} + +/* + * The following two routines map from a physical address to a kernel + * virtual address and vice versa. + */ +unsigned long mm_vtop (unsigned long vaddr) +{ + int i; + unsigned long voff = vaddr; + unsigned long offset = 0; + + for (i = 0; i < boot_info.num_memory; i++) + { + if (voff < offset + boot_info.memory[i].size) { +#ifdef DEBUGPV + printk ("VTOP(%lx)=%lx\n", vaddr, + boot_info.memory[i].addr + voff - offset); +#endif + return boot_info.memory[i].addr + voff - offset; + } else + offset += boot_info.memory[i].size; + } + + /* not in one of the memory chunks; get the actual + * physical address from the MMU. + */ + if (m68k_is040or060 == 6) { + unsigned long fs = get_fs(); + unsigned long paddr; + + set_fs (SUPER_DATA); + + /* The PLPAR instruction causes an access error if the translation + * is not possible. We don't catch that here, so a bad kernel trap + * will be reported in this case. */ + asm volatile ("movel %1,%/a0\n\t" + ".word 0xf5c8\n\t" /* plpar (a0) */ + "movel %/a0,%0" + : "=g" (paddr) + : "g" (vaddr) + : "a0" ); + set_fs (fs); + + return paddr; + + } else if (m68k_is040or060 == 4) { + unsigned long mmusr; + unsigned long fs = get_fs(); + + set_fs (SUPER_DATA); + + asm volatile ("movel %1,%/a0\n\t" + ".word 0xf568\n\t" /* ptestr (a0) */ + ".long 0x4e7a8805\n\t" /* movec mmusr, a0 */ + "movel %/a0,%0" + : "=g" (mmusr) + : "g" (vaddr) + : "a0", "d0"); + set_fs (fs); + + if (mmusr & MMU_R_040) + return (mmusr & PAGE_MASK) | (vaddr & (PAGE_SIZE-1)); + + panic ("VTOP040: bad virtual address %08lx (%lx)", vaddr, mmusr); + } else { + volatile unsigned short temp; + unsigned short mmusr; + unsigned long *descaddr; + + asm volatile ("ptestr #5,%2@,#7,%0\n\t" + "pmove %/psr,%1@" + : "=a&" (descaddr) + : "a" (&temp), "a" (vaddr)); + mmusr = temp; + + if (mmusr & (MMU_I|MMU_B|MMU_L)) + panic ("VTOP030: bad virtual address %08lx (%x)", vaddr, mmusr); + + descaddr = (unsigned long *)PTOV(descaddr); + + switch (mmusr & MMU_NUM) { + case 1: + return (*descaddr & 0xfe000000) | (vaddr & 0x01ffffff); + case 2: + return (*descaddr & 0xfffc0000) | (vaddr & 0x0003ffff); + case 3: + return (*descaddr & PAGE_MASK) | (vaddr & (PAGE_SIZE-1)); + default: + panic ("VTOP: bad levels (%u) for virtual address %08lx", + mmusr & MMU_NUM, vaddr); + } + } + + panic ("VTOP: bad virtual address %08lx", vaddr); +} + +unsigned long mm_ptov (unsigned long paddr) +{ + int i; + unsigned long offset = 0; + + for (i = 0; i < boot_info.num_memory; i++) + { + if (paddr >= boot_info.memory[i].addr && + paddr < (boot_info.memory[i].addr + + boot_info.memory[i].size)) { +#ifdef DEBUGPV + printk ("PTOV(%lx)=%lx\n", paddr, + (paddr - boot_info.memory[i].addr) + offset); +#endif + return (paddr - boot_info.memory[i].addr) + offset; + } else + offset += boot_info.memory[i].size; + } + + /* + * assume that the kernel virtual address is the same as the + * physical address. + * + * This should be reasonable in most situations: + * 1) They shouldn't be dereferencing the virtual address + * unless they are sure that it is valid from kernel space. + * 2) The only usage I see so far is converting a page table + * reference to some non-FASTMEM address space when freeing + * mmaped "/dev/mem" pages. These addresses are just passed + * to "free_page", which ignores addresses that aren't in + * the memory list anyway. + * + */ + + /* + * if on an amiga and address is in first 16M, move it + * to the ZTWO_ADDR range + */ + if (MACH_IS_AMIGA && paddr < 16*1024*1024) + return ZTWO_VADDR(paddr); + return paddr; +} + +#define clear040(paddr) __asm__ __volatile__ ("movel %0,%/a0\n\t"\ + ".word 0xf4d0"\ + /* CINVP I/D (a0) */\ + : : "g" ((paddr))\ + : "a0") + +#define push040(paddr) __asm__ __volatile__ ("movel %0,%/a0\n\t"\ + ".word 0xf4f0"\ + /* CPUSHP I/D (a0) */\ + : : "g" ((paddr))\ + : "a0") + +#define pushcl040(paddr) do { push040((paddr));\ + if (m68k_is040or060 == 6) clear040((paddr));\ + } while(0) + +#define pushv040(vaddr) __asm__ __volatile__ ("movel %0,%/a0\n\t"\ + /* ptestr (a0) */\ + ".word 0xf568\n\t"\ + /* movec mmusr,d0 */\ + ".long 0x4e7a0805\n\t"\ + "andw #0xf000,%/d0\n\t"\ + "movel %/d0,%/a0\n\t"\ + /* CPUSHP I/D (a0) */\ + ".word 0xf4f0"\ + : : "g" ((vaddr))\ + : "a0", "d0") + +#define pushv060(vaddr) __asm__ __volatile__ ("movel %0,%/a0\n\t"\ + /* plpar (a0) */\ + ".word 0xf5c8\n\t"\ + /* CPUSHP I/D (a0) */\ + ".word 0xf4f0"\ + : : "g" ((vaddr))\ + : "a0") + + +/* + * 040: Hit every page containing an address in the range paddr..paddr+len-1. + * (Low order bits of the ea of a CINVP/CPUSHP are "don't care"s). + * Hit every page until there is a page or less to go. Hit the next page, + * and the one after that if the range hits it. + */ +/* ++roman: A little bit more care is required here: The CINVP instruction + * invalidates cache entries WITHOUT WRITING DIRTY DATA BACK! So the beginning + * and the end of the region must be treated differently if they are not + * exactly at the beginning or end of a page boundary. Else, maybe too much + * data becomes invalidated and thus lost forever. CPUSHP does what we need: + * it invalidates the page after pushing dirty data to memory. (Thanks to Jes + * for discovering the problem!) + */ +/* ... but on the '060, CPUSH doesn't invalidate (for us, since we have set + * the DPI bit in the CACR; would it cause problems with temporarily changing + * this?). So we have to push first and then additionally to invalidate. + */ +void cache_clear (unsigned long paddr, int len) +{ + if (m68k_is040or060) { + /* ++roman: There have been too many problems with the CINV, it seems + * to break the cache maintainance of DMAing drivers. I don't expect + * too much overhead by using CPUSH instead. + */ + while (len > PAGE_SIZE) { + pushcl040(paddr); + len -= PAGE_SIZE; + paddr += PAGE_SIZE; + } + if (len > 0) { + pushcl040(paddr); + if (((paddr + len - 1) ^ paddr) & PAGE_MASK) { + /* a page boundary gets crossed at the end */ + pushcl040(paddr + len - 1); + } + } + } +#if 0 + /* on 68040, invalidate cache lines for pages in the range */ + while (len > PAGE_SIZE) { + clear040(paddr); + len -= PAGE_SIZE; + paddr += PAGE_SIZE; + } + if (len > 0) { + /* 0 < len <= PAGE_SIZE */ + clear040(paddr); + if (((paddr + len - 1) / PAGE_SIZE) != (paddr / PAGE_SIZE)) { + /* a page boundary gets crossed at the end */ + clear040(paddr + len - 1); + } + } +#endif + else /* 68030 or 68020 */ + asm volatile ("movec %/cacr,%/d0\n\t" + "oriw %0,%/d0\n\t" + "movec %/d0,%/cacr" + : : "i" (FLUSH_I_AND_D) + : "d0"); +} + + + +void cache_push (unsigned long paddr, int len) +{ + if (m68k_is040or060) { + /* + * on 68040 or 68060, push cache lines for pages in the range; + * on the '040 this also invalidates the pushed lines, but not on + * the '060! + */ + while (len > PAGE_SIZE) { + push040(paddr); + len -= PAGE_SIZE; + paddr += PAGE_SIZE; + } + if (len > 0) { + push040(paddr); +#if 0 + if (((paddr + len - 1) / PAGE_SIZE) != (paddr / PAGE_SIZE)) { +#endif + if (((paddr + len - 1) ^ paddr) & PAGE_MASK) { + /* a page boundary gets crossed at the end */ + push040(paddr + len - 1); + } + } + } + + + /* + * 68030/68020 have no writeback cache. On the other hand, + * cache_push is actually a superset of cache_clear (the lines + * get written back and invalidated), so we should make sure + * to perform the corresponding actions. After all, this is getting + * called in places where we've just loaded code, or whatever, so + * flushing the icache is appropriate; flushing the dcache shouldn't + * be required. + */ + else /* 68030 or 68020 */ + asm volatile ("movec %/cacr,%/d0\n\t" + "oriw %0,%/d0\n\t" + "movec %/d0,%/cacr" + : : "i" (FLUSH_I) + : "d0"); + } + +void cache_push_v (unsigned long vaddr, int len) +{ + if (m68k_is040or060 == 4) { + /* on 68040, push cache lines for pages in the range */ + while (len > PAGE_SIZE) { + pushv040(vaddr); + len -= PAGE_SIZE; + vaddr += PAGE_SIZE; + } + if (len > 0) { + pushv040(vaddr); +#if 0 + if (((vaddr + len - 1) / PAGE_SIZE) != (vaddr / PAGE_SIZE)) { +#endif + if (((vaddr + len - 1) ^ vaddr) & PAGE_MASK) { + /* a page boundary gets crossed at the end */ + pushv040(vaddr + len - 1); + } + } + } + else if (m68k_is040or060 == 6) { + /* on 68040, push cache lines for pages in the range */ + while (len > PAGE_SIZE) { + pushv060(vaddr); + len -= PAGE_SIZE; + vaddr += PAGE_SIZE; + } + if (len > 0) { + pushv060(vaddr); + if (((vaddr + len - 1) ^ vaddr) & PAGE_MASK) { + /* a page boundary gets crossed at the end */ + pushv060(vaddr + len - 1); + } + } + } + /* 68030/68020 have no writeback cache; still need to clear icache. */ + else /* 68030 or 68020 */ + asm volatile ("movec %/cacr,%/d0\n\t" + "oriw %0,%/d0\n\t" + "movec %/d0,%/cacr" + : : "i" (FLUSH_I) + : "d0"); +} + +#undef clear040 +#undef push040 +#undef pushv040 +#undef pushv060 + +unsigned long mm_phys_to_virt (unsigned long addr) +{ + return PTOV (addr); +} + +int mm_end_of_chunk (unsigned long addr, int len) +{ + int i; + + for (i = 0; i < boot_info.num_memory; i++) + if (boot_info.memory[i].addr + boot_info.memory[i].size + == addr + len) + return 1; + return 0; +} + +/* Map some physical address range into the kernel address space. The + * code is copied and adapted from map_chunk(). + */ + +unsigned long kernel_map(unsigned long paddr, unsigned long size, + int nocacheflag, unsigned long *memavailp ) +{ +#define STEP_SIZE (256*1024) + + static unsigned long vaddr = 0xe0000000; /* safe place */ + unsigned long physaddr, retaddr; + pte_t *ktablep = NULL; + pmd_t *kpointerp; + pgd_t *page_dir; + int pindex; /* index into pointer table */ + int prot; + + /* Round down 'paddr' to 256 KB and adjust size */ + physaddr = paddr & ~(STEP_SIZE-1); + size += paddr - physaddr; + retaddr = vaddr + (paddr - physaddr); + paddr = physaddr; + /* Round up the size to 256 KB. It doesn't hurt if too much is + * mapped... */ + size = (size + STEP_SIZE - 1) & ~(STEP_SIZE-1); + + if (m68k_is040or060) { + prot = _PAGE_PRESENT | _PAGE_GLOBAL040; + switch( nocacheflag ) { + case KERNELMAP_FULL_CACHING: + prot |= _PAGE_CACHE040; + break; + case KERNELMAP_NOCACHE_SER: + default: + prot |= _PAGE_NOCACHE_S; + break; + case KERNELMAP_NOCACHE_NONSER: + prot |= _PAGE_NOCACHE; + break; + case KERNELMAP_NO_COPYBACK: + prot |= _PAGE_CACHE040W; + /* prot |= 0; */ + break; + } + } else + prot = _PAGE_PRESENT | + ((nocacheflag == KERNELMAP_FULL_CACHING || + nocacheflag == KERNELMAP_NO_COPYBACK) ? 0 : _PAGE_NOCACHE030); + + page_dir = pgd_offset_k(vaddr); + if (pgd_present(*page_dir)) { + kpointerp = (pmd_t *)pgd_page(*page_dir); + pindex = (vaddr >> 18) & 0x7f; + if (pindex != 0 && m68k_is040or060) { + if (pmd_present(*kpointerp)) + ktablep = (pte_t *)pmd_page(*kpointerp); + else { + ktablep = kernel_page_table (memavailp); + /* Make entries invalid */ + memset( ktablep, 0, sizeof(long)*PTRS_PER_PTE); + pmd_set(kpointerp,ktablep); + } + ktablep += (pindex & 15)*64; + } + } + else { + /* we need a new pointer table */ + kpointerp = get_kpointer_table (); + pgd_set(page_dir, (pmd_t *)kpointerp); + memset( kpointerp, 0, PTRS_PER_PMD*sizeof(pmd_t)); + pindex = 0; + } + + for (physaddr = paddr; physaddr < paddr + size; vaddr += STEP_SIZE) { + + if (pindex > 127) { + /* we need a new pointer table */ + kpointerp = get_kpointer_table (); + pgd_set(pgd_offset_k(vaddr), (pmd_t *)kpointerp); + memset( kpointerp, 0, PTRS_PER_PMD*sizeof(pmd_t)); + pindex = 0; + } + + if (m68k_is040or060) { + int i; + unsigned long ktable; + + /* + * 68040, use page tables pointed to by the + * kernel pointer table. + */ + + if ((pindex & 15) == 0) { + /* Need new page table every 4M on the '040 */ + ktablep = kernel_page_table (memavailp); + /* Make entries invalid */ + memset( ktablep, 0, sizeof(long)*PTRS_PER_PTE); + } + + ktable = VTOP(ktablep); + + /* + * initialize section of the page table mapping + * this 1M portion. + */ + for (i = 0; i < 64; i++) { + pte_val(*ktablep++) = physaddr | prot; + physaddr += PAGE_SIZE; + } + + /* + * make the kernel pointer table point to the + * kernel page table. + */ + + ((unsigned long *)kpointerp)[pindex++] = ktable | _PAGE_TABLE; + + } else { + /* + * 68030, use early termination page descriptors. + * Each one points to 64 pages (256K). + */ + ((unsigned long *)kpointerp)[pindex++] = physaddr | prot; + physaddr += 64 * PAGE_SIZE; + } + } + + return( retaddr ); +} + + +static inline void set_cmode_pte( pmd_t *pmd, unsigned long address, + unsigned long size, unsigned cmode ) +{ pte_t *pte; + unsigned long end; + + if (pmd_none(*pmd)) + return; + + pte = pte_offset( pmd, address ); + address &= ~PMD_MASK; + end = address + size; + if (end >= PMD_SIZE) + end = PMD_SIZE; + + for( ; address < end; pte++ ) { + pte_val(*pte) = (pte_val(*pte) & ~_PAGE_NOCACHE) | cmode; + address += PAGE_SIZE; + } +} + + +static inline void set_cmode_pmd( pgd_t *dir, unsigned long address, + unsigned long size, unsigned cmode ) +{ + pmd_t *pmd; + unsigned long end; + + if (pgd_none(*dir)) + return; + + pmd = pmd_offset( dir, address ); + address &= ~PGDIR_MASK; + end = address + size; + if (end > PGDIR_SIZE) + end = PGDIR_SIZE; + + if ((pmd_val(*pmd) & _DESCTYPE_MASK) == _PAGE_PRESENT) { + /* 68030 early termination descriptor */ + pmd_val(*pmd) = (pmd_val(*pmd) & ~_PAGE_NOCACHE) | cmode; + return; + } + else { + /* "normal" tables */ + for( ; address < end; pmd++ ) { + set_cmode_pte( pmd, address, end - address, cmode ); + address = (address + PMD_SIZE) & PMD_MASK; + } + } +} + + +/* + * Set new cache mode for some kernel address space. + * The caller must push data for that range itself, if such data may already + * be in the cache. + */ + +void kernel_set_cachemode( unsigned long address, unsigned long size, + unsigned cmode ) +{ + pgd_t *dir = pgd_offset_k( address ); + unsigned long end = address + size; + + if (m68k_is040or060) { + switch( cmode ) { + case KERNELMAP_FULL_CACHING: + cmode = _PAGE_CACHE040; + break; + case KERNELMAP_NOCACHE_SER: + default: + cmode = _PAGE_NOCACHE_S; + break; + case KERNELMAP_NOCACHE_NONSER: + cmode = _PAGE_NOCACHE; + break; + case KERNELMAP_NO_COPYBACK: + cmode = _PAGE_CACHE040W; + break; + } + } else + cmode = ((cmode == KERNELMAP_FULL_CACHING || + cmode == KERNELMAP_NO_COPYBACK) ? + 0 : _PAGE_NOCACHE030); + + for( ; address < end; dir++ ) { + set_cmode_pmd( dir, address, end - address, cmode ); + address = (address + PGDIR_SIZE) & PGDIR_MASK; + } + flush_tlb_all(); +} + + diff -u --recursive --new-file v1.3.93/linux/arch/sparc/kernel/devices.c linux/arch/sparc/kernel/devices.c --- v1.3.93/linux/arch/sparc/kernel/devices.c Sun Apr 21 19:21:59 1996 +++ linux/arch/sparc/kernel/devices.c Mon Apr 22 10:59:39 1996 @@ -5,11 +5,12 @@ */ #include +#include #include #include #include -#include +#include #include struct prom_cpuinfo linux_cpus[NCPUS]; diff -u --recursive --new-file v1.3.93/linux/arch/sparc/kernel/probe.c linux/arch/sparc/kernel/probe.c --- v1.3.93/linux/arch/sparc/kernel/probe.c Sun Apr 21 19:22:00 1996 +++ linux/arch/sparc/kernel/probe.c Thu Jan 1 02:00:00 1970 @@ -1,464 +0,0 @@ -/* $Id: probe.c,v 1.42 1995/12/26 01:38:08 davem Exp $ - * probe.c: Preliminary device tree probing routines... - * - * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) - */ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* #define DEBUG_PROBING */ - -/* XXX Grrr, this stuff should have it's own file, only generic stuff goes - * XXX here. Possibly clock.c and timer.c? This file should get smaller - * XXX and smaller as time goes on... - */ -enum sparc_clock_type sp_clock_typ; -struct mostek48t02 *mstk48t02_regs = 0; -struct mostek48t08 *mstk48t08_regs = 0; -volatile unsigned int *master_l10_limit = 0; -volatile unsigned int *master_l10_counter = 0; -struct sun4m_timer_regs *sun4m_timers; - -static char node_str[128]; - -/* Cpu-type information and manufacturer strings */ - -struct cpu_iu_info { - int psr_impl; - int psr_vers; - char* cpu_name; /* should be enough I hope... */ -}; - -struct cpu_fp_info { - int psr_impl; - int fp_vers; - char* fp_name; -}; - -/* In order to get the fpu type correct, you need to take the IDPROM's - * machine type value into consideration too. I will fix this. - */ -struct cpu_fp_info linux_sparc_fpu[] = { - { 0, 0, "Fujitsu MB86910 or Weitek WTL1164/5"}, - { 0, 1, "Fujitsu MB86911 or Weitek WTL1164/5 or LSI L64831"}, - { 0, 2, "LSI Logic L64802 or Texas Instruments ACT8847"}, - /* SparcStation SLC, SparcStation1 */ - { 0, 3, "Weitek WTL3170/2"}, - /* SPARCstation-5 */ - { 0, 4, "Lsi Logic/Meiko L64804 or compatible"}, - { 0, 5, "reserved"}, - { 0, 6, "reserved"}, - { 0, 7, "No FPU"}, - { 1, 0, "ROSS HyperSparc combined IU/FPU"}, - { 1, 1, "Lsi Logic L64814"}, - { 1, 2, "Texas Instruments TMS390-C602A"}, - { 1, 3, "Cypress CY7C602 FPU"}, - { 1, 4, "reserved"}, - { 1, 5, "reserved"}, - { 1, 6, "reserved"}, - { 1, 7, "No FPU"}, - { 2, 0, "BIT B5010 or B5110/20 or B5210"}, - { 2, 1, "reserved"}, - { 2, 2, "reserved"}, - { 2, 3, "reserved"}, - { 2, 4, "reserved"}, - { 2, 5, "reserved"}, - { 2, 6, "reserved"}, - { 2, 7, "No FPU"}, - /* SuperSparc 50 module */ - { 4, 0, "SuperSparc on-chip FPU"}, - /* SparcClassic */ - { 4, 4, "TI MicroSparc on chip FPU"}, - { 5, 0, "Matsushita MN10501"}, - { 5, 1, "reserved"}, - { 5, 2, "reserved"}, - { 5, 3, "reserved"}, - { 5, 4, "reserved"}, - { 5, 5, "reserved"}, - { 5, 6, "reserved"}, - { 5, 7, "No FPU"}, -}; - -#define NSPARCFPU (sizeof(linux_sparc_fpu)/sizeof(struct cpu_fp_info)) - -struct cpu_iu_info linux_sparc_chips[] = { - /* Sun4/100, 4/200, SLC */ - { 0, 0, "Fujitsu MB86900/1A or LSI L64831 SparcKIT-40"}, - /* borned STP1012PGA */ - { 0, 4, "Fujitsu MB86904"}, - /* SparcStation2, SparcServer 490 & 690 */ - { 1, 0, "LSI Logic Corporation - L64811"}, - /* SparcStation2 */ - { 1, 1, "Cypress/ROSS CY7C601"}, - /* Embedded controller */ - { 1, 3, "Cypress/ROSS CY7C611"}, - /* Ross Technologies HyperSparc */ - { 1, 0xf, "ROSS HyperSparc RT620"}, - { 1, 0xe, "ROSS HyperSparc RT625"}, - /* ECL Implementation, CRAY S-MP Supercomputer... AIEEE! */ - /* Someone please write the code to support this beast! ;) */ - { 2, 0, "Bipolar Integrated Technology - B5010"}, - { 3, 0, "LSI Logic Corporation - unknown-type"}, - { 4, 0, "Texas Instruments, Inc. - SuperSparc 50"}, - /* SparcClassic -- borned STP1010TAB-50*/ - { 4, 1, "Texas Instruments, Inc. - MicroSparc"}, - { 4, 2, "Texas Instruments, Inc. - MicroSparc II"}, - { 4, 3, "Texas Instruments, Inc. - SuperSparc 51"}, - { 4, 4, "Texas Instruments, Inc. - SuperSparc 61"}, - { 4, 5, "Texas Instruments, Inc. - unknown"}, - { 5, 0, "Matsushita - MN10501"}, - { 6, 0, "Philips Corporation - unknown"}, - { 7, 0, "Harvest VLSI Design Center, Inc. - unknown"}, - /* Gallium arsenide 200MHz, BOOOOGOOOOMIPS!!! */ - { 8, 0, "Systems and Processes Engineering Corporation (SPEC)"}, - { 9, 0, "Fujitsu #3"}, - { 0xa, 0, "UNKNOWN CPU-VENDOR/TYPE"}, - { 0xb, 0, "UNKNOWN CPU-VENDOR/TYPE"}, - { 0xc, 0, "UNKNOWN CPU-VENDOR/TYPE"}, - { 0xd, 0, "UNKNOWN CPU-VENDOR/TYPE"}, - { 0xe, 0, "UNKNOWN CPU-VENDOR/TYPE"}, - { 0xf, 0, "UNKNOWN CPU-VENDOR/TYPE"}, -}; - -#define NSPARCCHIPS (sizeof(linux_sparc_chips)/sizeof(struct cpu_iu_info)) - -char *sparc_cpu_type[NCPUS] = { "cpu-oops", "cpu-oops1", "cpu-oops2", "cpu-oops3" }; -char *sparc_fpu_type[NCPUS] = { "fpu-oops", "fpu-oops1", "fpu-oops2", "fpu-oops3" }; - -static inline int find_mmu_num_contexts(int cpu) -{ - return prom_getintdefault(cpu, "mmu-nctx", 0x8); -} - -unsigned int fsr_storage; - -void -probe_cpu(void) -{ - int psr_impl, psr_vers, fpu_vers; - int i, cpuid; - - cpuid = get_cpuid(); - - psr_impl = ((get_psr()>>28)&0xf); - psr_vers = ((get_psr()>>24)&0xf); - - fpu_vers = ((get_fsr()>>17)&0x7); - - for(i = 0; iregs; - break; - } - - node = prom_getsibling(node); - if(node == 0) { - printk("Aieee, could not find timer chip type\n"); - return; - } - } - - if(sparc_cpu_model == sun4c) { - /* Map the Timer chip, this is implemented in hardware inside - * the cache chip on the sun4c. - */ - sparc_alloc_io ((void *) SUN4C_TIMER_PHYSADDR, (void *) TIMER_VADDR, - sizeof (*SUN4C_TIMER_STRUCT), "timer", 0x0, 0x0); - - /* Have the level 10 timer tick at 100HZ. We don't touch the - * level 14 timer limit since we are letting the prom handle - * them until we have a real console driver so L1-A works. - */ - SUN4C_TIMER_STRUCT->timer_limit10 = (((1000000/HZ) + 1) << 10); - master_l10_limit = &(SUN4C_TIMER_STRUCT->timer_limit10); - master_l10_counter = &(SUN4C_TIMER_STRUCT->cur_count10); - } else { - int reg_count; - struct linux_prom_registers cnt_regs[PROMREG_MAX]; - int obio_node, cnt_node; - - cnt_node = 0; - if((obio_node = - prom_searchsiblings (prom_getchild(prom_root_node), "obio")) == 0 || - (obio_node = prom_getchild (obio_node)) == 0 || - (cnt_node = prom_searchsiblings (obio_node, "counter")) == 0) { - printk ("Cannot find /obio/counter node\n"); - prom_halt (); - } - reg_count = prom_getproperty(cnt_node, "reg", - (void *) cnt_regs, sizeof(cnt_regs)); - reg_count = (reg_count/sizeof(struct linux_prom_registers)); - - /* Apply the obio ranges to the timer registers. */ - prom_apply_obio_ranges(cnt_regs, reg_count); - - /* Map the per-cpu Counter registers. */ - sparc_alloc_io(cnt_regs[0].phys_addr, (void *) TIMER_VADDR, - PAGE_SIZE*NCPUS, "counters_percpu", - cnt_regs[0].which_io, 0x0); - - /* Map the system Counter register. */ - sparc_alloc_io(cnt_regs[reg_count-1].phys_addr, - (void *) TIMER_VADDR+(NCPUS*PAGE_SIZE), - cnt_regs[reg_count-1].reg_size, - "counters_system", cnt_regs[reg_count-1].which_io, 0x0); - sun4m_timers = (struct sun4m_timer_regs *) TIMER_VADDR; - - /* Avoid interrupt bombs... */ - foo_limit = (volatile) sun4m_timers->l10_timer_limit; - - /* Must set the master pointer first or we will lose badly. */ - master_l10_limit = - &(((struct sun4m_timer_regs *)TIMER_VADDR)->l10_timer_limit); - master_l10_counter = - &(((struct sun4m_timer_regs *)TIMER_VADDR)->l10_cur_count); - - ((struct sun4m_timer_regs *)TIMER_VADDR)->l10_timer_limit = - (((1000000/HZ) + 1) << 10); - } -} - -/* Probe and map in the Auxiliaary I/O register */ -void -probe_auxio(void) -{ - int node, auxio_nd; - struct linux_prom_registers auxregs[1]; - - node = prom_getchild(prom_root_node); - auxio_nd = prom_searchsiblings(node, "auxiliary-io"); - if(!auxio_nd) { - node = prom_searchsiblings(node, "obio"); - node = prom_getchild(node); - auxio_nd = prom_searchsiblings(node, "auxio"); - if(!auxio_nd) { - printk("Cannot find auxio node, cannot continue...\n"); - prom_halt(); - } - } - prom_getproperty(auxio_nd, "reg", (char *) auxregs, sizeof(auxregs)); - prom_apply_obio_ranges(auxregs, 0x1); - /* Map the register both read and write */ - sparc_alloc_io(auxregs[0].phys_addr, (void *) AUXIO_VADDR, - auxregs[0].reg_size, "auxilliaryIO", auxregs[0].which_io, 0x0); -} - -extern unsigned long probe_memory(void); -extern struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS]; -unsigned int phys_bytes_of_ram, end_of_phys_memory; -extern void probe_mbus(void); - -/* #define DEBUG_PROBE_DEVICES */ -struct prom_cpuinfo linux_cpus[NCPUS]; -int linux_num_cpus; - -unsigned long -probe_devices(unsigned long mem_start) -{ - int nd, i, prom_node_cpu, thismid; - int cpu_nds[NCPUS]; /* One node for each cpu */ - int cpu_ctr = 0; - - prom_getstring(prom_root_node, "device_type", node_str, sizeof(node_str)); - if(strcmp(node_str, "cpu") == 0) { - cpu_nds[0] = prom_root_node; - cpu_ctr++; - } else { - int scan; - scan = prom_getchild(prom_root_node); - nd = 0; - while((scan = prom_getsibling(scan)) != 0) { - prom_getstring(scan, "device_type", node_str, sizeof(node_str)); - if(strcmp(node_str, "cpu") == 0) { - cpu_nds[cpu_ctr] = scan; - linux_cpus[cpu_ctr].prom_node = scan; - prom_getproperty(scan, "mid", (char *) &thismid, sizeof(thismid)); - linux_cpus[cpu_ctr].mid = thismid; - cpu_ctr++; - } - }; - if(cpu_ctr == 0) { - printk("No CPU nodes found, cannot continue.\n"); - /* Probably a sun4d or sun4e, Sun is trying to trick us ;-) */ - halt(); - } - printk("Found %d CPU prom device tree node(s).\n", cpu_ctr); - }; - prom_node_cpu = cpu_nds[0]; - - linux_num_cpus = cpu_ctr; - for(i=0; i - -#include -#include -#include -#include -#include -#include -#include -#include - -/* #define DEBUG_MBUS */ - -unsigned int viking_rev, swift_rev, cypress_rev; -enum mbus_module srmmu_modtype; -unsigned int hwbug_bitmask; - -void -probe_mbus(void) -{ - register unsigned int mreg, vaddr; - register int impl, vers, syscntrl, pso, resv, nofault, enable; - register int mod_typ, mod_rev; - - srmmu_modtype = SRMMU_INVAL_MOD; - hwbug_bitmask = 0; - vaddr = 0; - - mreg = srmmu_get_mmureg(); - impl = (mreg & SRMMU_CTREG_IMPL_MASK) >> SRMMU_CTREG_IMPL_SHIFT; - vers = (mreg & SRMMU_CTREG_VERS_MASK) >> SRMMU_CTREG_VERS_SHIFT; - syscntrl = (mreg & SRMMU_CTREG_SYSCNTRL_MASK) >> SRMMU_CTREG_SYSCNTRL_SHIFT; - pso = (mreg & SRMMU_CTREG_PSO_MASK) >> SRMMU_CTREG_PSO_SHIFT; - resv = (mreg & SRMMU_CTREG_RESV_MASK) >> SRMMU_CTREG_RESV_SHIFT; - nofault = (mreg & SRMMU_CTREG_NOFAULT_MASK) >> SRMMU_CTREG_NOFAULT_SHIFT; - enable = (mreg & SRMMU_CTREG_ENABLE_MASK) >> SRMMU_CTREG_ENABLE_SHIFT; - -#ifdef DEBUG_MBUS - printk("MMU REGISTER\n"); - printk("IMPL<%01x> VERS<%01x> SYSCNTRL<%04x> PSO<%d> RESV<%02x> NOFAULT<%d> ENABLE<%d>\n", - impl, vers, syscntrl, (int) pso, resv, (int) nofault, (int) enable); -#endif - - mod_typ = impl; mod_rev = vers; - printk("MBUS: "); - - if(mod_typ == 0x1) /* Ross HyperSparc or Cypress */ - if (mod_rev == 0x7) { - srmmu_modtype = HyperSparc; - hwbug_bitmask |= HWBUG_VACFLUSH_BITROT; - /* Turn off Cache Wrapping and copyback caching, I don't - * understand them completely yet... */ - printk("Enabling HyperSparc features...\n"); - /* FUCK IT, I wanna see this baby chug! */ - /* First, flush the cache */ -#if 0 - for(vaddr = 0; vaddr != vac_size; vaddr+=vac_linesize) - flush_ei_ctx(vaddr); -#endif - mreg &= (~HYPERSPARC_CWENABLE); - mreg &= (~HYPERSPARC_CMODE); - mreg &= (~HYPERSPARC_WBENABLE); - mreg |= (HYPERSPARC_CENABLE); - srmmu_set_mmureg(mreg); - /* Clear all the cache tags */ -#if 0 - for(vaddr = 0; vaddr != vac_size; vaddr+=vac_linesize) - __asm__ __volatile__("sta %%g0, [%0] %1" : : - "r" (vaddr), "i" (0xe)); -#endif - /* Flush the ICACHE */ - flush_whole_icache(); - - } else { - cypress_rev = mod_rev; - if(mod_rev == 0xe) { - srmmu_modtype = Cypress_vE; - hwbug_bitmask |= HWBUG_COPYBACK_BROKEN; - } else - if(mod_rev == 0xd) { - srmmu_modtype = Cypress_vD; - hwbug_bitmask |= HWBUG_ASIFLUSH_BROKEN; - } else - srmmu_modtype = Cypress; - - /* It is a Cypress module */ - printk("ROSS Cypress Module %s\n", - (srmmu_modtype == Cypress_vE ? "Rev. E" : - (srmmu_modtype == Cypress_vD ? "Rev. D" : - ""))); - /* Enable Cypress features */ - printk("Enabling Cypress features...\n"); - mreg &= (~CYPRESS_CMODE); - mreg |= (CYPRESS_CENABLE); - srmmu_set_mmureg(mreg); - /* Maybe play with Cypress 604/605 cache stuff here? */ - } - - - if(((get_psr()>>0x18)&0xff)==0x04) { - __asm__ __volatile__("lda [%1] %2, %0\n\t" - "srl %0, 0x18, %0\n\t" : - "=r" (swift_rev) : - "r" (0x10003000), "i" (0x20)); - printk("Fujitsu MB86904 or higher Swift module\n"); /* MB86905 etc. */ - switch(swift_rev) { - case 0x11: - case 0x20: - case 0x23: - case 0x30: - srmmu_modtype = Swift_lots_o_bugs; - hwbug_bitmask |= HWBUG_KERN_ACCBROKEN; - hwbug_bitmask |= HWBUG_KERN_CBITBROKEN; - printk("Detected Swift with Lots 'o' Bugs\n"); - break; - case 0x25: - case 0x31: - srmmu_modtype = Swift_bad_c; - hwbug_bitmask |= HWBUG_KERN_CBITBROKEN; - printk("Detected Swift with kernel pte C bit bug\n"); - break; - default: - srmmu_modtype = Swift_ok; - printk("Detected Swift with no bugs...\n"); - break; - } - /* Enable Fujitsu Swift specific features here... */ - printk("Enabling Swift features...\n"); - mreg |= 0; - srmmu_set_mmureg(mreg); - } - - if((((get_psr()>>0x18)&0xff)==0x40 || - (((get_psr()>>0x18)&0xff)==0x41 && mod_typ==0 && mod_rev==0))) { - if(((get_psr()>>0x18)&0xf)==0 && mod_rev==0) { - srmmu_modtype = Viking_12; - hwbug_bitmask |= HWBUG_MODIFIED_BITROT; - hwbug_bitmask |= HWBUG_PC_BADFAULT_ADDR; - } else { - if(((get_psr()>>0x18)&0xf)!=0) { - srmmu_modtype = Viking_2x; - hwbug_bitmask |= HWBUG_PC_BADFAULT_ADDR; - } else - if(mod_rev==1) { - srmmu_modtype = Viking_30; - hwbug_bitmask |= HWBUG_PACINIT_BITROT; - } else { - if (mod_rev<8) - srmmu_modtype = Viking_35; - else - srmmu_modtype = Viking_new; - } - } - - /* SPARCclassic's STP1010 may be produced under other name */ - printk("VIKING Module\n"); - printk("Enabling Viking features...\n"); - mreg |= (VIKING_DCENABLE | VIKING_ICENABLE | VIKING_SBENABLE | - VIKING_TCENABLE | VIKING_DPENABLE); - srmmu_set_mmureg(mreg); - } - - if((((get_psr()>>0x18)&0xff)==0x41) && (mod_typ || mod_rev)) { - srmmu_modtype = Tsunami; - printk("Tsunami module\n"); - /* Enable Tsunami features */ - } - - if(srmmu_modtype == SRMMU_INVAL_MOD) { - printk("Unknown SRMMU module type!\n"); - printk("MMU_CREG: impl=%x vers=%x\n", mod_typ, mod_rev); - printk("PSR: impl=%x vers=%x\n", ((get_psr()>>28)&0xf), - ((get_psr()>>24)&0xf)); - panic("probe_mbus()"); - } - - /* AIEEE, should get this from the prom... */ - printk("Boot processor ID %d Module ID %d (%s MBUS)\n", - get_cpuid(), get_modid(), (get_modid() == 0x8 ? "Level 1" : "Level 2")); -} diff -u --recursive --new-file v1.3.93/linux/arch/sparc/mm/srmmu_mp.S linux/arch/sparc/mm/srmmu_mp.S --- v1.3.93/linux/arch/sparc/mm/srmmu_mp.S Sun Apr 21 19:22:01 1996 +++ linux/arch/sparc/mm/srmmu_mp.S Thu Jan 1 02:00:00 1970 @@ -1,52 +0,0 @@ -/* srmmu_mp.S: Low level invalidates for MP SRMMU modules. - * - * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) - */ -#include -#include - - /* Protocol is: - * - * %l0 --> %l3 NO TOUCH - * %l7 NO TOUCH - * %l6 return address - 0x8 - * %l4, %l5 what we can use - */ - - .globl C_LABEL(hyper_invalidate_low) -C_LABEL(hyper_invalidate_low): - /* First the on-chip cache. */ - set C_LABEL(hyper_cache_size), %l5 - ld [%l5], %l5 -1: - subcc %l5, 32, %l5 - bne 1b - sta %g0, [%l5] ASI_M_FLUSH_CTX - - /* Now the on-chip ICACHE. */ - sta %g0, [%g0] ASI_M_FLUSH_IWHOLE - - /* Flush the TLB and return. */ - mov 0x400, %l4 - sta %g0, [%l4] ASI_M_FLUSH_PROBE - - jmpl %l6 + 0x8, %g0 - nop - - .globl C_LABEL(viking_invalidate_low) -C_LABEL(viking_invalidate_low): - /* Flash clear the I/D caches. */ - sta %g0, [%g0] ASI_M_IC_FLCLEAR - sta %g0, [%g0] ASI_M_DC_FLCLEAR - - /* Flush the TLB and return. */ - mov 0x400, %l4 - sta %g0, [%l4] ASI_M_FLUSH_PROBE - - jmpl %l6 + 0x8, %g0 - nop - - /* XXX Write the Cypress when I get access to - * XXX some modules, poke mossip real hard until - * XXX he takes care of the Nubis upgrade. - */ diff -u --recursive --new-file v1.3.93/linux/drivers/Makefile linux/drivers/Makefile --- v1.3.93/linux/drivers/Makefile Mon Feb 26 11:58:04 1996 +++ linux/drivers/Makefile Mon Apr 22 10:59:39 1996 @@ -9,12 +9,16 @@ SUB_DIRS := block char net #streams MOD_SUB_DIRS := $(SUB_DIRS) -ALL_SUB_DIRS := $(SUB_DIRS) pci scsi sound cdrom isdn +ALL_SUB_DIRS := $(SUB_DIRS) pci sbus scsi sound cdrom isdn ifdef CONFIG_PCI SUB_DIRS += pci endif +ifdef CONFIG_SBUS +SUB_DIRS += sbus +endif + # If CONFIG_SCSI is set, the core of scsi support will be added to the kernel, # but some of the low-level things may also be modules. ifeq ($(CONFIG_SCSI),y) @@ -46,6 +50,11 @@ ifeq ($(CONFIG_ISDN),m) MOD_SUB_DIRS += isdn endif +endif + +ifeq ($(CONFIG_AP1000),y) +SUB_DIRS += ap1000 +ALL_SUB_DIRS += ap1000 endif include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.93/linux/drivers/block/amiflop.c linux/drivers/block/amiflop.c --- v1.3.93/linux/drivers/block/amiflop.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/block/amiflop.c Sat Mar 30 14:11:12 1996 @@ -0,0 +1,1782 @@ +/* + * linux/amiga/amiflop.c + * + * Copyright (C) 1993 Greg Harp + * Portions of this driver are based on code contributed by Brad Pepers + * + * revised 28.5.95 by Joerg Dorchain + * - now no bugs(?) any more for both HD & DD + * - added support for 40 Track 5.25" drives, 80-track hopefully behaves + * like 3.5" dd (no way to test - are there any 5.25" drives out there + * that work on an A4000?) + * - wrote formatting routine (maybe dirty, but works) + * + * june/july 1995 added ms-dos support by Joerg Dorchain + * (portions based on messydos.device and various contributors) + * - currently only 9 and 18 sector disks + * + * - fixed a bug with the internal trackbuffer when using multiple + * disks the same time + * - made formatting a bit safer + * - added command line and machine based default for "silent" df0 + * + * december 1995 adapted for 1.2.13pl4 by Joerg Dorchain + * - works but I think its inefficient. (look in redo_fd_request) + * But the changes were very efficient. (only three and a half lines) + * + * january 1995 added special ioctl for tracking down read/write problems + * - usage ioctl(d, RAW_TRACK, ptr); the raw track buffer (MFM-encoded data + * is copied to area. (area should be large enough since no checking is + * done - 30K is currently sufficient). return the actual size of the + * trackbuffer + * - replaced udelays() by a timer (CIAA timer B) for the waits + * needed for the disk mechanic. + * + * revised Marts 3rd, 1996 by Jes Sorensen for use in the 1.3.28 kernel. + * - Minor changes to accept the kdev_t. + * - Replaced some more udelays with ms_delays. Udelay is just a loop, + * and so the delay will be different depending on the given + * processor :-( + * - The driver could use a major cleanup because of the new + * major/minor handling that came with kdev_t. It seems to work for + * the time being, but I can't guarantee that it will stay like + * that when we start using 16 (24?) bit minors. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define MAJOR_NR FLOPPY_MAJOR +#include + +#undef DEBUG /* print _LOTS_ of infos */ + +#define RAW_IOCTL +#ifdef RAW_IOCTL +#define IOCTL_RAW_TRACK 0x5254524B /* 'RTRK' */ +#endif + +/* prototypes */ + +static int amiga_read(int,unsigned char *, unsigned long, int); +static void amiga_write(int, unsigned long, unsigned char *, int); +static int dos_read(int, unsigned char *, unsigned long, int); +static void dos_write(int, unsigned long, unsigned char *,int); +static ushort dos_crc(void *, int, int, int); +static void fd_probe(int); + + +/* + * Defines + */ +#define MAX_SECTORS 22 + +/* + * Error codes + */ +#define FD_OK 0 /* operation succeeded */ +#define FD_ERROR -1 /* general error (seek, read, write, etc) */ +#define FD_NOUNIT 1 /* unit does not exist */ +#define FD_UNITBUSY 2 /* unit already active */ +#define FD_NOTACTIVE 3 /* unit is not active */ +#define FD_NOTREADY 4 /* unit is not ready (motor not on/no disk) */ + +/* + * Floppy ID values + */ +#define FD_NODRIVE 0x00000000 /* response when no unit is present */ +#define FD_DD_3 0xffffffff /* double-density 3.5" (880K) drive */ +#define FD_HD_3 0x55555555 /* high-density 3.5" (1760K) drive */ +#define FD_DD_5 0xaaaaaaaa /* double-density 5.25" (440K) drive */ + +static int fd_def_df0 = 0; /* default for df0 if it doesn't identify */ + + +/* + * Macros + */ +#define MOTOR_ON (ciab.prb &= ~DSKMOTOR) +#define MOTOR_OFF (ciab.prb |= DSKMOTOR) +#define SELECT(mask) (ciab.prb &= ~mask) +#define DESELECT(mask) (ciab.prb |= mask) +#define SELMASK(drive) (1 << (3 + (drive & 3))) + +#define DRIVE(x) ((x) & 3) +#define PROBE(x) ((x) >> 2) & 1) +#define TYPE(x) ((x) >> 3) & 2) +#define DATA(x) ((x) >> 5) & 3) + +static struct fd_drive_type drive_types[] = { +/* code name tr he rdsz wrsz sm pc1 pc2 sd st st*/ +/* warning: times are now in milliseconds (ms) */ + { FD_DD_3, "DD 3.5", 160, 2, 14716, 13630, 1, 80,161, 3, 18, 1}, + { FD_HD_3, "HD 3.5", 160, 2, 28344, 27258, 2, 80,161, 3, 18, 1}, + { FD_DD_5, "DD 5.25", 80, 2, 14716, 13630, 1, 40, 81, 6, 30, 2}, + { FD_NODRIVE, "No Drive", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +}; +static int num_dr_types = sizeof(drive_types) / sizeof(drive_types[0]); + +/* defaults for 3 1/2" HD-Disks */ +static int floppy_sizes[256]={880,880,880,880,720,720,720,}; +static int floppy_blocksizes[256]={0,}; +/* hardsector size assumed to be 512 */ + +static struct fd_data_type data_types[] = { + { "Amiga", 11 , amiga_read, amiga_write}, + { "MS-Dos", 9, dos_read, dos_write} +}; +static int num_da_types = sizeof(data_types) / sizeof(data_types[0]); + +/* current info on each unit */ +static struct amiga_floppy_struct unit[FD_MAX_UNITS]; + +static struct timer_list flush_track_timer; +static struct timer_list post_write_timer; +static struct timer_list motor_on_timer; +static struct timer_list motor_off_timer[FD_MAX_UNITS]; +static int on_attempts; + +/* track buffer */ +static int lastdrive = -1; +static int savedtrack = -1; +static int writepending = 0; +static int writefromint = 0; +static unsigned char trackdata[MAX_SECTORS * 512]; +static char *raw_buf; + +#define RAW_BUF_SIZE 30000 /* size of raw disk data */ + +/* + * These are global variables, as that's the easiest way to give + * information to interrupts. They are the data used for the current + * request. + */ +static char block_flag = 0; +static int selected = 0; +static struct wait_queue *wait_fd_block = NULL; + +/* Synchronization of FDC access. */ +static volatile int fdc_busy = 0; +static struct wait_queue *fdc_wait = NULL; +static struct wait_queue *motor_wait = NULL; + +/* MS-Dos MFM Coding tables (should go quick and easy) */ +static unsigned char mfmencode[16]={ + 0x2a, 0x29, 0x24, 0x25, 0x12, 0x11, 0x14, 0x15, + 0x4a, 0x49, 0x44, 0x45, 0x52, 0x51, 0x54, 0x55 +}; +static unsigned char mfmdecode[128]; + +/* floppy internal millisecond timer stuff */ +static struct semaphore ms_sem = MUTEX; +static struct wait_queue *ms_wait = NULL; +#define MS_TICKS ((amiga_eclock+50)/1000) + +static void ms_isr(int irq, struct pt_regs *fp, void *dummy) +{ +wake_up(&ms_wait); +} + +/* with the semaphore waits are queued up + A more generic routine would do a schedule a la timer.device */ +static void ms_delay(int ms) +{ + int ticks; + if (ms > 0) { + down(&ms_sem); + ticks=MS_TICKS*ms-1; + ciaa.tblo=ticks%256; + ciaa.tbhi=ticks/256; + ciaa.crb=0x19; /* count clock, force load, one-shot, start */ + sleep_on(&ms_wait); + up(&ms_sem); + } +} + +/* + * Functions + */ +/*====================================================================== + Turn off the motor of the given drive. Unit must already be active. + Returns standard floppy error code. +======================================================================*/ +static void fd_motor_off(unsigned long drive) +{ + unsigned long flags; + unsigned char prb = ~0; + + drive&=3; + save_flags(flags); + cli(); + + if (unit[drive].track % 2 != 0) + prb &= ~DSKSIDE; + ciab.prb |= (SELMASK(0)|SELMASK(1)|SELMASK(2)|SELMASK(3)); + ciab.prb = prb; + prb &= ~SELMASK(drive); + ciab.prb = prb; + udelay (1); + prb |= (SELMASK(0)|SELMASK(1)|SELMASK(2)|SELMASK(3)); + ciab.prb = prb; + selected = -1; + unit[drive].motor = 0; + + restore_flags(flags); +} + +static void motor_on_callback(unsigned long nr) +{ + nr &= 3; + + if (!(ciaa.pra & DSKRDY) || --on_attempts == 0) { + unit[nr].motor = 1; + wake_up (&motor_wait); + } else { + motor_on_timer.expires = jiffies + HZ/10; + add_timer(&motor_on_timer); + } +} + +static int motor_on(int nr) +{ + unsigned long flags; + unsigned char prb = ~0; + + nr &= 3; + save_flags (flags); + cli(); + del_timer(motor_off_timer + nr); + + if (!unit[nr].motor) { + del_timer(&motor_on_timer); + motor_on_timer.data = nr; + motor_on_timer.expires = jiffies + HZ/2; + add_timer(&motor_on_timer); + on_attempts = 10; + + + prb &= ~DSKMOTOR; + if (unit[nr].track % 2 != 0) + prb &= ~DSKSIDE; + ciab.prb |= (SELMASK(0)|SELMASK(1)|SELMASK(2)|SELMASK(3)); + ciab.prb = prb; + prb &= ~SELMASK(nr); + ciab.prb = prb; + selected = nr; + + while (!unit[nr].motor) + sleep_on (&motor_wait); + } + restore_flags(flags); + + if (on_attempts == 0) { + printk ("motor_on failed, turning motor off\n"); + fd_motor_off (nr); + return 0; + } + + return 1; +} + +static void floppy_off (unsigned int nr) +{ + nr&=3; + del_timer(motor_off_timer+nr); + motor_off_timer[nr].expires = jiffies + 3*HZ; + add_timer(motor_off_timer+nr); +} + +static void fd_select (int drive) +{ + unsigned char prb = ~0; + + drive&=3; + if (drive == selected) + return; + selected = drive; + + if (unit[drive].track % 2 != 0) + prb &= ~DSKSIDE; + if (unit[drive].motor == 1) + prb &= ~DSKMOTOR; + ciab.prb |= (SELMASK(0)|SELMASK(1)|SELMASK(2)|SELMASK(3)); + ciab.prb = prb; + prb &= ~SELMASK(drive); + ciab.prb = prb; +} + +static void fd_deselect (int drive) +{ + unsigned char prb; + unsigned long flags; + + drive&=3; + if (drive != selected) + return; + + save_flags (flags); + sti(); + + selected = -1; + + prb = ciab.prb; + prb |= (SELMASK(0)|SELMASK(1)|SELMASK(2)|SELMASK(3)); + ciab.prb = prb; + + restore_flags (flags); + +} + +/*====================================================================== + Seek the drive to track 0. + The drive must be active and the motor must be running. + Returns standard floppy error code. +======================================================================*/ +static int fd_calibrate(int drive) +{ + unsigned char prb; + int n; + + drive &= 3; + if (!motor_on (drive)) + return 0; + fd_select (drive); + prb = ciab.prb; + prb |= DSKSIDE; + prb &= ~DSKDIREC; + ciab.prb = prb; + for (n = unit[drive].type->tracks/4; n != 0; --n) { + if (ciaa.pra & DSKTRACK0) + break; + prb &= ~DSKSTEP; + ciab.prb = prb; + prb |= DSKSTEP; + ms_delay (2); + ciab.prb = prb; + ms_delay(unit[drive].type->step_delay); + } + ms_delay (unit[drive].type->settle_time); + prb |= DSKDIREC; + n = unit[drive].type->tracks/2 + 20; + for (;;) { + prb &= ~DSKSTEP; + ciab.prb = prb; + prb |= DSKSTEP; + ms_delay (2); + ciab.prb = prb; + ms_delay(unit[drive].type->step_delay + 1); + if ((ciaa.pra & DSKTRACK0) == 0) + break; + if (--n == 0) { + printk ("calibrate failed, turning motor off\n"); + fd_motor_off (drive); + unit[drive].track = -1; + return 0; + } + } + unit[drive].track = 0; + ms_delay(unit[drive].type->settle_time); + + return 1; +} + +/*====================================================================== + Seek the drive to the requested cylinder. + The drive must have been calibrated at some point before this. + The drive must also be active and the motor must be running. +======================================================================*/ +static int fd_seek(int drive, int track) +{ + unsigned char prb; + int cnt; + + drive &= 3; + if (unit[drive].track == track) + return 1; + if (!motor_on(drive)) + return 0; + fd_select (drive); + if (unit[drive].track < 0 && !fd_calibrate(drive)) + return 0; + + cnt = unit[drive].track/2 - track/2; + prb = ciab.prb; + prb |= DSKSIDE | DSKDIREC; + if (track % 2 != 0) + prb &= ~DSKSIDE; + if (cnt < 0) { + cnt = - cnt; + prb &= ~DSKDIREC; + } + ciab.prb = prb; + if (track % 2 != unit[drive].track % 2) + ms_delay (unit[drive].type->side_time); + unit[drive].track = track; + if (cnt == 0) + return 1; + do { + prb &= ~DSKSTEP; + ciab.prb = prb; + prb |= DSKSTEP; + ms_delay (1); + ciab.prb = prb; + ms_delay (unit[drive].type->step_delay); + } while (--cnt != 0); + ms_delay (unit[drive].type->settle_time); + + return 1; +} + +static void encode(unsigned long data, unsigned long *dest) +{ + unsigned long data2; + + data &= 0x55555555; + data2 = data ^ 0x55555555; + data |= ((data2 >> 1) | 0x80000000) & (data2 << 1); + + if (*(dest - 1) & 0x00000001) + data &= 0x7FFFFFFF; + + *dest = data; +} + +static void encode_block(unsigned long *dest, unsigned long *src, int len) +{ + int cnt, to_cnt = 0; + unsigned long data; + + /* odd bits */ + for (cnt = 0; cnt < len / 4; cnt++) { + data = src[cnt] >> 1; + encode(data, dest + to_cnt++); + } + + /* even bits */ + for (cnt = 0; cnt < len / 4; cnt++) { + data = src[cnt]; + encode(data, dest + to_cnt++); + } +} + +unsigned long checksum(unsigned long *addr, int len) +{ + unsigned long csum = 0; + + len /= sizeof(*addr); + while (len-- > 0) + csum ^= *addr++; + csum = ((csum>>1) & 0x55555555) ^ (csum & 0x55555555); + + return csum; +} + +struct header { + unsigned char magic; + unsigned char track; + unsigned char sect; + unsigned char ord; + unsigned char labels[16]; + unsigned long hdrchk; + unsigned long datachk; +}; + +static unsigned long *putsec(int disk, unsigned long *raw, int track, int cnt, + unsigned char *data) +{ + struct header hdr; + int i; + + if (!AMIGAHW_PRESENT(AMI_FLOPPY)) + return 0; + + disk&=3; + *raw = (raw[-1]&1) ? 0x2AAAAAAA : 0xAAAAAAAA; + raw++; + *raw++ = 0x44894489; + + hdr.magic = 0xFF; + hdr.track = track; + hdr.sect = cnt; + hdr.ord = unit[disk].sects-cnt; + for (i = 0; i < 16; i++) + hdr.labels[i] = 0; + hdr.hdrchk = checksum((ulong *)&hdr, + (char *)&hdr.hdrchk-(char *)&hdr); + hdr.datachk = checksum((ulong *)data, 512); + + encode_block(raw, (ulong *)&hdr.magic, 4); + raw += 2; + encode_block(raw, (ulong *)&hdr.labels, 16); + raw += 8; + encode_block(raw, (ulong *)&hdr.hdrchk, 4); + raw += 2; + encode_block(raw, (ulong *)&hdr.datachk, 4); + raw += 2; + encode_block(raw, (ulong *)data, 512); + raw += 256; + + return raw; +} + + +/*========================================================================== + amiga_write converts track/labels data to raw track data +==========================================================================*/ +static void amiga_write(int disk, unsigned long raw, unsigned char *data, + int track) +{ + int cnt; + unsigned long *ptr = (unsigned long *)raw; + + disk&=3; + /* gap space */ + for (cnt = 0; cnt < 415 * unit[disk].type->sect_mult; cnt++) + *ptr++ = 0xaaaaaaaa; + + /* sectors */ + for (cnt = 0; cnt < unit[disk].sects; cnt++) + ptr = putsec (disk, ptr, track, cnt, data + cnt*512); + *(ushort *)ptr = (ptr[-1]&1) ? 0x2AA8 : 0xAAA8; + raw = (unsigned long)ptr + 2; +} + +static unsigned long decode (unsigned long *data, unsigned long *raw, + int len) +{ + ulong *odd, *even; + + /* convert length from bytes to longwords */ + len >>= 2; + odd = raw; + even = odd + len; + + /* prepare return pointer */ + raw += len * 2; + + do { + *data++ = ((*odd++ & 0x55555555) << 1) | (*even++ & 0x55555555); + } while (--len != 0); + + return (ulong)raw; +} + +#define MFM_NOSYNC 1 +#define MFM_HEADER 2 +#define MFM_DATA 3 +#define MFM_TRACK 4 + +/*========================================================================== + scan_sync - looks for the next start of sector marked by a sync. d3 is the + sector number (10..0). When d3 = 10, can't be certain of a + starting sync. +==========================================================================*/ +static unsigned long scan_sync(unsigned long raw, unsigned long end) +{ + ushort *ptr = (ushort *)raw, *endp = (ushort *)end; + + while (ptr < endp && *ptr++ != 0x4489) + ; + if (ptr < endp) { + while (*ptr == 0x4489 && ptr < endp) + ptr++; + return (ulong)ptr; + } + return 0; +} + +/*========================================================================== + amiga_read reads a raw track of data into a track buffer +==========================================================================*/ +static int amiga_read(int drive, unsigned char *track_data, + unsigned long raw, int track) +{ + unsigned long end; + int scnt; + unsigned long csum; + struct header hdr; + + drive&=3; + end = raw + unit[drive].type->read_size; + + for (scnt = 0;scnt < unit[drive].sects; scnt++) { + if (!(raw = scan_sync(raw, end))) { + printk ("can't find sync for sector %d\n", scnt); + return MFM_NOSYNC; + } + + raw = decode ((ulong *)&hdr.magic, (ulong *)raw, 4); + raw = decode ((ulong *)&hdr.labels, (ulong *)raw, 16); + raw = decode ((ulong *)&hdr.hdrchk, (ulong *)raw, 4); + raw = decode ((ulong *)&hdr.datachk, (ulong *)raw, 4); + csum = checksum((ulong *)&hdr, + (char *)&hdr.hdrchk-(char *)&hdr); + +#ifdef DEBUG + printk ("(%x,%d,%d,%d) (%lx,%lx,%lx,%lx) %lx %lx\n", + hdr.magic, hdr.track, hdr.sect, hdr.ord, + *(ulong *)&hdr.labels[0], *(ulong *)&hdr.labels[4], + *(ulong *)&hdr.labels[8], *(ulong *)&hdr.labels[12], + hdr.hdrchk, hdr.datachk); +#endif + + if (hdr.hdrchk != csum) { + printk("MFM_HEADER: %08lx,%08lx\n", hdr.hdrchk, csum); + return MFM_HEADER; + } + + /* verify track */ + if (hdr.track != track) { + printk("MFM_TRACK: %d, %d\n", hdr.track, track); + return MFM_TRACK; + } + + raw = decode ((ulong *)(track_data + hdr.sect*512), + (ulong *)raw, 512); + csum = checksum((ulong *)(track_data + hdr.sect*512), 512); + + if (hdr.datachk != csum) { + printk("MFM_DATA: (%x:%d:%d:%d) sc=%d %lx, %lx\n", + hdr.magic, hdr.track, hdr.sect, hdr.ord, scnt, + hdr.datachk, csum); + printk ("data=(%lx,%lx,%lx,%lx)\n", + ((ulong *)(track_data+hdr.sect*512))[0], + ((ulong *)(track_data+hdr.sect*512))[1], + ((ulong *)(track_data+hdr.sect*512))[2], + ((ulong *)(track_data+hdr.sect*512))[3]); + return MFM_DATA; + } + } + + return 0; +} + +struct dos_header { +unsigned char track, /* 0-80 */ + side, /* 0-1 */ + sec, /* 0-...*/ + len_desc;/* 2 */ +unsigned short crc; /* on 68000 we got an alignment problem, + but this compiler solves it by adding silently + adding a pad byte so data wont fit + and this cost about 3h to discover.... */ +unsigned char gap1[22]; /* for longword-aligndness (0x4e) */ +}; + +/* crc routines are borrowed from the messydos-handler */ + +static inline ushort dos_hdr_crc (struct dos_header *hdr) +{ +return dos_crc(&(hdr->track), 0xb2, 0x30, 3); /* precomputed magic */ +} + +static inline ushort dos_data_crc(unsigned char *data) +{ +return dos_crc(data, 0xe2, 0x95 ,511); /* precomputed magic */ +} + +/* excerpt from the messydos-device +; The CRC is computed not only over the actual data, but including +; the SYNC mark (3 * $a1) and the 'ID/DATA - Address Mark' ($fe/$fb). +; As we don't read or encode these fields into our buffers, we have to +; preload the registers containing the CRC with the values they would have +; after stepping over these fields. +; +; How CRCs "really" work: +; +; First, you should regard a bitstring as a series of coefficients of +; polymomials. We calculate with these polynomials in modulo-2 +; arithmetic, in which both add and subtract are done the same as +; exclusive-or. Now, we modify our data (a very long polynomial) in +; such a way that it becomes divisible by the CCITT-standard 16-bit +; 16 12 5 +; polynomial: x + x + x + 1, represented by $11021. The easiest +; way to do this would be to multiply (using proper arithmetic) our +; datablock with $11021. So we have: +; data * $11021 = +; data * ($10000 + $1021) = +; data * $10000 + data * $1021 +; The left part of this is simple: Just add two 0 bytes. But then +; the right part (data $1021) remains difficult and even could have +; a carry into the left part. The solution is to use a modified +; multiplication, which has a result that is not correct, but with +; a difference of any multiple of $11021. We then only need to keep +; the 16 least significant bits of the result. +; +; The following algorithm does this for us: +; +; unsigned char *data, c, crclo, crchi; +; while (not done) { +; c = *data++ + crchi; +; crchi = (@ c) >> 8 + crclo; +; crclo = @ c; +; } +; +; Remember, + is done with EOR, the @ operator is in two tables (high +; and low byte separately), which is calculated as +; +; $1021 * (c & $F0) +; xor $1021 * (c & $0F) +; xor $1021 * (c >> 4) (* is regular multiplication) +; +; +; Anyway, the end result is the same as the remainder of the division of +; the data by $11021. I am afraid I need to study theory a bit more... + + +my only works was to code this from manx to C.... + +*/ + +static ushort dos_crc(void * data_a3, int data_d0, int data_d1, int data_d3) +{ +static unsigned char CRCTable1[] = { + 0x00,0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x81,0x91,0xa1,0xb1,0xc1,0xd1,0xe1,0xf1, + 0x12,0x02,0x32,0x22,0x52,0x42,0x72,0x62,0x93,0x83,0xb3,0xa3,0xd3,0xc3,0xf3,0xe3, + 0x24,0x34,0x04,0x14,0x64,0x74,0x44,0x54,0xa5,0xb5,0x85,0x95,0xe5,0xf5,0xc5,0xd5, + 0x36,0x26,0x16,0x06,0x76,0x66,0x56,0x46,0xb7,0xa7,0x97,0x87,0xf7,0xe7,0xd7,0xc7, + 0x48,0x58,0x68,0x78,0x08,0x18,0x28,0x38,0xc9,0xd9,0xe9,0xf9,0x89,0x99,0xa9,0xb9, + 0x5a,0x4a,0x7a,0x6a,0x1a,0x0a,0x3a,0x2a,0xdb,0xcb,0xfb,0xeb,0x9b,0x8b,0xbb,0xab, + 0x6c,0x7c,0x4c,0x5c,0x2c,0x3c,0x0c,0x1c,0xed,0xfd,0xcd,0xdd,0xad,0xbd,0x8d,0x9d, + 0x7e,0x6e,0x5e,0x4e,0x3e,0x2e,0x1e,0x0e,0xff,0xef,0xdf,0xcf,0xbf,0xaf,0x9f,0x8f, + 0x91,0x81,0xb1,0xa1,0xd1,0xc1,0xf1,0xe1,0x10,0x00,0x30,0x20,0x50,0x40,0x70,0x60, + 0x83,0x93,0xa3,0xb3,0xc3,0xd3,0xe3,0xf3,0x02,0x12,0x22,0x32,0x42,0x52,0x62,0x72, + 0xb5,0xa5,0x95,0x85,0xf5,0xe5,0xd5,0xc5,0x34,0x24,0x14,0x04,0x74,0x64,0x54,0x44, + 0xa7,0xb7,0x87,0x97,0xe7,0xf7,0xc7,0xd7,0x26,0x36,0x06,0x16,0x66,0x76,0x46,0x56, + 0xd9,0xc9,0xf9,0xe9,0x99,0x89,0xb9,0xa9,0x58,0x48,0x78,0x68,0x18,0x08,0x38,0x28, + 0xcb,0xdb,0xeb,0xfb,0x8b,0x9b,0xab,0xbb,0x4a,0x5a,0x6a,0x7a,0x0a,0x1a,0x2a,0x3a, + 0xfd,0xed,0xdd,0xcd,0xbd,0xad,0x9d,0x8d,0x7c,0x6c,0x5c,0x4c,0x3c,0x2c,0x1c,0x0c, + 0xef,0xff,0xcf,0xdf,0xaf,0xbf,0x8f,0x9f,0x6e,0x7e,0x4e,0x5e,0x2e,0x3e,0x0e,0x1e +}; + +static unsigned char CRCTable2[] = { + 0x00,0x21,0x42,0x63,0x84,0xa5,0xc6,0xe7,0x08,0x29,0x4a,0x6b,0x8c,0xad,0xce,0xef, + 0x31,0x10,0x73,0x52,0xb5,0x94,0xf7,0xd6,0x39,0x18,0x7b,0x5a,0xbd,0x9c,0xff,0xde, + 0x62,0x43,0x20,0x01,0xe6,0xc7,0xa4,0x85,0x6a,0x4b,0x28,0x09,0xee,0xcf,0xac,0x8d, + 0x53,0x72,0x11,0x30,0xd7,0xf6,0x95,0xb4,0x5b,0x7a,0x19,0x38,0xdf,0xfe,0x9d,0xbc, + 0xc4,0xe5,0x86,0xa7,0x40,0x61,0x02,0x23,0xcc,0xed,0x8e,0xaf,0x48,0x69,0x0a,0x2b, + 0xf5,0xd4,0xb7,0x96,0x71,0x50,0x33,0x12,0xfd,0xdc,0xbf,0x9e,0x79,0x58,0x3b,0x1a, + 0xa6,0x87,0xe4,0xc5,0x22,0x03,0x60,0x41,0xae,0x8f,0xec,0xcd,0x2a,0x0b,0x68,0x49, + 0x97,0xb6,0xd5,0xf4,0x13,0x32,0x51,0x70,0x9f,0xbe,0xdd,0xfc,0x1b,0x3a,0x59,0x78, + 0x88,0xa9,0xca,0xeb,0x0c,0x2d,0x4e,0x6f,0x80,0xa1,0xc2,0xe3,0x04,0x25,0x46,0x67, + 0xb9,0x98,0xfb,0xda,0x3d,0x1c,0x7f,0x5e,0xb1,0x90,0xf3,0xd2,0x35,0x14,0x77,0x56, + 0xea,0xcb,0xa8,0x89,0x6e,0x4f,0x2c,0x0d,0xe2,0xc3,0xa0,0x81,0x66,0x47,0x24,0x05, + 0xdb,0xfa,0x99,0xb8,0x5f,0x7e,0x1d,0x3c,0xd3,0xf2,0x91,0xb0,0x57,0x76,0x15,0x34, + 0x4c,0x6d,0x0e,0x2f,0xc8,0xe9,0x8a,0xab,0x44,0x65,0x06,0x27,0xc0,0xe1,0x82,0xa3, + 0x7d,0x5c,0x3f,0x1e,0xf9,0xd8,0xbb,0x9a,0x75,0x54,0x37,0x16,0xf1,0xd0,0xb3,0x92, + 0x2e,0x0f,0x6c,0x4d,0xaa,0x8b,0xe8,0xc9,0x26,0x07,0x64,0x45,0xa2,0x83,0xe0,0xc1, + 0x1f,0x3e,0x5d,0x7c,0x9b,0xba,0xd9,0xf8,0x17,0x36,0x55,0x74,0x93,0xb2,0xd1,0xf0 +}; + +/* look at the asm-code - what looks in C a bit strange is almost as good as handmade */ +register int i; +register unsigned char *CRCT1, *CRCT2, *data, c, crch, crcl; + +CRCT1=CRCTable1; +CRCT2=CRCTable2; +data=data_a3; +crcl=data_d1; +crch=data_d0; +for (i=data_d3; i>=0; i--) { + c = (*data++) ^ crch; + crch = CRCT1[c] ^ crcl; + crcl = CRCT2[c]; +} +return (crch<<8)|crcl; +} + +static inline unsigned char dos_decode_byte(ushort word) +{ +register ushort w2; +register unsigned char byte; +register unsigned char *dec = mfmdecode; + +w2=word; +w2>>=8; +w2&=127; +byte = dec[w2]; +byte <<= 4; +w2 = word & 127; +byte |= dec[w2]; +return byte; +} + +static unsigned long dos_decode(unsigned char *data, unsigned short *raw, int len) +{ +int i; + +for (i = 0; i < len; i++) + *data++=dos_decode_byte(*raw++); +return ((ulong)raw); +} + +#ifdef DEBUG +static void dbg(unsigned long ptr) +{ +printk("raw data @%08lx: %08lx, %08lx ,%08lx, %08lx\n",ptr, + ((ulong *)ptr)[0],((ulong *)ptr)[1],((ulong *)ptr)[2],((ulong *)ptr)[3]); +} +#endif + +/******************************************************************* + this reads a raw track of data into trackbuffer for ms-disks +*******************************************************************/ +static int dos_read(int drive, unsigned char *track_data, + unsigned long raw, int track) +{ + unsigned long end; + int scnt; + unsigned short crc,data_crc[2]; + struct dos_header hdr; + + drive&=3; + end = raw + unit[drive].type->read_size; + + for (scnt=0;scntheads) { + printk("dos_read: MFM_TRACK %d, %d\n", hdr.track, + track/unit[drive].type->heads); + return MFM_TRACK; + } + + if (hdr.side != track%unit[drive].type->heads) { + printk("dos_read: MFM_SIDE %d, %d\n", hdr.side, + track%unit[drive].type->heads); + return MFM_TRACK; + } + + if (hdr.len_desc != 2) { + printk("dos_read: unknown sector len descriptor %d\n", hdr.len_desc); + return MFM_DATA; + } +#ifdef DEBUG + printk("hdr accepted\n"); +#endif + if (!(raw = scan_sync (raw, end))) { + printk("dos_read: no data sync on track %d, unit %d for sector%d, disk sector %d\n", + track, drive, scnt, hdr.sec); + return MFM_NOSYNC; + } +#ifdef DEBUG + dbg(raw); +#endif + + if (*((ushort *)raw)!=0x5545) { + printk("dos_read: no data mark after sync (%d,%d,%d,%d) sc=%d\n", + hdr.track,hdr.side,hdr.sec,hdr.len_desc,scnt); + return MFM_NOSYNC; + } + + raw+=2; /* skip data mark (included in checksum) */ + raw = dos_decode((unsigned char *)(track_data + (hdr.sec - 1) * 512), (ushort *) raw, 512); + raw = dos_decode((unsigned char *)data_crc,(ushort *) raw,4); + crc = dos_data_crc(track_data + (hdr.sec - 1) * 512); + + if (crc != data_crc[0]) { + printk("dos_read: MFM_DATA (%d,%d,%d,%d) sc=%d, %x %x\n", + hdr.track, hdr.side, hdr.sec, hdr.len_desc, + scnt,data_crc[0], crc); + printk("data=(%lx,%lx,%lx,%lx,...)\n", + ((ulong *)(track_data+(hdr.sec-1)*512))[0], + ((ulong *)(track_data+(hdr.sec-1)*512))[1], + ((ulong *)(track_data+(hdr.sec-1)*512))[2], + ((ulong *)(track_data+(hdr.sec-1)*512))[3]); + return MFM_DATA; + } + } + return 0; +} + +static inline ushort dos_encode_byte(unsigned char byte) +{ +register unsigned char *enc, b2, b1; +register ushort word; + +enc=mfmencode; +b1=byte; +b2=b1>>4; +b1&=15; +word=enc[b2] <<8 | enc [b1]; +return (word|((word&(256|64)) ? 0: 128)); +} + +static void dos_encode_block(ushort *dest, unsigned char *src, int len) +{ +int i; + +for (i = 0; i < len; i++) { + *dest=dos_encode_byte(*src++); + *dest|=((dest[-1]&1)||(*dest&0x4000))? 0: 0x8000; + dest++; +} +} + +static unsigned long *ms_putsec(int drive, unsigned long *raw, int track, int cnt, + unsigned char *data) +{ +static struct dos_header hdr={0,0,0,2,0, + {78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78}}; +int i; +static ushort crc[2]={0,0x4e4e}; + +drive&=3; +/* id gap 1 */ +/* the MFM word before is always 9254 */ +for(i=0;i<6;i++) + *raw++=0xaaaaaaaa; +/* 3 sync + 1 headermark */ +*raw++=0x44894489; +*raw++=0x44895554; + +/* fill in the variable parts of the header */ +hdr.track=track/unit[drive].type->heads; +hdr.side=track%unit[drive].type->heads; +hdr.sec=cnt+1; +hdr.crc=dos_hdr_crc(&hdr); + +/* header (without "magic") and id gap 2*/ +dos_encode_block((ushort *)raw,(unsigned char *) &hdr.track,28); +raw+=14; + +/*id gap 3 */ +for(i=0;i<6;i++) + *raw++=0xaaaaaaaa; + +/* 3 syncs and 1 datamark */ +*raw++=0x44894489; +*raw++=0x44895545; + +/* data */ +dos_encode_block((ushort *)raw,(unsigned char *)data,512); +raw+=256; + +/*data crc + jd's special gap (long words :-/) */ +crc[0]=dos_data_crc(data); +dos_encode_block((ushort *) raw,(unsigned char *)crc,4); +raw+=2; + +/* data gap */ +for(i=0;i<38;i++) + *raw++=0x92549254; + +return raw; /* wrote 652 MFM words */ +} + + +/************************************************************** + builds encoded track data from trackbuffer data +**************************************************************/ +static void dos_write(int disk, unsigned long raw, unsigned char *data, + int track) +{ +int cnt; +unsigned long *ptr=(unsigned long *)raw; + +disk&=3; +/* really gap4 + indexgap , but we write it first and round it up */ +for (cnt=0;cnt<425;cnt++) + *ptr++=0x92549254; + +/* the following is just guessed */ +if (unit[disk].type->sect_mult==2) /* check for HD-Disks */ + for(cnt=0;cnt<473;cnt++) + *ptr++=0x92549254; + +/* now the index marks...*/ +for (cnt=0;cnt<20;cnt++) + *ptr++=0x92549254; +for (cnt=0;cnt<6;cnt++) + *ptr++=0xaaaaaaaa; +*ptr++=0x52245224; +*ptr++=0x52245552; +for (cnt=0;cnt<20;cnt++) + *ptr++=0x92549254; + +/* sectors */ +for(cnt=0;cntrq_dev) + +/* Current error count. */ +#define CURRENT_ERRORS (CURRENT->errors) + +static void request_done(int uptodate) +{ + timer_active &= ~(1 << FLOPPY_TIMER); + end_request(uptodate); +} + +/* + * floppy-change is never called from an interrupt, so we can relax a bit + * here, sleep etc. Note that floppy-on tries to set current_DOR to point + * to the desired drive, but it will probably not survive the sleep if + * several floppies are used at the same time: thus the loop. + */ +static int amiga_floppy_change(kdev_t dev) +{ + int drive = dev & 3; + int changed; + + if (MAJOR(dev) != MAJOR_NR) { + printk("floppy_change: not a floppy\n"); + return 0; + } + + fd_select (drive); + changed = !(ciaa.pra & DSKCHANGE); + fd_deselect (drive); + + if (changed) { + fd_probe(dev); + unit[drive].track = -1; + selected = -1; + savedtrack = -1; + writepending = 0; /* if this was true before, too bad! */ + writefromint = 0; + return 1; + } + return 0; +} + +static __inline__ void copy_buffer(void *from, void *to) +{ + ulong *p1,*p2; + int cnt; + + p1 = (ulong *)from; + p2 = (ulong *)to; + + for (cnt = 0; cnt < 512/4; cnt++) + *p2++ = *p1++; +} + +static void raw_read(int drive, int track, char *ptrack, int len) +{ + drive&=3; + /* setup adkcon bits correctly */ + custom.adkcon = ADK_MSBSYNC; + custom.adkcon = ADK_SETCLR|ADK_WORDSYNC|ADK_FAST; + + custom.dsksync = MFM_SYNC; + + custom.dsklen = 0; +#if 0 + ms_delay (unit[drive].type->side_time); +#endif + custom.dskptr = (u_char *)ZTWO_PADDR((u_char *)ptrack); + custom.dsklen = len/sizeof(short) | DSKLEN_DMAEN; + custom.dsklen = len/sizeof(short) | DSKLEN_DMAEN; + + block_flag = 1; + + while (block_flag == 1) + sleep_on (&wait_fd_block); + + custom.dsklen = 0; +} + +static int raw_write(int drive, int track, char *ptrack, int len) +{ + ushort adk; + + drive&=3; + if ((ciaa.pra & DSKPROT) == 0) + return 0; + + /* clear adkcon bits */ + custom.adkcon = ADK_PRECOMP1|ADK_PRECOMP0|ADK_WORDSYNC|ADK_MSBSYNC; + /* set appropriate adkcon bits */ + adk = ADK_SETCLR|ADK_FAST; + if ((ulong)track >= unit[drive].type->precomp2) + adk |= ADK_PRECOMP1; + else if ((ulong)track >= unit[drive].type->precomp1) + adk |= ADK_PRECOMP0; + custom.adkcon = adk; + + custom.dsklen = DSKLEN_WRITE; +#if 0 + ms_delay (unit[drive].type->side_time); +#endif + custom.dskptr = (u_char *)ZTWO_PADDR((u_char *)ptrack); + custom.dsklen = len/sizeof(short) | DSKLEN_DMAEN|DSKLEN_WRITE; + custom.dsklen = len/sizeof(short) | DSKLEN_DMAEN|DSKLEN_WRITE; + + block_flag = 2; + return 1; +} + +static void post_write (unsigned long dummy) +{ + custom.dsklen = 0; + writepending = 0; + writefromint = 0; +} + +static int get_track(int drive, int track) +{ + int error; + + drive&=3; + if ((lastdrive == drive) && (savedtrack == track)) + return 0; + + lastdrive = drive; + raw_read(drive, track, raw_buf, unit[drive].type->read_size); + savedtrack = -1; + error = (*unit[drive].dtype->read_fkt)(drive, trackdata, (unsigned long)raw_buf, track); + switch (error) { + case 0: + savedtrack = track; + return 0; + case MFM_TRACK: + unit[drive].track = -1; + /* fall through */ + default: + return -1; + } +} + +static void flush_track_callback(unsigned long nr) +{ + nr&=3; + writefromint = 1; + (*unit[nr].dtype->write_fkt)(nr, (unsigned long)raw_buf, trackdata, savedtrack); + if (!raw_write(nr, savedtrack, raw_buf, unit[nr].type->write_size)) { + printk ("floppy disk write protected\n"); + writefromint = 0; + writepending = 0; + } +} + +static int non_int_flush_track (unsigned long nr) +{ +unsigned long flags; + + nr&=3; + writefromint = 0; + del_timer(&post_write_timer); + save_flags(flags); + cli(); + if (writepending != 2) { + restore_flags(flags); + (*unit[nr].dtype->write_fkt)(nr, (unsigned long)raw_buf, trackdata, savedtrack); + if (!raw_write(nr, savedtrack, raw_buf, unit[nr].type->write_size)) { + printk ("floppy disk write protected in write!\n"); + writepending = 0; + return 0; + } + while (block_flag == 2) + sleep_on (&wait_fd_block); + } + else + restore_flags(flags); + ms_delay(2); /* 2 ms post_write delay */ + post_write(0); + return 1; +} + +static void redo_fd_request(void) +{ + unsigned int block, track, sector; + int device, drive, cnt; + struct amiga_floppy_struct *floppy; + char *data; + unsigned long flags; + + if (CURRENT && CURRENT->rq_status == RQ_INACTIVE){ + return; + } + + repeat: + if (!CURRENT) { + if (!fdc_busy) + printk("FDC access conflict!"); + fdc_busy = 0; + wake_up(&fdc_wait); + CLEAR_INTR; + return; + } + + if (MAJOR(CURRENT->rq_dev) != MAJOR_NR) + panic(DEVICE_NAME ": request list destroyed"); + + if (CURRENT->bh && !buffer_locked(CURRENT->bh)) + panic(DEVICE_NAME ": block not locked"); + + probing = 0; + device = MINOR(CURRENT_DEVICE); + if (device > 3) { + /* manual selection */ + drive = device & 3; + floppy = unit + drive; + } else { + /* Auto-detection */ + /* printk("redo_fd_request: can't handle auto detect\n");*/ + /* printk("redo_fd_request: default to normal\n");*/ + drive = device & 3; + floppy = unit + drive; + } + + save_flags (flags); + cli(); + if (drive != selected && writepending) { + del_timer (&flush_track_timer); + restore_flags (flags); + if (!non_int_flush_track (selected)) { + end_request(0); + goto repeat; + } + } else + restore_flags (flags); + + /* Here someone could investigate to be more efficient */ + for (cnt = 0; cnt < CURRENT->current_nr_sectors; cnt++) { +#ifdef DEBUG + printk("fd: sector %d + %d requested\n",CURRENT->sector,cnt); +#endif + block = CURRENT->sector + cnt; + if ((int)block > floppy->blocks) { + request_done(0); + goto repeat; + } + + track = block / floppy->sects; + sector = block % floppy->sects; + data = CURRENT->buffer + 512 * cnt; + + save_flags (flags); + cli(); + if (track != savedtrack && writepending) { + del_timer (&flush_track_timer); + restore_flags (flags); + if (!non_int_flush_track (selected)) { + end_request(0); + goto repeat; + } + } else + restore_flags (flags); + + switch (CURRENT->cmd) { + case READ: + if (!motor_on (drive)) { + end_request(0); + goto repeat; + } + fd_select (drive); + if (!fd_seek(drive, track)) { + end_request(0); + goto repeat; + } + if (get_track(drive, track) == -1) { + end_request(0); + goto repeat; + } + copy_buffer(trackdata + sector * 512, data); + break; + + case WRITE: + if (!motor_on (drive)) { + end_request(0); + goto repeat; + } + fd_select (drive); + if (!fd_seek(drive, track)) { + end_request(0); + goto repeat; + } + if (get_track(drive, track) == -1) { + end_request(0); + goto repeat; + } + copy_buffer(data, trackdata + sector * 512); + /* + * setup a callback to write the track buffer + * after a short (1 tick) delay. + */ + save_flags (flags); + cli(); + + if (writepending) + /* reset the timer */ + del_timer (&flush_track_timer); + + writepending = 1; + flush_track_timer.data = drive; + flush_track_timer.expires = jiffies + 1; + add_timer (&flush_track_timer); + restore_flags (flags); + break; + + default: + printk("do_fd_request: unknown command\n"); + request_done(0); + goto repeat; + } + } + CURRENT->nr_sectors -= CURRENT->current_nr_sectors; + CURRENT->sector += CURRENT->current_nr_sectors; + + request_done(1); + goto repeat; +} + +static void do_fd_request(void) +{ +unsigned long flags; + + save_flags(flags); + cli(); + while (fdc_busy) sleep_on(&fdc_wait); + fdc_busy = 1; + restore_flags(flags); /* sti(); */ + redo_fd_request(); +} + +static int fd_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long param) +{ + int drive = inode->i_rdev & 3; + static struct floppy_struct getprm; + int error; + + switch(cmd) + { + case FDFMTBEG: + if (fd_ref[drive] > 1) + return -EBUSY; + fsync_dev(inode->i_rdev); + if (motor_on(drive) == 0) + return -ENODEV; + if (fd_calibrate(drive) == 0) + return -ENXIO; + floppy_off(drive); + break; + case FDFMTTRK: + if (param < unit[drive].type->tracks) + { + fd_select(drive); + if (fd_seek(drive,param)!=0) + { + savedtrack=param; + memset(trackdata,FD_FILL_BYTE,unit[drive].sects*512); + non_int_flush_track(drive); + } + floppy_off(drive); + } + else + return -EINVAL; + break; + case FDFMTEND: + floppy_off(drive); + invalidate_inodes(inode->i_rdev); + invalidate_buffers(inode->i_rdev); + break; + case FDGETPRM: + error = verify_area(VERIFY_WRITE, (void *)param, + sizeof(struct floppy_struct)); + if (error) + return error; + memset((void *)&getprm, 0, sizeof (getprm)); + getprm.track=unit[drive].type->tracks/unit[drive].type->heads; + getprm.head=unit[drive].type->heads; + getprm.sect=unit[drive].sects; + getprm.size=unit[drive].blocks; + memcpy_tofs((void *)param,(void *)&getprm,sizeof(struct floppy_struct)); + break; + case BLKGETSIZE: + error = verify_area(VERIFY_WRITE, (void *)param, + sizeof(long)); + if (error) + return error; + put_fs_long(unit[drive].blocks,(long *)param); + break; + case FDSETPRM: + case FDDEFPRM: + return -EINVAL; + case FDFLUSH: + if ((drive == selected) && (writepending)) { + del_timer (&flush_track_timer); + non_int_flush_track(selected); + } + break; +#ifdef RAW_IOCTL + case IOCTL_RAW_TRACK: + error = verify_area(VERIFY_WRITE, (void *)param, + unit[drive].type->read_size); + if (error) + return error; + memcpy_tofs((void *)param, raw_buf, unit[drive].type->read_size); + return unit[drive].type->read_size; +#endif + default: + printk("fd_ioctl: unknown cmd %d for drive %d.",cmd,drive); + return -ENOSYS; + } + return 0; +} + +/*====================================================================== + Return unit ID number of given disk +======================================================================*/ +static unsigned long get_drive_id(int drive) +{ + int i; + ulong id = 0; + + drive&=3; + /* set up for ID */ + MOTOR_ON; + udelay(2); + SELECT(SELMASK(drive)); + udelay(2); + DESELECT(SELMASK(drive)); + udelay(2); + MOTOR_OFF; + udelay(2); + SELECT(SELMASK(drive)); + udelay(2); + DESELECT(SELMASK(drive)); + udelay(2); + + /* loop and read disk ID */ + for (i=0; i<32; i++) { + SELECT(SELMASK(drive)); + udelay(2); + + /* read and store value of DSKRDY */ + id <<= 1; + id |= (ciaa.pra & DSKRDY) ? 0 : 1; /* cia regs are low-active! */ + + DESELECT(SELMASK(drive)); + } + + selected = -1; + + /* + * RB: At least A500/A2000's df0: don't identify themselves. + * As every (real) Amiga has at least a 3.5" DD drive as df0: + * we default to that if df0: doesn't identify as a certain + * type. + */ + if(drive == 0 && id == FD_NODRIVE) + { + id = fd_def_df0; + printk("fd: drive 0 didn't identify, setting default %08lx\n",(ulong)fd_def_df0); + } + /* return the ID value */ + return (id); +} + +static void fd_probe(int dev) +{ + unsigned long code; + int type; + int drive; + int system; + + drive = dev & 3; + code = get_drive_id(drive); + + /* get drive type */ + unit[drive].type = NULL; + for (type = 0; type < num_dr_types; type++) + if (drive_types[type].code == code) + break; + + if (type >= num_dr_types) { + printk("fd_probe: unsupported drive type %08lx found\n", + code); + return; + } + + unit[drive].type = &drive_types[type]; + unit[drive].track = -1; + + unit[drive].disk = -1; + unit[drive].motor = 0; + unit[drive].busy = 0; + unit[drive].status = -1; + + + system=(dev & 4)>>2; + unit[drive].dtype=&data_types[system]; + unit[drive].sects=data_types[system].sects*unit[drive].type->sect_mult; + unit[drive].blocks=unit[drive].type->heads*unit[drive].type->tracks* + unit[drive].sects; + + floppy_sizes[MINOR(dev)] = unit[drive].blocks >> 1; + +} + +static void probe_drives(void) +{ + int drive,found; + + printk("FD: probing units\nfound "); + found=0; + for(drive=0;drivecode != FD_NODRIVE) { + printk("fd%d ",drive); + found=1; + } + } + printk("%s\n",(found==0)?" no drives":""); +} + +/* + * floppy_open check for aliasing (/dev/fd0 can be the same as + * /dev/PS0 etc), and disallows simultaneous access to the same + * drive with different device numbers. + */ +static int floppy_open(struct inode *inode, struct file *filp) +{ + int drive; + int old_dev; + int system; + + drive = inode->i_rdev & 3; + old_dev = fd_device[drive]; + + if (fd_ref[drive]) + if (old_dev != inode->i_rdev) + return -EBUSY; + + if (unit[drive].type->code == FD_NODRIVE) + return -ENODEV; + + fd_ref[drive]++; + fd_device[drive] = inode->i_rdev; + + if (old_dev && old_dev != inode->i_rdev) + invalidate_buffers(old_dev); + + if (filp && filp->f_mode) + check_disk_change(inode->i_rdev); + + if (filp && (filp->f_flags & (O_WRONLY|O_RDWR))) { + int wrprot; + + fd_select (drive); + wrprot = !(ciaa.pra & DSKPROT); + fd_deselect (drive); + + if (wrprot) + return -EROFS; + } + + system=(inode->i_rdev & 4)>>2; + unit[drive].dtype=&data_types[system]; + unit[drive].sects=data_types[system].sects*unit[drive].type->sect_mult; + unit[drive].blocks=unit[drive].type->heads*unit[drive].type->tracks* + unit[drive].sects; + +printk("fd%d: accesing %s-disk with %s-layout\n",drive,unit[drive].type->name, + data_types[system].name); + + return 0; +} + +static void floppy_release(struct inode * inode, struct file * filp) +{ + unsigned long flags; + + fsync_dev(inode->i_rdev); + invalidate_inodes(inode->i_rdev); + invalidate_buffers(inode->i_rdev); + save_flags (flags); + cli(); + if ((inode->i_rdev & 3) == selected && writepending) { + del_timer (&flush_track_timer); + restore_flags (flags); + non_int_flush_track (selected); + } else + restore_flags (flags); + + if (!fd_ref[inode->i_rdev & 3]--) { + printk("floppy_release with fd_ref == 0"); + fd_ref[inode->i_rdev & 3] = 0; + } +} + +void amiga_floppy_setup (char *str, int *ints) +{ +printk ("amiflop: Setting default df0 to %x\n", ints[1]); +fd_def_df0 = ints[1]; +} + +static struct file_operations floppy_fops = { + NULL, /* lseek - default */ + block_read, /* read - general block-dev read */ + block_write, /* write - general block-dev write */ + NULL, /* readdir - bad */ + NULL, /* select */ + fd_ioctl, /* ioctl */ + NULL, /* mmap */ + floppy_open, /* open */ + floppy_release, /* release */ + block_fsync, /* fsync */ + NULL, /* fasync */ + amiga_floppy_change, /* check_media_change */ + NULL, /* revalidate */ +}; + +static void fd_block_done(int irq, struct pt_regs *fp, void *dummy) +{ + if (block_flag) + custom.dsklen = 0x4000; + + block_flag = 0; + wake_up (&wait_fd_block); + + if (writefromint) { + /* + * if it was a write from an interrupt, + * we will call post_write from here + */ + writepending = 2; + post_write_timer.expires = 1; /* at least 2 ms */ + add_timer(&post_write_timer); + } + +} + +int amiga_floppy_init(void) +{ + int i; + + if (!AMIGAHW_PRESENT(AMI_FLOPPY)) + return -ENXIO; + + if (register_blkdev(MAJOR_NR,"fd",&floppy_fops)) { + printk("Unable to get major %d for floppy\n",MAJOR_NR); + return -EBUSY; + } + + /* initialize variables */ + motor_on_timer.next = NULL; + motor_on_timer.prev = NULL; + motor_on_timer.expires = 0; + motor_on_timer.data = 0; + motor_on_timer.function = motor_on_callback; + for (i = 0; i < FD_MAX_UNITS; i++) { + motor_off_timer[i].next = NULL; + motor_off_timer[i].prev = NULL; + motor_off_timer[i].expires = 0; + motor_off_timer[i].data = i; + motor_off_timer[i].function = fd_motor_off; + + unit[i].track = -1; + } + + flush_track_timer.next = NULL; + flush_track_timer.prev = NULL; + flush_track_timer.expires = 0; + flush_track_timer.data = 0; + flush_track_timer.function = flush_track_callback; + + post_write_timer.next = NULL; + post_write_timer.prev = NULL; + post_write_timer.expires = 0; + post_write_timer.data = 0; + post_write_timer.function = post_write; + + blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + blksize_size[MAJOR_NR] = floppy_blocksizes; + blk_size[MAJOR_NR] = floppy_sizes; + + + timer_table[FLOPPY_TIMER].fn = NULL; + timer_active &= ~(1 << FLOPPY_TIMER); + + if (fd_def_df0==0) { + if ((boot_info.bi_amiga.model == AMI_3000) || + (boot_info.bi_amiga.model == AMI_4000)) + fd_def_df0=FD_HD_3; + else + fd_def_df0=FD_DD_3; + } + + probe_drives(); + + raw_buf = (char *)amiga_chip_alloc (RAW_BUF_SIZE); + + for (i = 0; i < 128; i++) + mfmdecode[i]=255; + for (i = 0; i < 16; i++) + mfmdecode[mfmencode[i]]=i; + + /* make sure that disk DMA is enabled */ + custom.dmacon = DMAF_SETCLR | DMAF_DISK; + + add_isr(IRQ_FLOPPY, fd_block_done, 0, NULL, "floppy_dma"); + add_isr(IRQ_AMIGA_CIAA_TB, ms_isr, 0, NULL, "floppy_timer"); + + return 0; +} diff -u --recursive --new-file v1.3.93/linux/drivers/block/ataflop.c linux/drivers/block/ataflop.c --- v1.3.93/linux/drivers/block/ataflop.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/block/ataflop.c Fri Apr 19 02:35:23 1996 @@ -0,0 +1,1948 @@ +/* + * drivers/block/ataflop.c + * + * Copyright (C) 1993 Greg Harp + * Atari Support by Bjoern Brauel, Roman Hodek + * + * Big cleanup Sep 11..14 1994 Roman Hodek: + * - Driver now works interrupt driven + * - Support for two drives; should work, but I cannot test that :-( + * - Reading is done in whole tracks and buffered to speed up things + * - Disk change detection and drive deselecting after motor-off + * similar to TOS + * - Autodetection of disk format (DD/HD); untested yet, because I + * don't have an HD drive :-( + * + * Fixes Nov 13 1994 Martin Schaller: + * - Autodetection works now + * - Support for 5 1/4'' disks + * - Removed drive type (unknown on atari) + * - Do seeks with 8 Mhz + * + * Changes by Andreas Schwab: + * - After errors in multiple read mode try again reading single sectors + * (Feb 1995): + * - Clean up error handling + * - Set blk_size for proper size checking + * - Initialize track register when testing presence of floppy + * - Implement some ioctl's + * + * Changes by Torsten Lang: + * - When probing the floppies we should add the FDCCMDADD_H flag since + * the FDC will otherwise wait forever when no disk is inserted... + * + * ++ Freddi Aschwanden (fa) 20.9.95 fixes for medusa: + * - MFPDELAY() after each FDC access -> atari + * - more/other disk formats + * - DMA to the block buffer directly if we have a 32bit DMA + * - for medusa, the step rate is always 3ms + * - on medusa, use only cache_push() + * Roman: + * - Make disk format numbering independant from minors + * - Let user set max. supported drive type (speeds up format + * detection, saves buffer space) + * + * Roman 10/15/95: + * - implement some more ioctls + * - disk formatting + * + * Andreas 95/12/12: + * - increase gap size at start of track for HD/ED disks + * + * Things left to do: + * - Formatting + * - Maybe a better strategy for disk change detection (does anyone + * know one?) + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define MAJOR_NR FLOPPY_MAJOR +#include + +#define FD_MAX_UNITS 2 + +#undef DEBUG + +/* Disk types: DD, HD, ED */ +static struct atari_disk_type { + const char *name; + unsigned spt; /* sectors per track */ + unsigned blocks; /* total number of blocks */ + unsigned fdc_speed; /* fdc_speed setting */ + unsigned stretch; /* track doubling ? */ +} disk_type[] = { + { "d360", 9, 720, 0, 0}, /* 0: 360kB diskette */ + { "D360", 9, 720, 0, 1}, /* 1: 360kb in 720k or 1.2MB drive */ + { "D720", 9,1440, 0, 0}, /* 2: 720kb in 720k or 1.2MB drive */ + { "D820", 10,1640, 0, 0}, /* 3: DD disk with 82 tracks/10 sectors */ +/* formats above are probed for type DD */ +#define MAX_TYPE_DD 3 + { "h1200",15,2400, 3, 0}, /* 4: 1.2MB diskette */ + { "H1440",18,2880, 3, 0}, /* 5: 1.4 MB diskette (HD) */ + { "H1640",20,3280, 3, 0}, /* 6: 1.64MB diskette (fat HD) 82 tr 20 sec */ +/* formats above are probed for types DD and HD */ +#define MAX_TYPE_HD 6 + { "E2880",36,5760, 3, 0}, /* 7: 2.8 MB diskette (ED) */ + { "E3280",40,6560, 3, 0}, /* 8: 3.2 MB diskette (fat ED) 82 tr 40 sec */ +/* formats above are probed for types DD, HD and ED */ +#define MAX_TYPE_ED 8 +/* types below are never autoprobed */ + { "H1680",21,3360, 3, 0}, /* 9: 1.68MB diskette (fat HD) 80 tr 21 sec */ + { "h410",10,820, 0, 1}, /* 10: 410k diskette 41 tr 10 sec, stretch */ + { "h1476",18,2952, 3, 0}, /* 11: 1.48MB diskette 82 tr 18 sec */ + { "H1722",21,3444, 3, 0}, /* 12: 1.72MB diskette 82 tr 21 sec */ + { "h420",10,840, 0, 1}, /* 13: 420k diskette 42 tr 10 sec, stretch */ + { "H830",10,1660, 0, 0}, /* 14: 820k diskette 83 tr 10 sec */ + { "h1494",18,2952, 3, 0}, /* 15: 1.49MB diskette 83 tr 18 sec */ + { "H1743",21,3486, 3, 0}, /* 16: 1.74MB diskette 83 tr 21 sec */ + { "h880",11,1760, 0, 0}, /* 17: 880k diskette 80 tr 11 sec */ + { "D1040",13,2080, 0, 0}, /* 18: 1.04MB diskette 80 tr 13 sec */ + { "D1120",14,2240, 0, 0}, /* 19: 1.12MB diskette 80 tr 14 sec */ + { "h1600",20,3200, 3, 0}, /* 20: 1.60MB diskette 80 tr 20 sec */ + { "H1760",22,3520, 3, 0}, /* 21: 1.76MB diskette 80 tr 22 sec */ + { "H1920",24,3840, 3, 0}, /* 22: 1.92MB diskette 80 tr 24 sec */ + { "E3200",40,6400, 3, 0}, /* 23: 3.2MB diskette 80 tr 40 sec */ + { "E3520",44,7040, 3, 0}, /* 24: 3.52MB diskette 80 tr 44 sec */ + { "E3840",48,7680, 3, 0}, /* 25: 3.84MB diskette 80 tr 48 sec */ + { "H1840",23,3680, 3, 0}, /* 26: 1.84MB diskette 80 tr 23 sec */ + { "D800",10,1600, 0, 0}, /* 27: 800k diskette 80 tr 10 sec */ +}; + +static int StartDiskType[] = { + MAX_TYPE_DD, + MAX_TYPE_HD, + MAX_TYPE_ED +}; + +#define TYPE_DD 0 +#define TYPE_HD 1 +#define TYPE_ED 2 + +static int DriveType = TYPE_HD; + +/* Array for translating minors into disk formats */ +static struct { + int index; + unsigned drive_types; +} minor2disktype[] = { + { 0, TYPE_DD }, /* 1: d360 */ + { 4, TYPE_HD }, /* 2: h1200 */ + { 1, TYPE_DD }, /* 3: D360 */ + { 2, TYPE_DD }, /* 4: D720 */ + { 1, TYPE_DD }, /* 5: h360 = D360 */ + { 2, TYPE_DD }, /* 6: h720 = D720 */ + { 5, TYPE_HD }, /* 7: H1440 */ + { 7, TYPE_ED }, /* 8: E2880 */ +/* some PC formats :-) */ + { 8, TYPE_ED }, /* 9: E3280 <- was "CompaQ" == E2880 for PC */ + { 5, TYPE_HD }, /* 10: h1440 = H1440 */ + { 9, TYPE_HD }, /* 11: H1680 */ + { 10, TYPE_DD }, /* 12: h410 */ + { 3, TYPE_DD }, /* 13: H820 <- == D820, 82x10 */ + { 11, TYPE_HD }, /* 14: h1476 */ + { 12, TYPE_HD }, /* 15: H1722 */ + { 13, TYPE_DD }, /* 16: h420 */ + { 14, TYPE_DD }, /* 17: H830 */ + { 15, TYPE_HD }, /* 18: h1494 */ + { 16, TYPE_HD }, /* 19: H1743 */ + { 17, TYPE_DD }, /* 20: h880 */ + { 18, TYPE_DD }, /* 21: D1040 */ + { 19, TYPE_DD }, /* 22: D1120 */ + { 20, TYPE_HD }, /* 23: h1600 */ + { 21, TYPE_HD }, /* 24: H1760 */ + { 22, TYPE_HD }, /* 25: H1920 */ + { 23, TYPE_ED }, /* 26: E3200 */ + { 24, TYPE_ED }, /* 27: E3520 */ + { 25, TYPE_ED }, /* 28: E3840 */ + { 26, TYPE_HD }, /* 29: H1840 */ + { 27, TYPE_DD }, /* 30: D800 */ + { 6, TYPE_HD }, /* 31: H1640 <- was H1600 == h1600 for PC */ +}; + +#define NUM_DISK_MINORS (sizeof(minor2disktype)/sizeof(*minor2disktype)) + +/* + * Maximum disk size (in kilobytes). This default is used whenever the + * current disk size is unknown. + */ +#define MAX_DISK_SIZE 3280 + +static int floppy_sizes[256]; +static int floppy_blocksizes[256] = { 0, }; + +/* current info on each unit */ +static struct atari_floppy_struct { + int connected; /* !=0 : drive is connected */ + int autoprobe; /* !=0 : do autoprobe */ + + struct atari_disk_type *disktype; /* current type of disk */ + + int track; /* current head position or -1 if + unknown */ + unsigned int steprate; /* steprate setting */ + unsigned int wpstat; /* current state of WP signal (for + disk change detection) */ + int flags; /* flags */ +} unit[FD_MAX_UNITS]; + +#define UD unit[drive] +#define UDT unit[drive].disktype +#define SUD unit[SelectedDrive] +#define SUDT unit[SelectedDrive].disktype + + +#define FDC_READ(reg) ({ \ + /* unsigned long __flags; */ \ + unsigned short __val; \ + /* save_flags(__flags); cli(); */ \ + dma_wd.dma_mode_status = 0x80 | (reg); \ + udelay(25); \ + __val = dma_wd.fdc_acces_seccount; \ + MFPDELAY(); \ + /* restore_flags(__flags); */ \ + __val & 0xff; \ +}) + +#define FDC_WRITE(reg,val) \ + do { \ + /* unsigned long __flags; */ \ + /* save_flags(__flags); cli(); */ \ + dma_wd.dma_mode_status = 0x80 | (reg); \ + udelay(25); \ + dma_wd.fdc_acces_seccount = (val); \ + MFPDELAY(); \ + /* restore_flags(__flags); */ \ + } while(0) + + +/* Buffering variables: + * First, there is a DMA buffer in ST-RAM that is used for floppy DMA + * operations. Second, a track buffer is used to cache a whole track + * of the disk to save read operations. These are two seperate buffers + * because that allows write operations without clearing the track buffer. + */ + +static int MaxSectors[] = { + 11, 22, 44 +}; +static int BufferSize[] = { + 15*512, 30*512, 60*512 +}; + +#define MAX_SECTORS (MaxSectors[DriveType]) +#define BUFFER_SIZE (BufferSize[DriveType]) + +unsigned char *DMABuffer; /* buffer for writes */ +static unsigned long PhysDMABuffer; /* physical address */ + +static int UseTrackbuffer = -1; /* Do track buffering? */ + +unsigned char *TrackBuffer; /* buffer for reads */ +static unsigned long PhysTrackBuffer; /* physical address */ +static int BufferDrive, BufferSide, BufferTrack; +static int read_track; /* non-zero if we are reading whole tracks */ + +#define SECTOR_BUFFER(sec) (TrackBuffer + ((sec)-1)*512) +#define IS_BUFFERED(drive,side,track) \ + (BufferDrive == (drive) && BufferSide == (side) && BufferTrack == (track)) + +/* + * These are global variables, as that's the easiest way to give + * information to interrupts. They are the data used for the current + * request. + */ +static int SelectedDrive = 0; +static int ReqCmd, ReqBlock; +static int ReqSide, ReqTrack, ReqSector, ReqCnt; +static int HeadSettleFlag = 0; +static unsigned char *ReqData, *ReqBuffer; +static int MotorOn = 0, MotorOffTrys; +static int IsFormatting = 0, FormatError; + +static int UserSteprate[FD_MAX_UNITS] = { -1, -1 }; + +/* Synchronization of FDC access. */ +static volatile int fdc_busy = 0; +static struct wait_queue *fdc_wait = NULL; +static struct wait_queue *format_wait = NULL; + +static unsigned int changed_floppies = 0xff, fake_change = 0; +#define CHECK_CHANGE_DELAY HZ/2 + +#define FD_MOTOR_OFF_DELAY (3*HZ) +#define FD_MOTOR_OFF_MAXTRY (10*20) + +#define FLOPPY_TIMEOUT (6*HZ) +#define RECALIBRATE_ERRORS 4 /* Atfer this many errors the drive + * will be recalibrated. */ +#define MAX_ERRORS 8 /* After this many errors the driver + * will give up. */ + + +#define START_MOTOR_OFF_TIMER(delay) \ + do { \ + motor_off_timer.expires = jiffies + (delay); \ + add_timer( &motor_off_timer ); \ + MotorOffTrys = 0; \ + } while(0) + +#define START_CHECK_CHANGE_TIMER(delay) \ + do { \ + timer_table[FLOPPY_TIMER].expires = jiffies + (delay); \ + timer_active |= (1 << FLOPPY_TIMER); \ + } while(0) + +#define START_TIMEOUT() \ + do { \ + del_timer( &timeout_timer ); \ + timeout_timer.expires = jiffies + FLOPPY_TIMEOUT; \ + add_timer( &timeout_timer ); \ + } while(0) + +#define STOP_TIMEOUT() \ + do { \ + del_timer( &timeout_timer ); \ + } while(0) + + +/* + * The driver is trying to determine the correct media format + * while Probing is set. fd_rwsec_done() clears it after a + * successful access. + */ +static int Probing = 0; + +/* This flag is set when a dummy seek is necesary to make the WP + * status bit accessible. + */ +static int NeedSeek = 0; + + +#ifdef DEBUG +#define DPRINT(a) printk a +#else +#define DPRINT(a) +#endif + +/***************************** Prototypes *****************************/ + +static void fd_select_side( int side ); +static void fd_select_drive( int drive ); +static void fd_deselect( void ); +static void fd_motor_off_timer( unsigned long dummy ); +static void check_change( void ); +static __inline__ void set_head_settle_flag( void ); +static __inline__ int get_head_settle_flag( void ); +static void floppy_irq (int irq, struct pt_regs *fp, void *dummy); +static void fd_error( void ); +static int do_format(kdev_t drive, struct atari_format_descr *desc); +static void do_fd_action( int drive ); +static void fd_calibrate( void ); +static void fd_calibrate_done( int status ); +static void fd_seek( void ); +static void fd_seek_done( int status ); +static void fd_rwsec( void ); +static void fd_readtrack_check( unsigned long dummy ); +static void fd_rwsec_done( int status ); +static void fd_writetrack( void ); +static void fd_writetrack_done( int status ); +static void fd_times_out( unsigned long dummy ); +static void finish_fdc( void ); +static void finish_fdc_done( int dummy ); +static void floppy_off( unsigned int nr); +static __inline__ void copy_buffer( void *from, void *to); +static void setup_req_params( int drive ); +static void redo_fd_request( void); +static int invalidate_drive(kdev_t rdev); +static int fd_ioctl( struct inode *inode, struct file *filp, unsigned int + cmd, unsigned long param); +static void fd_probe( int drive ); +static int fd_test_drive_present( int drive ); +static void config_types( void ); +static int floppy_open( struct inode *inode, struct file *filp ); +static void floppy_release( struct inode * inode, struct file * filp ); + +/************************* End of Prototypes **************************/ + +static struct timer_list motor_off_timer = + { NULL, NULL, 0, 0, fd_motor_off_timer }; +static struct timer_list readtrack_timer = + { NULL, NULL, 0, 0, fd_readtrack_check }; + +static struct timer_list timeout_timer = + { NULL, NULL, 0, 0, fd_times_out }; + + + +/* Select the side to use. */ + +static void fd_select_side( int side ) +{ + unsigned long flags; + + save_flags(flags); + cli(); /* protect against various other ints mucking around with the PSG */ + + sound_ym.rd_data_reg_sel = 14; /* Select PSG Port A */ + sound_ym.wd_data = (side == 0) ? sound_ym.rd_data_reg_sel | 0x01 : + sound_ym.rd_data_reg_sel & 0xfe; + + restore_flags(flags); +} + + +/* Select a drive, update the FDC's track register and set the correct + * clock speed for this disk's type. + */ + +static void fd_select_drive( int drive ) +{ + unsigned long flags; + unsigned char tmp; + + if (drive == SelectedDrive) + return; + + save_flags(flags); + cli(); /* protect against various other ints mucking around with the PSG */ + sound_ym.rd_data_reg_sel = 14; /* Select PSG Port A */ + tmp = sound_ym.rd_data_reg_sel; + sound_ym.wd_data = (tmp | DSKDRVNONE) & ~(drive == 0 ? DSKDRV0 : DSKDRV1); + restore_flags(flags); + + /* restore track register to saved value */ + FDC_WRITE( FDCREG_TRACK, UD.track ); + udelay(25); + + /* select 8/16 MHz */ + if (UDT) + if (ATARIHW_PRESENT(FDCSPEED)) + dma_wd.fdc_speed = UDT->fdc_speed; + + SelectedDrive = drive; +} + + +/* Deselect both drives. */ + +static void fd_deselect( void ) +{ + unsigned long flags; + + save_flags(flags); + cli(); /* protect against various other ints mucking around with the PSG */ + sound_ym.rd_data_reg_sel=14; /* Select PSG Port A */ + sound_ym.wd_data = sound_ym.rd_data_reg_sel | 7; /* no drives selected */ + SelectedDrive = -1; + restore_flags(flags); +} + + +/* This timer function deselects the drives when the FDC switched the + * motor off. The deselection cannot happen earlier because the FDC + * counts the index signals, which arrive only if one drive is selected. + */ + +static void fd_motor_off_timer( unsigned long dummy ) +{ +/* unsigned long flags; */ + unsigned char status; + int delay; + + del_timer( &motor_off_timer ); + + if (SelectedDrive < 0) + /* no drive selected, needn't deselect anyone */ + return; + +/* save_flags(flags); + cli(); */ + + if (stdma_islocked()) + goto retry; + + status = FDC_READ( FDCREG_STATUS ); + + if (!(status & 0x80)) { + /* motor already turned off by FDC -> deselect drives */ + MotorOn = 0; + fd_deselect(); +/* restore_flags(flags); */ + return; + } + /* not yet off, try again */ + + retry: +/* restore_flags(flags); */ + /* Test again later; if tested too often, it seems there is no disk + * in the drive and the FDC will leave the motor on forever (or, + * at least until a disk is inserted). So we'll test only twice + * per second from then on... + */ + delay = (MotorOffTrys < FD_MOTOR_OFF_MAXTRY) ? + (++MotorOffTrys, HZ/20) : HZ/2; + START_MOTOR_OFF_TIMER( delay ); +} + + +/* This function is repeatedly called to detect disk changes (as good + * as possible) and keep track of the current state of the write protection. + */ + +static void check_change( void ) +{ + static int drive = 0; + + unsigned long flags; + unsigned char old_porta; + int stat; + + if (++drive > 1 || !UD.connected) + drive = 0; + + save_flags(flags); + cli(); /* protect against various other ints mucking around with the PSG */ + + if (!stdma_islocked()) { + sound_ym.rd_data_reg_sel = 14; + old_porta = sound_ym.rd_data_reg_sel; + sound_ym.wd_data = (old_porta | DSKDRVNONE) & + ~(drive == 0 ? DSKDRV0 : DSKDRV1); + stat = !!(FDC_READ( FDCREG_STATUS ) & FDCSTAT_WPROT); + sound_ym.wd_data = old_porta; + + if (stat != UD.wpstat) { + DPRINT(( "wpstat[%d] = %d\n", drive, stat )); + UD.wpstat = stat; + set_bit (drive, &changed_floppies); + } + } + restore_flags(flags); + + START_CHECK_CHANGE_TIMER( CHECK_CHANGE_DELAY ); +} + + +/* Handling of the Head Settling Flag: This flag should be set after each + * seek operation, because we dont't use seeks with verify. + */ + +static __inline__ void set_head_settle_flag( void ) +{ + HeadSettleFlag = FDCCMDADD_E; +} + +static __inline__ int get_head_settle_flag( void ) +{ + int tmp = HeadSettleFlag; + HeadSettleFlag = 0; + return( tmp ); +} + + + + +/* General Interrupt Handling */ + +static void (*FloppyIRQHandler)( int status ) = NULL; + +static void floppy_irq (int irq, struct pt_regs *fp, void *dummy) +{ + unsigned char status; + void (*handler)( int ); + + handler = FloppyIRQHandler; + FloppyIRQHandler = NULL; + + if (handler) { + nop(); + status = FDC_READ( FDCREG_STATUS ); + DPRINT(("FDC irq, status = %02x handler = %08lx\n",status,(unsigned long)handler)); + handler( status ); + } + else { + DPRINT(("FDC irq, no handler\n")); + } +} + + +/* Error handling: If some error happened, retry some times, then + * recalibrate, then try again, and fail after MAX_ERRORS. + */ + +static void fd_error( void ) +{ + if (IsFormatting) { + IsFormatting = 0; + FormatError = 1; + wake_up( &format_wait ); + return; + } + + if (!CURRENT) return; + CURRENT->errors++; + if (CURRENT->errors >= MAX_ERRORS) { + printk( "fd%d: too many errors.\n", SelectedDrive ); + end_request( 0 ); + } + else if (CURRENT->errors == RECALIBRATE_ERRORS) { + printk( "fd%d: recalibrating\n", SelectedDrive ); + if (SelectedDrive != -1) + SUD.track = -1; + } + redo_fd_request(); +} + + + +#define SET_IRQ_HANDLER(proc) do { FloppyIRQHandler = (proc); } while(0) + + +/* ---------- Formatting ---------- */ + +#define FILL(n,val) \ + do { \ + memset( p, val, n ); \ + p += n; \ + } while(0) + +static int do_format(kdev_t device, struct atari_format_descr *desc) +{ + unsigned char *p; + int sect, nsect; + unsigned long flags; + int type, drive = MINOR(device) & 3; + + DPRINT(("do_format( dr=%d tr=%d he=%d offs=%d )\n", + drive, desc->track, desc->head, desc->sect_offset )); + + save_flags(flags); + cli(); + while( fdc_busy ) sleep_on( &fdc_wait ); + fdc_busy = 1; + stdma_lock(floppy_irq, NULL); + atari_turnon_irq( IRQ_MFP_FDC ); /* should be already, just to be sure */ + restore_flags(flags); + + type = MINOR(device) >> 2; + if (type) { + if (--type >= NUM_DISK_MINORS || + minor2disktype[type].drive_types > DriveType) { + redo_fd_request(); + return -EINVAL; + } + type = minor2disktype[type].index; + UDT = &disk_type[type]; + } + + if (!UDT || desc->track >= UDT->blocks/UDT->spt/2 || desc->head >= 2) { + redo_fd_request(); + return -EINVAL; + } + + nsect = UDT->spt; + p = TrackBuffer; + /* The track buffer is used for the raw track data, so its + contents become invalid! */ + BufferDrive = -1; + /* stop deselect timer */ + del_timer( &motor_off_timer ); + + FILL( 60 * (nsect / 9), 0x4e ); + for( sect = 0; sect < nsect; ++sect ) { + FILL( 12, 0 ); + FILL( 3, 0xf5 ); + *p++ = 0xfe; + *p++ = desc->track; + *p++ = desc->head; + *p++ = (nsect + sect - desc->sect_offset) % nsect + 1; + *p++ = 2; + *p++ = 0xf7; + FILL( 22, 0x4e ); + FILL( 12, 0 ); + FILL( 3, 0xf5 ); + *p++ = 0xfb; + FILL( 512, 0xe5 ); + *p++ = 0xf7; + FILL( 40, 0x4e ); + } + FILL( TrackBuffer+BUFFER_SIZE-p, 0x4e ); + + IsFormatting = 1; + FormatError = 0; + ReqTrack = desc->track; + ReqSide = desc->head; + do_fd_action( drive ); + + sleep_on( &format_wait ); + + redo_fd_request(); + return( FormatError ? -EIO : 0 ); +} + + +/* do_fd_action() is the general procedure for a fd request: All + * required parameter settings (drive select, side select, track + * position) are checked and set if needed. For each of these + * parameters and the actual reading or writing exist two functions: + * one that starts the setting (or skips it if possible) and one + * callback for the "done" interrupt. Each done func calls the next + * set function to propagate the request down to fd_rwsec_done(). + */ + +static void do_fd_action( int drive ) +{ + DPRINT(("do_fd_action\n")); + + if (UseTrackbuffer && !IsFormatting) { + repeat: + if (IS_BUFFERED( drive, ReqSide, ReqTrack )) { + if (ReqCmd == READ) { + copy_buffer( SECTOR_BUFFER(ReqSector), ReqData ); + if (++ReqCnt < CURRENT->current_nr_sectors) { + /* read next sector */ + setup_req_params( drive ); + goto repeat; + } + else { + /* all sectors finished */ + CURRENT->nr_sectors -= CURRENT->current_nr_sectors; + CURRENT->sector += CURRENT->current_nr_sectors; + end_request( 1 ); + redo_fd_request(); + return; + } + } + else { + /* cmd == WRITE, pay attention to track buffer + * consistency! */ + copy_buffer( ReqData, SECTOR_BUFFER(ReqSector) ); + } + } + } + + if (SelectedDrive != drive) + fd_select_drive( drive ); + + if (UD.track == -1) + fd_calibrate(); + else if (UD.track != ReqTrack << UDT->stretch) + fd_seek(); + else if (IsFormatting) + fd_writetrack(); + else + fd_rwsec(); +} + + +/* Seek to track 0 if the current track is unknown */ + +static void fd_calibrate( void ) +{ + if (SUD.track >= 0) { + fd_calibrate_done( 0 ); + return; + } + + if (ATARIHW_PRESENT(FDCSPEED)) + dma_wd.fdc_speed = 0; /* always seek with 8 Mhz */; + DPRINT(("fd_calibrate\n")); + SET_IRQ_HANDLER( fd_calibrate_done ); + /* we can't verify, since the speed may be incorrect */ + FDC_WRITE( FDCREG_CMD, FDCCMD_RESTORE | SUD.steprate ); + + NeedSeek = 1; + MotorOn = 1; + START_TIMEOUT(); + /* wait for IRQ */ +} + + +static void fd_calibrate_done( int status ) +{ + DPRINT(("fd_calibrate_done()\n")); + STOP_TIMEOUT(); + + /* set the correct speed now */ + if (ATARIHW_PRESENT(FDCSPEED)) + dma_wd.fdc_speed = SUDT->fdc_speed; + if (status & FDCSTAT_RECNF) { + printk( "fd%d: restore failed\n", SelectedDrive ); + fd_error(); + } + else { + SUD.track = 0; + fd_seek(); + } +} + + +/* Seek the drive to the requested track. The drive must have been + * calibrated at some point before this. + */ + +static void fd_seek( void ) +{ + if (SUD.track == ReqTrack << SUDT->stretch) { + fd_seek_done( 0 ); + return; + } + + if (ATARIHW_PRESENT(FDCSPEED)) { + dma_wd.fdc_speed = 0; /* always seek witch 8 Mhz */ + MFPDELAY(); + } + + DPRINT(("fd_seek() to track %d\n",ReqTrack)); + FDC_WRITE( FDCREG_DATA, ReqTrack << SUDT->stretch); + udelay(25); + SET_IRQ_HANDLER( fd_seek_done ); + FDC_WRITE( FDCREG_CMD, FDCCMD_SEEK | SUD.steprate ); + + MotorOn = 1; + set_head_settle_flag(); + START_TIMEOUT(); + /* wait for IRQ */ +} + + +static void fd_seek_done( int status ) +{ + DPRINT(("fd_seek_done()\n")); + STOP_TIMEOUT(); + + /* set the correct speed */ + if (ATARIHW_PRESENT(FDCSPEED)) + dma_wd.fdc_speed = SUDT->fdc_speed; + if (status & FDCSTAT_RECNF) { + printk( "fd%d: seek error (to track %d)\n", + SelectedDrive, ReqTrack ); + /* we don't know exactly which track we are on now! */ + SUD.track = -1; + fd_error(); + } + else { + SUD.track = ReqTrack << SUDT->stretch; + NeedSeek = 0; + if (IsFormatting) + fd_writetrack(); + else + fd_rwsec(); + } +} + + +/* This does the actual reading/writing after positioning the head + * over the correct track. + */ + +static int MultReadInProgress = 0; + + +static void fd_rwsec( void ) +{ + unsigned long paddr, flags; + unsigned int rwflag, old_motoron; + unsigned int track; + + DPRINT(("fd_rwsec(), Sec=%d, Access=%c\n",ReqSector, ReqCmd == WRITE ? 'w' : 'r' )); + if (ReqCmd == WRITE) { + if (ATARIHW_PRESENT(EXTD_DMA)) { + paddr = (unsigned long)VTOP(ReqData); + } + else { + copy_buffer( ReqData, DMABuffer ); + paddr = PhysDMABuffer; + } + dma_cache_maintainance( paddr, 512, 1 ); + rwflag = 0x100; + } + else { + if (read_track) + paddr = PhysTrackBuffer; + else + paddr = ATARIHW_PRESENT(EXTD_DMA) ? VTOP(ReqData) : PhysDMABuffer; + rwflag = 0; + } + + fd_select_side( ReqSide ); + + /* Start sector of this operation */ + FDC_WRITE( FDCREG_SECTOR, read_track ? 1 : ReqSector ); + MFPDELAY(); + /* Cheat for track if stretch != 0 */ + if (SUDT->stretch) { + track = FDC_READ( FDCREG_TRACK); + MFPDELAY(); + FDC_WRITE( FDCREG_TRACK, track >> SUDT->stretch); + } + udelay(25); + + /* Setup DMA */ + save_flags(flags); + cli(); + dma_wd.dma_lo = (unsigned char)paddr; + MFPDELAY(); + paddr >>= 8; + dma_wd.dma_md = (unsigned char)paddr; + MFPDELAY(); + paddr >>= 8; + if (ATARIHW_PRESENT(EXTD_DMA)) + st_dma_ext_dmahi = (unsigned short)paddr; + else + dma_wd.dma_hi = (unsigned char)paddr; + MFPDELAY(); + restore_flags(flags); + + /* Clear FIFO and switch DMA to correct mode */ + dma_wd.dma_mode_status = 0x90 | rwflag; + MFPDELAY(); + dma_wd.dma_mode_status = 0x90 | (rwflag ^ 0x100); + MFPDELAY(); + dma_wd.dma_mode_status = 0x90 | rwflag; + MFPDELAY(); + + /* How many sectors for DMA */ + dma_wd.fdc_acces_seccount = read_track ? SUDT->spt : 1; + + udelay(25); + + /* Start operation */ + dma_wd.dma_mode_status = FDCSELREG_STP | rwflag; + udelay(25); + SET_IRQ_HANDLER( fd_rwsec_done ); + dma_wd.fdc_acces_seccount = + (get_head_settle_flag() | + (rwflag ? FDCCMD_WRSEC : (FDCCMD_RDSEC | (read_track ? FDCCMDADD_M : 0)))); + + old_motoron = MotorOn; + MotorOn = 1; + NeedSeek = 1; + /* wait for interrupt */ + + if (read_track) { + /* If reading a whole track, wait about one disk rotation and + * then check if all sectors are read. The FDC will even + * search for the first non-existant sector and need 1 sec to + * recognise that it isn't present :-( + */ + readtrack_timer.expires = + jiffies + HZ/5 + (old_motoron ? 0 : HZ); + /* 1 rot. + 5 rot.s if motor was off */ + add_timer( &readtrack_timer ); + MultReadInProgress = 1; + } + START_TIMEOUT(); +} + + +static void fd_readtrack_check( unsigned long dummy ) +{ + unsigned long flags, addr, addr2; + + save_flags(flags); + cli(); + + del_timer( &readtrack_timer ); + + if (!MultReadInProgress) { + /* This prevents a race condition that could arise if the + * interrupt is triggered while the calling of this timer + * callback function takes place. The IRQ function then has + * already cleared 'MultReadInProgress' when flow of control + * gets here. + */ + restore_flags(flags); + return; + } + + /* get the current DMA address */ + /* ++ f.a. read twice to avoid being fooled by switcher */ + addr = 0; + do { + addr2 = addr; + addr = dma_wd.dma_lo & 0xff; + MFPDELAY(); + addr |= (dma_wd.dma_md & 0xff) << 8; + MFPDELAY(); + if (ATARIHW_PRESENT( EXTD_DMA )) + addr |= (st_dma_ext_dmahi & 0xffff) << 16; + else + addr |= (dma_wd.dma_hi & 0xff) << 16; + MFPDELAY(); + } while(addr != addr2); + + if (addr >= PhysTrackBuffer + SUDT->spt*512) { + /* already read enough data, force an FDC interrupt to stop + * the read operation + */ + SET_IRQ_HANDLER( NULL ); + restore_flags(flags); + DPRINT(("fd_readtrack_check(): done\n")); + FDC_WRITE( FDCREG_CMD, FDCCMD_FORCI ); + udelay(25); + + /* No error until now -- the FDC would have interrupted + * otherwise! + */ + fd_rwsec_done( 0 ); + } + else { + /* not yet finished, wait another tenth rotation */ + restore_flags(flags); + DPRINT(("fd_readtrack_check(): not yet finished\n")); + readtrack_timer.expires = jiffies + HZ/5/10; + add_timer( &readtrack_timer ); + } +} + + +static void fd_rwsec_done( int status ) +{ + unsigned int track; + + DPRINT(("fd_rwsec_done()\n")); + + STOP_TIMEOUT(); + + if (read_track) { + if (!MultReadInProgress) + return; + MultReadInProgress = 0; + del_timer( &readtrack_timer ); + } + + /* Correct the track if stretch != 0 */ + if (SUDT->stretch) { + track = FDC_READ( FDCREG_TRACK); + MFPDELAY(); + FDC_WRITE( FDCREG_TRACK, track << SUDT->stretch); + } + + if (!UseTrackbuffer) { + dma_wd.dma_mode_status = 0x90; + MFPDELAY(); + if (!(dma_wd.dma_mode_status & 0x01)) { + printk( "fd%d: DMA error\n", SelectedDrive ); + goto err_end; + } + } + MFPDELAY(); + + if (ReqCmd == WRITE && (status & FDCSTAT_WPROT)) { + printk( "fd%d: is write protected\n", SelectedDrive ); + goto err_end; + } + if ((status & FDCSTAT_RECNF) && + /* RECNF is no error after a multiple read when the FDC + searched for a non-existant sector! */ + !(read_track && FDC_READ(FDCREG_SECTOR) > SUDT->spt)) { + if (Probing) { + if (SUDT > disk_type) { + /* try another disk type */ + SUDT--; + floppy_sizes[SelectedDrive] = SUDT->blocks >> 1; + } + else { + if (SUD.flags & FTD_MSG) + printk( "fd%d: Auto-detected floppy type %s\n", + SelectedDrive, SUDT->name ); + Probing=0; + } + } else { +/* record not found, but not probing. Maybe stretch wrong ? Restart probing */ + if (SUD.autoprobe) { + SUDT = disk_type + StartDiskType[DriveType]; + floppy_sizes[SelectedDrive] = SUDT->blocks >> 1; + Probing = 1; + } + } + if (Probing) { + if (ATARIHW_PRESENT(FDCSPEED)) { + dma_wd.fdc_speed = SUDT->fdc_speed; + MFPDELAY(); + } + setup_req_params( SelectedDrive ); + BufferDrive = -1; + do_fd_action( SelectedDrive ); + return; + } + + printk( "fd%d: sector %d not found (side %d, track %d)\n", + SelectedDrive, FDC_READ (FDCREG_SECTOR), ReqSide, ReqTrack ); + goto err_end; + } + if (status & FDCSTAT_CRC) { + printk( "fd%d: CRC error (side %d, track %d, sector %d)\n", + SelectedDrive, ReqSide, ReqTrack, FDC_READ (FDCREG_SECTOR) ); + goto err_end; + } + if (status & FDCSTAT_LOST) { + printk( "fd%d: lost data (side %d, track %d, sector %d)\n", + SelectedDrive, ReqSide, ReqTrack, FDC_READ (FDCREG_SECTOR) ); + goto err_end; + } + + Probing = 0; + + if (ReqCmd == READ) { + if (!read_track) { + void *addr; + addr = ATARIHW_PRESENT( EXTD_DMA ) ? ReqData : DMABuffer; + dma_cache_maintainance( VTOP(addr), 512, 0 ); + if (!ATARIHW_PRESENT( EXTD_DMA )) + copy_buffer (addr, ReqData); + } else { + dma_cache_maintainance( PhysTrackBuffer, MAX_SECTORS * 512, 0 ); + BufferDrive = SelectedDrive; + BufferSide = ReqSide; + BufferTrack = ReqTrack; + copy_buffer (SECTOR_BUFFER (ReqSector), ReqData); + } + } + + if (++ReqCnt < CURRENT->current_nr_sectors) { + /* read next sector */ + setup_req_params( SelectedDrive ); + do_fd_action( SelectedDrive ); + } + else { + /* all sectors finished */ + CURRENT->nr_sectors -= CURRENT->current_nr_sectors; + CURRENT->sector += CURRENT->current_nr_sectors; + end_request( 1 ); + redo_fd_request(); + } + return; + + err_end: + BufferDrive = -1; + fd_error(); +} + + +static void fd_writetrack( void ) +{ + unsigned long paddr, flags; + unsigned int track; + + DPRINT(("fd_writetrack() Tr=%d Si=%d\n", ReqTrack, ReqSide )); + + paddr = PhysTrackBuffer; + dma_cache_maintainance( paddr, BUFFER_SIZE, 1 ); + + fd_select_side( ReqSide ); + + /* Cheat for track if stretch != 0 */ + if (SUDT->stretch) { + track = FDC_READ( FDCREG_TRACK); + MFPDELAY(); + FDC_WRITE(FDCREG_TRACK,track >> SUDT->stretch); + } + udelay(40); + + /* Setup DMA */ + save_flags(flags); + cli(); + dma_wd.dma_lo = (unsigned char)paddr; + MFPDELAY(); + paddr >>= 8; + dma_wd.dma_md = (unsigned char)paddr; + MFPDELAY(); + paddr >>= 8; + if (ATARIHW_PRESENT( EXTD_DMA )) + st_dma_ext_dmahi = (unsigned short)paddr; + else + dma_wd.dma_hi = (unsigned char)paddr; + MFPDELAY(); + restore_flags(flags); + + /* Clear FIFO and switch DMA to correct mode */ + dma_wd.dma_mode_status = 0x190; + MFPDELAY(); + dma_wd.dma_mode_status = 0x90; + MFPDELAY(); + dma_wd.dma_mode_status = 0x190; + MFPDELAY(); + + /* How many sectors for DMA */ + dma_wd.fdc_acces_seccount = BUFFER_SIZE/512; + udelay(40); + + /* Start operation */ + dma_wd.dma_mode_status = FDCSELREG_STP | 0x100; + udelay(40); + SET_IRQ_HANDLER( fd_writetrack_done ); + dma_wd.fdc_acces_seccount = FDCCMD_WRTRA | get_head_settle_flag(); + + MotorOn = 1; + START_TIMEOUT(); + /* wait for interrupt */ +} + + +static void fd_writetrack_done( int status ) +{ + DPRINT(("fd_writetrack_done()\n")); + + STOP_TIMEOUT(); + + if (status & FDCSTAT_WPROT) { + printk( "fd%d: is write protected\n", SelectedDrive ); + goto err_end; + } + if (status & FDCSTAT_LOST) { + printk( "fd%d: lost data (side %d, track %d)\n", + SelectedDrive, ReqSide, ReqTrack ); + goto err_end; + } + + wake_up( &format_wait ); + return; + + err_end: + fd_error(); +} + +static void fd_times_out( unsigned long dummy ) +{ + atari_disable_irq( IRQ_MFP_FDC ); + if (!FloppyIRQHandler) goto end; /* int occured after timer was fired, but + * before we came here... */ + + SET_IRQ_HANDLER( NULL ); + /* If the timeout occured while the readtrack_check timer was + * active, we need to cancel it, else bad things will happen */ + if (UseTrackbuffer) + del_timer( &readtrack_timer ); + FDC_WRITE( FDCREG_CMD, FDCCMD_FORCI ); + udelay( 25 ); + + printk( "floppy timeout\n" ); + fd_error(); + end: + atari_enable_irq( IRQ_MFP_FDC ); +} + + +/* The (noop) seek operation here is needed to make the WP bit in the + * FDC status register accessible for check_change. If the last disk + * operation would have been a RDSEC, this bit would always read as 0 + * no matter what :-( To save time, the seek goes to the track we're + * already on. + */ + +static void finish_fdc( void ) +{ + if (!NeedSeek) { + finish_fdc_done( 0 ); + } + else { + DPRINT(("finish_fdc: dummy seek started\n")); + FDC_WRITE (FDCREG_DATA, SUD.track); + SET_IRQ_HANDLER( finish_fdc_done ); + FDC_WRITE (FDCREG_CMD, FDCCMD_SEEK); + MotorOn = 1; + START_TIMEOUT(); + /* we must wait for the IRQ here, because the ST-DMA + is released immediatly afterwards and the interrupt + may be delivered to the wrong driver. */ + } +} + + +static void finish_fdc_done( int dummy ) +{ + unsigned long flags; + + DPRINT(("finish_fdc_done entered\n")); + STOP_TIMEOUT(); + NeedSeek = 0; + + if ((timer_active & (1 << FLOPPY_TIMER)) && + timer_table[FLOPPY_TIMER].expires < jiffies + 5) + /* If the check for a disk change is done too early after this + * last seek command, the WP bit still reads wrong :-(( + */ + timer_table[FLOPPY_TIMER].expires = jiffies + 5; + else + START_CHECK_CHANGE_TIMER( CHECK_CHANGE_DELAY ); + del_timer( &motor_off_timer ); + START_MOTOR_OFF_TIMER( FD_MOTOR_OFF_DELAY ); + + save_flags(flags); + cli(); + stdma_release(); + fdc_busy = 0; + wake_up( &fdc_wait ); + restore_flags(flags); + + DPRINT(("finish_fdc() finished\n")); +} + + +/* Prevent "aliased" accesses. */ +static fd_ref[4] = { 0,0,0,0 }; +static fd_device[4] = { 0,0,0,0 }; + +/* + * Current device number. Taken either from the block header or from the + * format request descriptor. + */ +#define CURRENT_DEVICE (CURRENT->rq_dev) + +/* Current error count. */ +#define CURRENT_ERRORS (CURRENT->errors) + + +/* dummy for blk.h */ +static void floppy_off( unsigned int nr) {} + + +/* The detection of disk changes is a dark chapter in Atari history :-( + * Because the "Drive ready" signal isn't present in the Atari + * hardware, one has to rely on the "Write Protect". This works fine, + * as long as no write protected disks are used. TOS solves this + * problem by introducing tri-state logic ("maybe changed") and + * looking at the serial number in block 0. This isn't possible for + * Linux, since the floppy driver can't make assumptions about the + * filesystem used on the disk and thus the contents of block 0. I've + * choosen the method to always say "The disk was changed" if it is + * unsure whether it was. This implies that every open or mount + * invalidates the disk buffers if you work with write protected + * disks. But at least this is better than working with incorrect data + * due to unrecognised disk changes. + */ + +static int check_floppy_change (kdev_t dev) +{ + unsigned int drive = MINOR(dev) & 0x03; + + if (MAJOR(dev) != MAJOR_NR) { + printk("floppy_changed: not a floppy\n"); + return 0; + } + + if (test_bit (drive, &fake_change)) { + /* simulated change (e.g. after formatting) */ + return 1; + } + if (test_bit (drive, &changed_floppies)) { + /* surely changed (the WP signal changed at least once) */ + return 1; + } + if (UD.wpstat) { + /* WP is on -> could be changed: to be sure, buffers should be + * invalidated... + */ + return 1; + } + + return 0; +} + +static int floppy_revalidate (kdev_t dev) +{ + int drive = MINOR(dev) & 3; + + if (test_bit (drive, &changed_floppies) || test_bit (drive, &fake_change) + || unit[drive].disktype == 0) + { + BufferDrive = -1; + clear_bit (drive, &fake_change); + clear_bit (drive, &changed_floppies); + UDT = 0; + } + return 0; +} + +static __inline__ void copy_buffer(void *from, void *to) +{ + ulong *p1 = (ulong *)from, *p2 = (ulong *)to; + int cnt; + + for( cnt = 512/4; cnt; cnt-- ) + *p2++ = *p1++; +} + + +/* This sets up the global variables describing the current request. */ + +static void setup_req_params( int drive ) +{ + int block = ReqBlock + ReqCnt; + + ReqTrack = block / UDT->spt; + ReqSector = block - ReqTrack * UDT->spt + 1; + ReqSide = ReqTrack & 1; + ReqTrack >>= 1; + ReqData = ReqBuffer + 512 * ReqCnt; + + if (UseTrackbuffer) + read_track = (ReqCmd == READ && CURRENT_ERRORS == 0); + else + read_track = 0; + + DPRINT(("Request params: Si=%d Tr=%d Se=%d Data=%08lx\n",ReqSide, + ReqTrack, ReqSector, (unsigned long)ReqData )); +} + + +static void redo_fd_request(void) +{ + int device, drive, type; + + DPRINT(("redo_fd_request: CURRENT=%08lx CURRENT->dev=%04x CURRENT->sector=%ld\n", + (unsigned long)CURRENT, CURRENT ? CURRENT->rq_dev : 0, + CURRENT ? CURRENT->sector : 0 )); + + IsFormatting = 0; + + if (CURRENT && CURRENT->rq_status == RQ_INACTIVE){ + return; + } + +repeat: + + if (!CURRENT) + goto the_end; + + if (MAJOR(CURRENT->rq_dev) != MAJOR_NR) + panic(DEVICE_NAME ": request list destroyed"); + + if (CURRENT->bh && !buffer_locked(CURRENT->bh)) + panic(DEVICE_NAME ": block not locked"); + + device = MINOR(CURRENT_DEVICE); + drive = device & 3; + type = device >> 2; + + if (!UD.connected) { + /* drive not connected */ + printk( "Unknown Device: fd%d\n", drive ); + end_request(0); + goto repeat; + } + + if (type == 0) { + if (!UDT) { + Probing = 1; + UDT = disk_type + StartDiskType[DriveType]; + floppy_sizes[drive] = UDT->blocks >> 1; + UD.autoprobe = 1; + } + } + else { + /* user supplied disk type */ + if (--type >= NUM_DISK_MINORS) { + printk( "fd%d: invalid disk format", drive ); + end_request( 0 ); + goto repeat; + } + if (minor2disktype[type].drive_types > DriveType) { + printk( "fd%d: unsupported disk format", drive ); + end_request( 0 ); + goto repeat; + } + type = minor2disktype[type].index; + UDT = &disk_type[type]; + floppy_sizes[drive] = UDT->blocks >> 1; + UD.autoprobe = 0; + } + + if (CURRENT->sector + 1 > UDT->blocks) { + end_request(0); + goto repeat; + } + + /* stop deselect timer */ + del_timer( &motor_off_timer ); + + ReqCnt = 0; + ReqCmd = CURRENT->cmd; + ReqBlock = CURRENT->sector; + ReqBuffer = CURRENT->buffer; + setup_req_params( drive ); + do_fd_action( drive ); + + return; + + the_end: + finish_fdc(); +} + + +void do_fd_request(void) +{ + unsigned long flags; + + DPRINT(("do_fd_request for pid %d\n",current->pid)); + while( fdc_busy ) sleep_on( &fdc_wait ); + fdc_busy = 1; + stdma_lock(floppy_irq, NULL); + + atari_disable_irq( IRQ_MFP_FDC ); + save_flags(flags); /* The request function is called with ints + sti(); * disabled... so must save the IPL for later */ + redo_fd_request(); + restore_flags(flags); + atari_enable_irq( IRQ_MFP_FDC ); +} + + +static int +invalidate_drive (kdev_t rdev) +{ + /* invalidate the buffer track to force a reread */ + BufferDrive = -1; + set_bit (MINOR(rdev) & 3, &fake_change); + check_disk_change (rdev); + return 0; +} + +static int fd_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long param) +{ +#define IOCTL_MODE_BIT 8 +#define OPEN_WRITE_BIT 16 +#define IOCTL_ALLOWED (filp && (filp->f_mode & IOCTL_MODE_BIT)) +#define COPYIN(x) (memcpy_fromfs( &(x), (void *) param, sizeof(x))) + + int drive, type, error; + kdev_t device; + struct atari_format_descr fmt_desc; + struct atari_disk_type *dtp; + struct floppy_struct getprm; + + device = inode->i_rdev; + switch (cmd) { + RO_IOCTLS (device, param); + } + drive = MINOR (device); + type = drive >> 2; + drive &= 3; + switch (cmd) { + case FDGETPRM: + if (type) { + if (--type >= NUM_DISK_MINORS) + return -ENODEV; + if (minor2disktype[type].drive_types > DriveType) + return -ENODEV; + type = minor2disktype[type].index; + dtp = &disk_type[type]; + } + else { + if (!UDT) + return -ENXIO; + else + dtp = UDT; + } + error = verify_area(VERIFY_WRITE, (void *)param, + sizeof(struct floppy_struct)); + if (error) + return( error ); + memset((void *)&getprm, 0, sizeof(getprm)); + getprm.size = dtp->blocks; + getprm.sect = dtp->spt; + getprm.head = 2; + getprm.track = dtp->blocks/dtp->spt/2; + getprm.stretch = dtp->stretch; + memcpy_tofs((void *)param, &getprm, sizeof(struct floppy_struct)); + return 0; + } + if (!IOCTL_ALLOWED) + return -EPERM; + switch (cmd) { + case FDSETPRM: + case FDDEFPRM: + return -EINVAL; + case FDMSGON: + UD.flags |= FTD_MSG; + return 0; + case FDMSGOFF: + UD.flags &= ~FTD_MSG; + return 0; + case FDSETEMSGTRESH: + return -EINVAL; + case FDFMTBEG: + return 0; + case FDFMTTRK: + if (fd_ref[drive] != 1 && fd_ref[drive] != -1) + return -EBUSY; + if ((error = verify_area(VERIFY_READ, (void *)param, + sizeof(struct atari_format_descr) ))) + return( error ); + COPYIN( fmt_desc ); + return do_format(device, &fmt_desc); + case FDCLRPRM: + UDT = NULL; + floppy_sizes[drive] = MAX_DISK_SIZE; + return invalidate_drive (device); + case FDFMTEND: + case FDFLUSH: + return invalidate_drive (drive); + } + return -EINVAL; +} + + +/* Initialize the 'unit' variable for drive 'drive' */ + +static void fd_probe( int drive ) +{ + UD.connected = 0; + UDT = NULL; + + if (!fd_test_drive_present( drive )) + return; + + UD.connected = 1; + UD.track = 0; + switch( UserSteprate[drive] ) { + case 2: + UD.steprate = FDCSTEP_2; + break; + case 3: + UD.steprate = FDCSTEP_3; + break; + case 6: + UD.steprate = FDCSTEP_6; + break; + case 12: + UD.steprate = FDCSTEP_12; + break; + default: /* should be -1 for "not set by user" */ + if (ATARIHW_PRESENT( FDCSPEED ) || is_medusa) + UD.steprate = FDCSTEP_3; + else + UD.steprate = FDCSTEP_6; + break; + } + MotorOn = 1; /* from probe restore operation! */ +} + + +/* This function tests the physical presence of a floppy drive (not + * whether a disk is inserted). This is done by issuing a restore + * command, waiting max. 2 seconds (that should be enough to move the + * head across the whole disk) and looking at the state of the "TR00" + * signal. This should now be raised if there is a drive connected + * (and there is no hardware failure :-) Otherwise, the drive is + * declared absent. + */ + +static int fd_test_drive_present( int drive ) +{ + unsigned long timeout; + unsigned char status; + int ok; + + if (drive > 1) return( 0 ); + fd_select_drive( drive ); + + /* disable interrupt temporarily */ + atari_turnoff_irq( IRQ_MFP_FDC ); + FDC_WRITE (FDCREG_TRACK, 0xff00); + FDC_WRITE( FDCREG_CMD, FDCCMD_RESTORE | FDCCMDADD_H | FDCSTEP_6 ); + + for( ok = 0, timeout = jiffies + 2*HZ+HZ/2; jiffies < timeout; ) { + if (!(mfp.par_dt_reg & 0x20)) + break; + } + + status = FDC_READ( FDCREG_STATUS ); + ok = (status & FDCSTAT_TR00) != 0; + + /* force interrupt to abort restore operation (FDC would try + * about 50 seconds!) */ + FDC_WRITE( FDCREG_CMD, FDCCMD_FORCI ); + udelay(500); + status = FDC_READ( FDCREG_STATUS ); + udelay(20); + + if (ok) { + /* dummy seek command to make WP bit accessible */ + FDC_WRITE( FDCREG_DATA, 0 ); + FDC_WRITE( FDCREG_CMD, FDCCMD_SEEK ); + while( mfp.par_dt_reg & 0x20 ) + ; + status = FDC_READ( FDCREG_STATUS ); + } + + atari_turnon_irq( IRQ_MFP_FDC ); + return( ok ); +} + + +/* Look how many and which kind of drives are connected. If there are + * floppies, additionally start the disk-change and motor-off timers. + */ + +static void config_types( void ) +{ + int drive, cnt = 0; + + /* for probing drives, set the FDC speed to 8 MHz */ + if (ATARIHW_PRESENT(FDCSPEED)) + dma_wd.fdc_speed = 0; + + printk("Probing floppy drive(s):\n"); + for( drive = 0; drive < FD_MAX_UNITS; drive++ ) { + fd_probe( drive ); + if (UD.connected) { + printk("fd%d\n", drive); + ++cnt; + } + } + + if (FDC_READ( FDCREG_STATUS ) & FDCSTAT_BUSY) { + /* If FDC is still busy from probing, give it another FORCI + * command to abort the operation. If this isn't done, the FDC + * will interrupt later and its IRQ line stays low, because + * the status register isn't read. And this will block any + * interrupts on this IRQ line :-( + */ + FDC_WRITE( FDCREG_CMD, FDCCMD_FORCI ); + udelay(500); + FDC_READ( FDCREG_STATUS ); + udelay(20); + } + + if (cnt > 0) { + START_MOTOR_OFF_TIMER( FD_MOTOR_OFF_DELAY ); + if (cnt == 1) fd_select_drive( 0 ); + START_CHECK_CHANGE_TIMER( CHECK_CHANGE_DELAY ); + } +} + +/* + * floppy_open check for aliasing (/dev/fd0 can be the same as + * /dev/PS0 etc), and disallows simultaneous access to the same + * drive with different device numbers. + */ + +static int floppy_open( struct inode *inode, struct file *filp ) +{ + int drive, type; + int old_dev; + + if (!filp) + { + DPRINT (("Weird, open called with filp=0\n")); + return -EIO; + } + + drive = MINOR (inode->i_rdev) & 3; + type = MINOR(inode->i_rdev) >> 2; + DPRINT(("fd_open: type=%d\n",type)); + if (type > NUM_DISK_MINORS) + return -ENXIO; + + old_dev = fd_device[drive]; + + if (fd_ref[drive]) + if (old_dev != inode->i_rdev) + return -EBUSY; + + if (fd_ref[drive] == -1 || (fd_ref[drive] && filp->f_flags & O_EXCL)) + return -EBUSY; + + if (filp->f_flags & O_EXCL) + fd_ref[drive] = -1; + else + fd_ref[drive]++; + + fd_device[drive] = inode->i_rdev; + + if (old_dev && old_dev != inode->i_rdev) + invalidate_buffers(old_dev); + + /* Allow ioctls if we have write-permissions even if read-only open */ + if (filp->f_mode & 2 || permission (inode, 2) == 0) + filp->f_mode |= IOCTL_MODE_BIT; + if (filp->f_mode & 2) + filp->f_mode |= OPEN_WRITE_BIT; + + if (filp->f_flags & O_NDELAY) + return 0; + + if (filp->f_mode & 3) { + check_disk_change( inode->i_rdev ); + if (filp->f_mode & 2) { + if (UD.wpstat) { + floppy_release(inode, filp); + return -EROFS; + } + } + } + + return 0; +} + + +static void floppy_release( struct inode * inode, struct file * filp ) +{ + int drive; + + drive = inode->i_rdev & 3; + + if (!filp || (filp->f_mode & (2 | OPEN_WRITE_BIT))) + /* if the file is mounted OR (writable now AND writable at open + time) Linus: Does this cover all cases? */ + block_fsync (inode, filp); + + if (fd_ref[drive] < 0) + fd_ref[drive] = 0; + else if (!fd_ref[drive]--) + { + printk("floppy_release with fd_ref == 0"); + fd_ref[drive] = 0; + } +} + +static struct file_operations floppy_fops = { + NULL, /* lseek - default */ + block_read, /* read - general block-dev read */ + block_write, /* write - general block-dev write */ + NULL, /* readdir - bad */ + NULL, /* select */ + fd_ioctl, /* ioctl */ + NULL, /* mmap */ + floppy_open, /* open */ + floppy_release, /* release */ + block_fsync, /* fsync */ + NULL, /* fasync */ + check_floppy_change, /* media_change */ + floppy_revalidate, /* revalidate */ +}; + +int atari_floppy_init (void) +{ + int i; + + if (register_blkdev(MAJOR_NR,"fd",&floppy_fops)) { + printk("Unable to get major %d for floppy\n",MAJOR_NR); + return -EBUSY; + } + + if (UseTrackbuffer < 0) + /* not set by user -> use default: for now, we turn + track buffering off for all Medusas, though it + could be used with ones that have a counter + card. But the test is too hard :-( */ + UseTrackbuffer = !is_medusa; + + /* initialize variables */ + SelectedDrive = -1; + BufferDrive = -1; + + /* initialize check_change timer */ + timer_table[FLOPPY_TIMER].fn = check_change; + timer_active &= ~(1 << FLOPPY_TIMER); + + DMABuffer = kmalloc(BUFFER_SIZE + 512, GFP_KERNEL | GFP_DMA); + if (!DMABuffer) { + printk("atari_floppy_init: cannot get dma buffer\n"); + unregister_blkdev(MAJOR_NR, "fd"); + return -ENOMEM; + } + TrackBuffer = DMABuffer + 512; + PhysDMABuffer = (unsigned long) VTOP(DMABuffer); + PhysTrackBuffer = (unsigned long) VTOP(TrackBuffer); + BufferDrive = BufferSide = BufferTrack = -1; + + for (i = 0; i < FD_MAX_UNITS; i++) { + unit[i].track = -1; + unit[i].flags = 0; + } + + for (i = 0; i < 256; i++) + if ((i >> 2) > 0 && (i >> 2) <= NUM_DISK_MINORS) { + int type = minor2disktype[(i >> 2) - 1].index; + floppy_sizes[i] = disk_type[type].blocks >> 1; + } else + floppy_sizes[i] = MAX_DISK_SIZE; + + blk_size[MAJOR_NR] = floppy_sizes; + blksize_size[MAJOR_NR] = floppy_blocksizes; + blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + + printk("Atari floppy driver: max. %cD, %strack buffering\n", + DriveType == 0 ? 'D' : DriveType == 1 ? 'H' : 'E', + UseTrackbuffer ? "" : "no "); + config_types(); + + return 0; +} + + +void atari_floppy_setup( char *str, int *ints ) +{ + int i; + + if (ints[0] < 1) { + printk( "ataflop_setup: no arguments!\n" ); + return; + } + else if (ints[0] > 2+FD_MAX_UNITS) { + printk( "ataflop_setup: too many arguments\n" ); + } + + if (ints[1] < 0 || ints[1] > 2) + printk( "ataflop_setup: bad drive type\n" ); + else + DriveType = ints[1]; + + if (ints[0] >= 2) + UseTrackbuffer = (ints[2] > 0); + + for( i = 3; i <= ints[0] && i-3 < FD_MAX_UNITS; ++i ) { + if (ints[i] != 2 && ints[i] != 3 && ints[i] != 6 && ints[i] != 12) + printk( "ataflop_setup: bad steprate\n" ); + else + UserSteprate[i-3] = ints[i]; + } +} + +#ifdef MODULE +int init_module (void) +{ + return atari_floppy_init (); +} + +void cleanup_module (void) +{ + unregister_blkdev(MAJOR_NR, "fd"); + + blk_dev[MAJOR_NR].request_fn = 0; + timer_active &= ~(1 << FLOPPY_TIMER); + timer_table[FLOPPY_TIMER].fn = 0; + kfree (DMABuffer); +} +#endif diff -u --recursive --new-file v1.3.93/linux/drivers/char/Config.in linux/drivers/char/Config.in --- v1.3.93/linux/drivers/char/Config.in Fri Apr 19 10:07:58 1996 +++ linux/drivers/char/Config.in Mon Apr 22 07:14:01 1996 @@ -12,6 +12,7 @@ tristate ' Stallion EasyIO or EC8/32 support' CONFIG_STALLION tristate ' Stallion EC8/64, ONboard, Brumby support' CONFIG_ISTALLION fi +tristate 'SDL RISCom/8 card support' CONFIG_RISCOM8 tristate 'Parallel printer support' CONFIG_PRINTER tristate 'Logitech busmouse support' CONFIG_BUSMOUSE tristate 'PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE diff -u --recursive --new-file v1.3.93/linux/drivers/char/Makefile linux/drivers/char/Makefile --- v1.3.93/linux/drivers/char/Makefile Fri Apr 19 10:07:58 1996 +++ linux/drivers/char/Makefile Mon Apr 22 07:14:54 1996 @@ -60,6 +60,14 @@ endif endif +ifeq ($(CONFIG_RISCOM8),y) +L_OBJS += riscom8.o +else + ifeq ($(CONFIG_RISCOM8),m) + M_OBJS += riscom8.o + endif +endif + ifeq ($(CONFIG_ATIXL_BUSMOUSE),y) M = y L_OBJS += atixlmouse.o diff -u --recursive --new-file v1.3.93/linux/drivers/char/amigamouse.c linux/drivers/char/amigamouse.c --- v1.3.93/linux/drivers/char/amigamouse.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/char/amigamouse.c Thu Apr 18 02:08:04 1996 @@ -0,0 +1,340 @@ +/* + * Amiga Mouse Driver for Linux 68k by Michael Rausch + * based upon: + * + * Logitech Bus Mouse Driver for Linux + * by James Banks + * + * Mods by Matthew Dillon + * calls verify_area() + * tracks better when X is busy or paging + * + * Heavily modified by David Giller + * changed from queue- to counter- driven + * hacked out a (probably incorrect) mouse_select + * + * Modified again by Nathan Laredo to interface with + * 0.96c-pl1 IRQ handling changes (13JUL92) + * didn't bother touching select code. + * + * Modified the select() code blindly to conform to the VFS + * requirements. 92.07.14 - Linus. Somebody should test it out. + * + * Modified by Johan Myreen to make room for other mice (9AUG92) + * removed assignment chr_fops[10] = &mouse_fops; see mouse.c + * renamed mouse_fops => bus_mouse_fops, made bus_mouse_fops public. + * renamed this file mouse.c => busmouse.c + * + * Modfied for use in the 1.3 kernels by Jes Sorensen. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define MSE_INT_ON() mouseint_allowed = 1 +#define MSE_INT_OFF() mouseint_allowed = 0 + + +static struct mouse_status mouse; + +static int mouseint_allowed; + +static void mouse_interrupt(int irq, struct pt_regs *fp, void *dummy) +{ + static int lastx=0, lasty=0; + int dx, dy; + int nx, ny; + unsigned char buttons; + + unsigned short joy0dat, potgor; + + if(!mouseint_allowed) + return; + MSE_INT_OFF(); + + /* + * This routine assumes, just like Kickstart, that the mouse + * has not moved more than 127 ticks since last VBL. + */ + + joy0dat = custom.joy0dat; + + nx = joy0dat & 0xff; + ny = joy0dat >> 8; + + dx = nx - lastx; + if (dx < - 127) + dx = (256 + nx) - lastx; + + if (dx > 127) + dx = (nx - 256) - lastx; + + dy = ny - lasty; + if (dy < - 127) + dy = (256 + ny) - lasty; + + if (dy > 127) + dy = (ny - 256) - lasty; + + lastx = nx; + lasty = ny; + +#if 0 + dx = -lastdx; + dx += (lastdx = joy0dat & 0xff); + if (dx < -127) + dx = -255-dx; /* underrun */ + else + if (dx > 127) + dx = 255-dx; /* overflow */ + + dy = -lastdy; + dy += (lastdy = joy0dat >> 8); + if (dy < -127) + dy = -255-dy; + else + if (dy > 127) + dy = 255-dy; +#endif + + + potgor = custom.potgor; + buttons = (ciaa.pra & 0x40 ? 4 : 0) | /* left button; note that the bits are low-active, as are the expected results -> double negation */ +#if 1 + (potgor & 0x0100 ? 2 : 0) | /* middle button; emulation goes here */ +#endif + (potgor & 0x0400 ? 1 : 0); /* right button */ + + + if (dx != 0 || dy != 0 || buttons != mouse.buttons) { + add_mouse_randomness((buttons << 16) + (dy << 8) + dx); + mouse.buttons = buttons; + mouse.dx += dx; + mouse.dy -= dy; + mouse.ready = 1; + wake_up_interruptible(&mouse.wait); + + /* + * keep dx/dy reasonable, but still able to track when X (or + * whatever) must page or is busy (i.e. long waits between + * reads) + */ + if (mouse.dx < -2048) + mouse.dx = -2048; + else + if (mouse.dx > 2048) + mouse.dx = 2048; + + if (mouse.dy < -2048) + mouse.dy = -2048; + else + if (mouse.dy > 2048) + mouse.dy = 2048; + + if (mouse.fasyncptr) + kill_fasync(mouse.fasyncptr, SIGIO); + } + MSE_INT_ON(); +} + +static int fasync_mouse(struct inode *inode, struct file *filp, int on) +{ + int retval; + + retval = fasync_helper(inode, filp, on, &mouse.fasyncptr); + if (retval < 0) + return retval; + return 0; +} + +/* + * close access to the mouse + */ + +static void close_mouse(struct inode * inode, struct file * file) +{ + fasync_mouse(inode, file, 0); + if (--mouse.active) + return; + MSE_INT_OFF(); + MOD_DEC_USE_COUNT; +} + +/* + * open access to the mouse, currently only one open is + * allowed. + */ + +static int open_mouse(struct inode * inode, struct file * file) +{ + if (!mouse.present) + return -EINVAL; + if (mouse.active++) + return 0; + mouse.ready = 0; + mouse.dx = 0; + mouse.dy = 0; + mouse.buttons = 0x87; + mouse.active = 1; + MOD_INC_USE_COUNT; + MSE_INT_ON(); + return 0; +} + +/* + * writes are disallowed + */ + +static int write_mouse(struct inode * inode, struct file * file, const char * buffer, int count) +{ + return -EINVAL; +} + +/* + * read mouse data. Currently never blocks. + */ + +static int read_mouse(struct inode * inode, struct file * file, char * buffer, int count) +{ + int r; + int dx; + int dy; + unsigned char buttons; + + if (count < 3) + return -EINVAL; + if ((r = verify_area(VERIFY_WRITE, buffer, count))) + return r; + if (!mouse.ready) + return -EAGAIN; + + /* + * Obtain the current mouse parameters and limit as appropriate for + * the return data format. Interrupts are only disabled while + * obtaining the parameters, NOT during the puts_fs_byte() calls, + * so paging in put_fs_byte() does not effect mouse tracking. + */ + + MSE_INT_OFF(); + dx = mouse.dx; + dy = mouse.dy; + if (dx < -127) + dx = -127; + else + if (dx > 127) + dx = 127; + if (dy < -127) + dy = -127; + else + if (dy > 127) + dy = 127; + buttons = mouse.buttons; + mouse.dx -= dx; + mouse.dy -= dy; + mouse.ready = 0; + MSE_INT_ON(); + + put_fs_byte(buttons | 0x80, buffer); + put_fs_byte((char)dx, buffer + 1); + put_fs_byte((char)dy, buffer + 2); + for (r = 3; r < count; r++) + put_fs_byte(0x00, buffer + r); + return r; +} + +/* + * select for mouse input + */ + +static int mouse_select(struct inode *inode, struct file *file, int sel_type, select_table * wait) +{ + if (sel_type == SEL_IN) { + if (mouse.ready) + return 1; + select_wait(&mouse.wait, wait); + } + return 0; +} + +struct file_operations amiga_mouse_fops = { + NULL, /* mouse_seek */ + read_mouse, + write_mouse, + NULL, /* mouse_readdir */ + mouse_select, /* mouse_select */ + NULL, /* mouse_ioctl */ + NULL, /* mouse_mmap */ + open_mouse, + close_mouse, + NULL, + fasync_mouse, +}; + +static struct miscdevice amiga_mouse = { + AMIGAMOUSE_MINOR, "amigamouse", &amiga_mouse_fops +}; + +int amiga_mouse_init(void) +{ + if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_MOUSE)) + return -ENODEV; + + custom.joytest = 0; /* reset counters */ + + MSE_INT_OFF(); + + mouse.active = 0; + mouse.ready = 0; + mouse.buttons = 0x87; + mouse.dx = 0; + mouse.dy = 0; + mouse.wait = NULL; + + /* + * use VBL to poll mouse deltas + */ + + if(!add_isr(IRQ_AMIGA_VERTB, mouse_interrupt, 0, NULL, "Amiga mouse")) + { + mouse.present = 0; + printk(KERN_INFO "Installing Amiga mouse failed.\n"); + return -EIO; + } + + mouse.present = 1; + + printk(KERN_INFO "Amiga mouse installed.\n"); + misc_register(&amiga_mouse); + return 0; +} + +#ifdef MODULE +#include + +int init_module(void) +{ + return amiga_mouse_init(); +} + +void cleanup_module(void) +{ + remove_isr(IRQ_AMIGA_VERTB, mouse_interrupt); + misc_deregister(&amiga_mouse); +} +#endif diff -u --recursive --new-file v1.3.93/linux/drivers/char/atarimouse.c linux/drivers/char/atarimouse.c --- v1.3.93/linux/drivers/char/atarimouse.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/char/atarimouse.c Thu Apr 18 02:08:04 1996 @@ -0,0 +1,213 @@ +/* + * Atari Mouse Driver for Linux + * by Robert de Vries (robert@and.nl) 19Jul93 + * + * 16 Nov 1994 Andreas Schwab + * Compatibility with busmouse + * Support for three button mouse (shamelessly stolen from MiNT) + * third button wired to one of the joystick directions on joystick 1 + * + * 1996/02/11 Andreas Schwab + * Module support + * Allow multiple open's + */ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +static struct mouse_status mouse; +static int atari_mouse_x_threshold = 2, atari_mouse_y_threshold = 2; +extern int atari_mouse_buttons; + +static void atari_mouse_interrupt(char *buf) +{ + int buttons; + +/* ikbd_mouse_disable(); */ + + buttons = ((buf[0] & 1 ? 1 : 0) + | (buf[0] & 2 ? 4 : 0) + | (atari_mouse_buttons & 2)); + atari_mouse_buttons = buttons; + add_mouse_randomness((buttons << 16) + (buf[2] << 8) + buf[1]); + mouse.buttons = ~buttons & 7; + mouse.dx += buf[1]; + mouse.dy -= buf[2]; + mouse.ready = 1; + wake_up_interruptible(&mouse.wait); + if (mouse.fasyncptr) + kill_fasync(mouse.fasyncptr, SIGIO); + +/* ikbd_mouse_rel_pos(); */ +} + +static int fasync_mouse(struct inode *inode, struct file *filp, int on) +{ + int retval; + + retval = fasync_helper(inode, filp, on, &mouse.fasyncptr); + if (retval < 0) + return retval; + return 0; +} + +static void release_mouse(struct inode *inode, struct file *file) +{ + fasync_mouse(inode, file, 0); + if (--mouse.active) + return; + ikbd_mouse_disable(); + + atari_mouse_interrupt_hook = NULL; + MOD_DEC_USE_COUNT; +} + +static int open_mouse(struct inode *inode, struct file *file) +{ + if (mouse.active++) + return 0; + mouse.ready = 0; + mouse.dx = mouse.dy = 0; + atari_mouse_buttons = 0; + ikbd_mouse_y0_top (); + ikbd_mouse_thresh (atari_mouse_x_threshold, atari_mouse_y_threshold); + ikbd_mouse_rel_pos(); + MOD_INC_USE_COUNT; + atari_mouse_interrupt_hook = atari_mouse_interrupt; + return 0; +} + +static int write_mouse(struct inode *inode, struct file *file, const char *buffer, int count) +{ + return -EINVAL; +} + +static int read_mouse(struct inode *inode, struct file *file, char *buffer, int count) +{ + int dx, dy, buttons; + int r; + + if (count < 3) + return -EINVAL; + if ((r = verify_area(VERIFY_WRITE, buffer, count))) + return r; + if (!mouse.ready) + return -EAGAIN; + /* ikbd_mouse_disable */ + dx = mouse.dx; + dy = mouse.dy; + buttons = mouse.buttons; + if (dx > 127) + dx = 127; + else if (dx < -128) + dx = -128; + if (dy > 127) + dy = 127; + else if (dy < -128) + dy = -128; + mouse.dx -= dx; + mouse.dy -= dy; + if (mouse.dx == 0 && mouse.dy == 0) + mouse.ready = 0; + /* ikbd_mouse_rel_pos(); */ + put_user(buttons | 0x80, buffer); + put_user((char) dx, buffer + 1); + put_user((char) dy, buffer + 2); + for (r = 3; r < count; r++) + put_user (0, buffer + r); + return r; +} + +static int mouse_select(struct inode *inode, struct file *file, int sel_type, select_table *wait) +{ + if (sel_type == SEL_IN) { + if (mouse.ready) + return 1; + select_wait(&mouse.wait, wait); + } + return 0; +} + +struct file_operations atari_mouse_fops = { + NULL, /* mouse_seek */ + read_mouse, + write_mouse, + NULL, /* mouse_readdir */ + mouse_select, + NULL, /* mouse_ioctl */ + NULL, /* mouse_mmap */ + open_mouse, + release_mouse, + NULL, + fasync_mouse, +}; + +static struct miscdevice atari_mouse = { + ATARIMOUSE_MINOR, "atarimouse", &atari_mouse_fops +}; + +int atari_mouse_init(void) +{ + mouse.active = 0; + mouse.ready = 0; + mouse.wait = NULL; + + if (!MACH_IS_ATARI) + return -ENODEV; + printk(KERN_INFO "Atari mouse installed.\n"); + misc_register(&atari_mouse); + return 0; +} + + +#define MIN_THRESHOLD 1 +#define MAX_THRESHOLD 20 /* more seems not reasonable... */ + +void atari_mouse_setup( char *str, int *ints ) +{ + if (ints[0] < 1) { + printk( "atari_mouse_setup: no arguments!\n" ); + return; + } + else if (ints[0] > 2) { + printk( "atari_mouse_setup: too many arguments\n" ); + } + + if (ints[1] < MIN_THRESHOLD || ints[1] > MAX_THRESHOLD) + printk( "atari_mouse_setup: bad threshold value (ignored)\n" ); + else { + atari_mouse_x_threshold = ints[1]; + atari_mouse_y_threshold = ints[1]; + if (ints[0] > 1) { + if (ints[2] < MIN_THRESHOLD || ints[2] > MAX_THRESHOLD) + printk("atari_mouse_setup: bad threshold value (ignored)\n" ); + else + atari_mouse_y_threshold = ints[2]; + } + } + +} + +#ifdef MODULE +#include + +int init_module(void) +{ + return atari_mouse_init(); +} + +void cleanup_module(void) +{ + misc_deregister(&atari_mouse); +} +#endif diff -u --recursive --new-file v1.3.93/linux/drivers/char/fbmem.c linux/drivers/char/fbmem.c --- v1.3.93/linux/drivers/char/fbmem.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/char/fbmem.c Wed Mar 20 19:58:17 1996 @@ -0,0 +1,292 @@ +/* + * linux/drivers/char/fbmem.c + * + * Copyright (C) 1994 Martin Schaller + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file README.legal in the main directory of this archive + * for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#define FB_MAJOR 29 + +#define FB_MODES_SHIFT 5 /* 32 modes per framebuffer */ +#define FB_NUM_MINORS 256 /* 256 Minors */ +#define FB_MAX (FB_NUM_MINORS / (1 << FB_MODES_SHIFT)) + +#define GET_INODE(i) MKDEV(FB_MAJOR, (i) << FB_MODES_SHIFT) +#define GET_FB_IDX(node) (MINOR(node) >> FB_MODES_SHIFT) +#define GET_FB_VAR_IDX(node) (MINOR(node) & ((1 << FB_MODES_SHIFT)-1)) + +struct fb_ops *registered_fb[FB_MAX]; +struct fb_var_screeninfo *registered_fb_var[FB_MAX]; +int registered_fb_var_num[FB_MAX]; +int fb_curr_open[FB_MAX]; +int fb_open_count[FB_MAX]; + +static inline int PROC_CONSOLE(void) +{ + if (!current->tty) + return fg_console; + + if (MINOR(current->tty->device) < 1) + return fg_console; + + return MINOR(current->tty->device) - 1; +} + +static int +fb_read(struct inode *inode, struct file *file, char *buf, int count) +{ + unsigned long p = file->f_pos; + struct fb_ops *fb = registered_fb[GET_FB_IDX(inode->i_rdev)]; + struct fb_fix_screeninfo fix; + char *base_addr; + int copy_size; + + if (! fb) + return -ENODEV; + if (count < 0) + return -EINVAL; + + fb->fb_get_fix(&fix,PROC_CONSOLE()); + base_addr=(char *) fix.smem_start; + copy_size=(count + p <= fix.smem_len ? count : fix.smem_len - p); + memcpy_tofs(buf, base_addr+p, copy_size); + file->f_pos += copy_size; + return copy_size; +} + +static int +fb_write(struct inode *inode, struct file *file, const char *buf, int count) +{ + unsigned long p = file->f_pos; + struct fb_ops *fb = registered_fb[GET_FB_IDX(inode->i_rdev)]; + struct fb_fix_screeninfo fix; + char *base_addr; + int copy_size; + + if (! fb) + return -ENODEV; + if (count < 0) + return -EINVAL; + fb->fb_get_fix(&fix, PROC_CONSOLE()); + base_addr=(char *) fix.smem_start; + copy_size=(count + p <= fix.smem_len ? count : fix.smem_len - p); + memcpy_fromfs(base_addr+p, buf, copy_size); + file->f_pos += copy_size; + return copy_size; +} + + +static int +fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct fb_ops *fb = registered_fb[GET_FB_IDX(inode->i_rdev)]; + struct fb_cmap cmap; + struct fb_var_screeninfo var; + struct fb_fix_screeninfo fix; + + int i,fbidx,vidx; + + if (! fb) + return -ENODEV; + switch (cmd) { + case FBIOGET_VSCREENINFO: + i = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(struct fb_var_screeninfo)); + if (i) return i; + fbidx=GET_FB_IDX(inode->i_rdev); + vidx=GET_FB_VAR_IDX(inode->i_rdev); + if (! vidx) /* ask device driver for current */ + i=fb->fb_get_var(&var, PROC_CONSOLE()); + else + var=registered_fb_var[fbidx][vidx-1]; + memcpy_tofs((void *) arg, &var, sizeof(var)); + return i; + case FBIOPUT_VSCREENINFO: + i = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(struct fb_var_screeninfo)); + if (i) return i; + memcpy_fromfs(&var, (void *) arg, sizeof(var)); + i=fb->fb_set_var(&var, PROC_CONSOLE()); + memcpy_tofs((void *) arg, &var, sizeof(var)); + fbidx=GET_FB_IDX(inode->i_rdev); + vidx=GET_FB_VAR_IDX(inode->i_rdev); + if (! i && vidx) + registered_fb_var[fbidx][vidx-1]=var; + return i; + case FBIOGET_FSCREENINFO: + i = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(struct fb_fix_screeninfo)); + if (i) return i; + i=fb->fb_get_fix(&fix, PROC_CONSOLE()); + memcpy_tofs((void *) arg, &fix, sizeof(fix)); + return i; + case FBIOPUTCMAP: + i = verify_area(VERIFY_READ, (void *) arg, + sizeof(struct fb_cmap)); + if (i) return i; + memcpy_fromfs(&cmap, (void *) arg, sizeof(cmap)); + i = verify_area(VERIFY_READ, (void *) cmap.red, + cmap.len * sizeof(unsigned short)); + if (i) return i; + i = verify_area(VERIFY_READ, (void *) cmap.green, + cmap.len * sizeof(unsigned short)); + if (i) return i; + i = verify_area(VERIFY_READ, (void *) cmap.blue, + cmap.len * sizeof(unsigned short)); + if (i) return i; + if (cmap.transp) { + i = verify_area(VERIFY_READ, (void *) cmap.transp, + cmap.len * sizeof(unsigned short)); + if (i) return i; + } + return (fb->fb_set_cmap(&cmap, 0, PROC_CONSOLE())); + case FBIOGETCMAP: + i = verify_area(VERIFY_READ, (void *) arg, + sizeof(struct fb_cmap)); + if (i) return i; + memcpy_fromfs(&cmap, (void *) arg, sizeof(cmap)); + i = verify_area(VERIFY_WRITE, (void *) cmap.red, + cmap.len * sizeof(unsigned short)); + if (i) return i; + i = verify_area(VERIFY_WRITE, (void *) cmap.green, + cmap.len * sizeof(unsigned short)); + if (i) return i; + i = verify_area(VERIFY_WRITE, (void *) cmap.blue, + cmap.len * sizeof(unsigned short)); + if (i) return i; + if (cmap.transp) { + i = verify_area(VERIFY_WRITE, (void *) cmap.transp, + cmap.len * sizeof(unsigned short)); + if (i) return i; + } + return (fb->fb_get_cmap(&cmap, 0, PROC_CONSOLE())); + default: + return (fb->fb_ioctl(inode, file, cmd, arg, PROC_CONSOLE())); + } +} + +static int +fb_mmap(struct inode *inode, struct file *file, struct vm_area_struct * vma) +{ + struct fb_ops *fb = registered_fb[GET_FB_IDX(inode->i_rdev)]; + struct fb_fix_screeninfo fix; + + if (! fb) + return -ENODEV; + fb->fb_get_fix(&fix, PROC_CONSOLE()); + if ((vma->vm_end - vma->vm_start + vma->vm_offset) > fix.smem_len) + return -EINVAL; + vma->vm_offset += fix.smem_start; + if (vma->vm_offset & ~PAGE_MASK) + return -ENXIO; + if (boot_info.cputype & CPU_68040) + pgprot_val(vma->vm_page_prot) &= _CACHEMASK040; + if (remap_page_range(vma->vm_start, vma->vm_offset, + vma->vm_end - vma->vm_start, vma->vm_page_prot)) + return -EAGAIN; + vma->vm_inode = inode; + inode->i_count++; + return 0; +} + +static int +fb_open(struct inode *inode, struct file *file) +{ + int fbidx=GET_FB_IDX(inode->i_rdev); + int vidx=GET_FB_VAR_IDX(inode->i_rdev); + struct fb_ops *fb = registered_fb[fbidx]; + int err; + + if (! vidx) /* fb?current always succeeds */ + return 0; + if (vidx > registered_fb_var_num[fbidx]) + return -EINVAL; + if (fb_curr_open[fbidx] && fb_curr_open[fbidx] != vidx) + return -EBUSY; + if (file->f_mode & 2) /* only set parameters if opened writeable */ + if ((err=fb->fb_set_var(registered_fb_var[fbidx] + vidx-1, PROC_CONSOLE()))) + return err; + fb_curr_open[fbidx] = vidx; + fb_open_count[fbidx]++; + return 0; +} + +static void +fb_release(struct inode *inode, struct file *file) +{ + int fbidx=GET_FB_IDX(inode->i_rdev); + int vidx=GET_FB_VAR_IDX(inode->i_rdev); + if (! vidx) + return; + if (! (--fb_open_count[fbidx])) + fb_curr_open[fbidx]=0; +} + +static struct file_operations fb_fops = { + NULL, /* lseek */ + fb_read, /* read */ + fb_write, /* write */ + NULL, /* readdir */ + NULL, /* select */ + fb_ioctl, /* ioctl */ + fb_mmap, /* mmap */ + fb_open, /* open */ + fb_release, /* release */ + NULL /* fsync */ +}; + +int +register_framebuffer(char *id, int *node, struct fb_ops *fbops, int fbvar_num, + struct fb_var_screeninfo *fbvar) +{ + int i; + for (i = 0 ; i < FB_MAX; i++) + if (! registered_fb[i]) + break; + if (i == FB_MAX) + return -ENXIO; + registered_fb[i]=fbops; + registered_fb_var[i]=fbvar; + registered_fb_var_num[i]=fbvar_num; + *node=GET_INODE(i); + return 0; +} + +int +unregister_framebuffer(int node) +{ + int i=GET_FB_IDX(node); + if (! registered_fb[i]) + return -EINVAL; + registered_fb[i]=NULL; + registered_fb_var[i]=NULL; + return 0; +} + +void +fbmem_init(void) +{ + if (register_chrdev(FB_MAJOR,"fb",&fb_fops)) + printk("unable to get major %d for fb devs\n", FB_MAJOR); +} + diff -u --recursive --new-file v1.3.93/linux/drivers/char/ftape/Makefile linux/drivers/char/ftape/Makefile --- v1.3.93/linux/drivers/char/ftape/Makefile Fri Apr 12 15:51:52 1996 +++ linux/drivers/char/ftape/Makefile Mon Apr 22 11:46:18 1996 @@ -30,7 +30,7 @@ # FDC_82078SL - If you have a 82078SL, define this. FTAPE_OPT = -DVERIFY_HEADERS -DNR_BUFFERS=3 -DCLK_48MHZ=1 \ - -DNO_TRACE + -DNO_TRACE -DFDC_82078SL # If you're using a non-standard floppy disk controller for the # tape drive, enable one (only!) of the following lines and set diff -u --recursive --new-file v1.3.93/linux/drivers/char/keyb_m68k.c linux/drivers/char/keyb_m68k.c --- v1.3.93/linux/drivers/char/keyb_m68k.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/char/keyb_m68k.c Fri Apr 5 17:16:48 1996 @@ -0,0 +1,867 @@ +/* + * linux/drivers/char/keyboard.c + * + * Keyboard driver for Linux v0.99 using Latin-1. + * + * Written for linux by Johan Myreen as a translation from + * the assembly version by Linus (with diacriticals added) + * + * Some additional features added by Christoph Niemann (ChN), March 1993 + * + * Loadable keymaps by Risto Kankkunen, May 1993 + * + * Diacriticals redone & other small changes, aeb@cwi.nl, June 1993 + * Added decr/incr_console, dynamic keymaps, Unicode support, + * dynamic function/string keys, led setting, Sept 1994 + * `Sticky' modifier keys, 951006. + * + */ + +/* + * modified to provide 'generic' keyboard support by Hamish Macdonald + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "kbd_kern.h" +#include "diacr.h" +#include "vt_kern.h" + +#define SIZE(x) (sizeof(x)/sizeof((x)[0])) + +#define KBD_REPORT_ERR +#define KBD_REPORT_UNKN +/* #define KBD_IS_FOCUS_9000 */ + +#ifndef KBD_DEFMODE +#define KBD_DEFMODE ((1 << VC_REPEAT) | (1 << VC_META)) +#endif + +#ifndef KBD_DEFLEDS +/* + * Some laptops take the 789uiojklm,. keys as number pad when NumLock + * is on. This seems a good reason to start with NumLock off. + */ +#define KBD_DEFLEDS 0 +#endif + +#ifndef KBD_DEFLOCK +#define KBD_DEFLOCK 0 +#endif + +/* + * The default IO slowdown is doing 'inb()'s from 0x61, which should be + * safe. But as that is the keyboard controller chip address, we do our + * slowdowns here by doing short jumps: the keyboard controller should + * be able to keep up + */ +#define REALLY_SLOW_IO +#define SLOW_IO_BY_JUMPING +#include +#include + +extern void poke_blanked_console(void); +extern void ctrl_alt_del(void); +extern void reset_vc(unsigned int new_console); +extern void scrollback(int); +extern void scrollfront(int); +extern int vc_cons_allocated(unsigned int); + +unsigned char kbd_read_mask = 0x01; /* modified by psaux.c */ + +/* + * global state includes the following, and various static variables + * in this module: prev_scancode, shift_state, diacr, npadch, dead_key_next. + * (last_console is now a global variable) + */ + +/* shift state counters.. */ +static unsigned char k_down[NR_SHIFT] = {0, }; +/* keyboard key bitmap */ +#define BITS_PER_LONG (8*sizeof(unsigned long)) +static unsigned long key_down[256/BITS_PER_LONG] = { 0, }; + +static int dead_key_next = 0; +/* + * In order to retrieve the shift_state (for the mouse server), either + * the variable must be global, or a new procedure must be created to + * return the value. I chose the former way. + */ +/*static*/ int shift_state = 0; +static int npadch = -1; /* -1 or number assembled on pad */ +static unsigned char diacr = 0; +static char rep = 0; /* flag telling character repeat */ +struct kbd_struct kbd_table[MAX_NR_CONSOLES]; +static struct tty_struct **ttytab; +static struct kbd_struct *kbd = kbd_table; +static struct tty_struct *tty = NULL; + +extern void compute_shiftstate(void); + +typedef void (*k_hand)(unsigned char value, char up_flag); +typedef void (k_handfn)(unsigned char value, char up_flag); + +static k_handfn + do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift, + do_meta, do_ascii, do_lock, do_lowercase, do_slock, do_ignore; + +static k_hand key_handler[16] = { + do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift, + do_meta, do_ascii, do_lock, do_lowercase, do_slock, + do_ignore, do_ignore, do_ignore +}; + +typedef void (*void_fnp)(void); +typedef void (void_fn)(void); + +static void_fn do_null, enter, show_ptregs, send_intr, lastcons, caps_toggle, + num, hold, scroll_forw, scroll_back, boot_it, caps_on, compose, + SAK, decr_console, incr_console, spawn_console, bare_num; + +static void_fnp spec_fn_table[] = { + do_null, enter, show_ptregs, show_mem, + show_state, send_intr, lastcons, caps_toggle, + num, hold, scroll_forw, scroll_back, + boot_it, caps_on, compose, SAK, + decr_console, incr_console, spawn_console, bare_num +}; + +/* maximum values each key_handler can handle */ +const int max_vals[] = { + 255, SIZE(func_table) - 1, SIZE(spec_fn_table) - 1, NR_PAD - 1, + NR_DEAD - 1, 255, 3, NR_SHIFT - 1, + 255, NR_ASCII - 1, NR_LOCK - 1, 255, + NR_LOCK - 1 +}; + +const int NR_TYPES = SIZE(max_vals); + +static void put_queue(int); +static unsigned char handle_diacr(unsigned char); + +/* + * Many other routines do put_queue, but I think either + * they produce ASCII, or they produce some user-assigned + * string, and in both cases we might assume that it is + * in utf-8 already. + */ +void to_utf8(ushort c) { + if (c < 0x80) + put_queue(c); /* 0******* */ + else if (c < 0x800) { + put_queue(0xc0 | (c >> 6)); /* 110***** 10****** */ + put_queue(0x80 | (c & 0x3f)); + } else { + put_queue(0xe0 | (c >> 12)); /* 1110**** 10****** 10****** */ + put_queue(0x80 | ((c >> 6) & 0x3f)); + put_queue(0x80 | (c & 0x3f)); + } + /* UTF-8 is defined for words of up to 31 bits, + but we need only 16 bits here */ +} + +void process_keycode (int keycode) +{ + char up_flag; /* 0 or 0200 */ + char raw_mode; + + do_poke_blanked_console = 1; + mark_bh(KEYBOARD_BH); + add_keyboard_randomness(keycode); + + tty = ttytab[fg_console]; + kbd = kbd_table + fg_console; + if ((raw_mode = (kbd->kbdmode == VC_RAW))) { + put_queue(keycode); + /* we do not return yet, because we want to maintain + the key_down array, so that we have the correct + values when finishing RAW mode or when changing VT's */ + } + + /* + * At this point the variable `keycode' contains the keycode. + * Note: the keycode must not be 0. + * We keep track of the up/down status of the key, and + * return the keycode if in MEDIUMRAW mode. + */ + + up_flag = (keycode & 0200); + keycode &= 0x7f; + if (up_flag) { + rep = 0; + if(!clear_bit(keycode, key_down)) { + /* unexpected, but this can happen: + maybe this was a key release for a FOCUS 9000 + PF key; if we want to see it, we have to clear + up_flag */ +#ifndef __mc68000__ + if (keycode >= SC_LIM || keycode == 85) + up_flag = 0; +#endif + } + } else + rep = set_bit(keycode, key_down); + + if (raw_mode) + return; + + if (kbd->kbdmode == VC_MEDIUMRAW) { + /* soon keycodes will require more than one byte */ + put_queue(keycode + up_flag); + return; + } + + /* + * Small change in philosophy: earlier we defined repetition by + * rep = keycode == prev_keycode; + * prev_keycode = keycode; + * but now by the fact that the depressed key was down already. + * Does this ever make a difference? Yes. + */ + + /* + * Repeat a key only if the input buffers are empty or the + * characters get echoed locally. This makes key repeat usable + * with slow applications and under heavy loads. + */ + if (!rep || + (vc_kbd_mode(kbd,VC_REPEAT) && tty && + (L_ECHO(tty) || (tty->driver.chars_in_buffer(tty) == 0)))) { + u_short keysym; + u_char type; + + /* the XOR below used to be an OR */ + int shift_final = shift_state ^ kbd->lockstate ^ kbd->slockstate; + ushort *key_map = key_maps[shift_final]; + + if (key_map != NULL) { + keysym = key_map[keycode]; + type = KTYP(keysym); + + if (type >= 0xf0) { + type -= 0xf0; + if (type == KT_LETTER) { + type = KT_LATIN; + if (vc_kbd_led(kbd, VC_CAPSLOCK)) { + key_map = key_maps[shift_final ^ (1<slockstate = 0; + } else { + /* maybe only if (kbd->kbdmode == VC_UNICODE) ? */ + if (!up_flag) + to_utf8(keysym); + } + } else { + /* maybe beep? */ + /* we have at least to update shift_state */ +#if 1 /* how? two almost equivalent choices follow */ + compute_shiftstate(); +#else + keysym = U(plain_map[keycode]); + type = KTYP(keysym); + if (type == KT_SHIFT) + (*key_handler[type])(keysym & 0xff, up_flag); +#endif + } + } +} + +static void put_queue(int ch) +{ + wake_up(&keypress_wait); + if (tty) { + tty_insert_flip_char(tty, ch, 0); + tty_schedule_flip(tty); + } +} + +static void puts_queue(char *cp) +{ + wake_up(&keypress_wait); + if (!tty) + return; + + while (*cp) { + tty_insert_flip_char(tty, *cp, 0); + cp++; + } + tty_schedule_flip(tty); +} + +static void applkey(int key, char mode) +{ + static char buf[] = { 0x1b, 'O', 0x00, 0x00 }; + + buf[1] = (mode ? 'O' : '['); + buf[2] = key; + puts_queue(buf); +} + +static void enter(void) +{ + put_queue(13); + if (vc_kbd_mode(kbd,VC_CRLF)) + put_queue(10); +} + +static void caps_toggle(void) +{ + if (rep) + return; + chg_vc_kbd_led(kbd, VC_CAPSLOCK); +} + +static void caps_on(void) +{ + if (rep) + return; + set_vc_kbd_led(kbd, VC_CAPSLOCK); +} + +struct pt_regs *pt_regs; + +static void show_ptregs(void) +{ + if (pt_regs) + show_regs(pt_regs); + return; +} + +static void hold(void) +{ + if (rep || !tty) + return; + + /* + * Note: SCROLLOCK will be set (cleared) by stop_tty (start_tty); + * these routines are also activated by ^S/^Q. + * (And SCROLLOCK can also be set by the ioctl KDSKBLED.) + */ + if (tty->stopped) + start_tty(tty); + else + stop_tty(tty); +} + +static void num(void) +{ + if (vc_kbd_mode(kbd,VC_APPLIC)) + applkey('P', 1); + else + bare_num(); +} + +/* + * Bind this to Shift-NumLock if you work in application keypad mode + * but want to be able to change the NumLock flag. + * Bind this to NumLock if you prefer that the NumLock key always + * changes the NumLock flag. + */ +static void bare_num(void) +{ + if (!rep) + chg_vc_kbd_led(kbd,VC_NUMLOCK); +} + +static void lastcons(void) +{ + /* switch to the last used console, ChN */ + set_console(last_console); +} + +static void decr_console(void) +{ + int i; + + for (i = fg_console-1; i != fg_console; i--) { + if (i == -1) + i = MAX_NR_CONSOLES-1; + if (vc_cons_allocated(i)) + break; + } + set_console(i); +} + +static void incr_console(void) +{ + int i; + + for (i = fg_console+1; i != fg_console; i++) { + if (i == MAX_NR_CONSOLES) + i = 0; + if (vc_cons_allocated(i)) + break; + } + set_console(i); +} + +static void send_intr(void) +{ + if (!tty) + return; + tty_insert_flip_char(tty, 0, TTY_BREAK); + tty_schedule_flip(tty); +} + +static void scroll_forw(void) +{ + scrollfront(0); +} + +static void scroll_back(void) +{ + scrollback(0); +} + +static void boot_it(void) +{ + ctrl_alt_del(); +} + +static void compose(void) +{ + dead_key_next = 1; +} + +int spawnpid, spawnsig; + +static void spawn_console(void) +{ + if (spawnpid) + if(kill_proc(spawnpid, spawnsig, 1)) + spawnpid = 0; +} + +static void SAK(void) +{ + do_SAK(tty); +#if 0 + /* + * Need to fix SAK handling to fix up RAW/MEDIUM_RAW and + * vt_cons modes before we can enable RAW/MEDIUM_RAW SAK + * handling. + * + * We should do this some day --- the whole point of a secure + * attention key is that it should be guaranteed to always + * work. + */ + reset_vc(fg_console); + do_unblank_screen(); /* not in interrupt routine? */ +#endif +} + +static void do_ignore(unsigned char value, char up_flag) +{ +} + +static void do_null() +{ + compute_shiftstate(); +} + +static void do_spec(unsigned char value, char up_flag) +{ + if (up_flag) + return; + if (value >= SIZE(spec_fn_table)) + return; + spec_fn_table[value](); +} + +static void do_lowercase(unsigned char value, char up_flag) +{ + printk("keyboard.c: do_lowercase was called - impossible\n"); +} + +static void do_self(unsigned char value, char up_flag) +{ + if (up_flag) + return; /* no action, if this is a key release */ + + if (diacr) + value = handle_diacr(value); + + if (dead_key_next) { + dead_key_next = 0; + diacr = value; + return; + } + + put_queue(value); +} + +#define A_GRAVE '`' +#define A_ACUTE '\'' +#define A_CFLEX '^' +#define A_TILDE '~' +#define A_DIAER '"' +static unsigned char ret_diacr[] = + {A_GRAVE, A_ACUTE, A_CFLEX, A_TILDE, A_DIAER }; + +/* If a dead key pressed twice, output a character corresponding to it, */ +/* otherwise just remember the dead key. */ + +static void do_dead(unsigned char value, char up_flag) +{ + if (up_flag) + return; + + value = ret_diacr[value]; + if (diacr == value) { /* pressed twice */ + diacr = 0; + put_queue(value); + return; + } + diacr = value; +} + + +/* If space is pressed, return the character corresponding the pending */ +/* dead key, otherwise try to combine the two. */ + +unsigned char handle_diacr(unsigned char ch) +{ + int d = diacr; + int i; + + diacr = 0; + if (ch == ' ') + return d; + + for (i = 0; i < accent_table_size; i++) { + if (accent_table[i].diacr == d && accent_table[i].base == ch) + return accent_table[i].result; + } + + put_queue(d); + return ch; +} + +static void do_cons(unsigned char value, char up_flag) +{ + if (up_flag) + return; + set_console(value); +} + +static void do_fn(unsigned char value, char up_flag) +{ + if (up_flag) + return; + if (value < SIZE(func_table)) { + if (func_table[value]) + puts_queue(func_table[value]); + } else + printk("do_fn called with value=%d\n", value); +} + +static void do_pad(unsigned char value, char up_flag) +{ + static const char *pad_chars = "0123456789+-*/\015,.?"; + static const char *app_map = "pqrstuvwxylSRQMnn?"; + + if (up_flag) + return; /* no action, if this is a key release */ + + /* kludge... shift forces cursor/number keys */ + if (vc_kbd_mode(kbd,VC_APPLIC) && !k_down[KG_SHIFT]) { + applkey(app_map[value], 1); + return; + } + + if (!vc_kbd_led(kbd,VC_NUMLOCK)) + switch (value) { + case KVAL(K_PCOMMA): + case KVAL(K_PDOT): + do_fn(KVAL(K_REMOVE), 0); + return; + case KVAL(K_P0): + do_fn(KVAL(K_INSERT), 0); + return; + case KVAL(K_P1): + do_fn(KVAL(K_SELECT), 0); + return; + case KVAL(K_P2): + do_cur(KVAL(K_DOWN), 0); + return; + case KVAL(K_P3): + do_fn(KVAL(K_PGDN), 0); + return; + case KVAL(K_P4): + do_cur(KVAL(K_LEFT), 0); + return; + case KVAL(K_P6): + do_cur(KVAL(K_RIGHT), 0); + return; + case KVAL(K_P7): + do_fn(KVAL(K_FIND), 0); + return; + case KVAL(K_P8): + do_cur(KVAL(K_UP), 0); + return; + case KVAL(K_P9): + do_fn(KVAL(K_PGUP), 0); + return; + case KVAL(K_P5): + applkey('G', vc_kbd_mode(kbd, VC_APPLIC)); + return; + } + + put_queue(pad_chars[value]); + if (value == KVAL(K_PENTER) && vc_kbd_mode(kbd, VC_CRLF)) + put_queue(10); +} + +static void do_cur(unsigned char value, char up_flag) +{ + static const char *cur_chars = "BDCA"; + if (up_flag) + return; + + applkey(cur_chars[value], vc_kbd_mode(kbd,VC_CKMODE)); +} + +static void do_shift(unsigned char value, char up_flag) +{ + int old_state = shift_state; + + if (rep) + return; + + /* Mimic typewriter: + a CapsShift key acts like Shift but undoes CapsLock */ + if (value == KVAL(K_CAPSSHIFT)) { + value = KVAL(K_SHIFT); + if (!up_flag) + clr_vc_kbd_led(kbd, VC_CAPSLOCK); + } + + if (up_flag) { + /* handle the case that two shift or control + keys are depressed simultaneously */ + if (k_down[value]) + k_down[value]--; + } else + k_down[value]++; + + if (k_down[value]) + shift_state |= (1 << value); + else + shift_state &= ~ (1 << value); + + /* kludge */ + if (up_flag && shift_state != old_state && npadch != -1) { + if (kbd->kbdmode == VC_UNICODE) + to_utf8(npadch & 0xffff); + else + put_queue(npadch & 0xff); + npadch = -1; + } +} + +/* called after returning from RAW mode or when changing consoles - + recompute k_down[] and shift_state from key_down[] */ +/* maybe called when keymap is undefined, so that shiftkey release is seen */ +void compute_shiftstate(void) +{ + int i, j, k, sym, val; + + shift_state = 0; + for(i=0; i < SIZE(k_down); i++) + k_down[i] = 0; + + for(i=0; i < SIZE(key_down); i++) + if(key_down[i]) { /* skip this word if not a single bit on */ + k = i*BITS_PER_LONG; + for(j=0; jledmode = LED_SHOW_IOCTL; + } else + kbd->ledmode = LED_SHOW_FLAGS; + set_leds(); +} + +static struct ledptr { + unsigned int *addr; + unsigned int mask; + unsigned char valid:1; +} ledptrs[3]; + +void register_leds(int console, unsigned int led, + unsigned int *addr, unsigned int mask) { + struct kbd_struct *kbd = kbd_table + console; + if (led < 3) { + ledptrs[led].addr = addr; + ledptrs[led].mask = mask; + ledptrs[led].valid = 1; + kbd->ledmode = LED_SHOW_MEM; + } else + kbd->ledmode = LED_SHOW_FLAGS; +} + +static inline unsigned char getleds(void){ + struct kbd_struct *kbd = kbd_table + fg_console; + unsigned char leds; + + if (kbd->ledmode == LED_SHOW_IOCTL) + return ledioctl; + leds = kbd->ledflagstate; + if (kbd->ledmode == LED_SHOW_MEM) { + if (ledptrs[0].valid) { + if (*ledptrs[0].addr & ledptrs[0].mask) + leds |= 1; + else + leds &= ~1; + } + if (ledptrs[1].valid) { + if (*ledptrs[1].addr & ledptrs[1].mask) + leds |= 2; + else + leds &= ~2; + } + if (ledptrs[2].valid) { + if (*ledptrs[2].addr & ledptrs[2].mask) + leds |= 4; + else + leds &= ~4; + } + } + return leds; +} + +/* + * This routine is the bottom half of the keyboard interrupt + * routine, and runs with all interrupts enabled. It does + * console changing, led setting and copy_to_cooked, which can + * take a reasonably long time. + * + * Aside from timing (which isn't really that important for + * keyboard interrupts as they happen often), using the software + * interrupt routines for this thing allows us to easily mask + * this when we don't want any of the above to happen. Not yet + * used, but this allows for easy and efficient race-condition + * prevention later on. + */ +static void kbd_bh(void) +{ + unsigned char leds = getleds(); + + if (leds != ledstate) { + ledstate = leds; + if (mach_kbd_leds) + mach_kbd_leds(leds); + } +} + +int kbd_init(void) +{ + int i; + struct kbd_struct kbd0; + extern struct tty_driver console_driver; + + kbd0.ledflagstate = kbd0.default_ledflagstate = KBD_DEFLEDS; + kbd0.ledmode = LED_SHOW_FLAGS; + kbd0.lockstate = KBD_DEFLOCK; + kbd0.slockstate = 0; + kbd0.modeflags = KBD_DEFMODE; + kbd0.kbdmode = VC_XLATE; + + for (i = 0 ; i < MAX_NR_CONSOLES ; i++) + kbd_table[i] = kbd0; + + ttytab = console_driver.table; + + init_bh(KEYBOARD_BH, kbd_bh); + mark_bh(KEYBOARD_BH); + + mach_keyb_init (); + + return 0; +} diff -u --recursive --new-file v1.3.93/linux/drivers/char/lp_intern.c linux/drivers/char/lp_intern.c --- v1.3.93/linux/drivers/char/lp_intern.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/char/lp_intern.c Wed Mar 20 19:53:12 1996 @@ -0,0 +1,169 @@ + +/* + * split into mid and low-level for better support of diffent hardware + * by Joerg Dorchain (dorchain@mpi-sb.mpg.de) + * + * Amiga printer device by Michael Rausch (linux@uni-koblenz.de); + * Atari support added by Andreas Schwab (schwab@ls5.informatik.uni-dortmund.de); + * based upon work from + * + * Copyright (C) 1992 by Jim Weigand and Linus Torvalds + * Copyright (C) 1992,1993 by Michael K. Johnson + * - Thanks much to Gunter Windau for pointing out to me where the error + * checking ought to be. + * Copyright (C) 1993 by Nigel Gamble (added interrupt code) + */ + +#include +#include +#include +#ifdef CONFIG_AMIGA +#include +#endif +#ifdef CONFIG_ATARI +#include +#include +#include +#include +#endif + + +static void lp_int_out(int, int); +static int lp_int_busy(int); +static int lp_int_pout(int); +static int lp_int_online(int); +static int lp_int_interrupt(int); + +int lp_internal_init(struct lp_struct *, int, int, int); + + +static void +lp_int_out (int c, int dev) +{ + switch (boot_info.machtype) + { +#ifdef CONFIG_AMIGA + case MACH_AMIGA: + { + int wait = 0; + while (wait != lp_table[dev].wait) wait++; + ciaa.prb = c; + } + break; +#endif +#ifdef CONFIG_ATARI + case MACH_ATARI: + { + int wait = 0; + sound_ym.rd_data_reg_sel = 15; + sound_ym.wd_data = c; + sound_ym.rd_data_reg_sel = 14; + while (wait != lp_table[dev].wait) wait++; + sound_ym.wd_data = sound_ym.rd_data_reg_sel & ~(1 << 5); + while (wait) wait--; + sound_ym.wd_data = sound_ym.rd_data_reg_sel | (1 << 5); + break; + } +#endif + } +} + +static int +lp_int_busy (int dev) +{ + switch (boot_info.machtype) + { +#ifdef CONFIG_AMIGA + case MACH_AMIGA: + return ciab.pra & 1; +#endif +#ifdef CONFIG_ATARI + case MACH_ATARI: + return mfp.par_dt_reg & 1; +#endif + default: + return 0; + } +} + +static int +lp_int_pout (int dev) +{ + switch (boot_info.machtype) + { +#ifdef CONFIG_AMIGA + case MACH_AMIGA: + return ciab.pra & 2; +#endif +#ifdef CONFIG_ATARI + case MACH_ATARI: +#endif + default: + return 0; + } +} + +static int +lp_int_online (int dev) +{ + switch (boot_info.machtype) + { +#ifdef CONFIG_AMIGA + case MACH_AMIGA: + return ciab.pra & 4; +#endif +#ifdef CONFIG_ATARI + case MACH_ATARI: + return !(mfp.par_dt_reg & 1); +#endif + default: + return 0; + } +} + +static int lp_int_interrupt(int dev) +{ + return 1; +} + +int lp_internal_init(struct lp_struct *lp_table, int entry, + int max_lp, int irq) +{ + if (max_lp-entry < 1) + return 0; +#ifdef CONFIG_AMIGA + if (MACH_IS_AMIGA) + { + ciaa.ddrb = 0xff; + ciab.ddra &= 0xf8; + } +#endif +#ifdef CONFIG_ATARI + if (MACH_IS_ATARI) + { + unsigned long flags; + + save_flags(flags); + cli(); + sound_ym.rd_data_reg_sel = 7; + sound_ym.wd_data = (sound_ym.rd_data_reg_sel & 0x3f) | 0xc0; + restore_flags(flags); + } +#endif + lp_table[entry].name = "Builtin LP"; + lp_table[entry].lp_out = lp_int_out; + lp_table[entry].lp_is_busy = lp_int_busy; + lp_table[entry].lp_has_pout = lp_int_pout; + lp_table[entry].lp_is_online = lp_int_online; + lp_table[entry].lp_my_interrupt = lp_int_interrupt; + lp_table[entry].flags = LP_EXIST; + lp_table[entry].chars = LP_INIT_CHAR; + lp_table[entry].time = LP_INIT_TIME; + lp_table[entry].wait = LP_INIT_WAIT; + lp_table[entry].lp_wait_q = NULL; + + printk("lp%d: internal port\n", entry); + + return 1; +} + diff -u --recursive --new-file v1.3.93/linux/drivers/char/lp_m68k.c linux/drivers/char/lp_m68k.c --- v1.3.93/linux/drivers/char/lp_m68k.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/char/lp_m68k.c Fri Apr 19 02:41:15 1996 @@ -0,0 +1,492 @@ +/* + * split in two parts for better support of different hardware + * by Joerg Dorchain (dorchain@mpi-sb.mpg.de) + * + * Amiga printer device by Michael Rausch (linux@uni-koblenz.de); + * Atari support added by Andreas Schwab (schwab@ls5.informatik.uni-dortmund.de); + * based upon work from + * + * Copyright (C) 1992 by Jim Weigand and Linus Torvalds + * Copyright (C) 1992,1993 by Michael K. Johnson + * - Thanks much to Gunter Windau for pointing out to me where the error + * checking ought to be. + * Copyright (C) 1993 by Nigel Gamble (added interrupt code) + */ + +/* 01/17/95: Matthias Welwarsky (dg8y@rs11.hrz.th-darmstadt.de) + * lp_write(): rewritten from scratch + * lp_interrupt(): fixed cli()/sti()-bug + * + * 95/05/28: Andreas Schwab (schwab@issan.informatik.uni-dortmund.de) + * lp_write() fixed to make it work again. + * 95/08/18: Andreas Schwab + * lp_write_interrupt: fix race condition + * + * * CAUTION, please do check! * + * + * on 68000-based machines sti() must NEVER appear in interrupt driven + * code. The 68k-CPU has a priority-based interrupt scheme. while an interrupt + * with a certain priority is executed, all requests with lower or same + * priority get locked out. executing the sti()-macro allows ANY interrupt + * to be served. this really causes BIG trouble! + * to protect an interrupt driven routine against beeing interrupted + * (if absolutely needed!) one should use save_flags();cli()/restore_flags()! + * + */ + +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_AMIGA +#include +#ifdef CONFIG_MULTIFACE_III_LP +#include +#endif +#endif +#ifdef CONFIG_ATARI +#include +#include +#endif + +#include +#include +#include +#include + +#include +#include + + +/* + * why bother around with the pio driver when the interrupt works; + * so, for "security" reasons only, it's configurable here. + * saves some bytes, at least ... + */ +#define FORCE_POLLING 0 +#define FORCE_INTERRUPT 1 +#define PREFER_INTERRUPT 2 + +#define WHICH_DRIVER FORCE_INTERRUPT + +#define MAX_LP 3 /* the maximum number of devices */ + +struct lp_struct lp_table[MAX_LP] = {{0,},}; + +static int max_lp; /* the real number of devices */ + +/* + * All my debugging code assumes that you debug with only one printer at + * a time. RWWH + */ + +#define LP_DEBUG +#undef LP_DEBUG + + +#if WHICH_DRIVER != FORCE_INTERRUPT +#ifdef LP_DEBUG +static int lp_max_count = 1; +#endif + +static int lp_char_polled(char lpchar, int dev) +{ + unsigned long count = 0; + + do { + count ++; + if(need_resched) + schedule(); + } while (lp_table[dev].lp_is_busy(dev) && count < lp_table[dev].chars); + + if (count == lp_table[dev].chars) { + return 0; + /* we timed out, and the character was /not/ printed */ + } +#ifdef LP_DEBUG + if (count > lp_max_count) { + printk("lp success after %d counts.\n",count); + lp_max_count = count; + } +#endif + lp_table[dev].lp_out(lpchar, dev); + return 1; +} +#endif + + +#ifdef LP_DEBUG +unsigned int lp_total_chars = 0; +unsigned int lp_last_call = 0; +#endif + + +#if WHICH_DRIVER != FORCE_POLLING +static __inline__ int lp_char_interrupt(char lpchar, int dev) +{ + if (!lp_table[dev].lp_is_busy(dev)) { + lp_table[dev].lp_out(lpchar,dev); + return 1; + } + return 0; +} + +static int lp_error; + +static void lp_interrupt(int irq, struct pt_regs *fp, void *dummy) +{ + unsigned long flags; + int dev; + + for (dev = 0; dev < max_lp; dev++) { + if (lp_table[dev].lp_my_interrupt(dev) != 0) + if (lp_table[dev].do_print) + { + if (lp_table[dev].copy_size) + { + save_flags(flags); + cli(); + if (lp_char_interrupt(lp_table[dev].lp_buffer[lp_table[dev].bytes_written], dev)) { + --lp_table[dev].copy_size; + ++lp_table[dev].bytes_written; + restore_flags(flags); + } + else + { + lp_table[dev].do_print = 0; + restore_flags(flags); + lp_error = 1; + wake_up_interruptible(&lp_table[dev].lp_wait_q); + } + } + else + { + lp_table[dev].do_print = 0; + lp_error = 0; + wake_up_interruptible(&lp_table[dev].lp_wait_q); + } + + } + } +} + +#if WHICH_DRIVER == FORCE_INTERRUPT +static int lp_write(struct inode *inode, struct file *file, + const char *buf, int count) +#else +static int lp_write_interrupt(struct inode *inode, struct file *file, + const char *buf, int count) +#endif +{ + unsigned long total_bytes_written = 0; + unsigned int flags; + int rc; + int dev = MINOR(inode->i_rdev); + + do { + lp_table[dev].do_print = 0; /* disable lp_interrupt() */ + lp_table[dev].bytes_written = 0; /* init buffer read-pointer */ + lp_error = 0; + lp_table[dev].copy_size = (count <= LP_BUFFER_SIZE ? count : LP_BUFFER_SIZE); + memcpy_fromfs(lp_table[dev].lp_buffer, buf, lp_table[dev].copy_size); + while (lp_table[dev].copy_size) { + save_flags(flags); + cli(); /* no interrupts now */ + lp_table[dev].do_print = 1; /* enable lp_interrupt() */ + if (lp_char_interrupt(lp_table[dev].lp_buffer[lp_table[dev].bytes_written], dev)) { + ++lp_table[dev].bytes_written; + --lp_table[dev].copy_size; + lp_error = 0; + } else { /* something went wrong */ + lp_table[dev].do_print = 0; /* disable lp_interrupt() */ + lp_error = 1; /* printer caused error */ + } + if (lp_error) { + + /* something blocked printing, so we don't want to sleep too long, + in case we have to rekick the interrupt */ + + current->timeout = jiffies + LP_TIMEOUT_POLLED; + } else { + current->timeout = jiffies + LP_TIMEOUT_INTERRUPT; + } + + interruptible_sleep_on(&lp_table[dev].lp_wait_q); + restore_flags(flags); + + /* we're up again and running. we first disable lp_interrupt(), then + check what happened meanwhile */ + + lp_table[dev].do_print = 0; + rc = total_bytes_written + lp_table[dev].bytes_written; + + if (current->signal & ~current->blocked) { + if (rc) + return rc; + else + return -EINTR; + } + if (lp_error) { + + /* an error has occured, maybe in lp_interrupt(). + figure out the type of error, exit on request or if nothing has + been printed at all. */ + + if (lp_table[dev].lp_has_pout(dev)) { + printk("lp%d: paper-out\n",dev); + if (!rc) rc = -ENOSPC; + } else if (!lp_table[dev].lp_is_online(dev)) { + printk("lp%d: off-line\n",dev); + if (!rc) rc = -EIO; + } else if (lp_table[dev].lp_is_busy(dev)) { + printk("lp%d: on fire\n",dev); + if (!rc) rc = -EIO; + } + if (lp_table[dev].flags & LP_ABORT) + return rc; + } + /* check if our buffer was completely printed, if not, most likely + an unsolved error blocks the printer. As we can`t do anything + against, we start all over again. Else we set the read-pointer + of the buffer and count the printed characters */ + + if (!lp_table[dev].copy_size) { + total_bytes_written += lp_table[dev].bytes_written; + buf += lp_table[dev].bytes_written; + count -= lp_table[dev].bytes_written; + } + } + } while (count > 0); + return total_bytes_written; +} +#endif + +#if WHICH_DRIVER != FORCE_INTERRUPT +#if WHICH_DRIVER == FORCE_POLLING +static int lp_write(struct inode *inode, struct file *file, + const char *buf, int count) +#else +static int lp_write_polled(struct inode *inode, struct file *file, + const char *buf, int count) +#endif +{ + char *temp = buf; + int dev = MINOR(inode->i_rdev); + +#ifdef LP_DEBUG + if (jiffies-lp_last_call > lp_table[dev].time) { + lp_total_chars = 0; + lp_max_count = 1; + } + lp_last_call = jiffies; +#endif + + temp = buf; + while (count > 0) { + if (lp_char_polled(get_user(temp), dev)) { + /* only update counting vars if character was printed */ + count--; temp++; +#ifdef LP_DEBUG + lp_total_chars++; +#endif + } else { /* if printer timed out */ + if (lp_table[dev].lp_has_pout(dev)) { + printk("lp%d: out of paper\n",dev); + if (lp_table[dev].flags & LP_ABORT) + return temp - buf ? temp-buf : -ENOSPC; + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + LP_TIMEOUT_POLLED; + schedule(); + } else if (!lp_table[dev].lp_is_online(dev)) { + printk("lp%d: off-line\n",dev); + if (lp_table[dev].flags & LP_ABORT) + return temp - buf ? temp-buf : -EIO; + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + LP_TIMEOUT_POLLED; + schedule(); + } else + /* not offline or out of paper. on fire? */ + if (lp_table[dev].lp_is_busy(dev)) { + printk("lp%d: on fire\n",dev); + if (lp_table[dev].flags & LP_ABORT) + return temp - buf ? temp-buf : -EFAULT; + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + LP_TIMEOUT_POLLED; + schedule(); + } + + /* check for signals before going to sleep */ + if (current->signal & ~current->blocked) { + if (temp != buf) + return temp-buf; + else + return -EINTR; + } +#ifdef LP_DEBUG + printk("lp sleeping at %d characters for %d jiffies\n", + lp_total_chars, lp_table[dev].time); + lp_total_chars = 0; +#endif + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + lp_table[dev].time; + schedule(); + } + } + return temp - buf; +} +#endif + +static unsigned int lp_irq = 0; + +#if WHICH_DRIVER == PREFER_INTERRUPT +static int lp_write(struct inode *inode, struct file *file, + const char *buf, int count) +{ + if (lp_irq) + return lp_write_interrupt(inode, file, buf, count); + else + return lp_write_polled(inode, file, buf, count); +} +#endif + +static int lp_lseek(struct inode *inode, struct file *file, + off_t offset, int origin) +{ + return -ESPIPE; +} + +static int lp_open(struct inode *inode, struct file *file) +{ + int dev = MINOR(inode->i_rdev); + + if (dev >= max_lp) + return -ENODEV; + if (!(lp_table[dev].flags & LP_EXIST)) + return -ENODEV; + if (lp_table[dev].flags & LP_BUSY) + return -EBUSY; + + lp_table[dev].flags |= LP_BUSY; + + return 0; +} + +static void lp_release(struct inode *inode, struct file *file) +{ + lp_table[MINOR(inode->i_rdev)].flags &= ~LP_BUSY; +} + + +static int lp_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + unsigned int minor = MINOR(inode->i_rdev); + int retval = 0; + +#ifdef LP_DEBUG + printk("lp%d ioctl, cmd: 0x%x, arg: 0x%x\n", minor, cmd, arg); +#endif + if (minor >= max_lp) + return -ENODEV; + if (!(lp_table[minor].flags & LP_EXIST)) + return -ENODEV; + switch (cmd) { + case LPTIME: + lp_table[minor].time = arg; + break; + case LPCHAR: + lp_table[minor].chars = arg; + break; + case LPABORT: + if (arg) + lp_table[minor].flags |= LP_ABORT; + else + lp_table[minor].flags &= ~LP_ABORT; + break; + case LPWAIT: + lp_table[minor].wait = arg; + break; + case LPSETIRQ: + case LPGETIRQ: + retval = lp_irq; + break; + default: + retval = -EINVAL; + } + return retval; +} + + +static struct file_operations lp_fops = { + lp_lseek, + NULL, /* lp_read */ + lp_write, + NULL, /* lp_readdir */ + NULL, /* lp_select */ + lp_ioctl, + NULL, /* lp_mmap */ + lp_open, + lp_release +}; + + +int lp_init(void) +{ + extern char m68k_debug_device[]; + + if (!strcmp( m68k_debug_device, "par" )) + return -EBUSY; + + if (register_chrdev(LP_MAJOR,"lp", &lp_fops)) { + printk("unable to get major %d for line printer\n", LP_MAJOR); + return -EBUSY; + } + +#if WHICH_DRIVER == FORCE_POLLING + lp_irq = 0; + printk("lp_init: lp using polling driver\n"); +#else + +#ifdef CONFIG_AMIGA + if (MACH_IS_AMIGA && AMIGAHW_PRESENT(AMI_PARALLEL)) + lp_irq = add_isr(IRQ_AMIGA_CIAA_FLG, lp_interrupt, 0, + NULL, "printer"); +#endif +#ifdef CONFIG_ATARI + if (MACH_IS_ATARI) + lp_irq = add_isr(IRQ_MFP_BUSY, lp_interrupt, IRQ_TYPE_SLOW, + NULL, "printer"); +#endif + + if (lp_irq) + printk("lp_init: lp using interrupt\n"); + else + +#if WHICH_DRIVER == PREFER_INTERRUPT + printk("lp_init: lp using polling driver\n"); +#else + printk("lp_init: cant get interrupt, and polling driver not configured\n"); +#endif +#endif + + max_lp = 0; + max_lp += lp_internal_init(lp_table, max_lp, MAX_LP, WHICH_DRIVER); +#ifdef CONFIG_MULTIFACE_III_LP + max_lp += lp_mfc_init(lp_table, max_lp, MAX_LP, WHICH_DRIVER); +#if WHICH_DRIVER != FORCE_POLLING + add_isr(IRQ_AMIGA_PORTS, lp_interrupt, 0, NULL, + "Multiface III printer"); +#endif +#endif + return 0; +} + +/* + * Currently we do not accept any lp-parameters, but that may change. + */ +void lp_setup(char *str, int *ints) +{ +} diff -u --recursive --new-file v1.3.93/linux/drivers/char/riscom8.c linux/drivers/char/riscom8.c --- v1.3.93/linux/drivers/char/riscom8.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/char/riscom8.c Mon Apr 22 07:14:01 1996 @@ -0,0 +1,1899 @@ +/* + * linux/drivers/char/riscom.c -- RISCom/8 multiport serial driver. + * + * Copyright (C) 1994-1996 Dmitry Gorodchanin (begemot@bgm.rosprint.net) + * + * This code is loosely based on the Linux serial driver, written by + * Linus Torvalds, Theodore T'so and others. The RISCom/8 card + * programming info was obtained from various drivers for other OSes + * (FreeBSD, ISC, etc), but no source code from those drivers were + * directly included in this drvier. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Revision 1.0 + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "riscom8.h" +#include "riscom8_reg.h" + +/* Am I paranoid or not ? ;-) */ +#define RISCOM_PARANOIA_CHECK + +/* + * Crazy InteliCom/8 boards sometimes has swapped CTS & DSR signals. + * You can slightly speed up things by #undefing the following option, + * if you are REALLY sure that your board is correct one. + */ + +#define RISCOM_BRAIN_DAMAGED_CTS + +/* + * The following defines are mostly for testing purposes. But if you need + * some nice reporting in your syslog, you can define them also. + */ +#undef RC_REPORT_FIFO +#undef RC_REPORT_OVERRUN + + +#define RISCOM_LEGAL_FLAGS \ + (ASYNC_HUP_NOTIFY | ASYNC_SAK | ASYNC_SPLIT_TERMIOS | \ + ASYNC_SPD_HI | ASYNC_SPEED_VHI | ASYNC_SESSION_LOCKOUT | \ + ASYNC_PGRP_LOCKOUT | ASYNC_CALLOUT_NOHUP) + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +DECLARE_TASK_QUEUE(tq_riscom); + +#define RISCOM_TYPE_NORMAL 1 +#define RISCOM_TYPE_CALLOUT 2 + +static struct riscom_board * IRQ_to_board[16] = { NULL, } ; +static struct tty_driver riscom_driver, riscom_callout_driver; +static int riscom_refcount = 0; +static struct tty_struct * riscom_table[RC_NBOARD * RC_NPORT] = { NULL, }; +static struct termios * riscom_termios[RC_NBOARD * RC_NPORT] = { NULL, }; +static struct termios * riscom_termios_locked[RC_NBOARD * RC_NPORT] = { NULL, }; +static unsigned char * tmp_buf = NULL; +static struct semaphore tmp_buf_sem = MUTEX; + +static unsigned long baud_table[] = { + 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, + 9600, 19200, 38400, 57600, 76800, 0, +}; + +static struct riscom_board rc_board[RC_NBOARD] = { + { 0, RC_IOBASE1, 0, }, + { 0, RC_IOBASE2, 0, }, + { 0, RC_IOBASE3, 0, }, + { 0, RC_IOBASE4, 0, }, +}; + +static struct riscom_port rc_port[RC_NBOARD * RC_NPORT] = { + { 0, }, +}; + +/* RISCom/8 I/O ports addresses (without address translation) */ +static unsigned short rc_ioport[] = { +#if 1 + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x09, 0x0a, 0x0b, 0x0c, +#else + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x09, 0x0a, 0x0b, 0x0c, 0x10, + 0x11, 0x12, 0x18, 0x28, 0x31, 0x32, 0x39, 0x3a, 0x40, 0x41, 0x61, 0x62, + 0x63, 0x64, 0x6b, 0x70, 0x71, 0x78, 0x7a, 0x7b, 0x7f, 0x100, 0x101 +#endif +}; +#define RC_NIOPORT (sizeof(rc_ioport) / sizeof(rc_ioport[0])) + + +static inline int rc_paranoia_check(struct riscom_port const * port, + kdev_t device, const char *routine) +{ +#ifdef RISCOM_PARANOIA_CHECK + static const char *badmagic = + "rc: Warning: bad riscom port magic number for device %s in %s\n"; + static const char *badinfo = + "rc: Warning: null riscom port for device %s in %s\n"; + + if (!port) { + printk(badinfo, kdevname(device), routine); + return 1; + } + if (port->magic != RISCOM8_MAGIC) { + printk(badmagic, kdevname(device), routine); + return 1; + } +#endif + return 0; +} + +/* + * + * Service functions for RISCom/8 driver. + * + */ + +/* Get board number from pointer */ +extern inline int board_No (struct riscom_board const * bp) +{ + return bp - rc_board; +} + +/* Get port number from pointer */ +extern inline int port_No (struct riscom_port const * port) +{ + return RC_PORT(port - rc_port); +} + +/* Get pointer to board from pointer to port */ +extern inline struct riscom_board * port_Board(struct riscom_port const * port) +{ + return &rc_board[RC_BOARD(port - rc_port)]; +} + +/* Input Byte from CL CD180 register */ +extern inline unsigned char rc_in(struct riscom_board const * bp, unsigned short reg) +{ + return inb(bp->base + RC_TO_ISA(reg)); +} + +/* Output Byte to CL CD180 register */ +extern inline void rc_out(struct riscom_board const * bp, unsigned short reg, + unsigned char val) +{ + outb(val, bp->base + RC_TO_ISA(reg)); +} + +/* Wait for Chanel Command Register ready */ +extern inline void rc_wait_CCR(struct riscom_board const * bp) +{ + unsigned long delay; + + /* FIXME: need something more descriptive then 100000 :) */ + for (delay = 100000; delay; delay--) + if (!rc_in(bp, CD180_CCR)) + return; + + printk("rc%d: Timeout waiting for CCR.\n", board_No(bp)); +} + +/* + * RISCom/8 probe functions. + */ + +extern inline int rc_check_io_range(struct riscom_board * const bp) +{ + int i; + + for (i = 0; i < RC_NIOPORT; i++) + if (check_region(RC_TO_ISA(rc_ioport[i]) + bp->base, 1)) { + printk("rc%d: Skipping probe at 0x%03x. I/O adress in use.\n", + board_No(bp), bp->base); + return 1; + } + return 0; +} + +extern inline void rc_request_io_range(struct riscom_board * const bp) +{ + int i; + + for (i = 0; i < RC_NIOPORT; i++) + request_region(RC_TO_ISA(rc_ioport[i]) + bp->base, 1, "RISCom/8" ); +} + +extern inline void rc_release_io_range(struct riscom_board * const bp) +{ + int i; + + for (i = 0; i < RC_NIOPORT; i++) + release_region(RC_TO_ISA(rc_ioport[i]) + bp->base, 1); +} + + +/* Must be called with enabled interrupts */ +extern inline void rc_long_delay(unsigned long delay) +{ + unsigned long i; + + for (i = jiffies + delay; i > jiffies; ) ; +} + +/* Reset and setup CD180 chip */ +static void rc_init_CD180(struct riscom_board const * bp) +{ + unsigned long flags; + + save_flags(flags); cli(); + rc_out(bp, RC_CTOUT, 0); /* Clear timeout */ + rc_wait_CCR(bp); /* Wait for CCR ready */ + rc_out(bp, CD180_CCR, CCR_HARDRESET); /* Reset CD180 chip */ + sti(); + rc_long_delay(HZ/20); /* Delay 0.05 sec */ + cli(); + rc_out(bp, CD180_GIVR, RC_ID); /* Set ID for this chip */ + rc_out(bp, CD180_GICR, 0); /* Clear all bits */ + rc_out(bp, CD180_PILR1, RC_ACK_MINT); /* Prio for modem intr */ + rc_out(bp, CD180_PILR2, RC_ACK_TINT); /* Prio for transmitter intr */ + rc_out(bp, CD180_PILR3, RC_ACK_RINT); /* Prio for receiver intr */ + + /* Setting up prescaler. We need 4 ticks per 1 ms */ + rc_out(bp, CD180_PPRH, (RC_OSCFREQ/(1000000/RISCOM_TPS)) >> 8); + rc_out(bp, CD180_PPRL, (RC_OSCFREQ/(1000000/RISCOM_TPS)) & 0xff); + + restore_flags(flags); +} + +/* Main probing routine, also sets irq. */ +static int rc_probe(struct riscom_board *bp) +{ + unsigned char val1, val2; + int irqs = 0; + int retries; + + bp->irq = 0; + + if (rc_check_io_range(bp)) + return 1; + + /* Are the I/O ports here ? */ + rc_out(bp, CD180_PPRL, 0x5a); + outb(0xff, 0x80); + val1 = rc_in(bp, CD180_PPRL); + rc_out(bp, CD180_PPRL, 0xa5); + outb(0x00, 0x80); + val2 = rc_in(bp, CD180_PPRL); + + if ((val1 != 0x5a) || (val2 != 0xa5)) { + printk("rc%d: RISCom/8 Board at 0x%03x not found.\n", + board_No(bp), bp->base); + return 1; + } + + /* It's time to find IRQ for this board */ + for (retries = 0; retries < 5 && irqs <= 0; retries++) { + irqs = probe_irq_on(); + rc_init_CD180(bp); /* Reset CD180 chip */ + rc_out(bp, CD180_CAR, 2); /* Select port 2 */ + rc_wait_CCR(bp); + rc_out(bp, CD180_CCR, CCR_TXEN); /* Enable transmitter */ + rc_out(bp, CD180_IER, IER_TXRDY); /* Enable tx empty intr */ + rc_long_delay(HZ/20); + irqs = probe_irq_off(irqs); + val1 = rc_in(bp, RC_BSR); /* Get Board Status reg */ + val2 = rc_in(bp, RC_ACK_TINT); /* ACK interrupt */ + rc_init_CD180(bp); /* Reset CD180 again */ + + if ((val1 & RC_BSR_TINT) || (val2 != (RC_ID | GIVR_IT_TX))) { + printk("rc%d: RISCom/8 Board at 0x%03x not found.\n", + board_No(bp), bp->base); + return 1; + } + } + + if (irqs <= 0) { + printk("rc%d: Can't find IRQ for RISCom/8 board at 0x%03x.\n", + board_No(bp), bp->base); + return 1; + } + rc_request_io_range(bp); + bp->irq = irqs; + bp->flags |= RC_BOARD_PRESENT; + + printk("rc%d: RISCom/8 Rev. %c board detected at 0x%03x, IRQ %d.\n", + board_No(bp), + (rc_in(bp, CD180_GFRCR) & 0x0f) + 'A', /* Board revision */ + bp->base, bp->irq); + + return 0; +} + +/* + * + * Inerrupt processing routines. + * + */ + +extern inline void rc_mark_event(struct riscom_port * port, int event) +{ + /* + * I'm not quite happy with current scheme all serial + * drivers use their own BH routine. + * It seem's this easily can be done with one BH routine + * serving for all serial drivers. + * For now I must introduce another one - RISCOM8_BH. + * Still hope this will be changed in near future. + */ + set_bit(event, &port->event); + queue_task_irq_off(&port->tqueue, &tq_riscom); + mark_bh(RISCOM8_BH); +} + +extern inline struct riscom_port * rc_get_port(struct riscom_board const * bp, + unsigned char const * what) +{ + unsigned char channel; + struct riscom_port * port; + + channel = rc_in(bp, CD180_GICR) >> GICR_CHAN_OFF; + if (channel < CD180_NCH) { + port = &rc_port[board_No(bp) * RC_NPORT + channel]; + if (port->flags & ASYNC_INITIALIZED) { + return port; + } + } + printk("rc%d: %s interrupt from invalid port %d\n", + board_No(bp), what, channel); + return NULL; +} + +extern inline void rc_receive_exc(struct riscom_board const * bp) +{ + struct riscom_port *port; + struct tty_struct *tty; + unsigned char status; + unsigned char ch; + + if (!(port = rc_get_port(bp, "Receive"))) + return; + + tty = port->tty; + if (tty->flip.count >= TTY_FLIPBUF_SIZE) { + printk("rc%d: port %d: Working around flip buffer overflow.\n", + board_No(bp), port_No(port)); + return; + } + +#ifdef RC_REPORT_OVERRUN + status = rc_in(bp, CD180_RCSR); + if (status & RCSR_OE) { + port->overrun++; +#if 0 + printk("rc%d: port %d: Overrun. Total %ld overruns.\n", + board_No(bp), port_No(port), port->overrun); +#endif + } + status &= port->mark_mask; +#else + status = rc_in(bp, CD180_RCSR) & port->mark_mask; +#endif + ch = rc_in(bp, CD180_RDR); + if (!status) { + return; + } + if (status & RCSR_TOUT) { + printk("rc%d: port %d: Receiver timeout. Hardware problems ?\n", + board_No(bp), port_No(port)); + return; + + } else if (status & RCSR_BREAK) { + printk("rc%d: port %d: Handling break...\n", + board_No(bp), port_No(port)); + *tty->flip.flag_buf_ptr++ = TTY_BREAK; + if (port->flags & ASYNC_SAK) + do_SAK(tty); + + } else if (status & RCSR_PE) + *tty->flip.flag_buf_ptr++ = TTY_PARITY; + + else if (status & RCSR_FE) + *tty->flip.flag_buf_ptr++ = TTY_FRAME; + + else if (status & RCSR_OE) + *tty->flip.flag_buf_ptr++ = TTY_OVERRUN; + + else + *tty->flip.flag_buf_ptr++ = 0; + + *tty->flip.char_buf_ptr++ = ch; + tty->flip.count++; + queue_task_irq_off(&tty->flip.tqueue, &tq_timer); +} + +extern inline void rc_receive(struct riscom_board const * bp) +{ + struct riscom_port *port; + struct tty_struct *tty; + unsigned char count; + + if (!(port = rc_get_port(bp, "Receive"))) + return; + + tty = port->tty; + + count = rc_in(bp, CD180_RDCR); + +#ifdef RC_REPORT_FIFO + port->hits[count > 8 ? 9 : count]++; +#endif + + while (count--) { + if (tty->flip.count >= TTY_FLIPBUF_SIZE) { + printk("rc%d: port %d: Working around flip buffer overflow.\n", + board_No(bp), port_No(port)); + break; + } + *tty->flip.char_buf_ptr++ = rc_in(bp, CD180_RDR); + *tty->flip.flag_buf_ptr++ = 0; + tty->flip.count++; + } + queue_task_irq_off(&tty->flip.tqueue, &tq_timer); +} + +extern inline void rc_transmit(struct riscom_board const * bp) +{ + struct riscom_port *port; + struct tty_struct *tty; + unsigned char count; + + + if (!(port = rc_get_port(bp, "Transmit"))) + return; + + tty = port->tty; + + if (port->IER & IER_TXEMPTY) { + /* FIFO drained */ + rc_out(bp, CD180_CAR, port_No(port)); + port->IER &= ~IER_TXEMPTY; + rc_out(bp, CD180_IER, port->IER); + return; + } + + if ((port->xmit_cnt <= 0 && !port->break_length) + || tty->stopped || tty->hw_stopped) { + rc_out(bp, CD180_CAR, port_No(port)); + port->IER &= ~IER_TXRDY; + rc_out(bp, CD180_IER, port->IER); + return; + } + + if (port->break_length) { + if (port->break_length > 0) { + if (port->COR2 & COR2_ETC) { + rc_out(bp, CD180_TDR, CD180_C_ESC); + rc_out(bp, CD180_TDR, CD180_C_SBRK); + port->COR2 &= ~COR2_ETC; + } + count = MIN(port->break_length, 0xff); + rc_out(bp, CD180_TDR, CD180_C_ESC); + rc_out(bp, CD180_TDR, CD180_C_DELAY); + rc_out(bp, CD180_TDR, count); + if (!(port->break_length -= count)) + port->break_length--; + } else { + rc_out(bp, CD180_TDR, CD180_C_ESC); + rc_out(bp, CD180_TDR, CD180_C_EBRK); + rc_out(bp, CD180_COR2, port->COR2); + rc_wait_CCR(bp); + rc_out(bp, CD180_CCR, CCR_CORCHG2); + port->break_length = 0; + } + return; + } + + count = CD180_NFIFO; + do { + rc_out(bp, CD180_TDR, port->xmit_buf[port->xmit_tail++]); + port->xmit_tail = port->xmit_tail & (SERIAL_XMIT_SIZE-1); + if (--port->xmit_cnt <= 0) + break; + } while (--count > 0); + + if (port->xmit_cnt <= 0) { + rc_out(bp, CD180_CAR, port_No(port)); + port->IER &= ~IER_TXRDY; + rc_out(bp, CD180_IER, port->IER); + } + if (port->xmit_cnt <= port->wakeup_chars) + rc_mark_event(port, RS_EVENT_WRITE_WAKEUP); +} + +extern inline void rc_check_modem(struct riscom_board const * bp) +{ + struct riscom_port *port; + struct tty_struct *tty; + unsigned char mcr; + + if (!(port = rc_get_port(bp, "Modem"))) + return; + + tty = port->tty; + + mcr = rc_in(bp, CD180_MCR); + if (mcr & MCR_CDCHG) { + if (rc_in(bp, CD180_MSVR) & MSVR_CD) + wake_up_interruptible(&port->open_wait); + else if (!((port->flags & ASYNC_CALLOUT_ACTIVE) && + (port->flags & ASYNC_CALLOUT_NOHUP))) + queue_task_irq_off(&port->tqueue_hangup, + &tq_scheduler); + } + +#ifdef RISCOM_BRAIN_DAMAGED_CTS + if (mcr & MCR_CTSCHG) { + if (rc_in(bp, CD180_MSVR) & MSVR_CTS) { + tty->hw_stopped = 0; + port->IER |= IER_TXRDY; + if (port->xmit_cnt <= port->wakeup_chars) + rc_mark_event(port, RS_EVENT_WRITE_WAKEUP); + } else { + tty->hw_stopped = 1; + port->IER &= ~IER_TXRDY; + } + rc_out(bp, CD180_IER, port->IER); + } + if (mcr & MCR_DSRCHG) { + if (rc_in(bp, CD180_MSVR) & MSVR_DSR) { + tty->hw_stopped = 0; + port->IER |= IER_TXRDY; + if (port->xmit_cnt <= port->wakeup_chars) + rc_mark_event(port, RS_EVENT_WRITE_WAKEUP); + } else { + tty->hw_stopped = 1; + port->IER &= ~IER_TXRDY; + } + rc_out(bp, CD180_IER, port->IER); + } +#endif /* RISCOM_BRAIN_DAMAGED_CTS */ + + /* Clear change bits */ + rc_out(bp, CD180_MCR, 0); +} + +/* The main interrupt processing routine */ +static void rc_interrupt(int irq, void * dev_id, struct pt_regs * regs) +{ + unsigned char status; + unsigned char ack; + struct riscom_board *bp; + unsigned long loop = 0; + + bp = IRQ_to_board[irq]; + + if (!bp || !(bp->flags & RC_BOARD_ACTIVE)) { + return; + } + + while ((++loop < 16) && ((status = ~(rc_in(bp, RC_BSR))) & + (RC_BSR_TOUT | RC_BSR_TINT | + RC_BSR_MINT | RC_BSR_RINT))) { + + if (status & RC_BSR_TOUT) + printk("rc%d: Got timeout. Hardware error ?\n", board_No(bp)); + + else if (status & RC_BSR_RINT) { + ack = rc_in(bp, RC_ACK_RINT); + + if (ack == (RC_ID | GIVR_IT_RCV)) + rc_receive(bp); + else if (ack == (RC_ID | GIVR_IT_REXC)) + rc_receive_exc(bp); + else + printk("rc%d: Bad receive ack 0x%02x.\n", + board_No(bp), ack); + + } else if (status & RC_BSR_TINT) { + ack = rc_in(bp, RC_ACK_TINT); + + if (ack == (RC_ID | GIVR_IT_TX)) + rc_transmit(bp); + else + printk("rc%d: Bad transmit ack 0x%02x.\n", + board_No(bp), ack); + + } else /* if (status & RC_BSR_MINT) */ { + ack = rc_in(bp, RC_ACK_MINT); + + if (ack == (RC_ID | GIVR_IT_MODEM)) + rc_check_modem(bp); + else + printk("rc%d: Bad modem ack 0x%02x.\n", + board_No(bp), ack); + + } + + rc_out(bp, CD180_EOIR, 0); /* Mark end of interrupt */ + rc_out(bp, RC_CTOUT, 0); /* Clear timeout flag */ + } +} + +/* + * Routines for open & close processing. + */ + +/* Called with disabled interrupts */ +extern inline int rc_setup_board(struct riscom_board * bp) +{ + int error; + + if (bp->flags & RC_BOARD_ACTIVE) + return 0; + + error = request_irq(bp->irq, rc_interrupt, SA_INTERRUPT, "RISCom/8", NULL); + if (error) + return error; + + rc_out(bp, RC_CTOUT, 0); /* Just in case */ + bp->DTR = ~0; + rc_out(bp, RC_DTR, bp->DTR); /* Drop DTR on all ports */ + + IRQ_to_board[bp->irq] = bp; + bp->flags |= RC_BOARD_ACTIVE; + + MOD_INC_USE_COUNT; + return 0; +} + +/* Called with disabled interrupts */ +extern inline void rc_shutdown_board(struct riscom_board *bp) +{ + if (!(bp->flags & RC_BOARD_ACTIVE)) + return; + + bp->flags &= ~RC_BOARD_ACTIVE; + + free_irq(bp->irq, NULL); + IRQ_to_board[bp->irq] = NULL; + + bp->DTR = ~0; + rc_out(bp, RC_DTR, bp->DTR); /* Drop DTR on all ports */ + + MOD_DEC_USE_COUNT; +} + +/* + * Setting up port characteristics. + * Must be called with disabled interupts + */ +static void rc_change_speed(struct riscom_board *bp, struct riscom_port *port) +{ + struct tty_struct *tty; + unsigned long baud; + long tmp; + unsigned char cor1 = 0, cor3 = 0; + unsigned char mcor1 = 0, mcor2 = 0; + + if (!(tty = port->tty) || !tty->termios) + return; + + port->IER = 0; + port->COR2 = 0; + port->MSVR = MSVR_RTS; + + baud = C_BAUD(tty); + + if (baud & CBAUDEX) { + baud &= ~CBAUDEX; + if (baud < 1 || baud > 2) + port->tty->termios->c_cflag &= ~CBAUDEX; + else + baud += 15; + } + if (baud == 15) { + if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + baud ++; + if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + baud += 2; + } + + /* Select port on the board */ + rc_out(bp, CD180_CAR, port_No(port)); + + if (!baud_table[baud]) { + /* Drop DTR & exit */ + bp->DTR |= (1u << port_No(port)); + rc_out(bp, RC_DTR, bp->DTR); + return; + } else { + /* Set DTR on */ + bp->DTR &= ~(1u << port_No(port)); + rc_out(bp, RC_DTR, bp->DTR); + } + + /* + * Now we must calculate some speed depended things + */ + + /* Set baud rate for port */ + tmp = (((RC_OSCFREQ + baud_table[baud]/2) / baud_table[baud] + + CD180_TPC/2) / CD180_TPC); + + rc_out(bp, CD180_RBPRH, (tmp >> 8) & 0xff); + rc_out(bp, CD180_TBPRH, (tmp >> 8) & 0xff); + rc_out(bp, CD180_RBPRL, tmp & 0xff); + rc_out(bp, CD180_TBPRL, tmp & 0xff); + + baud = (baud_table[baud] + 5) / 10; /* Estimated CPS */ + + /* Two timer ticks seems enough to wakeup something like SLIP driver */ + tmp = ((baud + HZ/2) / HZ) * 2 - CD180_NFIFO; + port->wakeup_chars = (tmp < 0) ? 0 : ((tmp >= SERIAL_XMIT_SIZE) ? + SERIAL_XMIT_SIZE - 1 : tmp); + + /* Receiver timeout will be transmission time for 1.5 chars */ + tmp = (RISCOM_TPS + RISCOM_TPS/2 + baud/2) / baud; + tmp = (tmp > 0xff) ? 0xff : tmp; + rc_out(bp, CD180_RTPR, tmp); + + switch (C_CSIZE(tty)) { + case CS5: + cor1 |= COR1_5BITS; + break; + case CS6: + cor1 |= COR1_6BITS; + break; + case CS7: + cor1 |= COR1_7BITS; + break; + case CS8: + cor1 |= COR1_8BITS; + break; + } + + if (C_CSTOPB(tty)) + cor1 |= COR1_2SB; + + cor1 |= COR1_IGNORE; + if (C_PARENB(tty)) { + cor1 |= COR1_NORMPAR; + if (C_PARODD(tty)) + cor1 |= COR1_ODDP; + if (I_INPCK(tty)) + cor1 &= ~COR1_IGNORE; + } + /* Set marking of some errors */ + port->mark_mask = RCSR_OE | RCSR_TOUT; + if (I_INPCK(tty)) + port->mark_mask |= RCSR_FE | RCSR_PE; + if (I_BRKINT(tty) || I_PARMRK(tty)) + port->mark_mask |= RCSR_BREAK; + if (I_IGNPAR(tty)) + port->mark_mask &= ~(RCSR_FE | RCSR_PE); + if (I_IGNBRK(tty)) { + port->mark_mask &= ~RCSR_BREAK; + if (I_IGNPAR(tty)) + /* Real raw mode. Ignore all */ + port->mark_mask &= ~RCSR_OE; + } + /* Enable Hardware FLow Control */ + if (C_CRTSCTS(tty)) { +#ifdef RISCOM_BRAIN_DAMAGED_CTS + port->IER |= IER_DSR | IER_CTS; + mcor1 |= MCOR1_DSRZD | MCOR1_CTSZD; + mcor2 |= MCOR2_DSROD | MCOR2_CTSOD; + tty->hw_stopped = !(rc_in(bp, CD180_MSVR) & (MSVR_CTS|MSVR_DSR)); +#else + port->COR2 |= COR2_CTSAE; +#endif + } + /* Enable Software Flow Control. FIXME: I'm not sure about this */ + /* Some people reported that it works, but I still doubt */ + if (I_IXON(tty)) { + port->COR2 |= COR2_TXIBE; + cor3 |= (COR3_FCT | COR3_SCDE); + if (I_IXANY(tty)) + port->COR2 |= COR2_IXM; + rc_out(bp, CD180_SCHR1, START_CHAR(tty)); + rc_out(bp, CD180_SCHR2, STOP_CHAR(tty)); + rc_out(bp, CD180_SCHR3, START_CHAR(tty)); + rc_out(bp, CD180_SCHR4, STOP_CHAR(tty)); + } + if (!C_CLOCAL(tty)) { + /* Enable CD check */ + port->IER |= IER_CD; + mcor1 |= MCOR1_CDZD; + mcor2 |= MCOR2_CDOD; + } + + if (C_CREAD(tty)) + /* Enable receiver */ + port->IER |= IER_RXD; + + /* Set input FIFO size (1-8 bytes) */ + cor3 |= RISCOM_RXFIFO; + /* Setting up CD180 channel registers */ + rc_out(bp, CD180_COR1, cor1); + rc_out(bp, CD180_COR2, port->COR2); + rc_out(bp, CD180_COR3, cor3); + /* Make CD180 know about registers change */ + rc_wait_CCR(bp); + rc_out(bp, CD180_CCR, CCR_CORCHG1 | CCR_CORCHG2 | CCR_CORCHG3); + /* Setting up modem option registers */ + rc_out(bp, CD180_MCOR1, mcor1); + rc_out(bp, CD180_MCOR2, mcor2); + /* Enable CD180 trasmitter & receiver */ + rc_wait_CCR(bp); + rc_out(bp, CD180_CCR, CCR_TXEN | CCR_RXEN); + /* Enable interrupts */ + rc_out(bp, CD180_IER, port->IER); + /* And finaly set RTS on */ + rc_out(bp, CD180_MSVR, port->MSVR); +} + +/* Must be called with interrupts enabled */ +static int rc_setup_port(struct riscom_board *bp, struct riscom_port *port) +{ + unsigned long flags; + + if (port->flags & ASYNC_INITIALIZED) + return 0; + + if (!port->xmit_buf) { + /* We may sleep in get_free_page() */ + unsigned long tmp; + + if (!(tmp = get_free_page(GFP_KERNEL))) + return -ENOMEM; + + if (port->xmit_buf) { + free_page(tmp); + return -ERESTARTSYS; + } + port->xmit_buf = (unsigned char *) tmp; + } + + save_flags(flags); cli(); + + if (port->tty) + clear_bit(TTY_IO_ERROR, &port->tty->flags); + + if (port->count == 1) + bp->count++; + + port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; + rc_change_speed(bp, port); + port->flags |= ASYNC_INITIALIZED; + + restore_flags(flags); + return 0; +} + +/* Must be called with interrupts disabled */ +static void rc_shutdown_port(struct riscom_board *bp, struct riscom_port *port) +{ + struct tty_struct *tty; + + if (!(port->flags & ASYNC_INITIALIZED)) + return; + +#ifdef RC_REPORT_OVERRUN + printk("rc%d: port %d: Total %ld overruns were detected.\n", + board_No(bp), port_No(port), port->overrun); +#endif +#ifdef RC_REPORT_FIFO + { + int i; + + printk("rc%d: port %d: FIFO hits [ ", + board_No(bp), port_No(port)); + for (i = 0; i < 10; i++) { + printk("%ld ", port->hits[i]); + } + printk("].\n"); + } +#endif + if (port->xmit_buf) { + free_page((unsigned long) port->xmit_buf); + port->xmit_buf = NULL; + } + + if (!(tty = port->tty) || C_HUPCL(tty)) { + /* Drop DTR */ + bp->DTR |= (1u << port_No(port)); + rc_out(bp, RC_DTR, bp->DTR); + } + + /* Select port */ + rc_out(bp, CD180_CAR, port_No(port)); + /* Reset port */ + rc_wait_CCR(bp); + rc_out(bp, CD180_CCR, CCR_SOFTRESET); + /* Disable all interrupts from this port */ + port->IER = 0; + rc_out(bp, CD180_IER, port->IER); + + if (tty) + set_bit(TTY_IO_ERROR, &tty->flags); + port->flags &= ~ASYNC_INITIALIZED; + + if (--bp->count < 0) { + printk("rc%d: rc_shutdow_port: bad board count: %d\n", + board_No(bp), bp->count); + bp->count = 0; + } + + /* + * If this is the last opened port on the board + * shutdown whole board + */ + if (!bp->count) + rc_shutdown_board(bp); +} + + +static int block_til_ready(struct tty_struct *tty, struct file * filp, + struct riscom_port *port) +{ + struct wait_queue wait = { current, NULL }; + struct riscom_board *bp = port_Board(port); + int retval; + int do_clocal = 0; + int CD; + + /* + * If the device is in the middle of being closed, then block + * until it's done, and then try again. + */ + if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) { + interruptible_sleep_on(&port->close_wait); + if (port->flags & ASYNC_HUP_NOTIFY) + return -EAGAIN; + else + return -ERESTARTSYS; + } + + /* + * If this is a callout device, then just make sure the normal + * device isn't being used. + */ + if (tty->driver.subtype == RISCOM_TYPE_CALLOUT) { + if (port->flags & ASYNC_NORMAL_ACTIVE) + return -EBUSY; + if ((port->flags & ASYNC_CALLOUT_ACTIVE) && + (port->flags & ASYNC_SESSION_LOCKOUT) && + (port->session != current->session)) + return -EBUSY; + if ((port->flags & ASYNC_CALLOUT_ACTIVE) && + (port->flags & ASYNC_PGRP_LOCKOUT) && + (port->pgrp != current->pgrp)) + return -EBUSY; + port->flags |= ASYNC_CALLOUT_ACTIVE; + return 0; + } + + /* + * If non-blocking mode is set, or the port is not enabled, + * then make the check up front and then exit. + */ + if ((filp->f_flags & O_NONBLOCK) || + (tty->flags & (1 << TTY_IO_ERROR))) { + if (port->flags & ASYNC_CALLOUT_ACTIVE) + return -EBUSY; + port->flags |= ASYNC_NORMAL_ACTIVE; + return 0; + } + + if (port->flags & ASYNC_CALLOUT_ACTIVE) { + if (port->normal_termios.c_cflag & CLOCAL) + do_clocal = 1; + } else { + if (C_CLOCAL(tty)) + do_clocal = 1; + } + + /* + * Block waiting for the carrier detect and the line to become + * free (i.e., not in use by the callout). While we are in + * this loop, info->count is dropped by one, so that + * rs_close() knows when to free things. We restore it upon + * exit, either normal or abnormal. + */ + retval = 0; + add_wait_queue(&port->open_wait, &wait); + cli(); + if (!tty_hung_up_p(filp)) + port->count--; + sti(); + port->blocked_open++; + while (1) { + cli(); + rc_out(bp, CD180_CAR, port_No(port)); + CD = rc_in(bp, CD180_MSVR) & MSVR_CD; + if (!(port->flags & ASYNC_CALLOUT_ACTIVE)) { + rc_out(bp, CD180_MSVR, MSVR_RTS); + bp->DTR &= ~(1u << port_No(port)); + rc_out(bp, RC_DTR, bp->DTR); + } + sti(); + current->state = TASK_INTERRUPTIBLE; + if (tty_hung_up_p(filp) || + !(port->flags & ASYNC_INITIALIZED)) { + if (port->flags & ASYNC_HUP_NOTIFY) + retval = -EAGAIN; + else + retval = -ERESTARTSYS; + break; + } + if (!(port->flags & ASYNC_CALLOUT_ACTIVE) && + !(port->flags & ASYNC_CLOSING) && + (do_clocal || CD)) + break; + if (current->signal & ~current->blocked) { + retval = -ERESTARTSYS; + break; + } + schedule(); + } + current->state = TASK_RUNNING; + remove_wait_queue(&port->open_wait, &wait); + if (!tty_hung_up_p(filp)) + port->count++; + port->blocked_open--; + if (retval) + return retval; + + port->flags |= ASYNC_NORMAL_ACTIVE; + return 0; +} + +static int rc_open(struct tty_struct * tty, struct file * filp) +{ + int board; + int error; + struct riscom_port * port; + struct riscom_board * bp; + unsigned long flags; + + board = RC_BOARD(MINOR(tty->device)); + if (board > RC_NBOARD || !(rc_board[board].flags & RC_BOARD_PRESENT)) + return -ENODEV; + + bp = &rc_board[board]; + port = rc_port + board * RC_NPORT + RC_PORT(MINOR(tty->device)); + if (rc_paranoia_check(port, tty->device, "rc_open")) + return -ENODEV; + + if ((error = rc_setup_board(bp))) + return error; + + port->count++; + tty->driver_data = port; + port->tty = tty; + + if ((error = rc_setup_port(bp, port))) + return error; + + if ((error = block_til_ready(tty, filp, port))) + return error; + + if ((port->count == 1) && (port->flags & ASYNC_SPLIT_TERMIOS)) { + if (tty->driver.subtype == RISCOM_TYPE_NORMAL) + *tty->termios = port->normal_termios; + else + *tty->termios = port->callout_termios; + save_flags(flags); cli(); + rc_change_speed(bp, port); + restore_flags(flags); + } + + port->session = current->session; + port->pgrp = current->pgrp; + + return 0; +} + +static void rc_close(struct tty_struct * tty, struct file * filp) +{ + struct riscom_port *port = (struct riscom_port *) tty->driver_data; + struct riscom_board *bp; + unsigned long flags; + unsigned long timeout; + + if (!port || rc_paranoia_check(port, tty->device, "close")) + return; + + save_flags(flags); cli(); + if (tty_hung_up_p(filp)) { + restore_flags(flags); + return; + } + + bp = port_Board(port); + if ((tty->count == 1) && (port->count != 1)) { + printk("rc%d: rc_close: bad port count;" + " tty->count is 1, port count is %d\n", + board_No(bp), port->count); + port->count = 1; + } + if (--port->count < 0) { + printk("rc%d: rc_close: bad port count for tty%d: %d\n", + board_No(bp), port_No(port), port->count); + port->count = 0; + } + if (port->count) { + restore_flags(flags); + return; + } + port->flags |= ASYNC_CLOSING; + /* + * Save the termios structure, since this port may have + * separate termios for callout and dialin. + */ + if (port->flags & ASYNC_NORMAL_ACTIVE) + port->normal_termios = *tty->termios; + if (port->flags & ASYNC_CALLOUT_ACTIVE) + port->callout_termios = *tty->termios; + /* + * Now we wait for the transmit buffer to clear; and we notify + * the line discipline to only process XON/XOFF characters. + */ + tty->closing = 1; + if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) + tty_wait_until_sent(tty, port->closing_wait); + /* + * At this point we stop accepting input. To do this, we + * disable the receive line status interrupts, and tell the + * interrupt driver to stop checking the data ready bit in the + * line status register. + */ + port->IER &= ~IER_RXD; + if (port->flags & ASYNC_INITIALIZED) { + port->IER &= ~IER_TXRDY; + port->IER |= IER_TXEMPTY; + rc_out(bp, CD180_CAR, port_No(port)); + rc_out(bp, CD180_IER, port->IER); + /* + * Before we drop DTR, make sure the UART transmitter + * has completely drained; this is especially + * important if there is a transmit FIFO! + */ + timeout = jiffies+HZ; + while(port->IER & IER_TXEMPTY) { + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + port->timeout; + schedule(); + if (jiffies > timeout) + break; + } + } + rc_shutdown_port(bp, port); + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + tty->closing = 0; + port->event = 0; + port->tty = 0; + if (port->blocked_open) { + if (port->close_delay) { + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + port->close_delay; + schedule(); + } + wake_up_interruptible(&port->open_wait); + } + port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| + ASYNC_CLOSING); + wake_up_interruptible(&port->close_wait); + restore_flags(flags); +} + +static int rc_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) +{ + struct riscom_port *port = (struct riscom_port *)tty->driver_data; + struct riscom_board *bp; + int c, total = 0; + unsigned long flags; + + if (rc_paranoia_check(port, tty->device, "rc_write")) + return 0; + + bp = port_Board(port); + + if (!tty || !port->xmit_buf || !tmp_buf) + return 0; + + if (from_user) + down(&tmp_buf_sem); + + save_flags(flags); + while (1) { + cli(); + c = MIN(count, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, + SERIAL_XMIT_SIZE - port->xmit_head)); + if (c <= 0) + break; + + if (from_user) { + memcpy_fromfs(tmp_buf, buf, c); + c = MIN(c, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, + SERIAL_XMIT_SIZE - port->xmit_head)); + memcpy(port->xmit_buf + port->xmit_head, tmp_buf, c); + } else + memcpy(port->xmit_buf + port->xmit_head, buf, c); + port->xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE-1); + port->xmit_cnt += c; + restore_flags(flags); + buf += c; + count -= c; + total += c; + } + if (from_user) + up(&tmp_buf_sem); + if (port->xmit_cnt && !tty->stopped && !tty->hw_stopped && + !(port->IER & IER_TXRDY)) { + port->IER |= IER_TXRDY; + rc_out(bp, CD180_CAR, port_No(port)); + rc_out(bp, CD180_IER, port->IER); + } + restore_flags(flags); + return total; +} + +static void rc_put_char(struct tty_struct * tty, unsigned char ch) +{ + struct riscom_port *port = (struct riscom_port *)tty->driver_data; + unsigned long flags; + + if (rc_paranoia_check(port, tty->device, "rc_put_char")) + return; + + if (!tty || !port->xmit_buf) + return; + + save_flags(flags); cli(); + + if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) { + restore_flags(flags); + return; + } + + port->xmit_buf[port->xmit_head++] = ch; + port->xmit_head &= SERIAL_XMIT_SIZE - 1; + port->xmit_cnt++; + restore_flags(flags); +} + +static void rc_flush_chars(struct tty_struct * tty) +{ + struct riscom_port *port = (struct riscom_port *)tty->driver_data; + unsigned long flags; + + if (rc_paranoia_check(port, tty->device, "rc_flush_chars")) + return; + + if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || + !port->xmit_buf) + return; + + save_flags(flags); cli(); + port->IER |= IER_TXRDY; + rc_out(port_Board(port), CD180_CAR, port_No(port)); + rc_out(port_Board(port), CD180_IER, port->IER); + restore_flags(flags); +} + +static int rc_write_room(struct tty_struct * tty) +{ + struct riscom_port *port = (struct riscom_port *)tty->driver_data; + int ret; + + if (rc_paranoia_check(port, tty->device, "rc_write_room")) + return 0; + + ret = SERIAL_XMIT_SIZE - port->xmit_cnt - 1; + if (ret < 0) + ret = 0; + return ret; +} + +static int rc_chars_in_buffer(struct tty_struct *tty) +{ + struct riscom_port *port = (struct riscom_port *)tty->driver_data; + + if (rc_paranoia_check(port, tty->device, "rc_chars_in_buffer")) + return 0; + + return port->xmit_cnt; +} + +static void rc_flush_buffer(struct tty_struct *tty) +{ + struct riscom_port *port = (struct riscom_port *)tty->driver_data; + unsigned long flags; + + if (rc_paranoia_check(port, tty->device, "rc_flush_buffer")) + return; + + save_flags(flags); cli(); + port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; + restore_flags(flags); + + wake_up_interruptible(&tty->write_wait); + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); +} + +static int rc_get_modem_info(struct riscom_port * port, unsigned int *value) +{ + struct riscom_board * bp; + unsigned char status; + unsigned int result; + unsigned long flags; + + bp = port_Board(port); + save_flags(flags); cli(); + rc_out(bp, CD180_CAR, port_No(port)); + status = rc_in(bp, CD180_MSVR); + result = rc_in(bp, RC_RI) & (1u << port_No(port)) ? 0 : TIOCM_RNG; + restore_flags(flags); + result |= ((status & MSVR_RTS) ? TIOCM_RTS : 0) + | ((status & MSVR_DTR) ? TIOCM_DTR : 0) + | ((status & MSVR_CD) ? TIOCM_CAR : 0) + | ((status & MSVR_DSR) ? TIOCM_DSR : 0) + | ((status & MSVR_CTS) ? TIOCM_CTS : 0); + put_user(result,(unsigned long *) value); + return 0; +} + +static int rc_set_modem_info(struct riscom_port * port, unsigned int cmd, + unsigned int *value) +{ + int error; + unsigned int arg; + unsigned long flags; + struct riscom_board *bp = port_Board(port); + + error = verify_area(VERIFY_READ, value, sizeof(int)); + if (error) + return error; + arg = get_fs_long((unsigned long *) value); + switch (cmd) { + case TIOCMBIS: + if (arg & TIOCM_RTS) + port->MSVR |= MSVR_RTS; + if (arg & TIOCM_DTR) + bp->DTR &= ~(1u << port_No(port)); + break; + case TIOCMBIC: + if (arg & TIOCM_RTS) + port->MSVR &= ~MSVR_RTS; + if (arg & TIOCM_DTR) + bp->DTR |= (1u << port_No(port)); + break; + case TIOCMSET: + port->MSVR = (arg & TIOCM_RTS) ? (port->MSVR | MSVR_RTS) : + (port->MSVR & ~MSVR_RTS); + bp->DTR = arg & TIOCM_DTR ? (bp->DTR &= ~(1u << port_No(port))) : + (bp->DTR |= (1u << port_No(port))); + break; + default: + return -EINVAL; + } + save_flags(flags); cli(); + rc_out(bp, CD180_CAR, port_No(port)); + rc_out(bp, CD180_MSVR, port->MSVR); + rc_out(bp, RC_DTR, bp->DTR); + restore_flags(flags); + return 0; +} + +extern inline void rc_send_break(struct riscom_port * port, unsigned long length) +{ + struct riscom_board *bp = port_Board(port); + unsigned long flags; + + save_flags(flags); cli(); + port->break_length = RISCOM_TPS / HZ * length; + port->COR2 |= COR2_ETC; + port->IER |= IER_TXRDY; + rc_out(bp, CD180_CAR, port_No(port)); + rc_out(bp, CD180_COR2, port->COR2); + rc_out(bp, CD180_IER, port->IER); + rc_wait_CCR(bp); + rc_out(bp, CD180_CCR, CCR_CORCHG2); + rc_wait_CCR(bp); + restore_flags(flags); +} + +extern inline int rc_set_serial_info(struct riscom_port * port, + struct serial_struct * newinfo) +{ + struct serial_struct tmp; + struct riscom_board *bp = port_Board(port); + int change_speed; + unsigned long flags; + int error; + + error = verify_area(VERIFY_READ, (void *) newinfo, sizeof(tmp)); + if (error) + return error; + memcpy_fromfs(&tmp, newinfo, sizeof(tmp)); + +#if 0 + if ((tmp.irq != bp->irq) || + (tmp.port != bp->base) || + (tmp.type != PORT_CIRRUS) || + (tmp.baud_base != (RC_OSCFREQ + CD180_TPC/2) / CD180_TPC) || + (tmp.custom_divisor != 0) || + (tmp.xmit_fifo_size != CD180_NFIFO) || + (tmp.flags & ~RISCOM_LEGAL_FLAGS)) + return -EINVAL; +#endif + + change_speed = ((port->flags & ASYNC_SPD_MASK) != + (tmp.flags & ASYNC_SPD_MASK)); + + if (!suser()) { + if ((tmp.close_delay != port->close_delay) || + (tmp.closing_wait != port->closing_wait) || + ((tmp.flags & ~ASYNC_USR_MASK) != + (port->flags & ~ASYNC_USR_MASK))) + return -EPERM; + port->flags = ((port->flags & ~ASYNC_USR_MASK) | + (tmp.flags & ASYNC_USR_MASK)); + } else { + port->flags = ((port->flags & ~ASYNC_FLAGS) | + (tmp.flags & ASYNC_FLAGS)); + port->close_delay = tmp.close_delay; + port->closing_wait = tmp.closing_wait; + } + if (change_speed) { + save_flags(flags); cli(); + rc_change_speed(bp, port); + restore_flags(flags); + } + return 0; +} + +extern inline int rc_get_serial_info(struct riscom_port * port, + struct serial_struct * retinfo) +{ + struct serial_struct tmp; + struct riscom_board *bp = port_Board(port); + int error; + + error = verify_area(VERIFY_WRITE, (void *) retinfo, sizeof(tmp)); + if (error) + return error; + + memset(&tmp, 0, sizeof(tmp)); + tmp.type = PORT_CIRRUS; + tmp.line = port - rc_port; + tmp.port = bp->base; + tmp.irq = bp->irq; + tmp.flags = port->flags; + tmp.baud_base = (RC_OSCFREQ + CD180_TPC/2) / CD180_TPC; + tmp.close_delay = port->close_delay * HZ/100; + tmp.closing_wait = port->closing_wait * HZ/100; + tmp.xmit_fifo_size = CD180_NFIFO; + memcpy_tofs(retinfo, &tmp, sizeof(tmp)); + return 0; +} + +static int rc_ioctl(struct tty_struct * tty, struct file * filp, + unsigned int cmd, unsigned long arg) + +{ + struct riscom_port *port = (struct riscom_port *)tty->driver_data; + int error; + int retval; + + if (rc_paranoia_check(port, tty->device, "rc_ioctl")) + return -ENODEV; + + switch (cmd) { + case TCSBRK: /* SVID version: non-zero arg --> no break */ + retval = tty_check_change(tty); + if (retval) + return retval; + tty_wait_until_sent(tty, 0); + if (!arg) + rc_send_break(port, HZ/4); /* 1/4 second */ + return 0; + case TCSBRKP: /* support for POSIX tcsendbreak() */ + retval = tty_check_change(tty); + if (retval) + return retval; + tty_wait_until_sent(tty, 0); + rc_send_break(port, arg ? arg*(HZ/10) : HZ/4); + return 0; + case TIOCGSOFTCAR: + error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(long)); + if (error) + return error; + put_user(C_CLOCAL(tty) ? 1 : 0, + (unsigned long *) arg); + return 0; + case TIOCSSOFTCAR: + arg = get_user((unsigned long *) arg); + tty->termios->c_cflag = + ((tty->termios->c_cflag & ~CLOCAL) | + (arg ? CLOCAL : 0)); + return 0; + case TIOCMGET: + error = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(unsigned int)); + if (error) + return error; + return rc_get_modem_info(port, (unsigned int *) arg); + case TIOCMBIS: + case TIOCMBIC: + case TIOCMSET: + return rc_set_modem_info(port, cmd, (unsigned int *) arg); + case TIOCGSERIAL: + return rc_get_serial_info(port, (struct serial_struct *) arg); + case TIOCSSERIAL: + return rc_set_serial_info(port, (struct serial_struct *) arg); + default: + return -ENOIOCTLCMD; + } + return 0; +} + +static void rc_throttle(struct tty_struct * tty) +{ + struct riscom_port *port = (struct riscom_port *)tty->driver_data; + struct riscom_board *bp; + unsigned long flags; + + if (rc_paranoia_check(port, tty->device, "rc_throttle")) + return; + + bp = port_Board(port); + + save_flags(flags); cli(); + port->MSVR &= ~MSVR_RTS; + rc_out(bp, CD180_CAR, port_No(port)); + if (I_IXOFF(tty)) { + rc_wait_CCR(bp); + rc_out(bp, CD180_CCR, CCR_SSCH2); + rc_wait_CCR(bp); + } + rc_out(bp, CD180_MSVR, port->MSVR); + restore_flags(flags); +} + +static void rc_unthrottle(struct tty_struct * tty) +{ + struct riscom_port *port = (struct riscom_port *)tty->driver_data; + struct riscom_board *bp; + unsigned long flags; + + if (rc_paranoia_check(port, tty->device, "rc_unthrottle")) + return; + + bp = port_Board(port); + + save_flags(flags); cli(); + port->MSVR |= MSVR_RTS; + rc_out(bp, CD180_CAR, port_No(port)); + if (I_IXOFF(tty)) { + rc_wait_CCR(bp); + rc_out(bp, CD180_CCR, CCR_SSCH1); + rc_wait_CCR(bp); + } + rc_out(bp, CD180_MSVR, port->MSVR); + restore_flags(flags); +} + +static void rc_stop(struct tty_struct * tty) +{ + struct riscom_port *port = (struct riscom_port *)tty->driver_data; + struct riscom_board *bp; + unsigned long flags; + + if (rc_paranoia_check(port, tty->device, "rc_stop")) + return; + + bp = port_Board(port); + + save_flags(flags); cli(); + port->IER &= ~IER_TXRDY; + rc_out(bp, CD180_CAR, port_No(port)); + rc_out(bp, CD180_IER, port->IER); + restore_flags(flags); +} + +static void rc_start(struct tty_struct * tty) +{ + struct riscom_port *port = (struct riscom_port *)tty->driver_data; + struct riscom_board *bp; + unsigned long flags; + + if (rc_paranoia_check(port, tty->device, "rc_start")) + return; + + bp = port_Board(port); + + save_flags(flags); cli(); + if (port->xmit_cnt && port->xmit_buf && !(port->IER & IER_TXRDY)) { + port->IER |= IER_TXRDY; + rc_out(bp, CD180_CAR, port_No(port)); + rc_out(bp, CD180_IER, port->IER); + } + restore_flags(flags); +} + +/* + * This routine is called from the scheduler tqueue when the interrupt + * routine has signalled that a hangup has occurred. The path of + * hangup processing is: + * + * serial interrupt routine -> (scheduler tqueue) -> + * do_rc_hangup() -> tty->hangup() -> rc_hangup() + * + */ +static void do_rc_hangup(void *private_) +{ + struct riscom_port *port = (struct riscom_port *) private_; + struct tty_struct *tty; + + tty = port->tty; + if (!tty) + return; + + tty_hangup(tty); +} + +static void rc_hangup(struct tty_struct * tty) +{ + struct riscom_port *port = (struct riscom_port *)tty->driver_data; + struct riscom_board *bp; + + if (rc_paranoia_check(port, tty->device, "rc_hangup")) + return; + + bp = port_Board(port); + + rc_shutdown_port(bp, port); + port->event = 0; + port->count = 0; + port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); + port->tty = 0; + wake_up_interruptible(&port->open_wait); +} + +static void rc_set_termios(struct tty_struct * tty, struct termios * old_termios) +{ + struct riscom_port *port = (struct riscom_port *)tty->driver_data; + unsigned long flags; + + if (rc_paranoia_check(port, tty->device, "rc_set_termios")) + return; + + if (tty->termios->c_cflag == old_termios->c_cflag && + tty->termios->c_iflag == old_termios->c_iflag) + return; + + save_flags(flags); cli(); + rc_change_speed(port_Board(port), port); + restore_flags(flags); + + if ((old_termios->c_cflag & CRTSCTS) && + !(tty->termios->c_cflag & CRTSCTS)) { + tty->hw_stopped = 0; + rc_start(tty); + } +} + +static void do_riscom_bh(void) +{ + run_task_queue(&tq_riscom); +} + +static void do_softint(void *private_) +{ + struct riscom_port *port = (struct riscom_port *) private_; + struct tty_struct *tty; + + if(!(tty = port->tty)) + return; + + if (clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) { + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); + wake_up_interruptible(&tty->write_wait); + } +} + +static int rc_init_drivers(void) +{ + int error; + int i; + + + if (!(tmp_buf = (unsigned char *) get_free_page(GFP_KERNEL))) { + printk("rc: Couldn't get free page.\n"); + return 1; + } + init_bh(RISCOM8_BH, do_riscom_bh); + memset(IRQ_to_board, 0, sizeof(IRQ_to_board)); + memset(&riscom_driver, 0, sizeof(riscom_driver)); + riscom_driver.magic = TTY_DRIVER_MAGIC; + riscom_driver.name = "ttyL"; + riscom_driver.major = RISCOM8_NORMAL_MAJOR; + riscom_driver.num = RC_NBOARD * RC_NPORT; + riscom_driver.type = TTY_DRIVER_TYPE_SERIAL; + riscom_driver.subtype = RISCOM_TYPE_NORMAL; + riscom_driver.init_termios = tty_std_termios; + riscom_driver.init_termios.c_cflag = + B9600 | CS8 | CREAD | HUPCL | CLOCAL; + riscom_driver.flags = TTY_DRIVER_REAL_RAW; + riscom_driver.refcount = &riscom_refcount; + riscom_driver.table = riscom_table; + riscom_driver.termios = riscom_termios; + riscom_driver.termios_locked = riscom_termios_locked; + + riscom_driver.open = rc_open; + riscom_driver.close = rc_close; + riscom_driver.write = rc_write; + riscom_driver.put_char = rc_put_char; + riscom_driver.flush_chars = rc_flush_chars; + riscom_driver.write_room = rc_write_room; + riscom_driver.chars_in_buffer = rc_chars_in_buffer; + riscom_driver.flush_buffer = rc_flush_buffer; + riscom_driver.ioctl = rc_ioctl; + riscom_driver.throttle = rc_throttle; + riscom_driver.unthrottle = rc_unthrottle; + riscom_driver.set_termios = rc_set_termios; + riscom_driver.stop = rc_stop; + riscom_driver.start = rc_start; + riscom_driver.hangup = rc_hangup; + + riscom_callout_driver = riscom_driver; + riscom_callout_driver.name = "cul"; + riscom_callout_driver.major = RISCOM8_CALLOUT_MAJOR; + riscom_callout_driver.subtype = RISCOM_TYPE_CALLOUT; + + if ((error = tty_register_driver(&riscom_driver))) { + free_page((unsigned long)tmp_buf); + printk("rc: Couldn't register RISCom/8 driver, error = %d\n", + error); + return 1; + } + if ((error = tty_register_driver(&riscom_callout_driver))) { + free_page((unsigned long)tmp_buf); + tty_unregister_driver(&riscom_driver); + printk("rc: Couldn't register RISCom/8 callout driver, error = %d\n", + error); + return 1; + } + + memset(rc_port, 0, sizeof(rc_port)); + for (i = 0; i < RC_NPORT * RC_NBOARD; i++) { + rc_port[i].callout_termios = riscom_callout_driver.init_termios; + rc_port[i].normal_termios = riscom_driver.init_termios; + rc_port[i].magic = RISCOM8_MAGIC; + rc_port[i].tqueue.routine = do_softint; + rc_port[i].tqueue.data = &rc_port[i]; + rc_port[i].tqueue_hangup.routine = do_rc_hangup; + rc_port[i].tqueue_hangup.data = &rc_port[i]; + rc_port[i].close_delay = 50 * HZ/100; + rc_port[i].closing_wait = 3000 * HZ/100; + } + + return 0; +} + +static void rc_release_drivers(void) +{ + free_page((unsigned long)tmp_buf); + tty_unregister_driver(&riscom_driver); + tty_unregister_driver(&riscom_callout_driver); +} + +#ifndef MODULE +/* + * Called at boot time. + * + * You can specify IO base for up to RC_NBOARD cards, + * using line "riscom8=0xiobase1,0xiobase2,.." at LILO prompt. + * Note that there wiil be no probing at default + * addresses in this case. + * + */ +void riscom8_setup(char *str, int * ints) +{ + int i; + + for (i = 0; i < RC_NBOARD; i++) { + if (i < ints[0]) + rc_board[i].base = ints[i+1]; + else + rc_board[i].base = 0; + } +} +#endif + +/* + * This routine must be called by kernel at boot time + */ +int riscom8_init(void) +{ + int i; + int found = 0; + + printk("rc: SDL RISCom/8 card driver v1.0, (c) D.Gorodchanin 1994-1996.\n"); + + if (rc_init_drivers()) + return -EIO; + + for (i = 0; i < RC_NBOARD; i++) + if (rc_board[i].base && !rc_probe(&rc_board[i])) + found++; + + if (!found) { + rc_release_drivers(); + printk("rc: No RISCom/8 boards detected.\n"); + return -EIO; + } + return 0; +} + +#ifdef MODULE +int iobase = 0; +int iobase1 = 0; +int iobase2 = 0; +int iobase3 = 0; + +/* + * You can setup up to 4 boards (current value of RC_NBOARD) + * by specifying "iobase=0xXXX iobase1=0xXXX ..." as isnmod parametr. + * + */ +int init_module(void) +{ + int i; + + if (iobase || iobase1 || iobase2 || iobase3) { + for(i = 0; i < RC_NBOARD; i++) + rc_board[0].base = 0; + } + + if (iobase) + rc_board[0].base = iobase; + if (iobase1) + rc_board[1].base = iobase1; + if (iobase2) + rc_board[2].base = iobase2; + if (iobase3) + rc_board[3].base = iobase3; + + return riscom8_init(); +} + +void cleanup_module(void) +{ + int i; + + rc_release_drivers(); + for (i = 0; i < RC_NBOARD; i++) + if (rc_board[i].flags & RC_BOARD_PRESENT) + rc_release_io_range(&rc_board[i]); + +} +#endif /* MODULE */ diff -u --recursive --new-file v1.3.93/linux/drivers/char/riscom8.h linux/drivers/char/riscom8.h --- v1.3.93/linux/drivers/char/riscom8.h Thu Jan 1 02:00:00 1970 +++ linux/drivers/char/riscom8.h Mon Apr 22 07:14:01 1996 @@ -0,0 +1,106 @@ +/* + * linux/drivers/char/riscom8.h -- RISCom/8 multiport serial driver. + * + * Copyright (C) 1994-1996 Dmitry Gorodchanin (begemot@bgm.rosprint.net) + * + * This code is loosely based on the Linux serial driver, written by + * Linus Torvalds, Theodore T'so and others. The RISCom/8 card + * programming info was obtained from various drivers for other OSes + * (FreeBSD, ISC, etc), but no source code from those drivers were + * directly included in this drvier. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __LINUX_RISCOM8_H +#define __LINUX_RISCOM8_H + +#include + +#ifdef __KERNEL__ + +#define RC_NBOARD 4 +/* NOTE: RISCom decoder recognizes 16 addresses... */ +#define RC_NPORT 8 +#define RC_BOARD(line) (((line) >> 3) & 0x07) +#define RC_PORT(line) ((line) & (RC_NPORT - 1)) + +/* Ticks per sec. Used for setting receiver timeout and break length */ +#define RISCOM_TPS 4000 + +/* Yeah, after heavy testing I decided it must be 6. + * Sure, You can change it if needed. + */ +#define RISCOM_RXFIFO 6 /* Max. receiver FIFO size (1-8) */ + +#define RISCOM8_MAGIC 0x0907 + +#define RC_IOBASE1 0x220 +#define RC_IOBASE2 0x240 +#define RC_IOBASE3 0x250 +#define RC_IOBASE4 0x260 + +struct riscom_board { + unsigned long flags; + unsigned short base; + unsigned char irq; + signed char count; + unsigned char DTR; +}; + +#define RC_BOARD_PRESENT 0x00000001 +#define RC_BOARD_ACTIVE 0x00000002 + +struct riscom_port { + int magic; + int baud_base; + int flags; + struct tty_struct * tty; + int count; + int blocked_open; + int event; + int timeout; + int close_delay; + long session; + long pgrp; + unsigned char * xmit_buf; + int custom_divisor; + int xmit_head; + int xmit_tail; + int xmit_cnt; + struct termios normal_termios; + struct termios callout_termios; + struct wait_queue *open_wait; + struct wait_queue *close_wait; + struct tq_struct tqueue; + struct tq_struct tqueue_hangup; + short wakeup_chars; + short break_length; + unsigned short closing_wait; + unsigned char mark_mask; + unsigned char IER; + unsigned char MSVR; + unsigned char COR2; +#ifdef RC_REPORT_OVERRUN + unsigned long overrun; +#endif +#ifdef RC_REPORT_FIFO + unsigned long hits[10]; +#endif +}; + +#endif /* __KERNEL__ */ +#endif /* __LINUX_RISCOM8_H */ diff -u --recursive --new-file v1.3.93/linux/drivers/char/riscom8_reg.h linux/drivers/char/riscom8_reg.h --- v1.3.93/linux/drivers/char/riscom8_reg.h Thu Jan 1 02:00:00 1970 +++ linux/drivers/char/riscom8_reg.h Mon Apr 22 07:14:01 1996 @@ -0,0 +1,254 @@ +/* + * linux/drivers/char/riscom8_reg.h -- RISCom/8 multiport serial driver. + */ + +/* + * Definitions for RISCom/8 Async Mux card by SDL Communications, Inc. + */ + +/* + * Address mapping between Cirrus Logic CD180 chip internal registers + * and ISA port addresses: + * + * CL-CD180 A6 A5 A4 A3 A2 A1 A0 + * ISA A15 A14 A13 A12 A11 A10 A9 A8 A7 A6 A5 A4 A3 A2 A1 A0 + */ +#define RC_TO_ISA(r) ((((r)&0x07)<<1) | (((r)&~0x07)<<7)) + + +/* RISCom/8 On-Board Registers (assuming address translation) */ + +#define RC_RI 0x100 /* Ring Indicator Register (R/O) */ +#define RC_DTR 0x100 /* DTR Register (W/O) */ +#define RC_BSR 0x101 /* Board Status Register (R/O) */ +#define RC_CTOUT 0x101 /* Clear Timeout (W/O) */ + + +/* Board Status Register */ + +#define RC_BSR_TOUT 0x08 /* Hardware Timeout */ +#define RC_BSR_RINT 0x04 /* Receiver Interrupt */ +#define RC_BSR_TINT 0x02 /* Transmitter Interrupt */ +#define RC_BSR_MINT 0x01 /* Modem Ctl Interrupt */ + + +/* On-board oscillator frequency (in Hz) */ +#define RC_OSCFREQ 9830400 + +/* Values of choice for Interrupt ACKs */ +#define RC_ACK_MINT 0x81 /* goes to PILR1 */ +#define RC_ACK_RINT 0x82 /* goes to PILR3 */ +#define RC_ACK_TINT 0x84 /* goes to PILR2 */ + +/* Chip ID (sorry, only one chip now) */ +#define RC_ID 0x10 + +/* Definitions for Cirrus Logic CL-CD180 8-port async mux chip */ + +#define CD180_NCH 8 /* Total number of channels */ +#define CD180_TPC 16 /* Ticks per character */ +#define CD180_NFIFO 8 /* TX FIFO size */ + + +/* Global registers */ + +#define CD180_GIVR 0x40 /* Global Interrupt Vector Register */ +#define CD180_GICR 0x41 /* Global Interrupting Channel Register */ +#define CD180_PILR1 0x61 /* Priority Interrupt Level Register 1 */ +#define CD180_PILR2 0x62 /* Priority Interrupt Level Register 2 */ +#define CD180_PILR3 0x63 /* Priority Interrupt Level Register 3 */ +#define CD180_CAR 0x64 /* Channel Access Register */ +#define CD180_GFRCR 0x6b /* Global Firmware Revision Code Register */ +#define CD180_PPRH 0x70 /* Prescaler Period Register High */ +#define CD180_PPRL 0x71 /* Prescaler Period Register Low */ +#define CD180_RDR 0x78 /* Receiver Data Register */ +#define CD180_RCSR 0x7a /* Receiver Character Status Register */ +#define CD180_TDR 0x7b /* Transmit Data Register */ +#define CD180_EOIR 0x7f /* End of Interrupt Register */ + + +/* Channel Registers */ + +#define CD180_CCR 0x01 /* Channel Command Register */ +#define CD180_IER 0x02 /* Interrupt Enable Register */ +#define CD180_COR1 0x03 /* Channel Option Register 1 */ +#define CD180_COR2 0x04 /* Channel Option Register 2 */ +#define CD180_COR3 0x05 /* Channel Option Register 3 */ +#define CD180_CCSR 0x06 /* Channel Control Status Register */ +#define CD180_RDCR 0x07 /* Receive Data Count Register */ +#define CD180_SCHR1 0x09 /* Special Character Register 1 */ +#define CD180_SCHR2 0x0a /* Special Character Register 2 */ +#define CD180_SCHR3 0x0b /* Special Character Register 3 */ +#define CD180_SCHR4 0x0c /* Special Character Register 4 */ +#define CD180_MCOR1 0x10 /* Modem Change Option 1 Register */ +#define CD180_MCOR2 0x11 /* Modem Change Option 2 Register */ +#define CD180_MCR 0x12 /* Modem Change Register */ +#define CD180_RTPR 0x18 /* Receive Timeout Period Register */ +#define CD180_MSVR 0x28 /* Modem Signal Value Register */ +#define CD180_RBPRH 0x31 /* Receive Baud Rate Period Register High */ +#define CD180_RBPRL 0x32 /* Receive Baud Rate Period Register Low */ +#define CD180_TBPRH 0x39 /* Transmit Baud Rate Period Register High */ +#define CD180_TBPRL 0x3a /* Transmit Baud Rate Period Register Low */ + + +/* Global Interrupt Vector Register (R/W) */ + +#define GIVR_ITMASK 0x07 /* Interrupt type mask */ +#define GIVR_IT_MODEM 0x01 /* Modem Signal Change Interrupt */ +#define GIVR_IT_TX 0x02 /* Transmit Data Interrupt */ +#define GIVR_IT_RCV 0x03 /* Receive Good Data Interrupt */ +#define GIVR_IT_REXC 0x07 /* Receive Exception Interrupt */ + + +/* Global Interrupt Channel Register (R/W) */ + +#define GICR_CHAN 0x1c /* Channel Number Mask */ +#define GICR_CHAN_OFF 2 /* Channel Number Offset */ + + +/* Channel Address Register (R/W) */ + +#define CAR_CHAN 0x07 /* Channel Number Mask */ +#define CAR_A7 0x08 /* A7 Address Extention (unused) */ + + +/* Receive Character Status Register (R/O) */ + +#define RCSR_TOUT 0x80 /* Rx Timeout */ +#define RCSR_SCDET 0x70 /* Special Character Detected Mask */ +#define RCSR_NO_SC 0x00 /* No Special Characters Detected */ +#define RCSR_SC_1 0x10 /* Special Char 1 (or 1 & 3) Detected */ +#define RCSR_SC_2 0x20 /* Special Char 2 (or 2 & 4) Detected */ +#define RCSR_SC_3 0x30 /* Special Char 3 Detected */ +#define RCSR_SC_4 0x40 /* Special Char 4 Detected */ +#define RCSR_BREAK 0x08 /* Break has been detected */ +#define RCSR_PE 0x04 /* Parity Error */ +#define RCSR_FE 0x02 /* Frame Error */ +#define RCSR_OE 0x01 /* Overrun Error */ + + +/* Channel Command Register (R/W) (commands in groups can be OR-ed) */ + +#define CCR_HARDRESET 0x81 /* Reset the chip */ + +#define CCR_SOFTRESET 0x80 /* Soft Channel Reset */ + +#define CCR_CORCHG1 0x42 /* Channel Option Register 1 Changed */ +#define CCR_CORCHG2 0x44 /* Channel Option Register 2 Changed */ +#define CCR_CORCHG3 0x48 /* Channel Option Register 3 Changed */ + +#define CCR_SSCH1 0x21 /* Send Special Character 1 */ + +#define CCR_SSCH2 0x22 /* Send Special Character 2 */ + +#define CCR_SSCH3 0x23 /* Send Special Character 3 */ + +#define CCR_SSCH4 0x24 /* Send Special Character 4 */ + +#define CCR_TXEN 0x18 /* Enable Transmitter */ +#define CCR_RXEN 0x12 /* Enable Receiver */ + +#define CCR_TXDIS 0x14 /* Disable Transmitter */ +#define CCR_RXDIS 0x11 /* Disable Receiver */ + + +/* Interrupt Enable Register (R/W) */ + +#define IER_DSR 0x80 /* Enable interrupt on DSR change */ +#define IER_CD 0x40 /* Enable interrupt on CD change */ +#define IER_CTS 0x20 /* Enable interrupt on CTS change */ +#define IER_RXD 0x10 /* Enable interrupt on Receive Data */ +#define IER_RXSC 0x08 /* Enable interrupt on Receive Spec. Char */ +#define IER_TXRDY 0x04 /* Enable interrupt on TX FIFO empty */ +#define IER_TXEMPTY 0x02 /* Enable interrupt on TX completely empty */ +#define IER_RET 0x01 /* Enable interrupt on RX Exc. Timeout */ + + +/* Channel Option Register 1 (R/W) */ + +#define COR1_ODDP 0x80 /* Odd Parity */ +#define COR1_PARMODE 0x60 /* Parity Mode mask */ +#define COR1_NOPAR 0x00 /* No Parity */ +#define COR1_FORCEPAR 0x20 /* Force Parity */ +#define COR1_NORMPAR 0x40 /* Normal Parity */ +#define COR1_IGNORE 0x10 /* Ignore Parity on RX */ +#define COR1_STOPBITS 0x0c /* Number of Stop Bits */ +#define COR1_1SB 0x00 /* 1 Stop Bit */ +#define COR1_15SB 0x04 /* 1.5 Stop Bits */ +#define COR1_2SB 0x08 /* 2 Stop Bits */ +#define COR1_CHARLEN 0x03 /* Character Length */ +#define COR1_5BITS 0x00 /* 5 bits */ +#define COR1_6BITS 0x01 /* 6 bits */ +#define COR1_7BITS 0x02 /* 7 bits */ +#define COR1_8BITS 0x03 /* 8 bits */ + + +/* Channel Option Register 2 (R/W) */ + +#define COR2_IXM 0x80 /* Implied XON mode */ +#define COR2_TXIBE 0x40 /* Enable In-Band (XON/XOFF) Flow Control */ +#define COR2_ETC 0x20 /* Embedded Tx Commands Enable */ +#define COR2_LLM 0x10 /* Local Loopback Mode */ +#define COR2_RLM 0x08 /* Remote Loopback Mode */ +#define COR2_RTSAO 0x04 /* RTS Automatic Output Enable */ +#define COR2_CTSAE 0x02 /* CTS Automatic Enable */ +#define COR2_DSRAE 0x01 /* DSR Automatic Enable */ + + +/* Channel Option Register 3 (R/W) */ + +#define COR3_XONCH 0x80 /* XON is a pair of characters (1 & 3) */ +#define COR3_XOFFCH 0x40 /* XOFF is a pair of characters (2 & 4) */ +#define COR3_FCT 0x20 /* Flow-Control Transparency Mode */ +#define COR3_SCDE 0x10 /* Special Character Detection Enable */ +#define COR3_RXTH 0x0f /* RX FIFO Threshold value (1-8) */ + + +/* Channel Control Status Register (R/O) */ + +#define CCSR_RXEN 0x80 /* Receiver Enabled */ +#define CCSR_RXFLOFF 0x40 /* Receive Flow Off (XOFF was sent) */ +#define CCSR_RXFLON 0x20 /* Receive Flow On (XON was sent) */ +#define CCSR_TXEN 0x08 /* Transmitter Enabled */ +#define CCSR_TXFLOFF 0x04 /* Transmit Flow Off (got XOFF) */ +#define CCSR_TXFLON 0x02 /* Transmit Flow On (got XON) */ + + +/* Modem Change Option Register 1 (R/W) */ + +#define MCOR1_DSRZD 0x80 /* Detect 0->1 transition of DSR */ +#define MCOR1_CDZD 0x40 /* Detect 0->1 transition of CD */ +#define MCOR1_CTSZD 0x20 /* Detect 0->1 transition of CTS */ +#define MCOR1_DTRTH 0x0f /* Auto DTR flow control Threshold (1-8) */ +#define MCOR1_NODTRFC 0x0 /* Automatic DTR flow control disabled */ + + +/* Modem Change Option Register 2 (R/W) */ + +#define MCOR2_DSROD 0x80 /* Detect 1->0 transition of DSR */ +#define MCOR2_CDOD 0x40 /* Detect 1->0 transition of CD */ +#define MCOR2_CTSOD 0x20 /* Detect 1->0 transition of CTS */ + + +/* Modem Change Register (R/W) */ + +#define MCR_DSRCHG 0x80 /* DSR Changed */ +#define MCR_CDCHG 0x40 /* CD Changed */ +#define MCR_CTSCHG 0x20 /* CTS Changed */ + + +/* Modem Signal Value Register (R/W) */ + +#define MSVR_DSR 0x80 /* Current state of DSR input */ +#define MSVR_CD 0x40 /* Current state of CD input */ +#define MSVR_CTS 0x20 /* Current state of CTS input */ +#define MSVR_DTR 0x02 /* Current state of DTR output */ +#define MSVR_RTS 0x01 /* Current state of RTS output */ + + +/* Escape characters */ + +#define CD180_C_ESC 0x00 /* Escape character */ +#define CD180_C_SBRK 0x81 /* Start sending BREAK */ +#define CD180_C_DELAY 0x82 /* Delay output */ +#define CD180_C_EBRK 0x83 /* Stop sending BREAK */ diff -u --recursive --new-file v1.3.93/linux/drivers/char/rtc.c linux/drivers/char/rtc.c --- v1.3.93/linux/drivers/char/rtc.c Mon Apr 15 12:20:18 1996 +++ linux/drivers/char/rtc.c Mon Apr 22 12:12:33 1996 @@ -552,7 +552,6 @@ restore_flags(flags); p = buf; - p += sprintf(p, "Real Time Clock Status:\n"); get_rtc_time(&tm); @@ -560,9 +559,10 @@ * There is no way to tell if the luser has the RTC set for local * time or for Universal Standard Time (GMT). Probably local though. */ - p += sprintf(p, "\tRTC reports %02d:%02d:%02d of %d-%d-%d.\n", - tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_mday, - tm.tm_mon + 1, tm.tm_year + 1900); + p += sprintf(p, "date : %04d-%02d-%02d\n", + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); + p += sprintf(p, "time : %02d-%02d-%02d\n", + tm.tm_hour, tm.tm_min, tm.tm_sec); get_rtc_alm_time(&tm); @@ -571,36 +571,44 @@ * match any value for that particular field. Values that are * greater than a valid time, but less than 0xc0 shouldn't appear. */ - p += sprintf(p, "\tAlarm set to match: "); + p += sprintf(p, "alarm : "); if (tm.tm_hour <= 24) - p += sprintf(p, "hour=%d, ", tm.tm_hour); + p += sprintf(p, "%02d", tm.tm_hour); else - p += sprintf(p, "hour=any, "); + p += sprintf(p, "**"); + p += sprintf(p, "-"); if (tm.tm_min <= 59) - p += sprintf(p, "min=%d, ", tm.tm_min); + p += sprintf(p, "%02d", tm.tm_min); else - p += sprintf(p, "min=any, "); + p += sprintf(p, "**"); + p += sprintf(p, "-"); if (tm.tm_sec <= 59) - p += sprintf(p, "sec=%d.\n", tm.tm_sec); + p += sprintf(p, "%02d", tm.tm_sec); else - p += sprintf(p, "sec=any.\n"); + p += sprintf(p, "**"); + p += sprintf(p, "\n"); - p += sprintf(p, "\tMisc. settings: daylight=%s; BCD=%s; 24hr=%s; Sq-Wave=%s.\n", - ((ctrl & RTC_DST_EN) ? "yes" : "no" ), - ((ctrl & RTC_DM_BINARY) ? "no" : "yes" ), - ((ctrl & RTC_24H) ? "yes" : "no" ), + p += sprintf(p, "daylight : %s\n", + ((ctrl & RTC_DST_EN) ? "yes" : "no" )); + p += sprintf(p, "bcd : %s\n", + ((ctrl & RTC_DM_BINARY) ? "no" : "yes" )); + p += sprintf(p, "24hr : %s\n", + ((ctrl & RTC_24H) ? "yes" : "no" )); + p += sprintf(p, "sqwave : %s\n", ((ctrl & RTC_SQWE) ? "yes" : "no" )); - p += sprintf(p, "\tInterrupt for: alarm=%s; update=%s; periodic=%s.\n", - ((ctrl & RTC_AIE) ? "yes" : "no" ), - ((ctrl & RTC_UIE) ? "yes" : "no" ), + p += sprintf(p, "alarm_int : %s\n", + ((ctrl & RTC_AIE) ? "yes" : "no" )); + p += sprintf(p, "update_int : %s\n", + ((ctrl & RTC_UIE) ? "yes" : "no" )); + p += sprintf(p, "periodic_int : %s\n", ((ctrl & RTC_PIE) ? "yes" : "no" )); - p += sprintf(p, "\tPeriodic interrupt rate set to %dHz.\n", + p += sprintf(p, "periodic_freq : %d\n", (freq ? (65536/(1< + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include "a2065.h" + +#ifdef A2065_DEBUG +int a2065_debug = A2065_DEBUG; +#else +int a2065_debug = 1; +#endif + + + /* + * Transmit/Receive Ring Definitions + */ + +#define LANCE_LOG_TX_BUFFERS (2) +#define LANCE_LOG_RX_BUFFERS (4) + +#define TX_RING_SIZE (1<cd_BoardAddr)) { + sn = cd->cd_Rom.er_SerialNumber; + if (key1) { /* Commodore */ + dev->dev_addr[0] = 0x00; + dev->dev_addr[1] = 0x80; + dev->dev_addr[2] = 0x10; + } else { /* Ameristar */ + dev->dev_addr[0] = 0x00; + dev->dev_addr[1] = 0x00; + dev->dev_addr[2] = 0x9f; + } + dev->dev_addr[3] = (sn>>16) & 0xff; + dev->dev_addr[4] = (sn>>8) & 0xff; + dev->dev_addr[5] = sn & 0xff; + printk("%s: A2065 at 0x%08lx, Ethernet Address %02x:%02x:%02x:%02x:%02x:%02x\n", + dev->name, board, dev->dev_addr[0], + dev->dev_addr[1], dev->dev_addr[2], + dev->dev_addr[3], dev->dev_addr[4], + dev->dev_addr[5]); + + init_etherdev(dev, 0); + + dev->priv = kmalloc(sizeof(struct + a2065_private), + GFP_KERNEL); + priv = (struct a2065_private *)dev->priv; + memset(priv, 0, sizeof(struct a2065_private)); + + priv->board = (struct A2065Board *)ZTWO_VADDR(board); + + dev->open = &a2065_open; + dev->stop = &a2065_close; + dev->hard_start_xmit = &a2065_start_xmit; + dev->get_stats = &a2065_get_stats; + dev->set_multicast_list = &set_multicast_list; + + zorro_config_board(key1 ? key1 : key2, 0); + return(0); + } + } + return(ENODEV); +} + + +static int a2065_open(struct device *dev) +{ + struct a2065_private *priv = (struct a2065_private *)dev->priv; + struct A2065Board *board = priv->board; + static int interruptinstalled = 0; + struct lancedata *lancedata; /* LANCE point of view */ + struct lancedata *alancedata; /* Amiga point of view */ + + lancedata = (struct lancedata *)offsetof(struct A2065Board, RAM); + alancedata = (struct lancedata *)board->RAM; + + /* Stop the LANCE */ + board->Lance.RAP = CSR0; /* LANCE Controller Status */ + board->Lance.RDP = STOP; + + /* Enable big endian byte ordering */ + board->Lance.RAP = CSR3; /* CSR3 */ + board->Lance.RDP = BSWP; + + /* Set the Init Block Pointer */ + board->Lance.RAP = CSR1; /* IADR[15:0] */ + board->Lance.RDP = (u_long)&lancedata->init; + board->Lance.RAP = CSR2; /* IADR[23:16] */ + board->Lance.RDP = 0x0000; + + /* Set the Mode */ + alancedata->init.Mode = 0; + + /* Set the Ethernet Hardware Address */ + /* Physical Address Register */ + alancedata->init.PADR[0] = dev->dev_addr[1]; + alancedata->init.PADR[1] = dev->dev_addr[0]; + alancedata->init.PADR[2] = dev->dev_addr[3]; + alancedata->init.PADR[3] = dev->dev_addr[2]; + alancedata->init.PADR[4] = dev->dev_addr[5]; + alancedata->init.PADR[5] = dev->dev_addr[4]; + + /* Set the Multicast Table */ + /* Logical Address Filter, LADRF[31:0] */ + alancedata->init.LADRF[0] = 0x00000000; + /* Logical Address Filter, LADRF[63:32] */ + alancedata->init.LADRF[1] = 0x00000000; + + /* Set the Receive and Transmit Descriptor Ring Pointers */ + alancedata->init.RDRA = (u_long)&lancedata->rx_ring; + alancedata->init.RLEN = LANCE_LOG_RX_BUFFERS << 13; + alancedata->init.TDRA = (u_long)&lancedata->tx_ring; + alancedata->init.TLEN = LANCE_LOG_TX_BUFFERS << 13; + + /* Initialise the Rings */ + a2065_init_ring(dev); + + + /* Install the Interrupt handler */ + if (!interruptinstalled) { + if (!add_isr(IRQ_AMIGA_PORTS, a2065_interrupt, 0, dev, + "a2065 Ethernet")) + return(-EAGAIN); + interruptinstalled = 1; + } + + /* Make the LANCE read the Init Block */ + board->Lance.RAP = CSR0; /* LANCE Controller Status */ + board->Lance.RDP = INEA|INIT; + + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; + + return(0); +} + + +static void a2065_init_ring(struct device *dev) +{ + struct a2065_private *priv = (struct a2065_private *)dev->priv; + struct A2065Board *board = priv->board; + struct lancedata *lancedata; /* LANCE point of view */ + struct lancedata *alancedata; /* Amiga point of view */ + int i; + + priv->lock = 0, priv->tx_full = 0; + priv->cur_rx = priv->cur_tx = 0; + priv->dirty_tx = 0; + + lancedata = (struct lancedata *)offsetof(struct A2065Board, RAM); + alancedata = (struct lancedata *)board->RAM; + + /* Set up TX Ring */ + for (i = 0; i < TX_RING_SIZE; i++) { + alancedata->tx_ring[i].TMD0 = (u_long)lancedata->tx_buff[i]; + alancedata->tx_ring[i].TMD1 = TF_STP|TF_ENP; + alancedata->tx_ring[i].TMD2 = -PKT_BUF_SIZE; + alancedata->tx_ring[i].TMD3 = 0x0000; + priv->tx_ring[i] = &alancedata->tx_ring[i]; + priv->tx_buff[i] = alancedata->tx_buff[i]; +#if 0 + printk("TX Entry %2d @ 0x%08x (LANCE 0x%08x), Buf @ 0x%08x (LANCE 0x%08x)\n", i, + (int)&alancedata->tx_ring[i], + (int)&lancedata->tx_ring[i], + (int)alancedata->tx_buff[i], + (int)lancedata->tx_buff[i]); +#endif + } + + /* Set up RX Ring */ + for (i = 0; i < RX_RING_SIZE; i++) { + alancedata->rx_ring[i].RMD0 = (u_long)lancedata->rx_buff[i]; + alancedata->rx_ring[i].RMD1 = RF_OWN; + alancedata->rx_ring[i].RMD2 = -PKT_BUF_SIZE; + alancedata->rx_ring[i].RMD3 = 0x0000; + priv->rx_ring[i] = &alancedata->rx_ring[i]; + priv->rx_buff[i] = alancedata->rx_buff[i]; +#if 0 + printk("RX Entry %2d @ 0x%08x (LANCE 0x%08x), Buf @ 0x%08x (LANCE 0x%08x)\n", i, + (int)&alancedata->rx_ring[i], + (int)&lancedata->rx_ring[i], + (int)alancedata->rx_buff[i], + (int)lancedata->rx_buff[i]); +#endif + } +} + + +static int a2065_close(struct device *dev) +{ + struct a2065_private *priv = (struct a2065_private *)dev->priv; + struct A2065Board *board = priv->board; + + dev->start = 0; + dev->tbusy = 1; + + board->Lance.RAP = CSR0; /* LANCE Controller Status */ + + if (a2065_debug > 1) { + printk("%s: Shutting down ethercard, status was %2.2x.\n", + dev->name, board->Lance.RDP); + printk("%s: %d packets missed\n", dev->name, + priv->stats.rx_missed_errors); + } + + /* We stop the LANCE here - it occasionally polls memory if we don't */ + board->Lance.RDP = STOP; + + return(0); +} + + +static void a2065_interrupt(int irq, struct pt_regs *fp, void *data) +{ + struct device *dev = (struct device *)data; + struct a2065_private *priv; + struct A2065Board *board; + int csr0, boguscnt = 10; + + if (dev == NULL) { + printk("a2065_interrupt(): irq for unknown device.\n"); + return; + } + + priv = (struct a2065_private *)dev->priv; + board = priv->board; + + board->Lance.RAP = CSR0; /* LANCE Controller Status */ + + if (!(board->Lance.RDP & INTR)) /* Check if any interrrupt has + been generated by the board. */ + return; + + if (dev->interrupt) + printk("%s: Re-entering the interrupt handler.\n", dev->name); + + dev->interrupt = 1; + + while ((csr0 = board->Lance.RDP) & (ERR|RINT|TINT) && --boguscnt >= 0){ + /* Acknowledge all of the current interrupt sources ASAP. */ + board->Lance.RDP = csr0 & ~(INEA|TDMD|STOP|STRT|INIT); + +#if 0 + if (a2065_debug > 5) { + printk("%s: interrupt csr0=%#2.2x new csr=%#2.2x.", + dev->name, csr0, board->Lance.RDP); + printk("["); + if (csr0 & INTR) + printk(" INTR"); + if (csr0 & INEA) + printk(" INEA"); + if (csr0 & RXON) + printk(" RXON"); + if (csr0 & TXON) + printk(" TXON"); + if (csr0 & TDMD) + printk(" TDMD"); + if (csr0 & STOP) + printk(" STOP"); + if (csr0 & STRT) + printk(" STRT"); + if (csr0 & INIT) + printk(" INIT"); + if (csr0 & ERR) + printk(" ERR"); + if (csr0 & BABL) + printk(" BABL"); + if (csr0 & CERR) + printk(" CERR"); + if (csr0 & MISS) + printk(" MISS"); + if (csr0 & MERR) + printk(" MERR"); + if (csr0 & RINT) + printk(" RINT"); + if (csr0 & TINT) + printk(" TINT"); + if (csr0 & IDON) + printk(" IDON"); + printk(" ]\n"); + } +#endif + + if (csr0 & RINT) /* Rx interrupt */ + a2065_rx(dev); + + if (csr0 & TINT) { /* Tx-done interrupt */ + int dirty_tx = priv->dirty_tx; + + while (dirty_tx < priv->cur_tx) { + int entry = dirty_tx % TX_RING_SIZE; + int status = + priv->tx_ring[entry]->TMD1 & 0xff00; + + if (status & TF_OWN) + break; /* It still hasn't been Txed */ + + priv->tx_ring[entry]->TMD1 &= 0x00ff; + + if (status & TF_ERR) { + /* There was an major error, log it. */ + int err_status = + priv->tx_ring[entry]->TMD3; + priv->stats.tx_errors++; + if (err_status & EF_RTRY) + priv->stats.tx_aborted_errors++; + if (err_status & EF_LCAR) + priv->stats.tx_carrier_errors++; + if (err_status & EF_LCOL) + priv->stats.tx_window_errors++; + if (err_status & EF_UFLO) { + /* Ackk! On FIFO errors the Tx unit is turned off! */ + priv->stats.tx_fifo_errors++; + /* Remove this verbosity later! */ + printk("%s: Tx FIFO error! Status %4.4x.\n", dev->name, csr0); + /* Restart the chip. */ + board->Lance.RDP = STRT; + } + } else { + if (status & (TF_MORE|TF_ONE)) + priv->stats.collisions++; + priv->stats.tx_packets++; + } + dirty_tx++; + } + +#ifndef final_version + if (priv->cur_tx - dirty_tx >= TX_RING_SIZE) { + printk("out-of-sync dirty pointer, %d vs. %d, full=%d.\n", + dirty_tx, priv->cur_tx, priv->tx_full); + dirty_tx += TX_RING_SIZE; + } +#endif + + if (priv->tx_full && dev->tbusy && dirty_tx > + priv->cur_tx - TX_RING_SIZE + 2) { + /* The ring is no longer full, clear tbusy. */ + priv->tx_full = 0; + dev->tbusy = 0; + mark_bh(NET_BH); + } + + priv->dirty_tx = dirty_tx; + } + + /* Log misc errors. */ + if (csr0 & BABL) + priv->stats.tx_errors++; /* Tx babble. */ + if (csr0 & MISS) + priv->stats.rx_errors++; /* Missed a Rx frame. */ + if (csr0 & MERR) { + printk("%s: Bus master arbitration failure, status %4.4x.\n", dev->name, csr0); + /* Restart the chip. */ + board->Lance.RDP = STRT; + } + } + + /* Clear any other interrupt, and set interrupt enable. */ + board->Lance.RAP = CSR0; /* LANCE Controller Status */ + board->Lance.RDP = INEA|BABL|CERR|MISS|MERR|IDON; + +#if 0 + if (a2065_debug > 4) + printk("%s: exiting interrupt, csr%d=%#4.4x.\n", + dev->name, board->Lance.RAP, board->Lance.RDP); +#endif + + dev->interrupt = 0; + return; +} + + +static int a2065_start_xmit(struct sk_buff *skb, struct device *dev) +{ + struct a2065_private *priv = (struct a2065_private *)dev->priv; + struct A2065Board *board = priv->board; + int entry; + + /* Transmitter timeout, serious problems. */ + if (dev->tbusy) { + int tickssofar = jiffies - dev->trans_start; + if (tickssofar < 20) + return(1); + board->Lance.RAP = CSR0; /* LANCE Controller Status */ + printk("%s: transmit timed out, status %4.4x, resetting.\n", dev->name, board->Lance.RDP); + board->Lance.RDP = STOP; + + /* Enable big endian byte ordering */ + board->Lance.RAP = CSR3; /* CSR3 */ + board->Lance.RDP = BSWP; + + priv->stats.tx_errors++; +#ifndef final_version + { + int i; + printk(" Ring data dump: dirty_tx %d cur_tx %d%s cur_rx %d.", + priv->dirty_tx, priv->cur_tx, priv->tx_full ? + " (full)" : "", priv->cur_rx); + for (i = 0 ; i < RX_RING_SIZE; i++) + printk("%s %08x %04x %04x", i & 0x3 ? "" : "\n ", + ((priv->rx_ring[i]->RMD1)<<16) | + priv->rx_ring[i]->RMD0, + -priv->rx_ring[i]->RMD2, priv->rx_ring[i]->RMD3); + for (i = 0 ; i < TX_RING_SIZE; i++) + printk("%s %08x %04x %04x", i & 0x3 ? "" : "\n ", + ((priv->tx_ring[i]->TMD1)<<16) | + priv->tx_ring[i]->TMD0, + -priv->tx_ring[i]->TMD2, priv->tx_ring[i]->TMD3); + printk("\n"); + } +#endif + a2065_init_ring(dev); + board->Lance.RDP = INEA|INIT; + + dev->tbusy = 0; + dev->trans_start = jiffies; + + return(0); + } + + if (skb == NULL) { + dev_tint(dev); + return(0); + } + + if (skb->len <= 0) + return(0); + +#if 0 + if (a2065_debug > 3) { + board->Lance.RAP = CSR0; /* LANCE Controller Status */ + printk("%s: a2065_start_xmit() called, csr0 %4.4x.\n", + dev->name, board->Lance.RDP); + board->Lance.RDP = 0x0000; + } +#endif + + /* + * Block a timer-based transmit from overlapping. This could better be + * done with atomic_swap(1, dev->tbusy), but set_bit() works as well. + */ + if (set_bit(0, (void*)&dev->tbusy) != 0) { + printk("%s: Transmitter access conflict.\n", dev->name); + return(1); + } + + if (set_bit(0, (void*)&priv->lock) != 0) { + if (a2065_debug > 0) + printk("%s: tx queue lock!.\n", dev->name); + /* don't clear dev->tbusy flag. */ + return(1); + } + + /* Fill in a Tx ring entry */ + +#if 0 + printk("TX pkt type 0x%04x from ", ((u_short *)skb->data)[6]); + { + int i; + u_char *ptr = &((u_char *)skb->data)[6]; + for (i = 0; i < 6; i++) + printk("%02x", ptr[i]); + } + printk(" to "); + { + int i; + u_char *ptr = (u_char *)skb->data; + for (i = 0; i < 6; i++) + printk("%02x", ptr[i]); + } + printk(" data 0x%08x len %d\n", (int)skb->data, (int)skb->len); +#endif + + entry = priv->cur_tx % TX_RING_SIZE; + + priv->tx_ring[entry]->TMD2 = -(ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN); + priv->tx_ring[entry]->TMD3 = 0x0000; + memcpy(priv->tx_buff[entry], skb->data, skb->len); + +#if 0 + { + int i, len; + + len = skb->len > 64 ? 64 : skb->len; + for (i = 0; i < len; i += 8) { + int j; + printk("%02x:", i); + for (j = 0; (j < 16) && ((i+j) < len); j++) { + if (!(j & 1)) + printk(" "); + printk("%02x", priv->tx_buff[entry][i+j]); + } + printk("\n"); + } + } +#endif + + priv->tx_ring[entry]->TMD1 = (priv->tx_ring[entry]->TMD1 & + 0x00ff)|TF_OWN|TF_STP|TF_ENP; + + dev_kfree_skb(skb, FREE_WRITE); + + priv->cur_tx++; + if ((priv->cur_tx >= TX_RING_SIZE)&&(priv->dirty_tx >= TX_RING_SIZE)){ + +#if 0 + printk("*** Subtracting TX_RING_SIZE from cur_tx (%d) and dirty_tx (%d)\n", + priv->cur_tx, priv->dirty_tx); +#endif + + priv->cur_tx -= TX_RING_SIZE; + priv->dirty_tx -= TX_RING_SIZE; + } + + /* Trigger an immediate send poll. */ + board->Lance.RAP = CSR0; /* LANCE Controller Status */ + board->Lance.RDP = INEA|TDMD; + + dev->trans_start = jiffies; + + cli(); + priv->lock = 0; + if ((priv->tx_ring[(entry+1) % TX_RING_SIZE]->TMD1 & 0xff00) == 0) + dev->tbusy = 0; + else + priv->tx_full = 1; + sti(); + + return(0); +} + + +static int a2065_rx(struct device *dev) +{ + struct a2065_private *priv = (struct a2065_private *)dev->priv; + int entry = priv->cur_rx % RX_RING_SIZE; + int i; + + /* If we own the next entry, it's a new packet. Send it up. */ + while (!(priv->rx_ring[entry]->RMD1 & RF_OWN)) { + int status = priv->rx_ring[entry]->RMD1 & 0xff00; + + if (status != (RF_STP|RF_ENP)) { /* There was an error. */ + /* There is a tricky error noted by John Murphy, + to Russ Nelson: Even with full-sized + buffers it's possible for a jabber packet to use two + buffers, with only the last correctly noting the error. */ + if (status & RF_ENP) + /* Only count a general error at the */ + priv->stats.rx_errors++; /* end of a packet.*/ + if (status & RF_FRAM) + priv->stats.rx_frame_errors++; + if (status & RF_OFLO) + priv->stats.rx_over_errors++; + if (status & RF_CRC) + priv->stats.rx_crc_errors++; + if (status & RF_BUFF) + priv->stats.rx_fifo_errors++; + priv->rx_ring[entry]->RMD1 &= 0x00ff|RF_STP|RF_ENP; + } else { + /* Malloc up new buffer, compatible with net-3. */ + short pkt_len = priv->rx_ring[entry]->RMD3; + struct sk_buff *skb; + + if(pkt_len<60) + { + printk("%s: Runt packet!\n",dev->name); + priv->stats.rx_errors++; + } + else + { + skb = dev_alloc_skb(pkt_len+2); + if (skb == NULL) { + printk("%s: Memory squeeze, deferring packet.\n", dev->name); + for (i = 0; i < RX_RING_SIZE; i++) + if (priv->rx_ring[(entry+i) % RX_RING_SIZE]->RMD1 & RF_OWN) + break; + + if (i > RX_RING_SIZE-2) { + priv->stats.rx_dropped++; + priv->rx_ring[entry]->RMD1 |= RF_OWN; + priv->cur_rx++; + } + break; + } + skb->dev = dev; + skb_reserve(skb,2); /* 16 byte align */ + skb_put(skb,pkt_len); /* Make room */ + eth_copy_and_sum(skb, + priv->rx_buff[entry], + pkt_len,0); + skb->protocol=eth_type_trans(skb,dev); +#if 0 + printk("RX pkt type 0x%04x from ", + ((u_short *)skb->data)[6]); + { + int i; + u_char *ptr = &((u_char *)skb->data)[6]; + for (i = 0; i < 6; i++) + printk("%02x", ptr[i]); + } + printk(" to "); + { + int i; + u_char *ptr = (u_char *)skb->data; + for (i = 0; i < 6; i++) + printk("%02x", ptr[i]); + } + printk(" data 0x%08x len %d\n", + (int)skb->data, (int)skb->len); +#endif + + netif_rx(skb); + priv->stats.rx_packets++; + } + } + priv->rx_ring[entry]->RMD1 |= RF_OWN; + entry = (++priv->cur_rx) % RX_RING_SIZE; + } + + priv->cur_rx = priv->cur_rx % RX_RING_SIZE; + + /* We should check that at least two ring entries are free. + If not, we should free one and mark stats->rx_dropped++. */ + + return(0); +} + + +static struct enet_statistics *a2065_get_stats(struct device *dev) +{ + struct a2065_private *priv = (struct a2065_private *)dev->priv; + + return(&priv->stats); +} + + +/* Set or clear the multicast filter for this adaptor. + */ +static void set_multicast_list(struct device *dev) +{ + struct a2065_private *priv = (struct a2065_private *)dev->priv; + struct A2065Board *board = priv->board; + struct lancedata *alancedata; /* Amiga point of view */ + alancedata = (struct lancedata *)board->RAM; + + /* We take the simple way out and always enable promiscuous mode. */ + board->Lance.RAP = CSR0; /* LANCE Controller Status */ + board->Lance.RDP = STOP; /* Temporarily stop the lance. */ + + /* Enable big endian byte ordering */ + board->Lance.RAP = CSR3; /* CSR3 */ + board->Lance.RDP = BSWP; + + if (dev->flags&IFF_PROMISC) { + /* Log any net taps. */ + printk("%s: Promiscuous mode enabled.\n", dev->name); + alancedata->init.Mode = PROM; /* Set promiscuous mode */ + } else { + short multicast_table[4]; + int num_addrs=dev->mc_count; + if(dev->flags&IFF_ALLMULTI) + num_addrs=1; + /* + * We don't use the multicast table, + * but rely on upper-layer filtering. + */ + memset(multicast_table, (num_addrs == 0) ? 0 : -1, + sizeof(multicast_table)); + alancedata->init.LADRF[0] = multicast_table[0]<<16 | + multicast_table[1]; + alancedata->init.LADRF[1] = multicast_table[2]<<16 | + multicast_table[3]; + alancedata->init.Mode = 0x0000; + } + + board->Lance.RAP = CSR0; /* LANCE Controller Status */ + board->Lance.RDP = INEA|STRT|IDON|INIT; /* Resume normal operation. */ +} diff -u --recursive --new-file v1.3.93/linux/drivers/net/a2065.h linux/drivers/net/a2065.h --- v1.3.93/linux/drivers/net/a2065.h Thu Jan 1 02:00:00 1970 +++ linux/drivers/net/a2065.h Sun Mar 31 01:00:06 1996 @@ -0,0 +1,195 @@ +/* + * Amiga Linux/68k A2065 Ethernet Driver + * + * (C) Copyright 1995 by Geert Uytterhoeven + * (Geert.Uytterhoeven@cs.kuleuven.ac.be) + * + * --------------------------------------------------------------------------- + * + * This program is based on + * + * ariadne.?: Amiga Linux/68k Ariadne Ethernet Driver + * (C) Copyright 1995 by Geert Uytterhoeven, + * Peter De Schrijver + * + * lance.c: An AMD LANCE ethernet driver for linux. + * Written 1993-94 by Donald Becker. + * + * Am79C960: PCnet(tm)-ISA Single-Chip Ethernet Controller + * Advanced Micro Devices + * Publication #16907, Rev. B, Amendment/0, May 1994 + * + * --------------------------------------------------------------------------- + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file README.legal in the main directory of the Linux/68k + * distribution for more details. + * + * --------------------------------------------------------------------------- + * + * The A2065 is a Zorro-II board made by Commodore/Ameristar. It contains: + * + * - an Am7990 Local Area Network Controller for Ethernet (LANCE) with + * both 10BASE-2 (thin coax) and AUI (DB-15) connectors + */ + + +/* + * Am7990 Local Area Network Controller for Ethernet (LANCE) + */ + +struct Am7990 { + volatile u_short RDP; /* Register Data Port */ + volatile u_short RAP; /* Register Address Port */ +}; + + +/* + * Am7990 Control and Status Registers + */ + +#define CSR0 0x0000 /* LANCE Controller Status */ +#define CSR1 0x0001 /* IADR[15:0] */ +#define CSR2 0x0002 /* IADR[23:16] */ +#define CSR3 0x0003 /* Misc */ + + +/* + * Bit definitions for CSR0 (LANCE Controller Status) + */ + +#define ERR 0x8000 /* Error */ +#define BABL 0x4000 /* Babble: Transmitted too many bits */ +#define CERR 0x2000 /* No Heartbeat (10BASE-T) */ +#define MISS 0x1000 /* Missed Frame */ +#define MERR 0x0800 /* Memory Error */ +#define RINT 0x0400 /* Receive Interrupt */ +#define TINT 0x0200 /* Transmit Interrupt */ +#define IDON 0x0100 /* Initialization Done */ +#define INTR 0x0080 /* Interrupt Flag */ +#define INEA 0x0040 /* Interrupt Enable */ +#define RXON 0x0020 /* Receive On */ +#define TXON 0x0010 /* Transmit On */ +#define TDMD 0x0008 /* Transmit Demand */ +#define STOP 0x0004 /* Stop */ +#define STRT 0x0002 /* Start */ +#define INIT 0x0001 /* Initialize */ + + +/* + * Bit definitions for CSR3 + */ + +#define BSWP 0x0004 /* Byte Swap + (on for big endian byte order) */ +#define ACON 0x0002 /* ALE Control + (on for active low ALE) */ +#define BCON 0x0001 /* Byte Control */ + + +/* + * Initialization Block + */ + +struct InitBlock { + u_short Mode; /* Mode */ + u_char PADR[6]; /* Physical Address */ + u_long LADRF[2]; /* Logical Address Filter */ + u_short RDRA; /* Receive Descriptor Ring Address */ + u_short RLEN; /* Receive Descriptor Ring Length */ + u_short TDRA; /* Transmit Descriptor Ring Address */ + u_short TLEN; /* Transmit Descriptor Ring Length */ +}; + + +/* + * Mode Flags + */ + +#define PROM 0x8000 /* Promiscuous Mode */ +#define INTL 0x0040 /* Internal Loopback */ +#define DRTY 0x0020 /* Disable Retry */ +#define FCOLL 0x0010 /* Force Collision */ +#define DXMTFCS 0x0008 /* Disable Transmit CRC */ +#define LOOP 0x0004 /* Loopback Enable */ +#define DTX 0x0002 /* Disable Transmitter */ +#define DRX 0x0001 /* Disable Receiver */ + + +/* + * Receive Descriptor Ring Entry + */ + +struct RDRE { + volatile u_short RMD0; /* LADR[15:0] */ + volatile u_short RMD1; /* HADR[23:16] | Receive Flags */ + volatile u_short RMD2; /* Buffer Byte Count + (two's complement) */ + volatile u_short RMD3; /* Message Byte Count */ +}; + + +/* + * Transmit Descriptor Ring Entry + */ + +struct TDRE { + volatile u_short TMD0; /* LADR[15:0] */ + volatile u_short TMD1; /* HADR[23:16] | Transmit Flags */ + volatile u_short TMD2; /* Buffer Byte Count + (two's complement) */ + volatile u_short TMD3; /* Error Flags */ +}; + + +/* + * Receive Flags + */ + +#define RF_OWN 0x8000 /* LANCE owns the descriptor */ +#define RF_ERR 0x4000 /* Error */ +#define RF_FRAM 0x2000 /* Framing Error */ +#define RF_OFLO 0x1000 /* Overflow Error */ +#define RF_CRC 0x0800 /* CRC Error */ +#define RF_BUFF 0x0400 /* Buffer Error */ +#define RF_STP 0x0200 /* Start of Packet */ +#define RF_ENP 0x0100 /* End of Packet */ + + +/* + * Transmit Flags + */ + +#define TF_OWN 0x8000 /* LANCE owns the descriptor */ +#define TF_ERR 0x4000 /* Error */ +#define TF_RES 0x2000 /* Reserved, + LANCE writes this with a zero */ +#define TF_MORE 0x1000 /* More than one retry needed */ +#define TF_ONE 0x0800 /* One retry needed */ +#define TF_DEF 0x0400 /* Deferred */ +#define TF_STP 0x0200 /* Start of Packet */ +#define TF_ENP 0x0100 /* End of Packet */ + + +/* + * Error Flags + */ + +#define EF_BUFF 0x8000 /* Buffer Error */ +#define EF_UFLO 0x4000 /* Underflow Error */ +#define EF_LCOL 0x1000 /* Late Collision */ +#define EF_LCAR 0x0800 /* Loss of Carrier */ +#define EF_RTRY 0x0400 /* Retry Error */ +#define EF_TDR 0x003f /* Time Domain Reflectometry */ + + +/* + * A2065 Expansion Board Structure + */ + +struct A2065Board { + u_char Pad1[0x4000]; + struct Am7990 Lance; + u_char Pad2[0x3ffc]; + volatile u_char RAM[0x8000]; +}; diff -u --recursive --new-file v1.3.93/linux/drivers/net/ariadne.c linux/drivers/net/ariadne.c --- v1.3.93/linux/drivers/net/ariadne.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/net/ariadne.c Thu Apr 11 02:15:34 1996 @@ -0,0 +1,836 @@ +/* + * Amiga Linux/m68k Ariadne Ethernet Driver + * + * © Copyright 1995 by Geert Uytterhoeven + * (Geert.Uytterhoeven@cs.kuleuven.ac.be) + * Peter De Schrijver + * (Peter.DeSchrijver@linux.cc.kuleuven.ac.be) + * + * ---------------------------------------------------------------------------------- + * + * This program is based on + * + * lance.c: An AMD LANCE ethernet driver for linux. + * Written 1993-94 by Donald Becker. + * + * Am79C960: PCnet(tm)-ISA Single-Chip Ethernet Controller + * Advanced Micro Devices + * Publication #16907, Rev. B, Amendment/0, May 1994 + * + * MC68230: Parallel Interface/Timer (PI/T) + * Motorola Semiconductors, December, 1983 + * + * ---------------------------------------------------------------------------------- + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file README.legal in the main directory of the Linux/m68k + * distribution for more details. + * + * ---------------------------------------------------------------------------------- + * + * The Ariadne is a Zorro-II board made by Village Tronic. It contains: + * + * - an Am79C960 PCnet-ISA Single-Chip Ethernet Controller with both + * 10BASE-2 (thin coax) and 10BASE-T (UTP) connectors + * + * - an MC68230 Parallel Interface/Timer configured as 2 parallel ports + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "ariadne.h" + + +#ifdef ARIADNE_DEBUG +int ariadne_debug = ARIADNE_DEBUG; +#else +int ariadne_debug = 1; +#endif + + + /* + * Macros to Fix Endianness problems + */ + + /* Swap the Bytes in a WORD */ +#define swapw(x) (((x>>8)&0x00ff)|((x<<8)&0xff00)) + /* Get the Low BYTE in a WORD */ +#define lowb(x) (x&0xff) + /* Get the Swapped High WORD in a LONG */ +#define swhighw(x) ((((x)>>8)&0xff00)|(((x)>>24)&0x00ff)) + /* Get the Swapped Low WORD in a LONG */ +#define swloww(x) ((((x)<<8)&0xff00)|(((x)>>8)&0x00ff)) + + + /* + * Transmit/Receive Ring Definitions + */ + +#define TX_RING_SIZE 5 +#define RX_RING_SIZE 16 + +#define PKT_BUF_SIZE 1520 + + + /* + * Private Device Data + */ + +struct ariadne_private { + struct AriadneBoard *board; + struct TDRE *tx_ring[TX_RING_SIZE]; + struct RDRE *rx_ring[RX_RING_SIZE]; + u_short *tx_buff[TX_RING_SIZE]; + u_short *rx_buff[RX_RING_SIZE]; + int cur_tx, cur_rx; /* The next free ring entry */ + int dirty_tx; /* The ring entries to be free()ed. */ + struct enet_statistics stats; + char tx_full; + unsigned long lock; +}; + + + /* + * Structure Created in the Ariadne's RAM Buffer + */ + +struct lancedata { + struct TDRE tx_ring[TX_RING_SIZE]; + struct RDRE rx_ring[RX_RING_SIZE]; + u_short tx_buff[TX_RING_SIZE][PKT_BUF_SIZE/sizeof(u_short)]; + u_short rx_buff[RX_RING_SIZE][PKT_BUF_SIZE/sizeof(u_short)]; +}; + + +static int ariadne_open(struct device *dev); +static void ariadne_init_ring(struct device *dev); +static int ariadne_start_xmit(struct sk_buff *skb, struct device *dev); +static int ariadne_rx(struct device *dev); +static void ariadne_interrupt(int irq, struct pt_regs *fp, void *data); +static int ariadne_close(struct device *dev); +static struct enet_statistics *ariadne_get_stats(struct device *dev); +#ifdef HAVE_MULTICAST +static void set_multicast_list(struct device *dev); +#endif + + +static void memcpyw(u_short *dest, u_short *src, int len) +{ + while (len >= 2) { + *(dest++) = *(src++); + len -= 2; + } + if (len == 1) + *dest = (*(u_char *)src)<<8; +} + + +int long ariadne_probe(struct device *dev) +{ + int key; + struct ConfigDev *cd; + u_long board; + struct ariadne_private *priv; + + /* Ethernet is part 0, Parallel is part 1 */ + if ((key = zorro_find(MANUF_VILLAGE_TRONIC, PROD_ARIADNE, 0, 0))) { + cd = zorro_get_board(key); + if ((board = (u_long)cd->cd_BoardAddr)) { + dev->dev_addr[0] = 0x00; + dev->dev_addr[1] = 0x60; + dev->dev_addr[2] = 0x30; + dev->dev_addr[3] = (cd->cd_Rom.er_SerialNumber>>16)&0xff; + dev->dev_addr[4] = (cd->cd_Rom.er_SerialNumber>>8)&0xff; + dev->dev_addr[5] = cd->cd_Rom.er_SerialNumber&0xff; + printk("%s: Ariadne at 0x%08lx, Ethernet Address " + "%02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, board, + dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], + dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + + init_etherdev(dev, 0); + + dev->priv = kmalloc(sizeof(struct ariadne_private), GFP_KERNEL); + priv = (struct ariadne_private *)dev->priv; + memset(priv, 0, sizeof(struct ariadne_private)); + + priv->board = (struct AriadneBoard *)ZTWO_VADDR(board); + + dev->open = &ariadne_open; + dev->stop = &ariadne_close; + dev->hard_start_xmit = &ariadne_start_xmit; + dev->get_stats = &ariadne_get_stats; + dev->set_multicast_list = &set_multicast_list; + + zorro_config_board(key, 0); + return(0); + } + } + return(ENODEV); +} + + +static int ariadne_open(struct device *dev) +{ + struct ariadne_private *priv = (struct ariadne_private *)dev->priv; + struct AriadneBoard *board = priv->board; + static int interruptinstalled = 0; + struct lancedata *lancedata; + u_short in; + u_long version; + + /* Reset the LANCE */ + in = board->Lance.Reset; + + /* Stop the LANCE */ + board->Lance.RAP = CSR0; /* PCnet-ISA Controller Status */ + board->Lance.RDP = STOP; + + /* Check the LANCE version */ + board->Lance.RAP = CSR88; /* Chip ID */ + version = swapw(board->Lance.RDP); + board->Lance.RAP = CSR89; /* Chip ID */ + version |= swapw(board->Lance.RDP)<<16; + if ((version & 0x00000fff) != 0x00000003) { + printk("ariadne_open: Couldn't find AMD Ethernet Chip\n"); + return(-EAGAIN); + } + if ((version & 0x0ffff000) != 0x00003000) { + printk("ariadne_open: Couldn't find Am79C960 (Wrong part number = %ld)\n", + (version & 0x0ffff000)>>12); + return(-EAGAIN); + } +#if 0 + printk("ariadne_open: Am79C960 (PCnet-ISA) Revision %ld\n", + (version & 0xf0000000)>>28); +#endif + + ariadne_init_ring(dev); + + /* Miscellaneous Stuff */ + board->Lance.RAP = CSR3; /* Interrupt Masks and Deferral Control */ + board->Lance.RDP = 0x0000; + board->Lance.RAP = CSR4; /* Test and Features Control */ + board->Lance.RDP = DPOLL|APAD_XMT|MFCOM|RCVCCOM|TXSTRTM|JABM; + + /* Set the Multicast Table */ + board->Lance.RAP = CSR8; /* Logical Address Filter, LADRF[15:0] */ + board->Lance.RDP = 0x0000; + board->Lance.RAP = CSR9; /* Logical Address Filter, LADRF[31:16] */ + board->Lance.RDP = 0x0000; + board->Lance.RAP = CSR10; /* Logical Address Filter, LADRF[47:32] */ + board->Lance.RDP = 0x0000; + board->Lance.RAP = CSR11; /* Logical Address Filter, LADRF[63:48] */ + board->Lance.RDP = 0x0000; + + /* Set the Ethernet Hardware Address */ + board->Lance.RAP = CSR12; /* Physical Address Register, PADR[15:0] */ + board->Lance.RDP = ((u_short *)&dev->dev_addr[0])[0]; + board->Lance.RAP = CSR13; /* Physical Address Register, PADR[31:16] */ + board->Lance.RDP = ((u_short *)&dev->dev_addr[0])[1]; + board->Lance.RAP = CSR14; /* Physical Address Register, PADR[47:32] */ + board->Lance.RDP = ((u_short *)&dev->dev_addr[0])[2]; + + /* Set the Init Block Mode */ + board->Lance.RAP = CSR15; /* Mode Register */ + board->Lance.RDP = 0x0000; + + lancedata = (struct lancedata *)offsetof(struct AriadneBoard, RAM); + + /* Set the Transmit Descriptor Ring Pointer */ + board->Lance.RAP = CSR30; /* Base Address of Transmit Ring */ + board->Lance.RDP = swloww((u_long)&lancedata->tx_ring); + board->Lance.RAP = CSR31; /* Base Address of transmit Ring */ + board->Lance.RDP = swhighw((u_long)&lancedata->tx_ring); + + /* Set the Receive Descriptor Ring Pointer */ + board->Lance.RAP = CSR24; /* Base Address of Receive Ring */ + board->Lance.RDP = swloww((u_long)&lancedata->rx_ring); + board->Lance.RAP = CSR25; /* Base Address of Receive Ring */ + board->Lance.RDP = swhighw((u_long)&lancedata->rx_ring); + + /* Set the Number of RX and TX Ring Entries */ + board->Lance.RAP = CSR76; /* Receive Ring Length */ + board->Lance.RDP = swapw(((u_short)-RX_RING_SIZE)); + board->Lance.RAP = CSR78; /* Transmit Ring Length */ + board->Lance.RDP = swapw(((u_short)-TX_RING_SIZE)); + + /* Enable Media Interface Port Auto Select (10BASE-2/10BASE-T) */ + board->Lance.RAP = ISACSR2; /* Miscellaneous Configuration */ + board->Lance.IDP = ASEL; + + /* LED Control */ + board->Lance.RAP = ISACSR5; /* LED1 Status */ + board->Lance.IDP = PSE|XMTE; + board->Lance.RAP = ISACSR6; /* LED2 Status */ + board->Lance.IDP = PSE|COLE; + board->Lance.RAP = ISACSR7; /* LED3 Status */ + board->Lance.IDP = PSE|RCVE; + + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; + + if (!interruptinstalled) { + if (!add_isr(IRQ_AMIGA_PORTS, ariadne_interrupt, 0, dev, + "Ariadne Ethernet")) + return(-EAGAIN); + interruptinstalled = 1; + } + + board->Lance.RAP = CSR0; /* PCnet-ISA Controller Status */ + board->Lance.RDP = INEA|STRT; + + return(0); +} + + +static void ariadne_init_ring(struct device *dev) +{ + struct ariadne_private *priv = (struct ariadne_private *)dev->priv; + struct AriadneBoard *board = priv->board; + struct lancedata *lancedata; /* LANCE point of view */ + struct lancedata *alancedata; /* Amiga point of view */ + int i; + + priv->lock = 0, priv->tx_full = 0; + priv->cur_rx = priv->cur_tx = 0; + priv->dirty_tx = 0; + + lancedata = (struct lancedata *)offsetof(struct AriadneBoard, RAM); + alancedata = (struct lancedata *)board->RAM; + + /* Set up TX Ring */ + for (i = 0; i < TX_RING_SIZE; i++) { + alancedata->tx_ring[i].TMD0 = swloww((u_long)lancedata->tx_buff[i]); + alancedata->tx_ring[i].TMD1 = swhighw((u_long)lancedata->tx_buff[i])|TF_STP|TF_ENP; + alancedata->tx_ring[i].TMD2 = swapw((u_short)-PKT_BUF_SIZE); + alancedata->tx_ring[i].TMD3 = 0; + priv->tx_ring[i] = &alancedata->tx_ring[i]; + priv->tx_buff[i] = alancedata->tx_buff[i]; +#if 0 + printk("TX Entry %2d @ 0x%08x (LANCE 0x%08x), Buf @ 0x%08x (LANCE 0x%08x)\n", + i, (int)&alancedata->tx_ring[i], (int)&lancedata->tx_ring[i], + (int)alancedata->tx_buff[i], (int)lancedata->tx_buff[i]); +#endif + } + + /* Set up RX Ring */ + for (i = 0; i < RX_RING_SIZE; i++) { + alancedata->rx_ring[i].RMD0 = swloww((u_long)lancedata->rx_buff[i]); + alancedata->rx_ring[i].RMD1 = swhighw((u_long)lancedata->rx_buff[i])|RF_OWN; + alancedata->rx_ring[i].RMD2 = swapw((u_short)-PKT_BUF_SIZE); + alancedata->rx_ring[i].RMD3 = 0x0000; + priv->rx_ring[i] = &alancedata->rx_ring[i]; + priv->rx_buff[i] = alancedata->rx_buff[i]; +#if 0 + printk("RX Entry %2d @ 0x%08x (LANCE 0x%08x), Buf @ 0x%08x (LANCE 0x%08x)\n", + i, (int)&alancedata->rx_ring[i], (int)&lancedata->rx_ring[i], + (int)alancedata->rx_buff[i], (int)lancedata->rx_buff[i]); +#endif + } +} + + +static int ariadne_close(struct device *dev) +{ + struct ariadne_private *priv = (struct ariadne_private *)dev->priv; + struct AriadneBoard *board = priv->board; + + dev->start = 0; + dev->tbusy = 1; + + board->Lance.RAP = CSR112; /* Missed Frame Count */ + priv->stats.rx_missed_errors = swapw(board->Lance.RDP); + board->Lance.RAP = CSR0; /* PCnet-ISA Controller Status */ + + if (ariadne_debug > 1) { + printk("%s: Shutting down ethercard, status was %2.2x.\n", dev->name, + board->Lance.RDP); + printk("%s: %d packets missed\n", dev->name, + priv->stats.rx_missed_errors); + } + + /* We stop the LANCE here -- it occasionally polls memory if we don't. */ + board->Lance.RDP = STOP; + + return(0); +} + + +static void ariadne_interrupt(int irq, struct pt_regs *fp, void *data) +{ + struct device *dev = (struct device *)data; + struct ariadne_private *priv; + struct AriadneBoard *board; + int csr0, boguscnt = 10; + + if (dev == NULL) { + printk("ariadne_interrupt(): irq for unknown device.\n"); + return; + } + + priv = (struct ariadne_private *)dev->priv; + board = priv->board; + + board->Lance.RAP = CSR0; /* PCnet-ISA Controller Status */ + + if (!(board->Lance.RDP & INTR)) /* Check if any interrrupt has been + return; generated by the board. */ + + if (dev->interrupt) + printk("%s: Re-entering the interrupt handler.\n", dev->name); + + dev->interrupt = 1; + + while ((csr0 = board->Lance.RDP) & (ERR|RINT|TINT) && --boguscnt >= 0) { + /* Acknowledge all of the current interrupt sources ASAP. */ + board->Lance.RDP = csr0 & ~(INEA|TDMD|STOP|STRT|INIT); + +#if 0 + if (ariadne_debug > 5) { + printk("%s: interrupt csr0=%#2.2x new csr=%#2.2x.", dev->name, + csr0, board->Lance.RDP); + printk("["); + if (csr0 & INTR) + printk(" INTR"); + if (csr0 & INEA) + printk(" INEA"); + if (csr0 & RXON) + printk(" RXON"); + if (csr0 & TXON) + printk(" TXON"); + if (csr0 & TDMD) + printk(" TDMD"); + if (csr0 & STOP) + printk(" STOP"); + if (csr0 & STRT) + printk(" STRT"); + if (csr0 & INIT) + printk(" INIT"); + if (csr0 & ERR) + printk(" ERR"); + if (csr0 & BABL) + printk(" BABL"); + if (csr0 & CERR) + printk(" CERR"); + if (csr0 & MISS) + printk(" MISS"); + if (csr0 & MERR) + printk(" MERR"); + if (csr0 & RINT) + printk(" RINT"); + if (csr0 & TINT) + printk(" TINT"); + if (csr0 & IDON) + printk(" IDON"); + printk(" ]\n"); + } +#endif + + if (csr0 & RINT) /* Rx interrupt */ + ariadne_rx(dev); + + if (csr0 & TINT) { /* Tx-done interrupt */ + int dirty_tx = priv->dirty_tx; + + while (dirty_tx < priv->cur_tx) { + int entry = dirty_tx % TX_RING_SIZE; + int status = lowb(priv->tx_ring[entry]->TMD1); + + if (status & TF_OWN) + break; /* It still hasn't been Txed */ + + priv->tx_ring[entry]->TMD1 &= 0xff00; + + if (status & TF_ERR) { + /* There was an major error, log it. */ + int err_status = priv->tx_ring[entry]->TMD3; + priv->stats.tx_errors++; + if (err_status & EF_RTRY) + priv->stats.tx_aborted_errors++; + if (err_status & EF_LCAR) + priv->stats.tx_carrier_errors++; + if (err_status & EF_LCOL) + priv->stats.tx_window_errors++; + if (err_status & EF_UFLO) { + /* Ackk! On FIFO errors the Tx unit is turned off! */ + priv->stats.tx_fifo_errors++; + /* Remove this verbosity later! */ + printk("%s: Tx FIFO error! Status %4.4x.\n", dev->name, + csr0); + /* Restart the chip. */ + board->Lance.RDP = STRT; + } + } else { + if (status & (TF_MORE|TF_ONE)) + priv->stats.collisions++; + priv->stats.tx_packets++; + } + dirty_tx++; + } + +#ifndef final_version + if (priv->cur_tx - dirty_tx >= TX_RING_SIZE) { + printk("out-of-sync dirty pointer, %d vs. %d, full=%d.\n", + dirty_tx, priv->cur_tx, priv->tx_full); + dirty_tx += TX_RING_SIZE; + } +#endif + + if (priv->tx_full && dev->tbusy && + dirty_tx > priv->cur_tx - TX_RING_SIZE + 2) { + /* The ring is no longer full, clear tbusy. */ + priv->tx_full = 0; + dev->tbusy = 0; + mark_bh(NET_BH); + } + + priv->dirty_tx = dirty_tx; + } + + /* Log misc errors. */ + if (csr0 & BABL) + priv->stats.tx_errors++; /* Tx babble. */ + if (csr0 & MISS) + priv->stats.rx_errors++; /* Missed a Rx frame. */ + if (csr0 & MERR) { + printk("%s: Bus master arbitration failure, status %4.4x.\n", + dev->name, csr0); + /* Restart the chip. */ + board->Lance.RDP = STRT; + } + } + + /* Clear any other interrupt, and set interrupt enable. */ + board->Lance.RAP = CSR0; /* PCnet-ISA Controller Status */ + board->Lance.RDP = INEA|BABL|CERR|MISS|MERR|IDON; + +#if 0 + if (ariadne_debug > 4) + printk("%s: exiting interrupt, csr%d=%#4.4x.\n", dev->name, + board->Lance.RAP, board->Lance.RDP); +#endif + + dev->interrupt = 0; + return; +} + + +static int ariadne_start_xmit(struct sk_buff *skb, struct device *dev) +{ + struct ariadne_private *priv = (struct ariadne_private *)dev->priv; + struct AriadneBoard *board = priv->board; + int entry; + + /* Transmitter timeout, serious problems. */ + if (dev->tbusy) { + int tickssofar = jiffies - dev->trans_start; + if (tickssofar < 20) + return(1); + board->Lance.RAP = CSR0; /* PCnet-ISA Controller Status */ + printk("%s: transmit timed out, status %4.4x, resetting.\n", dev->name, + board->Lance.RDP); + board->Lance.RDP = STOP; + priv->stats.tx_errors++; +#ifndef final_version + { + int i; + printk(" Ring data dump: dirty_tx %d cur_tx %d%s cur_rx %d.", + priv->dirty_tx, priv->cur_tx, priv->tx_full ? " (full)" : "", + priv->cur_rx); + for (i = 0 ; i < RX_RING_SIZE; i++) + printk("%s %08x %04x %04x", i & 0x3 ? "" : "\n ", + (swapw((priv->rx_ring[i]->RMD1))<<16)|swapw(priv->rx_ring[i]->RMD0), + swapw(-priv->rx_ring[i]->RMD2), swapw(priv->rx_ring[i]->RMD3)); + for (i = 0 ; i < TX_RING_SIZE; i++) + printk("%s %08x %04x %04x", i & 0x3 ? "" : "\n ", + (swapw((priv->tx_ring[i]->TMD1))<<16)|swapw(priv->tx_ring[i]->TMD0), + swapw(-priv->tx_ring[i]->TMD2), priv->tx_ring[i]->TMD3); + printk("\n"); + } +#endif + ariadne_init_ring(dev); + board->Lance.RDP = INEA|STRT; + + dev->tbusy = 0; + dev->trans_start = jiffies; + + return(0); + } + + if (skb == NULL) { + dev_tint(dev); + return(0); + } + + if (skb->len <= 0) + return(0); + +#if 0 + if (ariadne_debug > 3) { + board->Lance.RAP = CSR0; /* PCnet-ISA Controller Status */ + printk("%s: ariadne_start_xmit() called, csr0 %4.4x.\n", dev->name, + board->Lance.RDP); + board->Lance.RDP = 0x0000; + } +#endif + + /* Block a timer-based transmit from overlapping. This could better be + done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ + if (set_bit(0, (void*)&dev->tbusy) != 0) { + printk("%s: Transmitter access conflict.\n", dev->name); + return(1); + } + + if (set_bit(0, (void*)&priv->lock) != 0) { + if (ariadne_debug > 0) + printk("%s: tx queue lock!.\n", dev->name); + /* don't clear dev->tbusy flag. */ + return(1); + } + + /* Fill in a Tx ring entry */ + +#if 0 + printk("TX pkt type 0x%04x from ", ((u_short *)skb->data)[6]); + { + int i; + u_char *ptr = &((u_char *)skb->data)[6]; + for (i = 0; i < 6; i++) + printk("%02x", ptr[i]); + } + printk(" to "); + { + int i; + u_char *ptr = (u_char *)skb->data; + for (i = 0; i < 6; i++) + printk("%02x", ptr[i]); + } + printk(" data 0x%08x len %d\n", (int)skb->data, (int)skb->len); +#endif + + entry = priv->cur_tx % TX_RING_SIZE; + + /* Caution: the write order is important here, set the base address with + the "ownership" bits last. */ + + priv->tx_ring[entry]->TMD2 = swapw((u_short)-skb->len); + priv->tx_ring[entry]->TMD3 = 0x0000; + memcpyw(priv->tx_buff[entry], (u_short *)skb->data, skb->len); + +#if 0 + { + int i, len; + + len = skb->len > 64 ? 64 : skb->len; + len >>= 1; + for (i = 0; i < len; i += 8) { + int j; + printk("%04x:", i); + for (j = 0; (j < 8) && ((i+j) < len); j++) { + if (!(j & 1)) + printk(" "); + printk("%04x", priv->tx_buff[entry][i+j]); + } + printk("\n"); + } + } +#endif + + priv->tx_ring[entry]->TMD1 = (priv->tx_ring[entry]->TMD1&0xff00)|TF_OWN|TF_STP|TF_ENP; + + dev_kfree_skb(skb, FREE_WRITE); + + priv->cur_tx++; + if ((priv->cur_tx >= TX_RING_SIZE) && (priv->dirty_tx >= TX_RING_SIZE)) { + +#if 0 + printk("*** Subtracting TX_RING_SIZE from cur_tx (%d) and dirty_tx (%d)\n", + priv->cur_tx, priv->dirty_tx); +#endif + + priv->cur_tx -= TX_RING_SIZE; + priv->dirty_tx -= TX_RING_SIZE; + } + + /* Trigger an immediate send poll. */ + board->Lance.RAP = CSR0; /* PCnet-ISA Controller Status */ + board->Lance.RDP = INEA|TDMD; + + dev->trans_start = jiffies; + + cli(); + priv->lock = 0; + if (lowb(priv->tx_ring[(entry+1) % TX_RING_SIZE]->TMD1) == 0) + dev->tbusy = 0; + else + priv->tx_full = 1; + sti(); + + return(0); +} + + +static int ariadne_rx(struct device *dev) +{ + struct ariadne_private *priv = (struct ariadne_private *)dev->priv; + int entry = priv->cur_rx % RX_RING_SIZE; + int i; + + /* If we own the next entry, it's a new packet. Send it up. */ + while (!(lowb(priv->rx_ring[entry]->RMD1) & RF_OWN)) { + int status = lowb(priv->rx_ring[entry]->RMD1); + + if (status != (RF_STP|RF_ENP)) { /* There was an error. */ + /* There is a tricky error noted by John Murphy, + to Russ Nelson: Even with full-sized + buffers it's possible for a jabber packet to use two + buffers, with only the last correctly noting the error. */ + if (status & RF_ENP) + /* Only count a general error at the end of a packet.*/ + priv->stats.rx_errors++; + if (status & RF_FRAM) + priv->stats.rx_frame_errors++; + if (status & RF_OFLO) + priv->stats.rx_over_errors++; + if (status & RF_CRC) + priv->stats.rx_crc_errors++; + if (status & RF_BUFF) + priv->stats.rx_fifo_errors++; + priv->rx_ring[entry]->RMD1 &= 0xff00|RF_STP|RF_ENP; + } else { + /* Malloc up new buffer, compatible with net-3. */ + short pkt_len = swapw(priv->rx_ring[entry]->RMD3); + struct sk_buff *skb; + + skb = dev_alloc_skb(pkt_len+2); + if (skb == NULL) { + printk("%s: Memory squeeze, deferring packet.\n", dev->name); + for (i = 0; i < RX_RING_SIZE; i++) + if (lowb(priv->rx_ring[(entry+i) % RX_RING_SIZE]->RMD1) & RF_OWN) + break; + + if (i > RX_RING_SIZE-2) { + priv->stats.rx_dropped++; + priv->rx_ring[entry]->RMD1 |= RF_OWN; + priv->cur_rx++; + } + break; + } + + + skb->dev = dev; + skb_reserve(skb,2); /* 16 byte align */ + skb_put(skb,pkt_len); /* Make room */ + eth_copy_and_sum(skb, (char *)priv->rx_buff[entry], pkt_len,0); + skb->protocol=eth_type_trans(skb,dev); +#if 0 + printk("RX pkt type 0x%04x from ", ((u_short *)skb->data)[6]); + { + int i; + u_char *ptr = &((u_char *)skb->data)[6]; + for (i = 0; i < 6; i++) + printk("%02x", ptr[i]); + } + printk(" to "); + { + int i; + u_char *ptr = (u_char *)skb->data; + for (i = 0; i < 6; i++) + printk("%02x", ptr[i]); + } + printk(" data 0x%08x len %d\n", (int)skb->data, (int)skb->len); +#endif + + netif_rx(skb); + priv->stats.rx_packets++; + } + + priv->rx_ring[entry]->RMD1 |= RF_OWN; + entry = (++priv->cur_rx) % RX_RING_SIZE; + } + + priv->cur_rx = priv->cur_rx % RX_RING_SIZE; + + /* We should check that at least two ring entries are free. If not, + we should free one and mark stats->rx_dropped++. */ + + return(0); +} + + +static struct enet_statistics *ariadne_get_stats(struct device *dev) +{ + struct ariadne_private *priv = (struct ariadne_private *)dev->priv; + struct AriadneBoard *board = priv->board; + short saved_addr; + + cli(); + saved_addr = board->Lance.RAP; + board->Lance.RAP = CSR112; /* Missed Frame Count */ + priv->stats.rx_missed_errors = swapw(board->Lance.RDP); + board->Lance.RAP = saved_addr; + sti(); + + return(&priv->stats); +} + + +/* Set or clear the multicast filter for this adaptor. + num_addrs == -1 Promiscuous mode, receive all packets + num_addrs == 0 Normal mode, clear multicast list + num_addrs > 0 Multicast mode, receive normal and MC packets, and do + best-effort filtering. + */ +static void set_multicast_list(struct device *dev) +{ + struct ariadne_private *priv = (struct ariadne_private *)dev->priv; + struct AriadneBoard *board = priv->board; + + /* We take the simple way out and always enable promiscuous mode. */ + board->Lance.RAP = CSR0; /* PCnet-ISA Controller Status */ + board->Lance.RDP = STOP; /* Temporarily stop the lance. */ + + if (dev->flags & IFF_PROMISC) { + /* Log any net taps. */ + printk("%s: Promiscuous mode enabled.\n", dev->name); + board->Lance.RAP = CSR15; /* Mode Register */ + board->Lance.RDP = PROM; /* Set promiscuous mode */ + } else { + short multicast_table[4]; + int num_addrs = dev->mc_count; + int i; + /* We don't use the multicast table, but rely on upper-layer filtering. */ + memset(multicast_table, (num_addrs == 0) ? 0 : -1, + sizeof(multicast_table)); + for (i = 0; i < 4; i++) { + board->Lance.RAP = CSR8+(i<<8); /* Logical Address Filter */ + board->Lance.RDP = swapw(multicast_table[i]); + } + board->Lance.RAP = CSR15; /* Mode Register */ + board->Lance.RDP = 0x0000; /* Unset promiscuous mode */ + } + + board->Lance.RAP = CSR0; /* PCnet-ISA Controller Status */ + board->Lance.RDP = INEA|STRT|IDON; /* Resume normal operation. */ +} diff -u --recursive --new-file v1.3.93/linux/drivers/net/ariadne.h linux/drivers/net/ariadne.h --- v1.3.93/linux/drivers/net/ariadne.h Thu Jan 1 02:00:00 1970 +++ linux/drivers/net/ariadne.h Tue Apr 9 00:13:56 1996 @@ -0,0 +1,415 @@ +/* + * Amiga Linux/m68k Ariadne Ethernet Driver + * + * © Copyright 1995 by Geert Uytterhoeven + * (Geert.Uytterhoeven@cs.kuleuven.ac.be) + * Peter De Schrijver + * (Peter.DeSchrijver@linux.cc.kuleuven.ac.be) + * + * ---------------------------------------------------------------------------------- + * + * This program is based on + * + * lance.c: An AMD LANCE ethernet driver for linux. + * Written 1993-94 by Donald Becker. + * + * Am79C960: PCnet(tm)-ISA Single-Chip Ethernet Controller + * Advanced Micro Devices + * Publication #16907, Rev. B, Amendment/0, May 1994 + * + * MC68230: Parallel Interface/Timer (PI/T) + * Motorola Semiconductors, December, 1983 + * + * ---------------------------------------------------------------------------------- + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file README.legal in the main directory of the Linux/m68k + * distribution for more details. + * + * ---------------------------------------------------------------------------------- + * + * The Ariadne is a Zorro-II board made by Village Tronic. It contains: + * + * - an Am79C960 PCnet-ISA Single-Chip Ethernet Controller with both + * 10BASE-2 (thin coax) and 10BASE-T (UTP) connectors + * + * - an MC68230 Parallel Interface/Timer configured as 2 parallel ports + */ + + + /* + * Am79C960 PCnet-ISA + */ + +struct Am79C960 { + volatile u_short AddressPROM[8]; + /* IEEE Address PROM (Unused in the Ariadne) */ + volatile u_short RDP; /* Register Data Port */ + volatile u_short RAP; /* Register Address Port */ + volatile u_short Reset; /* Reset Chip on Read Access */ + volatile u_short IDP; /* ISACSR Data Port */ +}; + + + /* + * Am79C960 Control and Status Registers + * + * These values are already swap()ed!! + * + * Only registers marked with a `-' are intended for network software + * access + */ + +#define CSR0 0x0000 /* - PCnet-ISA Controller Status */ +#define CSR1 0x0100 /* - IADR[15:0] */ +#define CSR2 0x0200 /* - IADR[23:16] */ +#define CSR3 0x0300 /* - Interrupt Masks and Deferral Control */ +#define CSR4 0x0400 /* - Test and Features Control */ +#define CSR6 0x0600 /* RCV/XMT Descriptor Table Length */ +#define CSR8 0x0800 /* - Logical Address Filter, LADRF[15:0] */ +#define CSR9 0x0900 /* - Logical Address Filter, LADRF[31:16] */ +#define CSR10 0x0a00 /* - Logical Address Filter, LADRF[47:32] */ +#define CSR11 0x0b00 /* - Logical Address Filter, LADRF[63:48] */ +#define CSR12 0x0c00 /* - Physical Address Register, PADR[15:0] */ +#define CSR13 0x0d00 /* - Physical Address Register, PADR[31:16] */ +#define CSR14 0x0e00 /* - Physical Address Register, PADR[47:32] */ +#define CSR15 0x0f00 /* - Mode Register */ +#define CSR16 0x1000 /* Initialization Block Address Lower */ +#define CSR17 0x1100 /* Initialization Block Address Upper */ +#define CSR18 0x1200 /* Current Receive Buffer Address */ +#define CSR19 0x1300 /* Current Receive Buffer Address */ +#define CSR20 0x1400 /* Current Transmit Buffer Address */ +#define CSR21 0x1500 /* Current Transmit Buffer Address */ +#define CSR22 0x1600 /* Next Receive Buffer Address */ +#define CSR23 0x1700 /* Next Receive Buffer Address */ +#define CSR24 0x1800 /* - Base Address of Receive Ring */ +#define CSR25 0x1900 /* - Base Address of Receive Ring */ +#define CSR26 0x1a00 /* Next Receive Descriptor Address */ +#define CSR27 0x1b00 /* Next Receive Descriptor Address */ +#define CSR28 0x1c00 /* Current Receive Descriptor Address */ +#define CSR29 0x1d00 /* Current Receive Descriptor Address */ +#define CSR30 0x1e00 /* - Base Address of Transmit Ring */ +#define CSR31 0x1f00 /* - Base Address of transmit Ring */ +#define CSR32 0x2000 /* Next Transmit Descriptor Address */ +#define CSR33 0x2100 /* Next Transmit Descriptor Address */ +#define CSR34 0x2200 /* Current Transmit Descriptor Address */ +#define CSR35 0x2300 /* Current Transmit Descriptor Address */ +#define CSR36 0x2400 /* Next Next Receive Descriptor Address */ +#define CSR37 0x2500 /* Next Next Receive Descriptor Address */ +#define CSR38 0x2600 /* Next Next Transmit Descriptor Address */ +#define CSR39 0x2700 /* Next Next Transmit Descriptor Address */ +#define CSR40 0x2800 /* Current Receive Status and Byte Count */ +#define CSR41 0x2900 /* Current Receive Status and Byte Count */ +#define CSR42 0x2a00 /* Current Transmit Status and Byte Count */ +#define CSR43 0x2b00 /* Current Transmit Status and Byte Count */ +#define CSR44 0x2c00 /* Next Receive Status and Byte Count */ +#define CSR45 0x2d00 /* Next Receive Status and Byte Count */ +#define CSR46 0x2e00 /* Poll Time Counter */ +#define CSR47 0x2f00 /* Polling Interval */ +#define CSR48 0x3000 /* Temporary Storage */ +#define CSR49 0x3100 /* Temporary Storage */ +#define CSR50 0x3200 /* Temporary Storage */ +#define CSR51 0x3300 /* Temporary Storage */ +#define CSR52 0x3400 /* Temporary Storage */ +#define CSR53 0x3500 /* Temporary Storage */ +#define CSR54 0x3600 /* Temporary Storage */ +#define CSR55 0x3700 /* Temporary Storage */ +#define CSR56 0x3800 /* Temporary Storage */ +#define CSR57 0x3900 /* Temporary Storage */ +#define CSR58 0x3a00 /* Temporary Storage */ +#define CSR59 0x3b00 /* Temporary Storage */ +#define CSR60 0x3c00 /* Previous Transmit Descriptor Address */ +#define CSR61 0x3d00 /* Previous Transmit Descriptor Address */ +#define CSR62 0x3e00 /* Previous Transmit Status and Byte Count */ +#define CSR63 0x3f00 /* Previous Transmit Status and Byte Count */ +#define CSR64 0x4000 /* Next Transmit Buffer Addres */ +#define CSR65 0x4100 /* Next Transmit Buffer Addres */ +#define CSR66 0x4200 /* Next Transmit Status and Byte Count */ +#define CSR67 0x4300 /* Next Transmit Status and Byte Count */ +#define CSR68 0x4400 /* Transmit Status Temporary Storage */ +#define CSR69 0x4500 /* Transmit Status Temporary Storage */ +#define CSR70 0x4600 /* Temporary Storage */ +#define CSR71 0x4700 /* Temporary Storage */ +#define CSR72 0x4800 /* Receive Ring Counter */ +#define CSR74 0x4a00 /* Transmit Ring Counter */ +#define CSR76 0x4c00 /* - Receive Ring Length */ +#define CSR78 0x4e00 /* - Transmit Ring Length */ +#define CSR80 0x5000 /* - Burst and FIFO Threshold Control */ +#define CSR82 0x5200 /* - Bus Activity Timer */ +#define CSR84 0x5400 /* DMA Address */ +#define CSR85 0x5500 /* DMA Address */ +#define CSR86 0x5600 /* Buffer Byte Counter */ +#define CSR88 0x5800 /* - Chip ID */ +#define CSR89 0x5900 /* - Chip ID */ +#define CSR92 0x5c00 /* Ring Length Conversion */ +#define CSR94 0x5e00 /* Transmit Time Domain Reflectometry Count */ +#define CSR96 0x6000 /* Bus Interface Scratch Register 0 */ +#define CSR97 0x6100 /* Bus Interface Scratch Register 0 */ +#define CSR98 0x6200 /* Bus Interface Scratch Register 1 */ +#define CSR99 0x6300 /* Bus Interface Scratch Register 1 */ +#define CSR104 0x6800 /* SWAP */ +#define CSR105 0x6900 /* SWAP */ +#define CSR108 0x6c00 /* Buffer Management Scratch */ +#define CSR109 0x6d00 /* Buffer Management Scratch */ +#define CSR112 0x7000 /* - Missed Frame Count */ +#define CSR114 0x7200 /* - Receive Collision Count */ +#define CSR124 0x7c00 /* - Buffer Management Unit Test */ + + + /* + * Am79C960 ISA Control and Status Registers + * + * These values are already swap()ed!! + */ + +#define ISACSR0 0x0000 /* Master Mode Read Active */ +#define ISACSR1 0x0100 /* Master Mode Write Active */ +#define ISACSR2 0x0200 /* Miscellaneous Configuration */ +#define ISACSR4 0x0400 /* LED0 Status (Link Integrity) */ +#define ISACSR5 0x0500 /* LED1 Status */ +#define ISACSR6 0x0600 /* LED2 Status */ +#define ISACSR7 0x0700 /* LED3 Status */ + + + /* + * Bit definitions for CSR0 (PCnet-ISA Controller Status) + * + * These values are already swap()ed!! + */ + +#define ERR 0x0080 /* Error */ +#define BABL 0x0040 /* Babble: Transmitted too many bits */ +#define CERR 0x0020 /* No Heartbeat (10BASE-T) */ +#define MISS 0x0010 /* Missed Frame */ +#define MERR 0x0008 /* Memory Error */ +#define RINT 0x0004 /* Receive Interrupt */ +#define TINT 0x0002 /* Transmit Interrupt */ +#define IDON 0x0001 /* Initialization Done */ +#define INTR 0x8000 /* Interrupt Flag */ +#define INEA 0x4000 /* Interrupt Enable */ +#define RXON 0x2000 /* Receive On */ +#define TXON 0x1000 /* Transmit On */ +#define TDMD 0x0800 /* Transmit Demand */ +#define STOP 0x0400 /* Stop */ +#define STRT 0x0200 /* Start */ +#define INIT 0x0100 /* Initialize */ + + + /* + * Bit definitions for CSR3 (Interrupt Masks and Deferral Control) + * + * These values are already swap()ed!! + */ + +#define BABLM 0x0040 /* Babble Mask */ +#define MISSM 0x0010 /* Missed Frame Mask */ +#define MERRM 0x0008 /* Memory Error Mask */ +#define RINTM 0x0004 /* Receive Interrupt Mask */ +#define TINTM 0x0002 /* Transmit Interrupt Mask */ +#define IDONM 0x0001 /* Initialization Done Mask */ +#define DXMT2PD 0x1000 /* Disable Transmit Two Part Deferral */ +#define EMBA 0x0800 /* Enable Modified Back-off Algorithm */ + + + /* + * Bit definitions for CSR4 (Test and Features Control) + * + * These values are already swap()ed!! + */ + +#define ENTST 0x0080 /* Enable Test Mode */ +#define DMAPLUS 0x0040 /* Disable Burst Transaction Counter */ +#define TIMER 0x0020 /* Timer Enable Register */ +#define DPOLL 0x0010 /* Disable Transmit Polling */ +#define APAD_XMT 0x0008 /* Auto Pad Transmit */ +#define ASTRP_RCV 0x0004 /* Auto Pad Stripping */ +#define MFCO 0x0002 /* Missed Frame Counter Overflow Interrupt */ +#define MFCOM 0x0001 /* Missed Frame Counter Overflow Mask */ +#define RCVCCO 0x2000 /* Receive Collision Counter Overflow Interrupt */ +#define RCVCCOM 0x1000 /* Receive Collision Counter Overflow Mask */ +#define TXSTRT 0x0800 /* Transmit Start Status */ +#define TXSTRTM 0x0400 /* Transmit Start Mask */ +#define JAB 0x0200 /* Jabber Error */ +#define JABM 0x0100 /* Jabber Error Mask */ + + + /* + * Bit definitions for CSR15 (Mode Register) + * + * These values are already swap()ed!! + */ + +#define PROM 0x0080 /* Promiscuous Mode */ +#define DRCVBC 0x0040 /* Disable Receive Broadcast */ +#define DRCVPA 0x0020 /* Disable Receive Physical Address */ +#define DLNKTST 0x0010 /* Disable Link Status */ +#define DAPC 0x0008 /* Disable Automatic Polarity Correction */ +#define MENDECL 0x0004 /* MENDEC Loopback Mode */ +#define LRTTSEL 0x0002 /* Low Receive Treshold/Transmit Mode Select */ +#define PORTSEL1 0x0001 /* Port Select Bits */ +#define PORTSEL2 0x8000 /* Port Select Bits */ +#define INTL 0x4000 /* Internal Loopback */ +#define DRTY 0x2000 /* Disable Retry */ +#define FCOLL 0x1000 /* Force Collision */ +#define DXMTFCS 0x0800 /* Disable Transmit CRC */ +#define LOOP 0x0400 /* Loopback Enable */ +#define DTX 0x0200 /* Disable Transmitter */ +#define DRX 0x0100 /* Disable Receiver */ + + + /* + * Bit definitions for ISACSR2 (Miscellaneous Configuration) + * + * These values are already swap()ed!! + */ + +#define ASEL 0x0200 /* Media Interface Port Auto Select */ + + + /* + * Bit definitions for ISACSR5-7 (LED1-3 Status) + * + * These values are already swap()ed!! + */ + +#define LEDOUT 0x0080 /* Current LED Status */ +#define PSE 0x8000 /* Pulse Stretcher Enable */ +#define XMTE 0x1000 /* Enable Transmit Status Signal */ +#define RVPOLE 0x0800 /* Enable Receive Polarity Signal */ +#define RCVE 0x0400 /* Enable Receive Status Signal */ +#define JABE 0x0200 /* Enable Jabber Signal */ +#define COLE 0x0100 /* Enable Collision Signal */ + + + /* + * Receive Descriptor Ring Entry + */ + +struct RDRE { + volatile u_short RMD0; /* LADR[15:0] */ + volatile u_short RMD1; /* HADR[23:16] | Receive Flags */ + volatile u_short RMD2; /* Buffer Byte Count (two's complement) */ + volatile u_short RMD3; /* Message Byte Count */ +}; + + + /* + * Transmit Descriptor Ring Entry + */ + +struct TDRE { + volatile u_short TMD0; /* LADR[15:0] */ + volatile u_short TMD1; /* HADR[23:16] | Transmit Flags */ + volatile u_short TMD2; /* Buffer Byte Count (two's complement) */ + volatile u_short TMD3; /* Error Flags */ +}; + + + /* + * Receive Flags + */ + +#define RF_OWN 0x0080 /* PCnet-ISA controller owns the descriptor */ +#define RF_ERR 0x0040 /* Error */ +#define RF_FRAM 0x0020 /* Framing Error */ +#define RF_OFLO 0x0010 /* Overflow Error */ +#define RF_CRC 0x0008 /* CRC Error */ +#define RF_BUFF 0x0004 /* Buffer Error */ +#define RF_STP 0x0002 /* Start of Packet */ +#define RF_ENP 0x0001 /* End of Packet */ + + + /* + * Transmit Flags + */ + +#define TF_OWN 0x0080 /* PCnet-ISA controller owns the descriptor */ +#define TF_ERR 0x0040 /* Error */ +#define TF_ADD_FCS 0x0020 /* Controls FCS Generation */ +#define TF_MORE 0x0010 /* More than one retry needed */ +#define TF_ONE 0x0008 /* One retry needed */ +#define TF_DEF 0x0004 /* Deferred */ +#define TF_STP 0x0002 /* Start of Packet */ +#define TF_ENP 0x0001 /* End of Packet */ + + + /* + * Error Flags + */ + +#define EF_BUFF 0x0080 /* Buffer Error */ +#define EF_UFLO 0x0040 /* Underflow Error */ +#define EF_LCOL 0x0010 /* Late Collision */ +#define EF_LCAR 0x0008 /* Loss of Carrier */ +#define EF_RTRY 0x0004 /* Retry Error */ +#define EF_TDR 0xff03 /* Time Domain Reflectometry */ + + + + /* + * MC68230 Parallel Interface/Timer + */ + +struct MC68230 { + volatile u_char PGCR; /* Port General Control Register */ + u_char Pad1[1]; + volatile u_char PSRR; /* Port Service Request Register */ + u_char Pad2[1]; + volatile u_char PADDR; /* Port A Data Direction Register */ + u_char Pad3[1]; + volatile u_char PBDDR; /* Port B Data Direction Register */ + u_char Pad4[1]; + volatile u_char PCDDR; /* Port C Data Direction Register */ + u_char Pad5[1]; + volatile u_char PIVR; /* Port Interrupt Vector Register */ + u_char Pad6[1]; + volatile u_char PACR; /* Port A Control Register */ + u_char Pad7[1]; + volatile u_char PBCR; /* Port B Control Register */ + u_char Pad8[1]; + volatile u_char PADR; /* Port A Data Register */ + u_char Pad9[1]; + volatile u_char PBDR; /* Port B Data Register */ + u_char Pad10[1]; + volatile u_char PAAR; /* Port A Alternate Register */ + u_char Pad11[1]; + volatile u_char PBAR; /* Port B Alternate Register */ + u_char Pad12[1]; + volatile u_char PCDR; /* Port C Data Register */ + u_char Pad13[1]; + volatile u_char PSR; /* Port Status Register */ + u_char Pad14[5]; + volatile u_char TCR; /* Timer Control Register */ + u_char Pad15[1]; + volatile u_char TIVR; /* Timer Interrupt Vector Register */ + u_char Pad16[3]; + volatile u_char CPRH; /* Counter Preload Register (High) */ + u_char Pad17[1]; + volatile u_char CPRM; /* Counter Preload Register (Mid) */ + u_char Pad18[1]; + volatile u_char CPRL; /* Counter Preload Register (Low) */ + u_char Pad19[3]; + volatile u_char CNTRH; /* Count Register (High) */ + u_char Pad20[1]; + volatile u_char CNTRM; /* Count Register (Mid) */ + u_char Pad21[1]; + volatile u_char CNTRL; /* Count Register (Low) */ + u_char Pad22[1]; + volatile u_char TSR; /* Timer Status Register */ + u_char Pad23[11]; +}; + + + /* + * Ariadne Expansion Board Structure + */ + +struct AriadneBoard { + u_char Pad1[0x360]; + struct Am79C960 Lance; + u_char Pad2[0xc88]; + struct MC68230 PiT; + u_char Pad3[0x2fc0]; + volatile u_short BootPROM[0x2000]; /* I guess it's here :-) */ + volatile u_short RAM[0x4000]; /* Always access WORDs!! */ +}; diff -u --recursive --new-file v1.3.93/linux/drivers/net/atarilance.c linux/drivers/net/atarilance.c --- v1.3.93/linux/drivers/net/atarilance.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/net/atarilance.c Sat Apr 13 14:31:02 1996 @@ -0,0 +1,1194 @@ +/* atarilance.c: Ethernet driver for VME Lance cards on the Atari */ +/* + Written 1995/96 by Roman Hodek (Roman.Hodek@informatik.uni-erlangen.de) + + This software may be used and distributed according to the terms + of the GNU Public License, incorporated herein by reference. + + This drivers was written with the following sources of reference: + - The driver for the Riebl Lance card by the TU Vienna. + - The modified TUW driver for PAM's VME cards + - The PC-Linux driver for Lance cards (but this is for bus master + cards, not the shared memory ones) + - The Amiga Ariadne driver + + v1.0: (in 1.2.13pl4/0.9.13) + Initial version + v1.1: (in 1.2.13pl5) + more comments + deleted some debugging stuff + optimized register access (keep AREG pointing to CSR0) + following AMD, CSR0_STRT should be set only after IDON is detected + use memcpy() for data transfers, that also employs long word moves + better probe procedure for 24-bit systems + non-VME-RieblCards need extra delays in memcpy + must also do write test, since 0xfxe00000 may hit ROM + use 8/32 tx/rx buffers, which should give better NFS performance; + this is made possible by shifting the last packet buffer after the + RieblCard reserved area + v1.2: (in 1.2.13pl8) + again fixed probing for the Falcon; 0xfe01000 hits phys. 0x00010000 + and thus RAM, in case of no Lance found all memory contents have to + be restored! + Now possible to compile as module. + v1.3: 03/30/96 Jes Sorensen, Roman (in 1.3) + Several little 1.3 adaptions + When the lance is stopped it jumps back into little-endian + mode. It is therefore necessary to put it back where it + belongs, in big endian mode, in order to make things work. + This might be the reason why multicast-mode didn't work + before, but I'm not able to test it as I only got an Amiga + (we had similar problems with the A2065 driver). + +*/ + +static char *version = "atarilance.c: v1.3 04/04/96 " + "Roman.Hodek@informatik.uni-erlangen.de\n"; + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* Debug level: + * 0 = silent, print only serious errors + * 1 = normal, print error messages + * 2 = debug, print debug infos + * 3 = debug, print even more debug infos (packet data) + */ + +#define LANCE_DEBUG 1 + +#ifdef LANCE_DEBUG +static int lance_debug = LANCE_DEBUG; +#else +static int lance_debug = 1; +#endif + +/* Print debug messages on probing? */ +#undef LANCE_DEBUG_PROBE + +#define DPRINTK(n,a) \ + do { \ + if (lance_debug >= n) \ + printk a; \ + } while( 0 ) + +#ifdef LANCE_DEBUG_PROBE +# define PROBE_PRINT(a) printk a +#else +# define PROBE_PRINT(a) +#endif + +/* These define the number of Rx and Tx buffers as log2. (Only powers + * of two are valid) + * Much more rx buffers (32) are reserved than tx buffers (8), since receiving + * is more time critical then sending and packets may have to remain in the + * board's memory when main memory is low. + */ + +#define TX_LOG_RING_SIZE 3 +#define RX_LOG_RING_SIZE 5 + +/* These are the derived values */ + +#define TX_RING_SIZE (1 << TX_LOG_RING_SIZE) +#define TX_RING_LEN_BITS (TX_LOG_RING_SIZE << 5) +#define TX_RING_MOD_MASK (TX_RING_SIZE - 1) + +#define RX_RING_SIZE (1 << RX_LOG_RING_SIZE) +#define RX_RING_LEN_BITS (RX_LOG_RING_SIZE << 5) +#define RX_RING_MOD_MASK (RX_RING_SIZE - 1) + +/* The LANCE Rx and Tx ring descriptors. */ +struct lance_rx_head { + unsigned short base; /* Low word of base addr */ + volatile unsigned char flag; + unsigned char base_hi; /* High word of base addr (unused) */ + short buf_length; /* This length is 2s complement! */ + volatile short msg_length; /* This length is "normal". */ +}; + +struct lance_tx_head { + unsigned short base; /* Low word of base addr */ + volatile unsigned char flag; + unsigned char base_hi; /* High word of base addr (unused) */ + short length; /* Length is 2s complement! */ + volatile short misc; +}; + +struct ringdesc { + unsigned short adr_lo; /* Low 16 bits of address */ + unsigned char len; /* Length bits */ + unsigned char adr_hi; /* High 8 bits of address (unused) */ +}; + +/* The LANCE initialization block, described in databook. */ +struct lance_init_block { + unsigned short mode; /* Pre-set mode */ + unsigned char hwaddr[6]; /* Physical ethernet address */ + unsigned filter[2]; /* Multicast filter (unused). */ + /* Receive and transmit ring base, along with length bits. */ + struct ringdesc rx_ring; + struct ringdesc tx_ring; +}; + +/* The whole layout of the Lance shared memory */ +struct lance_memory { + struct lance_init_block init; + struct lance_tx_head tx_head[TX_RING_SIZE]; + struct lance_rx_head rx_head[RX_RING_SIZE]; + char packet_area[0]; /* packet data follow after the + * init block and the ring + * descriptors and are located + * at runtime */ +}; + +/* RieblCard specifics: + * The original TOS driver for these cards reserves the area from offset + * 0xee70 to 0xeebb for storing configuration data. Of interest to us is the + * Ethernet address there, and the magic for verifying the data's validity. + * The reserved area isn't touch by packet buffers. Furthermore, offset 0xfffe + * is reserved for the interrupt vector number. + */ +#define RIEBL_RSVD_START 0xee70 +#define RIEBL_RSVD_END 0xeec0 +#define RIEBL_MAGIC 0x09051990 +#define RIEBL_MAGIC_ADDR ((unsigned long *)(((char *)MEM) + 0xee8a)) +#define RIEBL_HWADDR_ADDR ((unsigned char *)(((char *)MEM) + 0xee8e)) +#define RIEBL_IVEC_ADDR ((unsigned short *)(((char *)MEM) + 0xfffe)) + +/* This is a default address for the old RieblCards without a battery + * that have no ethernet address at boot time. 00:00:36:04 is the + * prefix for Riebl cards, the 00:00 at the end is arbitrary. + */ + +static unsigned char OldRieblDefHwaddr[6] = { + 0x00, 0x00, 0x36, 0x04, 0x00, 0x00 +}; + + +/* I/O registers of the Lance chip */ + +struct lance_ioreg { +/* base+0x0 */ volatile unsigned short data; +/* base+0x2 */ volatile unsigned short addr; + unsigned char _dummy1[3]; +/* base+0x7 */ volatile unsigned char ivec; + unsigned char _dummy2[5]; +/* base+0xd */ volatile unsigned char eeprom; + unsigned char _dummy3; +/* base+0xf */ volatile unsigned char mem; +}; + +/* Types of boards this driver supports */ + +enum lance_type { + OLD_RIEBL, /* old Riebl card without battery */ + NEW_RIEBL, /* new Riebl card with battery */ + PAM_CARD /* PAM card with EEPROM */ +}; + +static char *lance_names[] = { + "Riebl-Card (without battery)", + "Riebl-Card (with battery)", + "PAM intern card" +}; + +/* The driver's private device structure */ + +struct lance_private { + enum lance_type cardtype; + struct lance_ioreg *iobase; + struct lance_memory *mem; + int cur_rx, cur_tx; /* The next free ring entry */ + int dirty_tx; /* Ring entries to be freeed. */ + /* copy function */ + void *(*memcpy_f)( void *, const void *, size_t ); + struct enet_statistics stats; +/* These two must be ints for set_bit() */ + int tx_full; + int lock; +}; + +/* I/O register access macros */ + +#define MEM lp->mem +#define DREG IO->data +#define AREG IO->addr +#define REGA(a) ( AREG = (a), DREG ) + +/* Definitions for packet buffer access: */ +#define PKT_BUF_SZ 1544 +/* Get the address of a packet buffer corresponding to a given buffer head */ +#define PKTBUF_ADDR(head) (((unsigned char *)(MEM)) + (head)->base) + +/* Possible memory/IO addresses for probing */ + +struct lance_addr { + unsigned long memaddr; + unsigned long ioaddr; + int slow_flag; +} lance_addr_list[] = { + { 0xfe010000, 0xfe00fff0, 0 }, /* RieblCard VME in TT */ + { 0xffc10000, 0xffc0fff0, 0 }, /* RieblCard VME in MegaSTE + (highest byte stripped) */ + { 0xffe00000, 0xffff7000, 1 }, /* RieblCard in ST + (highest byte stripped) */ + { 0xffd00000, 0xffff7000, 1 }, /* RieblCard in ST with hw modif. to + avoid conflict with ROM + (highest byte stripped) */ + { 0xffcf0000, 0xffcffff0, 0 }, /* PAMCard VME in TT and MSTE + (highest byte stripped) */ +}; + +#define N_LANCE_ADDR (sizeof(lance_addr_list)/sizeof(*lance_addr_list)) + + +/* Definitions for the Lance */ + +/* tx_head flags */ +#define TMD1_ENP 0x01 /* end of packet */ +#define TMD1_STP 0x02 /* start of packet */ +#define TMD1_DEF 0x04 /* deferred */ +#define TMD1_ONE 0x08 /* one retry needed */ +#define TMD1_MORE 0x10 /* more than one retry needed */ +#define TMD1_ERR 0x40 /* error summary */ +#define TMD1_OWN 0x80 /* ownership (set: chip owns) */ + +#define TMD1_OWN_CHIP TMD1_OWN +#define TMD1_OWN_HOST 0 + +/* tx_head misc field */ +#define TMD3_TDR 0x03FF /* Time Domain Reflectometry counter */ +#define TMD3_RTRY 0x0400 /* failed after 16 retries */ +#define TMD3_LCAR 0x0800 /* carrier lost */ +#define TMD3_LCOL 0x1000 /* late collision */ +#define TMD3_UFLO 0x4000 /* underflow (late memory) */ +#define TMD3_BUFF 0x8000 /* buffering error (no ENP) */ + +/* rx_head flags */ +#define RMD1_ENP 0x01 /* end of packet */ +#define RMD1_STP 0x02 /* start of packet */ +#define RMD1_BUFF 0x04 /* buffer error */ +#define RMD1_CRC 0x08 /* CRC error */ +#define RMD1_OFLO 0x10 /* overflow */ +#define RMD1_FRAM 0x20 /* framing error */ +#define RMD1_ERR 0x40 /* error summary */ +#define RMD1_OWN 0x80 /* ownership (set: ship owns) */ + +#define RMD1_OWN_CHIP RMD1_OWN +#define RMD1_OWN_HOST 0 + +/* register names */ +#define CSR0 0 /* mode/status */ +#define CSR1 1 /* init block addr (low) */ +#define CSR2 2 /* init block addr (high) */ +#define CSR3 3 /* misc */ +#define CSR8 8 /* address filter */ +#define CSR15 15 /* promiscous mode */ + +/* CSR0 */ +/* (R=readable, W=writeable, S=set on write, C=clear on write) */ +#define CSR0_INIT 0x0001 /* initialize (RS) */ +#define CSR0_STRT 0x0002 /* start (RS) */ +#define CSR0_STOP 0x0004 /* stop (RS) */ +#define CSR0_TDMD 0x0008 /* transmit demand (RS) */ +#define CSR0_TXON 0x0010 /* transmitter on (R) */ +#define CSR0_RXON 0x0020 /* receiver on (R) */ +#define CSR0_INEA 0x0040 /* interrupt enable (RW) */ +#define CSR0_INTR 0x0080 /* interrupt active (R) */ +#define CSR0_IDON 0x0100 /* initialization done (RC) */ +#define CSR0_TINT 0x0200 /* transmitter interrupt (RC) */ +#define CSR0_RINT 0x0400 /* receiver interrupt (RC) */ +#define CSR0_MERR 0x0800 /* memory error (RC) */ +#define CSR0_MISS 0x1000 /* missed frame (RC) */ +#define CSR0_CERR 0x2000 /* carrier error (no heartbeat :-) (RC) */ +#define CSR0_BABL 0x4000 /* babble: tx-ed too many bits (RC) */ +#define CSR0_ERR 0x8000 /* error (RC) */ + +/* CSR3 */ +#define CSR3_BCON 0x0001 /* byte control */ +#define CSR3_ACON 0x0002 /* ALE control */ +#define CSR3_BSWP 0x0004 /* byte swap (1=big endian) */ + + + +/***************************** Prototypes *****************************/ + +static int addr_accessible( volatile void *regp, int wordflag, int + writeflag ); +static unsigned long lance_probe1( struct device *dev, struct lance_addr + *init_rec ); +static int lance_open( struct device *dev ); +static void lance_init_ring( struct device *dev ); +static int lance_start_xmit( struct sk_buff *skb, struct device *dev ); +static void lance_interrupt( int irq, struct pt_regs *fp, struct device + *dev ); +static int lance_rx( struct device *dev ); +static int lance_close( struct device *dev ); +static struct enet_statistics *lance_get_stats( struct device *dev ); +static void set_multicast_list( struct device *dev ); +static int lance_set_mac_address( struct device *dev, void *addr ); + +/************************* End of Prototypes **************************/ + + + + + +void *slow_memcpy( void *dst, const void *src, size_t len ) + +{ char *cto = dst; + const char *cfrom = src; + + while( len-- ) { + *cto++ = *cfrom++; + MFPDELAY(); + } + return( dst ); +} + + +int atarilance_probe( struct device *dev ) + +{ int i; + static int found = 0; + + if (!MACH_IS_ATARI || found) + /* Assume there's only one board possible... That seems true, since + * the Riebl/PAM board's address cannot be changed. */ + return( ENODEV ); + + for( i = 0; i < N_LANCE_ADDR; ++i ) { + if (lance_probe1( dev, &lance_addr_list[i] )) { + found = 1; + return( 0 ); + } + } + + return( ENODEV ); +} + + +/* Derived from hwreg_present() in atari/config.c: */ + +static int addr_accessible( volatile void *regp, int wordflag, int writeflag ) + +{ int ret; + long flags; + long *vbr, save_berr; + + save_flags(flags); + cli(); + + __asm__ __volatile__ ( "movec %/vbr,%0" : "=r" (vbr) : ); + save_berr = vbr[2]; + + __asm__ __volatile__ + ( "movel %/sp,%/d1\n\t" + "movel #Lberr,%2@\n\t" + "moveq #0,%0\n\t" + "tstl %3\n\t" + "bne 1f\n\t" + "moveb %1@,%/d0\n\t" + "nop \n\t" + "bra 2f\n" +"1: movew %1@,%/d0\n\t" + "nop \n" +"2: tstl %4\n\t" + "beq 2f\n\t" + "tstl %3\n\t" + "bne 1f\n\t" + "clrb %1@\n\t" + "nop \n\t" + "moveb %/d0,%1@\n\t" + "nop \n\t" + "bra 2f\n" +"1: clrw %1@\n\t" + "nop \n\t" + "movew %/d0,%1@\n\t" + "nop \n" +"2: moveq #1,%0\n" +"Lberr: movel %/d1,%/sp" + : "=&d" (ret) + : "a" (regp), "a" (&vbr[2]), "rm" (wordflag), "rm" (writeflag) + : "d0", "d1", "memory" + ); + + vbr[2] = save_berr; + restore_flags(flags); + + return( ret ); +} + + +static unsigned long lance_probe1( struct device *dev, + struct lance_addr *init_rec ) + +{ volatile unsigned short *memaddr = + (volatile unsigned short *)init_rec->memaddr; + volatile unsigned short *ioaddr = + (volatile unsigned short *)init_rec->ioaddr; + struct lance_private *lp; + struct lance_ioreg *IO; + int i; + static int did_version = 0; + unsigned short save1, save2; + + PROBE_PRINT(( "Probing for Lance card at mem %#lx io %#lx\n", + (long)memaddr, (long)ioaddr )); + + /* Test whether memory readable and writable */ + PROBE_PRINT(( "lance_probe1: testing memory to be accessible\n" )); + if (!addr_accessible( memaddr, 1, 1 )) goto probe_fail; + + /* Written values should come back... */ + PROBE_PRINT(( "lance_probe1: testing memory to be writable (1)\n" )); + save1 = *memaddr; + *memaddr = 0x0001; + if (*memaddr != 0x0001) goto probe_fail; + PROBE_PRINT(( "lance_probe1: testing memory to be writable (2)\n" )); + *memaddr = 0x0000; + if (*memaddr != 0x0000) goto probe_fail; + *memaddr = save1; + + /* First port should be readable and writable */ + PROBE_PRINT(( "lance_probe1: testing ioport to be accessible\n" )); + if (!addr_accessible( ioaddr, 1, 1 )) goto probe_fail; + + /* and written values should be readable */ + PROBE_PRINT(( "lance_probe1: testing ioport to be writeable\n" )); + save2 = ioaddr[1]; + ioaddr[1] = 0x0001; + if (ioaddr[1] != 0x0001) goto probe_fail; + + /* The CSR0_INIT bit should not be readable */ + PROBE_PRINT(( "lance_probe1: testing CSR0 register function (1)\n" )); + save1 = ioaddr[0]; + ioaddr[1] = CSR0; + ioaddr[0] = CSR0_INIT | CSR0_STOP; + if (ioaddr[0] != CSR0_STOP) { + ioaddr[0] = save1; + ioaddr[1] = save2; + goto probe_fail; + } + PROBE_PRINT(( "lance_probe1: testing CSR0 register function (2)\n" )); + ioaddr[0] = CSR0_STOP; + if (ioaddr[0] != CSR0_STOP) { + ioaddr[0] = save1; + ioaddr[1] = save2; + goto probe_fail; + } + + /* Now ok... */ + PROBE_PRINT(( "lance_probe1: Lance card detected\n" )); + goto probe_ok; + + probe_fail: + return( 0 ); + + probe_ok: + init_etherdev( dev, sizeof(struct lance_private) ); + if (!dev->priv) + dev->priv = kmalloc( sizeof(struct lance_private), GFP_KERNEL ); + lp = (struct lance_private *)dev->priv; + MEM = (struct lance_memory *)memaddr; + IO = lp->iobase = (struct lance_ioreg *)ioaddr; + dev->base_addr = (unsigned long)ioaddr; /* informational only */ + lp->memcpy_f = init_rec->slow_flag ? slow_memcpy : memcpy; + + REGA( CSR0 ) = CSR0_STOP; + + /* Now test for type: If the eeprom I/O port is readable, it is a + * PAM card */ + if (addr_accessible( &(IO->eeprom), 0, 0 )) { + /* Switch back to Ram */ + i = IO->mem; + lp->cardtype = PAM_CARD; + } + else if (*RIEBL_MAGIC_ADDR == RIEBL_MAGIC) { + lp->cardtype = NEW_RIEBL; + } + else + lp->cardtype = OLD_RIEBL; + + if (lp->cardtype == PAM_CARD || + memaddr == (unsigned short *)0xffe00000) { + /* PAMs card and Riebl on ST use level 5 autovector */ + add_isr( IRQ_AUTO_5, (isrfunc)lance_interrupt, IRQ_TYPE_PRIO, dev, + "PAM/Riebl-ST Ethernet" ); + dev->irq = (unsigned short)IRQ_AUTO_5; + } + else { + /* For VME-RieblCards, request a free VME int; + * (This must be unsigned long, since dev->irq is short and the + * IRQ_MACHSPEC bit would be cut off...) + */ + unsigned long irq = atari_register_vme_int(); + if (!irq) { + printk( "Lance: request for VME interrupt failed\n" ); + return( 0 ); + } + add_isr( irq, (isrfunc)lance_interrupt, IRQ_TYPE_PRIO, dev, + "Riebl-VME Ethernet" ); + dev->irq = irq; + } + + printk("%s: %s at io %#lx, mem %#lx, irq %d%s, hwaddr ", + dev->name, lance_names[lp->cardtype], + (unsigned long)ioaddr, + (unsigned long)memaddr, + dev->irq, + init_rec->slow_flag ? " (slow memcpy)" : "" ); + + /* Get the ethernet address */ + switch( lp->cardtype ) { + case OLD_RIEBL: + /* No ethernet address! (Set some default address) */ + memcpy( dev->dev_addr, OldRieblDefHwaddr, 6 ); + break; + case NEW_RIEBL: + lp->memcpy_f( dev->dev_addr, RIEBL_HWADDR_ADDR, 6 ); + break; + case PAM_CARD: + i = IO->eeprom; + for( i = 0; i < 6; ++i ) + dev->dev_addr[i] = + ((((unsigned short *)MEM)[i*2] & 0x0f) << 4) | + ((((unsigned short *)MEM)[i*2+1] & 0x0f)); + i = IO->mem; + break; + } + for( i = 0; i < 6; ++i ) + printk( "%02x%s", dev->dev_addr[i], (i < 5) ? ":" : "\n" ); + if (lp->cardtype == OLD_RIEBL) { + printk( "%s: Warning: This is a default ethernet address!\n", + dev->name ); + printk( " Use \"ifconfig hw ether ...\" to set the address.\n" ); + } + + MEM->init.mode = 0x0000; /* Disable Rx and Tx. */ + for( i = 0; i < 6; i++ ) + MEM->init.hwaddr[i] = dev->dev_addr[i^1]; /* <- 16 bit swap! */ + MEM->init.filter[0] = 0x00000000; + MEM->init.filter[1] = 0x00000000; + MEM->init.rx_ring.adr_lo = offsetof( struct lance_memory, rx_head ); + MEM->init.rx_ring.adr_hi = 0; + MEM->init.rx_ring.len = RX_RING_LEN_BITS; + MEM->init.tx_ring.adr_lo = offsetof( struct lance_memory, tx_head ); + MEM->init.tx_ring.adr_hi = 0; + MEM->init.tx_ring.len = TX_RING_LEN_BITS; + + if (lp->cardtype == PAM_CARD) + IO->ivec = IRQ_SOURCE_TO_VECTOR(dev->irq); + else + *RIEBL_IVEC_ADDR = IRQ_SOURCE_TO_VECTOR(dev->irq); + + if (did_version++ == 0) + DPRINTK( 1, ( version )); + + /* The LANCE-specific entries in the device structure. */ + dev->open = &lance_open; + dev->hard_start_xmit = &lance_start_xmit; + dev->stop = &lance_close; + dev->get_stats = &lance_get_stats; + dev->set_multicast_list = &set_multicast_list; + dev->set_mac_address = &lance_set_mac_address; + dev->start = 0; + + memset( &lp->stats, 0, sizeof(lp->stats) ); + + return( 1 ); +} + + +static int lance_open( struct device *dev ) + +{ struct lance_private *lp = (struct lance_private *)dev->priv; + struct lance_ioreg *IO = lp->iobase; + int i; + + DPRINTK( 2, ( "%s: lance_open()\n", dev->name )); + + lance_init_ring(dev); + /* Re-initialize the LANCE, and start it when done. */ + + REGA( CSR3 ) = CSR3_BSWP | (lp->cardtype == PAM_CARD ? CSR3_ACON : 0); + REGA( CSR2 ) = 0; + REGA( CSR1 ) = 0; + REGA( CSR0 ) = CSR0_INIT; + /* From now on, AREG is kept to point to CSR0 */ + + i = 1000000; + while (--i > 0) + if (DREG & CSR0_IDON) + break; + if (i < 0 || (DREG & CSR0_ERR)) { + DPRINTK( 2, ( "lance_open(): opening %s failed, i=%d, csr0=%04x\n", + dev->name, i, DREG )); + DREG = CSR0_STOP; + return( -EIO ); + } + DREG = CSR0_IDON; + DREG = CSR0_STRT; + DREG = CSR0_INEA; + + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; + + DPRINTK( 2, ( "%s: LANCE is open, csr0 %04x\n", dev->name, DREG )); + MOD_INC_USE_COUNT; + + return( 0 ); +} + + +/* Initialize the LANCE Rx and Tx rings. */ + +static void lance_init_ring( struct device *dev ) + +{ struct lance_private *lp = (struct lance_private *)dev->priv; + int i; + unsigned offset; + + lp->lock = 0; + lp->tx_full = 0; + lp->cur_rx = lp->cur_tx = 0; + lp->dirty_tx = 0; + + offset = offsetof( struct lance_memory, packet_area ); + +/* If the packet buffer at offset 'o' would conflict with the reserved area + * of RieblCards, advance it */ +#define CHECK_OFFSET(o) \ + do { \ + if (lp->cardtype == OLD_RIEBL || lp->cardtype == NEW_RIEBL) { \ + if (((o) < RIEBL_RSVD_START) ? (o)+PKT_BUF_SZ > RIEBL_RSVD_START \ + : (o) < RIEBL_RSVD_END) \ + (o) = RIEBL_RSVD_END; \ + } \ + } while(0) + + for( i = 0; i < TX_RING_SIZE; i++ ) { + CHECK_OFFSET(offset); + MEM->tx_head[i].base = offset; + MEM->tx_head[i].flag = TMD1_OWN_HOST; + MEM->tx_head[i].base_hi = 0; + MEM->tx_head[i].length = 0; + MEM->tx_head[i].misc = 0; + offset += PKT_BUF_SZ; + } + + for( i = 0; i < RX_RING_SIZE; i++ ) { + CHECK_OFFSET(offset); + MEM->rx_head[i].base = offset; + MEM->rx_head[i].flag = TMD1_OWN_CHIP; + MEM->rx_head[i].base_hi = 0; + MEM->rx_head[i].buf_length = -PKT_BUF_SZ; + MEM->rx_head[i].msg_length = 0; + offset += PKT_BUF_SZ; + } +} + + +static int lance_start_xmit( struct sk_buff *skb, struct device *dev ) + +{ struct lance_private *lp = (struct lance_private *)dev->priv; + struct lance_ioreg *IO = lp->iobase; + int entry, len; + struct lance_tx_head *head; + unsigned long flags; + + /* Transmitter timeout, serious problems. */ + if (dev->tbusy) { + int tickssofar = jiffies - dev->trans_start; + if (tickssofar < 20) + return( 1 ); + AREG = CSR0; + DPRINTK( 1, ( "%s: transmit timed out, status %04x, resetting.\n", + dev->name, DREG )); + DREG = CSR0_STOP; + /* + * Always set BSWP after a STOP as STOP puts it back into + * little endian mode. + */ + REGA( CSR3 ) = CSR3_BSWP | (lp->cardtype == PAM_CARD ? CSR3_ACON : 0); + lp->stats.tx_errors++; +#ifndef final_version + { int i; + DPRINTK( 2, ( "Ring data: dirty_tx %d cur_tx %d%s cur_rx %d\n", + lp->dirty_tx, lp->cur_tx, + lp->tx_full ? " (full)" : "", + lp->cur_rx )); + for( i = 0 ; i < RX_RING_SIZE; i++ ) + DPRINTK( 2, ( "rx #%d: base=%04x blen=%04x mlen=%04x\n", + i, MEM->rx_head[i].base, + -MEM->rx_head[i].buf_length, + MEM->rx_head[i].msg_length )); + for( i = 0 ; i < TX_RING_SIZE; i++ ) + DPRINTK( 2, ( "tx #%d: base=%04x len=%04x misc=%04x\n", + i, MEM->tx_head[i].base, + -MEM->tx_head[i].length, + MEM->tx_head[i].misc )); + } +#endif + lance_init_ring(dev); + REGA( CSR0 ) = CSR0_INEA | CSR0_INIT | CSR0_STRT; + + dev->tbusy = 0; + dev->trans_start = jiffies; + + return( 0 ); + } + + if (skb == NULL) { + dev_tint( dev ); + return( 0 ); + } + + if (skb->len <= 0) + return( 0 ); + + DPRINTK( 2, ( "%s: lance_start_xmit() called, csr0 %4.4x.\n", + dev->name, DREG )); + + /* Block a timer-based transmit from overlapping. This could better be + done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ + if (set_bit( 0, (void*)&dev->tbusy ) != 0) { + DPRINTK( 0, ( "%s: Transmitter access conflict.\n", dev->name )); + return 1; + } + + if (set_bit( 0, (void*)&lp->lock ) != 0) { + DPRINTK( 0, ( "%s: tx queue lock!.\n", dev->name )); + /* don't clear dev->tbusy flag. */ + return 1; + } + + /* Fill in a Tx ring entry */ + if (lance_debug >= 3) { + u_char *p; + int i; + printk( "%s: TX pkt type 0x%04x from ", dev->name, + ((u_short *)skb->data)[6]); + for( p = &((u_char *)skb->data)[6], i = 0; i < 6; i++ ) + printk("%02x%s", *p++, i != 5 ? ":" : "" ); + printk(" to "); + for( p = (u_char *)skb->data, i = 0; i < 6; i++ ) + printk("%02x%s", *p++, i != 5 ? ":" : "" ); + printk(" data at 0x%08x len %d\n", (int)skb->data, + (int)skb->len ); + } + + /* We're not prepared for the int until the last flags are set/reset. And + * the int may happen already after setting the OWN_CHIP... */ + save_flags(flags); + cli(); + + /* Mask to ring buffer boundary. */ + entry = lp->cur_tx & TX_RING_MOD_MASK; + head = &(MEM->tx_head[entry]); + + /* Caution: the write order is important here, set the "ownership" bits + * last. + */ + + /* The old LANCE chips doesn't automatically pad buffers to min. size. */ + len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN; + /* PAM-Card has a bug: Can only send packets with even number of bytes! */ + if (lp->cardtype == PAM_CARD && (len & 1)) + ++len; + + head->length = -len; + head->misc = 0; + lp->memcpy_f( PKTBUF_ADDR(head), (void *)skb->data, skb->len ); + head->flag = TMD1_OWN_CHIP | TMD1_ENP | TMD1_STP; + dev_kfree_skb( skb, FREE_WRITE ); + lp->cur_tx++; + while( lp->cur_tx >= TX_RING_SIZE && lp->dirty_tx >= TX_RING_SIZE ) { + lp->cur_tx -= TX_RING_SIZE; + lp->dirty_tx -= TX_RING_SIZE; + } + + /* Trigger an immediate send poll. */ + DREG = CSR0_INEA | CSR0_TDMD; + dev->trans_start = jiffies; + + lp->lock = 0; + if ((MEM->tx_head[(entry+1) & TX_RING_MOD_MASK].flag & TMD1_OWN) == + TMD1_OWN_HOST) + dev->tbusy = 0; + else + lp->tx_full = 1; + restore_flags(flags); + + return 0; +} + +/* The LANCE interrupt handler. */ + +static void lance_interrupt( int irq, struct pt_regs *fp, struct device *dev ) + +{ struct lance_private *lp; + struct lance_ioreg *IO; + int csr0, boguscnt = 10; + + if (dev == NULL) { + DPRINTK( 1, ( "lance_interrupt(): interrupt for unknown device.\n" )); + return; + } + + lp = (struct lance_private *)dev->priv; + IO = lp->iobase; + AREG = CSR0; + + if (dev->interrupt) + DPRINTK( 2, ( "%s: Re-entering the interrupt handler.\n", dev->name )); + dev->interrupt = 1; + + while( ((csr0 = DREG) & (CSR0_ERR | CSR0_TINT | CSR0_RINT)) && + --boguscnt >= 0) { + /* Acknowledge all of the current interrupt sources ASAP. */ + DREG = csr0 & ~(CSR0_INIT | CSR0_STRT | CSR0_STOP | + CSR0_TDMD | CSR0_INEA); + + DPRINTK( 2, ( "%s: interrupt csr0=%04x new csr=%04x.\n", + dev->name, csr0, DREG )); + + if (csr0 & CSR0_RINT) /* Rx interrupt */ + lance_rx( dev ); + + if (csr0 & CSR0_TINT) { /* Tx-done interrupt */ + int dirty_tx = lp->dirty_tx; + + while( dirty_tx < lp->cur_tx) { + int entry = dirty_tx & TX_RING_MOD_MASK; + int status = MEM->tx_head[entry].flag; + + if (status & TMD1_OWN_CHIP) + break; /* It still hasn't been Txed */ + + MEM->tx_head[entry].flag = 0; + + if (status & TMD1_ERR) { + /* There was an major error, log it. */ + int err_status = MEM->tx_head[entry].misc; + lp->stats.tx_errors++; + if (err_status & TMD3_RTRY) lp->stats.tx_aborted_errors++; + if (err_status & TMD3_LCAR) lp->stats.tx_carrier_errors++; + if (err_status & TMD3_LCOL) lp->stats.tx_window_errors++; + if (err_status & TMD3_UFLO) { + /* Ackk! On FIFO errors the Tx unit is turned off! */ + lp->stats.tx_fifo_errors++; + /* Remove this verbosity later! */ + DPRINTK( 1, ( "%s: Tx FIFO error! Status %04x\n", + dev->name, csr0 )); + /* Restart the chip. */ + DREG = CSR0_STRT; + } + } else { + if (status & (TMD1_MORE | TMD1_ONE | TMD1_DEF)) + lp->stats.collisions++; + lp->stats.tx_packets++; + } + dirty_tx++; + } + +#ifndef final_version + if (lp->cur_tx - dirty_tx >= TX_RING_SIZE) { + DPRINTK( 0, ( "out-of-sync dirty pointer," + " %d vs. %d, full=%d.\n", + dirty_tx, lp->cur_tx, lp->tx_full )); + dirty_tx += TX_RING_SIZE; + } +#endif + + if (lp->tx_full && dev->tbusy + && dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) { + /* The ring is no longer full, clear tbusy. */ + lp->tx_full = 0; + dev->tbusy = 0; + mark_bh( NET_BH ); + } + + lp->dirty_tx = dirty_tx; + } + + /* Log misc errors. */ + if (csr0 & CSR0_BABL) lp->stats.tx_errors++; /* Tx babble. */ + if (csr0 & CSR0_MISS) lp->stats.rx_errors++; /* Missed a Rx frame. */ + if (csr0 & CSR0_MERR) { + DPRINTK( 1, ( "%s: Bus master arbitration failure (?!?), " + "status %04x.\n", dev->name, csr0 )); + /* Restart the chip. */ + DREG = CSR0_STRT; + } + } + + /* Clear any other interrupt, and set interrupt enable. */ + DREG = CSR0_BABL | CSR0_CERR | CSR0_MISS | CSR0_MERR | + CSR0_IDON | CSR0_INEA; + + DPRINTK( 2, ( "%s: exiting interrupt, csr0=%#04x.\n", + dev->name, DREG )); + dev->interrupt = 0; + return; +} + + +static int lance_rx( struct device *dev ) + +{ struct lance_private *lp = (struct lance_private *)dev->priv; + int entry = lp->cur_rx & RX_RING_MOD_MASK; + int i; + + DPRINTK( 2, ( "%s: rx int, flag=%04x\n", dev->name, + MEM->rx_head[entry].flag )); + + /* If we own the next entry, it's a new packet. Send it up. */ + while( (MEM->rx_head[entry].flag & RMD1_OWN) == RMD1_OWN_HOST ) { + struct lance_rx_head *head = &(MEM->rx_head[entry]); + int status = head->flag; + + if (status != (RMD1_ENP|RMD1_STP)) { /* There was an error. */ + /* There is a tricky error noted by John Murphy, + to Russ Nelson: Even with full-sized + buffers it's possible for a jabber packet to use two + buffers, with only the last correctly noting the error. */ + if (status & RMD1_ENP) /* Only count a general error at the */ + lp->stats.rx_errors++; /* end of a packet.*/ + if (status & RMD1_FRAM) lp->stats.rx_frame_errors++; + if (status & RMD1_OFLO) lp->stats.rx_over_errors++; + if (status & RMD1_CRC) lp->stats.rx_crc_errors++; + if (status & RMD1_BUFF) lp->stats.rx_fifo_errors++; + head->flag &= (RMD1_ENP|RMD1_STP); + } else { + /* Malloc up new buffer, compatible with net-3. */ + short pkt_len = head->msg_length & 0xfff; + struct sk_buff *skb; + + if (pkt_len < 60) { + printk( "%s: Runt packet!\n", dev->name ); + lp->stats.rx_errors++; + } + else { + skb = dev_alloc_skb( pkt_len+2 ); + if (skb == NULL) { + DPRINTK( 1, ( "%s: Memory squeeze, deferring packet.\n", + dev->name )); + for( i = 0; i < RX_RING_SIZE; i++ ) + if (MEM->rx_head[(entry+i) & RX_RING_MOD_MASK].flag & + RMD1_OWN_CHIP) + break; + + if (i > RX_RING_SIZE - 2) { + lp->stats.rx_dropped++; + head->flag |= RMD1_OWN_CHIP; + lp->cur_rx++; + } + break; + } + + if (lance_debug >= 3) { + u_char *data = PKTBUF_ADDR(head), *p; + printk( "%s: RX pkt type 0x%04x from ", dev->name, + ((u_short *)data)[6]); + for( p = &data[6], i = 0; i < 6; i++ ) + printk("%02x%s", *p++, i != 5 ? ":" : "" ); + printk(" to "); + for( p = data, i = 0; i < 6; i++ ) + printk("%02x%s", *p++, i != 5 ? ":" : "" ); + printk(" data %02x %02x %02x %02x %02x %02x %02x %02x " + "len %d\n", + data[15], data[16], data[17], data[18], + data[19], data[20], data[21], data[22], + pkt_len ); + } + + skb->dev = dev; + skb_reserve( skb, 2 ); /* 16 byte align */ + skb_put( skb, pkt_len ); /* Make room */ + lp->memcpy_f( skb->data, PKTBUF_ADDR(head), pkt_len ); + skb->protocol = eth_type_trans( skb, dev ); + netif_rx( skb ); + lp->stats.rx_packets++; + } + } + + head->flag |= RMD1_OWN_CHIP; + entry = (++lp->cur_rx) & RX_RING_MOD_MASK; + } + lp->cur_rx &= RX_RING_MOD_MASK; + + /* From lance.c (Donald Becker): */ + /* We should check that at least two ring entries are free. If not, + we should free one and mark stats->rx_dropped++. */ + + return 0; +} + + +static int lance_close( struct device *dev ) + +{ struct lance_private *lp = (struct lance_private *)dev->priv; + struct lance_ioreg *IO = lp->iobase; + + dev->start = 0; + dev->tbusy = 1; + + AREG = CSR0; + + DPRINTK( 2, ( "%s: Shutting down ethercard, status was %2.2x.\n", + dev->name, DREG )); + + /* We stop the LANCE here -- it occasionally polls + memory if we don't. */ + DREG = CSR0_STOP; + + MOD_DEC_USE_COUNT; + return 0; +} + + +static struct enet_statistics *lance_get_stats( struct device *dev ) + +{ struct lance_private *lp = (struct lance_private *)dev->priv; + + return &lp->stats; +} + + +/* Set or clear the multicast filter for this adaptor. + num_addrs == -1 Promiscuous mode, receive all packets + num_addrs == 0 Normal mode, clear multicast list + num_addrs > 0 Multicast mode, receive normal and MC packets, and do + best-effort filtering. + */ + +static void set_multicast_list( struct device *dev ) + +{ struct lance_private *lp = (struct lance_private *)dev->priv; + struct lance_ioreg *IO = lp->iobase; + + if (!dev->start) + /* Only possible if board is already started */ + return; + + /* We take the simple way out and always enable promiscuous mode. */ + DREG = CSR0_STOP; /* Temporarily stop the lance. */ + + if (dev->flags & IFF_PROMISC) { + /* Log any net taps. */ + DPRINTK( 1, ( "%s: Promiscuous mode enabled.\n", dev->name )); + REGA( CSR15 ) = 0x8000; /* Set promiscuous mode */ + } else { + short multicast_table[4]; + int num_addrs = dev->mc_count; + int i; + /* We don't use the multicast table, but rely on upper-layer + * filtering. */ + memset( multicast_table, (num_addrs == 0) ? 0 : -1, + sizeof(multicast_table) ); + for( i = 0; i < 4; i++ ) + REGA( CSR8+i ) = multicast_table[i]; + REGA( CSR15 ) = 0; /* Unset promiscuous mode */ + } + + /* + * Always set BSWP after a STOP as STOP puts it back into + * little endian mode. + */ + REGA( CSR3 ) = CSR3_BSWP | (lp->cardtype == PAM_CARD ? CSR3_ACON : 0); + + /* Resume normal operation and reset AREG to CSR0 */ + REGA( CSR0 ) = CSR0_IDON | CSR0_INEA | CSR0_STRT; +} + + +/* This is needed for old RieblCards and possible for new RieblCards */ + +static int lance_set_mac_address( struct device *dev, void *addr ) + +{ struct lance_private *lp = (struct lance_private *)dev->priv; + struct sockaddr *saddr = addr; + int i; + + if (lp->cardtype != OLD_RIEBL && lp->cardtype != NEW_RIEBL) + return( -EOPNOTSUPP ); + + if (dev->start) { + /* Only possible while card isn't started */ + DPRINTK( 1, ( "%s: hwaddr can be set only while card isn't open.\n", + dev->name )); + return( -EIO ); + } + + memcpy( dev->dev_addr, saddr->sa_data, dev->addr_len ); + for( i = 0; i < 6; i++ ) + MEM->init.hwaddr[i] = dev->dev_addr[i^1]; /* <- 16 bit swap! */ + lp->memcpy_f( RIEBL_HWADDR_ADDR, dev->dev_addr, 6 ); + /* set also the magic for future sessions */ + *RIEBL_MAGIC_ADDR = RIEBL_MAGIC; + + return( 0 ); +} + + +#ifdef MODULE +static char devicename[9] = { 0, }; + +static struct device atarilance_dev = +{ + devicename, /* filled in by register_netdev() */ + 0, 0, 0, 0, /* memory */ + 0, 0, /* base, irq */ + 0, 0, 0, NULL, atarilance_probe, +}; + +int init_module(void) + +{ int err; + + if ((err = register_netdev( &atarilance_dev ))) { + if (err == -EIO) { + printk( "No Atari Lance board found. Module not loaded.\n"); + } + return( err ); + } + return( 0 ); +} + +void cleanup_module(void) + +{ + unregister_netdev( &atarilance_dev ); +} + +#endif /* MODULE */ + + +/* + * Local variables: + * c-indent-level: 4 + * tab-width: 4 + * End: + */ diff -u --recursive --new-file v1.3.93/linux/drivers/scsi/README.g_NCR5380 linux/drivers/scsi/README.g_NCR5380 --- v1.3.93/linux/drivers/scsi/README.g_NCR5380 Fri Apr 12 15:51:59 1996 +++ linux/drivers/scsi/README.g_NCR5380 Mon Apr 22 12:26:21 1996 @@ -41,52 +41,23 @@ it!). This driver works as a module. +When included as a module, parameters can be passed on the insmod/modprobe +command line: + ncr_irq=xx the interrupt + ncr_addr=xx the port or base address (for port or memory + mapped, resp.) + ncr_dma=xx the DMA + ncr_5380=1 to set up for a NCR5380 board + ncr_53c400=1 to set up for a NCR53C400 board +e.g. +modprobe g_NCR5380 ncr_irq=5 ncr_addr=0x350 ncr_5380=1 + for a port mapped NCR5380 board or +modprobe g_NCR5380 ncr_irq=255 ncr_addr=0xc8000 ncr_53c400=1 + for a memory mapped NCR53C400 board with interrupts disabled. -Kevin Lentin -K.Lentin@cs.monash.edu.au -README file for the Linux g_NCR5380 driver. +(255 should be specified for no or DMA interrupt, 254 to autoprobe for an + IRQ line if overridden on the command line.) -(c) 1993 Drew Eckhard -NCR53c400 extensions (c) 1994,1995,1996 Kevin Lentin - -This file documents the NCR53c400 extensions by Kevin Lentin and some -enhancements to the NCR5380 core. - -This driver supports both NCR5380 and NCR53c400 cards in port or memory -mapped modes. Currently this driver can only support one of those mapping -modes at a time but it does support both of these chips at the same time. -The next release of this driver will support port & memory mapped cards at -the same time. It should be able to handle multiple different cards in the -same machine. - -The drivers/scsi/Makefile has an override in it for the most common -NCR53c400 card, the Trantor T130B in its default configuration: - Port: 0x350 - IRQ : 5 - -The NCR53c400 does not support DMA but it does have Pseudo-DMA which is -supported by the driver. - -If the default configuration does not work for you, you can use the kernel -command lines (eg using the lilo append command): - ncr5380=port,irq,dma - ncr53c400=port,irq -or - ncr5380=base,irq,dma - ncr53c400=base,irq - -The driver does not probe for any addresses or ports other than those in -the OVERRIDE or given to the kernel as above. - -This driver provides some information on what it has detected in -/proc/scsi/g_NCR5380/x where x is the scsi card number as detected at boot -time. More info to come in the future. - -When NCR53c400 support is compiled in, BIOS parameters will be returned by -the driver (the raw 5380 driver does not and I don't plan to fiddle with -it!). - -This driver works as a module. Kevin Lentin K.Lentin@cs.monash.edu.au diff -u --recursive --new-file v1.3.93/linux/drivers/scsi/README.st linux/drivers/scsi/README.st --- v1.3.93/linux/drivers/scsi/README.st Mon Apr 8 19:01:44 1996 +++ linux/drivers/scsi/README.st Mon Apr 22 11:13:22 1996 @@ -1,5 +1,5 @@ This file contains brief information about the SCSI tape driver. -Last modified: Mon Apr 8 09:34:33 1996 by makisara@kai.makisara.fi +Last modified: Sun Apr 21 21:19:22 1996 by root@kai.makisara.fi BASICS @@ -197,13 +197,16 @@ can be specified differently for each mode): MT_ST_BUFFER_WRITES write buffering (mode) MT_ST_ASYNC_WRITES asynchronous writes (mode) - MT_ST_READ_AHEAD read ahead (global) + MT_ST_READ_AHEAD read ahead (mode) MT_ST_TWO_FM writing of two filemarks (global) MT_ST_FAST_EOM using the SCSI spacing to EOD (global) MT_ST_AUTO_LOCK automatic locking of the drive door (global) MT_ST_DEF_WRITES the defaults are meant only for writes (mode) MT_ST_CAN_BSR backspacing over records can be used for repositioning the tape (global) + MT_ST_NO_BLKLIMS the driver does not ask the block limits + from the drive (block size can be changed only to + variable) (global) MT_ST_DEBUGGING debugging (global; debugging must be compiled into the driver) MT_ST_SETBOOLEANS diff -u --recursive --new-file v1.3.93/linux/drivers/scsi/a2091.c linux/drivers/scsi/a2091.c --- v1.3.93/linux/drivers/scsi/a2091.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/scsi/a2091.c Mon Apr 1 22:13:57 1996 @@ -0,0 +1,229 @@ +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "scsi.h" +#include "hosts.h" +#include "wd33c93.h" +#include "a2091.h" + +#include + +struct proc_dir_entry proc_scsi_a2091 = { + PROC_SCSI_A2091, 5, "A2091", + S_IFDIR | S_IRUGO | S_IXUGO, 2 +}; + +#define DMA(ptr) ((a2091_scsiregs *)((ptr)->base)) +#define HDATA(ptr) ((struct WD33C93_hostdata *)((ptr)->hostdata)) + +static struct Scsi_Host *first_instance = NULL; +static Scsi_Host_Template *a2091_template; + +static void a2091_intr (int irq, struct pt_regs *fp, void *dummy) +{ + unsigned int status; + struct Scsi_Host *instance; + + for (instance = first_instance; instance && + instance->hostt == a2091_template; instance = instance->next) + { + status = DMA(instance)->ISTR; + if (!(status & (ISTR_INT_F|ISTR_INT_P))) + continue; + + if (status & ISTR_INTS) + { + /* disable PORTS interrupt */ + custom.intena = IF_PORTS; + wd33c93_intr (instance); + /* enable PORTS interrupt */ + custom.intena = IF_SETCLR | IF_PORTS; + } + } +} + +static int dma_setup (Scsi_Cmnd *cmd, int dir_in) +{ + unsigned short cntr = CNTR_PDMD | CNTR_INTEN; + unsigned long addr = VTOP(cmd->SCp.ptr); + struct Scsi_Host *instance = cmd->host; + + /* don't allow DMA if the physical address is bad */ + if (addr & A2091_XFER_MASK || + (!dir_in && mm_end_of_chunk (addr, cmd->SCp.this_residual))) + { + HDATA(instance)->dma_bounce_len = (cmd->SCp.this_residual + 511) + & ~0x1ff; + HDATA(instance)->dma_bounce_buffer = + scsi_malloc (HDATA(instance)->dma_bounce_len); + + /* can't allocate memory; use PIO */ + if (!HDATA(instance)->dma_bounce_buffer) { + HDATA(instance)->dma_bounce_len = 0; + return 1; + } + + /* get the physical address of the bounce buffer */ + addr = VTOP(HDATA(instance)->dma_bounce_buffer); + + /* the bounce buffer may not be in the first 16M of physmem */ + if (addr & A2091_XFER_MASK) { + /* we could use chipmem... maybe later */ + scsi_free (HDATA(instance)->dma_bounce_buffer, + HDATA(instance)->dma_bounce_len); + HDATA(instance)->dma_bounce_buffer = NULL; + HDATA(instance)->dma_bounce_len = 0; + return 1; + } + + if (!dir_in) { + /* copy to bounce buffer for a write */ + if (cmd->use_sg) +#if 0 + panic ("scsi%ddma: incomplete s/g support", + instance->host_no); +#else + memcpy (HDATA(instance)->dma_bounce_buffer, + cmd->SCp.ptr, cmd->SCp.this_residual); +#endif + else + memcpy (HDATA(instance)->dma_bounce_buffer, + cmd->request_buffer, cmd->request_bufflen); + } + } + + /* setup dma direction */ + if (!dir_in) + cntr |= CNTR_DDIR; + + /* remember direction */ + HDATA(cmd->host)->dma_dir = dir_in; + + DMA(cmd->host)->CNTR = cntr; + + /* setup DMA *physical* address */ + DMA(cmd->host)->ACR = addr; + + if (dir_in){ + /* invalidate any cache */ + cache_clear (addr, cmd->SCp.this_residual); + }else{ + /* push any dirty cache */ + cache_push (addr, cmd->SCp.this_residual); + } + /* start DMA */ + DMA(cmd->host)->ST_DMA = 1; + + /* return success */ + return 0; +} + +static void dma_stop (struct Scsi_Host *instance, Scsi_Cmnd *SCpnt, + int status) +{ + /* disable SCSI interrupts */ + unsigned short cntr = CNTR_PDMD; + + if (!HDATA(instance)->dma_dir) + cntr |= CNTR_DDIR; + + /* disable SCSI interrupts */ + DMA(instance)->CNTR = cntr; + + /* flush if we were reading */ + if (HDATA(instance)->dma_dir) { + DMA(instance)->FLUSH = 1; + while (!(DMA(instance)->ISTR & ISTR_FE_FLG)) + ; + } + + /* clear a possible interrupt */ + DMA(instance)->CINT = 1; + + /* stop DMA */ + DMA(instance)->SP_DMA = 1; + + /* restore the CONTROL bits (minus the direction flag) */ + DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN; + + /* copy from a bounce buffer, if necessary */ + if (status && HDATA(instance)->dma_bounce_buffer) { + if (SCpnt && SCpnt->use_sg) { +#if 0 + panic ("scsi%d: incomplete s/g support", + instance->host_no); +#else + if( HDATA(instance)->dma_dir ) + memcpy (SCpnt->SCp.ptr, + HDATA(instance)->dma_bounce_buffer, + SCpnt->SCp.this_residual); + scsi_free (HDATA(instance)->dma_bounce_buffer, + HDATA(instance)->dma_bounce_len); + HDATA(instance)->dma_bounce_buffer = NULL; + HDATA(instance)->dma_bounce_len = 0; + +#endif + } else { + if (HDATA(instance)->dma_dir && SCpnt) + memcpy (SCpnt->request_buffer, + HDATA(instance)->dma_bounce_buffer, + SCpnt->request_bufflen); + + scsi_free (HDATA(instance)->dma_bounce_buffer, + HDATA(instance)->dma_bounce_len); + HDATA(instance)->dma_bounce_buffer = NULL; + HDATA(instance)->dma_bounce_len = 0; + } + } +} + +int a2091_detect(Scsi_Host_Template *tpnt) +{ + static unsigned char called = 0; + struct Scsi_Host *instance; + int i, manuf, product, num_a2091 = 0; + caddr_t address; + + if (!MACH_IS_AMIGA || called) + return 0; + called = 1; + + tpnt->proc_dir = &proc_scsi_a2091; + + for (i = 0; i < boot_info.bi_amiga.num_autocon; i++) + { + manuf = boot_info.bi_amiga.autocon[i].cd_Rom.er_Manufacturer; + product = boot_info.bi_amiga.autocon[i].cd_Rom.er_Product; + if (manuf == MANUF_COMMODORE && (product == PROD_A2091 || + product == PROD_A590)) { + address = boot_info.bi_amiga.autocon[i].cd_BoardAddr; + instance = scsi_register (tpnt, + sizeof (struct WD33C93_hostdata)); + instance->base = (unsigned char *)ZTWO_VADDR(address); + DMA(instance)->DAWR = DAWR_A2091; + wd33c93_init(instance, (wd33c93_regs *)&(DMA(instance)->SASR), + dma_setup, dma_stop, WD33C93_FS_8_10); + if (num_a2091++ == 0) { + first_instance = instance; + a2091_template = instance->hostt; + add_isr(IRQ_AMIGA_PORTS, a2091_intr, 0, NULL, "A2091 SCSI"); + } + DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN; + +#if 0 /* The Zorro stuff is not totally integrated yet ! */ + boot_info.bi_amiga.autocon_configured |= 1< + +int a2091_detect(Scsi_Host_Template *); +const char *wd33c93_info(void); +int wd33c93_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +int wd33c93_abort(Scsi_Cmnd *); +int wd33c93_reset(Scsi_Cmnd *); + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef CMD_PER_LUN +#define CMD_PER_LUN 2 +#endif + +#ifndef CAN_QUEUE +#define CAN_QUEUE 16 +#endif + +#ifdef HOSTS_C + +extern struct proc_dir_entry proc_scsi_a2091; + +#define A2091_SCSI { /* next */ NULL, \ + /* usage_count */ NULL, \ + /* proc_dir_entry */ &proc_scsi_a2091, \ + /* proc_info */ NULL, \ + /* name */ "Commodore A2091/A590 SCSI", \ + /* detect */ a2091_detect, \ + /* release */ NULL, \ + /* info */ NULL, \ + /* command */ NULL, \ + /* queuecommand */ wd33c93_queuecommand, \ + /* abort */ wd33c93_abort, \ + /* reset */ wd33c93_reset, \ + /* slave_attach */ NULL, \ + /* bios_param */ NULL, \ + /* can_queue */ CAN_QUEUE, \ + /* this_id */ 7, \ + /* sg_tablesize */ SG_ALL, \ + /* cmd_per_lun */ CMD_PER_LUN, \ + /* present */ 0, \ + /* unchecked_isa_dma */ 0, \ + /* use_clustering */ DISABLE_CLUSTERING } +#else + +/* + * if the transfer address ANDed with this results in a non-zero + * result, then we can't use DMA. + */ +#define A2091_XFER_MASK (0xff000001) + +typedef struct { + unsigned char pad1[64]; + volatile unsigned short ISTR; + volatile unsigned short CNTR; + unsigned char pad2[60]; + volatile unsigned int WTC; + volatile unsigned long ACR; + unsigned char pad3[6]; + volatile unsigned short DAWR; + unsigned char pad4; + volatile unsigned char SASR; + unsigned char pad5; + volatile unsigned char SCMD; + unsigned char pad6[76]; + volatile unsigned short ST_DMA; + volatile unsigned short SP_DMA; + volatile unsigned short CINT; + unsigned char pad7[2]; + volatile unsigned short FLUSH; +} a2091_scsiregs; + +#define DAWR_A2091 (3) + +/* CNTR bits. */ +#define CNTR_TCEN (1<<7) +#define CNTR_PREST (1<<6) +#define CNTR_PDMD (1<<5) +#define CNTR_INTEN (1<<4) +#define CNTR_DDIR (1<<3) + +/* ISTR bits. */ +#define ISTR_INTX (1<<8) +#define ISTR_INT_F (1<<7) +#define ISTR_INTS (1<<6) +#define ISTR_E_INT (1<<5) +#define ISTR_INT_P (1<<4) +#define ISTR_UE_INT (1<<3) +#define ISTR_OE_INT (1<<2) +#define ISTR_FF_FLG (1<<1) +#define ISTR_FE_FLG (1<<0) + +#endif /* else def HOSTS_C */ + +#endif /* A2091_H */ diff -u --recursive --new-file v1.3.93/linux/drivers/scsi/a3000.c linux/drivers/scsi/a3000.c --- v1.3.93/linux/drivers/scsi/a3000.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/scsi/a3000.c Sun Mar 17 21:53:33 1996 @@ -0,0 +1,203 @@ +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "scsi.h" +#include "hosts.h" +#include "wd33c93.h" +#include "a3000.h" + +#include + +struct proc_dir_entry proc_scsi_a3000 = { + PROC_SCSI_A3000, 5, "A3000", + S_IFDIR | S_IRUGO | S_IXUGO, 2 +}; + +#define DMA(ptr) ((a3000_scsiregs *)((ptr)->base)) +#define HDATA(ptr) ((struct WD33C93_hostdata *)((ptr)->hostdata)) + +static struct Scsi_Host *a3000_host = NULL; + +static void a3000_intr (int irq, struct pt_regs *fp, void *dummy) +{ + unsigned int status = DMA(a3000_host)->ISTR; + + if (!(status & ISTR_INT_P)) + return; + + if (status & ISTR_INTS) + { + /* disable PORTS interrupt */ + custom.intena = IF_PORTS; + wd33c93_intr (a3000_host); + /* enable PORTS interrupt */ + custom.intena = IF_SETCLR | IF_PORTS; + } else { + printk("Non-serviced A3000 SCSI-interrupt? ISTR = %02x\n", status); + } +} + +static int dma_setup (Scsi_Cmnd *cmd, int dir_in) +{ + unsigned short cntr = CNTR_PDMD | CNTR_INTEN; + unsigned long addr = VTOP(cmd->SCp.ptr); + + /* + * if the physical address has the wrong alignment, or if + * physical address is bad, or if it is a write and at the + * end of a physical memory chunk, then allocate a bounce + * buffer + */ + if (addr & A3000_XFER_MASK || + (!dir_in && mm_end_of_chunk (addr, cmd->SCp.this_residual))) + { + HDATA(a3000_host)->dma_bounce_len = (cmd->SCp.this_residual + 511) + & ~0x1ff; + HDATA(a3000_host)->dma_bounce_buffer = + scsi_malloc (HDATA(a3000_host)->dma_bounce_len); + + /* can't allocate memory; use PIO */ + if (!HDATA(a3000_host)->dma_bounce_buffer) { + HDATA(a3000_host)->dma_bounce_len = 0; + return 1; + } + + if (!dir_in) { + /* copy to bounce buffer for a write */ + if (cmd->use_sg) { + memcpy (HDATA(a3000_host)->dma_bounce_buffer, + cmd->SCp.ptr, cmd->SCp.this_residual); + } else + memcpy (HDATA(a3000_host)->dma_bounce_buffer, + cmd->request_buffer, cmd->request_bufflen); + } + + addr = VTOP(HDATA(a3000_host)->dma_bounce_buffer); + } + + /* setup dma direction */ + if (!dir_in) + cntr |= CNTR_DDIR; + + /* remember direction */ + HDATA(a3000_host)->dma_dir = dir_in; + + DMA(a3000_host)->CNTR = cntr; + + /* setup DMA *physical* address */ + DMA(a3000_host)->ACR = addr; + + + if (dir_in) + { + /* invalidate any cache */ + /* + * On the 68040 it's not ok to use cache_clear, as it just invalidates + * cache-lines, and thereby trashing them. We need to use cache_push + * to avoid problems/crashes. + * This was a real bitch to catch :-( -Jes + */ + + if (boot_info.cputype & CPU_68040) + cache_push (addr, cmd->SCp.this_residual); + else + cache_clear (addr, cmd->SCp.this_residual); + } + else + /* push any dirty cache */ + cache_push (addr, cmd->SCp.this_residual); + + + /* start DMA */ + DMA(a3000_host)->ST_DMA = 1; + + /* return success */ + return 0; +} + +static void dma_stop (struct Scsi_Host *instance, Scsi_Cmnd *SCpnt, + int status) +{ + /* disable SCSI interrupts */ + unsigned short cntr = CNTR_PDMD; + + if (!HDATA(instance)->dma_dir) + cntr |= CNTR_DDIR; + + DMA(instance)->CNTR = cntr; + + /* flush if we were reading */ + if (HDATA(instance)->dma_dir) { + DMA(instance)->FLUSH = 1; + while (!(DMA(instance)->ISTR & ISTR_FE_FLG)) + ; + } + + /* clear a possible interrupt */ + /* I think that this CINT is only necessary if you are + * using the terminal count features. HM 7 Mar 1994 + */ + DMA(instance)->CINT = 1; + + /* stop DMA */ + DMA(instance)->SP_DMA = 1; + + /* restore the CONTROL bits (minus the direction flag) */ + DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN; + + /* copy from a bounce buffer, if necessary */ + if (status && HDATA(instance)->dma_bounce_buffer) { + if (SCpnt && SCpnt->use_sg) { + if (HDATA(instance)->dma_dir && SCpnt) + memcpy (SCpnt->SCp.ptr, + HDATA(instance)->dma_bounce_buffer, + SCpnt->SCp.this_residual); + scsi_free (HDATA(instance)->dma_bounce_buffer, + HDATA(instance)->dma_bounce_len); + HDATA(instance)->dma_bounce_buffer = NULL; + HDATA(instance)->dma_bounce_len = 0; + } else { + if (HDATA(instance)->dma_dir && SCpnt) + memcpy (SCpnt->request_buffer, + HDATA(instance)->dma_bounce_buffer, + SCpnt->request_bufflen); + + scsi_free (HDATA(instance)->dma_bounce_buffer, + HDATA(instance)->dma_bounce_len); + HDATA(instance)->dma_bounce_buffer = NULL; + HDATA(instance)->dma_bounce_len = 0; + } + } +} + +int a3000_detect(Scsi_Host_Template *tpnt) +{ + static unsigned char called = 0; + + if (called) + return 0; + + if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(A3000_SCSI)) + return 0; + + tpnt->proc_dir = &proc_scsi_a3000; + + a3000_host = scsi_register (tpnt, sizeof(struct WD33C93_hostdata)); + a3000_host->base = (unsigned char *)ZTWO_VADDR(0xDD0000); + DMA(a3000_host)->DAWR = DAWR_A3000; + wd33c93_init(a3000_host, (wd33c93_regs *)&(DMA(a3000_host)->SASR), + dma_setup, dma_stop, WD33C93_FS_12_15); + add_isr(IRQ_AMIGA_PORTS, a3000_intr, 0, NULL, "A3000 SCSI"); + DMA(a3000_host)->CNTR = CNTR_PDMD | CNTR_INTEN; + called = 1; + + return 1; +} diff -u --recursive --new-file v1.3.93/linux/drivers/scsi/a3000.h linux/drivers/scsi/a3000.h --- v1.3.93/linux/drivers/scsi/a3000.h Thu Jan 1 02:00:00 1970 +++ linux/drivers/scsi/a3000.h Fri Apr 5 15:15:07 1996 @@ -0,0 +1,110 @@ +#ifndef A3000_H + +/* $Id: a3000.h,v 1.2 1996/02/29 22:10:29 root Exp root $ + * + * Header file for the Amiga 3000 built-in SCSI controller for Linux + * + * Written and (C) 1993, Hamish Macdonald, see a3000.c for more info + * + */ + +#include + +int a3000_detect(Scsi_Host_Template *); +const char *wd33c93_info(void); +int wd33c93_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +int wd33c93_abort(Scsi_Cmnd *); +int wd33c93_reset(Scsi_Cmnd *); + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef CMD_PER_LUN +#define CMD_PER_LUN 2 +#endif + +#ifndef CAN_QUEUE +#define CAN_QUEUE 16 +#endif + +#ifdef HOSTS_C + +extern struct proc_dir_entry proc_scsi_a3000; + +#define A3000_SCSI { /* next */ NULL, \ + /* usage_count */ NULL, \ + /* proc_dir_entry */ &proc_scsi_a3000, \ + /* proc_info */ NULL, \ + /* name */ "Amiga 3000 built-in SCSI", \ + /* detect */ a3000_detect, \ + /* release */ NULL, \ + /* info */ NULL, \ + /* command */ NULL, \ + /* queuecommand */ wd33c93_queuecommand, \ + /* abort */ wd33c93_abort, \ + /* reset */ wd33c93_reset, \ + /* slave_attach */ NULL, \ + /* bios_param */ NULL, \ + /* can_queue */ CAN_QUEUE, \ + /* this_id */ 7, \ + /* sg_tablesize */ SG_ALL, \ + /* cmd_per_lun */ CMD_PER_LUN, \ + /* present */ 0, \ + /* unchecked_isa_dma */ 0, \ + /* use_clustering */ DISABLE_CLUSTERING } +#else + +/* + * if the transfer address ANDed with this results in a non-zero + * result, then we can't use DMA. + */ +#define A3000_XFER_MASK (0x00000003) + +typedef struct { + unsigned char pad1[2]; + volatile unsigned short DAWR; + volatile unsigned int WTC; + unsigned char pad2[2]; + volatile unsigned short CNTR; + volatile unsigned long ACR; + unsigned char pad3[2]; + volatile unsigned short ST_DMA; + unsigned char pad4[2]; + volatile unsigned short FLUSH; + unsigned char pad5[2]; + volatile unsigned short CINT; + unsigned char pad6[2]; + volatile unsigned short ISTR; + unsigned char pad7[30]; + volatile unsigned short SP_DMA; + unsigned char pad8; + volatile unsigned char SASR; + unsigned char pad9; + volatile unsigned char SCMD; +} a3000_scsiregs; + +#define DAWR_A3000 (3) + +/* CNTR bits. */ +#define CNTR_TCEN (1<<5) +#define CNTR_PREST (1<<4) +#define CNTR_PDMD (1<<3) +#define CNTR_INTEN (1<<2) +#define CNTR_DDIR (1<<1) +#define CNTR_IO_DX (1<<0) + +/* ISTR bits. */ +#define ISTR_INTX (1<<8) +#define ISTR_INT_F (1<<7) +#define ISTR_INTS (1<<6) +#define ISTR_E_INT (1<<5) +#define ISTR_INT_P (1<<4) +#define ISTR_UE_INT (1<<3) +#define ISTR_OE_INT (1<<2) +#define ISTR_FF_FLG (1<<1) +#define ISTR_FE_FLG (1<<0) + +#endif /* else def HOSTS_C */ + +#endif /* A3000_H */ diff -u --recursive --new-file v1.3.93/linux/drivers/scsi/atari_NCR5380.c linux/drivers/scsi/atari_NCR5380.c --- v1.3.93/linux/drivers/scsi/atari_NCR5380.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/scsi/atari_NCR5380.c Sat Apr 13 14:31:03 1996 @@ -0,0 +1,3099 @@ +/* + * NCR 5380 generic driver routines. These should make it *trivial* + * to implement 5380 SCSI drivers under Linux with a non-trantor + * architecture. + * + * Note that these routines also work with NR53c400 family chips. + * + * Copyright 1993, Drew Eckhardt + * Visionary Computing + * (Unix and Linux consulting and custom programming) + * drew@colorado.edu + * +1 (303) 666-5836 + * + * DISTRIBUTION RELEASE 6. + * + * For more information, please consult + * + * NCR 5380 Family + * SCSI Protocol Controller + * Databook + * + * NCR Microelectronics + * 1635 Aeroplaza Drive + * Colorado Springs, CO 80916 + * 1+ (719) 578-3400 + * 1+ (800) 334-5454 + */ + +/* + * ++roman: To port the 5380 driver to the Atari, I had to do some changes in + * this file, too: + * + * - Some of the debug statements were incorrect (undefined variables and the + * like). I fixed that. + * + * - In information_transfer(), I think a #ifdef was wrong. Looking at the + * possible DMA transfer size should also happen for REAL_DMA. I added this + * in the #if statement. + * + * - When using real DMA, information_transfer() should return in a DATAOUT + * phase after starting the DMA. It has nothing more to do. + * + * - The interrupt service routine should run main after end of DMA, too (not + * only after RESELECTION interrupts). Additionally, it should _not_ test + * for more interrupts after running main, since a DMA process may have + * been started and interrupts are turned on now. The new int could happen + * inside the execution of NCR5380_intr(), leading to recursive + * calls. + * + * - I've added a function merge_consecutive_buffers() that trys to + * merge scatter-gather buffers that are located at consecutive + * physical addresses and can be processed with the same DMA setup. + * Since most scatter-gather operations work on a page (4K) of + * 4 buffers (1K), in more than 90% of all cases three interrupts and + * DMA setup actions are saved. + * + */ + +/* + * +++roman: I've deleted all the stuff for AUTOPROBE_IRQ, REAL_DMA_POLL, + * PSEUDO_DMA and USLEEP, because these were messing up + * readability and will never be needed for Atari SCSI. + */ + + +/* + * $Log: atari_NCR5380.c,v $ + * Revision 1.2 1996/04/04 13:30:22 root + * interrupts more like the pc + * + * Revision 1.1 1996/03/20 17:51:35 root + * Initial revision + * + * Revision 1.2 1994/11/26 03:38:32 hamish + * v0.9pl4 + * + * Revision 1.1 1994/11/08 03:25:43 hamish + * Initial revision + * + * Revision 1.5 1994/01/19 09:14:57 drew + * Fixed udelay() hack that was being used on DATAOUT phases + * instead of a proper wait for the final handshake. + * + * Revision 1.4 1994/01/19 06:44:25 drew + * *** empty log message *** + * + * Revision 1.3 1994/01/19 05:24:40 drew + * Added support for TCR LAST_BYTE_SENT bit. + * + * Revision 1.2 1994/01/15 06:14:11 drew + * REAL DMA support, bug fixes. + * + * Revision 1.1 1994/01/15 06:00:54 drew + * Initial revision + * + */ + +/* + * Further development / testing that should be done : + * 1. Cleanup the NCR5380_transfer_dma function and DMA operation complete + * code so that everything does the same thing that's done at the + * end of a pseudo-DMA read operation. + * + * 2. Fix REAL_DMA (interrupt driven, polled works fine) - + * basically, transfer size needs to be reduced by one + * and the last byte read as is done with PSEUDO_DMA. + * + * 3. Test USLEEP code + * + * 4. Test SCSI-II tagged queueing (I have no devices which support + * tagged queueing) + * + * 5. Test linked command handling code after Eric is ready with + * the high level code. + */ + +#if (NDEBUG & NDEBUG_LISTS) +#define LIST(x,y) \ + { printk("LINE:%d Adding %p to %p\n", __LINE__, (void*)(x), (void*)(y)); \ + if ((x)==(y)) udelay(5); } +#define REMOVE(w,x,y,z) \ + { printk("LINE:%d Removing: %p->%p %p->%p \n", __LINE__, \ + (void*)(w), (void*)(x), (void*)(y), (void*)(z)); \ + if ((x)==(y)) udelay(5); } +#else +#define LIST(x,y) +#define REMOVE(w,x,y,z) +#endif + +#ifndef notyet +#undef LINKED +#endif + +/* + * Design + * Issues : + * + * The other Linux SCSI drivers were written when Linux was Intel PC-only, + * and specifically for each board rather than each chip. This makes their + * adaptation to platforms like the Mac (Some of which use NCR5380's) + * more difficult than it has to be. + * + * Also, many of the SCSI drivers were written before the command queuing + * routines were implemented, meaning their implementations of queued + * commands were hacked on rather than designed in from the start. + * + * When I designed the Linux SCSI drivers I figured that + * while having two different SCSI boards in a system might be useful + * for debugging things, two of the same type wouldn't be used. + * Well, I was wrong and a number of users have mailed me about running + * multiple high-performance SCSI boards in a server. + * + * Finally, when I get questions from users, I have no idea what + * revision of my driver they are running. + * + * This driver attempts to address these problems : + * This is a generic 5380 driver. To use it on a different platform, + * one simply writes appropriate system specific macros (ie, data + * transfer - some PC's will use the I/O bus, 68K's must use + * memory mapped) and drops this file in their 'C' wrapper. + * + * As far as command queueing, two queues are maintained for + * each 5380 in the system - commands that haven't been issued yet, + * and commands that are currently executing. This means that an + * unlimited number of commands may be queued, letting + * more commands propagate from the higher driver levels giving higher + * throughput. Note that both I_T_L and I_T_L_Q nexuses are supported, + * allowing multiple commands to propagate all the way to a SCSI-II device + * while a command is already executing. + * + * To solve the multiple-boards-in-the-same-system problem, + * there is a separate instance structure for each instance + * of a 5380 in the system. So, multiple NCR5380 drivers will + * be able to coexist with appropriate changes to the high level + * SCSI code. + * + * A NCR5380_PUBLIC_REVISION macro is provided, with the release + * number (updated for each public release) printed by the + * NCR5380_print_options command, which should be called from the + * wrapper detect function, so that I know what release of the driver + * users are using. + * + * Issues specific to the NCR5380 : + * + * When used in a PIO or pseudo-dma mode, the NCR5380 is a braindead + * piece of hardware that requires you to sit in a loop polling for + * the REQ signal as long as you are connected. Some devices are + * brain dead (ie, many TEXEL CD ROM drives) and won't disconnect + * while doing long seek operations. + * + * The workaround for this is to keep track of devices that have + * disconnected. If the device hasn't disconnected, for commands that + * should disconnect, we do something like + * + * while (!REQ is asserted) { sleep for N usecs; poll for M usecs } + * + * Some tweaking of N and M needs to be done. An algorithm based + * on "time to data" would give the best results as long as short time + * to datas (ie, on the same track) were considered, however these + * broken devices are the exception rather than the rule and I'd rather + * spend my time optimizing for the normal case. + * + * Architecture : + * + * At the heart of the design is a coroutine, NCR5380_main, + * which is started when not running by the interrupt handler, + * timer, and queue command function. It attempts to establish + * I_T_L or I_T_L_Q nexuses by removing the commands from the + * issue queue and calling NCR5380_select() if a nexus + * is not established. + * + * Once a nexus is established, the NCR5380_information_transfer() + * phase goes through the various phases as instructed by the target. + * if the target goes into MSG IN and sends a DISCONNECT message, + * the command structure is placed into the per instance disconnected + * queue, and NCR5380_main tries to find more work. If USLEEP + * was defined, and the target is idle for too long, the system + * will try to sleep. + * + * If a command has disconnected, eventually an interrupt will trigger, + * calling NCR5380_intr() which will in turn call NCR5380_reselect + * to reestablish a nexus. This will run main if necessary. + * + * On command termination, the done function will be called as + * appropriate. + * + * SCSI pointers are maintained in the SCp field of SCSI command + * structures, being initialized after the command is connected + * in NCR5380_select, and set as appropriate in NCR5380_information_transfer. + * Note that in violation of the standard, an implicit SAVE POINTERS operation + * is done, since some BROKEN disks fail to issue an explicit SAVE POINTERS. + */ + +/* + * Using this file : + * This file a skeleton Linux SCSI driver for the NCR 5380 series + * of chips. To use it, you write a architecture specific functions + * and macros and include this file in your driver. + * + * These macros control options : + * AUTOSENSE - if defined, REQUEST SENSE will be performed automatically + * for commands that return with a CHECK CONDITION status. + * + * LINKED - if defined, linked commands are supported. + * + * REAL_DMA - if defined, REAL DMA is used during the data transfer phases. + * + * SUPPORT_TAGS - if defined, SCSI-2 tagged queuing is used where possible + * + * These macros MUST be defined : + * + * NCR5380_read(register) - read from the specified register + * + * NCR5380_write(register, value) - write to the specific register + * + * Either real DMA *or* pseudo DMA may be implemented + * REAL functions : + * NCR5380_REAL_DMA should be defined if real DMA is to be used. + * Note that the DMA setup functions should return the number of bytes + * that they were able to program the controller for. + * + * Also note that generic i386/PC versions of these macros are + * available as NCR5380_i386_dma_write_setup, + * NCR5380_i386_dma_read_setup, and NCR5380_i386_dma_residual. + * + * NCR5380_dma_write_setup(instance, src, count) - initialize + * NCR5380_dma_read_setup(instance, dst, count) - initialize + * NCR5380_dma_residual(instance); - residual count + * + * PSEUDO functions : + * NCR5380_pwrite(instance, src, count) + * NCR5380_pread(instance, dst, count); + * + * If nothing specific to this implementation needs doing (ie, with external + * hardware), you must also define + * + * NCR5380_queue_command + * NCR5380_reset + * NCR5380_abort + * NCR5380_proc_info + * + * to be the global entry points into the specific driver, ie + * #define NCR5380_queue_command t128_queue_command. + * + * If this is not done, the routines will be defined as static functions + * with the NCR5380* names and the user must provide a globally + * accessible wrapper function. + * + * The generic driver is initialized by calling NCR5380_init(instance), + * after setting the appropriate host specific fields and ID. If the + * driver wishes to autoprobe for an IRQ line, the NCR5380_probe_irq(instance, + * possible) function may be used. Before the specific driver initialization + * code finishes, NCR5380_print_options should be called. + */ + +static struct Scsi_Host *first_instance = NULL; +static Scsi_Host_Template *the_template = NULL; + +/* Macros ease life... :-) */ +#define SETUP_HOSTDATA(in) \ + struct NCR5380_hostdata *hostdata = \ + (struct NCR5380_hostdata *)(in)->hostdata +#define HOSTDATA(in) ((struct NCR5380_hostdata *)(in)->hostdata) + +#define NEXT(cmd) ((Scsi_Cmnd *)((cmd)->host_scribble)) +#define NEXTADDR(cmd) ((Scsi_Cmnd **)&((cmd)->host_scribble)) + +#define HOSTNO instance->host_no +#define H_NO(cmd) (cmd)->host->host_no + +#ifdef SUPPORT_TAGS + +/* + * Functions for handling tagged queuing + * ===================================== + * + * ++roman (01/96): Now I've implemented SCSI-2 tagged queuing. Some notes: + * + * Using consecutive numbers for the tags is no good idea in my eyes. There + * could be wrong re-usings if the counter (8 bit!) wraps and some early + * command has been preempted for a long time. My solution: a bitfield for + * remembering used tags. + * + * There's also the problem that each target has a certain queue size, but we + * cannot know it in advance :-( We just see a QUEUE_FULL status being + * returned. So, in this case, the driver internal queue size assumption is + * reduced to the number of active tags if QUEUE_FULL is returned by the + * target. The command is returned to the mid-level, but with status changed + * to BUSY, since --as I've seen-- the mid-level can't handle QUEUE_FULL + * correctly. + * + * We're also not allowed running tagged commands as long as an untagged + * command is active. And REQUEST SENSE commands after a contingent allegiance + * condition _must_ be untagged. To keep track whether an untagged command has + * been issued, the host->busy array is still employed, as it is without + * support for tagged queuing. + * + * One could suspect that there are possible race conditions between + * is_lun_busy(), cmd_get_tag() and cmd_free_tag(). But I think this isn't the + * case: is_lun_busy() and cmd_get_tag() are both called from NCR5380_main(), + * which already guaranteed to be running at most once. It is also the only + * place where tags/LUNs are allocated. So no other allocation can slip + * between that pair, there could only happen a reselection, which can free a + * tag, but that doesn't hurt. Only the sequence in cmd_free_tag() becomes + * important: the tag bit must be cleared before 'nr_allocated' is decreased. + */ + +/* -1 for TAG_NONE is not possible with unsigned char cmd->tag */ +#undef TAG_NONE +#define TAG_NONE 0xff + +/* For the m68k, the number of bits in 'allocated' must be a multiple of 32! */ +#if (MAX_TAGS % 32) != 0 +#error "MAX_TAGS must be a multiple of 32!" +#endif + +typedef struct { + char allocated[MAX_TAGS/8]; + int nr_allocated; + int queue_size; +} TAG_ALLOC; + +static TAG_ALLOC TagAlloc[8][8]; /* 8 targets and 8 LUNs */ + + +static void init_tags( void ) +{ + int target, lun; + TAG_ALLOC *ta; + + if (!setup_use_tagged_queuing) + return; + + for( target = 0; target < 8; ++target ) { + for( lun = 0; lun < 8; ++lun ) { + ta = &TagAlloc[target][lun]; + memset( &ta->allocated, 0, MAX_TAGS/8 ); + ta->nr_allocated = 0; + /* At the beginning, assume the maximum queue size we could + * support (MAX_TAGS). This value will be decreased if the target + * returns QUEUE_FULL status. + */ + ta->queue_size = MAX_TAGS; + } + } +} + + +/* Check if we can issue a command to this LUN: First see if the LUN is marked + * busy by an untagged command. If the command should use tagged queuing, also + * check that there is a free tag and the target's queue won't overflow. This + * function should be called with interrupts disabled to avoid race + * conditions. + */ + +static int is_lun_busy( Scsi_Cmnd *cmd, int should_be_tagged ) +{ + SETUP_HOSTDATA(cmd->host); + + if (hostdata->busy[cmd->target] & (1 << cmd->lun)) + return( 1 ); + if (!should_be_tagged || + !setup_use_tagged_queuing || !cmd->device->tagged_supported) + return( 0 ); + if (TagAlloc[cmd->target][cmd->lun].nr_allocated >= + TagAlloc[cmd->target][cmd->lun].queue_size ) { +#if (NDEBUG & NDEBUG_TAGS) + printk( "scsi%d: target %d lun %d: no free tags\n", + H_NO(cmd), cmd->target, cmd->lun ); +#endif + return( 1 ); + } + return( 0 ); +} + + +/* Allocate a tag for a command (there are no checks anymore, check_lun_busy() + * must be called before!), or reserve the LUN in 'busy' if the command is + * untagged. + */ + +static void cmd_get_tag( Scsi_Cmnd *cmd, int should_be_tagged ) +{ + SETUP_HOSTDATA(cmd->host); + + /* If we or the target don't support tagged queuing, allocate the LUN for + * an untagged command. + */ + if (!should_be_tagged || + !setup_use_tagged_queuing || !cmd->device->tagged_supported) { + cmd->tag = TAG_NONE; + hostdata->busy[cmd->target] |= (1 << cmd->lun); +#if (NDEBUG & NDEBUG_TAGS) + printk( "scsi%d: target %d lun %d now allocated by untagged command\n", + H_NO(cmd), cmd->target, cmd->lun ); +#endif + } + else { + TAG_ALLOC *ta = &TagAlloc[cmd->target][cmd->lun]; + + cmd->tag = find_first_zero_bit( &ta->allocated, MAX_TAGS ); + set_bit( cmd->tag, &ta->allocated ); + ta->nr_allocated++; +#if (NDEBUG & NDEBUG_TAGS) + printk( "scsi%d: using tag %d for target %d lun %d " + "(now %d tags in use)\n", + H_NO(cmd), cmd->tag, cmd->target, cmd->lun, + ta->nr_allocated ); +#endif + } +} + + +/* Mark the tag of command 'cmd' as free, or in case of an untagged command, + * unlock the LUN. + */ + +static void cmd_free_tag( Scsi_Cmnd *cmd ) +{ + SETUP_HOSTDATA(cmd->host); + + if (cmd->tag == TAG_NONE) { + hostdata->busy[cmd->target] &= ~(1 << cmd->lun); +#if (NDEBUG & NDEBUG_TAGS) + printk( "scsi%d: target %d lun %d untagged cmd finished\n", + H_NO(cmd), cmd->target, cmd->lun ); +#endif + } + else if (cmd->tag >= MAX_TAGS) { + printk( "scsi%d: trying to free bad tag %d!\n", + H_NO(cmd), cmd->tag ); + } + else { + TAG_ALLOC *ta = &TagAlloc[cmd->target][cmd->lun]; + clear_bit( cmd->tag, &ta->allocated ); + ta->nr_allocated--; +#if (NDEBUG & NDEBUG_TAGS) + printk( "scsi%d: freed tag %d for target %d lun %d\n", + H_NO(cmd), cmd->tag, cmd->target, cmd->lun ); +#endif + } +} + + +#if 0 +static void free_all_tags( void ) +{ + int target, lun; + TAG_ALLOC *ta; + + if (!setup_use_tagged_queuing) + return; + + for( target = 0; target < 8; ++target ) { + for( lun = 0; lun < 8; ++lun ) { + ta = &TagAlloc[target][lun]; + memset( &ta->allocated, 0, MAX_TAGS/8 ); + ta->nr_allocated = 0; + } + } +} +#endif + +#endif /* SUPPORT_TAGS */ + + +/* + * Function: void merge_consecutive_buffers( Scsi_Cmnd *cmd ) + * + * Purpose: Try to merge several scatter-gather requests into one DMA + * transfer. This is possible if the scatter buffers lie on + * physical consecutive addresses. + * + * Parameters: Scsi_Cmnd *cmd + * The command to work on. The first scatter buffer's data are + * assumed to be already transfered into ptr/this_residual. + */ + +/* A special issue is when the buffer is exactly at the end of the + * last physical memory chunk: VTOP would have to calculate the + * physical address just 1 byte behind the end of physical memory. But + * it will panic if given this address :-( So we need to avoid calling + * VTOP on addresses that don't exist. This is done by keeping + * 'endadr' to be the real end address of the buffer, not one byte + * more (which would be easier). + */ + +static void merge_consecutive_buffers( Scsi_Cmnd *cmd ) +{ + unsigned long endadr; +#if (NDEBUG & NDEBUG_MERGING) + unsigned long oldlen = cmd->SCp.this_residual; + int cnt = 1; +#endif + + for( endadr = VTOP(cmd->SCp.ptr + cmd->SCp.this_residual - 1); + cmd->SCp.buffers_residual && + VTOP( (cmd->SCp.buffer+1)->address ) == endadr + 1; ) { + +#if (NDEBUG & NDEBUG_MERGING) + printk( "%08lx == %08lx -> merging\n", + VTOP( (cmd->SCp.buffer+1)->address ), endadr ); + ++cnt; +#endif + ++cmd->SCp.buffer; + --cmd->SCp.buffers_residual; + cmd->SCp.this_residual += cmd->SCp.buffer->length; + endadr += cmd->SCp.buffer->length; + } +#if (NDEBUG & NDEBUG_MERGING) + if (oldlen != cmd->SCp.this_residual) + printk( "merged %d buffers from %08lx, new length %08lx\n", + cnt, (long)(cmd->SCp.ptr), cmd->SCp.this_residual ); +#endif +} + +/* + * Function : void initialize_SCp(Scsi_Cmnd *cmd) + * + * Purpose : initialize the saved data pointers for cmd to point to the + * start of the buffer. + * + * Inputs : cmd - Scsi_Cmnd structure to have pointers reset. + */ + +static __inline__ void initialize_SCp(Scsi_Cmnd *cmd) +{ + /* + * Initialize the Scsi Pointer field so that all of the commands in the + * various queues are valid. + */ + + if (cmd->use_sg) { + cmd->SCp.buffer = (struct scatterlist *) cmd->buffer; + cmd->SCp.buffers_residual = cmd->use_sg - 1; + cmd->SCp.ptr = (char *) cmd->SCp.buffer->address; + cmd->SCp.this_residual = cmd->SCp.buffer->length; + /* ++roman: Try to merge some scatter-buffers if they are at + * consecutive physical addresses. + */ + merge_consecutive_buffers( cmd ); + } else { + cmd->SCp.buffer = NULL; + cmd->SCp.buffers_residual = 0; + cmd->SCp.ptr = (char *) cmd->request_buffer; + cmd->SCp.this_residual = cmd->request_bufflen; + } +} + +#include +#include + +#ifdef NDEBUG +static struct { + unsigned char mask; + const char * name;} +signals[] = {{ SR_DBP, "PARITY"}, { SR_RST, "RST" }, { SR_BSY, "BSY" }, + { SR_REQ, "REQ" }, { SR_MSG, "MSG" }, { SR_CD, "CD" }, { SR_IO, "IO" }, + { SR_SEL, "SEL" }, {0, NULL}}, +basrs[] = {{BASR_ATN, "ATN"}, {BASR_ACK, "ACK"}, {0, NULL}}, +icrs[] = {{ICR_ASSERT_RST, "ASSERT RST"},{ICR_ASSERT_ACK, "ASSERT ACK"}, + {ICR_ASSERT_BSY, "ASSERT BSY"}, {ICR_ASSERT_SEL, "ASSERT SEL"}, + {ICR_ASSERT_ATN, "ASSERT ATN"}, {ICR_ASSERT_DATA, "ASSERT DATA"}, + {0, NULL}}, +mrs[] = {{MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"}, {MR_TARGET, "MODE TARGET"}, + {MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"}, {MR_ENABLE_PAR_INTR, + "MODE PARITY INTR"}, {MR_ENABLE_EOP_INTR,"MODE EOP INTR"}, + {MR_MONITOR_BSY, "MODE MONITOR BSY"}, + {MR_DMA_MODE, "MODE DMA"}, {MR_ARBITRATE, "MODE ARBITRATION"}, + {0, NULL}}; + +/* + * Function : void NCR5380_print(struct Scsi_Host *instance) + * + * Purpose : print the SCSI bus signals for debugging purposes + * + * Input : instance - which NCR5380 + */ + +static void NCR5380_print(struct Scsi_Host *instance) { + unsigned char status, data, basr, mr, icr, i; + unsigned long flags; + + save_flags(flags); + cli(); + data = NCR5380_read(CURRENT_SCSI_DATA_REG); + status = NCR5380_read(STATUS_REG); + mr = NCR5380_read(MODE_REG); + icr = NCR5380_read(INITIATOR_COMMAND_REG); + basr = NCR5380_read(BUS_AND_STATUS_REG); + restore_flags(flags); + printk("STATUS_REG: %02x ", status); + for (i = 0; signals[i].mask ; ++i) + if (status & signals[i].mask) + printk(",%s", signals[i].name); + printk("\nBASR: %02x ", basr); + for (i = 0; basrs[i].mask ; ++i) + if (basr & basrs[i].mask) + printk(",%s", basrs[i].name); + printk("\nICR: %02x ", icr); + for (i = 0; icrs[i].mask; ++i) + if (icr & icrs[i].mask) + printk(",%s", icrs[i].name); + printk("\nMODE: %02x ", mr); + for (i = 0; mrs[i].mask; ++i) + if (mr & mrs[i].mask) + printk(",%s", mrs[i].name); + printk("\n"); +} + +static struct { + unsigned char value; + const char *name; +} phases[] = { + {PHASE_DATAOUT, "DATAOUT"}, {PHASE_DATAIN, "DATAIN"}, {PHASE_CMDOUT, "CMDOUT"}, + {PHASE_STATIN, "STATIN"}, {PHASE_MSGOUT, "MSGOUT"}, {PHASE_MSGIN, "MSGIN"}, + {PHASE_UNKNOWN, "UNKNOWN"}}; + +/* + * Function : void NCR5380_print_phase(struct Scsi_Host *instance) + * + * Purpose : print the current SCSI phase for debugging purposes + * + * Input : instance - which NCR5380 + */ + +static void NCR5380_print_phase(struct Scsi_Host *instance) +{ + unsigned char status; + int i; + + status = NCR5380_read(STATUS_REG); + if (!(status & SR_REQ)) + printk("scsi%d: REQ not asserted, phase unknown.\n", HOSTNO); + else { + for (i = 0; (phases[i].value != PHASE_UNKNOWN) && + (phases[i].value != (status & PHASE_MASK)); ++i); + printk("scsi%d: phase %s\n", HOSTNO, phases[i].name); + } +} +#endif + +/* + * We need to have our coroutine active given these constraints : + * 1. The mutex flag, main_running, can only be set when the main + * routine can actually process data, otherwise SCSI commands + * will never get issued. + * + * 2. NCR5380_main() shouldn't be called before it has exited, because + * other drivers have had kernel stack overflows in similar + * situations. + * + * 3. We don't want to inline NCR5380_main() because of space concerns, + * even though it is only called in two places. + * + * So, the solution is to set the mutex in an inline wrapper for the + * main coroutine, and have the main coroutine exit with interrupts + * disabled after the final search through the queues so that no race + * conditions are possible. + */ + +static volatile int main_running = 0; + +/* + * Function : run_main(void) + * + * Purpose : insure that the coroutine is running and will process our + * request. main_running is checked/set here (in an inline function) + * rather than in NCR5380_main itself to reduce the chances of stack + * overflow. + * + */ + +static void NCR5380_main_a ( unsigned long flags ); + +static __inline__ void run_main(void) +{ + unsigned long flags; + + save_flags(flags); + cli(); + if (!main_running) { + main_running = 1; + NCR5380_main_a( flags ); + /* + * main_running is cleared in NCR5380_main once it can't do + * more work, and NCR5380_main exits with interrupts disabled. + */ + } + restore_flags(flags); +} + + +static void NCR5380_all_init (void) +{ + static int done = 0; + if (!done) { +#if (NDEBUG & NDEBUG_INIT) + printk("scsi : NCR5380_all_init()\n"); +#endif + done = 1; + } +} + + +/* + * Function : void NCR58380_print_options (struct Scsi_Host *instance) + * + * Purpose : called by probe code indicating the NCR5380 driver + * options that were selected. + * + * Inputs : instance, pointer to this instance. Unused. + */ + +static void NCR5380_print_options (struct Scsi_Host *instance) +{ + printk(" generic options" +#ifdef AUTOSENSE + " AUTOSENSE" +#endif +#ifdef REAL_DMA + " REAL DMA" +#endif +#ifdef PARITY + " PARITY" +#endif +#ifdef SUPPORT_TAGS + " SCSI-2 TAGGED QUEUING" +#endif + ); + printk(" generic release=%d", NCR5380_PUBLIC_RELEASE); +} + +/* + * Function : void NCR5380_print_status (struct Scsi_Host *instance) + * + * Purpose : print commands in the various queues, called from + * NCR5380_abort and NCR5380_debug to aid debugging. + * + * Inputs : instance, pointer to this instance. + */ + +static void NCR5380_print_status (struct Scsi_Host *instance) +{ + char pr_bfr[256]; + char *start; + int len; + + printk("NCR5380: coroutine is%s running.\n", + main_running ? "" : "n't"); + +#ifdef NDEBUG + NCR5380_print (instance); + NCR5380_print_phase (instance); +#endif + + len = NCR5380_proc_info(pr_bfr, &start, 0, sizeof(pr_bfr), HOSTNO, 0); + pr_bfr[len] = 0; + printk("\n%s\n", pr_bfr); +} + + +/******************************************/ +/* + * /proc/scsi/[dtc pas16 t128 generic]/[0-ASC_NUM_BOARD_SUPPORTED] + * + * *buffer: I/O buffer + * **start: if inout == FALSE pointer into buffer where user read should start + * offset: current offset + * length: length of buffer + * hostno: Scsi_Host host_no + * inout: TRUE - user is writing; FALSE - user is reading + * + * Return the number of bytes read from or written +*/ + +#undef SPRINTF +#define SPRINTF(args...) do { if(pos < buffer + length) pos += sprintf(pos, ## args); } while(0) +static +char *lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length); +static +char *lprint_command (unsigned char *cmd, char *pos, char *buffer, int len); +static +char *lprint_opcode(int opcode, char *pos, char *buffer, int length); + +#ifndef NCR5380_proc_info +static +#endif +int NCR5380_proc_info (char *buffer, char **start, off_t offset, + int length, int hostno, int inout) +{ + char *pos = buffer; + struct Scsi_Host *instance; + struct NCR5380_hostdata *hostdata; + Scsi_Cmnd *ptr; + unsigned long flags; + + for (instance = first_instance; instance && HOSTNO != hostno; + instance = instance->next) + ; + if (!instance) + return(-ESRCH); + hostdata = (struct NCR5380_hostdata *)instance->hostdata; + + if (inout) { /* Has data been written to the file ? */ + return(-ENOSYS); /* Currently this is a no-op */ + } + SPRINTF("NCR5380 core release=%d.\n", NCR5380_PUBLIC_RELEASE); + save_flags(flags); + cli(); + SPRINTF("NCR5380: coroutine is%s running.\n", main_running ? "" : "n't"); + if (!hostdata->connected) + SPRINTF("scsi%d: no currently connected command\n", HOSTNO); + else + pos = lprint_Scsi_Cmnd ((Scsi_Cmnd *) hostdata->connected, + pos, buffer, length); + SPRINTF("scsi%d: issue_queue\n", HOSTNO); + for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr; ptr = NEXT(ptr)) + pos = lprint_Scsi_Cmnd (ptr, pos, buffer, length); + + SPRINTF("scsi%d: disconnected_queue\n", HOSTNO); + for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr; + ptr = NEXT(ptr)) + pos = lprint_Scsi_Cmnd (ptr, pos, buffer, length); + + restore_flags(flags); + *start = buffer; + if (pos - buffer < offset) + return 0; + else if (pos - buffer - offset < length) + return pos - buffer - offset; + return length; +} + +static char * +lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length) +{ + SPRINTF("scsi%d: destination target %d, lun %d\n", + H_NO(cmd), cmd->target, cmd->lun); + SPRINTF(" command = "); + pos = lprint_command (cmd->cmnd, pos, buffer, length); + return (pos); +} + +static char * +lprint_command (unsigned char *command, char *pos, char *buffer, int length) +{ + int i, s; + pos = lprint_opcode(command[0], pos, buffer, length); + for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i) + SPRINTF("%02x ", command[i]); + SPRINTF("\n"); + return(pos); +} + +static +char *lprint_opcode(int opcode, char *pos, char *buffer, int length) +{ + SPRINTF("%2d (0x%02x)", opcode, opcode); + return(pos); +} + + +/* + * Function : void NCR5380_init (struct Scsi_Host *instance) + * + * Purpose : initializes *instance and corresponding 5380 chip. + * + * Inputs : instance - instantiation of the 5380 driver. + * + * Notes : I assume that the host, hostno, and id bits have been + * set correctly. I don't care about the irq and other fields. + * + */ + +static void NCR5380_init (struct Scsi_Host *instance, int flags) +{ + int i; + SETUP_HOSTDATA(instance); + + NCR5380_all_init(); + + hostdata->aborted = 0; + hostdata->id_mask = 1 << instance->this_id; + hostdata->id_higher_mask = 0; + for (i = hostdata->id_mask; i <= 0x80; i <<= 1) + if (i > hostdata->id_mask) + hostdata->id_higher_mask |= i; + for (i = 0; i < 8; ++i) + hostdata->busy[i] = 0; +#ifdef SUPPORT_TAGS + init_tags(); +#endif +#if defined (REAL_DMA) + hostdata->dma_len = 0; +#endif + hostdata->targets_present = 0; + hostdata->connected = NULL; + hostdata->issue_queue = NULL; + hostdata->disconnected_queue = NULL; + hostdata->flags = FLAG_CHECK_LAST_BYTE_SENT; + + if (!the_template) { + the_template = instance->hostt; + first_instance = instance; + } + + +#ifndef AUTOSENSE + if ((instance->cmd_per_lun > 1) || instance->can_queue > 1)) + printk("scsi%d: WARNING : support for multiple outstanding commands enabled\n" + " without AUTOSENSE option, contingent allegiance conditions may\n" + " be incorrectly cleared.\n", HOSTNO); +#endif /* def AUTOSENSE */ + + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + NCR5380_write(MODE_REG, MR_BASE); + NCR5380_write(TARGET_COMMAND_REG, 0); + NCR5380_write(SELECT_ENABLE_REG, 0); +} + +/* + * Function : int NCR5380_queue_command (Scsi_Cmnd *cmd, + * void (*done)(Scsi_Cmnd *)) + * + * Purpose : enqueues a SCSI command + * + * Inputs : cmd - SCSI command, done - function called on completion, with + * a pointer to the command descriptor. + * + * Returns : 0 + * + * Side effects : + * cmd is added to the per instance issue_queue, with minor + * twiddling done to the host specific fields of cmd. If the + * main coroutine is not running, it is restarted. + * + */ + +/* Only make static if a wrapper function is used */ +#ifndef NCR5380_queue_command +static +#endif +int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) +{ + SETUP_HOSTDATA(cmd->host); + Scsi_Cmnd *tmp; + int oldto; + unsigned long flags; + extern int scsi_update_timeout(Scsi_Cmnd * SCset, int timeout); + +#if (NDEBUG & NDEBUG_NO_WRITE) + switch (cmd->cmnd[0]) { + case WRITE_6: + case WRITE_10: + printk("scsi%d: WRITE attempted with NO_WRITE debugging flag set\n", + H_NO(cmd)); + cmd->result = (DID_ERROR << 16); + done(cmd); + return 0; + } +#endif /* (NDEBUG & NDEBUG_NO_WRITE) */ + + +#ifdef NCR5380_STATS +# if 0 + if (!hostdata->connected && !hostdata->issue_queue && + !hostdata->disconnected_queue) { + hostdata->timebase = jiffies; + } +# endif +# ifdef NCR5380_STAT_LIMIT + if (cmd->request_bufflen > NCR5380_STAT_LIMIT) +# endif + switch (cmd->cmnd[0]) + { + case WRITE: + case WRITE_6: + case WRITE_10: + hostdata->time_write[cmd->target] -= (jiffies - hostdata->timebase); + hostdata->bytes_write[cmd->target] += cmd->request_bufflen; + hostdata->pendingw++; + break; + case READ: + case READ_6: + case READ_10: + hostdata->time_read[cmd->target] -= (jiffies - hostdata->timebase); + hostdata->bytes_read[cmd->target] += cmd->request_bufflen; + hostdata->pendingr++; + break; + } +#endif + + /* + * We use the host_scribble field as a pointer to the next command + * in a queue + */ + + NEXT(cmd) = NULL; + cmd->scsi_done = done; + + cmd->result = 0; + + + /* + * Insert the cmd into the issue queue. Note that REQUEST SENSE + * commands are added to the head of the queue since any command will + * clear the contingent allegiance condition that exists and the + * sense data is only guaranteed to be valid while the condition exists. + */ + + save_flags(flags); + cli(); + /* ++guenther: now that the issue queue is being set up, we can lock ST-DMA. + * Otherwise a running NCR5380_main may steal the lock. + * Lock before actually inserting due to fairness reasons explained in + * atari_scsi.c. If we insert first, then it's impossible for this driver + * to release the lock. + * Stop timer for this command while waiting for the lock, or timeouts + * may happen (and they really do), and it's no good if the command doesn't + * appear in any of the queues. + * ++roman: Just disabling the NCR interrupt isn't sufficient here, + * because also a timer int can trigger an abort or reset, which would + * alter queues and touch the lock. + */ + if (!IS_A_TT()) { + oldto = scsi_update_timeout(cmd, 0); + falcon_get_lock(); + scsi_update_timeout(cmd, oldto); + } + if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) { + LIST(cmd, hostdata->issue_queue); + NEXT(cmd) = hostdata->issue_queue; + hostdata->issue_queue = cmd; + } else { + for (tmp = (Scsi_Cmnd *)hostdata->issue_queue; + NEXT(tmp); tmp = NEXT(tmp)) + ; + LIST(cmd, tmp); + NEXT(tmp) = cmd; + } + restore_flags(flags); + +#if (NDEBUG & NDEBUG_QUEUES) + printk("scsi%d: command added to %s of queue\n", H_NO(cmd), + (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail"); +#endif + +/* Run the coroutine if it isn't already running. */ + run_main(); + return 0; +} + +/* + * Function : NCR5380_main (void) + * + * Purpose : NCR5380_main is a coroutine that runs as long as more work can + * be done on the NCR5380 host adapters in a system. Both + * NCR5380_queue_command() and NCR5380_intr() will try to start it + * in case it is not running. + * + * NOTE : NCR5380_main exits with interrupts *disabled*, the caller should + * reenable them. This prevents reentrancy and kernel stack overflow. + */ + +static inline void NCR5380_main () {} + +static void NCR5380_main_a ( unsigned long flags ) +{ + Scsi_Cmnd *tmp, *prev; + struct Scsi_Host *instance = first_instance; + struct NCR5380_hostdata *hostdata = HOSTDATA(instance); + int done; + + /* + * We run (with interrupts disabled) until we're sure that none of + * the host adapters have anything that can be done, at which point + * we set main_running to 0 and exit. + * + * Interrupts are enabled before doing various other internal + * instructions, after we've decided that we need to run through + * the loop again. + * + * this should prevent any race conditions. + * + * ++roman: Just disabling the NCR interrupt isn't sufficient here, + * because also a timer int can trigger an abort or reset, which can + * alter queues and touch the Falcon lock. + */ + + do { + cli(); /* Freeze request queues */ + done = 1; + + if (!hostdata->connected) { +#if (NDEBUG & NDEBUG_MAIN) + printk("scsi%d: not connected\n", HOSTNO); +#endif + /* + * Search through the issue_queue for a command destined + * for a target that's not busy. + */ +#if (NDEBUG & NDEBUG_LISTS) + for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, prev = NULL; + tmp && (tmp != prev); prev = tmp, tmp = NEXT(tmp)) + ; + /*printk("%p ", tmp);*/ + if ((tmp == prev) && tmp) printk(" LOOP\n");/* else printk("\n");*/ +#endif + for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, + prev = NULL; tmp; prev = tmp, tmp = NEXT(tmp) ) { + +#if (NDEBUG & NDEBUG_LISTS) + if (prev != tmp) + printk("MAIN tmp=%p target=%d busy=%d lun=%d\n", + tmp, tmp->target, hostdata->busy[tmp->target], + tmp->lun); +#endif + /* When we find one, remove it from the issue queue. */ + /* ++guenther: possible race with Falcon locking */ + if ( +#ifdef SUPPORT_TAGS + !is_lun_busy( tmp, tmp->cmnd[0] != REQUEST_SENSE) +#else + !(hostdata->busy[tmp->target] & (1 << tmp->lun)) +#endif + ) { + cli(); /* ++guenther: just to be sure, this must be atomic */ + if (prev) { + REMOVE(prev, NEXT(prev), tmp, NEXT(tmp)); + NEXT(prev) = NEXT(tmp); + } else { + REMOVE(-1, hostdata->issue_queue, tmp, NEXT(tmp)); + hostdata->issue_queue = NEXT(tmp); + } + NEXT(tmp) = NULL; + falcon_dont_release++; + + /* reenable interrupts after finding one */ + restore_flags(flags); + + /* + * Attempt to establish an I_T_L nexus here. + * On success, instance->hostdata->connected is set. + * On failure, we must add the command back to the + * issue queue so we can keep trying. + */ +#if (NDEBUG & (NDEBUG_MAIN | NDEBUG_QUEUES)) + printk("scsi%d: main(): command for target %d lun %d " + "removed from issue_queue\n", + HOSTNO, tmp->target, tmp->lun); +#endif + /* + * REQUEST SENSE commands are issued without tagged + * queueing, even on SCSI-II devices because the + * contingent allegiance condition exists for the + * entire unit. + */ + /* ++roman: ...and the standard also requires that + * REQUEST SENSE command are untagged. + */ + +#ifdef SUPPORT_TAGS + cmd_get_tag( tmp, tmp->cmnd[0] != REQUEST_SENSE ); +#endif + if (!NCR5380_select(instance, tmp, + (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE : + TAG_NEXT)) { + falcon_dont_release--; + /* release if target did not response! */ + falcon_release_lock_if_possible( hostdata ); + break; + } else { + cli(); + LIST(tmp, hostdata->issue_queue); + NEXT(tmp) = hostdata->issue_queue; + hostdata->issue_queue = tmp; +#ifdef SUPPORT_TAGS + cmd_free_tag( tmp ); +#endif + falcon_dont_release--; + restore_flags(flags); +#if (NDEBUG & (NDEBUG_MAIN | NDEBUG_QUEUES)) + printk("scsi%d: main(): select() failed, " + "returned to issue_queue\n", HOSTNO); +#endif + if (hostdata->connected) + break; + } + } /* if target/lun/target queue is not busy */ + } /* for issue_queue */ + } /* if (!hostdata->connected) */ + + if (hostdata->connected +#ifdef REAL_DMA + && !hostdata->dma_len +#endif + ) { + restore_flags(flags); +#if (NDEBUG & NDEBUG_MAIN) + printk("scsi%d: main() : performing information transfer\n", + HOSTNO); +#endif + NCR5380_information_transfer(instance); +#if (NDEBUG & NDEBUG_MAIN) + printk("scsi%d: main() : done set false\n", HOSTNO); +#endif + done = 0; + } else { + cli(); /* ++guenther: be sure to protect main_running */ + break; + } + } while (!done); + main_running = 0; +} + + +#ifdef REAL_DMA +/* + * Function : void NCR5380_dma_complete (struct Scsi_Host *instance) + * + * Purpose : Called by interrupt handler when DMA finishes or a phase + * mismatch occurs (which would finish the DMA transfer). + * + * Inputs : instance - this instance of the NCR5380. + * + */ + +static void NCR5380_dma_complete( struct Scsi_Host *instance ) +{ + SETUP_HOSTDATA(instance); + int transfered, saved_data = 0, overrun = 0, cnt, toPIO; + unsigned char **data, p; + volatile int *count; + + if (!hostdata->connected) { + printk("scsi%d: received end of DMA interrupt with no connected cmd\n", + HOSTNO); + return; + } + + if (atari_read_overruns) { + p = hostdata->connected->SCp.phase; + if (p & SR_IO) { + udelay(10); + if ((((NCR5380_read(BUS_AND_STATUS_REG)) & + (BASR_PHASE_MATCH|BASR_ACK)) == + (BASR_PHASE_MATCH|BASR_ACK))) { + saved_data = NCR5380_read(INPUT_DATA_REG); + overrun = 1; +#if (NDEBUG & NDEBUG_DMA) + printk( "scsi%d: read overrun handled\n", HOSTNO ); +#endif + } + } + } + +#if (NDEBUG & NDEBUG_DMA) + printk("scsi%d: real DMA transfer complete, basr 0x%X, sr 0x%X\n", + HOSTNO, NCR5380_read(BUS_AND_STATUS_REG), + NCR5380_read(STATUS_REG)); +#endif + + (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); + NCR5380_write(MODE_REG, MR_BASE); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + + transfered = hostdata->dma_len - NCR5380_dma_residual(instance); + hostdata->dma_len = 0; + + data = (unsigned char **) &(hostdata->connected->SCp.ptr); + count = &(hostdata->connected->SCp.this_residual); + *data += transfered; + *count -= transfered; + + if (atari_read_overruns) { + if ((NCR5380_read(STATUS_REG) & PHASE_MASK) == p && (p & SR_IO)) { + cnt = toPIO = atari_read_overruns; + if (overrun) { +#if (NDEBUG & NDEBUG_DMA) + printk("Got an input overrun, using saved byte\n"); +#endif + *(*data)++ = saved_data; + (*count)--; + cnt--; + toPIO--; + } +#if (NDEBUG & NDEBUG_DMA) + printk( "Doing %d-byte PIO to 0x%08lx\n", cnt, (long)*data ); +#endif + + NCR5380_transfer_pio(instance, &p, &cnt, data); + *count -= toPIO - cnt; + } + } +} +#endif /* REAL_DMA */ + + +/* + * Function : void NCR5380_intr (int irq) + * + * Purpose : handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses + * from the disconnected queue, and restarting NCR5380_main() + * as required. + * + * Inputs : int irq, irq that caused this interrupt. + * + */ + +static void NCR5380_intr (int irq, void *dev_id, struct pt_regs *regs) +{ + struct Scsi_Host *instance = first_instance; + int done = 1; + unsigned char basr; + +#if (NDEBUG & NDEBUG_INTR) + printk("scsi%d: NCR5380 irq triggered\n", HOSTNO); +#endif + + /* Look for pending interrupts */ + basr = NCR5380_read(BUS_AND_STATUS_REG); +#if (NDEBUG & NDEBUG_INTR) + printk( "scsi%d: BASR=%02x\n", HOSTNO, basr ); +#endif + /* dispatch to appropriate routine if found and done=0 */ + if (basr & BASR_IRQ) { +#if (NDEBUG & NDEBUG_INTR) + NCR5380_print(instance); +#endif + if ((NCR5380_read(STATUS_REG) & (SR_SEL|SR_IO)) == (SR_SEL|SR_IO)) { + done = 0; + ENABLE_IRQ(); +#if (NDEBUG & NDEBUG_INTR) + printk("scsi%d: SEL interrupt\n", HOSTNO); +#endif + NCR5380_reselect(instance); + (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); + } + else if (basr & BASR_PARITY_ERROR) { +#if (NDEBUG & NDEBUG_INTR) + printk("scsi%d: PARITY interrupt\n", HOSTNO); +#endif + (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); + } + else if ((NCR5380_read(STATUS_REG) & SR_RST) == SR_RST) { +#if (NDEBUG & NDEBUG_INTR) + printk("scsi%d: RESET interrupt\n", HOSTNO); +#endif + (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG); + } + else { + /* + * The rest of the interrupt conditions can occur only during a + * DMA transfer + */ + +#if defined(REAL_DMA) + /* + * We should only get PHASE MISMATCH and EOP interrupts if we have + * DMA enabled, so do a sanity check based on the current setting + * of the MODE register. + */ + + if ((NCR5380_read(MODE_REG) & MR_DMA_MODE) && + ((basr & BASR_END_DMA_TRANSFER) || + !(basr & BASR_PHASE_MATCH))) { + +#if (NDEBUG & NDEBUG_INTR) + printk("scsi%d: PHASE MISM or EOP interrupt\n", HOSTNO); +#endif + NCR5380_dma_complete( instance ); + done = 0; + ENABLE_IRQ(); + } else +#endif /* REAL_DMA */ + { +#if 1 || (NDEBUG & NDEBUG_INTR) +/* MS: Ignore unknown phase mismatch interrupts (caused by EOP interrupt) */ + if (basr & BASR_PHASE_MATCH) + printk("scsi%d: unknown interrupt, " + "BASR 0x%x, MR 0x%x, SR 0x%x\n", + HOSTNO, basr, NCR5380_read(MODE_REG), + NCR5380_read(STATUS_REG)); +#endif + (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); + } + } /* if !(SELECTION || PARITY) */ + } /* BASR & IRQ */ + else { +#if 1 || (NDEBUG & NDEBUG_INTR) + printk("scsi%d: interrupt without IRQ bit set in BASR, " + "BASR 0x%X, MR 0x%X, SR 0x%x\n", HOSTNO, basr, + NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG)); +#endif + (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); + } + + if (!done) { +#if (NDEBUG & NDEBUG_INTR) + printk("scsi%d: in int routine, calling main\n", HOSTNO ); +#endif + run_main(); + } +} + +#ifdef NCR5380_STATS +static void collect_stats(struct NCR5380_hostdata* hostdata, Scsi_Cmnd* cmd) +{ +# ifdef NCR5380_STAT_LIMIT + if (cmd->request_bufflen > NCR5380_STAT_LIMIT) +# endif + switch (cmd->cmnd[0]) + { + case WRITE: + case WRITE_6: + case WRITE_10: + hostdata->time_write[cmd->target] += (jiffies - hostdata->timebase); + /*hostdata->bytes_write[cmd->target] += cmd->request_bufflen;*/ + hostdata->pendingw--; + break; + case READ: + case READ_6: + case READ_10: + hostdata->time_read[cmd->target] += (jiffies - hostdata->timebase); + /*hostdata->bytes_read[cmd->target] += cmd->request_bufflen;*/ + hostdata->pendingr--; + break; + } +} +#endif + +/* + * Function : int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, + * int tag); + * + * Purpose : establishes I_T_L or I_T_L_Q nexus for new or existing command, + * including ARBITRATION, SELECTION, and initial message out for + * IDENTIFY and queue messages. + * + * Inputs : instance - instantiation of the 5380 driver on which this + * target lives, cmd - SCSI command to execute, tag - set to TAG_NEXT for + * new tag, TAG_NONE for untagged queueing, otherwise set to the tag for + * the command that is presently connected. + * + * Returns : -1 if selection could not execute for some reason, + * 0 if selection succeeded or failed because the target + * did not respond. + * + * Side effects : + * If bus busy, arbitration failed, etc, NCR5380_select() will exit + * with registers as they should have been on entry - ie + * SELECT_ENABLE will be set appropriately, the NCR5380 + * will cease to drive any SCSI bus signals. + * + * If successful : I_T_L or I_T_L_Q nexus will be established, + * instance->connected will be set to cmd. + * SELECT interrupt will be disabled. + * + * If failed (no target) : cmd->scsi_done() will be called, and the + * cmd->result host byte set to DID_BAD_TARGET. + */ + +static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag) +{ + SETUP_HOSTDATA(instance); + unsigned char tmp[3], phase; + unsigned char *data; + int len; + unsigned long timeout; + unsigned long flags; + + hostdata->restart_select = 0; +#if defined (NDEBUG) && (NDEBUG & NDEBUG_ARBITRATION) + NCR5380_print(instance); + printk("scsi%d: starting arbitration, id = %d\n", HOSTNO, + instance->this_id); +#endif + + /* + * Set the phase bits to 0, otherwise the NCR5380 won't drive the + * data bus during SELECTION. + */ + + save_flags(flags); + cli(); + if (hostdata->connected) { + restore_flags(flags); + return -1; + } + NCR5380_write(TARGET_COMMAND_REG, 0); + + + /* + * Start arbitration. + */ + + NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask); + NCR5380_write(MODE_REG, MR_ARBITRATE); + + restore_flags(flags); + + /* Wait for arbitration logic to complete */ +#if NCR_TIMEOUT + { + unsigned long timeout = jiffies + 2*NCR_TIMEOUT; + + while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS) + && jiffies < timeout && !hostdata->connected) + ; + if (jiffies >= timeout) + { + printk("scsi : arbitration timeout at %d\n", __LINE__); + NCR5380_write(MODE_REG, MR_BASE); + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + return -1; + } + } +#else /* NCR_TIMEOUT */ + while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS) + && !hostdata->connected); +#endif + +#if (NDEBUG & NDEBUG_ARBITRATION) + printk("scsi%d: arbitration complete\n", HOSTNO); +/* Avoid GCC 2.4.5 asm needs to many reloads error */ + __asm__("nop"); +#endif + + if (hostdata->connected) { + NCR5380_write(MODE_REG, MR_BASE); + return -1; + } + /* + * The arbitration delay is 2.2us, but this is a minimum and there is + * no maximum so we can safely sleep for ceil(2.2) usecs to accommodate + * the integral nature of udelay(). + * + */ + + udelay(3); + + /* Check for lost arbitration */ + if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) || + (NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) || + (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) || + hostdata->connected) { + NCR5380_write(MODE_REG, MR_BASE); +#if (NDEBUG & NDEBUG_ARBITRATION) + printk("scsi%d: lost arbitration, deasserting MR_ARBITRATE\n", HOSTNO); +#endif + return -1; + } + + /* after/during arbitration, BSY should be asserted. + IBM DPES-31080 Version S31Q works now */ + /* Tnx to Thomas_Roesch@m2.maus.de for finding this! (Roman) */ + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_SEL | + ICR_ASSERT_BSY ) ; + + if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) || + hostdata->connected) { + NCR5380_write(MODE_REG, MR_BASE); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); +#if (NDEBUG & NDEBUG_ARBITRATION) + printk("scsi%d: lost arbitration, deasserting ICR_ASSERT_SEL\n", HOSTNO); +#endif + return -1; + } + + /* + * Again, bus clear + bus settle time is 1.2us, however, this is + * a minimum so we'll udelay ceil(1.2) + */ + +#ifdef CONFIG_ATARI_SCSI_TOSHIBA_DELAY + /* ++roman: But some targets (see above :-) seem to need a bit more... */ + udelay(15); +#else + udelay(2); +#endif + + if (hostdata->connected) { + NCR5380_write(MODE_REG, MR_BASE); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + return -1; + } + +#if (NDEBUG & NDEBUG_ARBITRATION) + printk("scsi%d: won arbitration\n", HOSTNO); +#endif + + + /* + * Now that we have won arbitration, start Selection process, asserting + * the host and target ID's on the SCSI bus. + */ + + NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << cmd->target))); + + /* + * Raise ATN while SEL is true before BSY goes false from arbitration, + * since this is the only way to guarantee that we'll get a MESSAGE OUT + * phase immediately after selection. + */ + + NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_BSY | + ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL )); + NCR5380_write(MODE_REG, MR_BASE); + + /* + * Reselect interrupts must be turned off prior to the dropping of BSY, + * otherwise we will trigger an interrupt. + */ + + if (hostdata->connected) { + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + return -1; + } + + NCR5380_write(SELECT_ENABLE_REG, 0); + + /* + * The initiator shall then wait at least two deskew delays and release + * the BSY signal. + */ + udelay(1); /* wingel -- wait two bus deskew delay >2*45ns */ + + /* Reset BSY */ + NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_DATA | + ICR_ASSERT_ATN | ICR_ASSERT_SEL)); + + /* + * Something weird happens when we cease to drive BSY - looks + * like the board/chip is letting us do another read before the + * appropriate propagation delay has expired, and we're confusing + * a BSY signal from ourselves as the target's response to SELECTION. + * + * A small delay (the 'C++' frontend breaks the pipeline with an + * unnecessary jump, making it work on my 386-33/Trantor T128, the + * tighter 'C' code breaks and requires this) solves the problem - + * the 1 us delay is arbitrary, and only used because this delay will + * be the same on other platforms and since it works here, it should + * work there. + * + * wingel suggests that this could be due to failing to wait + * one deskew delay. + */ + + udelay(1); + +#if (NDEBUG & NDEBUG_SELECTION) + printk("scsi%d: selecting target %d\n", HOSTNO, cmd->target); +#endif + + /* + * The SCSI specification calls for a 250 ms timeout for the actual + * selection. + */ + + timeout = jiffies + 25; + + /* + * XXX very interesting - we're seeing a bounce where the BSY we + * asserted is being reflected / still asserted (propagation delay?) + * and it's detecting as true. Sigh. + */ + +#if 0 + /* ++roman: If a target conformed to the SCSI standard, it wouldn't assert + * IO while SEL is true. But again, there are some disks out the in the + * world that do that nevertheless. (Somebody claimed that this announces + * reselection capability of the target.) So we better skip that test and + * only wait for BSY... (Famous german words: Der Klügere gibt nach :-) + */ + + while ((jiffies < timeout) && !(NCR5380_read(STATUS_REG) & + (SR_BSY | SR_IO))); + + if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == + (SR_SEL | SR_IO)) { + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + NCR5380_reselect(instance); + printk ("scsi%d: reselection after won arbitration?\n", HOSTNO); + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + return -1; + } +#else + while ((jiffies < timeout) && !(NCR5380_read(STATUS_REG) & SR_BSY)); +#endif + + /* + * No less than two deskew delays after the initiator detects the + * BSY signal is true, it shall release the SEL signal and may + * change the DATA BUS. -wingel + */ + + udelay(1); + + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); + + if (!(NCR5380_read(STATUS_REG) & SR_BSY)) { + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + if (hostdata->targets_present & (1 << cmd->target)) { + printk("scsi%d: weirdness\n", HOSTNO); + if (hostdata->restart_select) + printk("\trestart select\n"); +#ifdef NDEBUG + NCR5380_print (instance); +#endif + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + return -1; + } + cmd->result = DID_BAD_TARGET << 16; +#ifdef NCR5380_STATS + collect_stats(hostdata, cmd); +#endif +#ifdef SUPPORT_TAGS + cmd_free_tag( cmd ); +#endif + cmd->scsi_done(cmd); + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); +#if (NDEBUG & NDEBUG_SELECTION) + printk("scsi%d: target did not respond within 250ms\n", HOSTNO); +#endif + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + return 0; + } + + hostdata->targets_present |= (1 << cmd->target); + + /* + * Since we followed the SCSI spec, and raised ATN while SEL + * was true but before BSY was false during selection, the information + * transfer phase should be a MESSAGE OUT phase so that we can send the + * IDENTIFY message. + * + * If SCSI-II tagged queuing is enabled, we also send a SIMPLE_QUEUE_TAG + * message (2 bytes) with a tag ID that we increment with every command + * until it wraps back to 0. + * + * XXX - it turns out that there are some broken SCSI-II devices, + * which claim to support tagged queuing but fail when more than + * some number of commands are issued at once. + */ + + /* Wait for start of REQ/ACK handshake */ + while (!(NCR5380_read(STATUS_REG) & SR_REQ)); + +#if (NDEBUG & NDEBUG_SELECTION) + printk("scsi%d: target %d selected, going into MESSAGE OUT phase.\n", + HOSTNO, cmd->target); +#endif + tmp[0] = IDENTIFY(1, cmd->lun); + +#ifdef SUPPORT_TAGS + if (cmd->tag != TAG_NONE) { + tmp[1] = hostdata->last_message = SIMPLE_QUEUE_TAG; + tmp[2] = cmd->tag; + len = 3; + } else + len = 1; +#else + len = 1; + cmd->tag=0; +#endif /* SUPPORT_TAGS */ + + /* Send message(s) */ + data = tmp; + phase = PHASE_MSGOUT; + NCR5380_transfer_pio(instance, &phase, &len, &data); +#if (NDEBUG & NDEBUG_SELECTION) + printk("scsi%d: nexus established.\n", HOSTNO); +#endif + /* XXX need to handle errors here */ + hostdata->connected = cmd; +#ifndef SUPPORT_TAGS + hostdata->busy[cmd->target] |= (1 << cmd->lun); +#endif + + initialize_SCp(cmd); + + + return 0; +} + +/* + * Function : int NCR5380_transfer_pio (struct Scsi_Host *instance, + * unsigned char *phase, int *count, unsigned char **data) + * + * Purpose : transfers data in given phase using polled I/O + * + * Inputs : instance - instance of driver, *phase - pointer to + * what phase is expected, *count - pointer to number of + * bytes to transfer, **data - pointer to data pointer. + * + * Returns : -1 when different phase is entered without transferring + * maximum number of bytes, 0 if all bytes are transfered or exit + * is in same phase. + * + * Also, *phase, *count, *data are modified in place. + * + * XXX Note : handling for bus free may be useful. + */ + +/* + * Note : this code is not as quick as it could be, however it + * IS 100% reliable, and for the actual data transfer where speed + * counts, we will always do a pseudo DMA or DMA transfer. + */ + +static int NCR5380_transfer_pio( struct Scsi_Host *instance, + unsigned char *phase, int *count, + unsigned char **data) +{ + register unsigned char p = *phase, tmp; + register int c = *count; + register unsigned char *d = *data; + + /* + * The NCR5380 chip will only drive the SCSI bus when the + * phase specified in the appropriate bits of the TARGET COMMAND + * REGISTER match the STATUS REGISTER + */ + + NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p)); + + do { + /* + * Wait for assertion of REQ, after which the phase bits will be + * valid + */ + while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ)); + +#if (NDEBUG & NDEBUG_HANDSHAKE) + printk("scsi%d: REQ detected\n", HOSTNO); +#endif + + /* Check for phase mismatch */ + if ((tmp & PHASE_MASK) != p) { +#if (NDEBUG & NDEBUG_PIO) + printk("scsi%d: phase mismatch\n", HOSTNO); + NCR5380_print_phase(instance); +#endif + break; + } + + /* Do actual transfer from SCSI bus to / from memory */ + if (!(p & SR_IO)) + NCR5380_write(OUTPUT_DATA_REG, *d); + else + *d = NCR5380_read(CURRENT_SCSI_DATA_REG); + + ++d; + + /* + * The SCSI standard suggests that in MSGOUT phase, the initiator + * should drop ATN on the last byte of the message phase + * after REQ has been asserted for the handshake but before + * the initiator raises ACK. + */ + + if (!(p & SR_IO)) { + if (!((p & SR_MSG) && c > 1)) { + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | + ICR_ASSERT_DATA); +#if (NDEBUG & NDEBUG_PIO) + NCR5380_print(instance); +#endif + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | + ICR_ASSERT_DATA | ICR_ASSERT_ACK); + } else { + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | + ICR_ASSERT_DATA | ICR_ASSERT_ATN); +#if (NDEBUG & NDEBUG_PIO) + NCR5380_print(instance); +#endif + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | + ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK); + } + } else { +#if (NDEBUG & NDEBUG_PIO) + NCR5380_print(instance); +#endif + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK); + } + + while (NCR5380_read(STATUS_REG) & SR_REQ); + +#if (NDEBUG & NDEBUG_HANDSHAKE) + printk("scsi%d: req false, handshake complete\n", HOSTNO); +#endif + +/* + * We have several special cases to consider during REQ/ACK handshaking : + * 1. We were in MSGOUT phase, and we are on the last byte of the + * message. ATN must be dropped as ACK is dropped. + * + * 2. We are in a MSGIN phase, and we are on the last byte of the + * message. We must exit with ACK asserted, so that the calling + * code may raise ATN before dropping ACK to reject the message. + * + * 3. ACK and ATN are clear and the target may proceed as normal. + */ + if (!(p == PHASE_MSGIN && c == 1)) { + if (p == PHASE_MSGOUT && c > 1) + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); + else + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + } + } while (--c); + +#if (NDEBUG & NDEBUG_PIO) + printk("scsi%d: residual %d\n", HOSTNO, c); +#endif + + *count = c; + *data = d; + tmp = NCR5380_read(STATUS_REG); + /* The phase read from the bus is valid if either REQ is (already) + * asserted or if ACK hasn't been released yet. The latter is the case if + * we're in MSGIN and all wanted bytes have been received. */ + if ((tmp & SR_REQ) || (p == PHASE_MSGIN && c == 0)) + *phase = tmp & PHASE_MASK; + else + *phase = PHASE_UNKNOWN; + + if (!c || (*phase == p)) + return 0; + else + return -1; +} + +/* + * Function : do_abort (Scsi_Host *host) + * + * Purpose : abort the currently established nexus. Should only be + * called from a routine which can drop into a + * + * Returns : 0 on success, -1 on failure. + */ + +static int do_abort (struct Scsi_Host *host) +{ + unsigned char tmp, *msgptr, phase; + int len; + + /* Request message out phase */ + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); + + /* + * Wait for the target to indicate a valid phase by asserting + * REQ. Once this happens, we'll have either a MSGOUT phase + * and can immediately send the ABORT message, or we'll have some + * other phase and will have to source/sink data. + * + * We really don't care what value was on the bus or what value + * the target see's, so we just handshake. + */ + + while (!(tmp = NCR5380_read(STATUS_REG)) & SR_REQ); + + NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp)); + + if ((tmp & PHASE_MASK) != PHASE_MSGOUT) { + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | + ICR_ASSERT_ACK); + while (NCR5380_read(STATUS_REG) & SR_REQ); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); + } + + tmp = ABORT; + msgptr = &tmp; + len = 1; + phase = PHASE_MSGOUT; + NCR5380_transfer_pio (host, &phase, &len, &msgptr); + + /* + * If we got here, and the command completed successfully, + * we're about to go into bus free state. + */ + + return len ? -1 : 0; +} + +#if defined(REAL_DMA) +/* + * Function : int NCR5380_transfer_dma (struct Scsi_Host *instance, + * unsigned char *phase, int *count, unsigned char **data) + * + * Purpose : transfers data in given phase using either real + * or pseudo DMA. + * + * Inputs : instance - instance of driver, *phase - pointer to + * what phase is expected, *count - pointer to number of + * bytes to transfer, **data - pointer to data pointer. + * + * Returns : -1 when different phase is entered without transferring + * maximum number of bytes, 0 if all bytes or transfered or exit + * is in same phase. + * + * Also, *phase, *count, *data are modified in place. + * + */ + + +static int NCR5380_transfer_dma( struct Scsi_Host *instance, + unsigned char *phase, int *count, + unsigned char **data) +{ + SETUP_HOSTDATA(instance); + register int c = *count; + register unsigned char p = *phase; + register unsigned char *d = *data; + unsigned char tmp; + unsigned long flags; + + if ((tmp = (NCR5380_read(STATUS_REG) & PHASE_MASK)) != p) { + *phase = tmp; + return -1; + } + + if (atari_read_overruns && (p & SR_IO)) { + c -= atari_read_overruns; + } + +#if (NDEBUG & NDEBUG_DMA) + printk("scsi%d: initializing DMA channel %d for %s, %d bytes %s %0x\n", + HOSTNO, instance->dma_channel, (p & SR_IO) ? "reading" : + "writing", c, (p & SR_IO) ? "to" : "from", (unsigned) d); +#endif + + NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p)); + +#ifdef REAL_DMA + NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_EOP_INTR | MR_MONITOR_BSY); +#endif /* def REAL_DMA */ + + if (IS_A_TT()) { + /* On the Medusa, it is a must to initialize the DMA before + * starting the NCR. This is also the cleaner way for the TT. + */ + save_flags(flags); + cli(); + hostdata->dma_len = (p & SR_IO) ? + NCR5380_dma_read_setup(instance, d, c) : + NCR5380_dma_write_setup(instance, d, c); + restore_flags(flags); + } + + if (p & SR_IO) + NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0); + else { + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA); + NCR5380_write(START_DMA_SEND_REG, 0); + } + + if (!IS_A_TT()) { + /* On the Falcon, the DMA setup must be done after the last */ + /* NCR access, else the DMA setup gets trashed! + */ + save_flags(flags); + cli(); + hostdata->dma_len = (p & SR_IO) ? + NCR5380_dma_read_setup(instance, d, c) : + NCR5380_dma_write_setup(instance, d, c); + restore_flags(flags); + } + return 0; +} +#endif /* defined(REAL_DMA) */ + +/* + * Function : NCR5380_information_transfer (struct Scsi_Host *instance) + * + * Purpose : run through the various SCSI phases and do as the target + * directs us to. Operates on the currently connected command, + * instance->connected. + * + * Inputs : instance, instance for which we are doing commands + * + * Side effects : SCSI things happen, the disconnected queue will be + * modified if a command disconnects, *instance->connected will + * change. + * + * XXX Note : we need to watch for bus free or a reset condition here + * to recover from an unexpected bus free condition. + */ + +static void NCR5380_information_transfer (struct Scsi_Host *instance) +{ + SETUP_HOSTDATA(instance); + unsigned long flags; + unsigned char msgout = NOP; + int sink = 0; + int len; +#if defined(REAL_DMA) + int transfersize; +#endif + unsigned char *data; + unsigned char phase, tmp, extended_msg[10], old_phase=0xff; + Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->connected; + + while (1) { + tmp = NCR5380_read(STATUS_REG); + /* We only have a valid SCSI phase when REQ is asserted */ + if (tmp & SR_REQ) { + phase = (tmp & PHASE_MASK); + if (phase != old_phase) { + old_phase = phase; +#if (NDEBUG & NDEBUG_INFORMATION) + NCR5380_print_phase(instance); +#endif + } + + if (sink && (phase != PHASE_MSGOUT)) { + NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp)); + + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | + ICR_ASSERT_ACK); + while (NCR5380_read(STATUS_REG) & SR_REQ); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | + ICR_ASSERT_ATN); + sink = 0; + continue; + } + + switch (phase) { + case PHASE_DATAOUT: +#if (NDEBUG & NDEBUG_NO_DATAOUT) + printk("scsi%d: NDEBUG_NO_DATAOUT set, attempted DATAOUT " + "aborted\n", HOSTNO); + sink = 1; + do_abort(instance); + cmd->result = DID_ERROR << 16; + cmd->done(cmd); + return; +#endif + case PHASE_DATAIN: + /* + * If there is no room left in the current buffer in the + * scatter-gather list, move onto the next one. + */ + + if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) { + ++cmd->SCp.buffer; + --cmd->SCp.buffers_residual; + cmd->SCp.this_residual = cmd->SCp.buffer->length; + cmd->SCp.ptr = cmd->SCp.buffer->address; + /* ++roman: Try to merge some scatter-buffers if + * they are at consecutive physical addresses. + */ + merge_consecutive_buffers( cmd ); +#if (NDEBUG & NDEBUG_INFORMATION) + printk("scsi%d: %d bytes and %d buffers left\n", + HOSTNO, cmd->SCp.this_residual, + cmd->SCp.buffers_residual); +#endif + } + + /* + * The preferred transfer method is going to be + * PSEUDO-DMA for systems that are strictly PIO, + * since we can let the hardware do the handshaking. + * + * For this to work, we need to know the transfersize + * ahead of time, since the pseudo-DMA code will sit + * in an unconditional loop. + */ + +/* ++roman: I suggest, this should be + * #if def(REAL_DMA) + * instead of leaving REAL_DMA out. + */ + +#if defined(REAL_DMA) + if (!cmd->device->borken && + (transfersize = NCR5380_dma_xfer_len(instance,cmd,phase)) > 31) { + len = transfersize; + cmd->SCp.phase = phase; + if (NCR5380_transfer_dma(instance, &phase, + &len, (unsigned char **) &cmd->SCp.ptr)) { + /* + * If the watchdog timer fires, all future + * accesses to this device will use the + * polled-IO. */ + printk("scsi%d: switching target %d lun %d to slow " + "handshake\n", HOSTNO, cmd->target, cmd->lun); + cmd->device->borken = 1; + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | + ICR_ASSERT_ATN); + sink = 1; + do_abort(instance); + cmd->result = DID_ERROR << 16; + cmd->done(cmd); + /* XXX - need to source or sink data here, as appropriate */ + } else { +#ifdef REAL_DMA + /* ++roman: When using real DMA, + * information_transfer() should return after + * starting DMA since it has nothing more to + * do. + */ + return; +#else + cmd->SCp.this_residual -= transfersize - len; +#endif + } + } else +#endif /* defined(REAL_DMA) */ + NCR5380_transfer_pio(instance, &phase, + (int *) &cmd->SCp.this_residual, (unsigned char **) + &cmd->SCp.ptr); + break; + case PHASE_MSGIN: + len = 1; + data = &tmp; + NCR5380_write(SELECT_ENABLE_REG, 0); /* disable reselects */ + NCR5380_transfer_pio(instance, &phase, &len, &data); + cmd->SCp.Message = tmp; + + switch (tmp) { + /* + * Linking lets us reduce the time required to get the + * next command out to the device, hopefully this will + * mean we don't waste another revolution due to the delays + * required by ARBITRATION and another SELECTION. + * + * In the current implementation proposal, low level drivers + * merely have to start the next command, pointed to by + * next_link, done() is called as with unlinked commands. + */ +#ifdef LINKED + case LINKED_CMD_COMPLETE: + case LINKED_FLG_CMD_COMPLETE: + /* Accept message by clearing ACK */ + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + +#if (NDEBUG & NDEBUG_LINKED) + printk("scsi%d: target %d lun %d linked command complete.\n", + HOSTNO, cmd->target, cmd->lun); +#endif + /* Enable reselect interupts */ + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + /* + * Sanity check : A linked command should only terminate + * with one of these messages if there are more linked + * commands available. + */ + + if (!cmd->next_link) { + printk("scsi%d: target %d lun %d linked command " + "complete, no next_link\n", + HOSTNO, cmd->target, cmd->lun); + sink = 1; + do_abort (instance); + return; + } + + initialize_SCp(cmd->next_link); + /* The next command is still part of this process; copy it + * and don't free it! */ + cmd->next_link->tag = cmd->tag; + cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); +#if (NDEBUG & NDEBUG_LINKED) + printk("scsi%d: target %d lun %d linked request done, " + "calling scsi_done().\n", + HOSTNO, cmd->target, cmd->lun); +#endif +#ifdef NCR5380_STATS + collect_stats(hostdata, cmd); +#endif + cmd->scsi_done(cmd); + cmd = hostdata->connected; + break; +#endif /* def LINKED */ + case ABORT: + case COMMAND_COMPLETE: + /* Accept message by clearing ACK */ + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + /* ++guenther: possible race with Falcon locking */ + falcon_dont_release++; + hostdata->connected = NULL; +#if (NDEBUG & NDEBUG_QUEUES) + printk("scsi%d: command for target %d, lun %d completed\n", + HOSTNO, cmd->target, cmd->lun); +#endif +#ifdef SUPPORT_TAGS + cmd_free_tag( cmd ); + if (cmd->SCp.Status == QUEUE_FULL) { + /* Turn a QUEUE FULL status into BUSY, I think the + * mid level cannot handle QUEUE FULL :-( (The + * command is retried after BUSY). Also update our + * queue size to the number of currently issued + * commands now. + */ + TAG_ALLOC *ta = &TagAlloc[cmd->target][cmd->lun]; +#if (NDEBUG & NDEBUG_TAGS) + printk( "scsi%d: target %d lun %d returned " + "QUEUE_FULL after %d commands\n", + HOSTNO, cmd->target, cmd->lun, + ta->nr_allocated ); +#endif + if (ta->queue_size > ta->nr_allocated) + ta->nr_allocated = ta->queue_size; + cmd->SCp.Status = BUSY; + } +#else + hostdata->busy[cmd->target] &= ~(1 << cmd->lun); +#endif + /* Enable reselect interupts */ + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + + /* + * I'm not sure what the correct thing to do here is : + * + * If the command that just executed is NOT a request + * sense, the obvious thing to do is to set the result + * code to the values of the stored parameters. + * + * If it was a REQUEST SENSE command, we need some way to + * differentiate between the failure code of the original + * and the failure code of the REQUEST sense - the obvious + * case is success, where we fall through and leave the + * result code unchanged. + * + * The non-obvious place is where the REQUEST SENSE failed + */ + + if (cmd->cmnd[0] != REQUEST_SENSE) + cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); + else if (cmd->SCp.Status != GOOD) + cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16); + +#ifdef AUTOSENSE + if ((cmd->cmnd[0] != REQUEST_SENSE) && + (cmd->SCp.Status == CHECK_CONDITION)) { +#if (NDEBUG & NDEBUG_AUTOSENSE) + printk("scsi%d: performing request sense\n", HOSTNO); +#endif + cmd->cmnd[0] = REQUEST_SENSE; + cmd->cmnd[1] &= 0xe0; + cmd->cmnd[2] = 0; + cmd->cmnd[3] = 0; + cmd->cmnd[4] = sizeof(cmd->sense_buffer); + cmd->cmnd[5] = 0; + + cmd->SCp.buffer = NULL; + cmd->SCp.buffers_residual = 0; + cmd->SCp.ptr = (char *) cmd->sense_buffer; + cmd->SCp.this_residual = sizeof(cmd->sense_buffer); + + save_flags(flags); + cli(); + LIST(cmd,hostdata->issue_queue); + NEXT(cmd) = hostdata->issue_queue; + hostdata->issue_queue = (Scsi_Cmnd *) cmd; + restore_flags(flags); +#if (NDEBUG & NDEBUG_QUEUES) + printk("scsi%d: REQUEST SENSE added to head of " + "issue queue\n", H_NO(cmd)); +#endif + } else +#endif /* def AUTOSENSE */ + { +#ifdef NCR5380_STATS + collect_stats(hostdata, cmd); +#endif + cmd->scsi_done(cmd); + } + + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + /* + * Restore phase bits to 0 so an interrupted selection, + * arbitration can resume. + */ + NCR5380_write(TARGET_COMMAND_REG, 0); + + while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected) + barrier(); + + falcon_dont_release--; + /* ++roman: For Falcon SCSI, release the lock on the + * ST-DMA here if no other commands are waiting on the + * disconnected queue. + */ + falcon_release_lock_if_possible( hostdata ); + return; + case MESSAGE_REJECT: + /* Accept message by clearing ACK */ + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + /* Enable reselect interupts */ + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + switch (hostdata->last_message) { + case HEAD_OF_QUEUE_TAG: + case ORDERED_QUEUE_TAG: + case SIMPLE_QUEUE_TAG: + /* The target obviously doesn't support tagged + * queuing, even though it announced this ability in + * its INQUIRY data ?!? (maybe only this LUN?) Ok, + * clear 'tagged_supported' and lock the LUN, since + * the command is treated as untagged furtheron. + */ + cmd->device->tagged_supported = 0; + hostdata->busy[cmd->target] |= (1 << cmd->lun); + cmd->tag = TAG_NONE; +#if (NDEBUG & NDEBUG_TAGS) + printk( "scsi%d: target %d lun %d rejected QUEUE_TAG " + "message; tagged queuing disabled\n", + HOSTNO, cmd->target, cmd->lun ); +#endif + break; + } + break; + case DISCONNECT: + /* Accept message by clearing ACK */ + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + save_flags(flags); + cli(); + cmd->device->disconnect = 1; + LIST(cmd,hostdata->disconnected_queue); + NEXT(cmd) = hostdata->disconnected_queue; + hostdata->connected = NULL; + hostdata->disconnected_queue = cmd; + restore_flags(flags); +#if (NDEBUG & NDEBUG_QUEUES) + printk("scsi%d: command for target %d lun %d was moved from connected to" + " the disconnected_queue\n", HOSTNO, + cmd->target, cmd->lun); +#endif + /* + * Restore phase bits to 0 so an interrupted selection, + * arbitration can resume. + */ + NCR5380_write(TARGET_COMMAND_REG, 0); + + /* Enable reselect interrupts */ + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + /* Wait for bus free to avoid nasty timeouts */ + while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected) + barrier(); + return; + /* + * The SCSI data pointer is *IMPLICITLY* saved on a disconnect + * operation, in violation of the SCSI spec so we can safely + * ignore SAVE/RESTORE pointers calls. + * + * Unfortunately, some disks violate the SCSI spec and + * don't issue the required SAVE_POINTERS message before + * disconnecting, and we have to break spec to remain + * compatible. + */ + case SAVE_POINTERS: + case RESTORE_POINTERS: + /* Accept message by clearing ACK */ + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + /* Enable reselect interupts */ + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + break; + case EXTENDED_MESSAGE: +/* + * Extended messages are sent in the following format : + * Byte + * 0 EXTENDED_MESSAGE == 1 + * 1 length (includes one byte for code, doesn't + * include first two bytes) + * 2 code + * 3..length+1 arguments + * + * Start the extended message buffer with the EXTENDED_MESSAGE + * byte, since print_msg() wants the whole thing. + */ + extended_msg[0] = EXTENDED_MESSAGE; + /* Accept first byte by clearing ACK */ + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + +#if (NDEBUG & NDEBUG_EXTENDED) + printk("scsi%d: receiving extended message\n", HOSTNO); +#endif + + len = 2; + data = extended_msg + 1; + phase = PHASE_MSGIN; + NCR5380_transfer_pio(instance, &phase, &len, &data); + +#if (NDEBUG & NDEBUG_EXTENDED) + printk("scsi%d: length=%d, code=0x%02x\n", HOSTNO, + (int) extended_msg[1], + (int) extended_msg[2]); +#endif + + if (!len && extended_msg[1] <= + (sizeof (extended_msg) - 1)) { + /* Accept third byte by clearing ACK */ + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + len = extended_msg[1] - 1; + data = extended_msg + 3; + phase = PHASE_MSGIN; + + NCR5380_transfer_pio(instance, &phase, &len, &data); + +#if (NDEBUG & NDEBUG_EXTENDED) + printk("scsi%d: message received, residual %d\n", + HOSTNO, len); +#endif + + switch (extended_msg[2]) { + case EXTENDED_SDTR: + case EXTENDED_WDTR: + case EXTENDED_MODIFY_DATA_POINTER: + case EXTENDED_EXTENDED_IDENTIFY: + tmp = 0; + } + } else if (len) { + printk("scsi%d: error receiving extended message\n", + HOSTNO); + tmp = 0; + } else { + printk("scsi%d: extended message code %02x length %d is too long\n", + HOSTNO, extended_msg[2], extended_msg[1]); + tmp = 0; + } + /* Fall through to reject message */ + + /* + * If we get something weird that we aren't expecting, + * reject it. + */ + default: + if (!tmp) { + printk("scsi%d: rejecting message ", HOSTNO); + print_msg (extended_msg); + printk("\n"); + } else if (tmp != EXTENDED_MESSAGE) + printk("scsi%d: rejecting unknown message %02x from target %d, lun %d\n", + HOSTNO, tmp, cmd->target, cmd->lun); + else + printk("scsi%d: rejecting unknown extended message " + "code %02x, length %d from target %d, lun %d\n", + HOSTNO, extended_msg[1], extended_msg[0], + cmd->target, cmd->lun); + + + msgout = MESSAGE_REJECT; + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | + ICR_ASSERT_ATN); + break; + } /* switch (tmp) */ + break; + case PHASE_MSGOUT: + len = 1; + data = &msgout; + hostdata->last_message = msgout; + NCR5380_transfer_pio(instance, &phase, &len, &data); + if (msgout == ABORT) { +#ifdef SUPPORT_TAGS + cmd_free_tag( cmd ); +#else + hostdata->busy[cmd->target] &= ~(1 << cmd->lun); +#endif + hostdata->connected = NULL; + cmd->result = DID_ERROR << 16; +#ifdef NCR5380_STATS + collect_stats(hostdata, cmd); +#endif + cmd->scsi_done(cmd); + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + falcon_release_lock_if_possible( hostdata ); + return; + } + msgout = NOP; + break; + case PHASE_CMDOUT: + len = cmd->cmd_len; + data = cmd->cmnd; + /* + * XXX for performance reasons, on machines with a + * PSEUDO-DMA architecture we should probably + * use the dma transfer function. + */ + NCR5380_transfer_pio(instance, &phase, &len, + &data); + break; + case PHASE_STATIN: + len = 1; + data = &tmp; + NCR5380_transfer_pio(instance, &phase, &len, &data); + cmd->SCp.Status = tmp; + break; + default: + printk("scsi%d: unknown phase\n", HOSTNO); +#ifdef NDEBUG + NCR5380_print(instance); +#endif + } /* switch(phase) */ + } /* if (tmp * SR_REQ) */ + } /* while (1) */ +} + +/* + * Function : void NCR5380_reselect (struct Scsi_Host *instance) + * + * Purpose : does reselection, initializing the instance->connected + * field to point to the Scsi_Cmnd for which the I_T_L or I_T_L_Q + * nexus has been reestablished, + * + * Inputs : instance - this instance of the NCR5380. + * + */ + + +static void NCR5380_reselect (struct Scsi_Host *instance) +{ + SETUP_HOSTDATA(instance); + unsigned char target_mask; + unsigned char lun, phase; + int len; +#ifdef SUPPORT_TAGS + unsigned char tag; +#endif + unsigned char msg[3]; + unsigned char *data; + Scsi_Cmnd *tmp = NULL, *prev; +/* unsigned long flags; */ + + /* + * Disable arbitration, etc. since the host adapter obviously + * lost, and tell an interrupted NCR5380_select() to restart. + */ + + NCR5380_write(MODE_REG, MR_BASE); + hostdata->restart_select = 1; + + target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask); + +#if (NDEBUG & NDEBUG_RESELECTION) + printk("scsi%d: reselect\n", HOSTNO); +#endif + + /* + * At this point, we have detected that our SCSI ID is on the bus, + * SEL is true and BSY was false for at least one bus settle delay + * (400 ns). + * + * We must assert BSY ourselves, until the target drops the SEL + * signal. + */ + + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY); + + while (NCR5380_read(STATUS_REG) & SR_SEL); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + + /* + * Wait for target to go into MSGIN. + */ + + while (!(NCR5380_read(STATUS_REG) & SR_REQ)); + + len = 1; + data = msg; + phase = PHASE_MSGIN; + NCR5380_transfer_pio(instance, &phase, &len, &data); + + if (!msg[0] & 0x80) { + printk("scsi%d: expecting IDENTIFY message, got ", HOSTNO); + print_msg(msg); + do_abort(instance); + return; + } + lun = (msg[0] & 0x07); + +#ifdef SUPPORT_TAGS + /* If the phase is still MSGIN, the target wants to send some more + * messages. In case it supports tagged queuing, this is probably a + * SIMPLE_QEUE_TAG for the I_T_L_Q nexus. + */ + tag = TAG_NONE; + if (phase == PHASE_MSGIN && setup_use_tagged_queuing) { + /* Accept previous IDENTIFY message by clearing ACK */ + NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE ); + len = 2; + data = msg+1; + if (!NCR5380_transfer_pio(instance, &phase, &len, &data) && + msg[1] == SIMPLE_QUEUE_TAG) + tag = msg[2]; +#if (NDEBUG & NDEBUG_TAGS) + printk("scsi%d: target mask %02x, lun %d sent tag %d at reselection\n", + HOSTNO, target_mask, lun, tag ); +#endif + } +#endif + + /* + * Find the command corresponding to the I_T_L or I_T_L_Q nexus we + * just reestablished, and remove it from the disconnected queue. + */ + + for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL; + tmp; prev = tmp, tmp = NEXT(tmp) ) { + if ((target_mask == (1 << tmp->target)) && (lun == tmp->lun) +#ifdef SUPPORT_TAGS + && (tag == tmp->tag) +#endif + ) { + /* ++guenther: prevent race with falcon_release_lock */ + falcon_dont_release++; + if (prev) { + REMOVE(prev, NEXT(prev), tmp, NEXT(tmp)); + NEXT(prev) = NEXT(tmp); + } else { + REMOVE(-1, hostdata->disconnected_queue, tmp, NEXT(tmp)); + hostdata->disconnected_queue = NEXT(tmp); + } + NEXT(tmp) = NULL; + break; + } + } + + if (!tmp) { + printk( "scsi%d: warning: target bitmask %02x lun %d " +#ifdef SUPPORT_TAGS + "tag %d " +#endif + "not in disconnect_queue.\n", + HOSTNO, target_mask, lun +#ifdef SUPPORT_TAGS + , tag +#endif + ); + /* + * Since we have an established nexus that we can't do anything + * with, we must abort it. + */ + do_abort(instance); + return; + } + + /* Accept message by clearing ACK */ + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + + hostdata->connected = tmp; +#if (NDEBUG & NDEBUG_RESELECTION) + printk("scsi%d: nexus established, target = %d, lun = %d, tag = %d\n", + HOSTNO, tmp->target, tmp->lun, tmp->tag); +#endif + falcon_dont_release--; +} + + +/* + * Function : int NCR5380_abort (Scsi_Cmnd *cmd) + * + * Purpose : abort a command + * + * Inputs : cmd - the Scsi_Cmnd to abort, code - code to set the + * host byte of the result field to, if zero DID_ABORTED is + * used. + * + * Returns : 0 - success, -1 on failure. + * + * XXX - there is no way to abort the command that is currently + * connected, you have to wait for it to complete. If this is + * a problem, we could implement longjmp() / setjmp(), setjmp() + * called where the loop started in NCR5380_main(). + */ + +#ifndef NCR5380_abort +static +#endif +int NCR5380_abort (Scsi_Cmnd *cmd) +{ + struct Scsi_Host *instance = cmd->host; + SETUP_HOSTDATA(instance); + Scsi_Cmnd *tmp, **prev; + unsigned long flags; + + printk("scsi%d: aborting command\n", HOSTNO); + print_Scsi_Cmnd (cmd); + + NCR5380_print_status (instance); + + save_flags(flags); + cli(); + + if (!IS_A_TT() && !falcon_got_lock) + printk("scsi%d: !!BINGO!! Falcon has no lock in NCR5380_abort\n", + HOSTNO); + +#if (NDEBUG & NDEBUG_ABORT) + printk("scsi%d: abort called basr 0x%02x, sr 0x%02x\n", HOSTNO, + NCR5380_read(BUS_AND_STATUS_REG), + NCR5380_read(STATUS_REG)); +#endif + +#if 0 +/* + * Case 1 : If the command is the currently executing command, + * we'll set the aborted flag and return control so that + * information transfer routine can exit cleanly. + */ + + if (hostdata->connected == cmd) { +#if (NDEBUG & NDEBUG_ABORT) + printk("scsi%d: aborting connected command\n", HOSTNO); +#endif + hostdata->aborted = 1; +/* + * We should perform BSY checking, and make sure we haven't slipped + * into BUS FREE. + */ + + NCR5380_write(INITIATOR_COMMAND_REG, ICR_ASSERT_ATN); +/* + * Since we can't change phases until we've completed the current + * handshake, we have to source or sink a byte of data if the current + * phase is not MSGOUT. + */ + +/* + * Return control to the executing NCR drive so we can clear the + * aborted flag and get back into our main loop. + */ + + return 0; + } +#endif + +/* + * Case 2 : If the command hasn't been issued yet, we simply remove it + * from the issue queue. + */ + for (prev = (Scsi_Cmnd **) &(hostdata->issue_queue), + tmp = (Scsi_Cmnd *) hostdata->issue_queue; + tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp) ) + if (cmd == tmp) { + REMOVE(5, *prev, tmp, NEXT(tmp)); + (*prev) = NEXT(tmp); + NEXT(tmp) = NULL; + tmp->result = DID_ABORT << 16; + restore_flags(flags); +#if (NDEBUG & NDEBUG_ABORT) + printk("scsi%d: abort removed command from issue queue.\n", + HOSTNO); +#endif + /* Tagged queuing note: no tag to free here, hasn't been assigned + * yet... */ + tmp->done(tmp); + falcon_release_lock_if_possible( hostdata ); + return SCSI_ABORT_SUCCESS; + } + +/* + * Case 3 : If any commands are connected, we're going to fail the abort + * and let the high level SCSI driver retry at a later time or + * issue a reset. + * + * Timeouts, and therefore aborted commands, will be highly unlikely + * and handling them cleanly in this situation would make the common + * case of noresets less efficient, and would pollute our code. So, + * we fail. + */ + + if (hostdata->connected) { + restore_flags(flags); +#if (NDEBUG & NDEBUG_ABORT) + printk("scsi%d: abort failed, command connected.\n", HOSTNO); +#endif + return SCSI_ABORT_NOT_RUNNING; + } + +/* + * Case 4: If the command is currently disconnected from the bus, and + * there are no connected commands, we reconnect the I_T_L or + * I_T_L_Q nexus associated with it, go into message out, and send + * an abort message. + * + * This case is especially ugly. In order to reestablish the nexus, we + * need to call NCR5380_select(). The easiest way to implement this + * function was to abort if the bus was busy, and let the interrupt + * handler triggered on the SEL for reselect take care of lost arbitrations + * where necessary, meaning interrupts need to be enabled. + * + * When interrupts are enabled, the queues may change - so we + * can't remove it from the disconnected queue before selecting it + * because that could cause a failure in hashing the nexus if that + * device reselected. + * + * Since the queues may change, we can't use the pointers from when we + * first locate it. + * + * So, we must first locate the command, and if NCR5380_select() + * succeeds, then issue the abort, relocate the command and remove + * it from the disconnected queue. + */ + + for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp; + tmp = NEXT(tmp)) + if (cmd == tmp) { + restore_flags(flags); +#if (NDEBUG & NDEBUG_ABORT) + printk("scsi%d: aborting disconnected command.\n", HOSTNO); +#endif + + if (NCR5380_select (instance, cmd, (int) cmd->tag)) + return SCSI_ABORT_BUSY; + +#if (NDEBUG & NDEBUG_ABORT) + printk("scsi%d: nexus reestablished.\n", HOSTNO); +#endif + + do_abort (instance); + + save_flags(flags); + cli(); + for (prev = (Scsi_Cmnd **) &(hostdata->disconnected_queue), + tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; + tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp) ) + if (cmd == tmp) { + REMOVE(5, *prev, tmp, NEXT(tmp)); + *prev = NEXT(tmp); + NEXT(tmp) = NULL; + tmp->result = DID_ABORT << 16; + /* We must unlock the tag/LUN immediately here, since the + * target goes to BUS FREE and doesn't send us another + * message (COMMAND_COMPLETE or the like) + */ +#ifdef SUPPORT_TAGS + cmd_free_tag( tmp ); +#else + hostdata->busy[cmd->target] &= ~(1 << cmd->lun); +#endif + restore_flags(flags); + tmp->done(tmp); + falcon_release_lock_if_possible( hostdata ); + return SCSI_ABORT_SUCCESS; + } + } + +/* + * Case 5 : If we reached this point, the command was not found in any of + * the queues. + * + * We probably reached this point because of an unlikely race condition + * between the command completing successfully and the abortion code, + * so we won't panic, but we will notify the user in case something really + * broke. + */ + + restore_flags(flags); + printk("scsi%d: warning : SCSI command probably completed successfully\n" + " before abortion\n", HOSTNO); + +/* Maybe it is sufficient just to release the ST-DMA lock... (if + * possible at all) At least, we should check if the lock could be + * released after the abort, in case it is kept due to some bug. + */ + falcon_release_lock_if_possible( hostdata ); + + return SCSI_ABORT_NOT_RUNNING; +} + + +/* + * Function : int NCR5380_reset (Scsi_Cmnd *cmd) + * + * Purpose : reset the SCSI bus. + * + * Returns : SCSI_RESET_WAKEUP + * + */ + +static int NCR5380_reset( Scsi_Cmnd *cmd ) +{ +#if 0 + SETUP_HOSTDATA(cmd->host); + int i; + unsigned long flags; + Scsi_Cmnd *connected, *disconnected_queue; +#endif + + if (!IS_A_TT() && !falcon_got_lock) + printk("scsi%d: !!BINGO!! Falcon has no lock in NCR5380_reset\n", + H_NO(cmd) ); + + NCR5380_print_status (cmd->host); + + /* get in phase */ + NCR5380_write( TARGET_COMMAND_REG, + PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) )); + /* assert RST */ + NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST ); + udelay (40); + /* reset NCR registers */ + NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE ); + NCR5380_write( MODE_REG, MR_BASE ); + NCR5380_write( TARGET_COMMAND_REG, 0 ); + NCR5380_write( SELECT_ENABLE_REG, 0 ); + /* ++roman: reset interrupt condition! otherwise no interrupts don't get + * through anymore ... */ + (void)NCR5380_read( RESET_PARITY_INTERRUPT_REG ); + +#if 0 /* XXX Now done by midlevel code XXX */ + + /* After the reset, there are no more connected or disconnected commands + * and no busy units; to avoid problems with re-inserting the commands + * into the issue_queue (via scsi_done()), the aborted commands are + * remebered in local variables first. + */ + save_flags(flags); + cli(); + connected = (Scsi_Cmnd *)hostdata->connected; + hostdata->connected = NULL; + disconnected_queue = (Scsi_Cmnd *)hostdata->disconnected_queue; + hostdata->disconnected_queue = NULL; +#ifdef SUPPORT_TAGS + free_all_tags(); +#endif + for( i = 0; i < 8; ++i ) + hostdata->busy[i] = 0; +#ifdef REAL_DMA + hostdata->dma_len = 0; +#endif + restore_flags(flags); + + if ((cmd = connected)) { +#if (NDEBUG & NDEBUG_ABORT) + printk( "scsi%d: reset aborted a connected command\n", H_NO(cmd)); +#endif + cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16); + cmd->scsi_done( cmd ); + } + + for (i = 0; (cmd = disconnected_queue); ++i) { + disconnected_queue = NEXT(cmd); + NEXT(cmd) = NULL; + cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16); + cmd->scsi_done( cmd ); + } +#if (NDEBUG & NDEBUG_ABORT) + if (i > 0) + printk( "scsi : reset aborted %d disconnected command(s)\n", i ); +#endif + +/* The Falcon lock should be released after a reset... + */ +/* ++guenther: moved to atari_scsi_reset(), to prevent a race between + * unlocking and enabling dma interrupt. + */ +/* falcon_release_lock_if_possible( hostdata );*/ + +#endif /* 0 */ + + return SCSI_RESET_WAKEUP; +} + +/* Local Variables: */ +/* tab-width: 8 */ +/* End: */ diff -u --recursive --new-file v1.3.93/linux/drivers/scsi/atari_scsi.c linux/drivers/scsi/atari_scsi.c --- v1.3.93/linux/drivers/scsi/atari_scsi.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/scsi/atari_scsi.c Fri Apr 19 02:35:24 1996 @@ -0,0 +1,1163 @@ +/* + * atari_scsi.c -- Device dependant functions for the Atari generic SCSI port + * + * Copyright 1994 Roman Hodek + * + * Loosely based on the work of Robert De Vries' team and added: + * - working real DMA + * - Falcon support (untested yet!) ++bjoern fixed and now it works + * - lots of extensions and bug fixes. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file README.legal in the main directory of this archive + * for more details. + * + */ + + +/**************************************************************************/ +/* */ +/* Notes for Falcon SCSI: */ +/* ---------------------- */ +/* */ +/* Since the Falcon SCSI uses the ST-DMA chip, that is shared among */ +/* several device drivers, locking and unlocking the access to this */ +/* chip is required. But locking is not possible from an interrupt, */ +/* since it puts the process to sleep if the lock is not available. */ +/* This prevents "late" locking of the DMA chip, i.e. locking it just */ +/* before using it, since in case of disconnection-reconnection */ +/* commands, the DMA is started from the reselection interrupt. */ +/* */ +/* Two possible schemes for ST-DMA-locking would be: */ +/* 1) The lock is taken for each command separately and disconnecting */ +/* is forbidden (i.e. can_queue = 1). */ +/* 2) The DMA chip is locked when the first command comes in and */ +/* released when the last command is finished and all queues are */ +/* empty. */ +/* The first alternative would result in bad performance, since the */ +/* interleaving of commands would not be used. The second is unfair to */ +/* other drivers using the ST-DMA, because the queues will seldom be */ +/* totally empty if there is a lot of disk traffic. */ +/* */ +/* For this reasons I decided to employ a more elaborate scheme: */ +/* - First, we give up the lock everytime we can (for fairness), this */ +/* means every time a command finishes and there are no other commands */ +/* on the disconnected queue. */ +/* - If there are others waiting to lock the DMA chip, we stop */ +/* issueing commands, i.e. moving them onto the issue queue. */ +/* Because of that, the disconnected queue will run empty in a */ +/* while. Instead we go to sleep on a 'fairness_queue'. */ +/* - If the lock is released, all processes waiting on the fairness */ +/* queue will be woken. The first of them trys to re-lock the DMA, */ +/* the others wait for the first to finish this task. After that, */ +/* they can all run on and do their commands... */ +/* This sounds complicated (and it is it :-(), but it seems to be a */ +/* good compromise between fairness and performance: As long as noone */ +/* else wants to work with the ST-DMA chip, SCSI can go along as */ +/* usual. If now someone else comes, this behaviour is changed to a */ +/* "fairness mode": just already initiated commands are finished and */ +/* then the lock is released. The other one waiting will probably win */ +/* the race for locking the DMA, since it was waiting for longer. And */ +/* after it has finished, SCSI can go ahead again. Finally: I hope I */ +/* have not produced any deadlock possibilities! */ +/* */ +/**************************************************************************/ + + + +#include +#include + +/* #define NDEBUG (NDEBUG_DMA) */ + +#define AUTOSENSE +/* For the Atari version, use only polled IO or REAL_DMA */ +#define REAL_DMA +/* Support tagged queuing? (on devices that are able to... :-) */ +#define SUPPORT_TAGS +#define MAX_TAGS 32 + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "scsi.h" +#include "hosts.h" +#include "atari_scsi.h" +#include "NCR5380.h" +#include "constants.h" +#include +#include + +#include + +struct proc_dir_entry proc_scsi_atari = { + PROC_SCSI_ATARI, 5, "Atari", + S_IFDIR | S_IRUGO | S_IXUGO, 2 +}; + +#define IS_A_TT() ATARIHW_PRESENT(TT_SCSI) + +#define SCSI_DMA_WRITE_P(elt,val) \ + do { \ + unsigned long v = val; \ + tt_scsi_dma.elt##_lo = v & 0xff; \ + v >>= 8; \ + tt_scsi_dma.elt##_lmd = v & 0xff; \ + v >>= 8; \ + tt_scsi_dma.elt##_hmd = v & 0xff; \ + v >>= 8; \ + tt_scsi_dma.elt##_hi = v & 0xff; \ + } while(0) + +#define SCSI_DMA_READ_P(elt) \ + (((unsigned long)tt_scsi_dma.elt##_hi << 24) | \ + ((unsigned long)tt_scsi_dma.elt##_hmd << 16) | \ + ((unsigned long)tt_scsi_dma.elt##_lmd << 8) | \ + (unsigned long)tt_scsi_dma.elt##_lo) + + +#define SCSI_DMA_SETADR(adr) \ + do { \ + unsigned long __adr = (adr); \ + st_dma.dma_lo = (unsigned char)__adr; \ + MFPDELAY(); \ + __adr >>= 8; \ + st_dma.dma_md = (unsigned char)__adr; \ + MFPDELAY(); \ + __adr >>= 8; \ + st_dma.dma_hi = (unsigned char)__adr; \ + MFPDELAY(); \ + } while(0) + +#define SCSI_DMA_GETADR() ({ \ + unsigned long __adr; \ + __adr = st_dma.dma_lo; \ + MFPDELAY(); \ + __adr |= (st_dma.dma_md & 0xff) << 8; \ + MFPDELAY(); \ + __adr |= (st_dma.dma_hi & 0xff) << 16; \ + MFPDELAY(); \ + __adr; \ +}) + +#define ENABLE_IRQ() \ + do { \ + if (IS_A_TT()) \ + atari_enable_irq( IRQ_TT_MFP_SCSI ); \ + else \ + atari_enable_irq( IRQ_MFP_FSCSI ); \ + } while(0) + +#define DISABLE_IRQ() \ + do { \ + if (IS_A_TT()) \ + atari_disable_irq( IRQ_TT_MFP_SCSI ); \ + else \ + atari_disable_irq( IRQ_MFP_FSCSI ); \ + } while(0) + + +#define HOSTDATA_DMALEN (((struct NCR5380_hostdata *) \ + (atari_scsi_host->hostdata))->dma_len) + +/* Time (in jiffies) to wait after a reset; the SCSI standard calls for 250ms, + * we usually do 0.5s to be on the safe side. But Toshiba CD-ROMs once more + * need ten times the standard value... */ +#ifndef CONFIG_ATARI_SCSI_TOSHIBA_DELAY +#define AFTER_RESET_DELAY (HZ/2) +#else +#define AFTER_RESET_DELAY (5*HZ/2) +#endif + +/***************************** Prototypes *****************************/ + +#ifdef REAL_DMA +static int scsi_dma_is_ignored_buserr( unsigned char dma_stat ); +static void scsi_dma_buserr( int irq, struct pt_regs *fp, void *dummy); +static void atari_scsi_fetch_restbytes( void ); +static long atari_scsi_dma_residual( struct Scsi_Host *instance ); +static int falcon_classify_cmd( Scsi_Cmnd *cmd ); +static unsigned long atari_dma_xfer_len( unsigned long wanted_len, + Scsi_Cmnd *cmd, int write_flag ); +#endif +static void scsi_tt_intr( int irq, struct pt_regs *fp, void *dummy); +static void scsi_falcon_intr( int irq, struct pt_regs *fp, void *dummy); +static void falcon_release_lock_if_possible( struct NCR5380_hostdata * + hostdata ); +static void falcon_get_lock( void ); +static void atari_scsi_reset_boot( void ); +static unsigned char atari_scsi_tt_reg_read( unsigned char reg ); +static void atari_scsi_tt_reg_write( unsigned char reg, unsigned char value); +static unsigned char atari_scsi_falcon_reg_read( unsigned char reg ); +static void atari_scsi_falcon_reg_write( unsigned char reg, unsigned char value ); + +/************************* End of Prototypes **************************/ + + +static struct Scsi_Host *atari_scsi_host = NULL; +static unsigned char (*atari_scsi_reg_read)( unsigned char reg ); +static void (*atari_scsi_reg_write)( unsigned char reg, unsigned char value ); + +#ifdef REAL_DMA +static unsigned long atari_dma_residual, atari_dma_startaddr; +static short atari_dma_active; +/* pointer to the dribble buffer */ +static char *atari_dma_buffer = NULL; +/* precalculated physical address of the dribble buffer */ +static unsigned long atari_dma_phys_buffer; +/* != 0 tells the Falcon int handler to copy data from the dribble buffer */ +static char *atari_dma_orig_addr; +/* size of the dribble buffer; 4k seems enough, since the Falcon cannot use + * scatter-gather anyway, so most transfers are 1024 byte only. In the rare + * cases where requests to physical contiguous buffers have been merged, this + * request is <= 4k (one page). So I don't think we have to split transfers + * just due to this buffer size... + */ +#define STRAM_BUFFER_SIZE (4096) +/* mask for address bits that can't be used with the ST-DMA */ +static unsigned long atari_dma_stram_mask; +#define STRAM_ADDR(a) (((a) & atari_dma_stram_mask) == 0) +/* number of bytes to cut from a transfer to handle NCR overruns */ +static int atari_read_overruns = 0; +#endif + +int setup_can_queue = -1; +int setup_cmd_per_lun = -1; +int setup_sg_tablesize = -1; +#ifdef SUPPORT_TAGS +int setup_use_tagged_queuing = -1; +#endif +int setup_hostid = -1; + + +#if defined(REAL_DMA) + +static int scsi_dma_is_ignored_buserr( unsigned char dma_stat ) +{ + int i; + unsigned long addr = SCSI_DMA_READ_P( dma_addr ), end_addr; + + if (dma_stat & 0x01) { + + /* A bus error happens when DMA-ing from the last page of a + * physical memory chunk (DMA prefetch!), but that doesn't hurt. + * Check for this case: + */ + + for( i = 0; i < boot_info.num_memory; ++i ) { + end_addr = boot_info.memory[i].addr + + boot_info.memory[i].size; + if (end_addr <= addr && addr <= end_addr + 4) + return( 1 ); + } + } + return( 0 ); +} + + +static void scsi_dma_buserr (int irq, struct pt_regs *fp, void *dummy) +{ + unsigned char dma_stat = tt_scsi_dma.dma_ctrl; + + /* Don't do anything if a NCR interrupt is pending. Probably it's just + * masked... */ + if (atari_irq_pending( IRQ_TT_MFP_SCSI )) + return; + + printk("Bad SCSI DMA interrupt! dma_addr=0x%08lx dma_stat=%02x dma_cnt=%08lx\n", + SCSI_DMA_READ_P(dma_addr), dma_stat, SCSI_DMA_READ_P(dma_cnt)); + if (dma_stat & 0x80) { + if (!scsi_dma_is_ignored_buserr( dma_stat )) + printk( "SCSI DMA bus error -- bad DMA programming!\n" ); + } + else { + /* Under normal circumstances we never should get to this point, + * since both interrupts are triggered simultaneously and the 5380 + * int has higher priority. When this irq is handled, that DMA + * interrupt is cleared. So a warning message is printed here. + */ + printk( "SCSI DMA intr ?? -- this shouldn't happen!\n" ); + } +} + +#endif + + +static void scsi_tt_intr (int irq, struct pt_regs *fp, void *dummy) +{ + unsigned long flags; +#ifdef REAL_DMA + int dma_stat; +#endif + + /* If we got this interrupt, we don't need the other one from the DMA any + * more. So clear it. */ + atari_clear_pending_irq( IRQ_TT_MFP_SCSIDMA ); + /* After this has been done, we can make this int handler "slow", i.e. + * mask the NCR int and lower the IPL, as a slow int would do (see + * arch/m68k/atari/ataints.c) */ + atari_disable_irq( IRQ_TT_MFP_SCSI ); + save_flags(flags); + flags &= 0xf8ff; + flags |= fp->sr & 0x0700; + restore_flags(flags); + +#ifdef REAL_DMA + dma_stat = tt_scsi_dma.dma_ctrl; + +#if (NDEBUG & NDEBUG_INTR) + printk("scsi%d: NCR5380 interrupt, DMA status = %02x\n", + atari_scsi_host->host_no, dma_stat & 0xff); +#endif + + /* Look if it was the DMA that has interrupted: First possibility + * is that a bus error occured... + */ + if (dma_stat & 0x80) { + if (!scsi_dma_is_ignored_buserr( dma_stat )) { + printk( "SCSI DMA caused bus error near 0x%08lx\n", + SCSI_DMA_READ_P( dma_addr )); + panic( "SCSI DMA bus error -- bad DMA programming!" ); + } + } + + /* If the DMA is active but not finished, we have the the case + * that some other 5380 interrupt occured within the DMA transfer. + * This means we have residual bytes, if the desired end address + * is not yet reached. Maybe we have to fetch some bytes from the + * rest data register, too. The residual must be calculated from + * the address pointer, not the counter register, because only the + * addr reg counts bytes not yet written and pending in the rest + * data reg! + */ + if ((dma_stat & 0x02) && !(dma_stat & 0x40)) { + atari_dma_residual = HOSTDATA_DMALEN - (SCSI_DMA_READ_P( dma_addr ) - + atari_dma_startaddr); +#if (NDEBUG & NDEBUG_DMA) + printk( "SCSI DMA: There are %ld residual bytes.\n", + atari_dma_residual ); +#endif + if ((signed int)atari_dma_residual < 0) + atari_dma_residual = 0; + if ((dma_stat & 1) == 0) { + /* After read operations, we maybe have to + transport some rest bytes */ + atari_scsi_fetch_restbytes(); + } + else { + /* There seems to be a nasty bug in some SCSI-DMA/NCR + combinations: If a target disconnects while a write + operation is going on, the address register of the + DMA may be a few bytes farer than it actually read. + This is probably due to DMA prefetching and a delay + between DMA and NCR. Experiments showed that the + dma_addr is 9 bytes to high, but this could vary. + The problem is, that the residual is thus calculated + wrong and the next transfer will start behind where + it should. So we round up the residual to the next + multiple of a sector size, if it isn't already a + multiple and the originally expected transfer size + was. The latter condition is there to ensure that + the correction is taken only for "real" data + transfers and not for, e.g., the parameters of some + other command. These shouldn't disconnect anyway. + */ + if (atari_dma_residual & 0x1ff) { +#if (NDEBUG & NDEBUG_DMA) + printk("SCSI DMA: DMA bug corrected, difference %ld bytes\n", + 512 - (atari_dma_residual & 0x1ff)); +#endif + atari_dma_residual = (atari_dma_residual + 511) & ~0x1ff; + } + } + tt_scsi_dma.dma_ctrl = 0; + } + + /* If the DMA is finished, fetch the rest bytes and turn it off */ + if (dma_stat & 0x40) { + atari_dma_residual = 0; + if ((dma_stat & 1) == 0) + atari_scsi_fetch_restbytes(); + tt_scsi_dma.dma_ctrl = 0; + } + +#endif /* REAL_DMA */ + + NCR5380_intr (0, 0, 0); + + /* To be sure the int is not masked */ + atari_enable_irq( IRQ_TT_MFP_SCSI ); +} + + +static void scsi_falcon_intr (int irq, struct pt_regs *fp, void *dummy) +{ +#ifdef REAL_DMA + int dma_stat; + + /* Turn off DMA and select sector counter register before + * accessing the status register (Atari recommendation!) + */ + st_dma.dma_mode_status = 0x90; + dma_stat = st_dma.dma_mode_status; + + /* Bit 0 indicates some error in the DMA process... don't know + * what happened exactly (no further docu). + */ + if (!(dma_stat & 0x01)) { + /* DMA error */ + printk( "SCSI DMA error near 0x%08lx!\n", SCSI_DMA_GETADR() ); + } + + /* If the DMA was active, but now bit 1 is not clear, it is some + * other 5380 interrupt that finishes the DMA transfer. We have to + * calculate the number of residual bytes and give a warning if + * bytes are stuck in the ST-DMA fifo (there's no way to reach them!) + */ + if (atari_dma_active && (dma_stat & 0x02)) { + unsigned long transferred; + + transferred = SCSI_DMA_GETADR() - atari_dma_startaddr; + /* The ST-DMA address is incremented in 2-byte steps, but the + * data are written only in 16-byte chunks. If the number of + * transferred bytes is not divisible by 16, the remainder is + * lost somewhere in outer space. + */ + if (transferred & 15) + printk( "SCSI DMA error: %ld bytes lost in ST-DMA fifo :-((\n", + transferred & 15 ); + + atari_dma_residual = HOSTDATA_DMALEN - transferred; +#if (NDEBUG & NDEBUG_DMA) + printk( "SCSI DMA: There are %ld residual bytes.\n", + atari_dma_residual ); +#endif + } + else + atari_dma_residual = 0; + atari_dma_active = 0; + + if (atari_dma_orig_addr) { + /* If the dribble buffer was used on a read operation, copy the DMA-ed + * data to the original destination address. + */ + memcpy( atari_dma_orig_addr, (void *)PTOV(atari_dma_startaddr), + HOSTDATA_DMALEN - atari_dma_residual ); + atari_dma_orig_addr = NULL; + } + +#endif /* REAL_DMA */ + + NCR5380_intr (0, 0, 0); +} + + +#ifdef REAL_DMA +static void atari_scsi_fetch_restbytes( void ) +{ + int nr; + char *src, *dst; + + /* fetch rest bytes in the DMA register */ + dst = (char *)SCSI_DMA_READ_P( dma_addr ); + if ((nr = ((long)dst & 3))) { + /* there are 'nr' bytes left for the last long address before the + DMA pointer */ + dst = (char *)( (unsigned long)dst & ~3 ); +#if (NDEBUG & NDEBUG_DMA) + printk( "SCSI DMA: there are %d rest bytes for phys addr 0x%08lx", + nr, (long)dst ); +#endif + dst = (char *)PTOV(dst); /* The content of the DMA pointer + * is a physical address! */ +#if (NDEBUG & NDEBUG_DMA) + printk( " = virt addr 0x%08lx\n", (long)dst ); +#endif + for( src = (char *)&tt_scsi_dma.dma_restdata; nr > 0; --nr ) + *dst++ = *src++; + } +} +#endif /* REAL_DMA */ + + +static int falcon_got_lock = 0; +static struct wait_queue *falcon_fairness_wait = NULL; +static int falcon_trying_lock = 0; +static struct wait_queue *falcon_try_wait = NULL; +static int falcon_dont_release = 0; + +/* This function releases the lock on the DMA chip if there is no + * connected command and the disconnected queue is empty. On + * releasing, instances of falcon_get_lock are awoken, that put + * themselves to sleep for fairness. They can now try to get the lock + * again (but others waiting longer more probably will win). + */ + +static void +falcon_release_lock_if_possible( struct NCR5380_hostdata * hostdata ) +{ + unsigned long oldflags; + + if (IS_A_TT()) return; + + save_flags(oldflags); + cli(); + + if (falcon_got_lock && + !hostdata->disconnected_queue && + !hostdata->issue_queue && + !hostdata->connected) { + + if (falcon_dont_release) { +#if 0 + printk("WARNING: Lock release not allowed. Ignored\n"); +#endif + restore_flags(oldflags); + return; + } + falcon_got_lock = 0; + stdma_release(); + wake_up( &falcon_fairness_wait ); + } + + restore_flags(oldflags); +} + +/* This function manages the locking of the ST-DMA. + * If the DMA isn't locked already for SCSI, it trys to lock it by + * calling stdma_lock(). But if the DMA is locked by the SCSI code and + * there are other drivers waiting for the chip, we do not issue the + * command immediately but wait on 'falcon_fairness_queue'. We will be + * waked up when the DMA is unlocked by some SCSI interrupt. After that + * we try to get the lock again. + * But we must be prepared that more than one instance of + * falcon_get_lock() is waiting on the fairness queue. They should not + * try all at once to call stdma_lock(), one is enough! For that, the + * first one sets 'falcon_trying_lock', others that see that variable + * set wait on the queue 'falcon_try_wait'. + * Complicated, complicated.... Sigh... + */ + +static void falcon_get_lock( void ) +{ + unsigned long oldflags; + + if (IS_A_TT()) return; + + save_flags(oldflags); + cli(); + + while( intr_count == 0 && falcon_got_lock && stdma_others_waiting() ) + sleep_on( &falcon_fairness_wait ); + + while (!falcon_got_lock) { + if (intr_count > 0) + panic( "Falcon SCSI hasn't ST-DMA lock in interrupt" ); + if (!falcon_trying_lock) { + falcon_trying_lock = 1; + stdma_lock(scsi_falcon_intr, NULL); + falcon_got_lock = 1; + falcon_trying_lock = 0; + wake_up( &falcon_try_wait ); + } + else { + sleep_on( &falcon_try_wait ); + } + } + + restore_flags(oldflags); + if (!falcon_got_lock) + panic("Falcon SCSI: someone stole the lock :-(\n"); +} + + +/* This is the wrapper function for NCR5380_queue_command(). It just + * trys to get the lock on the ST-DMA (see above) and then calls the + * original function. + */ + +#if 0 +int atari_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) +{ + /* falcon_get_lock(); + * ++guenther: moved to NCR5380_queue_command() to prevent + * race condition, see there for an explanation. + */ + return( NCR5380_queue_command( cmd, done ) ); +} +#endif + + +#define RTC_READ(reg) \ + ({ unsigned char __val; \ + outb(reg,&tt_rtc.regsel); \ + __val = tt_rtc.data; \ + __val; \ + }) + +#define RTC_WRITE(reg,val) \ + do { \ + outb(reg,&tt_rtc.regsel); \ + tt_rtc.data = (val); \ + } while(0) + + +int atari_scsi_detect (Scsi_Host_Template *host) +{ + static int called = 0; + struct Scsi_Host *instance; + + if (!MACH_IS_ATARI || + (!ATARIHW_PRESENT(ST_SCSI) && !ATARIHW_PRESENT(TT_SCSI)) || + called) + return( 0 ); + + host->proc_dir = &proc_scsi_atari; + + atari_scsi_reg_read = IS_A_TT() ? atari_scsi_tt_reg_read : + atari_scsi_falcon_reg_read; + atari_scsi_reg_write = IS_A_TT() ? atari_scsi_tt_reg_write : + atari_scsi_falcon_reg_write; + + /* setup variables */ + host->can_queue = + (setup_can_queue > 0) ? setup_can_queue : + IS_A_TT() ? ATARI_TT_CAN_QUEUE : ATARI_FALCON_CAN_QUEUE; + host->cmd_per_lun = + (setup_cmd_per_lun > 0) ? setup_cmd_per_lun : + IS_A_TT() ? ATARI_TT_CMD_PER_LUN : ATARI_FALCON_CMD_PER_LUN; + /* Force sg_tablesize to 0 on a Falcon! */ + host->sg_tablesize = + !IS_A_TT() ? ATARI_FALCON_SG_TABLESIZE : + (setup_sg_tablesize >= 0) ? setup_sg_tablesize : ATARI_TT_SG_TABLESIZE; + + if (setup_hostid >= 0) + host->this_id = setup_hostid; + else { + /* use 7 as default */ + host->this_id = 7; + /* Test if a host id is set in the NVRam */ + if (ATARIHW_PRESENT(TT_CLK)) { + unsigned char sum = 0, b; + int i; + + /* Make checksum */ + for( i = 14; i < 62; ++i ) + sum += RTC_READ(i); + + if (/* NV-Ram checksum valid? */ + RTC_READ(62) == sum && RTC_READ(63) == ~sum && + /* Arbitration enabled? (for TOS) */ + (b = RTC_READ( 30 )) & 0x80) { + host->this_id = b & 7; + } + } + } + +#ifdef SUPPORT_TAGS + if (setup_use_tagged_queuing < 0) + setup_use_tagged_queuing = DEFAULT_USE_TAGGED_QUEUING; +#endif + + /* If running on a Falcon and if there's TT-Ram (i.e., more than one + * memory block, since there's always ST-Ram in a Falcon), then allocate a + * STRAM_BUFFER_SIZE byte dribble buffer for transfers from/to alternative + * Ram. + */ + if (MACH_IS_ATARI && ATARIHW_PRESENT(ST_SCSI) && + !ATARIHW_PRESENT(EXTD_DMA) && boot_info.num_memory > 1) { + atari_dma_buffer = scsi_init_malloc(STRAM_BUFFER_SIZE, + GFP_ATOMIC | GFP_DMA); + atari_dma_phys_buffer = VTOP( atari_dma_buffer ); + atari_dma_orig_addr = 0; + } + + instance = scsi_register (host, sizeof (struct NCR5380_hostdata)); + atari_scsi_host = instance; + instance->irq = IS_A_TT() ? IRQ_TT_MFP_SCSI : IRQ_MFP_FSCSI; + + atari_scsi_reset_boot(); + NCR5380_init (instance, 0); + + if (IS_A_TT()) { + + /* This int is actually "pseudo-slow", i.e. it acts like a slow + * interrupt after having cleared the pending flag for the DMA + * interrupt. */ + add_isr(IRQ_TT_MFP_SCSI, scsi_tt_intr, IRQ_TYPE_PRIO, + NULL, "SCSI NCR5380"); + tt_mfp.active_edge |= 0x80; /* SCSI int on L->H */ +#ifdef REAL_DMA + /* On the TT, we got a second interrupt for DMA ready and DMA buserror. + * Since on DMA ready we get a "normal" interrupt, too, the service + * routine for the second int just checks for buserrs. + */ + add_isr(IRQ_TT_MFP_SCSIDMA, scsi_dma_buserr, IRQ_TYPE_SLOW, + NULL, "SCSI DMA"); + tt_mfp.active_edge &= ~0x20; /* DMA int on H->L */ + + tt_scsi_dma.dma_ctrl = 0; + atari_dma_residual = 0; +#endif /* REAL_DMA */ + + if (is_medusa) { + /* While the read overruns (described by Drew Eckhardt in + * NCR5380.c) never happened on TTs, they do in fact on the Medusa + * (This was the cause why SCSI didn't work right for so long + * there.) Since handling the overruns slows down a bit, I turned + * the #ifdef's into a runtime condition. + * + * In principle it should be sufficient to do max. 1 byte with + * PIO, but there is another problem on the Medusa with the DMA + * rest data register. So 'atari_read_overruns' is currently set + * to 4 to avoid having transfers that aren't a multiple of 4. If + * the rest data bug is fixed, this can be lowered to 1. + */ + atari_read_overruns = 4; + } + + } + else { /* ! IS_A_TT */ + + /* Nothing to do for the interrupt: the ST-DMA is initialized + * already by atari_init_INTS() + */ + +#ifdef REAL_DMA + atari_dma_residual = 0; + atari_dma_active = 0; + atari_dma_stram_mask = (ATARIHW_PRESENT(EXTD_DMA) ? 0x00000000 + : 0xff000000); +#endif + } + + printk( "scsi%d: options CAN_QUEUE=%d CMD_PER_LUN=%d SCAT-GAT=%d " +#ifdef SUPPORT_TAGS + "TAGGED-QUEUING=%s " +#endif + "HOSTID=%d", + instance->host_no, instance->hostt->can_queue, + instance->hostt->cmd_per_lun, + instance->hostt->sg_tablesize, +#ifdef SUPPORT_TAGS + setup_use_tagged_queuing ? "yes" : "no", +#endif + instance->hostt->this_id ); + NCR5380_print_options (instance); + printk ("\n"); + + called = 1; + return( 1 ); +} + +#ifdef MODULE +int atari_scsi_release (struct Scsi_Host *sh) +{ + if (IS_A_TT()) { + remove_isr (IRQ_TT_MFP_SCSI, scsi_tt_intr); +#ifdef REAL_DMA + remove_isr (IRQ_TT_MFP_SCSIDMA, scsi_dma_buserr); +#endif + } + if (atari_dma_bufffer) + scsi_init_free (atari_dma_buffer, STRAM_BUFFER_SIZE); + return 1; +} +#endif + +void atari_scsi_setup( char *str, int *ints ) +{ + /* Format of atascsi parameter is: + * atascsi=,,,, + * Defaults depend on TT or Falcon, hostid determined at run time. + * Negative values mean don't change. + */ + + /* Grmbl... the standard parameter parsing can't handle negative numbers + * :-( So let's do it ourselves! + */ + + int i = ints[0]+1, fact; + + while( str && (isdigit(*str) || *str == '-') && i <= 10) { + if (*str == '-') + fact = -1, ++str; + else + fact = 1; + ints[i++] = simple_strtoul( str, NULL, 0 ) * fact; + if ((str = strchr( str, ',' )) != NULL) + ++str; + } + ints[0] = i-1; + + if (ints[0] < 1) { + printk( "atari_scsi_setup: no arguments!\n" ); + return; + } + + if (ints[0] >= 1) { + if (ints[1] > 0) + /* no limits on this, just > 0 */ + setup_can_queue = ints[1]; + } + if (ints[0] >= 2) { + if (ints[2] > 0) + setup_cmd_per_lun = ints[2]; + } + if (ints[0] >= 3) { + if (ints[3] >= 0) { + setup_sg_tablesize = ints[3]; + /* Must be <= SG_ALL (255) */ + if (setup_sg_tablesize > SG_ALL) + setup_sg_tablesize = SG_ALL; + } + } + if (ints[0] >= 4) { + /* Must be between 0 and 7 */ + if (ints[4] >= 0 && ints[4] <= 7) + setup_hostid = ints[4]; + else if (ints[4] > 7) + printk( "atari_scsi_setup: invalid host ID %d !\n", ints[4] ); + } +#ifdef SUPPORT_TAGS + if (ints[0] >= 5) { + if (ints[5] >= 0) + setup_use_tagged_queuing = !!ints[5]; + } +#endif +} + +int atari_scsi_reset( Scsi_Cmnd *cmd ) +{ + int rv; + struct NCR5380_hostdata *hostdata = + (struct NCR5380_hostdata *)cmd->host->hostdata; + + /* For doing the reset, SCSI interrupts must be disabled first, + * since the 5380 raises its IRQ line while _RST is active and we + * can't disable interrupts completely, since we need the timer. + */ + /* And abort a maybe active DMA transfer */ + if (IS_A_TT()) { + atari_turnoff_irq( IRQ_TT_MFP_SCSI ); +#ifdef REAL_DMA + tt_scsi_dma.dma_ctrl = 0; +#endif /* REAL_DMA */ + } + else { + atari_turnoff_irq( IRQ_MFP_FSCSI ); +#ifdef REAL_DMA + st_dma.dma_mode_status = 0x90; + atari_dma_active = 0; + atari_dma_orig_addr = NULL; +#endif /* REAL_DMA */ + } + + rv = NCR5380_reset( cmd ); + + /* Re-enable ints */ + if (IS_A_TT()) { + atari_turnon_irq( IRQ_TT_MFP_SCSI ); + } + else { + atari_turnon_irq( IRQ_MFP_FSCSI ); + } + falcon_release_lock_if_possible(hostdata); + + return( rv ); +} + + +static void atari_scsi_reset_boot( void ) +{ + unsigned long end; + + /* + * Do a SCSI reset to clean up the bus during initialization. No messing + * with the queues, interrupts, or locks necessary here. + */ + + printk( "Atari SCSI: resetting the SCSI bus..." ); + + /* get in phase */ + NCR5380_write( TARGET_COMMAND_REG, + PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) )); + + /* assert RST */ + NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST ); + /* The min. reset hold time is 25us, so 40us should be enough */ + udelay( 50 ); + /* reset RST and interrupt */ + NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE ); + NCR5380_read( RESET_PARITY_INTERRUPT_REG ); + + for( end = jiffies + AFTER_RESET_DELAY; jiffies < end; ) + barrier(); + + printk( " done\n" ); +} + + +const char * atari_scsi_info (struct Scsi_Host *host) +{ + /* atari_scsi_detect() is verbose enough... */ + static const char string[] = "Atari native SCSI"; + return string; +} + + +#if defined(REAL_DMA) + +unsigned long atari_scsi_dma_setup( struct Scsi_Host *instance, void *data, + unsigned long count, int dir ) +{ + unsigned long addr = VTOP( data ); + +#if (NDEBUG & NDEBUG_DMA) + printk ("scsi%d: setting up dma, data = %p, phys = %lx, count = %ld, dir = %d\n", + instance->host_no, data, addr, count, dir); +#endif + + if (!IS_A_TT() && !STRAM_ADDR(addr)) { + /* If we have a non-DMAable address on a Falcon, use the dribble + * buffer; 'orig_addr' != 0 in the read case tells the interrupt + * handler to copy data from the dribble buffer to the originally + * wanted address. + */ + if (dir) + memcpy( atari_dma_buffer, data, count ); + else + atari_dma_orig_addr = data; + addr = atari_dma_phys_buffer; + } + + atari_dma_startaddr = addr; /* Needed for calculating residual later. */ + + /* Cache cleanup stuff: On writes, push any dirty cache out before sending + * it to the peripheral. (Must be done before DMA setup, since at least + * the ST-DMA begins to fill internal buffers right after setup. For + * reads, invalidate any cache, may be altered after DMA without CPU + * knowledge. + * + * ++roman: For the Medusa, there's no need at all for that cache stuff, + * because the hardware does bus snooping (fine!). + */ + dma_cache_maintainance( addr, count, dir ); + + if (count == 0) + printk("SCSI warning: DMA programmed for 0 bytes !\n"); + + if (IS_A_TT()) { + tt_scsi_dma.dma_ctrl = dir; + SCSI_DMA_WRITE_P( dma_addr, addr ); + SCSI_DMA_WRITE_P( dma_cnt, count ); + tt_scsi_dma.dma_ctrl = dir | 2; + } + else { /* ! IS_A_TT */ + + /* set address */ + SCSI_DMA_SETADR( addr ); + + /* toggle direction bit to clear FIFO and set DMA direction */ + dir <<= 8; + st_dma.dma_mode_status = 0x90 | dir; + st_dma.dma_mode_status = 0x90 | (dir ^ 0x100); + st_dma.dma_mode_status = 0x90 | dir; + udelay(40); + /* On writes, round up the transfer length to the next multiple of 512 + * (see also comment at atari_dma_xfer_len()). */ + st_dma.fdc_acces_seccount = (count + (dir ? 511 : 0)) >> 9; + udelay(40); + st_dma.dma_mode_status = 0x10 | dir; + udelay(40); + /* need not restore value of dir, only boolean value is tested */ + atari_dma_active = 1; + } + + return( count ); +} + + +static long atari_scsi_dma_residual( struct Scsi_Host *instance ) +{ + return( atari_dma_residual ); +} + + +#define CMD_SURELY_BLOCK_MODE 0 +#define CMD_SURELY_BYTE_MODE 1 +#define CMD_MODE_UNKNOWN 2 + +static int falcon_classify_cmd( Scsi_Cmnd *cmd ) +{ + unsigned char opcode = cmd->cmnd[0]; + + if (opcode == READ_DEFECT_DATA || opcode == READ_LONG || + opcode == READ_BUFFER) + return( CMD_SURELY_BYTE_MODE ); + else if (opcode == READ_6 || opcode == READ_10 || + opcode == 0xa8 /* READ_12 */ || opcode == READ_REVERSE || + opcode == RECOVER_BUFFERED_DATA) { + /* In case of a sequential-access target (tape), special care is + * needed here: The transfer is block-mode only if the 'fixed' bit is + * set! */ + if (cmd->device->type == TYPE_TAPE && !(cmd->cmnd[1] & 1)) + return( CMD_SURELY_BYTE_MODE ); + else + return( CMD_SURELY_BLOCK_MODE ); + } + else + return( CMD_MODE_UNKNOWN ); +} + + +/* This function calculates the number of bytes that can be transferred via + * DMA. On the TT, this is arbitrary, but on the Falcon we have to use the + * ST-DMA chip. There are only multiples of 512 bytes possible and max. + * 255*512 bytes :-( This means also, that defining READ_OVERRUNS is not + * possible on the Falcon, since that would require to program the DMA for + * n*512 - atari_read_overrun bytes. But it seems that the Falcon doesn't have + * the overrun problem, so this question is academic :-) + */ + +static unsigned long atari_dma_xfer_len( unsigned long wanted_len, + Scsi_Cmnd *cmd, + int write_flag ) +{ + unsigned long possible_len, limit; + + if (IS_A_TT()) + /* TT SCSI DMA can transfer arbitrary #bytes */ + return( wanted_len ); + + /* ST DMA chip is stupid -- only multiples of 512 bytes! (and max. + * 255*512 bytes, but this should be enough) + * + * ++roman: Aaargl! Another Falcon-SCSI problem... There are some commands + * that return a number of bytes which cannot be known beforehand. In this + * case, the given transfer length is an "allocation length". Now it + * can happen that this allocation length is a multiple of 512 bytes and + * the DMA is used. But if not n*512 bytes really arrive, some input data + * will be lost in the ST-DMA's FIFO :-( Thus, we have to distinguish + * between commands that do block transfers and those that do byte + * transfers. But this isn't easy... there are lots of vendor specific + * commands, and the user can issue any command via the + * SCSI_IOCTL_SEND_COMMAND. + * + * The solution: We classify SCSI commands in 1) surely block-mode cmd.s, + * 2) surely byte-mode cmd.s and 3) cmd.s with unknown mode. In case 1) + * and 3), the thing to do is obvious: allow any number of blocks via DMA + * or none. In case 2), we apply some heuristic: Byte mode is assumed if + * the transfer (allocation) length is < 1024, hoping that no cmd. not + * explicitly known as byte mode have such big allocation lengths... + * BTW, all the discussion above applies only to reads. DMA writes are + * unproblematic anyways, since the targets aborts the transfer after + * receiving a sufficient number of bytes. + * + * Another point: If the transfer is from/to an non-ST-RAM address, we + * use the dribble buffer and thus can do only STRAM_BUFFER_SIZE bytes. + */ + + if (write_flag) { + /* Write operation can always use the DMA, but the transfer size must + * be rounded up to the next multiple of 512 (atari_dma_setup() does + * this). + */ + possible_len = wanted_len; + } + else { + /* Read operations: if the wanted transfer length is not a multiple of + * 512, we cannot use DMA, since the ST-DMA cannot split transfers + * (no interrupt on DMA finished!) + */ + if (wanted_len & 0x1ff) + possible_len = 0; + else { + /* Now classify the command (see above) and decide whether it is + * allowed to do DMA at all */ + switch( falcon_classify_cmd( cmd )) { + case CMD_SURELY_BLOCK_MODE: + possible_len = wanted_len; + break; + case CMD_SURELY_BYTE_MODE: + possible_len = 0; /* DMA prohibited */ + break; + case CMD_MODE_UNKNOWN: + default: + /* For unknown commands assume block transfers if the transfer + * size/allocation length is >= 1024 */ + possible_len = (wanted_len < 1024) ? 0 : wanted_len; + break; + } + } + } + + /* Last step: apply the hard limit on DMA transfers */ + limit = (atari_dma_buffer && !STRAM_ADDR( VTOP(cmd->SCp.ptr) )) ? + STRAM_BUFFER_SIZE : 255*512; + if (possible_len > limit) + possible_len = limit; + +#if (NDEBUG & NDEBUG_DMA) + if (possible_len != wanted_len) + printk( "Sorry, must cut DMA transfer size to %ld bytes instead of %ld\n", + possible_len, wanted_len ); +#endif + + return( possible_len ); +} + + +#endif /* REAL_DMA */ + + +/* NCR5380 register access functions + * + * There are separate functions for TT and Falcon, because the access + * methods are quite different. The calling macros NCR5380_read and + * NCR5380_write call these functions via function pointers. + */ + +static unsigned char atari_scsi_tt_reg_read( unsigned char reg ) +{ + return( tt_scsi_regp[reg * 2] ); +} + +static void atari_scsi_tt_reg_write( unsigned char reg, unsigned char value ) +{ + tt_scsi_regp[reg * 2] = value; +} + +static unsigned char atari_scsi_falcon_reg_read( unsigned char reg ) +{ + dma_wd.dma_mode_status= (u_short)(0x88 + reg); + return( (u_char)dma_wd.fdc_acces_seccount ); +} + +static void atari_scsi_falcon_reg_write( unsigned char reg, unsigned char value ) +{ + dma_wd.dma_mode_status = (u_short)(0x88 + reg); + dma_wd.fdc_acces_seccount = (u_short)value; +} + + +#include "atari_NCR5380.c" + +#ifdef MODULE +Scsi_Host_Template driver_template = ATARI_SCSI; + +#include "scsi_module.c" +#endif diff -u --recursive --new-file v1.3.93/linux/drivers/scsi/atari_scsi.h linux/drivers/scsi/atari_scsi.h --- v1.3.93/linux/drivers/scsi/atari_scsi.h Thu Jan 1 02:00:00 1970 +++ linux/drivers/scsi/atari_scsi.h Sat Apr 13 14:31:03 1996 @@ -0,0 +1,99 @@ +/* + * atari_scsi.h -- Header file for the Atari native SCSI driver + * + * Copyright 1994 Roman Hodek + * + * (Loosely based on the work of Robert De Vries' team) + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file README.legal in the main directory of this archive + * for more details. + * + */ + + +#ifndef ATARI_SCSI_H +#define ATARI_SCSI_H + +/* (I_HAVE_OVERRUNS stuff removed) */ + +#ifndef ASM +int atari_scsi_abort (Scsi_Cmnd *); +int atari_scsi_detect (Scsi_Host_Template *); +const char *atari_scsi_info (struct Scsi_Host *); +int atari_scsi_queue_command (Scsi_Cmnd *, void (*done) (Scsi_Cmnd *)); +int atari_scsi_reset (Scsi_Cmnd *); +int atari_scsi_proc_info (char *, char **, off_t, int, int, int); +#ifdef MODULE +int atari_scsi_release (struct Scsi_Host *); +#else +#define atari_scsi_release NULL +#endif + +/* The values for CMD_PER_LUN and CAN_QUEUE are somehow arbitrary. Higher + * values should work, too; try it! (but cmd_per_lun costs memory!) */ + +/* But there seems to be a bug somewhere that requires CAN_QUEUE to be + * 2*CMD_OER_LUN. At least on a TT, no suprious timeouts seen since + * changed CMD_PER_LUN... */ + +/* Note: The Falcon currently uses 8/1 setting due to unsolved problems with + * cmd_per_lun != 1 */ + +#define ATARI_TT_CAN_QUEUE 16 +#define ATARI_TT_CMD_PER_LUN 8 +#define ATARI_TT_SG_TABLESIZE SG_ALL + +#define ATARI_FALCON_CAN_QUEUE 8 +#define ATARI_FALCON_CMD_PER_LUN 1 +#define ATARI_FALCON_SG_TABLESIZE SG_NONE + +#define DEFAULT_USE_TAGGED_QUEUING 0 + + +#if defined (HOSTS_C) || defined (MODULE) + +#define ATARI_SCSI { NULL, NULL, NULL, \ + atari_scsi_proc_info, \ + "Atari native SCSI", \ + atari_scsi_detect, \ + atari_scsi_release, \ + atari_scsi_info, \ + /* command */ NULL, \ + atari_scsi_queue_command, \ + atari_scsi_abort, \ + atari_scsi_reset, \ + /* slave_attach */ NULL, \ + /* bios_param */ NULL, \ + /* can queue */ 0, /* initialized at run-time */ \ + /* host_id */ 0, /* initialized at run-time */ \ + /* scatter gather */ 0, /* initialized at run-time */ \ + /* cmd per lun */ 0, /* initialized at run-time */ \ + /* present */ 0, \ + /* unchecked ISA DMA */ 0, \ + /* use_clustering */ DISABLE_CLUSTERING } + +#endif + +#ifndef HOSTS_C + +#define NCR5380_implementation_fields /* none */ + +#define NCR5380_read(reg) atari_scsi_reg_read( reg ) +#define NCR5380_write(reg, value) atari_scsi_reg_write( reg, value ) + +#define NCR5380_intr atari_scsi_intr +#define NCR5380_queue_command atari_scsi_queue_command +#define NCR5380_abort atari_scsi_abort +#define NCR5380_proc_info atari_scsi_proc_info +#define NCR5380_dma_read_setup(inst,d,c) atari_scsi_dma_setup (inst, d, c, 0) +#define NCR5380_dma_write_setup(inst,d,c) atari_scsi_dma_setup (inst, d, c, 1) +#define NCR5380_dma_residual(inst) atari_scsi_dma_residual( inst ) +#define NCR5380_dma_xfer_len(i,cmd,phase) \ + atari_dma_xfer_len(cmd->SCp.this_residual,cmd,((phase) & SR_IO) ? 0 : 1) + +#endif /* else def HOSTS_C */ +#endif /* ndef ASM */ +#endif /* ATARI_SCSI_H */ + + diff -u --recursive --new-file v1.3.93/linux/drivers/scsi/gvp11.c linux/drivers/scsi/gvp11.c --- v1.3.93/linux/drivers/scsi/gvp11.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/scsi/gvp11.c Mon Apr 1 22:14:33 1996 @@ -0,0 +1,246 @@ +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "scsi.h" +#include "hosts.h" +#include "wd33c93.h" +#include "gvp11.h" + +#include + +struct proc_dir_entry proc_scsi_gvp11 = { + PROC_SCSI_GVP11, 5, "GVP11", + S_IFDIR | S_IRUGO | S_IXUGO, 2 +}; + +#define DMA(ptr) ((gvp11_scsiregs *)((ptr)->base)) +#define HDATA(ptr) ((struct WD33C93_hostdata *)((ptr)->hostdata)) + +static struct Scsi_Host *first_instance = NULL; +static Scsi_Host_Template *gvp11_template; + +static void gvp11_intr (int irq, struct pt_regs *fp, void *dummy) +{ + unsigned int status; + struct Scsi_Host *instance; + + for (instance = first_instance; instance && + instance->hostt == gvp11_template; instance = instance->next) + { + status = DMA(instance)->CNTR; + if (!(status & GVP11_DMAC_INT_PENDING)) + continue; + + /* disable PORTS interrupt */ + custom.intena = IF_PORTS; + wd33c93_intr (instance); + /* enable PORTS interrupt */ + custom.intena = IF_SETCLR | IF_PORTS; + } +} + +/* + * DMA transfer mask for GVP Series II SCSI controller. + * Some versions can only DMA into the 24 bit address space + * (0->16M). Others can DMA into the full 32 bit address + * space. The default is to only allow DMA into the 24 bit + * address space. The "gvp11=0xFFFFFFFE" setup parameter can + * be supplied to force an alternate (32 bit) mask. + */ +static int gvp11_xfer_mask = GVP11_XFER_MASK; + +void gvp11_setup (char *str, int *ints) +{ + gvp11_xfer_mask = ints[1]; +} + +static int dma_setup (Scsi_Cmnd *cmd, int dir_in) +{ + unsigned short cntr = GVP11_DMAC_INT_ENABLE; + unsigned long addr = VTOP(cmd->SCp.ptr); + + /* don't allow DMA if the physical address is bad */ + if (addr & gvp11_xfer_mask || + (!dir_in && mm_end_of_chunk (addr, cmd->SCp.this_residual))) + { + HDATA(cmd->host)->dma_bounce_len = (cmd->SCp.this_residual + 511) + & ~0x1ff; + HDATA(cmd->host)->dma_bounce_buffer = + scsi_malloc (HDATA(cmd->host)->dma_bounce_len); + + /* can't allocate memory; use PIO */ + if (!HDATA(cmd->host)->dma_bounce_buffer) { + HDATA(cmd->host)->dma_bounce_len = 0; + return 1; + } + + /* check if the address of the bounce buffer is OK */ + addr = VTOP(HDATA(cmd->host)->dma_bounce_buffer); + + if (addr & gvp11_xfer_mask) { + scsi_free (HDATA(cmd->host)->dma_bounce_buffer, + HDATA(cmd->host)->dma_bounce_len); + HDATA(cmd->host)->dma_bounce_buffer = NULL; + HDATA(cmd->host)->dma_bounce_len = 0; + return 1; + } + + if (!dir_in) { + /* copy to bounce buffer for a write */ + if (cmd->use_sg) +#if 0 + panic ("scsi%ddma: incomplete s/g support", + cmd->host->host_no); +#else + memcpy (HDATA(cmd->host)->dma_bounce_buffer, + cmd->SCp.ptr, cmd->SCp.this_residual); +#endif + else + memcpy (HDATA(cmd->host)->dma_bounce_buffer, + cmd->request_buffer, cmd->request_bufflen); + } + } + + /* setup dma direction */ + if (!dir_in) + cntr |= GVP11_DMAC_DIR_WRITE; + + HDATA(cmd->host)->dma_dir = dir_in; + DMA(cmd->host)->CNTR = cntr; + + /* setup DMA *physical* address */ + DMA(cmd->host)->ACR = addr; + + if (dir_in) + /* invalidate any cache */ + cache_clear (addr, cmd->SCp.this_residual); + else + /* push any dirty cache */ + cache_push (addr, cmd->SCp.this_residual); + + /* start DMA */ + DMA(cmd->host)->ST_DMA = 1; + + /* return success */ + return 0; +} + +static void dma_stop (struct Scsi_Host *instance, Scsi_Cmnd *SCpnt, + int status) +{ + /* stop DMA */ + DMA(instance)->SP_DMA = 1; + /* remove write bit from CONTROL bits */ + DMA(instance)->CNTR = GVP11_DMAC_INT_ENABLE; + + /* copy from a bounce buffer, if necessary */ + if (status && HDATA(instance)->dma_bounce_buffer) { + if (SCpnt && SCpnt->use_sg) { +#if 0 + panic ("scsi%d: incomplete s/g support", + instance->host_no); +#else + if( HDATA(instance)->dma_dir ) + memcpy (SCpnt->SCp.ptr, + HDATA(instance)->dma_bounce_buffer, + SCpnt->SCp.this_residual); + scsi_free (HDATA(instance)->dma_bounce_buffer, + HDATA(instance)->dma_bounce_len); + HDATA(instance)->dma_bounce_buffer = NULL; + HDATA(instance)->dma_bounce_len = 0; + +#endif + } else { + if (HDATA(instance)->dma_dir && SCpnt) + memcpy (SCpnt->request_buffer, + HDATA(instance)->dma_bounce_buffer, + SCpnt->request_bufflen); + + scsi_free (HDATA(instance)->dma_bounce_buffer, + HDATA(instance)->dma_bounce_len); + HDATA(instance)->dma_bounce_buffer = NULL; + HDATA(instance)->dma_bounce_len = 0; + } + } +} + +int gvp11_detect(Scsi_Host_Template *tpnt) +{ + static unsigned char called = 0; + struct Scsi_Host *instance; + int i, manuf, product, num_gvp11 = 0; + caddr_t address; + enum GVP_ident epc; + + if (!MACH_IS_AMIGA || called) + return 0; + called = 1; + + tpnt->proc_dir = &proc_scsi_gvp11; + + for (i = 0; i < boot_info.bi_amiga.num_autocon; i++) + { + manuf = boot_info.bi_amiga.autocon[i].cd_Rom.er_Manufacturer; + product = boot_info.bi_amiga.autocon[i].cd_Rom.er_Product; +#if 0 +/* this seems to catch some non HD boards. GVP is sooooo stupid */ + if (manuf == MANUF_GVP && + ((product == PROD_GVPIISCSI) || (product == PROD_GVPIISCSI_2))) { +#else + if (manuf == MANUF_GVP && product == PROD_GVPIISCSI) { +#endif + /* check extended product code */ + address = boot_info.bi_amiga.autocon[i].cd_BoardAddr; + epc = *(unsigned short *)(ZTWO_VADDR(address) + 0x8000); + + epc = epc & GVP_EPCMASK; + + /* + * This should (hopefully) be the correct way to identify + * all the different GVP SCSI controllers (except for the + * SERIES I though). + */ + if (!((epc == GVP_A1291_SCSI) || + (epc == GVP_GFORCE_040_SCSI) || + (epc == GVP_GFORCE_030_SCSI) || + (epc == GVP_A530_SCSI) || + (epc == GVP_COMBO_R4_SCSI) || + (epc == GVP_COMBO_R3_SCSI) || + (epc == GVP_SERIESII))) + continue; + + instance = scsi_register (tpnt, + sizeof (struct WD33C93_hostdata)); + instance->base = (unsigned char *)ZTWO_VADDR(address); + DMA(instance)->secret2 = 1; + DMA(instance)->secret1 = 0; + DMA(instance)->secret3 = 15; + while (DMA(instance)->CNTR & GVP11_DMAC_BUSY) ; + DMA(instance)->CNTR = 0; + wd33c93_init(instance, (wd33c93_regs *)&(DMA(instance)->SASR), + dma_setup, dma_stop, WD33C93_FS_8_10); + if (num_gvp11++ == 0) { + first_instance = instance; + gvp11_template = instance->hostt; + add_isr(IRQ_AMIGA_PORTS, gvp11_intr, 0, NULL, "GVP11 SCSI"); + } + DMA(instance)->CNTR = GVP11_DMAC_INT_ENABLE; + +#if 0 /* The Zorro stuff is not totally integrated yet ! */ + boot_info.bi_amiga.autocon_configured |= 1< + +int gvp11_detect(Scsi_Host_Template *); +const char *wd33c93_info(void); +int wd33c93_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +int wd33c93_abort(Scsi_Cmnd *); +int wd33c93_reset(Scsi_Cmnd *); + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef CMD_PER_LUN +#define CMD_PER_LUN 2 +#endif + +#ifndef CAN_QUEUE +#define CAN_QUEUE 16 +#endif + +#ifdef HOSTS_C + +extern struct proc_dir_entry proc_scsi_gvp11; + +#define GVP11_SCSI { /* next */ NULL, \ + /* usage_count */ NULL, \ + /* proc_dir_entry */ &proc_scsi_gvp11, \ + /* proc_info */ NULL, \ + /* name */ "GVP Series II SCSI", \ + /* detect */ gvp11_detect, \ + /* release */ NULL, \ + /* info */ NULL, \ + /* command */ NULL, \ + /* queuecommand */ wd33c93_queuecommand, \ + /* abort */ wd33c93_abort, \ + /* reset */ wd33c93_reset, \ + /* slave_attach */ NULL, \ + /* bios_param */ NULL, \ + /* can_queue */ CAN_QUEUE, \ + /* this_id */ 7, \ + /* sg_tablesize */ SG_ALL, \ + /* cmd_per_lun */ CMD_PER_LUN, \ + /* present */ 0, \ + /* unchecked_isa_dma */ 0, \ + /* use_clustering */ DISABLE_CLUSTERING } +#else + +/* + * if the transfer address ANDed with this results in a non-zero + * result, then we can't use DMA. + */ +#define GVP11_XFER_MASK (0xff000001) + +typedef struct { + unsigned char pad1[64]; + volatile unsigned short CNTR; + unsigned char pad2[31]; + volatile unsigned char SASR; + unsigned char pad3; + volatile unsigned char SCMD; + unsigned char pad4[4]; + volatile unsigned short BANK; + unsigned char pad5[6]; + volatile unsigned long ACR; + volatile unsigned short secret1; /* store 0 here */ + volatile unsigned short ST_DMA; + volatile unsigned short SP_DMA; + volatile unsigned short secret2; /* store 1 here */ + volatile unsigned short secret3; /* store 15 here */ +} gvp11_scsiregs; + +/* bits in CNTR */ +#define GVP11_DMAC_BUSY (1<<0) +#define GVP11_DMAC_INT_PENDING (1<<1) +#define GVP11_DMAC_INT_ENABLE (1<<3) +#define GVP11_DMAC_DIR_WRITE (1<<4) + +#endif /* else def HOSTS_C */ + +#endif /* GVP11_H */ diff -u --recursive --new-file v1.3.93/linux/drivers/scsi/st.c linux/drivers/scsi/st.c --- v1.3.93/linux/drivers/scsi/st.c Mon Apr 8 19:01:44 1996 +++ linux/drivers/scsi/st.c Mon Apr 22 11:13:22 1996 @@ -11,7 +11,7 @@ Copyright 1992 - 1996 Kai Makisara email Kai.Makisara@metla.fi - Last modified: Sun Apr 7 20:33:27 1996 by root@kai.makisara.fi + Last modified: Sun Apr 21 22:03:50 1996 by root@kai.makisara.fi Some small formal changes - aeb, 950809 */ @@ -77,6 +77,10 @@ #define TAPE_NR(x) (MINOR(x) & ~(128 | ST_MODE_MASK)) #define TAPE_MODE(x) ((MINOR(x) & ST_MODE_MASK) >> ST_MODE_SHIFT) +/* Internal ioctl to set both density (uppermost 8 bits) and blocksize (lower + 24 bits) */ +#define SET_DENS_AND_BLK 0x10001 + static int st_nbr_buffers; static ST_buffer **st_buffers; static int st_buffer_size = ST_BUFFER_SIZE; @@ -459,7 +463,8 @@ scsi_tape_open(struct inode * inode, struct file * filp) { unsigned short flags; - int i, need_dma_buffer, new_session = FALSE, setting_failed; + int i, need_dma_buffer, new_session = FALSE, set_it; + unsigned int arg; unsigned char cmd[10]; Scsi_Cmnd * SCpnt; Scsi_Tape * STp; @@ -568,28 +573,32 @@ return 0; } - memset ((void *) &cmd[0], 0, 10); - cmd[0] = READ_BLOCK_LIMITS; + if (STp->omit_blklims) + STp->min_block = STp->max_block = (-1); + else { + memset ((void *) &cmd[0], 0, 10); + cmd[0] = READ_BLOCK_LIMITS; - SCpnt = st_do_scsi(SCpnt, STp, cmd, 6, ST_TIMEOUT, MAX_READY_RETRIES); + SCpnt = st_do_scsi(SCpnt, STp, cmd, 6, ST_TIMEOUT, MAX_READY_RETRIES); - if (!SCpnt->result && !SCpnt->sense_buffer[0]) { - STp->max_block = ((STp->buffer)->b_data[1] << 16) | - ((STp->buffer)->b_data[2] << 8) | (STp->buffer)->b_data[3]; - STp->min_block = ((STp->buffer)->b_data[4] << 8) | - (STp->buffer)->b_data[5]; + if (!SCpnt->result && !SCpnt->sense_buffer[0]) { + STp->max_block = ((STp->buffer)->b_data[1] << 16) | + ((STp->buffer)->b_data[2] << 8) | (STp->buffer)->b_data[3]; + STp->min_block = ((STp->buffer)->b_data[4] << 8) | + (STp->buffer)->b_data[5]; #if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Block limits %d - %d bytes.\n", dev, STp->min_block, - STp->max_block); + if (debugging) + printk(ST_DEB_MSG "st%d: Block limits %d - %d bytes.\n", dev, STp->min_block, + STp->max_block); #endif - } - else { - STp->min_block = STp->max_block = (-1); + } + else { + STp->min_block = STp->max_block = (-1); #if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Can't read block limits.\n", dev); + if (debugging) + printk(ST_DEB_MSG "st%d: Can't read block limits.\n", dev); #endif + } } memset ((void *) &cmd[0], 0, 10); @@ -674,34 +683,34 @@ STp->density_changed = STp->blksize_changed = FALSE; STp->compression_changed = FALSE; if (!(STm->defaults_for_writes)) { - setting_failed = FALSE; + set_it = FALSE; + if (STm->default_density >= 0 && + STm->default_density != STp->density) { + arg = STm->default_density; + set_it = TRUE; + } + else + arg = STp->density; + arg <<= MT_ST_DENSITY_SHIFT; if (STm->default_blksize >= 0 && STm->default_blksize != STp->block_size) { - if (STm->default_density >= 0 && - STm->default_density != STp->density) - STp->density = STm->default_density; /* Dirty trick! */ - if (st_int_ioctl(inode, filp, MTSETBLK, STm->default_blksize)) { - printk(KERN_WARNING "st%d: Can't set default block size to %d bytes.\n", - dev, STm->default_blksize); - if (modes_defined) - setting_failed = TRUE; - } + arg |= STm->default_blksize; + set_it = TRUE; } - if (STm->default_density >= 0 && - STm->default_density != STp->density) { - if (st_int_ioctl(inode, filp, MTSETDENSITY, STm->default_density)) { - printk(KERN_WARNING "st%d: Can't set default density to %x.\n", - dev, STm->default_density); - if (modes_defined) - setting_failed = TRUE; + else + arg |= STp->block_size; + if (set_it && + st_int_ioctl(inode, filp, SET_DENS_AND_BLK, arg)) { + printk(KERN_WARNING + "st%d: Can't set default block size to %d bytes and density %x.\n", + dev, STm->default_blksize, STm->default_density); + if (modes_defined) { + (STp->buffer)->in_use = 0; + STp->buffer = 0; + STp->in_use = 0; + return (-EINVAL); } } - if (setting_failed) { - (STp->buffer)->in_use = 0; - STp->buffer = 0; - STp->in_use = 0; - return (-EINVAL); - } } if (STp->default_drvbuffer != 0xff) { if (st_int_ioctl(inode, filp, MTSETDRVBUFFER, STp->default_drvbuffer)) @@ -807,7 +816,8 @@ { int total, do_count, blks, retval, transfer; int write_threshold; - int doing_write = 0; + int doing_write = 0, set_it; + unsigned int arg; static unsigned char cmd[10]; const char *b_point; Scsi_Cmnd * SCpnt = NULL; @@ -854,32 +864,33 @@ return retval; STp->rw = ST_WRITING; } - else if (STp->rw != ST_WRITING) { - if (STm->defaults_for_writes && - (STp->mt_status)->mt_fileno == 0 && STp->drv_block == 0) { - /* Force unless explicitly changed by the user */ - if (!(STp->blksize_changed) && STm->default_blksize >= 0 && - STp->block_size != STm->default_blksize) { - if (STm->default_density >= 0 && - STm->default_density != STp->density) - STp->density = STm->default_density; /* Dirty trick! */ - if (st_int_ioctl(inode, filp, MTSETBLK, STm->default_blksize)) { - printk(KERN_WARNING "st%d: Can't set default block size to %d bytes.\n", - dev, STm->default_blksize); - if (modes_defined) - return (-EINVAL); - } - } - if (!(STp->density_changed) && STm->default_density >= 0 && - STm->default_density != STp->density) { - if (st_int_ioctl(inode, filp, MTSETDENSITY, STm->default_density)) { - printk(KERN_WARNING "st%d: Can't set default density %x.\n", - dev, STm->default_density); - if (modes_defined) - return (-EINVAL); - } - } + else if (STp->rw != ST_WRITING && + (STp->mt_status)->mt_fileno == 0 && STp->drv_block == 0) { + set_it = FALSE; + if (!STp->density_changed && STm->default_density >= 0 && + STm->default_density != STp->density) { + arg = STm->default_density; + set_it = TRUE; + } + else + arg = STp->density; + arg <<= MT_ST_DENSITY_SHIFT; + if (!STp->blksize_changed && STm->default_blksize >= 0 && + STm->default_blksize != STp->block_size) { + arg |= STm->default_blksize; + set_it = TRUE; } + else + arg |= STp->block_size; + if (set_it && + st_int_ioctl(inode, filp, SET_DENS_AND_BLK, arg)) { + printk(KERN_WARNING + "st%d: Can't set default block size to %d bytes and density %x.\n", + dev, STm->default_blksize, STm->default_density); + if (modes_defined) + return (-EINVAL); + } + if (STm->default_compression != ST_DONT_TOUCH && !(STp->compression_changed)) { if (st_compression(STp, (STm->default_compression == ST_YES))) { @@ -1104,12 +1115,14 @@ static unsigned char cmd[10]; Scsi_Cmnd * SCpnt = NULL; Scsi_Tape * STp; + ST_mode * STm; int dev = TAPE_NR(inode->i_rdev); STp = &(scsi_tapes[dev]); if (STp->ready != ST_READY) return (-EIO); - if (!STp->modes[STp->current_mode].defined) + STm = &(STp->modes[STp->current_mode]); + if (!STm->defined) return (-ENXIO); #if DEBUG if (!STp->in_use) { @@ -1123,7 +1136,7 @@ !enlarge_buffer(STp->buffer, count, STp->restr_dma)) return (-EOVERFLOW); - if (!(STp->do_read_ahead) && STp->block_size != 0 && + if (!(STm->do_read_ahead) && STp->block_size != 0 && (count % STp->block_size) != 0) return (-EIO); /* Read must be integral number of blocks */ @@ -1162,12 +1175,12 @@ if (STp->block_size == 0) blks = bytes = count; else { - if (STp->do_read_ahead) { + if (STm->do_read_ahead) { blks = (STp->buffer)->buffer_blocks; bytes = blks * STp->block_size; } else { - bytes = count; + bytes = count - total; if (bytes > (STp->buffer)->buffer_size) bytes = (STp->buffer)->buffer_size; blks = bytes / STp->block_size; @@ -1346,11 +1359,13 @@ printk(KERN_INFO "st%d: Mode %d options: buffer writes: %d, async writes: %d, read ahead: %d\n", dev, STp->current_mode, STm->do_buffer_writes, STm->do_async_writes, - STp->do_read_ahead); + STm->do_read_ahead); + printk(KERN_INFO +"st%d: can bsr: %d, two FMs: %d, fast mteom: %d, auto lock: %d,\n", + dev, STp->can_bsr, STp->two_fm, STp->fast_mteom, STp->do_auto_lock); printk(KERN_INFO -"st%d: can bsr: %d, two FMs: %d, fast mteom: %d, auto lock: %d, defs for wr: %d \n", - dev, STp->can_bsr, STp->two_fm, STp->fast_mteom, STp->do_auto_lock, - STm->defaults_for_writes); +"st%d: defs for wr: %d, no block limits: %d\n", + dev, STm->defaults_for_writes, STp->omit_blklims); #if DEBUG printk(KERN_INFO "st%d: debugging: %d\n", @@ -1385,11 +1400,12 @@ STm->do_buffer_writes = (options & MT_ST_BUFFER_WRITES) != 0; STm->do_async_writes = (options & MT_ST_ASYNC_WRITES) != 0; STm->defaults_for_writes = (options & MT_ST_DEF_WRITES) != 0; - STp->do_read_ahead = (options & MT_ST_READ_AHEAD) != 0; + STm->do_read_ahead = (options & MT_ST_READ_AHEAD) != 0; STp->two_fm = (options & MT_ST_TWO_FM) != 0; STp->fast_mteom = (options & MT_ST_FAST_MTEOM) != 0; STp->do_auto_lock = (options & MT_ST_AUTO_LOCK) != 0; STp->can_bsr = (options & MT_ST_CAN_BSR) != 0; + STp->omit_blklims = (options & MT_ST_NO_BLKLIMS) != 0; #if DEBUG debugging = (options & MT_ST_DEBUGGING) != 0; #endif @@ -1404,7 +1420,7 @@ if ((options & MT_ST_DEF_WRITES) != 0) STm->defaults_for_writes = value; if ((options & MT_ST_READ_AHEAD) != 0) - STp->do_read_ahead = value; + STm->do_read_ahead = value; if ((options & MT_ST_TWO_FM) != 0) STp->two_fm = value; if ((options & MT_ST_FAST_MTEOM) != 0) @@ -1413,6 +1429,8 @@ STp->do_auto_lock = value; if ((options & MT_ST_CAN_BSR) != 0) STp->can_bsr = value; + if ((options & MT_ST_NO_BLKLIMS) != 0) + STp->omit_blklims = value; #if DEBUG if ((options & MT_ST_DEBUGGING) != 0) debugging = value; @@ -1875,12 +1893,14 @@ case MTSETBLK: /* Set block length */ case MTSETDENSITY: /* Set tape density */ case MTSETDRVBUFFER: /* Set drive buffering */ + case SET_DENS_AND_BLK: /* Set density and block size */ if (STp->dirty || (STp->buffer)->buffer_bytes != 0) return (-EIO); /* Not allowed if data in buffer */ - if (cmd_in == MTSETBLK && - arg != 0 && - (arg < STp->min_block || arg > STp->max_block || - arg > st_buffer_size)) { + if ((cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) && + (arg & MT_ST_BLKSIZE_MASK) != 0 && + ((arg & MT_ST_BLKSIZE_MASK) < STp->min_block || + (arg & MT_ST_BLKSIZE_MASK) > STp->max_block || + (arg & MT_ST_BLKSIZE_MASK) > st_buffer_size)) { printk(KERN_WARNING "st%d: Illegal block size.\n", dev); return (-EINVAL); } @@ -1898,11 +1918,14 @@ (STp->buffer)->b_data[4] = arg; STp->density_changed = TRUE; /* At least we tried ;-) */ } + else if (cmd_in == SET_DENS_AND_BLK) + (STp->buffer)->b_data[4] = arg >> 24; else (STp->buffer)->b_data[4] = STp->density; - if (cmd_in == MTSETBLK) { - ltmp = arg; - STp->blksize_changed = TRUE; /* At least we tried ;-) */ + if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) { + ltmp = arg & MT_ST_BLKSIZE_MASK; + if (cmd_in == MTSETBLK) + STp->blksize_changed = TRUE; /* At least we tried ;-) */ } else ltmp = STp->block_size; @@ -1912,15 +1935,15 @@ timeout = ST_TIMEOUT; #if DEBUG if (debugging) { - if (cmd_in == MTSETBLK) + if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) printk(ST_DEB_MSG "st%d: Setting block size to %d bytes.\n", dev, (STp->buffer)->b_data[9] * 65536 + (STp->buffer)->b_data[10] * 256 + (STp->buffer)->b_data[11]); - else if (cmd_in == MTSETDENSITY) + if (cmd_in == MTSETDENSITY || cmd_in == SET_DENS_AND_BLK) printk(ST_DEB_MSG "st%d: Setting density code to %x.\n", dev, (STp->buffer)->b_data[4]); - else + if (cmd_in == MTSETDRVBUFFER) printk(ST_DEB_MSG "st%d: Setting drive buffer code to %d.\n", dev, ((STp->buffer)->b_data[2] >> 4) & 7); } @@ -1960,9 +1983,9 @@ ioctl_result = st_int_ioctl(inode, file, MTFSF, 1); else if (cmd_in == MTFSFM) ioctl_result = st_int_ioctl(inode, file, MTBSF, 1); - else if (cmd_in == MTSETBLK) { - STp->block_size = arg; - if (arg != 0) + else if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) { + STp->block_size = arg & MT_ST_BLKSIZE_MASK; + if (STp->block_size != 0) (STp->buffer)->buffer_blocks = (STp->buffer)->buffer_size / STp->block_size; (STp->buffer)->buffer_bytes = (STp->buffer)->read_pointer = 0; @@ -1979,6 +2002,8 @@ STp->eof = ST_NOEOF; STp->eof_hit = 0; } + if (cmd_in == SET_DENS_AND_BLK) + STp->density = arg >> MT_ST_DENSITY_SHIFT; if (cmd_in == MTOFFL || cmd_in == MTUNLOAD) STp->rew_at_close = 0; else if (cmd_in == MTLOAD) @@ -2450,7 +2475,6 @@ tpnt->drv_buffer = 1; /* Try buffering if no mode sense */ tpnt->restr_dma = (SDp->host)->unchecked_isa_dma; tpnt->density = 0; - tpnt->do_read_ahead = ST_READ_AHEAD; tpnt->do_auto_lock = ST_AUTO_LOCK; tpnt->can_bsr = ST_IN_FILE_POS; tpnt->two_fm = ST_TWO_FM; @@ -2467,6 +2491,7 @@ tpnt->modes[i].defaults_for_writes = 0; tpnt->modes[i].do_async_writes = ST_ASYNC_WRITES; tpnt->modes[i].do_buffer_writes = ST_BUFFER_WRITES; + tpnt->modes[i].do_read_ahead = ST_READ_AHEAD; tpnt->modes[i].default_compression = ST_DONT_TOUCH; tpnt->modes[i].default_blksize = (-1); /* No forced size */ tpnt->modes[i].default_density = (-1); /* No forced density */ diff -u --recursive --new-file v1.3.93/linux/drivers/scsi/st.h linux/drivers/scsi/st.h --- v1.3.93/linux/drivers/scsi/st.h Mon Apr 8 19:01:44 1996 +++ linux/drivers/scsi/st.h Mon Apr 22 11:13:22 1996 @@ -31,6 +31,7 @@ unsigned char defined; unsigned char do_async_writes; unsigned char do_buffer_writes; + unsigned char do_read_ahead; unsigned char defaults_for_writes; unsigned char default_compression; /* 0 = don't touch, etc */ short default_density; /* Forced density, -1 = no value */ @@ -53,7 +54,7 @@ ST_buffer * buffer; /* Drive characteristics */ - unsigned char do_read_ahead; + unsigned char omit_blklims; unsigned char do_auto_lock; unsigned char can_bsr; unsigned char two_fm; diff -u --recursive --new-file v1.3.93/linux/drivers/scsi/wd33c93.c linux/drivers/scsi/wd33c93.c --- v1.3.93/linux/drivers/scsi/wd33c93.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/scsi/wd33c93.c Sun Mar 17 22:44:39 1996 @@ -0,0 +1,1339 @@ +/* + * wd33c93.c - Linux-68k device driver for the Commodore + * Amiga A2091/590 SCSI controller card + * + * Copyright (c) 1996 John Shifflett, GeoLog Consulting + * john@geolog.com + * jshiffle@netcom.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * + * Drew Eckhardt's excellent 'Generic NCR5380' sources from Linux-PC + * provided much of the inspiration and some of the code for this + * driver. Everything I know about Amiga DMA was gleaned from careful + * reading of Hamish Mcdonald's original wd33c93 driver; in fact, I + * borrowed shamelessly from all over that source. Thanks Hamish! + * + * _This_ driver is (I feel) an improvement over the old one in + * several respects: + * + * - Target Disconnection/Reconnection is now supported. Any + * system with more than one device active on the SCSI bus + * will benefit from this. + * + * - Synchronous data transfers are now supported. The driver + * automatically uses this faster protocol with any device + * able to handle it. + * + * - Runtime operating parameters can now be specified through + * either the 'amiboot' or the LILO command line. Something + * like: + * "wd33c93=0x0000" + * The value 0x0000 results in the defaults being used; bits + * are defined in wd33c93.h. + * + * - The old driver relied exclusively on what the Western Digital + * docs call "Combination Level 2 Commands", which are a great + * idea in that the CPU is relieved of a lot of interrupt + * overhead. However, by accepting a certain (user-settable) + * amount of additional interrupts, this driver achieves + * better control over the SCSI bus, and data transfers are + * almost as fast while being much easier to define, track, + * and debug. + * + * + * TODO: + * more speed. tagged queuing. + * + * + * People with bug reports, wish-lists, complaints, comments, + * or improvements are asked to pah-leeez email me (John Shifflett) + * at john@geolog.com or jshiffle@netcom.com! I'm anxious to get + * this thing into as good a shape as possible, and I'm positive + * there are lots of lurking bugs and "Stupid Places". + * + */ + +#include +#include +#include +#include +#include +#include "scsi.h" +#include "hosts.h" +#include "wd33c93.h" + + +#define SYNC_DEBUG + +#define DEBUGGING_ON + +#define WD33C93_VERSION "1.17" +#define WD33C93_DATE "06/Feb/1996" + +#ifdef DEBUGGING_ON +#define DB(f,a) if (hostdata->args & (f)) a; +#else +#define DB(f,a) +#endif + +#define IS_DIR_OUT(cmd) ((cmd)->cmnd[0] == WRITE_6 || \ + (cmd)->cmnd[0] == WRITE_10 || \ + (cmd)->cmnd[0] == WRITE_12) + + +/* + * setup_default is a bunch of bits that define some of the operating + * parameters and settings for this driver. It is used unless a LILO + * or insmod command line has been specified, in which case setup_default + * is _completely_ ignored. Take a look at the "defines for hostdata->args" + * section in wd33c93.h - that stuff is what you'd use here if you want + * to change the defaults. + */ + +static unsigned int setup_default = 0; + + +inline uchar read_wd33c93(wd33c93_regs *regp,uchar reg_num) +{ + regp->SASR = reg_num; + return(regp->SCMD); +} + + +#define READ_AUX_STAT() (regp->SASR) + + +inline void write_wd33c93(wd33c93_regs *regp,uchar reg_num, uchar value) +{ + regp->SASR = reg_num; + regp->SCMD = value; +} + + +inline void write_wd33c93_cmd(wd33c93_regs *regp, uchar cmd) +{ + regp->SASR = WD_COMMAND; + regp->SCMD = cmd; +} + + +inline uchar read_1_byte(wd33c93_regs *regp) +{ +uchar asr; +uchar x = 0; + + write_wd33c93(regp, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED); + write_wd33c93_cmd(regp, WD_CMD_TRANS_INFO|0x80); + do { + asr = READ_AUX_STAT(); + if (asr & ASR_DBR) + x = read_wd33c93(regp, WD_DATA); + } while (!(asr & ASR_INT)); + return x; +} + + +void write_wd33c93_count(wd33c93_regs *regp,unsigned long value) +{ + regp->SASR = WD_TRANSFER_COUNT_MSB; + regp->SCMD = value >> 16; + regp->SCMD = value >> 8; + regp->SCMD = value; +} + + +unsigned long read_wd33c93_count(wd33c93_regs *regp) +{ +unsigned long value; + + regp->SASR = WD_TRANSFER_COUNT_MSB; + value = regp->SCMD << 16; + value |= regp->SCMD << 8; + value |= regp->SCMD; + return value; +} + + + +static struct sx_period sx_table[] = { + { 1, 0x20}, + {252, 0x20}, + {376, 0x30}, + {500, 0x40}, + {624, 0x50}, + {752, 0x60}, + {876, 0x70}, + {1000,0x00}, + {0, 0} }; + +uchar calc_sync_xfer(unsigned int period, unsigned int offset) +{ +uchar result; +int x; + + period *= 4; /* convert SDTR code to ns */ + result = 0x00; + for (x=1; sx_table[x].period_ns; x++) { + if ((period <= sx_table[x-0].period_ns) && + (period > sx_table[x-1].period_ns)) { + result = sx_table[x].reg_value; + break; + } + } + result |= (offset < OPTIMUM_SX_OFF)?offset:OPTIMUM_SX_OFF; + return result; +} + + + +static void wd33c93_execute(struct Scsi_Host *instance); + +int wd33c93_queuecommand (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) +{ +struct WD33C93_hostdata *hostdata; +Scsi_Cmnd *tmp; +unsigned long flags; + + hostdata = (struct WD33C93_hostdata *)cmd->host->hostdata; + +DB(DB_QUEUE_COMMAND,printk("Q-%d-%02x-%ld( ",cmd->target,cmd->cmnd[0],cmd->pid)) + + +/* + * Set up a few fields in the Scsi_Cmnd structure for our own use: + * - host_scribble is the pointer to the next cmd in the input queue + * - scsi_done points to the routine we call when a cmd is finished + * - result is what you'd expect + */ + + cmd->host_scribble = NULL; + cmd->scsi_done = done; + cmd->result = 0; + +/* We use the Scsi_Pointer structure that's included with each command + * as a scratchpad (as it's intended to be used!). The handy thing about + * the SCp.xxx fields is that they're always associated with a given + * cmd, and are preserved across disconnect-reselect. This means we + * can pretty much ignore SAVE_POINTERS and RESTORE_POINTERS messages + * if we keep all the critical pointers and counters in SCp: + * - SCp.ptr is the pointer into the RAM buffer + * - SCp.this_residual is the size of that buffer + * - SCp.buffer points to the current scatter-gather buffer + * - SCp.buffers_residual tells us how many S.G. buffers there are + */ + + if (cmd->use_sg) { + cmd->SCp.buffer = (struct scatterlist *)cmd->buffer; + cmd->SCp.buffers_residual = cmd->use_sg - 1; + cmd->SCp.ptr = (char *)cmd->SCp.buffer->address; + cmd->SCp.this_residual = cmd->SCp.buffer->length; + } + else { + cmd->SCp.buffer = NULL; + cmd->SCp.buffers_residual = 0; + cmd->SCp.ptr = (char *)cmd->request_buffer; + cmd->SCp.this_residual = cmd->request_bufflen; + } + +/* Preset the command status to GOOD, since that's the normal case */ + + cmd->SCp.Status = GOOD; + + /* + * Add the cmd to the end of 'input_Q'. Note that REQUEST SENSE + * commands are added to the head of the queue so that the desired + * sense data is not lost before REQUEST_SENSE executes. + */ + + save_flags(flags); + cli(); + if (!(hostdata->input_Q) || (cmd->cmnd[0] == REQUEST_SENSE)) { + cmd->host_scribble = (uchar *)hostdata->input_Q; + hostdata->input_Q = cmd; + } + else { + for (tmp=(Scsi_Cmnd *)hostdata->input_Q; tmp->host_scribble; + tmp=(Scsi_Cmnd *)tmp->host_scribble) + ; + tmp->host_scribble = (uchar *)cmd; + } + restore_flags(flags); + +/* We know that there's at least one command in 'input_Q' now. + * Go see if any of them are runnable! + */ + + wd33c93_execute(cmd->host); + +DB(DB_QUEUE_COMMAND,printk(")Q-%d-%02x-%ld ",cmd->target,cmd->cmnd[0],cmd->pid)) + return 0; +} + + + +/* + * This routine attempts to start a scsi command. If the host_card is + * already connected, we give up immediately. Otherwise, look through + * the input_Q, using the first command we find that's intended + * for a currently non-busy target/lun. + */ +static void wd33c93_execute (struct Scsi_Host *instance) +{ +struct WD33C93_hostdata *hostdata; +wd33c93_regs *regp; +Scsi_Cmnd *cmd, *prev; +unsigned long flags; +int i; + + + save_flags(flags); + cli(); + hostdata = (struct WD33C93_hostdata *)instance->hostdata; + regp = hostdata->regp; + +DB(DB_EXECUTE,printk("EX( ")) + + if (hostdata->selecting || hostdata->connected) { +DB(DB_EXECUTE,printk(")EX-0 ")) + restore_flags(flags); + return; + } + + /* + * Search through the input_Q for a command destined + * for an idle target/lun. + */ + + cmd = (Scsi_Cmnd *)hostdata->input_Q; + prev = 0; + while (cmd) { + if (!(hostdata->busy[cmd->target] & (1 << cmd->lun))) + break; + prev = cmd; + cmd = (Scsi_Cmnd *)cmd->host_scribble; + } + + /* quit if queue empty or all possible targets are busy */ + + if (!cmd) { +DB(DB_EXECUTE,printk(")EX-1 ")) + restore_flags(flags); + return; + } + + /* remove command from queue, put it in selecting */ + + if (prev) + prev->host_scribble = cmd->host_scribble; + else + hostdata->input_Q = (Scsi_Cmnd *)cmd->host_scribble; + hostdata->selecting = cmd; + + /* + * Start the selection process + */ + + if (IS_DIR_OUT(cmd)) + write_wd33c93(regp, WD_DESTINATION_ID, cmd->target); + else + write_wd33c93(regp, WD_DESTINATION_ID, cmd->target | DSTID_DPD); + + write_wd33c93(regp, WD_TARGET_LUN, cmd->lun); + write_wd33c93(regp, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED); + write_wd33c93_count(regp, 0); /* this guarantees a DATA_PHASE interrupt */ + hostdata->busy[cmd->target] |= (1 << cmd->lun); + + if ((hostdata->level2 == L2_NONE) || + (hostdata->sync_stat[cmd->target] == SS_UNSET)) { + + /* + * Now do a 'Select-With-ATN' command. This will end with + * one of the following interrupts: + * CSR_RESEL_AM: failure - can try again later. + * CSR_TIMEOUT: failure - give up. + * CSR_SELECT: success - proceed. + */ + +/* Every target has its own synchronous transfer setting, kept in the + * sync_xfer array, and a corresponding status byte in sync_stat[]. + * Each target's sync_stat[] entry is initialized to SX_UNSET, and its + * sync_xfer[] entry is initialized to the default/safe value. SS_UNSET + * means that the parameters are undetermined as yet, and that we + * need to send an SDTR message to this device after selection is + * complete. We set SS_FIRST to tell the interrupt routine to do so, + * unless we've been asked not to try synchronous transfers on this + * target (and _all_ luns within it): In this case we set SS_SET to + * make the defaults final. + */ + if (hostdata->sync_stat[cmd->target] == SS_UNSET) { + if (hostdata->args & (1 << cmd->target)) + hostdata->sync_stat[cmd->target] = SS_SET; + else + hostdata->sync_stat[cmd->target] = SS_FIRST; + } + hostdata->state = S_SELECTING; + write_wd33c93_cmd(regp, WD_CMD_SEL_ATN); + } + + else { + + /* + * Now do a 'Select-With-ATN-Xfer' command. This will end with + * one of the following interrupts: + * CSR_RESEL_AM: failure - can try again later. + * CSR_TIMEOUT: failure - give up. + * anything else: success - proceed. + */ + + hostdata->connected = cmd; + hostdata->selecting = NULL; + write_wd33c93(regp, WD_COMMAND_PHASE, 0); + + /* copy command_descriptor_block into WD chip */ + + for (i=0; icmd_len; i++) + write_wd33c93(regp, WD_CDB_1+i, cmd->cmnd[i]); + + /* The wd33c93 only knows about Group 0, 1, and 5 commands when + * it's doing a 'select-and-transfer'. To be safe, we write the + * size of the CDB into the OWN_ID register for every case. This + * way there won't be problems with vendor-unique, audio, etc. + */ + + write_wd33c93(regp, WD_OWN_ID, cmd->cmd_len); + + hostdata->state = S_RUNNING_LEVEL2; + write_wd33c93_cmd(regp, WD_CMD_SEL_ATN_XFER); + } + + /* + * Since the SCSI bus can handle only 1 connection at a time, + * we get out of here now. If the selection fails, or when + * the command disconnects, we'll come back to this routine + * to search the input_Q again... + */ + +DB(DB_EXECUTE,printk(")EX-2 ")) + restore_flags(flags); +} + + + +void transfer_pio(wd33c93_regs *regp, uchar **buf, int *cnt, + int data_in_dir, struct WD33C93_hostdata *hostdata) +{ +uchar *b, asr; +int c; + + write_wd33c93(regp, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED); + b = *buf; + c = *cnt; +DB(DB_TRANSFER_DATA,printk("[[%p/%d]]",b,c)) + write_wd33c93_count(regp,c); + write_wd33c93_cmd(regp, WD_CMD_TRANS_INFO); + if (data_in_dir) { + do { + asr = READ_AUX_STAT(); + if (asr & ASR_DBR) + *b++ = read_wd33c93(regp, WD_DATA); + } while (!(asr & ASR_INT)); + } + else { + do { + asr = READ_AUX_STAT(); + if (asr & ASR_DBR) + write_wd33c93(regp, WD_DATA, *b++); + } while (!(asr & ASR_INT)); + } + +/* update original buffer pointer and original count */ + + *cnt = read_wd33c93_count(regp); + if (data_in_dir) + *buf = b; + else + *buf += (c - *cnt); + + /* Note: we are returning with the interrupt UN-cleared. + * Since (presumably) an entire I/O operation has + * completed, the bus phase is probably different, and + * the interrupt routine will discover this when it + * responds to the uncleared int. + */ + +} + + + +void transfer_bytes(wd33c93_regs *regp, Scsi_Cmnd *cmd, int data_in_dir) +{ +struct WD33C93_hostdata *hostdata; + + hostdata = (struct WD33C93_hostdata *)cmd->host->hostdata; + +/* Normally, you'd expect 'this_residual' to be non-zero here. + * In a series of scatter-gather transfers, however, this + * routine will usually be called with 'this_residual' equal + * to 0 and 'buffers_residual' non-zero. This means that a + * previous transfer completed, clearing 'this_residual', and + * now we need to setup the next scatter-gather buffer as the + * source or destination for THIS transfer. + */ + if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) { + ++cmd->SCp.buffer; + --cmd->SCp.buffers_residual; + cmd->SCp.this_residual = cmd->SCp.buffer->length; + cmd->SCp.ptr = cmd->SCp.buffer->address; + } + + write_wd33c93(regp,WD_SYNCHRONOUS_TRANSFER,hostdata->sync_xfer[cmd->target]); + +/* 'dma_setup()' will return TRUE if we can't do DMA. */ + + if (hostdata->dma_setup(cmd, data_in_dir)) { + transfer_pio(regp, (uchar **)&cmd->SCp.ptr, &cmd->SCp.this_residual, + data_in_dir, hostdata); + } + +/* We are able to do DMA (in fact, the Amiga hardware is + * already going!), so start up the wd33c93 in DMA mode. + * We set 'hostdata->dma' = D_DMA_RUNNING so that when the + * transfer completes and causes an interrupt, we're + * reminded to tell the Amiga to shut down its end. We'll + * postpone the updating of 'this_residual' and 'ptr' + * until then. + */ + + else { + write_wd33c93(regp, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_DMA); +DB(DB_TRANSFER_DATA,printk("[%p/%d]",cmd->SCp.ptr,cmd->SCp.this_residual)) + write_wd33c93_count(regp,cmd->SCp.this_residual); + + if (hostdata->level2 >= L2_DATA) { + write_wd33c93(regp, WD_COMMAND_PHASE, 0x41); + write_wd33c93_cmd(regp, WD_CMD_SEL_ATN_XFER); + hostdata->state = S_RUNNING_LEVEL2; + } + else + write_wd33c93_cmd(regp, WD_CMD_TRANS_INFO); + + hostdata->dma = D_DMA_RUNNING; + } +} + + + +void wd33c93_intr (struct Scsi_Host *instance) +{ +struct WD33C93_hostdata *hostdata; +Scsi_Cmnd *patch, *cmd; +wd33c93_regs *regp; +uchar asr, sr, phs, id, lun, *ucp, msg; +unsigned long length; +int i; + + + hostdata = (struct WD33C93_hostdata *)instance->hostdata; + regp = hostdata->regp; + + asr = READ_AUX_STAT(); + if (!(asr & ASR_INT) || (asr & ASR_BSY)) + return; + + cmd = (Scsi_Cmnd *)hostdata->connected; /* assume we're connected */ + sr = read_wd33c93(regp, WD_SCSI_STATUS); /* clear the interrupt */ + phs = read_wd33c93(regp, WD_COMMAND_PHASE); + +DB(DB_INTR,printk("{%02x:%02x-",asr,sr)) + +/* After starting a DMA transfer, the next interrupt + * is guaranteed to be in response to completion of + * the transfer. Since the Amiga DMA hardware runs in + * in an open-ended fashion, it needs to be told when + * to stop; do that here if D_DMA_RUNNING is true. + * Also, we have to update 'this_residual' and 'ptr' + * based on the contents of the TRANSFER_COUNT register, + * in case the device decided to do an intermediate + * disconnect (a device may do this if it has to do a + * seek, or just to be nice and let other devices have + * some bus time during long transfers). After doing + * whatever is needed, we go on and service the WD3393 + * interrupt normally. + */ + + if (hostdata->dma == D_DMA_RUNNING) { +DB(DB_TRANSFER_DATA,printk("[%p/%d:",cmd->SCp.ptr,cmd->SCp.this_residual)) + hostdata->dma_stop(cmd->host, cmd, 1); + hostdata->dma = D_DMA_OFF; + length = cmd->SCp.this_residual; + cmd->SCp.this_residual = read_wd33c93_count(regp); + cmd->SCp.ptr += (length - cmd->SCp.this_residual); +DB(DB_TRANSFER_DATA,printk("%p/%d]",cmd->SCp.ptr,cmd->SCp.this_residual)) + } + +/* Respond to the specific WD3393 interrupt - there are quite a few! */ + + switch (sr) { + + case CSR_TIMEOUT: + cli(); +DB(DB_INTR,printk("TIMEOUT")) + if (hostdata->state == S_RUNNING_LEVEL2) { + hostdata->connected = NULL; + hostdata->busy[cmd->target] &= ~(1 << cmd->lun); + } + else { + cmd = (Scsi_Cmnd *)hostdata->selecting; /* get a valid cmd */ + hostdata->selecting = NULL; + } + + cmd->result = DID_NO_CONNECT << 16; + hostdata->selecting = NULL; + hostdata->state = S_UNCONNECTED; + cmd->scsi_done(cmd); /* I think scsi_done() enables ints */ + +/* We are not connected to a target - check to see if there + * are commands waiting to be executed. + */ + + wd33c93_execute(instance); + break; + + +/* Note: this interrupt should not occur in a LEVEL2 command */ + + case CSR_SELECT: + cli(); +DB(DB_INTR,printk("SELECT")) + hostdata->connected = cmd = (Scsi_Cmnd *)hostdata->selecting; + hostdata->selecting = NULL; + + /* construct an IDENTIFY message with correct disconnect bit */ + + if (hostdata->args & A_NO_DISCONNECT) + hostdata->outgoing_msg[0] = (0x80 | cmd->lun); + else + hostdata->outgoing_msg[0] = (0x80 | 0x40 | cmd->lun); + + if (hostdata->sync_stat[cmd->target] == SS_FIRST) { +#ifdef SYNC_DEBUG +printk(" sending SDTR "); +#endif + + hostdata->sync_stat[cmd->target] = SS_WAITING; + + /* tack on a 2nd message to ask about synchronous transfers */ + + hostdata->outgoing_msg[1] = EXTENDED_MESSAGE; + hostdata->outgoing_msg[2] = 3; + hostdata->outgoing_msg[3] = EXTENDED_SDTR; + hostdata->outgoing_msg[4] = OPTIMUM_SX_PER/4; + hostdata->outgoing_msg[5] = OPTIMUM_SX_OFF; + hostdata->outgoing_len = 6; + } + else + hostdata->outgoing_len = 1; + + hostdata->state = S_CONNECTED; + break; + + + case CSR_XFER_DONE|PHS_DATA_IN: + case CSR_UNEXP |PHS_DATA_IN: + case CSR_SRV_REQ |PHS_DATA_IN: +DB(DB_INTR,printk("IN-%d.%d",cmd->SCp.this_residual,cmd->SCp.buffers_residual)) + transfer_bytes(regp, cmd, DATA_IN_DIR); + if (hostdata->state != S_RUNNING_LEVEL2) + hostdata->state = S_CONNECTED; + break; + + + case CSR_XFER_DONE|PHS_DATA_OUT: + case CSR_UNEXP |PHS_DATA_OUT: + case CSR_SRV_REQ |PHS_DATA_OUT: +DB(DB_INTR,printk("OUT-%d.%d",cmd->SCp.this_residual,cmd->SCp.buffers_residual)) + transfer_bytes(regp, cmd, DATA_OUT_DIR); + if (hostdata->state != S_RUNNING_LEVEL2) + hostdata->state = S_CONNECTED; + break; + + +/* Note: this interrupt should not occur in a LEVEL2 command */ + + case CSR_XFER_DONE|PHS_COMMAND: + case CSR_SRV_REQ |PHS_COMMAND: +DB(DB_INTR,printk("CMND-%02x,%ld",cmd->cmnd[0],cmd->pid)) + ucp = cmd->cmnd; + i = cmd->cmd_len; + transfer_pio(regp, &ucp, &i, DATA_OUT_DIR, hostdata); + hostdata->state = S_CONNECTED; + break; + + + case CSR_XFER_DONE|PHS_STATUS: + case CSR_UNEXP |PHS_STATUS: + case CSR_SRV_REQ |PHS_STATUS: +DB(DB_INTR,printk("STATUS")) + + cmd->SCp.Status = read_1_byte(regp); + if (hostdata->level2 >= L2_BASIC) { + sr = read_wd33c93(regp, WD_SCSI_STATUS); /* clear interrupt */ + hostdata->state = S_RUNNING_LEVEL2; + write_wd33c93(regp, WD_COMMAND_PHASE, 0x50); + write_wd33c93_cmd(regp, WD_CMD_SEL_ATN_XFER); + } + else { +DB(DB_INTR,printk("=%02x",cmd->SCp.Status)) + hostdata->state = S_CONNECTED; + } + break; + + + case CSR_XFER_DONE|PHS_MESS_IN: + case CSR_UNEXP |PHS_MESS_IN: + case CSR_SRV_REQ |PHS_MESS_IN: +DB(DB_INTR,printk("MSG_IN=")) + + msg = read_1_byte(regp); + sr = read_wd33c93(regp, WD_SCSI_STATUS); /* clear interrupt */ + + hostdata->incoming_msg[hostdata->incoming_ptr] = msg; + if (hostdata->incoming_msg[0] == EXTENDED_MESSAGE) + msg = EXTENDED_MESSAGE; + else + hostdata->incoming_ptr = 0; + + cmd->SCp.Message = msg; + switch (msg) { + + case COMMAND_COMPLETE: +DB(DB_INTR,printk("CCMP-%ld",cmd->pid)) + write_wd33c93_cmd(regp,WD_CMD_NEGATE_ACK); + hostdata->state = S_PRE_CMP_DISC; + break; + + case SAVE_POINTERS: +DB(DB_INTR,printk("SDP")) + write_wd33c93_cmd(regp,WD_CMD_NEGATE_ACK); + hostdata->state = S_CONNECTED; + break; + + case RESTORE_POINTERS: +DB(DB_INTR,printk("RDP")) + + if (hostdata->level2 >= L2_BASIC) { + write_wd33c93(regp, WD_COMMAND_PHASE, 0x45); + write_wd33c93_cmd(regp, WD_CMD_SEL_ATN_XFER); + hostdata->state = S_RUNNING_LEVEL2; + } + else { + write_wd33c93_cmd(regp, WD_CMD_NEGATE_ACK); + hostdata->state = S_CONNECTED; + } + break; + + case DISCONNECT: +DB(DB_INTR,printk("DIS")) + cmd->device->disconnect = 1; + write_wd33c93_cmd(regp,WD_CMD_NEGATE_ACK); + hostdata->state = S_PRE_TMP_DISC; + break; + + case MESSAGE_REJECT: +DB(DB_INTR,printk("REJ")) +#ifdef SYNC_DEBUG +printk("-REJ-"); +#endif + if (hostdata->sync_stat[cmd->target] == SS_WAITING) + hostdata->sync_stat[cmd->target] = SS_SET; + write_wd33c93_cmd(regp,WD_CMD_NEGATE_ACK); + hostdata->state = S_CONNECTED; + break; + + case EXTENDED_MESSAGE: +DB(DB_INTR,printk("EXT")) + + ucp = hostdata->incoming_msg; + +#ifdef SYNC_DEBUG +printk("%02x",ucp[hostdata->incoming_ptr]); +#endif + /* Is this the last byte of the extended message? */ + + if ((hostdata->incoming_ptr >= 2) && + (hostdata->incoming_ptr == (ucp[1] + 1))) { + + switch (ucp[2]) { /* what's the EXTENDED code? */ + case EXTENDED_SDTR: + id = calc_sync_xfer(ucp[3],ucp[4]); + if (hostdata->sync_stat[cmd->target] != SS_WAITING) { + printk("Rejecting target's SDTR message "); + write_wd33c93_cmd(regp,WD_CMD_ASSERT_ATN); /* want MESS_OUT */ + hostdata->outgoing_msg[0] = MESSAGE_REJECT; + hostdata->outgoing_len = 1; + } + else { + hostdata->sync_xfer[cmd->target] = id; + hostdata->sync_stat[cmd->target] = SS_SET; + } +#ifdef SYNC_DEBUG +printk("sync_xfer=%02x",id); +#endif + write_wd33c93_cmd(regp,WD_CMD_NEGATE_ACK); + hostdata->state = S_CONNECTED; + break; + default: + printk("Rejecting Unknown Extended Message(%02x). ",ucp[2]); + write_wd33c93_cmd(regp,WD_CMD_ASSERT_ATN); /* want MESS_OUT */ + hostdata->outgoing_msg[0] = MESSAGE_REJECT; + hostdata->outgoing_len = 1; + write_wd33c93_cmd(regp,WD_CMD_NEGATE_ACK); + hostdata->state = S_CONNECTED; + break; + } + hostdata->incoming_ptr = 0; + } + + /* We need to read more MESS_IN bytes for the extended message */ + + else { + hostdata->incoming_ptr++; + write_wd33c93_cmd(regp,WD_CMD_NEGATE_ACK); + hostdata->state = S_CONNECTED; + } + break; + + default: + printk("Rejecting Unknown Message(%02x) ",ucp[0]); + write_wd33c93_cmd(regp,WD_CMD_ASSERT_ATN); /* want MESS_OUT */ + hostdata->outgoing_msg[0] = MESSAGE_REJECT; + hostdata->outgoing_len = 1; + write_wd33c93_cmd(regp,WD_CMD_NEGATE_ACK); + hostdata->state = S_CONNECTED; + } + break; + + +/* Note: this interrupt will occur only after a LEVEL2 command */ + + case CSR_SEL_XFER_DONE: + cli(); + if (phs == 0x60) { +DB(DB_INTR,printk("SX-DONE-%ld",cmd->pid)) + cmd->SCp.Message = COMMAND_COMPLETE; + lun = read_wd33c93(regp, WD_TARGET_LUN); + if (cmd->SCp.Status == GOOD) + cmd->SCp.Status = lun; + hostdata->connected = NULL; + if (cmd->cmnd[0] != REQUEST_SENSE) + cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); + else if (cmd->SCp.Status != GOOD) + cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16); + hostdata->busy[cmd->target] &= ~(1 << cmd->lun); + hostdata->state = S_UNCONNECTED; + cmd->scsi_done(cmd); /* I think scsi_done() enables ints */ + +/* We are no longer connected to a target - check to see if + * there are commands waiting to be executed. + */ + + wd33c93_execute(instance); + } + else { + printk("%02x:%02x:%02x-%ld: Unknown SEL_XFER_DONE phase!!---",asr,sr,phs,cmd->pid); + } + break; + + +/* Note: this interrupt will occur only after a LEVEL2 command */ + + case CSR_SDP: +DB(DB_INTR,printk("SDP")) + hostdata->state = S_RUNNING_LEVEL2; + write_wd33c93(regp, WD_COMMAND_PHASE, 0x41); + write_wd33c93_cmd(regp, WD_CMD_SEL_ATN_XFER); + break; + + + case CSR_XFER_DONE|PHS_MESS_OUT: + case CSR_UNEXP |PHS_MESS_OUT: + case CSR_SRV_REQ |PHS_MESS_OUT: +DB(DB_INTR,printk("MSG_OUT=")) + +/* To get here, we've probably requested MESSAGE_OUT and have + * already put the correct bytes in outgoing_msg[] and filled + * in outgoing_len. We simply send them out to the SCSI bus. + * Sometimes we get MESSAGE_OUT phase when we're not expecting + * it - like when our SDTR message is rejected by a target. Some + * targets send the REJECT before receiving all of the extended + * message, and then seem to go back to MESSAGE_OUT for a byte + * or two. Not sure why, ot if I'm doing something wrong to + * casue this to happen. Regardless, it seems that sending + * NOP messages in these situations results in no harm and + * makes everyone happy. + */ + + if (hostdata->outgoing_len == 0) { + hostdata->outgoing_len = 1; + hostdata->outgoing_msg[0] = NOP; + } + ucp = hostdata->outgoing_msg; + i = hostdata->outgoing_len; + transfer_pio(regp, &ucp, &i, DATA_OUT_DIR, hostdata); +DB(DB_INTR,printk("%02x",hostdata->outgoing_msg[0])) + hostdata->outgoing_len = 0; + hostdata->state = S_CONNECTED; + break; + + + case CSR_DISC: +DB(DB_INTR,printk("DISC")) + if (cmd == NULL) { + printk(" - Already disconnected! "); + hostdata->state = S_UNCONNECTED; + return; + } + switch (hostdata->state) { + case S_PRE_CMP_DISC: + hostdata->connected = NULL; + hostdata->busy[cmd->target] &= ~(1 << cmd->lun); + hostdata->state = S_UNCONNECTED; + if (cmd->cmnd[0] != REQUEST_SENSE) + cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); + else if (cmd->SCp.Status != GOOD) + cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16); + cmd->scsi_done(cmd); /* I think scsi_done() enables ints */ + break; + case S_PRE_TMP_DISC: + case S_RUNNING_LEVEL2: + cmd->host_scribble = (uchar *)hostdata->disconnected_Q; + hostdata->disconnected_Q = cmd; + hostdata->connected = NULL; + hostdata->state = S_UNCONNECTED; + break; + default: + printk("*** Unexpected DISCONNECT interrupt! ***"); + hostdata->state = S_UNCONNECTED; + } + +/* We are no longer connected to a target - check to see if + * there are commands waiting to be executed. + */ + + wd33c93_execute(instance); + break; + + + case CSR_RESEL_AM: +DB(DB_INTR,printk("RESEL")) + + cli(); + + /* First we have to make sure this reselection didn't */ + /* happen during Arbitration/Selection of some other device. */ + /* If yes, put losing command back on top of input_Q. */ + + if (hostdata->level2 == L2_NONE) { + + if (hostdata->selecting) { + cmd = (Scsi_Cmnd *)hostdata->selecting; + hostdata->selecting = NULL; + hostdata->busy[cmd->target] &= ~(1 << cmd->lun); + cmd->host_scribble = (uchar *)hostdata->input_Q; + hostdata->input_Q = cmd; + } + } + + else { + + if (cmd) { + if (phs == 0x00) { + hostdata->busy[cmd->target] &= ~(1 << cmd->lun); + cmd->host_scribble = (uchar *)hostdata->input_Q; + hostdata->input_Q = cmd; + } + else { + printk("---%02x:%02x:%02x-TROUBLE: Intrusive ReSelect!---",asr,sr,phs); + while (1) + printk("\r"); + } + } + + } + + /* OK - find out which device reslected us. */ + + id = read_wd33c93(regp, WD_SOURCE_ID); + id &= SRCID_MASK; + + /* and extract the lun from the ID message. (Note that we don't + * bother to check for a valid message here - I guess this is + * not the right way to go, but...) + */ + + lun = read_wd33c93(regp, WD_DATA); + if (hostdata->level2 < L2_RESELECT) + write_wd33c93_cmd(regp,WD_CMD_NEGATE_ACK); + lun &= 7; + + /* Now we look for the command that's reconnecting. */ + + cmd = (Scsi_Cmnd *)hostdata->disconnected_Q; + patch = NULL; + while (cmd) { + if (id == cmd->target && lun == cmd->lun) + break; + patch = cmd; + cmd = (Scsi_Cmnd *)cmd->host_scribble; + } + + /* Hmm. Couldn't find a valid command.... What to do? */ + + if (!cmd) { + printk("---TROUBLE: target %d.%d not in disconnect queue---",id,lun); + return; + } + + /* Ok, found the command - now start it up again. */ + + if (patch) + patch->host_scribble = cmd->host_scribble; + else + hostdata->disconnected_Q = (Scsi_Cmnd *)cmd->host_scribble; + hostdata->connected = cmd; + + /* We don't need to worry about 'initialize_SCp()' or 'hostdata->busy[]' + * because these things are preserved over a disconnect. + * But we DO need to fix the DPD bit so it's correct for this command. + */ + + if (IS_DIR_OUT(cmd)) + write_wd33c93(regp, WD_DESTINATION_ID, cmd->target); + else + write_wd33c93(regp, WD_DESTINATION_ID, cmd->target | DSTID_DPD); + if (hostdata->level2 >= L2_RESELECT) { + write_wd33c93_count(regp, 0); /* we want a DATA_PHASE interrupt */ + write_wd33c93(regp, WD_COMMAND_PHASE, 0x45); + write_wd33c93_cmd(regp, WD_CMD_SEL_ATN_XFER); + hostdata->state = S_RUNNING_LEVEL2; + } + else + hostdata->state = S_CONNECTED; + +DB(DB_INTR,printk("-%ld",cmd->pid)) + break; + + default: + printk("\n---UNKNOWN INTERRUPT:%02x:%02x:%02x!!---",asr,sr,phs); + } + +DB(DB_INTR,printk("} ")) + +} + + + +void reset_wd33c93(struct Scsi_Host *instance) +{ +struct WD33C93_hostdata *hostdata; +wd33c93_regs *regp; +uchar sr; + + hostdata = (struct WD33C93_hostdata *)instance->hostdata; + regp = hostdata->regp; + + write_wd33c93(regp, WD_OWN_ID, OWNID_EAF | OWNID_RAF | + instance->this_id | hostdata->clock_freq); + write_wd33c93(regp, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED); + write_wd33c93(regp, WD_SYNCHRONOUS_TRANSFER, + calc_sync_xfer(DEFAULT_SX_PER/4,DEFAULT_SX_OFF)); + write_wd33c93(regp, WD_COMMAND, WD_CMD_RESET); + + while (!(READ_AUX_STAT() & ASR_INT)) + ; + sr = read_wd33c93(regp, WD_SCSI_STATUS); + + hostdata->microcode = read_wd33c93(regp, WD_CDB_1); + if (sr == 0x00) + hostdata->chip = C_WD33C93; + else if (sr == 0x01) { + write_wd33c93(regp, WD_QUEUE_TAG, 0xa5); /* any random number */ + sr = read_wd33c93(regp, WD_QUEUE_TAG); + if (sr == 0xa5) { + hostdata->chip = C_WD33C93B; + write_wd33c93(regp, WD_QUEUE_TAG, 0); + } + else + hostdata->chip = C_WD33C93A; + } + else + hostdata->chip = C_UNKNOWN_CHIP; + + write_wd33c93(regp, WD_TIMEOUT_PERIOD, TIMEOUT_PERIOD_VALUE); + if (hostdata->args & A_NO_DISCONNECT) + write_wd33c93(regp, WD_SOURCE_ID, 0); + else + write_wd33c93(regp, WD_SOURCE_ID, SRCID_ER); + write_wd33c93(regp, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED); +} + + + +int wd33c93_reset(Scsi_Cmnd *SCpnt) +{ +unsigned long flags; +struct Scsi_Host *instance; + + instance = SCpnt->host; + + printk("scsi%d: reset. ", instance->host_no); + save_flags(flags); + cli(); + ((struct WD33C93_hostdata *)instance->hostdata)->dma_stop(instance,NULL,0); + reset_wd33c93(instance); + SCpnt->result = DID_RESET << 16; + restore_flags(flags); + return 0; +} + + + +int wd33c93_abort (Scsi_Cmnd *cmd) +{ +struct Scsi_Host *instance; +struct WD33C93_hostdata *hostdata; +wd33c93_regs *regp; +Scsi_Cmnd *tmp, **prev; +unsigned long flags; + + instance = cmd->host; + hostdata = (struct WD33C93_hostdata *)instance->hostdata; + regp = hostdata->regp; + + printk ("scsi%d: abort. ", instance->host_no); + + save_flags (flags); + cli(); + +/* + * Case 1 : If the command hasn't been issued yet, we simply remove it + * from the issue queue. + */ + for (prev=(Scsi_Cmnd **)&(hostdata->input_Q),tmp=(Scsi_Cmnd *)hostdata->input_Q; + tmp; + prev=(Scsi_Cmnd **)&(tmp->host_scribble),tmp=(Scsi_Cmnd *)tmp->host_scribble) + if (cmd == tmp) { + (*prev) = (Scsi_Cmnd *)tmp->host_scribble; + tmp->host_scribble = NULL; + tmp->result = DID_ABORT << 16; + restore_flags(flags); + printk("scsi%d : abort removed command from issue queue. ", + instance->host_no); + tmp->scsi_done(tmp); + return SCSI_ABORT_SUCCESS; + } + +/* + * Case 2 : If any commands are connected, we're going to fail the abort + * and let the high level SCSI driver retry at a later time or + * issue a reset. + * + * Timeouts, and therefore aborted commands, will be highly unlikely + * and handling them cleanly in this situation would make the common + * case of noresets less efficient, and would pollute our code. So, + * we fail. + */ + + if (hostdata->connected == cmd) { + uchar sr, asr; + unsigned long timeout; + + printk("scsi%d : aborting connected command. ", instance->host_no); + + if (hostdata->dma == D_DMA_RUNNING) { + hostdata->dma_stop(instance, cmd, 0); + hostdata->dma = D_DMA_OFF; + } + + printk("scsi%d : wd33c93 asr is %x. ", instance->host_no, READ_AUX_STAT()); + + write_wd33c93(regp, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED); + write_wd33c93_cmd(regp, WD_CMD_ABORT); + +/* Now we have to attempt to flush out the FIFO... */ + + timeout = 1000000; + do { + asr = READ_AUX_STAT(); + if (asr & ASR_DBR) + read_wd33c93(regp, WD_DATA); + } while (!(asr & ASR_INT) && timeout-- > 0); + sr = read_wd33c93(regp, WD_SCSI_STATUS); + printk("scsi%d : wd33c93 sr is %x. ", instance->host_no, + read_wd33c93(regp, WD_SCSI_STATUS)); + + if (sr >= (CSR_ABORT|PHS_DATA_OUT) && sr <= (CSR_ABORT|PHS_MESS_IN)) { + /* + * Abort command processed. + * Still connected. + * We must disconnect. + */ + printk("scsi%d : count was %ld. ", instance->host_no, + read_wd33c93_count(regp)); + + timeout = 1000000; + while ((asr & ASR_CIP) && timeout-- > 0) + asr = READ_AUX_STAT(); + write_wd33c93_cmd(regp, WD_CMD_DISCONNECT); + asr = READ_AUX_STAT(); + if (asr & ASR_LCI) + printk ("scsi%d: disconnect command ignored. ", + instance->host_no); + timeout = 1000000; + while ((asr & ASR_CIP) && timeout-- > 0) + asr = READ_AUX_STAT(); + } + asr = READ_AUX_STAT(); + sr = read_wd33c93(regp, WD_SCSI_STATUS); + printk("scsi%d : asr is %x, sr is %x. ",instance->host_no,asr,sr); + write_wd33c93_cmd(regp, WD_CMD_DISCONNECT); + timeout = 1000000; + while ((asr & ASR_CIP) && timeout-- > 0) + asr = READ_AUX_STAT(); + sr = read_wd33c93(regp, WD_SCSI_STATUS); + printk("scsi%d : asr is %x, sr is %x. ",instance->host_no,asr,sr); + reset_wd33c93(instance); + cmd->result = DID_ABORT << 16; + cmd->scsi_done(cmd); + hostdata->busy[cmd->target] &= ~(1 << cmd->lun); + hostdata->connected = NULL; + hostdata->state = S_UNCONNECTED; + wd33c93_execute (instance); + restore_flags(flags); + return SCSI_ABORT_SUCCESS; + } + +/* + * Case 3: If the command is currently disconnected from the bus, + * we're not going to expend much effort here: Let's just return + * an ABORT_SNOOZE and hope for the best... + */ + + for (tmp=(Scsi_Cmnd *)hostdata->disconnected_Q; tmp; + tmp=(Scsi_Cmnd *)tmp->host_scribble) + if (cmd == tmp) { + restore_flags(flags); + return SCSI_ABORT_SNOOZE; + } + +/* + * Case 4 : If we reached this point, the command was not found in any of + * the queues. + * + * We probably reached this point because of an unlikely race condition + * between the command completing successfully and the abortion code, + * so we won't panic, but we will notify the user in case somethign really + * broke. + */ + + restore_flags(flags); + printk("scsi%d : warning : SCSI command probably completed successfully\n" + " before abortion. ", instance->host_no); + return SCSI_ABORT_NOT_RUNNING; +} + + + +#define MAX_WD33C93_HOSTS 8 +static unsigned int setup_args_array[MAX_WD33C93_HOSTS]; +static int setup_args_array_x = 0; + +void wd33c93_setup (char *str, int *ints) +{ +int i; + + for (i=0; ihostdata; + + hostdata->regp = regs; + hostdata->clock_freq = clock_freq; + hostdata->dma_setup = setup; + hostdata->dma_stop = stop; + hostdata->dma_bounce_buffer = NULL; + hostdata->dma_bounce_len = 0; + for (i = 0; i < 8; i++) { + hostdata->busy[i] = 0; + hostdata->sync_xfer[i] = calc_sync_xfer(DEFAULT_SX_PER/4,DEFAULT_SX_OFF); + hostdata->sync_stat[i] = SS_UNSET; /* using default sync values */ + } + hostdata->input_Q = NULL; + hostdata->selecting = NULL; + hostdata->connected = NULL; + hostdata->disconnected_Q = NULL; + hostdata->state = S_UNCONNECTED; + hostdata->dma = D_DMA_OFF; + hostdata->incoming_ptr = 0; + hostdata->outgoing_len = 0; + + hostdata->args = setup_default; + if ((setup_args_array_x < MAX_WD33C93_HOSTS) && + (setup_args_array[setup_args_array_x])) + hostdata->args = setup_args_array[setup_args_array_x]; + setup_args_array_x++; + + i = hostdata->args & (A_LEVEL2_0 | A_LEVEL2_1 | A_LEVEL2_2); + i >>= 8; + if (i == 0) + i = L2_DEFAULT; + hostdata->level2 = i; + + cli(); + reset_wd33c93(instance); + sti(); + + printk("wd33c93-%d: ",instance->host_no); + switch (hostdata->chip) { + case C_WD33C93: + printk("Found WD33c93 chip! This driver probably needs at least the 'A' version!\n"); + break; + case C_WD33C93A: + printk("Found WD33c93A chip: microcode=%02x\n",hostdata->microcode); + break; + case C_WD33C93B: + printk("Found WD33c93B chip: microcode=%02x\n",hostdata->microcode); + break; + default: + printk("Unknown 3393 chip!\n"); + } + printk("wd33c93-%d: LEVEL2 commands %s (%d)\n",instance->host_no, + (hostdata->level2 == L2_NONE)?"disabled":"enabled", + hostdata->level2); +#ifdef DEBUGGING_ON + printk("wd33c93-%d: debug_flags = %04x\n",instance->host_no,hostdata->args); +#endif + printk("wd33c93-%d: driver version %s - %s\n",instance->host_no, + WD33C93_VERSION,WD33C93_DATE); +} + diff -u --recursive --new-file v1.3.93/linux/drivers/scsi/wd33c93.h linux/drivers/scsi/wd33c93.h --- v1.3.93/linux/drivers/scsi/wd33c93.h Thu Jan 1 02:00:00 1970 +++ linux/drivers/scsi/wd33c93.h Sat Mar 16 02:50:46 1996 @@ -0,0 +1,292 @@ +#ifndef WD33C93_H +#define WD33C93_H + +/* + * wd33c93.h - Linux device driver definitions for the + * Commodore Amiga A2091/590 SCSI controller card + * + * Copyright (c) 1996 John Shifflett, GeoLog Consulting + * john@geolog.com + * jshiffle@netcom.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + + + +#define uchar unsigned char + + +/* wd register names */ +#define WD_OWN_ID 0x00 +#define WD_CONTROL 0x01 +#define WD_TIMEOUT_PERIOD 0x02 +#define WD_CDB_1 0x03 +#define WD_CDB_2 0x04 +#define WD_CDB_3 0x05 +#define WD_CDB_4 0x06 +#define WD_CDB_5 0x07 +#define WD_CDB_6 0x08 +#define WD_CDB_7 0x09 +#define WD_CDB_8 0x0a +#define WD_CDB_9 0x0b +#define WD_CDB_10 0x0c +#define WD_CDB_11 0x0d +#define WD_CDB_12 0x0e +#define WD_TARGET_LUN 0x0f +#define WD_COMMAND_PHASE 0x10 +#define WD_SYNCHRONOUS_TRANSFER 0x11 +#define WD_TRANSFER_COUNT_MSB 0x12 +#define WD_TRANSFER_COUNT 0x13 +#define WD_TRANSFER_COUNT_LSB 0x14 +#define WD_DESTINATION_ID 0x15 +#define WD_SOURCE_ID 0x16 +#define WD_SCSI_STATUS 0x17 +#define WD_COMMAND 0x18 +#define WD_DATA 0x19 +#define WD_QUEUE_TAG 0x1a +#define WD_AUXILIARY_STATUS 0x1f + +/* WD commands */ +#define WD_CMD_RESET 0x00 +#define WD_CMD_ABORT 0x01 +#define WD_CMD_ASSERT_ATN 0x02 +#define WD_CMD_NEGATE_ACK 0x03 +#define WD_CMD_DISCONNECT 0x04 +#define WD_CMD_RESELECT 0x05 +#define WD_CMD_SEL_ATN 0x06 +#define WD_CMD_SEL 0x07 +#define WD_CMD_SEL_ATN_XFER 0x08 +#define WD_CMD_SEL_XFER 0x09 +#define WD_CMD_RESEL_RECEIVE 0x0a +#define WD_CMD_RESEL_SEND 0x0b +#define WD_CMD_WAIT_SEL_RECEIVE 0x0c +#define WD_CMD_TRANS_ADDR 0x18 +#define WD_CMD_TRANS_INFO 0x20 +#define WD_CMD_TRANSFER_PAD 0x21 +#define WD_CMD_SBT_MODE 0x80 + +/* ASR register */ +#define ASR_INT (0x80) +#define ASR_LCI (0x40) +#define ASR_BSY (0x20) +#define ASR_CIP (0x10) +#define ASR_PE (0x02) +#define ASR_DBR (0x01) + +/* SCSI Bus Phases */ +#define PHS_DATA_OUT 0x00 +#define PHS_DATA_IN 0x01 +#define PHS_COMMAND 0x02 +#define PHS_STATUS 0x03 +#define PHS_MESS_OUT 0x06 +#define PHS_MESS_IN 0x07 + +/* Command Status Register definitions */ + + /* reset state interrupts */ +#define CSR_RESET 0x00 +#define CSR_RESET_AF 0x01 + + /* successful completion interrupts */ +#define CSR_RESELECT 0x10 +#define CSR_SELECT 0x11 +#define CSR_SEL_XFER_DONE 0x16 +#define CSR_XFER_DONE 0x18 + + /* paused or aborted interrupts */ +#define CSR_MSGIN 0x20 +#define CSR_SDP 0x21 +#define CSR_SEL_ABORT 0x22 +#define CSR_RESEL_ABORT 0x25 +#define CSR_RESEL_ABORT_AM 0x27 +#define CSR_ABORT 0x28 + + /* terminated interrupts */ +#define CSR_INVALID 0x40 +#define CSR_UNEXP_DISC 0x41 +#define CSR_TIMEOUT 0x42 +#define CSR_PARITY 0x43 +#define CSR_PARITY_ATN 0x44 +#define CSR_BAD_STATUS 0x45 +#define CSR_UNEXP 0x48 + + /* service required interrupts */ +#define CSR_RESEL 0x80 +#define CSR_RESEL_AM 0x81 +#define CSR_DISC 0x85 +#define CSR_SRV_REQ 0x88 + + /* Own ID/CDB Size register */ +#define OWNID_EAF 0x08 +#define OWNID_EHP 0x10 +#define OWNID_RAF 0x20 +#define OWNID_FS_8 0x00 +#define OWNID_FS_12 0x40 +#define OWNID_FS_16 0x80 + + /* define these so we don't have to change a2091.c, etc. */ +#define WD33C93_FS_8_10 OWNID_FS_8 +#define WD33C93_FS_12_15 OWNID_FS_12 +#define WD33C93_FS_16_20 OWNID_FS_16 + + /* Control register */ +#define CTRL_HSP 0x01 +#define CTRL_HA 0x02 +#define CTRL_IDI 0x04 +#define CTRL_EDI 0x08 +#define CTRL_HHP 0x10 +#define CTRL_POLLED 0x00 +#define CTRL_BURST 0x20 +#define CTRL_BUS 0x40 +#define CTRL_DMA 0x80 + + /* Timeout Period register */ +#define TIMEOUT_PERIOD_VALUE 20 /* results in 200 ms. */ + + /* Synchronous Transfer Register */ +#define STR_FSS 0x80 + + /* Destination ID register */ +#define DSTID_DPD 0x40 +#define DATA_OUT_DIR 0 +#define DATA_IN_DIR 1 +#define DSTID_SCC 0x80 + + /* Source ID register */ +#define SRCID_MASK 0x07 +#define SRCID_SIV 0x08 +#define SRCID_DSP 0x20 +#define SRCID_ES 0x40 +#define SRCID_ER 0x80 + + /* This is what the 3393 chip looks like to us */ +typedef struct { + volatile unsigned char SASR; + char pad; + volatile unsigned char SCMD; +} wd33c93_regs; + + +typedef int (*dma_setup_t) (Scsi_Cmnd *SCpnt, int dir_in); +typedef void (*dma_stop_t) (struct Scsi_Host *instance, Scsi_Cmnd *SCpnt, + int status); + + +#define DEFAULT_SX_PER 500 /* (ns) fairly safe */ +#define DEFAULT_SX_OFF 0 /* aka async */ + +#define OPTIMUM_SX_PER 252 /* (ns) best we can do (mult-of-4) */ +#define OPTIMUM_SX_OFF 12 /* size of wd3393 fifo */ + +struct sx_period { + unsigned int period_ns; + uchar reg_value; + }; + + +struct WD33C93_hostdata { + struct Scsi_Host *next; + wd33c93_regs *regp; + uchar clock_freq; + uchar chip; /* what kind of wd33c93? */ + uchar microcode; /* microcode rev if 'B' */ + int dma_dir; /* data transfer dir. */ + dma_setup_t dma_setup; + dma_stop_t dma_stop; + uchar *dma_bounce_buffer; + unsigned int dma_bounce_len; + volatile uchar busy[8]; /* index = target, bit = lun */ + volatile Scsi_Cmnd *input_Q; /* commands waiting to be started */ + volatile Scsi_Cmnd *selecting; /* trying to select this command */ + volatile Scsi_Cmnd *connected; /* currently connected command */ + volatile Scsi_Cmnd *disconnected_Q;/* commands waiting for reconnect */ + uchar state; /* what we are currently doing */ + uchar dma; /* current state of DMA (on/off) */ + uchar level2; /* extent to which Level-2 commands are used */ + unsigned int args; /* set from command-line argument */ + uchar incoming_msg[8]; /* filled during message_in phase */ + int incoming_ptr; /* mainly used with EXTENDED messages */ + uchar outgoing_msg[8]; /* send this during next message_out */ + int outgoing_len; /* length of outgoing message */ + uchar sync_xfer[8]; /* sync_xfer reg settings per target */ + uchar sync_stat[8]; /* status of sync negotiation per target */ + }; + + +/* defines for hostdata->chip */ + +#define C_WD33C93 0 +#define C_WD33C93A 1 +#define C_WD33C93B 2 +#define C_UNKNOWN_CHIP 100 + +/* defines for hostdata->state */ + +#define S_UNCONNECTED 0 +#define S_SELECTING 1 +#define S_RUNNING_LEVEL2 2 +#define S_CONNECTED 3 +#define S_PRE_TMP_DISC 4 +#define S_PRE_CMP_DISC 5 + +/* defines for hostdata->dma */ + +#define D_DMA_OFF 0 +#define D_DMA_RUNNING 1 + +/* defines for hostdata->level2 */ +/* NOTE: only the first 3 are implemented so far - having trouble + * when more than 1 device is reading/writing at the same time... + */ + +#define L2_NONE 1 /* no combination commands - we get lots of ints */ +#define L2_SELECT 2 /* start with SEL_ATN_XFER, but never resume it */ +#define L2_BASIC 3 /* resume after STATUS ints & RDP messages */ +#define L2_DATA 4 /* resume after DATA_IN/OUT ints */ +#define L2_MOST 5 /* resume after anything except a RESELECT int */ +#define L2_RESELECT 6 /* resume after everything, including RESELECT ints */ +#define L2_ALL 7 /* always resume */ +#define L2_DEFAULT L2_BASIC + +/* defines for hostdata->args */ +/* (The first 8 bits are reserved for compatability. They function + * as they did in the old driver - note that turning off sync_xfer + * on a target affects all LUNs at that SCSI id.) + */ + +#define A_LEVEL2_0 1<<8 +#define A_LEVEL2_1 1<<9 +#define A_LEVEL2_2 1<<10 +#define A_NO_DISCONNECT 1<<11 + +#define DB_QUEUE_COMMAND 1<<12 +#define DB_EXECUTE 1<<13 +#define DB_INTR 1<<14 +#define DB_TRANSFER_DATA 1<<15 + +/* defines for hostdata->sync_stat[] */ + +#define SS_UNSET 0 +#define SS_FIRST 1 +#define SS_WAITING 2 +#define SS_SET 3 + + +void wd33c93_init (struct Scsi_Host *instance, wd33c93_regs *regs, + dma_setup_t setup, dma_stop_t stop, int clock_freq); +int wd33c93_abort (Scsi_Cmnd *cmd); +int wd33c93_reset (Scsi_Cmnd *); +int wd33c93_queuecommand (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)); +void wd33c93_intr (struct Scsi_Host *instance); + +#endif /* WD33C93_H */ diff -u --recursive --new-file v1.3.93/linux/drivers/sound/dmasound.c linux/drivers/sound/dmasound.c --- v1.3.93/linux/drivers/sound/dmasound.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/sound/dmasound.c Thu Apr 18 02:03:28 1996 @@ -0,0 +1,3252 @@ + +/* linux/drivers/sound/dmasound.c */ + +/* + +VoxWare compatible Atari TT DMA sound driver for 680x0 Linux + +(c) 1995 by Michael Schlueter & Michael Marte + +Michael Schlueter (michael@duck.syd.de) did the basic structure of the VFS +interface and the u-law to signed byte conversion. + +Michael Marte (marte@informatik.uni-muenchen.de) did the sound queue, +/dev/mixer, /dev/sndstat and complemented the VFS interface. He would like +to thank: +Michael Schlueter for initial ideas and documentation on the MFP and +the DMA sound hardware. +Therapy? for their CD 'Troublegum' which really made me rock. + +/dev/sndstat is based on code by Hannu Savolainen, the author of the +VoxWare family of drivers. + +This file is subject to the terms and conditions of the GNU General Public +License. See the file README.legal in the main directory of this archive +for more details. + +History: +1995/8/25 first release + +1995/9/02 ++roman: fixed atari_stram_alloc() call, the timer programming + and several race conditions + +1995/9/14 ++roman: After some discussion with Michael Schlueter, revised + the interrupt disabling + Slightly speeded up U8->S8 translation by using long + operations where possible + Added 4:3 interpolation for /dev/audio + +1995/9/20 ++TeSche: Fixed a bug in sq_write and changed /dev/audio + converting to play at 12517Hz instead of 6258Hz. + +1995/9/23 ++TeSche: Changed sq_interrupt() and sq_play() to pre-program + the DMA for another frame while there's still one + running. This allows the IRQ response to be + arbitrarily delayed and playing will still continue. + +1995/10/14 ++Guenther_Kelleter@ac3.maus.de, ++TeSche: better support for + Falcon audio (the Falcon doesn't raise an IRQ at the + end of a frame, but at the beginning instead!). uses + 'if (codec_dma)' in lots of places to simply switch + between Falcon and TT code. + +1995/11/06 ++TeSche: started introducing a hardware abstraction scheme + (may perhaps also serve for Amigas?), can now play + samples at almost all frequencies by means of a more + generalized expand routine, takes a good deal of care + to cut data only at sample sizes, buffer size is now + a kernel runtime option, implemented fsync() & several + minor improvements + ++Guenther: useful hints and bugfixes, cross-checked it for + Falcons + +1996/3/9 ++geert: support added for Amiga, A-law, 16-bit little endian. + Unification to drivers/sound/dmasound.c. +1996/4/6 ++Martin Mitchell: updated to 1.3 kernel. +*/ + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifdef CONFIG_ATARI +#include +#include +#endif /* CONFIG_ATARI */ +#ifdef CONFIG_AMIGA +#include +#include +#endif /* CONFIG_AMIGA */ + +#include "dmasound.h" +#include + + +#ifdef CONFIG_ATARI +extern void atari_microwire_cmd(int cmd); +#endif /* CONFIG_ATARI */ + +#ifdef CONFIG_AMIGA + /* + * The minimum period for audio depends on htotal (for OCS/ECS/AGA) + * (Imported from arch/m68k/amiga/amisound.c) + */ + +extern volatile u_short amiga_audio_min_period; + + + /* + * amiga_mksound() should be able to restore the period after beeping + * (Imported from arch/m68k/amiga/amisound.c) + */ + +extern u_short amiga_audio_period; + + + /* + * Audio DMA masks + */ + +#define AMI_AUDIO_OFF (DMAF_AUD0 | DMAF_AUD1 | DMAF_AUD2 | DMAF_AUD3) +#define AMI_AUDIO_8 (DMAF_SETCLR | DMAF_MASTER | DMAF_AUD0 | DMAF_AUD1) +#define AMI_AUDIO_14 (AMI_AUDIO_8 | DMAF_AUD2 | DMAF_AUD3) + +#endif /* CONFIG_AMIGA */ + + +/*** Some declarations *******************************************************/ + + +#define DMASND_TT 1 +#define DMASND_FALCON 2 +#define DMASND_AMIGA 3 + +#define MAX_CATCH_RADIUS 10 +#define MIN_BUFFERS 4 +#define MIN_BUFSIZE 4 +#define MAX_BUFSIZE 128 /* Limit for Amiga */ + +static int catchRadius = 0, numBufs = 4, bufSize = 32; + + +#define arraysize(x) (sizeof(x)/sizeof(*(x))) +#define min(x, y) ((x) < (y) ? (x) : (y)) +#define le2be16(x) (((x)<<8 & 0xff00) | ((x)>>8 & 0x00ff)) +#define le2be16dbl(x) (((x)<<8 & 0xff00ff00) | ((x)>>8 & 0x00ff00ff)) + +#define IOCTL_IN(arg) get_user((int *)(arg)) +#define IOCTL_OUT(arg, ret) ioctl_return((int *)arg, ret) + + +/*** Some low level helpers **************************************************/ + + +/* 8 bit mu-law */ + +static char ulaw2dma8[] = { + -126, -122, -118, -114, -110, -106, -102, -98, + -94, -90, -86, -82, -78, -74, -70, -66, + -63, -61, -59, -57, -55, -53, -51, -49, + -47, -45, -43, -41, -39, -37, -35, -33, + -31, -30, -29, -28, -27, -26, -25, -24, + -23, -22, -21, -20, -19, -18, -17, -16, + -16, -15, -15, -14, -14, -13, -13, -12, + -12, -11, -11, -10, -10, -9, -9, -8, + -8, -8, -7, -7, -7, -7, -6, -6, + -6, -6, -5, -5, -5, -5, -4, -4, + -4, -4, -4, -4, -3, -3, -3, -3, + -3, -3, -3, -3, -2, -2, -2, -2, + -2, -2, -2, -2, -2, -2, -2, -2, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 0, + 125, 121, 117, 113, 109, 105, 101, 97, + 93, 89, 85, 81, 77, 73, 69, 65, + 62, 60, 58, 56, 54, 52, 50, 48, + 46, 44, 42, 40, 38, 36, 34, 32, + 30, 29, 28, 27, 26, 25, 24, 23, + 22, 21, 20, 19, 18, 17, 16, 15, + 15, 14, 14, 13, 13, 12, 12, 11, + 11, 10, 10, 9, 9, 8, 8, 7, + 7, 7, 6, 6, 6, 6, 5, 5, + 5, 5, 4, 4, 4, 4, 3, 3, + 3, 3, 3, 3, 2, 2, 2, 2, + 2, 2, 2, 2, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* 8 bit A-law */ + +static char alaw2dma8[] = { + -22, -21, -24, -23, -18, -17, -20, -19, + -30, -29, -32, -31, -26, -25, -28, -27, + -11, -11, -12, -12, -9, -9, -10, -10, + -15, -15, -16, -16, -13, -13, -14, -14, + -86, -82, -94, -90, -70, -66, -78, -74, + -118, -114, -126, -122, -102, -98, -110, -106, + -43, -41, -47, -45, -35, -33, -39, -37, + -59, -57, -63, -61, -51, -49, -55, -53, + -2, -2, -2, -2, -2, -2, -2, -2, + -2, -2, -2, -2, -2, -2, -2, -2, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -6, -6, -6, -6, -5, -5, -5, -5, + -8, -8, -8, -8, -7, -7, -7, -7, + -3, -3, -3, -3, -3, -3, -3, -3, + -4, -4, -4, -4, -4, -4, -4, -4, + 21, 20, 23, 22, 17, 16, 19, 18, + 29, 28, 31, 30, 25, 24, 27, 26, + 10, 10, 11, 11, 8, 8, 9, 9, + 14, 14, 15, 15, 12, 12, 13, 13, + 86, 82, 94, 90, 70, 66, 78, 74, + 118, 114, 126, 122, 102, 98, 110, 106, + 43, 41, 47, 45, 35, 33, 39, 37, + 59, 57, 63, 61, 51, 49, 55, 53, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 5, 5, 5, 5, 4, 4, 4, 4, + 7, 7, 7, 7, 6, 6, 6, 6, + 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3 +}; + + +#ifdef HAS_16BIT_TABLES + +/* 16 bit mu-law */ + +static char ulaw2dma16[] = { + -32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956, + -23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764, + -15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412, + -11900, -11388, -10876, -10364, -9852, -9340, -8828, -8316, + -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140, + -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092, + -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004, + -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980, + -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436, + -1372, -1308, -1244, -1180, -1116, -1052, -988, -924, + -876, -844, -812, -780, -748, -716, -684, -652, + -620, -588, -556, -524, -492, -460, -428, -396, + -372, -356, -340, -324, -308, -292, -276, -260, + -244, -228, -212, -196, -180, -164, -148, -132, + -120, -112, -104, -96, -88, -80, -72, -64, + -56, -48, -40, -32, -24, -16, -8, 0, + 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956, + 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764, + 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412, + 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316, + 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140, + 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092, + 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004, + 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980, + 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436, + 1372, 1308, 1244, 1180, 1116, 1052, 988, 924, + 876, 844, 812, 780, 748, 716, 684, 652, + 620, 588, 556, 524, 492, 460, 428, 396, + 372, 356, 340, 324, 308, 292, 276, 260, + 244, 228, 212, 196, 180, 164, 148, 132, + 120, 112, 104, 96, 88, 80, 72, 64, + 56, 48, 40, 32, 24, 16, 8, 0, +}; + +/* 16 bit A-law */ + +static char alaw2dma16[] = { + -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736, + -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784, + -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368, + -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392, + -22016, -20992, -24064, -23040, -17920, -16896, -19968, -18944, + -30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136, + -11008, -10496, -12032, -11520, -8960, -8448, -9984, -9472, + -15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568, + -344, -328, -376, -360, -280, -264, -312, -296, + -472, -456, -504, -488, -408, -392, -440, -424, + -88, -72, -120, -104, -24, -8, -56, -40, + -216, -200, -248, -232, -152, -136, -184, -168, + -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184, + -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696, + -688, -656, -752, -720, -560, -528, -624, -592, + -944, -912, -1008, -976, -816, -784, -880, -848, + 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736, + 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784, + 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368, + 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392, + 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944, + 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136, + 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472, + 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568, + 344, 328, 376, 360, 280, 264, 312, 296, + 472, 456, 504, 488, 408, 392, 440, 424, + 88, 72, 120, 104, 24, 8, 56, 40, + 216, 200, 248, 232, 152, 136, 184, 168, + 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184, + 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696, + 688, 656, 752, 720, 560, 528, 624, 592, + 944, 912, 1008, 976, 816, 784, 880, 848, +}; +#endif /* HAS_16BIT_TABLES */ + + +#ifdef HAS_14BIT_TABLES + +/* 14 bit mu-law (lsb) */ + +static char alaw2dma14l[] = { + 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 49, 17, 49, 17, 49, 17, 49, 17, + 49, 17, 49, 17, 49, 17, 49, 17, + 41, 57, 9, 25, 41, 57, 9, 25, + 41, 57, 9, 25, 41, 57, 9, 25, + 37, 45, 53, 61, 5, 13, 21, 29, + 37, 45, 53, 61, 5, 13, 21, 29, + 35, 39, 43, 47, 51, 55, 59, 63, + 3, 7, 11, 15, 19, 23, 27, 31, + 34, 36, 38, 40, 42, 44, 46, 48, + 50, 52, 54, 56, 58, 60, 62, 0, + 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, + 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, + 15, 47, 15, 47, 15, 47, 15, 47, + 15, 47, 15, 47, 15, 47, 15, 47, + 23, 7, 55, 39, 23, 7, 55, 39, + 23, 7, 55, 39, 23, 7, 55, 39, + 27, 19, 11, 3, 59, 51, 43, 35, + 27, 19, 11, 3, 59, 51, 43, 35, + 29, 25, 21, 17, 13, 9, 5, 1, + 61, 57, 53, 49, 45, 41, 37, 33, + 30, 28, 26, 24, 22, 20, 18, 16, + 14, 12, 10, 8, 6, 4, 2, 0 +}; + +/* 14 bit A-law (lsb) */ + +static char alaw2dma14l[] = { + 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, + 16, 48, 16, 48, 16, 48, 16, 48, + 16, 48, 16, 48, 16, 48, 16, 48, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 42, 46, 34, 38, 58, 62, 50, 54, + 10, 14, 2, 6, 26, 30, 18, 22, + 42, 46, 34, 38, 58, 62, 50, 54, + 10, 14, 2, 6, 26, 30, 18, 22, + 40, 56, 8, 24, 40, 56, 8, 24, + 40, 56, 8, 24, 40, 56, 8, 24, + 20, 28, 4, 12, 52, 60, 36, 44, + 20, 28, 4, 12, 52, 60, 36, 44, + 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, + 48, 16, 48, 16, 48, 16, 48, 16, + 48, 16, 48, 16, 48, 16, 48, 16, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 22, 18, 30, 26, 6, 2, 14, 10, + 54, 50, 62, 58, 38, 34, 46, 42, + 22, 18, 30, 26, 6, 2, 14, 10, + 54, 50, 62, 58, 38, 34, 46, 42, + 24, 8, 56, 40, 24, 8, 56, 40, + 24, 8, 56, 40, 24, 8, 56, 40, + 44, 36, 60, 52, 12, 4, 28, 20, + 44, 36, 60, 52, 12, 4, 28, 20 +}; +#endif /* HAS_14BIT_TABLES */ + + +/*** Translations ************************************************************/ + + +#ifdef CONFIG_ATARI +static long ata_ct_law(const u_char *userPtr, long userCount, u_char frame[], + long *frameUsed, long frameLeft); +static long ata_ct_s8(const u_char *userPtr, long userCount, u_char frame[], + long *frameUsed, long frameLeft); +static long ata_ct_u8(const u_char *userPtr, long userCount, u_char frame[], + long *frameUsed, long frameLeft); +static long ata_ct_s16be(const u_char *userPtr, long userCount, u_char frame[], + long *frameUsed, long frameLeft); +static long ata_ct_u16be(const u_char *userPtr, long userCount, u_char frame[], + long *frameUsed, long frameLeft); +static long ata_ct_s16le(const u_char *userPtr, long userCount, u_char frame[], + long *frameUsed, long frameLeft); +static long ata_ct_u16le(const u_char *userPtr, long userCount, u_char frame[], + long *frameUsed, long frameLeft); +static long ata_ctx_law(const u_char *userPtr, long userCount, u_char frame[], + long *frameUsed, long frameLeft); +static long ata_ctx_s8(const u_char *userPtr, long userCount, u_char frame[], + long *frameUsed, long frameLeft); +static long ata_ctx_u8(const u_char *userPtr, long userCount, u_char frame[], + long *frameUsed, long frameLeft); +static long ata_ctx_s16be(const u_char *userPtr, long userCount, u_char frame[], + long *frameUsed, long frameLeft); +static long ata_ctx_u16be(const u_char *userPtr, long userCount, u_char frame[], + long *frameUsed, long frameLeft); +static long ata_ctx_s16le(const u_char *userPtr, long userCount, u_char frame[], + long *frameUsed, long frameLeft); +static long ata_ctx_u16le(const u_char *userPtr, long userCount, u_char frame[], + long *frameUsed, long frameLeft); +#endif /* CONFIG_ATARI */ + +#ifdef CONFIG_AMIGA +static long ami_ct_law(const u_char *userPtr, long userCount, u_char frame[], + long *frameUsed, long frameLeft); +static long ami_ct_s8(const u_char *userPtr, long userCount, u_char frame[], + long *frameUsed, long frameLeft); +static long ami_ct_u8(const u_char *userPtr, long userCount, u_char frame[], + long *frameUsed, long frameLeft); +static long ami_ct_s16be(const u_char *userPtr, long userCount, u_char frame[], + long *frameUsed, long frameLeft); +static long ami_ct_u16be(const u_char *userPtr, long userCount, u_char frame[], + long *frameUsed, long frameLeft); +static long ami_ct_s16le(const u_char *userPtr, long userCount, u_char frame[], + long *frameUsed, long frameLeft); +static long ami_ct_u16le(const u_char *userPtr, long userCount, u_char frame[], + long *frameUsed, long frameLeft); +#endif /* CONFIG_AMIGA */ + + +/*** Machine definitions *****************************************************/ + + +typedef struct { + int type; + void *(*dma_alloc)(unsigned int, int); + void (*dma_free)(void *, unsigned int); + int (*irqinit)(void); + void (*init)(void); + void (*silence)(void); + int (*setFormat)(int); + int (*setVolume)(int); + int (*setBass)(int); + int (*setTreble)(int); + void (*play)(void); +} MACHINE; + + +/*** Low level stuff *********************************************************/ + + +typedef struct { + int format; /* AFMT_* */ + int stereo; /* 0 = mono, 1 = stereo */ + int size; /* 8/16 bit*/ + int speed; /* speed */ +} SETTINGS; + +typedef struct { + long (*ct_ulaw)(const u_char *, long, u_char *, long *, long); + long (*ct_alaw)(const u_char *, long, u_char *, long *, long); + long (*ct_s8)(const u_char *, long, u_char *, long *, long); + long (*ct_u8)(const u_char *, long, u_char *, long *, long); + long (*ct_s16be)(const u_char *, long, u_char *, long *, long); + long (*ct_u16be)(const u_char *, long, u_char *, long *, long); + long (*ct_s16le)(const u_char *, long, u_char *, long *, long); + long (*ct_u16le)(const u_char *, long, u_char *, long *, long); +} TRANS; + +struct sound_settings { + MACHINE mach; /* machine dependend things */ + SETTINGS hard; /* hardware settings */ + SETTINGS soft; /* software settings */ + SETTINGS dsp; /* /dev/dsp default settings */ + TRANS *trans; /* supported translations */ + int volume_left; /* volume (range is machine dependent) */ + int volume_right; + int bass; /* tone (range is machine dependent) */ + int treble; + int minDev; /* minor device number currently open */ +#ifdef CONFIG_ATARI + int bal; /* balance factor for expanding (not volume!) */ + u_long data; /* data for expanding */ +#endif /* CONFIG_ATARI */ +}; + +static struct sound_settings sound; + + +#ifdef CONFIG_ATARI +static void *AtaAlloc(unsigned int size, int flags); +static void AtaFree(void *, unsigned int size); +static int AtaIrqInit(void); +static int AtaSetBass(int bass); +static int AtaSetTreble(int treble); +static void TTSilence(void); +static void TTInit(void); +static int TTSetFormat(int format); +static int TTSetVolume(int volume); +static void FalconSilence(void); +static void FalconInit(void); +static int FalconSetFormat(int format); +static int FalconSetVolume(int volume); +static void ata_sq_play_next_frame(int index); +static void AtaPlay(void); +static void ata_sq_interrupt(int irq, struct pt_regs *fp, void *dummy); +#endif /* CONFIG_ATARI */ + +#ifdef CONFIG_AMIGA +static void *AmiAlloc(unsigned int size, int flags); +static void AmiFree(void *, unsigned int); +static int AmiIrqInit(void); +static void AmiSilence(void); +static void AmiInit(void); +static int AmiSetFormat(int format); +static int AmiSetVolume(int volume); +static int AmiSetTreble(int treble); +static void ami_sq_play_next_frame(int index); +static void AmiPlay(void); +static void ami_sq_interrupt(int irq, struct pt_regs *fp, void *dummy); +#endif /* CONFIG_AMIGA */ + + +/*** Mid level stuff *********************************************************/ + + +static void sound_silence(void); +static void sound_init(void); +static int sound_set_format(int format); +static int sound_set_speed(int speed); +static int sound_set_stereo(int stereo); +static int sound_set_volume(int volume); +#ifdef CONFIG_ATARI +static int sound_set_bass(int bass); +#endif /* CONFIG_ATARI */ +static int sound_set_treble(int treble); +static long sound_copy_translate(const u_char *userPtr, long userCount, + u_char frame[], long *frameUsed, + long frameLeft); + + +/* + * /dev/mixer abstraction + */ + +struct sound_mixer { + int busy; +}; + +static struct sound_mixer mixer; + +static void mixer_init(void); +static int mixer_open(int open_mode); +static int mixer_release(void); +static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd, + u_long arg); + + +/* + * Sound queue stuff, the heart of the driver + */ + +struct sound_queue { + int max_count, block_size; + char **buffers; + + /* it shouldn't be necessary to declare any of these volatile */ + int front, rear, count; + int rear_size; + /* + * The use of the playing field depends on the hardware + * + * Atari: The number of frames that are loaded/playing + * + * Amiga: Bit 0 is set: a frame is loaded + * Bit 1 is set: a frame is playing + */ + int playing; + struct wait_queue *write_queue, *open_queue, *sync_queue; + int open_mode; + int busy, syncing; +#ifdef CONFIG_ATARI + int ignore_int; /* ++TeSche: used for Falcon */ +#endif /* CONFIG_ATARI */ +#ifdef CONFIG_AMIGA + int block_size_half, block_size_quarter; +#endif /* CONFIG_AMIGA */ +}; + +static struct sound_queue sq; + +#define sq_block_address(i) (sq.buffers[i]) +#define SIGNAL_RECEIVED (current->signal & ~current->blocked) +#define NON_BLOCKING(open_mode) (open_mode & O_NONBLOCK) +#define ONE_SECOND HZ /* in jiffies (100ths of a second) */ +#define NO_TIME_LIMIT 0xffffffff +#define SLEEP(queue, time_limit) \ + current->timeout = jiffies+(time_limit); \ + interruptible_sleep_on(&queue); +#define WAKE_UP(queue) (wake_up_interruptible(&queue)) + +static void sq_init(int numBufs, int bufSize, char **buffers); +static void sq_play(void); +static int sq_write(const char *src, int uLeft); +static int sq_open(int open_mode); +static void sq_reset(void); +static int sq_sync(void); +static int sq_release(void); + + +/* + * /dev/sndstat + */ + +struct sound_state { + int busy; + char buf[512]; + int len, ptr; +}; + +static struct sound_state state; + +static void state_init(void); +static int state_open(int open_mode); +static int state_release(void); +static int state_read(char *dest, int count); + + +/*** High level stuff ********************************************************/ + + +static int sound_open(struct inode *inode, struct file *file); +static int sound_fsync(struct inode *inode, struct file *filp); +static void sound_release(struct inode *inode, struct file *file); +static int sound_lseek(struct inode *inode, struct file *file, off_t offset, + int orig); +static int sound_read(struct inode *inode, struct file *file, char *buf, + int count); +static int sound_write(struct inode *inode, struct file *file, const char *buf, + int count); +static int ioctl_return(int *addr, int value); +static int unknown_minor_dev(char *fname, int dev); +static int sound_ioctl(struct inode *inode, struct file *file, u_int cmd, + u_long arg); + + +/*** Config & Setup **********************************************************/ + + +void soundcard_init(void); +void dmasound_setup(char *str, int *ints); +void sound_setup(char *str, int *ints); /* ++Martin: stub for now */ + + +/*** Translations ************************************************************/ + + +/* ++TeSche: radically changed for new expanding purposes... + * + * These two routines now deal with copying/expanding/translating the samples + * from user space into our buffer at the right frequency. They take care about + * how much data there's actually to read, how much buffer space there is and + * to convert samples into the right frequency/encoding. They will only work on + * complete samples so it may happen they leave some bytes in the input stream + * if the user didn't write a multiple of the current sample size. They both + * return the number of bytes they've used from both streams so you may detect + * such a situation. Luckily all programs should be able to cope with that. + * + * I think I've optimized anything as far as one can do in plain C, all + * variables should fit in registers and the loops are really short. There's + * one loop for every possible situation. Writing a more generalized and thus + * parametrized loop would only produce slower code. Feel free to optimize + * this in assembler if you like. :) + * + * I think these routines belong here because they're not yet really hardware + * independend, especially the fact that the Falcon can play 16bit samples + * only in stereo is hardcoded in both of them! + * + * ++geert: split in even more functions (one per format) + */ + +#ifdef CONFIG_ATARI +static long ata_ct_law(const u_char *userPtr, long userCount, u_char frame[], + long *frameUsed, long frameLeft) +{ + char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8; + long count, used; + u_char *p = &frame[*frameUsed]; + + count = min(userCount, frameLeft); + if (sound.soft.stereo) + count &= ~1; + used = count; + while (count > 0) { + *p++ = table[get_user(userPtr++)]; + count--; + } + *frameUsed += used; + return(used); +} + + +static long ata_ct_s8(const u_char *userPtr, long userCount, u_char frame[], + long *frameUsed, long frameLeft) +{ + long count, used; + void *p = &frame[*frameUsed]; + + count = min(userCount, frameLeft); + if (sound.soft.stereo) + count &= ~1; + used = count; + memcpy_fromfs(p, userPtr, count); + *frameUsed += used; + return(used); +} + + +static long ata_ct_u8(const u_char *userPtr, long userCount, u_char frame[], + long *frameUsed, long frameLeft) +{ + long count, used; + + if (!sound.soft.stereo) { + u_char *p = &frame[*frameUsed]; + count = min(userCount, frameLeft); + used = count; + while (count > 0) { + *p++ = get_user(userPtr++) ^ 0x80; + count--; + } + } else { + u_short *p = (u_short *)&frame[*frameUsed]; + count = min(userCount, frameLeft)>>1; + used = count*2; + while (count > 0) { + *p++ = get_user(((u_short *)userPtr)++) ^ 0x8080; + count--; + } + } + *frameUsed += used; + return(used); +} + + +static long ata_ct_s16be(const u_char *userPtr, long userCount, u_char frame[], + long *frameUsed, long frameLeft) +{ + long count, used; + u_long data; + + if (!sound.soft.stereo) { + u_short *p = (u_short *)&frame[*frameUsed]; + count = min(userCount, frameLeft)>>1; + used = count*2; + while (count > 0) { + data = get_user(((u_short *)userPtr)++); + *p++ = data; + *p++ = data; + count--; + } + *frameUsed += used*2; + } else { + void *p = (u_short *)&frame[*frameUsed]; + count = min(userCount, frameLeft) & ~3; + used = count; + memcpy_fromfs(p, userPtr, count); + *frameUsed += used; + } + return(used); +} + + +static long ata_ct_u16be(const u_char *userPtr, long userCount, u_char frame[], + long *frameUsed, long frameLeft) +{ + long count, used; + u_long data; + + if (!sound.soft.stereo) { + u_short *p = (u_short *)&frame[*frameUsed]; + count = min(userCount, frameLeft)>>1; + used = count*2; + while (count > 0) { + data = get_user(((u_short *)userPtr)++) ^ 0x8000; + *p++ = data; + *p++ = data; + count--; + } + *frameUsed += used*2; + } else { + u_long *p = (u_long *)&frame[*frameUsed]; + count = min(userCount, frameLeft)>>2; + used = count*4; + while (count > 0) { + *p++ = get_user(((u_int *)userPtr)++) ^ 0x80008000; + count--; + } + *frameUsed += used; + } + return(used); +} + + +static long ata_ct_s16le(const u_char *userPtr, long userCount, u_char frame[], + long *frameUsed, long frameLeft) +{ + long count, used; + u_long data; + + count = frameLeft; + if (!sound.soft.stereo) { + u_short *p = (u_short *)&frame[*frameUsed]; + count = min(userCount, frameLeft)>>1; + used = count*2; + while (count > 0) { + data = get_user(((u_short *)userPtr)++); + data = le2be16(data); + *p++ = data; + *p++ = data; + count--; + } + *frameUsed += used*2; + } else { + u_long *p = (u_long *)&frame[*frameUsed]; + count = min(userCount, frameLeft)>>2; + used = count*4; + while (count > 0) { + data = get_user(((u_int *)userPtr)++); + data = le2be16dbl(data); + *p++ = data; + count--; + } + *frameUsed += used; + } + return(used); +} + + +static long ata_ct_u16le(const u_char *userPtr, long userCount, u_char frame[], + long *frameUsed, long frameLeft) +{ + long count, used; + u_long data; + + count = frameLeft; + if (!sound.soft.stereo) { + u_short *p = (u_short *)&frame[*frameUsed]; + count = min(userCount, frameLeft)>>1; + used = count*2; + while (count > 0) { + data = get_user(((u_short *)userPtr)++); + data = le2be16(data) ^ 0x8000; + *p++ = data; + *p++ = data; + } + *frameUsed += used*2; + } else { + u_long *p = (u_long *)&frame[*frameUsed]; + count = min(userCount, frameLeft)>>2; + used = count; + while (count > 0) { + data = get_user(((u_int *)userPtr)++); + data = le2be16dbl(data) ^ 0x80008000; + *p++ = data; + count--; + } + *frameUsed += used; + } + return(used); +} + + +static long ata_ctx_law(const u_char *userPtr, long userCount, u_char frame[], + long *frameUsed, long frameLeft) +{ + char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8; + /* this should help gcc to stuff everything into registers */ + u_long data = sound.data; + long bal = sound.bal; + long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; + long used, usedf; + + used = userCount; + usedf = frameLeft; + if (!sound.soft.stereo) { + u_char *p = &frame[*frameUsed]; + while (frameLeft) { + if (bal < 0) { + if (!userCount) + break; + data = table[get_user(userPtr++)]; + userCount--; + bal += hSpeed; + } + *p++ = data; + frameLeft--; + bal -= sSpeed; + } + } else { + u_short *p = (u_short *)&frame[*frameUsed]; + while (frameLeft >= 2) { + if (bal < 0) { + if (userCount < 2) + break; + data = table[get_user(userPtr++)] << 8; + data |= table[get_user(userPtr++)]; + userCount -= 2; + bal += hSpeed; + } + *p++ = data; + frameLeft -= 2; + bal -= sSpeed; + } + } + sound.bal = bal; + sound.data = data; + used -= userCount; + *frameUsed += usedf-frameLeft; + return(used); +} + + +static long ata_ctx_s8(const u_char *userPtr, long userCount, u_char frame[], + long *frameUsed, long frameLeft) +{ + /* this should help gcc to stuff everything into registers */ + u_long data = sound.data; + long bal = sound.bal; + long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; + long used, usedf; + + used = userCount; + usedf = frameLeft; + if (!sound.soft.stereo) { + u_char *p = &frame[*frameUsed]; + while (frameLeft) { + if (bal < 0) { + if (!userCount) + break; + data = get_user(userPtr++); + userCount--; + bal += hSpeed; + } + *p++ = data; + frameLeft--; + bal -= sSpeed; + } + } else { + u_short *p = (u_short *)&frame[*frameUsed]; + while (frameLeft >= 2) { + if (bal < 0) { + if (userCount < 2) + break; + data = get_user(((u_short *)userPtr)++); + userCount -= 2; + bal += hSpeed; + } + *p++ = data; + frameLeft -= 2; + bal -= sSpeed; + } + } + sound.bal = bal; + sound.data = data; + used -= userCount; + *frameUsed += usedf-frameLeft; + return(used); +} + + +static long ata_ctx_u8(const u_char *userPtr, long userCount, u_char frame[], + long *frameUsed, long frameLeft) +{ + /* this should help gcc to stuff everything into registers */ + u_long data = sound.data; + long bal = sound.bal; + long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; + long used, usedf; + + used = userCount; + usedf = frameLeft; + if (!sound.soft.stereo) { + u_char *p = &frame[*frameUsed]; + while (frameLeft) { + if (bal < 0) { + if (!userCount) + break; + data = get_user(userPtr++) ^ 0x80; + userCount--; + bal += hSpeed; + } + *p++ = data; + frameLeft--; + bal -= sSpeed; + } + } else { + u_short *p = (u_short *)&frame[*frameUsed]; + while (frameLeft >= 2) { + if (bal < 0) { + if (userCount < 2) + break; + data = get_user(((u_short *)userPtr)++) ^ 0x8080; + userCount -= 2; + bal += hSpeed; + } + *p++ = data; + frameLeft -= 2; + bal -= sSpeed; + } + } + sound.bal = bal; + sound.data = data; + used -= userCount; + *frameUsed += usedf-frameLeft; + return(used); +} + + +static long ata_ctx_s16be(const u_char *userPtr, long userCount, u_char frame[], + long *frameUsed, long frameLeft) +{ + /* this should help gcc to stuff everything into registers */ + u_long data = sound.data; + long bal = sound.bal; + long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; + long used, usedf; + + used = userCount; + usedf = frameLeft; + if (!sound.soft.stereo) { + u_short *p = (u_short *)&frame[*frameUsed]; + while (frameLeft >= 4) { + if (bal < 0) { + if (userCount < 2) + break; + data = get_user(((u_short *)userPtr)++); + userCount -= 2; + bal += hSpeed; + } + *p++ = data; + *p++ = data; + frameLeft -= 4; + bal -= sSpeed; + } + } else { + u_long *p = (u_long *)&frame[*frameUsed]; + while (frameLeft >= 4) { + if (bal < 0) { + if (userCount < 4) + break; + data = get_user(((u_int *)userPtr)++); + userCount -= 4; + bal += hSpeed; + } + *p++ = data; + frameLeft -= 4; + bal -= sSpeed; + } + } + sound.bal = bal; + sound.data = data; + used -= userCount; + *frameUsed += usedf-frameLeft; + return(used); +} + + +static long ata_ctx_u16be(const u_char *userPtr, long userCount, u_char frame[], + long *frameUsed, long frameLeft) +{ + /* this should help gcc to stuff everything into registers */ + u_long data = sound.data; + long bal = sound.bal; + long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; + long used, usedf; + + used = userCount; + usedf = frameLeft; + if (!sound.soft.stereo) { + u_short *p = (u_short *)&frame[*frameUsed]; + while (frameLeft >= 4) { + if (bal < 0) { + if (userCount < 2) + break; + data = get_user(((u_short *)userPtr)++) ^ 0x8000; + userCount -= 2; + bal += hSpeed; + } + *p++ = data; + *p++ = data; + frameLeft -= 4; + bal -= sSpeed; + } + } else { + u_long *p = (u_long *)&frame[*frameUsed]; + while (frameLeft >= 4) { + if (bal < 0) { + if (userCount < 4) + break; + data = get_user(((u_int *)userPtr)++) ^ 0x80008000; + userCount -= 4; + bal += hSpeed; + } + *p++ = data; + frameLeft -= 4; + bal -= sSpeed; + } + } + sound.bal = bal; + sound.data = data; + used -= userCount; + *frameUsed += usedf-frameLeft; + return(used); +} + + +static long ata_ctx_s16le(const u_char *userPtr, long userCount, u_char frame[], + long *frameUsed, long frameLeft) +{ + /* this should help gcc to stuff everything into registers */ + u_long data = sound.data; + long bal = sound.bal; + long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; + long used, usedf; + + used = userCount; + usedf = frameLeft; + if (!sound.soft.stereo) { + u_short *p = (u_short *)&frame[*frameUsed]; + while (frameLeft >= 4) { + if (bal < 0) { + if (userCount < 2) + break; + data = get_user(((u_short *)userPtr)++); + data = le2be16(data); + userCount -= 2; + bal += hSpeed; + } + *p++ = data; + *p++ = data; + frameLeft -= 4; + bal -= sSpeed; + } + } else { + u_long *p = (u_long *)&frame[*frameUsed]; + while (frameLeft >= 4) { + if (bal < 0) { + if (userCount < 4) + break; + data = get_user(((u_int *)userPtr)++); + data = le2be16dbl(data); + userCount -= 4; + bal += hSpeed; + } + *p++ = data; + frameLeft -= 4; + bal -= sSpeed; + } + } + sound.bal = bal; + sound.data = data; + used -= userCount; + *frameUsed += usedf-frameLeft; + return(used); +} + + +static long ata_ctx_u16le(const u_char *userPtr, long userCount, u_char frame[], + long *frameUsed, long frameLeft) +{ + /* this should help gcc to stuff everything into registers */ + u_long data = sound.data; + long bal = sound.bal; + long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; + long used, usedf; + + used = userCount; + usedf = frameLeft; + if (!sound.soft.stereo) { + u_short *p = (u_short *)&frame[*frameUsed]; + while (frameLeft >= 4) { + if (bal < 0) { + if (userCount < 2) + break; + data = get_user(((u_short *)userPtr)++); + data = le2be16(data) ^ 0x8000; + userCount -= 2; + bal += hSpeed; + } + *p++ = data; + *p++ = data; + frameLeft -= 4; + bal -= sSpeed; + } + } else { + u_long *p = (u_long *)&frame[*frameUsed]; + while (frameLeft >= 4) { + if (bal < 0) { + if (userCount < 4) + break; + data = get_user(((u_int *)userPtr)++); + data = le2be16dbl(data) ^ 0x80008000; + userCount -= 4; + bal += hSpeed; + } + *p++ = data; + frameLeft -= 4; + bal -= sSpeed; + } + } + sound.bal = bal; + sound.data = data; + used -= userCount; + *frameUsed += usedf-frameLeft; + return(used); +} +#endif /* CONFIG_ATARI */ + + +#ifdef CONFIG_AMIGA +static long ami_ct_law(const u_char *userPtr, long userCount, u_char frame[], + long *frameUsed, long frameLeft) +{ + char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8; + long count, used; + + if (!sound.soft.stereo) { + u_char *p = &frame[*frameUsed]; + count = min(userCount, frameLeft) & ~1; + used = count; + while (count > 0) { + *p++ = table[get_user(userPtr++)]; + count--; + } + } else { + u_char *left = &frame[*frameUsed>>1]; + u_char *right = left+sq.block_size_half; + count = min(userCount, frameLeft)>>1 & ~1; + used = count*2; + while (count > 0) { + *left++ = table[get_user(userPtr++)]; + *right++ = table[get_user(userPtr++)]; + count--; + } + } + *frameUsed += used; + return(used); +} + + +static long ami_ct_s8(const u_char *userPtr, long userCount, u_char frame[], + long *frameUsed, long frameLeft) +{ + long count, used; + + if (!sound.soft.stereo) { + void *p = &frame[*frameUsed]; + count = min(userCount, frameLeft) & ~1; + used = count; + memcpy_fromfs(p, userPtr, count); + } else { + u_char *left = &frame[*frameUsed>>1]; + u_char *right = left+sq.block_size_half; + count = min(userCount, frameLeft)>>1 & ~1; + used = count*2; + while (count > 0) { + *left++ = get_user(userPtr++); + *right++ = get_user(userPtr++); + count--; + } + } + *frameUsed += used; + return(used); +} + + +static long ami_ct_u8(const u_char *userPtr, long userCount, u_char frame[], + long *frameUsed, long frameLeft) +{ + long count, used; + + if (!sound.soft.stereo) { + char *p = &frame[*frameUsed]; + count = min(userCount, frameLeft) & ~1; + used = count; + while (count > 0) { + *p++ = get_user(userPtr++) ^ 0x80; + count--; + } + } else { + u_char *left = &frame[*frameUsed>>1]; + u_char *right = left+sq.block_size_half; + count = min(userCount, frameLeft)>>1 & ~1; + used = count*2; + while (count > 0) { + *left++ = get_user(userPtr++) ^ 0x80; + *right++ = get_user(userPtr++) ^ 0x80; + count--; + } + } + *frameUsed += used; + return(used); +} + + +static long ami_ct_s16be(const u_char *userPtr, long userCount, u_char frame[], + long *frameUsed, long frameLeft) +{ + long count, used; + u_long data; + + if (!sound.soft.stereo) { + u_char *high = &frame[*frameUsed>>1]; + u_char *low = high+sq.block_size_half; + count = min(userCount, frameLeft)>>1 & ~1; + used = count*2; + while (count > 0) { + data = get_user(((u_short *)userPtr)++); + *high = data>>8; + *low = (data>>2) & 0x3f; + count--; + } + } else { + u_char *lefth = &frame[*frameUsed>>2]; + u_char *leftl = lefth+sq.block_size_quarter; + u_char *righth = lefth+sq.block_size_half; + u_char *rightl = righth+sq.block_size_quarter; + count = min(userCount, frameLeft)>>2 & ~1; + used = count*4; + while (count > 0) { + data = get_user(((u_short *)userPtr)++); + *lefth = data>>8; + *leftl = (data>>2) & 0x3f; + data = get_user(((u_short *)userPtr)++); + *righth = data>>8; + *rightl = (data>>2) & 0x3f; + count--; + } + } + *frameUsed += used; + return(used); +} + + +static long ami_ct_u16be(const u_char *userPtr, long userCount, u_char frame[], + long *frameUsed, long frameLeft) +{ + long count, used; + u_long data; + + if (!sound.soft.stereo) { + u_char *high = &frame[*frameUsed>>1]; + u_char *low = high+sq.block_size_half; + count = min(userCount, frameLeft)>>1 & ~1; + used = count*2; + while (count > 0) { + data = get_user(((u_short *)userPtr)++) ^ 0x8000; + *high = data>>8; + *low = (data>>2) & 0x3f; + count--; + } + } else { + u_char *lefth = &frame[*frameUsed>>2]; + u_char *leftl = lefth+sq.block_size_quarter; + u_char *righth = lefth+sq.block_size_half; + u_char *rightl = righth+sq.block_size_quarter; + count = min(userCount, frameLeft)>>2 & ~1; + used = count*4; + while (count > 0) { + data = get_user(((u_short *)userPtr)++) ^ 0x8000; + *lefth = data>>8; + *leftl = (data>>2) & 0x3f; + data = get_user(((u_short *)userPtr)++) ^ 0x8000; + *righth = data>>8; + *rightl = (data>>2) & 0x3f; + count--; + } + } + *frameUsed += used; + return(used); +} + + +static long ami_ct_s16le(const u_char *userPtr, long userCount, u_char frame[], + long *frameUsed, long frameLeft) +{ + long count, used; + u_long data; + + if (!sound.soft.stereo) { + u_char *high = &frame[*frameUsed>>1]; + u_char *low = high+sq.block_size_half; + count = min(userCount, frameLeft)>>1 & ~1; + used = count*2; + while (count > 0) { + data = get_user(((u_short *)userPtr)++); + data = le2be16(data); + *high = data>>8; + *low = (data>>2) & 0x3f; + count--; + } + } else { + u_char *lefth = &frame[*frameUsed>>2]; + u_char *leftl = lefth+sq.block_size_quarter; + u_char *righth = lefth+sq.block_size_half; + u_char *rightl = righth+sq.block_size_quarter; + count = min(userCount, frameLeft)>>2 & ~1; + used = count*4; + while (count > 0) { + data = get_user(((u_short *)userPtr)++); + data = le2be16(data); + *lefth = data>>8; + *leftl = (data>>2) & 0x3f; + data = get_user(((u_short *)userPtr)++); + data = le2be16(data); + *righth = data>>8; + *rightl = (data>>2) & 0x3f; + count--; + } + } + *frameUsed += used; + return(used); +} + + +static long ami_ct_u16le(const u_char *userPtr, long userCount, u_char frame[], + long *frameUsed, long frameLeft) +{ + long count, used; + u_long data; + + if (!sound.soft.stereo) { + u_char *high = &frame[*frameUsed>>1]; + u_char *low = high+sq.block_size_half; + count = min(userCount, frameLeft)>>1 & ~1; + used = count*2; + while (count > 0) { + data = get_user(((u_short *)userPtr)++); + data = le2be16(data) ^ 0x8000; + *high = data>>8; + *low = (data>>2) & 0x3f; + count--; + } + } else { + u_char *lefth = &frame[*frameUsed>>2]; + u_char *leftl = lefth+sq.block_size_quarter; + u_char *righth = lefth+sq.block_size_half; + u_char *rightl = righth+sq.block_size_quarter; + count = min(userCount, frameLeft)>>2 & ~1; + used = count*4; + while (count > 0) { + data = get_user(((u_short *)userPtr)++); + data = le2be16(data) ^ 0x8000; + *lefth = data>>8; + *leftl = (data>>2) & 0x3f; + data = get_user(((u_short *)userPtr)++); + data = le2be16(data) ^ 0x8000; + *righth = data>>8; + *rightl = (data>>2) & 0x3f; + count--; + } + } + *frameUsed += used; + return(used); +} +#endif /* CONFIG_AMIGA */ + + +#ifdef CONFIG_ATARI +static TRANS transTTNormal = { + ata_ct_law, ata_ct_law, ata_ct_s8, ata_ct_u8, NULL, NULL, NULL, NULL +}; + +static TRANS transTTExpanding = { + ata_ctx_law, ata_ctx_law, ata_ctx_s8, ata_ctx_u8, NULL, NULL, NULL, NULL +}; + +static TRANS transFalconNormal = { + ata_ct_law, ata_ct_law, ata_ct_s8, ata_ct_u8, ata_ct_s16be, ata_ct_u16be, + ata_ct_s16le, ata_ct_u16le +}; + +static TRANS transFalconExpanding = { + ata_ctx_law, ata_ctx_law, ata_ctx_s8, ata_ctx_u8, ata_ctx_s16be, + ata_ctx_u16be, ata_ctx_s16le, ata_ctx_u16le +}; +#endif /* CONFIG_ATARI */ + +#ifdef CONFIG_AMIGA +static TRANS transAmiga = { + ami_ct_law, ami_ct_law, ami_ct_s8, ami_ct_u8, ami_ct_s16be, ami_ct_u16be, + ami_ct_s16le, ami_ct_u16le +}; +#endif /* CONFIG_AMIGA */ + + +/*** Low level stuff *********************************************************/ + + +#ifdef CONFIG_ATARI + +/* + * Atari (TT/Falcon) + */ + +static void *AtaAlloc(unsigned int size, int flags) +{ + int order; + unsigned int a_size; + order = 0; + a_size = PAGE_SIZE; + while (a_size < size) { + order++; + a_size <<= 1; + } + return (void *) __get_dma_pages(flags, order); +} + +static void AtaFree(void *obj, unsigned int size) +{ + int order; + unsigned int a_size; + order = 0; + a_size = PAGE_SIZE; + while (a_size < size) { + order++; + a_size <<= 1; + } + free_pages (obj, order); +} + +static int AtaIrqInit(void) +{ + /* Set up timer A. Timer A + will receive a signal upon end of playing from the sound + hardware. Furthermore Timer A is able to count events + and will cause an interrupt after a programmed number + of events. So all we need to keep the music playing is + to provide the sound hardware with new data upon + an interrupt from timer A. */ + mfp.tim_ct_a = 0; /* ++roman: Stop timer before programming! */ + mfp.tim_dt_a = 1; /* Cause interrupt after first event. */ + mfp.tim_ct_a = 8; /* Turn on event counting. */ + /* Register interrupt handler. */ + add_isr(IRQ_MFP_TIMA, ata_sq_interrupt, IRQ_TYPE_SLOW, NULL, "DMA sound"); + mfp.int_en_a |= 0x20; /* Turn interrupt on. */ + mfp.int_mk_a |= 0x20; + return(1); +} + + +#define TONE_VOXWARE_TO_DB(v) \ + (((v) < 0) ? -12 : ((v) > 100) ? 12 : ((v) - 50) * 6 / 25) +#define TONE_DB_TO_VOXWARE(v) (((v) * 25 + ((v) > 0 ? 5 : -5)) / 6 + 50) + + +static int AtaSetBass(int bass) +{ + sound.bass = TONE_VOXWARE_TO_DB(bass); + atari_microwire_cmd(MW_LM1992_BASS(sound.bass)); + return(TONE_DB_TO_VOXWARE(sound.bass)); +} + + +static int AtaSetTreble(int treble) +{ + sound.treble = TONE_VOXWARE_TO_DB(treble); + atari_microwire_cmd(MW_LM1992_TREBLE(sound.treble)); + return(TONE_DB_TO_VOXWARE(sound.treble)); +} + + + +/* + * TT + */ + + +static void TTSilence(void) +{ + tt_dmasnd.ctrl = DMASND_CTRL_OFF; + atari_microwire_cmd(MW_LM1992_PSG_HIGH); /* mix in PSG signal 1:1 */ +} + + +static void TTInit(void) +{ + int mode, i, idx; + const int freq[4] = {50066, 25033, 12517, 6258}; + + /* search a frequency that fits into the allowed error range */ + + idx = -1; + for (i = 0; i < arraysize(freq); i++) + /* this isn't as much useful for a TT than for a Falcon, but + * then it doesn't hurt very much to implement it for a TT too. + */ + if ((100 * abs(sound.soft.speed - freq[i]) / freq[i]) < catchRadius) + idx = i; + if (idx > -1) { + sound.soft.speed = freq[idx]; + sound.trans = &transTTNormal; + } else + sound.trans = &transTTExpanding; + + TTSilence(); + sound.hard = sound.soft; + + if (sound.hard.speed > 50066) { + /* we would need to squeeze the sound, but we won't do that */ + sound.hard.speed = 50066; + mode = DMASND_MODE_50KHZ; + sound.trans = &transTTNormal; + } else if (sound.hard.speed > 25033) { + sound.hard.speed = 50066; + mode = DMASND_MODE_50KHZ; + } else if (sound.hard.speed > 12517) { + sound.hard.speed = 25033; + mode = DMASND_MODE_25KHZ; + } else if (sound.hard.speed > 6258) { + sound.hard.speed = 12517; + mode = DMASND_MODE_12KHZ; + } else { + sound.hard.speed = 6258; + mode = DMASND_MODE_6KHZ; + } + + tt_dmasnd.mode = (sound.hard.stereo ? + DMASND_MODE_STEREO : DMASND_MODE_MONO) | + DMASND_MODE_8BIT | mode; + + sound.bal = -sound.soft.speed; +} + + +static int TTSetFormat(int format) +{ + /* TT sound DMA supports only 8bit modes */ + + switch (format) { + case AFMT_QUERY: + return(sound.soft.format); + case AFMT_MU_LAW: + case AFMT_A_LAW: + case AFMT_S8: + case AFMT_U8: + break; + default: + format = AFMT_S8; + } + + sound.soft.format = format; + sound.soft.size = 8; + if (sound.minDev == SND_DEV_DSP) { + sound.dsp.format = format; + sound.dsp.size = 8; + } + TTInit(); + + return(format); +} + + +#define VOLUME_VOXWARE_TO_DB(v) \ + (((v) < 0) ? -40 : ((v) > 100) ? 0 : ((v) * 2) / 5 - 40) +#define VOLUME_DB_TO_VOXWARE(v) ((((v) + 40) * 5 + 1) / 2) + + +static int TTSetVolume(int volume) +{ + sound.volume_left = VOLUME_VOXWARE_TO_DB(volume & 0xff); + atari_microwire_cmd(MW_LM1992_BALLEFT(sound.volume_left)); + sound.volume_right = VOLUME_VOXWARE_TO_DB((volume & 0xff00) >> 8); + atari_microwire_cmd(MW_LM1992_BALRIGHT(sound.volume_right)); + return(VOLUME_DB_TO_VOXWARE(sound.volume_left) | + (VOLUME_DB_TO_VOXWARE(sound.volume_right) << 8)); +} + + + +/* + * Falcon + */ + + +static void FalconSilence(void) +{ + /* stop playback, set sample rate 50kHz for PSG sound */ + tt_dmasnd.ctrl = DMASND_CTRL_OFF; + tt_dmasnd.mode = DMASND_MODE_50KHZ | DMASND_MODE_STEREO | DMASND_MODE_8BIT; + tt_dmasnd.int_div = 0; /* STE compatible divider */ + tt_dmasnd.int_ctrl = 0x0; + tt_dmasnd.cbar_src = 0x0000; /* no matrix inputs */ + tt_dmasnd.cbar_dst = 0x0000; /* no matrix outputs */ + tt_dmasnd.dac_src = 1; /* connect ADC to DAC, disconnect matrix */ + tt_dmasnd.adc_src = 3; /* ADC Input = PSG */ +} + + +static void FalconInit(void) +{ + int divider, i, idx; + const int freq[8] = {49170, 32780, 24585, 19668, 16390, 12292, 9834, 8195}; + + /* search a frequency that fits into the allowed error range */ + + idx = -1; + for (i = 0; i < arraysize(freq); i++) + /* if we will tolerate 3% error 8000Hz->8195Hz (2.38%) would + * be playable without expanding, but that now a kernel runtime + * option + */ + if ((100 * abs(sound.soft.speed - freq[i]) / freq[i]) < catchRadius) + idx = i; + if (idx > -1) { + sound.soft.speed = freq[idx]; + sound.trans = &transFalconNormal; + } else + sound.trans = &transFalconExpanding; + + FalconSilence(); + sound.hard = sound.soft; + + if (sound.hard.size == 16) { + /* the Falcon can play 16bit samples only in stereo */ + sound.hard.stereo = 1; + } + + if (sound.hard.speed > 49170) { + /* we would need to squeeze the sound, but we won't do that */ + sound.hard.speed = 49170; + divider = 1; + sound.trans = &transFalconNormal; + } else if (sound.hard.speed > 32780) { + sound.hard.speed = 49170; + divider = 1; + } else if (sound.hard.speed > 24585) { + sound.hard.speed = 32780; + divider = 2; + } else if (sound.hard.speed > 19668) { + sound.hard.speed = 24585; + divider = 3; + } else if (sound.hard.speed > 16390) { + sound.hard.speed = 19668; + divider = 4; + } else if (sound.hard.speed > 12292) { + sound.hard.speed = 16390; + divider = 5; + } else if (sound.hard.speed > 9834) { + sound.hard.speed = 12292; + divider = 7; + } else if (sound.hard.speed > 8195) { + sound.hard.speed = 9834; + divider = 9; + } else { + sound.hard.speed = 8195; + divider = 11; + } + tt_dmasnd.int_div = divider; + + /* Setup Falcon sound DMA for playback */ + tt_dmasnd.int_ctrl = 0x4; /* Timer A int at play end */ + tt_dmasnd.track_select = 0x0; /* play 1 track, track 1 */ + tt_dmasnd.cbar_src = 0x0001; /* DMA(25MHz) --> DAC */ + tt_dmasnd.cbar_dst = 0x0000; + tt_dmasnd.rec_track_select = 0; + tt_dmasnd.dac_src = 2; /* connect matrix to DAC */ + tt_dmasnd.adc_src = 0; /* ADC Input = Mic */ + + tt_dmasnd.mode = (sound.hard.stereo ? + DMASND_MODE_STEREO : DMASND_MODE_MONO) | + ((sound.hard.size == 8) ? + DMASND_MODE_8BIT : DMASND_MODE_16BIT) | + DMASND_MODE_6KHZ; + + sound.bal = -sound.soft.speed; +} + + +static int FalconSetFormat(int format) +{ + int size; + /* Falcon sound DMA supports 8bit and 16bit modes */ + + switch (format) { + case AFMT_QUERY: + return(sound.soft.format); + case AFMT_MU_LAW: + case AFMT_A_LAW: + case AFMT_U8: + case AFMT_S8: + size = 8; + break; + case AFMT_S16_BE: + case AFMT_U16_BE: + case AFMT_S16_LE: + case AFMT_U16_LE: + size = 16; + break; + default: /* :-) */ + size = 8; + format = AFMT_S8; + } + + sound.soft.format = format; + sound.soft.size = size; + if (sound.minDev == SND_DEV_DSP) { + sound.dsp.format = format; + sound.dsp.size = sound.soft.size; + } + + FalconInit(); + + return(format); +} + + +/* This is for the Falcon output *attenuation* in 1.5dB steps, + * i.e. output level from 0 to -22.5dB in -1.5dB steps. + */ +#define VOLUME_VOXWARE_TO_ATT(v) \ + ((v) < 0 ? 15 : (v) > 100 ? 0 : 15 - (v) * 3 / 20) +#define VOLUME_ATT_TO_VOXWARE(v) (100 - (v) * 20 / 3) + + +static int FalconSetVolume(int volume) +{ + sound.volume_left = VOLUME_VOXWARE_TO_ATT(volume & 0xff); + sound.volume_right = VOLUME_VOXWARE_TO_ATT((volume & 0xff00) >> 8); + tt_dmasnd.output_atten = sound.volume_left << 8 | sound.volume_right << 4; + return(VOLUME_ATT_TO_VOXWARE(sound.volume_left) | + VOLUME_ATT_TO_VOXWARE(sound.volume_right) << 8); +} + + +static void ata_sq_play_next_frame(int index) +{ + char *start, *end; + + /* used by AtaPlay() if all doubts whether there really is something + * to be played are already wiped out. + */ + start = sq_block_address(sq.front); + end = start+((sq.count == index) ? sq.rear_size : sq.block_size); + /* end might not be a legal virtual address. */ + DMASNDSetEnd(VTOP(end - 1) + 1); + DMASNDSetBase(VTOP(start)); + /* Since only an even number of samples per frame can + be played, we might lose one byte here. (TO DO) */ + sq.front = (sq.front+1) % sq.max_count; + sq.playing++; + tt_dmasnd.ctrl = DMASND_CTRL_ON | DMASND_CTRL_REPEAT; +} + + +static void AtaPlay(void) +{ + /* ++TeSche: Note that sq.playing is no longer just a flag but holds + * the number of frames the DMA is currently programmed for instead, + * may be 0, 1 (currently being played) or 2 (pre-programmed). + * + * Changes done to sq.count and sq.playing are a bit more subtle again + * so now I must admit I also prefer disabling the irq here rather + * than considering all possible situations. But the point is that + * disabling the irq doesn't have any bad influence on this version of + * the driver as we benefit from having pre-programmed the DMA + * whereever possible: There's no need to reload the DMA at the exact + * time of an interrupt but only at some time while the pre-programmed + * frame is playing! + */ + atari_disable_irq(IRQ_MFP_TIMA); + + if (sq.playing == 2 || /* DMA is 'full' */ + sq.count <= 0) { /* nothing to do */ + atari_enable_irq(IRQ_MFP_TIMA); + return; + } + + if (sq.playing == 0) { + /* looks like there's nothing 'in' the DMA yet, so try + * to put two frames into it (at least one is available). + */ + if (sq.count == 1 && sq.rear_size < sq.block_size && !sq.syncing) { + /* hmmm, the only existing frame is not + * yet filled and we're not syncing? + */ + atari_enable_irq(IRQ_MFP_TIMA); + return; + } + ata_sq_play_next_frame(1); + if (sq.count == 1) { + /* no more frames */ + atari_enable_irq(IRQ_MFP_TIMA); + return; + } + if (sq.count == 2 && sq.rear_size < sq.block_size && !sq.syncing) { + /* hmmm, there were two frames, but the second + * one is not yet filled and we're not syncing? + */ + atari_enable_irq(IRQ_MFP_TIMA); + return; + } + ata_sq_play_next_frame(2); + } else { + /* there's already a frame being played so we may only stuff + * one new into the DMA, but even if this may be the last + * frame existing the previous one is still on sq.count. + */ + if (sq.count == 2 && sq.rear_size < sq.block_size && !sq.syncing) { + /* hmmm, the only existing frame is not + * yet filled and we're not syncing? + */ + atari_enable_irq(IRQ_MFP_TIMA); + return; + } + ata_sq_play_next_frame(2); + } + atari_enable_irq(IRQ_MFP_TIMA); +} + + +static void ata_sq_interrupt(int irq, struct pt_regs *fp, void *dummy) +{ +#if 0 + /* ++TeSche: if you should want to test this... */ + static int cnt = 0; + if (sq.playing == 2) + if (++cnt == 10) { + /* simulate losing an interrupt */ + cnt = 0; + return; + } +#endif + + if (sq.ignore_int && (sound.mach.type == DMASND_FALCON)) { + /* ++TeSche: Falcon only: ignore first irq because it comes + * immediately after starting a frame. after that, irqs come + * (almost) like on the TT. + */ + sq.ignore_int = 0; + return; + } + + if (!sq.playing) { + /* playing was interrupted and sq_reset() has already cleared + * the sq variables, so better don't do anything here. + */ + WAKE_UP(sq.sync_queue); + return; + } + + /* Probably ;) one frame is finished. Well, in fact it may be that a + * pre-programmed one is also finished because there has been a long + * delay in interrupt delivery and we've completely lost one, but + * there's no way to detect such a situation. In such a case the last + * frame will be played more than once and the situation will recover + * as soon as the irq gets through. + */ + sq.count--; + sq.playing--; + + if (!sq.playing) { + tt_dmasnd.ctrl = DMASND_CTRL_OFF; + sq.ignore_int = 1; + } + + WAKE_UP(sq.write_queue); + /* At least one block of the queue is free now + so wake up a writing process blocked because + of a full queue. */ + + if ((sq.playing != 1) || (sq.count != 1)) + /* We must be a bit carefully here: sq.count indicates the + * number of buffers used and not the number of frames to + * be played. If sq.count==1 and sq.playing==1 that means + * the only remaining frame was already programmed earlier + * (and is currently running) so we mustn't call AtaPlay() + * here, otherwise we'll play one frame too much. + */ + AtaPlay(); + + if (!sq.playing) WAKE_UP(sq.sync_queue); + /* We are not playing after AtaPlay(), so there + is nothing to play any more. Wake up a process + waiting for audio output to drain. */ +} +#endif /* CONFIG_ATARI */ + + +#ifdef CONFIG_AMIGA + +/* + * Amiga + */ + + +static void *AmiAlloc(unsigned int size, int flags) +{ + return(amiga_chip_alloc((long)size)); +} + +static void AmiFree(void *obj, unsigned int size) +{ + amiga_chip_free (obj); +} + +static int AmiIrqInit(void) +{ + /* turn off DMA for audio channels */ + custom.dmacon = AMI_AUDIO_OFF; + + /* Register interrupt handler. */ + if (!add_isr(IRQ_AMIGA_AUD0, ami_sq_interrupt, 0, NULL, "DMA sound")) + panic("Couldn't add audio interrupt"); + return(1); +} + + +static void AmiSilence(void) +{ + /* turn off DMA for audio channels */ + custom.dmacon = AMI_AUDIO_OFF; +} + + +static void AmiInit(void) +{ + int period, i; + + AmiSilence(); + + if (sound.soft.speed) + period = amiga_colorclock/sound.soft.speed-1; + else + period = amiga_audio_min_period; + sound.hard = sound.soft; + sound.trans = &transAmiga; + + if (period < amiga_audio_min_period) { + /* we would need to squeeze the sound, but we won't do that */ + period = amiga_audio_min_period; + sound.hard.speed = amiga_colorclock/(period+1); + } else if (period > 65535) { + period = 65535; + sound.hard.speed = amiga_colorclock/(period+1); + } + for (i = 0; i < 4; i++) + custom.aud[i].audper = period; + amiga_audio_period = period; +} + + +static int AmiSetFormat(int format) +{ + int size; + + /* Amiga sound DMA supports 8bit and 16bit (pseudo 14 bit) modes */ + + switch (format) { + case AFMT_QUERY: + return(sound.soft.format); + case AFMT_MU_LAW: + case AFMT_A_LAW: + case AFMT_U8: + case AFMT_S8: + size = 8; + break; + case AFMT_S16_BE: + case AFMT_U16_BE: + case AFMT_S16_LE: + case AFMT_U16_LE: + size = 16; + break; + default: /* :-) */ + size = 8; + format = AFMT_S8; + } + + sound.soft.format = format; + sound.soft.size = size; + if (sound.minDev == SND_DEV_DSP) { + sound.dsp.format = format; + sound.dsp.size = sound.soft.size; + } + AmiInit(); + + return(format); +} + + +#define VOLUME_VOXWARE_TO_AMI(v) \ + (((v) < 0) ? 0 : ((v) > 100) ? 64 : ((v) * 64)/100) +#define VOLUME_AMI_TO_VOXWARE(v) ((v)*100/64) + +static int AmiSetVolume(int volume) +{ + sound.volume_left = VOLUME_VOXWARE_TO_AMI(volume & 0xff); + custom.aud[0].audvol = sound.volume_left; + sound.volume_right = VOLUME_VOXWARE_TO_AMI((volume & 0xff00) >> 8); + custom.aud[1].audvol = sound.volume_right; + return(VOLUME_AMI_TO_VOXWARE(sound.volume_left) | + (VOLUME_AMI_TO_VOXWARE(sound.volume_right) << 8)); +} + +static int AmiSetTreble(int treble) +{ + sound.treble = treble; + if (treble > 50) + ciaa.pra |= 0x02; + else + ciaa.pra &= ~0x02; + return(treble); +} + + +#define AMI_PLAY_LOADED 1 +#define AMI_PLAY_PLAYING 2 +#define AMI_PLAY_MASK 3 + + +static void ami_sq_play_next_frame(int index) +{ + u_char *start, *ch0, *ch1, *ch2, *ch3; + u_long size; + + /* used by AmiPlay() if all doubts whether there really is something + * to be played are already wiped out. + */ + start = sq_block_address(sq.front); + size = (sq.count == index ? sq.rear_size : sq.block_size)>>1; + + if (sound.hard.stereo) { + ch0 = start; + ch1 = start+sq.block_size_half; + size >>= 1; + } else { + ch0 = start; + ch1 = start; + } + if (sound.hard.size == 8) { + custom.aud[0].audlc = (u_short *)ZTWO_PADDR(ch0); + custom.aud[0].audlen = size; + custom.aud[1].audlc = (u_short *)ZTWO_PADDR(ch1); + custom.aud[1].audlen = size; + custom.dmacon = AMI_AUDIO_8; + } else { + size >>= 1; + custom.aud[0].audlc = (u_short *)ZTWO_PADDR(ch0); + custom.aud[0].audlen = size; + custom.aud[1].audlc = (u_short *)ZTWO_PADDR(ch1); + custom.aud[1].audlen = size; + if (sound.volume_left == 64 && sound.volume_right == 64) { + /* We can play pseudo 14-bit only with the maximum volume */ + ch3 = ch0+sq.block_size_quarter; + ch2 = ch1+sq.block_size_quarter; + custom.aud[2].audlc = (u_short *)ZTWO_PADDR(ch2); + custom.aud[2].audlen = size; + custom.aud[3].audlc = (u_short *)ZTWO_PADDR(ch3); + custom.aud[3].audlen = size; + custom.dmacon = AMI_AUDIO_14; + } else + custom.dmacon = AMI_AUDIO_8; + } + sq.front = (sq.front+1) % sq.max_count; + sq.playing |= AMI_PLAY_LOADED; +} + + +static void AmiPlay(void) +{ + int minframes = 1; + + custom.intena = IF_AUD0; + + if (sq.playing & AMI_PLAY_LOADED) { + /* There's already a frame loaded */ + custom.intena = IF_SETCLR | IF_AUD0; + return; + } + + if (sq.playing & AMI_PLAY_PLAYING) + /* Increase threshold: frame 1 is already being played */ + minframes = 2; + + if (sq.count < minframes) { + /* Nothing to do */ + custom.intena = IF_SETCLR | IF_AUD0; + return; + } + + if (sq.count <= minframes && sq.rear_size < sq.block_size && !sq.syncing) { + /* hmmm, the only existing frame is not + * yet filled and we're not syncing? + */ + custom.intena = IF_SETCLR | IF_AUD0; + return; + } + + ami_sq_play_next_frame(minframes); + + custom.intena = IF_SETCLR | IF_AUD0; +} + + +static void ami_sq_interrupt(int irq, struct pt_regs *fp, void *dummy) +{ + int minframes = 1; + + if (!sq.playing) { + /* Playing was interrupted and sq_reset() has already cleared + * the sq variables, so better don't do anything here. + */ + WAKE_UP(sq.sync_queue); + return; + } + + if (sq.playing & AMI_PLAY_PLAYING) { + /* We've just finished a frame */ + sq.count--; + WAKE_UP(sq.write_queue); + } + + if (sq.playing & AMI_PLAY_LOADED) + /* Increase threshold: frame 1 is already being played */ + minframes = 2; + + /* Shift the flags */ + sq.playing = (sq.playing<<1) & AMI_PLAY_MASK; + + if (!sq.playing) + /* No frame is playing, disable audio DMA */ + custom.dmacon = AMI_AUDIO_OFF; + + if (sq.count >= minframes) + /* Try to play the next frame */ + AmiPlay(); + + if (!sq.playing) + /* Nothing to play anymore. + Wake up a process waiting for audio output to drain. */ + WAKE_UP(sq.sync_queue); +} +#endif /* CONFIG_AMIGA */ + + +/*** Machine definitions *****************************************************/ + + +#ifdef CONFIG_ATARI +static MACHINE machTT = { + DMASND_TT, AtaAlloc, AtaFree, AtaIrqInit, TTInit, TTSilence, TTSetFormat, + TTSetVolume, AtaSetBass, AtaSetTreble, AtaPlay +}; + +static MACHINE machFalcon = { + DMASND_FALCON, AtaAlloc, AtaFree, AtaIrqInit, FalconInit, FalconSilence, + FalconSetFormat, FalconSetVolume, AtaSetBass, AtaSetTreble, AtaPlay +}; +#endif /* CONFIG_ATARI */ + +#ifdef CONFIG_AMIGA +static MACHINE machAmiga = { + DMASND_AMIGA, AmiAlloc, AmiFree, AmiIrqInit, AmiInit, AmiSilence, + AmiSetFormat, AmiSetVolume, NULL, AmiSetTreble, AmiPlay +}; +#endif /* CONFIG_AMIGA */ + + +/*** Mid level stuff *********************************************************/ + + +static void sound_silence(void) +{ + /* update hardware settings one more */ + (*sound.mach.init)(); + + (*sound.mach.silence)(); +} + + +static void sound_init(void) +{ + (*sound.mach.init)(); +} + + +static int sound_set_format(int format) +{ + return(*sound.mach.setFormat)(format); +} + + +static int sound_set_speed(int speed) +{ + if (speed < 0) + return(sound.soft.speed); + + sound.soft.speed = speed; + (*sound.mach.init)(); + if (sound.minDev == SND_DEV_DSP) + sound.dsp.speed = sound.soft.speed; + + return(sound.soft.speed); +} + + +static int sound_set_stereo(int stereo) +{ + if (stereo < 0) + return(sound.soft.stereo); + + stereo = !!stereo; /* should be 0 or 1 now */ + + sound.soft.stereo = stereo; + if (sound.minDev == SND_DEV_DSP) + sound.dsp.stereo = stereo; + (*sound.mach.init)(); + + return(stereo); +} + + +static int sound_set_volume(int volume) +{ + return(*sound.mach.setVolume)(volume); +} + + +#ifdef CONFIG_ATARI +static int sound_set_bass(int bass) +{ + return(sound.mach.setBass ? (*sound.mach.setBass)(bass) : 50); +} +#endif /* CONFIG_ATARI */ + + +static int sound_set_treble(int treble) +{ + return(sound.mach.setTreble ? (*sound.mach.setTreble)(treble) : 50); +} + + +static long sound_copy_translate(const u_char *userPtr, long userCount, + u_char frame[], long *frameUsed, + long frameLeft) +{ + long (*ct_func)(const u_char *, long, u_char *, long *, long) = NULL; + + switch (sound.soft.format) { + case AFMT_MU_LAW: + ct_func = sound.trans->ct_ulaw; + break; + case AFMT_A_LAW: + ct_func = sound.trans->ct_alaw; + break; + case AFMT_S8: + ct_func = sound.trans->ct_s8; + break; + case AFMT_U8: + ct_func = sound.trans->ct_u8; + break; + case AFMT_S16_BE: + ct_func = sound.trans->ct_s16be; + break; + case AFMT_U16_BE: + ct_func = sound.trans->ct_u16be; + break; + case AFMT_S16_LE: + ct_func = sound.trans->ct_s16le; + break; + case AFMT_U16_LE: + ct_func = sound.trans->ct_u16le; + break; + } + if (ct_func) + return(ct_func(userPtr, userCount, frame, frameUsed, frameLeft)); + else + return(0); +} + + +/* + * /dev/mixer abstraction + */ + + +#define RECLEVEL_VOXWARE_TO_GAIN(v) \ + ((v) < 0 ? 0 : (v) > 100 ? 15 : (v) * 3 / 20) +#define RECLEVEL_GAIN_TO_VOXWARE(v) (((v) * 20 + 2) / 3) + + +static void mixer_init(void) +{ + mixer.busy = 0; + sound.treble = 0; + sound.bass = 0; + switch (sound.mach.type) { +#ifdef CONFIG_ATARI + case DMASND_TT: + atari_microwire_cmd(MW_LM1992_VOLUME(0)); + sound.volume_left = 0; + atari_microwire_cmd(MW_LM1992_BALLEFT(0)); + sound.volume_right = 0; + atari_microwire_cmd(MW_LM1992_BALRIGHT(0)); + atari_microwire_cmd(MW_LM1992_TREBLE(0)); + atari_microwire_cmd(MW_LM1992_BASS(0)); + break; + case DMASND_FALCON: + sound.volume_left = (tt_dmasnd.output_atten & 0xf00) >> 8; + sound.volume_right = (tt_dmasnd.output_atten & 0xf0) >> 4; + break; +#endif /* CONFIG_ATARI */ +#ifdef CONFIG_AMIGA + case DMASND_AMIGA: + sound.volume_left = 64; + sound.volume_right = 64; + custom.aud[0].audvol = sound.volume_left; + custom.aud[3].audvol = 1; /* For pseudo 14bit */ + custom.aud[1].audvol = sound.volume_right; + custom.aud[2].audvol = 1; /* For pseudo 14bit */ + sound.treble = 50; + break; +#endif /* CONFIG_AMIGA */ + } +} + + +static int mixer_open(int open_mode) +{ + if (mixer.busy) + return(-EBUSY); + mixer.busy = 1; + return(0); +} + + +static int mixer_release(void) +{ + mixer.busy = 0; + return(0); +} + + +static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd, + u_long arg) +{ + switch (sound.mach.type) { +#ifdef CONFIG_ATARI + case DMASND_FALCON: + switch (cmd) { + case SOUND_MIXER_READ_DEVMASK: + return(IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC | SOUND_MASK_SPEAKER)); + case SOUND_MIXER_READ_RECMASK: + return(IOCTL_OUT(arg, SOUND_MASK_MIC)); + case SOUND_MIXER_READ_STEREODEVS: + return(IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC)); + case SOUND_MIXER_READ_CAPS: + return(IOCTL_OUT(arg, SOUND_CAP_EXCL_INPUT)); + case SOUND_MIXER_READ_VOLUME: + return(IOCTL_OUT(arg, + VOLUME_ATT_TO_VOXWARE(sound.volume_left) | + VOLUME_ATT_TO_VOXWARE(sound.volume_right) << 8)); + case SOUND_MIXER_WRITE_MIC: + tt_dmasnd.input_gain = + RECLEVEL_VOXWARE_TO_GAIN(IOCTL_IN(arg) & 0xff) << 4 | + RECLEVEL_VOXWARE_TO_GAIN(IOCTL_IN(arg) >> 8 & 0xff); + /* fall thru, return set value */ + case SOUND_MIXER_READ_MIC: + return(IOCTL_OUT(arg, + RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain >> 4 & 0xf) | + RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain & 0xf) << 8)); + case SOUND_MIXER_READ_SPEAKER: + { + int porta; + cli(); + sound_ym.rd_data_reg_sel = 14; + porta = sound_ym.rd_data_reg_sel; + sti(); + return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100)); + } + case SOUND_MIXER_WRITE_VOLUME: + return(IOCTL_OUT(arg, sound_set_volume(IOCTL_IN(arg)))); + case SOUND_MIXER_WRITE_SPEAKER: + { + int porta; + cli(); + sound_ym.rd_data_reg_sel = 14; + porta = (sound_ym.rd_data_reg_sel & ~0x40) | + (IOCTL_IN(arg) < 50 ? 0x40 : 0); + sound_ym.wd_data = porta; + sti(); + return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100)); + } + } + break; + + case DMASND_TT: + switch (cmd) { + case SOUND_MIXER_READ_DEVMASK: + return(IOCTL_OUT(arg, + SOUND_MASK_VOLUME | SOUND_MASK_TREBLE | SOUND_MASK_BASS | + ((boot_info.bi_atari.mch_cookie >> 16) == ATARI_MCH_TT ? + SOUND_MASK_SPEAKER : 0))); + case SOUND_MIXER_READ_RECMASK: + return(IOCTL_OUT(arg, 0)); + case SOUND_MIXER_READ_STEREODEVS: + return(IOCTL_OUT(arg, SOUND_MASK_VOLUME)); + case SOUND_MIXER_READ_VOLUME: + return(IOCTL_OUT(arg, + VOLUME_DB_TO_VOXWARE(sound.volume_left) | + (VOLUME_DB_TO_VOXWARE(sound.volume_right) << 8))); + case SOUND_MIXER_READ_BASS: + return(IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(sound.bass))); + case SOUND_MIXER_READ_TREBLE: + return(IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(sound.treble))); + case SOUND_MIXER_READ_SPEAKER: + { + int porta; + if ((boot_info.bi_atari.mch_cookie >> 16) == ATARI_MCH_TT) { + cli(); + sound_ym.rd_data_reg_sel = 14; + porta = sound_ym.rd_data_reg_sel; + sti(); + return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100)); + } else + return(-EINVAL); + } + case SOUND_MIXER_WRITE_VOLUME: + return(IOCTL_OUT(arg, sound_set_volume(IOCTL_IN(arg)))); + case SOUND_MIXER_WRITE_BASS: + return(IOCTL_OUT(arg, sound_set_bass(IOCTL_IN(arg)))); + case SOUND_MIXER_WRITE_TREBLE: + return(IOCTL_OUT(arg, sound_set_treble(IOCTL_IN(arg)))); + case SOUND_MIXER_WRITE_SPEAKER: + if ((boot_info.bi_atari.mch_cookie >> 16) == ATARI_MCH_TT) { + int porta; + cli(); + sound_ym.rd_data_reg_sel = 14; + porta = (sound_ym.rd_data_reg_sel & ~0x40) | + (IOCTL_IN(arg) < 50 ? 0x40 : 0); + sound_ym.wd_data = porta; + sti(); + return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100)); + } else + return(-EINVAL); + } + break; +#endif /* CONFIG_ATARI */ + +#ifdef CONFIG_AMIGA + case DMASND_AMIGA: + switch (cmd) { + case SOUND_MIXER_READ_DEVMASK: + return(IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_TREBLE)); + case SOUND_MIXER_READ_RECMASK: + return(IOCTL_OUT(arg, 0)); + case SOUND_MIXER_READ_STEREODEVS: + return(IOCTL_OUT(arg, SOUND_MASK_VOLUME)); + case SOUND_MIXER_READ_VOLUME: + return(IOCTL_OUT(arg, + VOLUME_AMI_TO_VOXWARE(sound.volume_left) | + VOLUME_AMI_TO_VOXWARE(sound.volume_right) << 8)); + case SOUND_MIXER_WRITE_VOLUME: + return(IOCTL_OUT(arg, sound_set_volume(IOCTL_IN(arg)))); + case SOUND_MIXER_READ_TREBLE: + return(IOCTL_OUT(arg, sound.treble)); + case SOUND_MIXER_WRITE_TREBLE: + return(IOCTL_OUT(arg, sound_set_treble(IOCTL_IN(arg)))); + } + break; +#endif /* CONFIG_AMIGA */ + } + + return(-EINVAL); +} + + + +/* + * Sound queue stuff, the heart of the driver + */ + + +static void sq_init(int numBufs, int bufSize, char **buffers) +{ + sq.max_count = numBufs; + sq.block_size = bufSize; + sq.buffers = buffers; + + sq.front = sq.count = 0; + sq.rear = -1; + sq.write_queue = sq.open_queue = sq.sync_queue = 0; + sq.busy = 0; + sq.syncing = 0; + + sq.playing = 0; + +#ifdef CONFIG_ATARI + sq.ignore_int = 0; +#endif /* CONFIG_ATARI */ +#ifdef CONFIG_AMIGA + sq.block_size_half = sq.block_size>>1; + sq.block_size_quarter = sq.block_size_half>>1; +#endif /* CONFIG_AMIGA */ + + sound_silence(); + + /* whatever you like as startup mode for /dev/dsp, + * (/dev/audio hasn't got a startup mode). note that + * once changed a new open() will *not* restore these! + */ + sound.dsp.format = AFMT_S8; + sound.dsp.stereo = 0; + sound.dsp.size = 8; + + /* set minimum rate possible without expanding */ + switch (sound.mach.type) { +#ifdef CONFIG_ATARI + case DMASND_TT: + sound.dsp.speed = 6258; + break; + case DMASND_FALCON: + sound.dsp.speed = 8195; + break; +#endif /* CONFIG_ATARI */ +#ifdef CONFIG_AMIGA + case DMASND_AMIGA: + sound.dsp.speed = 8000; + break; +#endif /* CONFIG_AMIGA */ + } + + /* before the first open to /dev/dsp this wouldn't be set */ + sound.soft = sound.dsp; +} + + +static void sq_play(void) +{ + (*sound.mach.play)(); +} + + +/* ++TeSche: radically changed this one too */ + +static int sq_write(const char *src, int uLeft) +{ + int uWritten = 0; + u_char *dest; + long uUsed, bUsed, bLeft; + + /* ++TeSche: Is something like this necessary? + * Hey, that's an honest question! Or does any other part of the + * filesystem already checks this situation? I really don't know. + */ + if (uLeft < 1) + return(0); + + /* The interrupt doesn't start to play the last, incomplete frame. + * Thus we can append to it without disabling the interrupts! (Note + * also that sq.rear isn't affected by the interrupt.) + */ + + if (sq.count > 0 && (bLeft = sq.block_size-sq.rear_size) > 0) { + dest = sq_block_address(sq.rear); + bUsed = sq.rear_size; + uUsed = sound_copy_translate(src, uLeft, dest, &bUsed, bLeft); + src += uUsed; + uWritten += uUsed; + uLeft -= uUsed; + sq.rear_size = bUsed; + } + + do { + if (sq.count == sq.max_count) { + sq_play(); + if (NON_BLOCKING(sq.open_mode)) + return(uWritten > 0 ? uWritten : -EAGAIN); + SLEEP(sq.write_queue, ONE_SECOND); + if (SIGNAL_RECEIVED) + return(uWritten > 0 ? uWritten : -EINTR); + } + + /* Here, we can avoid disabling the interrupt by first + * copying and translating the data, and then updating + * the sq variables. Until this is done, the interrupt + * won't see the new frame and we can work on it + * undisturbed. + */ + + dest = sq_block_address((sq.rear+1) % sq.max_count); + bUsed = 0; + bLeft = sq.block_size; + uUsed = sound_copy_translate(src, uLeft, dest, &bUsed, bLeft); + src += uUsed; + uWritten += uUsed; + uLeft -= uUsed; + if (bUsed) { + sq.rear = (sq.rear+1) % sq.max_count; + sq.rear_size = bUsed; + sq.count++; + } + } while (bUsed); /* uUsed may have been 0 */ + + sq_play(); + + return(uWritten); +} + + +static int sq_open(int open_mode) +{ + if (sq.busy) { + if (NON_BLOCKING(open_mode)) + return(-EBUSY); + while (sq.busy) { + SLEEP(sq.open_queue, ONE_SECOND); + if (SIGNAL_RECEIVED) + return(-EINTR); + } + } + sq.open_mode = open_mode; + sq.busy = 1; +#ifdef CONFIG_ATARI + sq.ignore_int = 1; +#endif /* CONFIG_ATARI */ + return(0); +} + + +static void sq_reset(void) +{ + sound_silence(); + sq.playing = 0; + sq.count = 0; + sq.front = (sq.rear+1) % sq.max_count; +} + + +static int sq_sync(void) +{ + int rc = 0; + + sq.syncing = 1; + sq_play(); /* there may be an incomplete frame waiting */ + + while (sq.playing) { + SLEEP(sq.sync_queue, ONE_SECOND); + if (SIGNAL_RECEIVED) { + /* While waiting for audio output to drain, an interrupt occured. + Stop audio output immediately and clear the queue. */ + sq_reset(); + rc = -EINTR; + break; + } + } + + sq.syncing = 0; + return(rc); +} + + +static int sq_release(void) +{ + int rc = 0; + if (sq.busy) { + rc = sq_sync(); + sq.busy = 0; + WAKE_UP(sq.open_queue); + /* Wake up a process waiting for the queue beeing released. + Note: There may be several processes waiting for a call to open() + returning. */ + } + return(rc); +} + + + +/* + * /dev/sndstat + */ + + +static void state_init(void) +{ + state.busy = 0; +} + + +/* state.buf should not overflow! */ + +static int state_open(int open_mode) +{ + char *buffer = state.buf, *mach = ""; + int len = 0; + + if (state.busy) + return(-EBUSY); + + state.ptr = 0; + state.busy = 1; + + switch (sound.mach.type) { +#ifdef CONFIG_ATARI + case DMASND_TT: + case DMASND_FALCON: + mach = "Atari "; + break; +#endif /* CONFIG_ATARI */ +#ifdef CONFIG_AMIGA + case DMASND_AMIGA: + mach = "Amiga "; + break; +#endif /* CONFIG_AMIGA */ + } + len += sprintf(buffer+len, "%sDMA sound driver:\n", mach); + + len += sprintf(buffer+len, "\tsound.format = 0x%x", sound.soft.format); + switch (sound.soft.format) { + case AFMT_MU_LAW: + len += sprintf(buffer+len, " (mu-law)"); + break; + case AFMT_A_LAW: + len += sprintf(buffer+len, " (A-law)"); + break; + case AFMT_U8: + len += sprintf(buffer+len, " (unsigned 8 bit)"); + break; + case AFMT_S8: + len += sprintf(buffer+len, " (signed 8 bit)"); + break; + case AFMT_S16_BE: + len += sprintf(buffer+len, " (signed 16 bit big)"); + break; + case AFMT_U16_BE: + len += sprintf(buffer+len, " (unsigned 16 bit big)"); + break; + case AFMT_S16_LE: + len += sprintf(buffer+len, " (signed 16 bit little)"); + break; + case AFMT_U16_LE: + len += sprintf(buffer+len, " (unsigned 16 bit little)"); + break; + } + len += sprintf(buffer+len, "\n"); + len += sprintf(buffer+len, "\tsound.speed = %dHz (phys. %dHz)\n", + sound.soft.speed, sound.hard.speed); + len += sprintf(buffer+len, "\tsound.stereo = 0x%x (%s)\n", + sound.soft.stereo, sound.soft.stereo ? "stereo" : "mono"); + switch (sound.mach.type) { +#ifdef CONFIG_ATARI + case DMASND_TT: + len += sprintf(buffer+len, "\tsound.volume_left = %ddB [-40...0]\n", + sound.volume_left); + len += sprintf(buffer+len, "\tsound.volume_right = %ddB [-40...0]\n", + sound.volume_right); + len += sprintf(buffer+len, "\tsound.bass = %ddB [-12...+12]\n", + sound.bass); + len += sprintf(buffer+len, "\tsound.treble = %ddB [-12...+12]\n", + sound.treble); + break; + case DMASND_FALCON: + len += sprintf(buffer+len, "\tsound.volume_left = %ddB [-22.5...0]\n", + sound.volume_left); + len += sprintf(buffer+len, "\tsound.volume_right = %ddB [-22.5...0]\n", + sound.volume_right); + break; +#endif /* CONFIG_ATARI */ +#ifdef CONFIG_AMIGA + case DMASND_AMIGA: + len += sprintf(buffer+len, "\tsound.volume_left = %d [0...64]\n", + sound.volume_left); + len += sprintf(buffer+len, "\tsound.volume_right = %d [0...64]\n", + sound.volume_right); + break; +#endif /* CONFIG_AMIGA */ + } + len += sprintf(buffer+len, "\tsq.block_size = %d sq.max_count = %d\n", + sq.block_size, sq.max_count); + len += sprintf(buffer+len, "\tsq.count = %d sq.rear_size = %d\n", sq.count, + sq.rear_size); + len += sprintf(buffer+len, "\tsq.playing = %d sq.syncing = %d\n", + sq.playing, sq.syncing); + state.len = len; + return(0); +} + + +static int state_release(void) +{ + state.busy = 0; + return(0); +} + + +static int state_read(char *dest, int count) +{ + int n = state.len-state.ptr; + if (n > count) + n = count; + if (n <= 0) + return(0); + memcpy_tofs(dest, &state.buf[state.ptr], n); + state.ptr += n; + return(n); +} + + + +/*** High level stuff ********************************************************/ + + +static int sound_open(struct inode *inode, struct file *file) +{ + int dev = MINOR(inode->i_rdev) & 0x0f; + + switch (dev) { + case SND_DEV_STATUS: + return(state_open(file->f_flags)); + case SND_DEV_CTL: + return(mixer_open(file->f_flags)); + case SND_DEV_DSP: + case SND_DEV_AUDIO: + { + int rc = sq_open(file->f_flags); + if (rc == 0) { + sound.minDev = dev; + sound.soft = sound.dsp; + sound_init(); + if (dev == SND_DEV_AUDIO) { + sound_set_speed(8000); + sound_set_stereo(0); + sound_set_format(AFMT_MU_LAW); + } + } + return(rc); + } + default: + return(-ENXIO); + } +} + + +static int sound_fsync(struct inode *inode, struct file *filp) +{ + int dev = MINOR(inode->i_rdev) & 0x0f; + + switch (dev) { + case SND_DEV_STATUS: + case SND_DEV_CTL: + return(0); + case SND_DEV_DSP: + case SND_DEV_AUDIO: + return(sq_sync()); + default: + return(unknown_minor_dev("sound_fsync", dev)); + } +} + + +static void sound_release(struct inode *inode, struct file *file) +{ + int dev = MINOR(inode->i_rdev); + + switch (dev & 0x0f) { + case SND_DEV_STATUS: state_release(); return; + case SND_DEV_CTL: mixer_release(); return; + case SND_DEV_DSP: + case SND_DEV_AUDIO: + sq_release(); sound.soft = sound.dsp; sound_silence(); + return; + default: + unknown_minor_dev("sound_release", dev); + } +} + + +static int sound_lseek(struct inode *inode, struct file *file, off_t offset, + int orig) +{ + return(-EPERM); +} + + +static int sound_read(struct inode *inode, struct file *file, char *buf, + int count) +{ + int dev = MINOR(inode->i_rdev); + + switch (dev & 0x0f) { + case SND_DEV_STATUS: + return(state_read(buf, count)); + case SND_DEV_CTL: + case SND_DEV_DSP: + case SND_DEV_AUDIO: + return(-EPERM); + default: + return(unknown_minor_dev("sound_read", dev)); + } +} + + +static int sound_write(struct inode *inode, struct file *file, const char *buf, + int count) +{ + int dev = MINOR(inode->i_rdev); + + switch (dev & 0x0f) { + case SND_DEV_STATUS: + case SND_DEV_CTL: + return(-EPERM); + case SND_DEV_DSP: + case SND_DEV_AUDIO: + return(sq_write(buf, count)); + default: + return(unknown_minor_dev("sound_write", dev)); + } +} + + +static int ioctl_return(int *addr, int value) +{ + int error; + + if (value < 0) + return(value); + + error = verify_area(VERIFY_WRITE, addr, sizeof(int)); + if (error) + return(error); + + put_user(value, addr); + return(0); +} + + +static int unknown_minor_dev(char *fname, int dev) +{ + /* printk("%s: Unknown minor device %d\n", fname, dev); */ + return(-ENXIO); +} + + +static int sound_ioctl(struct inode *inode, struct file *file, u_int cmd, + u_long arg) +{ + int dev = MINOR(inode->i_rdev); + u_long fmt; + + switch (dev & 0x0f) { + case SND_DEV_STATUS: + return(-EPERM); + case SND_DEV_CTL: + return(mixer_ioctl(inode, file, cmd, arg)); + case SND_DEV_AUDIO: + case SND_DEV_DSP: + switch (cmd) { + case SNDCTL_DSP_RESET: + sq_reset(); + return(0); + case SNDCTL_DSP_POST: + case SNDCTL_DSP_SYNC: + return(sound_fsync(inode, file)); + + /* ++TeSche: before changing any of these it's probably wise to + * wait until sound playing has settled down + */ + case SNDCTL_DSP_SPEED: + sound_fsync(inode, file); + return(IOCTL_OUT(arg, sound_set_speed(IOCTL_IN(arg)))); + case SNDCTL_DSP_STEREO: + sound_fsync(inode, file); + return(IOCTL_OUT(arg, sound_set_stereo(IOCTL_IN(arg)))); + case SOUND_PCM_WRITE_CHANNELS: + sound_fsync(inode, file); + return(IOCTL_OUT(arg, sound_set_stereo(IOCTL_IN(arg)-1)+1)); + case SNDCTL_DSP_SETFMT: + sound_fsync(inode, file); + return(IOCTL_OUT(arg, sound_set_format(IOCTL_IN(arg)))); + case SNDCTL_DSP_GETFMTS: + fmt = 0; + if (sound.trans) { + if (sound.trans->ct_ulaw) + fmt |= AFMT_MU_LAW; + if (sound.trans->ct_alaw) + fmt |= AFMT_A_LAW; + if (sound.trans->ct_s8) + fmt |= AFMT_S8; + if (sound.trans->ct_u8) + fmt |= AFMT_U8; + if (sound.trans->ct_s16be) + fmt |= AFMT_S16_BE; + if (sound.trans->ct_u16be) + fmt |= AFMT_U16_BE; + if (sound.trans->ct_s16le) + fmt |= AFMT_S16_LE; + if (sound.trans->ct_u16le) + fmt |= AFMT_U16_LE; + } + return(IOCTL_OUT(arg, fmt)); + case SNDCTL_DSP_GETBLKSIZE: + return(IOCTL_OUT(arg, 10240)); + case SNDCTL_DSP_SUBDIVIDE: + case SNDCTL_DSP_SETFRAGMENT: + break; + + default: + return(mixer_ioctl(inode, file, cmd, arg)); + } + break; + + default: + return(unknown_minor_dev("sound_ioctl", dev)); + } + return(-EINVAL); +} + + +static struct file_operations sound_fops = +{ + sound_lseek, + sound_read, + sound_write, + NULL, + NULL, /* select */ + sound_ioctl, + NULL, + sound_open, + sound_release, + sound_fsync +}; + + + +/*** Config & Setup **********************************************************/ + + +void soundcard_init(void) +{ + int has_sound = 0; + char **buffers; + int i; + + switch (boot_info.machtype) { +#ifdef CONFIG_ATARI + case MACH_ATARI: + if (ATARIHW_PRESENT(PCM_8BIT)) { + if (ATARIHW_PRESENT(CODEC)) + sound.mach = machFalcon; + else if (ATARIHW_PRESENT(MICROWIRE)) + sound.mach = machTT; + else + break; + if ((mfp.int_en_a & mfp.int_mk_a & 0x20) == 0) + has_sound = 1; + else + printk("DMA sound driver: Timer A interrupt already in use\n"); + } + break; + +#endif /* CONFIG_ATARI */ +#ifdef CONFIG_AMIGA + case MACH_AMIGA: + if (AMIGAHW_PRESENT(AMI_AUDIO)) { + sound.mach = machAmiga; + has_sound = 1; + } + break; +#endif /* CONFIG_AMIGA */ + } + if (!has_sound) + return; + + /* Set up sound queue, /dev/audio and /dev/dsp. */ + buffers = kmalloc (numBufs * sizeof(char *), GFP_KERNEL); + if (!buffers) { + out_of_memory: + printk("DMA sound driver: Not enough buffer memory, driver disabled!\n"); + return; + } + for (i = 0; i < numBufs; i++) { + buffers[i] = sound.mach.dma_alloc (bufSize << 10, GFP_KERNEL); + if (!buffers[i]) { + while (i--) + sound.mach.dma_free (buffers[i], bufSize << 10); + kfree (buffers); + goto out_of_memory; + } + } + + /* Register driver with the VFS. */ + register_chrdev(SOUND_MAJOR, "sound", &sound_fops); + + sq_init(numBufs, bufSize << 10, buffers); + + /* Set up /dev/sndstat. */ + state_init(); + + /* Set up /dev/mixer. */ + mixer_init(); + + if (!sound.mach.irqinit()) { + printk("DMA sound driver: Interrupt initialization failed\n"); + return; + } + + printk("DMA sound driver installed, using %d buffers of %dk.\n", numBufs, + bufSize); + + return; +} + +void sound_setup(char *str, int *ints) +{ + /* ++Martin: stub, could possibly be merged with soundcard.c et al later */ +} + +void dmasound_setup(char *str, int *ints) +{ + /* check the bootstrap parameter for "dmasound=" */ + + switch (ints[0]) { + case 3: + if ((ints[3] < 0) || (ints[3] > MAX_CATCH_RADIUS)) + printk("dmasound_setup: illegal catch radius, using default = %d\n", catchRadius); + else + catchRadius = ints[3]; + /* fall through */ + case 2: + if (ints[1] < MIN_BUFFERS) + printk("dmasound_setup: illegal number of buffers, using default = %d\n", numBufs); + else + numBufs = ints[1]; + if (ints[2] < MIN_BUFSIZE || ints[2] > MAX_BUFSIZE) + printk("dmasound_setup: illegal buffer size, using default = %d\n", bufSize); + else + bufSize = ints[2]; + break; + case 0: + break; + default: + printk("dmasound_setup: illegal number of arguments\n"); + } +} diff -u --recursive --new-file v1.3.93/linux/drivers/sound/dmasound.h linux/drivers/sound/dmasound.h --- v1.3.93/linux/drivers/sound/dmasound.h Thu Jan 1 02:00:00 1970 +++ linux/drivers/sound/dmasound.h Thu Apr 18 02:01:38 1996 @@ -0,0 +1,36 @@ + +/* linux/drivers/sound/dmasound.h */ + +/* + * Minor numbers for the sound driver. + * + * Unfortunately Creative called the codec chip of SB as a DSP. For this + * reason the /dev/dsp is reserved for digitized audio use. There is a + * device for true DSP processors but it will be called something else. + * In v3.0 it's /dev/sndproc but this could be a temporary solution. + */ + +#define SND_NDEVS 256 /* Number of supported devices */ +#define SND_DEV_CTL 0 /* Control port /dev/mixer */ +#define SND_DEV_SEQ 1 /* Sequencer output /dev/sequencer (FM + synthesizer and MIDI output) */ +#define SND_DEV_MIDIN 2 /* Raw midi access */ +#define SND_DEV_DSP 3 /* Digitized voice /dev/dsp */ +#define SND_DEV_AUDIO 4 /* Sparc compatible /dev/audio */ +#define SND_DEV_DSP16 5 /* Like /dev/dsp but 16 bits/sample */ +#define SND_DEV_STATUS 6 /* /dev/sndstat */ +/* #7 not in use now. Was in 2.4. Free for use after v3.0. */ +#define SND_DEV_SEQ2 8 /* /dev/sequencer, level 2 interface */ +#define SND_DEV_SNDPROC 9 /* /dev/sndproc for programmable devices */ +#define SND_DEV_PSS SND_DEV_SNDPROC + +#define DSP_DEFAULT_SPEED 8000 + +#define ON 1 +#define OFF 0 + +#define MAX_AUDIO_DEV 5 +#define MAX_MIXER_DEV 2 +#define MAX_SYNTH_DEV 3 +#define MAX_MIDI_DEV 6 +#define MAX_TIMER_DEV 3 diff -u --recursive --new-file v1.3.93/linux/fs/Config.in linux/fs/Config.in --- v1.3.93/linux/fs/Config.in Mon Apr 8 19:01:44 1996 +++ linux/fs/Config.in Mon Apr 22 15:39:27 1996 @@ -34,4 +34,6 @@ tristate 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS tristate 'OS/2 HPFS filesystem support (read only)' CONFIG_HPFS_FS tristate 'System V and Coherent filesystem support' CONFIG_SYSV_FS +bool 'AFFS filesystem support' CONFIG_AFFS_FS +bool 'UFS filesystem support (read only)' CONFIG_UFS_FS endmenu diff -u --recursive --new-file v1.3.93/linux/fs/Makefile linux/fs/Makefile --- v1.3.93/linux/fs/Makefile Sat Mar 2 13:18:47 1996 +++ linux/fs/Makefile Mon Apr 22 15:39:51 1996 @@ -17,7 +17,7 @@ MOD_LIST_NAME := FS_MODULES ALL_SUB_DIRS = minix ext ext2 fat msdos vfat proc isofs nfs xiafs umsdos \ - hpfs sysv smbfs ncpfs + hpfs sysv smbfs ncpfs ufs affs ifeq ($(CONFIG_QUOTA),y) O_OBJS += dquot.o @@ -139,6 +139,14 @@ ifeq ($(CONFIG_HPFS_FS),m) MOD_SUB_DIRS += hpfs endif +endif + +ifeq ($(CONFIG_UFS_FS),y) +SUB_DIRS += ufs +endif + +ifeq ($(CONFIG_AFFS_FS),y) +SUB_DIRS += affs endif ifeq ($(CONFIG_BINFMT_ELF),y) diff -u --recursive --new-file v1.3.93/linux/fs/affs/Makefile linux/fs/affs/Makefile --- v1.3.93/linux/fs/affs/Makefile Thu Jan 1 02:00:00 1970 +++ linux/fs/affs/Makefile Sun Feb 25 19:17:29 1996 @@ -0,0 +1,14 @@ +# +# Makefile for the linux amiga fast filesystem routines. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now in the main makefile... + +O_TARGET := affs.o +O_OBJS := namei.o inode.o file.o dir.o amigaffs.o symlink.o +M_OBJS := $(O_TARGET) + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.93/linux/fs/affs/amigaffs.c linux/fs/affs/amigaffs.c --- v1.3.93/linux/fs/affs/amigaffs.c Thu Jan 1 02:00:00 1970 +++ linux/fs/affs/amigaffs.c Sat Mar 30 17:46:01 1996 @@ -0,0 +1,130 @@ +/* + * linux/fs/affs/amigaffs.c + * + * (C) 1993 Ray Burr - Amiga FFS filesystem. + * + */ + +#include +#include +#include + +#include "amigaffs.h" + +/* + * Functions for accessing Amiga-FFS structures. + * + */ + +/* Get key entry number ENTRY_POS from the header block pointed to + by DATA. If ENTRY_POS is invalid, -1 is returned. This is + used to get entries from file and directory headers as well + as extension and root blocks. In the current FFS specs, these + tables are defined to be the same size in all of these. */ + +int affs_get_key_entry (int bsize, void *data, int entry_pos) +{ + struct dir_front *dir_front = (struct dir_front *)data; + int key, hash_table_size; + + hash_table_size = MIDBLOCK_LONGS (bsize); + key = 0; + if (entry_pos >= 0 && entry_pos < hash_table_size) + key = swap_long (dir_front->hash_table[entry_pos]); + + return key; +} + +/* Find the next used hash entry at or after *HASH_POS in a directory's hash + table. *HASH_POS is assigned that entry's number. DIR_DATA points to + the directory header block in memory. If there are no more entries, + 0 is returned. Otherwise, the key number in the next used hash slot + is returned. */ + +int affs_find_next_hash_entry (int bsize, void *dir_data, int *hash_pos) +{ + struct dir_front *dir_front = (struct dir_front *)dir_data; + int i, hash_table_size; + + hash_table_size = MIDBLOCK_LONGS (bsize); + if (*hash_pos < 0 || *hash_pos >= hash_table_size) + return -1; + for (i = *hash_pos; i < hash_table_size; i++) + if (dir_front->hash_table[i] != 0) + break; + if (i == hash_table_size) + return 0; + *hash_pos = i; + return swap_long (dir_front->hash_table[i]); +} + +/* Get the hash_chain (next file header key in hash chain) entry from a + file header block in memory pointed to by FH_DATA. */ + +int affs_get_fh_hash_link (int bsize, void *fh_data) +{ + struct file_end *file_end; + int key; + + file_end = GET_END_PTR (struct file_end, fh_data, bsize); + key = swap_long (file_end->hash_chain); + return key; +} + +/* Set *NAME to point to the file name in a file header block in memory + pointed to by FH_DATA. The length of the name is returned. */ + +int affs_get_file_name (int bsize, void *fh_data, char **name) +{ + struct file_end *file_end; + + file_end = GET_END_PTR (struct file_end, fh_data, bsize); + if (file_end->file_name[0] == 0 + || file_end->file_name[0] > 30) { + printk ("affs_get_file_name: OOPS! bad filename\n"); + printk (" file_end->file_name[0] = %d\n", + file_end->file_name[0]); + *name = "***BAD_FILE***"; + return 14; + } + *name = (char *) &file_end->file_name[1]; + return file_end->file_name[0]; +} + +/* Get the key number of the first extention block for the file + header pointed to by FH_DATA. */ + +int affs_get_extension (int bsize, void *fh_data) +{ + struct file_end *file_end; + int key; + + file_end = GET_END_PTR (struct file_end, fh_data, bsize); + key = swap_long (file_end->extension); + return key; +} + +/* Checksum a block, do various consistency checks and optionally return + the blocks type number. DATA points to the block. If their pointers + are non-null, *PTYPE and *STYPE are set to the primary and secondary + block types respectively. Returns non-zero if the block is not + consistent. */ + +int affs_checksum_block (int bsize, void *data, int *ptype, int *stype) +{ + if (ptype) + *ptype = swap_long (((long *) data)[0]); + if (stype) + *stype = swap_long (((long *) data)[bsize / 4 - 1]); + return 0; +} + +static struct file_system_type affs_fs_type = { + affs_read_super, "affs", 1, NULL +}; + +int init_affs_fs(void) +{ + return register_filesystem(&affs_fs_type); +} + diff -u --recursive --new-file v1.3.93/linux/fs/affs/amigaffs.h linux/fs/affs/amigaffs.h --- v1.3.93/linux/fs/affs/amigaffs.h Thu Jan 1 02:00:00 1970 +++ linux/fs/affs/amigaffs.h Sun Feb 25 19:14:27 1996 @@ -0,0 +1,206 @@ +#ifndef AMIGAFFS_H +#define AMIGAFFS_H + +/* Ugly macros to make the code pretty. */ + +#define GET_END_PTR(st,p,sz) ((st *)((char *)(p)+((sz)-sizeof(st)))) + +#define MIDBLOCK_LONGS(sz) ((sz - sizeof (struct dir_front) \ + - sizeof (struct dir_end)) / 4) + +static __inline__ unsigned long +swap_long (unsigned long x) +{ +#ifdef __i386__ /* bad check... should be endian check */ + unsigned char *px; + + px = (unsigned char *) &x; + return ( (px[3] << 0) + | (px[2] << 8) + | (px[1] << 16) + | (px[0] << 24)); +#else + return x; +#endif +} + +typedef unsigned long ULONG; +typedef unsigned short UWORD; +typedef unsigned char UBYTE; + +typedef long LONG; +typedef short WORD; +typedef char BYTE; + +struct DateStamp +{ + ULONG ds_Days; + ULONG ds_Minute; + ULONG ds_Tick; +}; + +#define T_SHORT 2 +#define T_LIST 16 +#define T_DATA 8 + +#define ST_FILE -3 +#define ST_USERDIR 2 +#define ST_ROOT 1 +#define ST_SOFTLINK 3 +#define ST_LINKFILE -4 +#define ST_LINKDIR 4 + +#define PROT_ARCHIVE (1<<4) +#define PROT_READ (1<<3) +#define PROT_WRITE (1<<2) +#define PROT_EXECUTE (1<<1) +#define PROT_DELETE (1<<0) + +#define PROT_OTR_READ (1<<15) +#define PROT_OTR_WRITE (1<<14) +#define PROT_OTR_EXECUTE (1<<13) +#define PROT_OTR_DELETE (1<<12) + +#define PROT_GRP_READ (1<<11) +#define PROT_GRP_WRITE (1<<10) +#define PROT_GRP_EXECUTE (1<<9) +#define PROT_GRP_DELETE (1<<8) + +struct ffs_root_front +{ + LONG primary_type; + ULONG spare1[2]; + ULONG hash_size; + ULONG spare2; + ULONG checksum; +}; + +struct ffs_root_end +{ + LONG bm_flag; + ULONG bm_keys[25]; + ULONG bm_extend; + struct DateStamp dir_altered; + UBYTE disk_name[40]; + struct DateStamp disk_altered; + struct DateStamp disk_made; + ULONG spare1[3]; + LONG secondary_type; +}; + +struct dir_front +{ + LONG primary_type; + ULONG own_key; + ULONG spare1[3]; + ULONG checksum; + ULONG hash_table[0]; +}; + +struct dir_end +{ + ULONG spare1; + UWORD uid; + UWORD gid; + ULONG protect; + ULONG spare2; + UBYTE comment[92]; + struct DateStamp created; + UBYTE dir_name[64]; + ULONG hash_chain; + ULONG parent; + ULONG spare3; + LONG secondary_type; +}; + +struct file_front +{ + LONG primary_type; + ULONG own_key; + ULONG block_count; + ULONG unknown1; + ULONG first_data; + ULONG checksum; + ULONG blocks[0]; +}; + +struct file_end +{ + ULONG spare1; + UWORD uid; + UWORD gid; + ULONG protect; + ULONG byte_size; + UBYTE comment[92]; + struct DateStamp created; + UBYTE file_name[64]; + ULONG hash_chain; + ULONG parent; + ULONG extension; + LONG secondary_type; +}; + +struct data_front +{ + LONG primary_type; + ULONG header; + ULONG seq_num; + ULONG data_size; + ULONG next_data; + ULONG checksum; +}; + +struct symlink_front +{ + LONG primary_type; + ULONG own_key; + LONG unused[3]; + ULONG checksum; + UBYTE symname[0]; +}; + +struct symlink_end +{ + ULONG spare1; + UWORD uid; + UWORD gid; + ULONG protect; + ULONG spare2; + UBYTE comment[92]; + struct DateStamp created; + UBYTE link_name[64]; + ULONG hash_chain; + ULONG parent; + ULONG spare3; + LONG secondary_type; +}; + +struct hardlink_front +{ + LONG primary_type; + ULONG own_key; + LONG unused[3]; + ULONG checkksum; +}; + +struct hardlink_end +{ + ULONG spare1; + UWORD uid; + UWORD gid; + ULONG protect; + ULONG spare2; + UBYTE comment[92]; + struct DateStamp created; + UBYTE link_name[32]; + ULONG spare3; + ULONG original; + ULONG link_chain; + ULONG spare4[5]; + ULONG hash_chain; + ULONG parent; + ULONG spare5; + LONG secondary_type; +}; + +#endif diff -u --recursive --new-file v1.3.93/linux/fs/affs/dir.c linux/fs/affs/dir.c --- v1.3.93/linux/fs/affs/dir.c Thu Jan 1 02:00:00 1970 +++ linux/fs/affs/dir.c Mon Apr 1 21:23:46 1996 @@ -0,0 +1,150 @@ +/* + * linux/fs/affs/dir.c + * + * (C) 1993 Ray Burr - Modified for Amiga FFS filesystem. + * + * (C) 1992 Eric Youngdale Modified for ISO9660 filesystem. + * + * (C) 1991 Linus Torvalds - minix filesystem + * + * affs directory handling functions + */ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +static int affs_readdir(struct inode *, struct file *, void *, filldir_t); + +struct file_operations affs_dir_operations = { + NULL, /* lseek - default */ + NULL, /* read */ + NULL, /* write - bad */ + affs_readdir, /* readdir */ + NULL, /* select - default */ + NULL, /* ioctl - default */ + NULL, /* mmap */ + NULL, /* no special open code */ + NULL, /* no special release code */ + NULL /* fsync */ +}; + +/* + * directories can handle most operations... + */ +struct inode_operations affs_dir_inode_operations = { + &affs_dir_operations, /* default directory file-ops */ + NULL, /* create */ + affs_lookup, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL /* permission */ +}; + +/* This is used to speed up lookup. Without this we would need to +make a linear search of the directory to find the file that the +directory read just returned. This is a single element cache. */ + +/* struct lookup_cache cache = {0,}; */ + +static int affs_readdir(struct inode * inode, struct file * filp, + void * dirent, filldir_t filldir) +{ + int i, j, chain_pos, hash_pos, reclen, ino; + char *name; + struct buffer_head *dir_bh; + struct buffer_head *fh_bh; + void *dir_data; + void *fh_data; + +#ifdef DEBUG + printk ("AFFS: readdir: inode=%d f_pos=%d\n", + inode->i_ino, filp->f_pos); +#endif + + if (!inode || !S_ISDIR(inode->i_mode)) + return -EBADF; + + while ((unsigned long)filp->f_pos < 2) { + if (filp->f_pos == 0) { + if (filldir (dirent, ".", 1, filp->f_pos, inode->i_ino) < 0) + return 0; + } else { + i = affs_parent_ino (inode); + if (filldir (dirent, "..", 2, filp->f_pos, i) < 0) + return 0; + } + filp->f_pos++; + } + /* No caching here. I've got 16 megs why should I care? :-) */ + chain_pos = (filp->f_pos - 2) & 0xffff; + if (chain_pos == 0xffff) + return 0; + hash_pos = (filp->f_pos - 2) >> 16; +#ifdef DEBUG + printk ("AFFS: hash_pos=%d chain_pos=%d\n", hash_pos, chain_pos); +#endif + if (!(dir_bh = affs_pread(inode, inode->i_ino, &dir_data))) + return 0; + /* HASH_POS should already be on a used entry unless it is + the first read of the directory. Will this break the + dirtell thing somehow? */ + i = affs_find_next_hash_entry (AFFS_I2BSIZE (inode), dir_data, + &hash_pos); + j = chain_pos; + for (;;) { + if (i <= 0) { +#ifdef DEBUG + printk ("AFFS: bad f_pos in readdir\n"); +#endif + brelse (dir_bh); + return 0; + } + ino = i; + if (!(fh_bh = affs_pread (inode, i, &fh_data))) { + brelse (dir_bh); + return 0; + } + i = affs_get_fh_hash_link (AFFS_I2BSIZE (inode), fh_data); + if (j == 0) { + j = 1; + if (i <= 0) { + hash_pos++; + i = affs_find_next_hash_entry (AFFS_I2BSIZE (inode), + dir_data, &hash_pos); + if (i <= 0) + chain_pos = 0xffff; + else + chain_pos = 0; + } else + chain_pos++; + reclen = affs_get_file_name (AFFS_I2BSIZE (inode), + fh_data, &name); + if (filldir (dirent, name, reclen, filp->f_pos, ino) < 0) { + brelse (fh_bh); + brelse (dir_bh); + return 0; + } + filp->f_pos = ((hash_pos << 16) | chain_pos) + 2; + } + brelse (fh_bh); + j--; + } +} diff -u --recursive --new-file v1.3.93/linux/fs/affs/file.c linux/fs/affs/file.c --- v1.3.93/linux/fs/affs/file.c Thu Jan 1 02:00:00 1970 +++ linux/fs/affs/file.c Sat Mar 30 18:37:05 1996 @@ -0,0 +1,174 @@ +/* + * linux/fs/affs/file.c + * + * (C) 1993 Ray Burr - Modified for Amiga FFS filesystem. + * + * (C) 1992 Eric Youngdale Modified for ISO9660 filesystem. + * + * (C) 1991 Linus Torvalds - minix filesystem + * + * affs regular file handling primitives + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#define NBUF 16 + +#define MIN(a,b) (((a)<(b))?(a):(b)) +#define MAX(a,b) (((a)>(b))?(a):(b)) + +#include +#include + +#include "amigaffs.h" + +int affs_file_read(struct inode *, struct file *, char *, int); + +/* + * We have mostly NULL's here: the current defaults are ok for + * the affs filesystem. + */ +struct file_operations affs_file_operations = { + NULL, /* lseek - default */ + affs_file_read, /* read */ + NULL, /* write */ + NULL, /* readdir - bad */ + NULL, /* select - default */ + NULL, /* ioctl - default */ + generic_file_mmap, /* mmap */ + NULL, /* no special open is needed */ + NULL, /* release */ + NULL /* can't fsync */ +}; + +struct inode_operations affs_file_inode_operations = { + &affs_file_operations, /* default file operations */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL /* affs_bmap */, /* bmap */ + NULL, /* truncate */ + NULL /* permission */ +}; + +static int affs_smap(struct inode *inode, int block) +{ + struct buffer_head *bh; + int key; + void *fh_data; + +/* FIXME */ +#define KEY_SLOTS_PER_BLOCK 72 + +#ifdef DEBUG + printk ("affs_smap: ino=%d block=%d\n", inode->i_ino, block); +#endif + + if (block < 0) { + printk("affs_smap: block < 0"); + return 0; + } + + key = inode->i_ino; + for (;;) { + bh = affs_pread (inode, key, &fh_data); + if (!bh) + return 0; + if (block < KEY_SLOTS_PER_BLOCK) + break; + block -= KEY_SLOTS_PER_BLOCK; + key = affs_get_extension (AFFS_I2BSIZE (inode), fh_data); +#ifdef DEBUG + printk ("affs_smap: reading extension block %d\n", key); +#endif + brelse (bh); + } + key = affs_get_key_entry (AFFS_I2BSIZE (inode), fh_data, + (KEY_SLOTS_PER_BLOCK - 1) - block); + brelse (bh); + +#ifdef DEBUG + printk ("affs_smap: key=%d\n", key); +#endif + return key; +} + +/* + * affs_file_read() is also needed by the directory read-routine, + * so it's not static. NOTE! reading directories directly is a bad idea, + * but has to be supported for now for compatability reasons with older + * versions. + */ +int affs_file_read(struct inode * inode, struct file * filp, + char * buf, int count) +{ + char *start; + int left, offset, size, sector; + struct buffer_head *bh; + void *data; + + if (!inode) { + printk("affs_file_read: inode = NULL\n"); + return -EINVAL; + } + if (!(S_ISREG(inode->i_mode))) { +#ifdef DEBUG + printk("affs_file_read: mode = %07o\n",inode->i_mode); +#endif + return -EINVAL; + } + if (filp->f_pos >= inode->i_size || count <= 0) + return 0; + + start = buf; + for (;;) { + left = MIN (inode->i_size - filp->f_pos, + count - (buf - start)); + if (!left) + break; + sector = affs_smap (inode, filp->f_pos >> AFFS_BLOCK_BITS); + if (!sector) + break; + offset = filp->f_pos & (AFFS_BLOCK_SIZE - 1); + bh = affs_pread (inode, sector, &data); + if (!bh) + break; + size = MIN (AFFS_BLOCK_SIZE - offset, left); + filp->f_pos += size; + memcpy_tofs (buf, data + offset, size); + buf += size; + brelse (bh); + } + if (start == buf) + return -EIO; + return buf - start; + +#if 0 + if (filp->f_pos == 0 && count > 0) { + put_fs_byte ('X', buf++); + filp->f_pos++; + return 1; + } + else + return 0; +#endif +} diff -u --recursive --new-file v1.3.93/linux/fs/affs/inode.c linux/fs/affs/inode.c --- v1.3.93/linux/fs/affs/inode.c Thu Jan 1 02:00:00 1970 +++ linux/fs/affs/inode.c Wed Mar 20 20:01:47 1996 @@ -0,0 +1,431 @@ +/* + * linux/fs/affs/inode.c + * + * (C) 1994 Geert Uytterhoeven - Modified for MultiUserFileSystem + * + * (C) 1993 Ray Burr - Modified for Amiga FFS filesystem. + * + * (C) 1992 Eric Youngdale Modified for ISO9660 filesystem. + * + * (C) 1991 Linus Torvalds - minix filesystem + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "amigaffs.h" + +extern int check_cdrom_media_change(int, int); + +#ifdef LEAK_CHECK +static int check_malloc = 0; +static int check_bread = 0; +#endif + +void affs_put_super(struct super_block *sb) +{ + lock_super(sb); + +#ifdef LEAK_CHECK + printk("Outstanding mallocs:%d, outstanding buffers: %d\n", + check_malloc, check_bread); +#endif + sb->s_dev = 0; + unlock_super(sb); + return; +} + +static struct super_operations affs_sops = { + affs_read_inode, + NULL, /* notify_change */ + NULL, /* write_inode */ + NULL, /* put_inode */ + affs_put_super, + NULL, /* write_super */ + affs_statfs, + NULL /* remount */ +}; + +int affs_parent_ino(struct inode *dir) +{ + int root_ino = (dir->i_sb->u.affs_sb.s_root_block + - dir->i_sb->u.affs_sb.s_partition_offset); + + if (!S_ISDIR (dir->i_mode)) { + printk ("affs_parent_ino: argument is not a directory\n"); + return root_ino; + } + if (dir->i_ino == root_ino) + return root_ino; + return dir->u.affs_i.i_parent; +} + +static int parse_options(char *options, struct affs_options *optp) +{ + char *this_opt,*value,*end; + int n; + + optp->offset = 0; + optp->size = 0; + optp->root = 0; + optp->conv_links = 0; + + if (!options) + return 1; + for (this_opt = strtok(options,","); this_opt; this_opt = strtok(NULL,",")) { + if ((value = strchr(this_opt,'='))) *value++ = 0; + + if (!strcmp(this_opt,"offset") && value) { + n = simple_strtoul (value, &end, 10); + if (end == value || *end != 0) + return 0; + optp->offset = n; + } + else if (!strcmp(this_opt,"size") && value) { + n = simple_strtoul (value, &end, 10); + if (end == value || *end != 0 || n <= 0) + return 0; + optp->size = n; + } + else if (!strcmp(this_opt,"root") && value) { + n = simple_strtoul (value, &end, 10); + if (end == value || *end != 0 || n <= 0) + return 0; + optp->root = n; + } + else if (!strcmp(this_opt,"conv_symlinks")) { + optp->conv_links = 1; + } + else return 0; + } + return 1; +} + +/* Is this The Right Way? Should I be locking something? */ + +static int get_device_size (dev_t dev) +{ + struct gendisk *gd_p; + int dev_size = 0; + + for (gd_p = gendisk_head ; gd_p ; gd_p=gd_p->next) { + if (gd_p->major != MAJOR(dev)) + continue; + dev_size = gd_p->part[MINOR(dev)].nr_sects; + break; + } + return dev_size; +} + +struct super_block *affs_read_super(struct super_block *s,void *data, + int silent) +{ + struct buffer_head *bh; + int dev = s->s_dev; + int root_block; + int ptype, stype; + void *root_data; + struct affs_options *optp; + + optp = &s->u.affs_sb.s_options; + + if (!parse_options((char *) data, optp)) { + s->s_dev = 0; + printk ("AFFS: bad mount options\n"); + return NULL; + } + + lock_super(s); + + root_block = 0; + if (optp->size) { + s->u.affs_sb.s_partition_size = optp->size; + } + else { + int size = get_device_size (dev); + if (size == 0) { + s->s_dev = 0; + unlock_super(s); + printk ("affs_read_super: could not" + "determine device size\n"); + } + s->u.affs_sb.s_partition_size = size; + } + + s->u.affs_sb.s_partition_offset = optp->offset; + root_block = optp->root; + + if (!root_block) + root_block = (s->u.affs_sb.s_partition_offset + + s->u.affs_sb.s_partition_size / 2 + + (s->u.affs_sb.s_partition_size & 1)); + s->u.affs_sb.s_root_block = root_block; + + s->u.affs_sb.s_block_size = AFFS_BLOCK_SIZE; + +#if 0 + printk ("affs_read_super: dev=0x%04x offset=%d " + "size=%d root=%d blocksize=%d\n", + dev, + s->u.affs_sb.s_partition_offset, + s->u.affs_sb.s_partition_size, + s->u.affs_sb.s_root_block, + s->u.affs_sb.s_block_size); +#endif + + bh = affs_sread (dev, root_block, &root_data); + if (!bh) { + s->s_dev = 0; + unlock_super(s); + printk ("AFFS: unable to read superblock\n"); + return NULL; + } + + if (affs_checksum_block (AFFS_BLOCK_SIZE, root_data, &ptype, &stype) + || ptype != T_SHORT || stype != ST_ROOT) { + printk ("AFFS: invalid root block %d on device 0x%04x\n", + root_block, dev); + goto out; + } + +#if 1 +{ + char *name; + int len; + char buf[33]; + len = affs_get_file_name (AFFS_BLOCK_SIZE, root_data, &name); + memcpy (buf,name,len); + buf[len] = 0; +#if 0 + printk ("affs_read_super: volume name \"%s\"\n", buf); +#endif +} +#endif + + s->s_magic = AFFS_SUPER_MAGIC; + + s->s_flags = MS_RDONLY | MS_NODEV | MS_NOSUID; + + brelse(bh); + + /* set up enough so that it can read an inode */ + s->s_dev = dev; + s->s_op = &affs_sops; + s->s_blocksize = AFFS_BUFFER_SIZE; + s->s_mounted = iget (s, root_block - s->u.affs_sb.s_partition_offset); + + unlock_super(s); + + if (!(s->s_mounted)) { + s->s_dev = 0; + printk("AFFS: get root inode failed\n"); + return NULL; + } + + return s; + + out: /* Kick out for various error conditions */ + brelse (bh); + s->s_dev = 0; + unlock_super(s); + return NULL; +} + +void affs_statfs (struct super_block *sb, struct statfs *buf, int bufsiz) +{ +#ifdef DEBUG + printk ("AFFS: affs_statfs called\n"); +#endif + put_fs_long(AFFS_SUPER_MAGIC, &buf->f_type); + put_fs_long(sb->u.affs_sb.s_block_size, &buf->f_bsize); + put_fs_long(sb->u.affs_sb.s_partition_size, &buf->f_blocks); + put_fs_long(0, &buf->f_bfree); + put_fs_long(0, &buf->f_bavail); + put_fs_long(0, &buf->f_files); + put_fs_long(0, &buf->f_ffree); + /* Don't know what value to put in buf->f_fsid */ +} + +static int prot_table[9][2] = { + {PROT_OTR_EXECUTE, PROT_OTR_EXECUTE}, /* other: 1 = allowed */ + {PROT_OTR_WRITE, PROT_OTR_WRITE}, + {PROT_OTR_READ, PROT_OTR_READ}, + {PROT_GRP_EXECUTE, PROT_GRP_EXECUTE}, /* group: 1 = allowed */ + {PROT_GRP_WRITE, PROT_GRP_WRITE}, + {PROT_GRP_READ, PROT_GRP_READ}, + {PROT_EXECUTE, 0}, /* owner: 0 = allowed */ + {PROT_WRITE, 0}, + {PROT_READ, 0} +}; + +void affs_read_inode(struct inode * inode) +{ + struct buffer_head *bh; + int block; + void *fh_data; + struct file_front *file_front; + struct file_end *file_end; + int i; + struct hardlink_end *link_end; + int link; + +#ifdef DEBUG + printk ("AFFS: entering affs_read_inode\n"); +#endif + + inode->i_nlink = 1; /* at least */ + do { + link = 0; + block = inode->i_ino; + if (!(bh=affs_pread (inode, block, &fh_data))) { + printk("AFFS: unable to read i-node block %d\n", block); + return; + } + + file_front = (struct file_front *) fh_data; + file_end = GET_END_PTR (struct file_end, fh_data, /* coincidendly the same as dir_end */ + AFFS_I2BSIZE (inode)); + + /* don't use bitmap data for mode, uid & gid of the rootblock */ + if (block == inode->i_sb->u.affs_sb.s_root_block) { + inode->u.affs_i.i_protect = 0; + inode->u.affs_i.i_parent = block; + + inode->i_mode = S_IRWXUGO | S_IFDIR | S_ISVTX ; /* drwxrwxrwt */ + inode->i_nlink = 2; /* at least ..... */ + + inode->i_size = 0; /* some differrent idea ? */ + + inode->i_uid = 0; + inode->i_gid = 0; + } + else { + + inode->u.affs_i.i_protect = file_end->protect; + inode->u.affs_i.i_parent = swap_long (file_end->parent); + + inode->i_mode = 0; + for (i = 0; i < 9; i++) + if ((prot_table[i][0] & inode->u.affs_i.i_protect) == prot_table[i][1]) + inode->i_mode |= 1<secondary_type)) { + case ST_USERDIR: + inode->i_mode |= ((inode->i_mode & 0444)>>2) | S_IFDIR; + + inode->i_nlink++; /* There are always at least 2. It is + hard to figure out what is correct*/ + inode->i_size = 0; + break; + case ST_SOFTLINK: + inode->i_mode |= S_IFLNK; + inode->i_size = 0; + break; + case ST_LINKFILE: /* doing things very easy (not really correct) */ + case ST_LINKDIR: /* code is _very_ inefficient (see below) */ + + /* Where is struct link_end defined? + ... I don't know what is going on + here, someone else should + probably spend some time on this */ + link_end = (struct hardlink_end *)file_end; + inode->i_ino = link_end->original; + inode->i_nlink += 2; /* It's hard to say whats correct */ + brelse(bh); + link = 1; + break; + default: + printk("affs: unknown secondary type %ld; assuming file\n", + file_end->secondary_type); + case ST_FILE: + inode->i_mode |= S_IFREG; + inode->i_size = swap_long (file_end->byte_size); + break; + } + if (file_end->uid == 0xffff) + inode->i_uid = 0; /* root uid */ + else if (file_end->uid == 0x0000) { + umode_t mode; + inode->i_uid = -1; /* unknown uid */ + + /* + * change the mode of the inode to duplicate the + * perms of the user in the group and other fields; + * the assumption is that this isn't a MultiUser + * filesystem/file, so the permissions should be + * the same for all users + */ + mode = (inode->i_mode >> 6) & 7; + inode->i_mode |= (mode << 3) | (mode); + } else + inode->i_uid = file_end->uid; + if (file_end->gid == 0xffff) + inode->i_gid = 0; /* root gid */ + else if (file_end->gid == 0x0000) + inode->i_gid = -1; /* unknown gid */ + else + inode->i_gid = file_end->gid; + } + } + while (link); + +#ifdef DEBUG + printk ("AFFS: read inode %d: size=%d\n", block, inode->i_size); +#endif + inode->i_mtime = inode->i_atime = inode->i_ctime + = (swap_long (file_end->created.ds_Days) * (24 * 60 * 60) + + swap_long (file_end->created.ds_Minute) * 60 + + swap_long (file_end->created.ds_Tick) / 50 + + ((8 * 365 + 2) * 24 * 60 * 60)); + + brelse(bh); + + inode->i_op = NULL; + if (S_ISREG(inode->i_mode)) + inode->i_op = &affs_file_inode_operations; + else if (S_ISDIR(inode->i_mode)) + inode->i_op = &affs_dir_inode_operations; + else if (S_ISLNK(inode->i_mode)) + inode->i_op = &affs_symlink_inode_operations; +} + + +#ifdef LEAK_CHECK +#undef malloc +#undef free_s +#undef bread +#undef brelse + +void * leak_check_malloc(unsigned int size){ + void * tmp; + check_malloc++; + tmp = kmalloc(size, GFP_ATOMIC); + return tmp; +} + +void leak_check_free_s(void * obj, int size){ + check_malloc--; + return kfree_s(obj, size); +} + +struct buffer_head * leak_check_bread(int dev, int block, int size){ + check_bread++; + return bread(dev, block, size); +} + +void leak_check_brelse(struct buffer_head * bh){ + check_bread--; + return brelse(bh); +} + +#endif diff -u --recursive --new-file v1.3.93/linux/fs/affs/namei.c linux/fs/affs/namei.c --- v1.3.93/linux/fs/affs/namei.c Thu Jan 1 02:00:00 1970 +++ linux/fs/affs/namei.c Sun Feb 25 19:14:29 1996 @@ -0,0 +1,187 @@ +/* + * linux/fs/affs/namei.c + * + * (C) 1993 Ray Burr - Modified for Amiga FFS filesystem. + * + * (C) 1992 Eric Youngdale Modified for ISO9660 filesystem. + * + * (C) 1991 Linus Torvalds - minix filesystem + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + + +static inline int namecompare(int len, int maxlen, + const char * name, const char * buffer) +{ + if (len >= maxlen || !buffer[len]) { + return strncmp (name, buffer, len) == 0; + } + return 0; +} + +/* + * ok, we cannot use strncmp, as the name is not in our data space. + * Thus we'll have to use affs_match. No big problem. Match also makes + * some sanity tests. + * + * NOTE! unlike strncmp, affs_match returns 1 for success, 0 for failure. + */ +static int affs_match(int len,const char * name, char * compare, int dlen) +{ + if (!compare) return 0; + + /* "" means "." ---> so paths like "/usr/lib//libc.a" work */ + if (!len && dlen == 1 && compare[0] == '.') + return 1; + +#if 0 + if (len <= 2) printk("Match: %d %d %s %d %d \n",len,dlen,compare,de->name[0], dlen); +#endif + + return namecompare(len,dlen,name,compare); +} + +/* Avoid pulling in ctype stuff. */ + +static int affs_toupper (int ch) +{ + if (ch >= 'a' && ch <= 'z') + ch -= ('a' - 'A'); + return ch; +} + +static int affs_hash_name (const char *name, int len) +{ + int i, x; + + x = len; + for (i = 0; i < len; i++) + x = (x * 13 + affs_toupper (name[i])) & 0x7ff; + return x % 72; /* FIXME: Assumes 512 byte blocks. */ +} + +static struct buffer_head *affs_find_entry(struct inode *dir, + const char *name, int namelen, int *ino) +{ + struct buffer_head *bh; + void *dir_data; + int key; + + *ino = 0; + + bh = affs_pread (dir, dir->i_ino, &dir_data); + if (!bh) + return NULL; + + if (affs_match (namelen, name, ".", 1)) { + *ino = dir->i_ino; + return bh; + } + if (affs_match (namelen, name, "..", 2)) { + *ino = affs_parent_ino (dir); + return bh; + } + key = affs_get_key_entry (AFFS_I2BSIZE (dir), dir_data, + affs_hash_name (name, namelen)); + + for (;;) { + char *cname; + int cnamelen; + + brelse (bh); + if (key <= 0) + return NULL; + bh = affs_pread (dir, key, &dir_data); + if (!bh) + return NULL; + cnamelen = affs_get_file_name (AFFS_I2BSIZE (dir), + dir_data, &cname); + if (affs_match (namelen, name, cname, cnamelen)) + break; + key = affs_get_fh_hash_link (AFFS_I2BSIZE (dir), dir_data); + } + + *ino = key; + + return bh; +} + +int affs_lookup(struct inode * dir,const char * name, int len, + struct inode ** result) +{ + int ino; + struct buffer_head *bh; + + *result = NULL; + if (!dir) + return -ENOENT; + +#ifdef DEBUG + printk ("lookup: %d %d\n", dir->i_ino, len); +#endif + + if (!S_ISDIR(dir->i_mode)) { + iput(dir); + return -ENOENT; + } + if (!(bh = affs_find_entry(dir, name, len, &ino))) { + iput(dir); + return -ENOENT; + } + brelse(bh); + if (!(*result = iget(dir->i_sb, ino))) { + iput(dir); + return -EACCES; + } + iput (dir); + return 0; + +#if 0 + ino = 0; + while(cache.lock); + cache.lock = 1; + if (dir->i_dev == cache.dev && + dir->i_ino == cache.dir && + len == cache.dlen && + affs_match(len, name, cache.filename, cache.dlen)) + { + ino = cache.ino; + ino_back = dir->i_ino; + /* These two cases are special, but since they are at the start + of the directory, we can just as easily search there */ + if (cache.dlen == 1 && cache.filename[0] == '.') ino = 0; + if (cache.dlen == 2 && cache.filename[0] == '.' && + cache.filename[1] == '.') ino = 0; + }; + cache.lock = 0; + + if (!ino) { + if (!(bh = affs_find_entry(dir,name,len, &ino, &ino_back))) { + iput(dir); + return -ENOENT; + } + brelse(bh); + }; + + if (!(*result = iget(dir->i_sb,ino))) { + iput(dir); + return -EACCES; + } + + /* We need this backlink for the .. entry */ + + if (ino_back) (*result)->u.affs_i.i_backlink = ino_back; + + iput(dir); + return 0; +#endif +} diff -u --recursive --new-file v1.3.93/linux/fs/affs/symlink.c linux/fs/affs/symlink.c --- v1.3.93/linux/fs/affs/symlink.c Thu Jan 1 02:00:00 1970 +++ linux/fs/affs/symlink.c Sun Feb 25 19:14:29 1996 @@ -0,0 +1,179 @@ +/* + * linux/fs/affs/symlink.c + * + * (C) 1995 Joerg Dorchain Modified for Amiga FFS filesystem + * based on: + * + * (C) 1992 Eric Youngdale Modified for ISO9660 filesystem. + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * isofs symlink handling code. This is only used with the Rock Ridge + * extensions to iso9660 + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include "amigaffs.h" + +static int affs_readlink(struct inode *, char *, int); +static int affs_follow_link(struct inode *, struct inode *, int, int, struct inode **); + +/* + * symlinks can't do much... + */ +struct inode_operations affs_symlink_inode_operations = { + NULL, /* no file-operations */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + affs_readlink, /* readlink */ + affs_follow_link, /* follow_link */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL /* permission */ +}; + +static int affs_follow_link(struct inode * dir, struct inode * inode, + int flag, int mode, struct inode ** res_inode) +{ + int error; + char * pnt; + struct buffer_head *bh; + struct symlink_front *sy_data; + + if (!dir) { + dir = current->fs->root; + dir->i_count++; + } + if (!inode) { + iput(dir); + *res_inode = NULL; + return -ENOENT; + } + if (!S_ISLNK(inode->i_mode)) { + iput(dir); + *res_inode = inode; + return 0; + } + if (current->link_count > 5) { + iput(dir); + iput(inode); + *res_inode = NULL; + return -ELOOP; + } + if (!(bh = affs_pread(inode,inode->i_ino,(void **)&sy_data))) { + printk("affs: unable to read block %ld",inode->i_ino); + return 0; + } + + pnt = sy_data->symname; + iput(inode); + current->link_count++; + error = open_namei(pnt,flag,mode,res_inode,dir); + current->link_count--; + brelse(bh); + return error; +} + +static char *affs_conv_path(char *affs_path) +{ +static char unix_path[1024]="/"; +int up,ap; +char dp,slash; + + +dp=1; +slash=1; +ap=0; +up=1; +if (affs_path[0] == 0) + unix_path[up++]='.'; +while ((up < 1020) && (affs_path[ap]!=0)) + { + switch (affs_path[ap]) { + case ':': + if (dp == 0) { + slash=0; + unix_path[up++]=':'; + } + else { + dp=0; + slash=1; + unix_path[up++]='/'; + } + break; + case '/': + if (slash==0) { + slash=1; + unix_path[up++]='/'; + } + else { + unix_path[up++]='.'; + unix_path[up++]='.'; + unix_path[up++]='/'; + } + break; + default: + slash=0; + unix_path[up++]=affs_path[ap]; + break; + } + ap++; + } +unix_path[up]=0; +return unix_path+dp; +} + + +static int affs_readlink(struct inode * inode, char * buffer, int buflen) +{ + char * pnt; + int i; + char c; + struct buffer_head *bh; + struct symlink_front *sy_data; + + if (!S_ISLNK(inode->i_mode)) { + iput(inode); + return -EINVAL; + } + + if (buflen > 1023) + buflen = 1023; + + if (!(bh = affs_pread(inode,inode->i_ino,(void **)&sy_data))) { + printk("affs: unable to read block %ld\n",inode->i_ino); + return -ENOENT; + } + + iput(inode); + + pnt = sy_data->symname; + if (inode->i_sb->u.affs_sb.s_options.conv_links != 0) + pnt = affs_conv_path(pnt); + + i = 0; + + while (i #include #include +#include #include extern void device_setup(void); @@ -98,6 +99,10 @@ #ifdef CONFIG_HPFS_FS init_hpfs_fs(); +#endif + +#ifdef CONFIG_UFS_FS + init_ufs_fs(); #endif mount_root(); diff -u --recursive --new-file v1.3.93/linux/fs/minix/truncate.c linux/fs/minix/truncate.c --- v1.3.93/linux/fs/minix/truncate.c Thu Jan 4 14:07:58 1996 +++ linux/fs/minix/truncate.c Mon Apr 22 11:47:49 1996 @@ -15,8 +15,9 @@ #define DIRECT_BLOCK ((inode->i_size + 1023) >> 10) #define INDIRECT_BLOCK(offset) (DIRECT_BLOCK-offset) -#define DINDIRECT_BLOCK(offset) ((DIRECT_BLOCK-offset)>>9) -#define TINDIRECT_BLOCK(offset) ((DIRECT_BLOCK-(offset))>>9) +#define V1_DINDIRECT_BLOCK(offset) ((DIRECT_BLOCK-offset)>>9) +#define V2_DINDIRECT_BLOCK(offset) ((DIRECT_BLOCK-offset)>>8) +#define TINDIRECT_BLOCK(offset) ((DIRECT_BLOCK-(offset))>>8) /* * Truncate has the most races in the whole filesystem: coding it is @@ -147,10 +148,10 @@ return 0; } repeat: - for (i = DINDIRECT_BLOCK(offset) ; i < 512 ; i ++) { + for (i = V1_DINDIRECT_BLOCK(offset) ; i < 512 ; i ++) { if (i < 0) i = 0; - if (i < DINDIRECT_BLOCK(offset)) + if (i < V1_DINDIRECT_BLOCK(offset)) goto repeat; dind = i+(unsigned short *) dind_bh->b_data; retry |= V1_trunc_indirect(inode,offset+(i<<9),dind); @@ -309,13 +310,13 @@ return 0; } repeat: - for (i = DINDIRECT_BLOCK(offset) ; i < 256 ; i ++) { + for (i = V2_DINDIRECT_BLOCK(offset) ; i < 256 ; i ++) { if (i < 0) i = 0; - if (i < DINDIRECT_BLOCK(offset)) + if (i < V2_DINDIRECT_BLOCK(offset)) goto repeat; dind = i+(unsigned long *) dind_bh->b_data; - retry |= V2_trunc_indirect(inode,offset+(i<<9),dind); + retry |= V2_trunc_indirect(inode,offset+(i<<8),dind); mark_buffer_dirty(dind_bh, 1); } dind = (unsigned long *) dind_bh->b_data; @@ -360,7 +361,7 @@ if (i < TINDIRECT_BLOCK(offset)) goto repeat; tind = i+(unsigned long *) tind_bh->b_data; - retry |= V2_trunc_dindirect(inode,offset+(i<<9),tind); + retry |= V2_trunc_dindirect(inode,offset+(i<<8),tind); mark_buffer_dirty(tind_bh, 1); } tind = (unsigned long *) tind_bh->b_data; diff -u --recursive --new-file v1.3.93/linux/fs/proc/array.c linux/fs/proc/array.c --- v1.3.93/linux/fs/proc/array.c Fri Apr 19 10:08:01 1996 +++ linux/fs/proc/array.c Mon Apr 22 11:29:09 1996 @@ -180,11 +180,11 @@ a = avenrun[0] + (FIXED_1/200); b = avenrun[1] + (FIXED_1/200); c = avenrun[2] + (FIXED_1/200); - return sprintf(buffer,"%d.%02d %d.%02d %d.%02d %d/%d\n", + return sprintf(buffer,"%d.%02d %d.%02d %d.%02d %d/%d %d\n", LOAD_INT(a), LOAD_FRAC(a), LOAD_INT(b), LOAD_FRAC(b), LOAD_INT(c), LOAD_FRAC(c), - nr_running, nr_tasks); + nr_running, nr_tasks, last_pid); } static int get_kstat(char * buffer) diff -u --recursive --new-file v1.3.93/linux/fs/super.c linux/fs/super.c --- v1.3.93/linux/fs/super.c Sun Apr 21 12:39:02 1996 +++ linux/fs/super.c Mon Apr 22 10:59:39 1996 @@ -540,7 +540,7 @@ * filesystems which don't use real block-devices. -- jrs */ -static unsigned int unnamed_dev_in_use[256/32] = { 0, }; +static unsigned int unnamed_dev_in_use[256/(8*sizeof(unsigned int))] = { 0, }; kdev_t get_unnamed_dev(void) { diff -u --recursive --new-file v1.3.93/linux/fs/ufs/Makefile linux/fs/ufs/Makefile --- v1.3.93/linux/fs/ufs/Makefile Thu Jan 1 02:00:00 1970 +++ linux/fs/ufs/Makefile Mon Apr 22 10:59:39 1996 @@ -0,0 +1,15 @@ +# +# Makefile for the linux ufs-filesystem routines. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now in the main makefile... + +O_TARGET := ufs.o +O_OBJS := ufs_dir.o ufs_file.o ufs_inode.o ufs_namei.o \ + ufs_super.o ufs_symlink.o +M_OBJS := $(O_TARGET) + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.93/linux/fs/ufs/ufs_dir.c linux/fs/ufs/ufs_dir.c --- v1.3.93/linux/fs/ufs/ufs_dir.c Thu Jan 1 02:00:00 1970 +++ linux/fs/ufs/ufs_dir.c Mon Apr 22 10:59:39 1996 @@ -0,0 +1,196 @@ +/* + * linux/fs/ufs/ufs_dir.c + * + * Copyright (C) 1996 + * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu) + * Laboratory for Computer Science Research Computing Facility + * Rutgers, The State University of New Jersey + * + * $Id: ufs_dir.c,v 1.1 1996/04/21 14:41:04 davem Exp $ + * + */ + +#include + +/* XXX */ +extern int ufs_lookup(); +extern int ufs_bmap(); + +static int ufs_dir_read (struct inode * inode, struct file * filp, + char * buf, int count) +{ + /* XXX - probably allow this for root, EISDIR for normal users */ + return -EISDIR; +} + +/* + * This is blatantly stolen from ext2fs + */ +static int +ufs_readdir (struct inode * inode, struct file * filp, void * dirent, + filldir_t filldir) +{ + int error = 0; + unsigned long offset, lblk, blk; + int i, stored; + struct buffer_head * bh; + struct direct * de; + struct super_block * sb; + + if (!inode || !S_ISDIR(inode->i_mode)) + return -EBADF; + sb = inode->i_sb; + + if (inode->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) { + printk("ufs_readdir: ino %lu f_pos %lu\n", + inode->i_ino, filp->f_pos); + ufs_print_inode(inode); + } + + stored = 0; + bh = NULL; + offset = filp->f_pos & (sb->s_blocksize - 1); + + while (!error && !stored && filp->f_pos < inode->i_size) { + lblk = (filp->f_pos) >> sb->s_blocksize_bits; + blk = ufs_bmap(inode, lblk); + /* XXX - ufs_bmap() call needs error checking */ + blk = ufs_bmap(inode, lblk); + bh = bread (sb->s_dev, blk, sb->s_blocksize); + if (!bh) { + /* XXX - error - skip to the next block */ + printk("ufs_readdir: dir inode %lu has a hole at offset %lu\n", + inode->i_ino, (unsigned long int)filp->f_pos); + filp->f_pos += sb->s_blocksize - offset; + continue; + } + +revalidate: + /* If the dir block has changed since the last call to + * readdir(2), then we might be pointing to an invalid + * dirent right now. Scan from the start of the block + * to make sure. */ + if (filp->f_version != inode->i_version) { + for (i = 0; i < sb->s_blocksize && i < offset; ) { + de = (struct direct *) + (bh->b_data + i); + /* It's too expensive to do a full + * dirent test each time round this + * loop, but we do have to test at + * least that it is non-zero. A + * failure will be detected in the + * dirent test below. */ + if (de->d_reclen < 1) + break; + i += de->d_reclen; + } + offset = i; + filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1)) + | offset; + filp->f_version = inode->i_version; + } + + while (!error && filp->f_pos < inode->i_size + && offset < sb->s_blocksize) { + de = (struct direct *) (bh->b_data + offset); + /* XXX - put in a real ufs_check_dir_entry() */ + if ((de->d_reclen == 0) || (de->d_namlen == 0)) { + filp->f_pos = filp->f_pos & (sb->s_blocksize - 1) + sb->s_blocksize; + brelse(bh); + return stored; + } +#if 0 + if (!ext2_check_dir_entry ("ext2_readdir", inode, de, + bh, offset)) { + /* On error, skip the f_pos to the + next block. */ + filp->f_pos = (filp->f_pos & (sb->s_blocksize - 1)) + + sb->s_blocksize; + brelse (bh); + return stored; + } +#endif /* XXX */ + offset += de->d_reclen; + if (de->d_ino) { + /* We might block in the next section + * if the data destination is + * currently swapped out. So, use a + * version stamp to detect whether or + * not the directory has been modified + * during the copy operation. */ + unsigned long version; + dcache_add(inode, de->d_name, de->d_namlen, + de->d_ino); + version = inode->i_version; + if (inode->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) { + printk("ufs_readdir: filldir(%s,%lu)\n", + de->d_name, de->d_ino); + } + error = filldir(dirent, de->d_name, de->d_namlen, filp->f_pos, de->d_ino); + if (error) + break; + if (version != inode->i_version) + goto revalidate; + stored ++; + } + filp->f_pos += de->d_reclen; + } + offset = 0; + brelse (bh); + } +#if 0 /* XXX */ + if (!IS_RDONLY(inode)) { + inode->i_atime = CURRENT_TIME; + inode->i_dirt = 1; + } +#endif /* XXX */ + return 0; +} + + +static struct file_operations ufs_dir_operations = { + NULL, /* lseek */ + &ufs_dir_read, /* read */ + NULL, /* write */ + &ufs_readdir, /* readdir */ + NULL, /* select */ + NULL, /* ioctl */ + NULL, /* mmap */ + NULL, /* open */ + NULL, /* release */ + &file_fsync, /* fsync */ + NULL, /* fasync */ + NULL, /* check_media_change */ + NULL, /* revalidate */ +}; + +struct inode_operations ufs_dir_inode_operations = { + &ufs_dir_operations, /* default directory file operations */ + NULL, /* create */ + &ufs_lookup, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* readpage */ + NULL, /* writepage */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL, /* permission */ + NULL, /* smap */ +}; + +/* + * Local Variables: *** + * c-indent-level: 8 *** + * c-continued-statement-offset: 8 *** + * c-brace-offset: -8 *** + * c-argdecl-indent: 0 *** + * c-label-offset: -8 *** + * End: *** + */ diff -u --recursive --new-file v1.3.93/linux/fs/ufs/ufs_file.c linux/fs/ufs/ufs_file.c --- v1.3.93/linux/fs/ufs/ufs_file.c Thu Jan 1 02:00:00 1970 +++ linux/fs/ufs/ufs_file.c Mon Apr 22 10:59:39 1996 @@ -0,0 +1,144 @@ +/* + * linux/fs/ufs/ufs_file.c + * + * Copyright (C) 1996 + * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu) + * Laboratory for Computer Science Research Computing Facility + * Rutgers, The State University of New Jersey + * + * $Id: ufs_file.c,v 1.1 1996/04/21 14:41:08 davem Exp $ + * + */ + +#include + +/* + * Return values: + * 0: bmap failed + * nonzero: absolute "block" number + */ +int ufs_bmap (struct inode * inode, int block) +{ + unsigned long int fsblkno, phys_block, lfsblkno; + struct buffer_head * bh; + + /* + * Note that contrary to what the BSD source calls these things, + * blkno and lblkno are *frags* (1024), not UFS blocks (8192). + * XXX - maybe I'm wrong, and ui_blocks is really 512-blocks... + */ + + /* + * Ok, I think I figured out what is going on. ui_blocks is the + * number of 512-byte blocks that are allocated to the file. The + * elements in ui_db[UFS_NDADDR] are pointers to 1024-byte aligned + * 8192 byte objects. The entire 8192 bytes (16 512-blocks) may + * not be allocated to the file in question - use ui_blocks to see + * how many of the blocks are allocated. Also, use ui_size to see + * what fraction of the last block is allocated to the file, and + * what fraction is unused. I have not yet seen a file with a + * hole in it, but I'd guess that a hole must be at least 8192 + * bytes of zeros, and it's represented by a zero in ui_db[X]. + * + * Yes, this means that there is more than one way to name a given + * 512-byte block on the disk. Because of the 1024-byte alignment + * of 8192-byte filesystem blocks, a given 512-byte disk block + * could be referred to in eight different ways. + */ + + /* + * block is the logical 1024-block in the file + * lfsblkno is the logical 8192-block in the file + * fsblkno is the physical 8192-block + * phys_block is the 1024-block + */ + lfsblkno = block>>3; + + if (block < UFS_NDADDR) { + /* It's a direct block */ + fsblkno = inode->u.ufs_i.ui_db[lfsblkno]; /* XXX */ +#if 0 + phys_block = ufs_cgdmin(inode->i_sb, ufs_ino2cg(inode)) + + blkno%(inode->i_sb->u.ufs_sb.s_fpg); +#endif + phys_block = fsblkno + ((block & 0x7)<<10); /* XXX */ + if (inode->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) { + printk("ufs_bmap: mapped ino %lu logical %u to %lu (phys %lu)\n", + inode->i_ino, block, fsblkno, phys_block); + } + return(phys_block); + } else { + /* Need to use indirect blocks */ + /* XXX - bmap through indirect blocks not implemented */ + block -= UFS_NDADDR; + if (block < (inode->i_sb->s_blocksize/sizeof(__u32))) { + bh = bread(inode->i_dev, inode->u.ufs_i.ui_ib[0], + BLOCK_SIZE); + if (bh == NULL) { + printk("ufs_bmap: can't map block %lu, ino %lu\n", + block + UFS_NDADDR, inode->i_ino); + return(0); + } + phys_block = ((__u32 *)bh->b_data)[block]; + brelse(bh); + printk("ufs_bmap: imap ino %lu block %lu phys %lu\n", + inode->i_ino, block + UFS_NDADDR, phys_block); + return(phys_block); + } else { + printk("ufs_bmap: ino %lu: indirect blocks not implemented\n", + inode->i_ino); + return(0); + } + } + + return(0); +} + + +static struct file_operations ufs_file_operations = { + NULL, /* lseek */ + &generic_file_read, /* read */ + NULL, /* write */ + NULL, /* readdir */ + NULL, /* select */ + NULL, /* ioctl */ + &generic_file_mmap, /* mmap */ + NULL, /* open */ + NULL, /* release */ + &file_fsync, /* fsync */ /* XXX - is this ok? */ + NULL, /* fasync */ + NULL, /* check_media_change */ + NULL, /* revalidate */ +}; + +struct inode_operations ufs_file_inode_operations = { + &ufs_file_operations, /* default directory file operations */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + &generic_readpage, /* readpage */ + NULL, /* writepage */ + &ufs_bmap, /* bmap */ + NULL, /* truncate */ + NULL, /* permission */ + NULL, /* smap */ +}; + + +/* + * Local Variables: *** + * c-indent-level: 8 *** + * c-continued-statement-offset: 8 *** + * c-brace-offset: -8 *** + * c-argdecl-indent: 0 *** + * c-label-offset: -8 *** + * End: *** + */ diff -u --recursive --new-file v1.3.93/linux/fs/ufs/ufs_inode.c linux/fs/ufs/ufs_inode.c --- v1.3.93/linux/fs/ufs/ufs_inode.c Thu Jan 1 02:00:00 1970 +++ linux/fs/ufs/ufs_inode.c Mon Apr 22 10:59:39 1996 @@ -0,0 +1,237 @@ +/* + * linux/fs/ufs/ufs_inode.c + * + * Copyright (C) 1996 + * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu) + * Laboratory for Computer Science Research Computing Facility + * Rutgers, The State University of New Jersey + * + * $Id: ufs_inode.c,v 1.1 1996/04/21 14:41:12 davem Exp $ + * + */ + +#include +#include +#include + +extern struct inode_operations ufs_file_inode_operations; +extern struct inode_operations ufs_dir_inode_operations; +extern struct inode_operations ufs_symlink_inode_operations; +extern struct file_operations ufs_file_operations; +extern struct file_operations ufs_dir_operations; +extern struct file_operations ufs_symlink_operations; + +void ufs_print_inode(struct inode * inode) +{ + printk("ino %lu mode 0%6.6o lk %d uid %d gid %d sz %lu blks %lu cnt %u\n", + inode->i_ino, inode->i_mode, inode->i_nlink, inode->i_uid, inode->i_gid, inode->i_size, inode->i_blocks, inode->i_count); + printk(" db <0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x>\n", + inode->u.ufs_i.ui_db[0], inode->u.ufs_i.ui_db[1], + inode->u.ufs_i.ui_db[2], inode->u.ufs_i.ui_db[3], + inode->u.ufs_i.ui_db[4], inode->u.ufs_i.ui_db[5], + inode->u.ufs_i.ui_db[6], inode->u.ufs_i.ui_db[7], + inode->u.ufs_i.ui_db[8], inode->u.ufs_i.ui_db[9], + inode->u.ufs_i.ui_db[10], inode->u.ufs_i.ui_db[11]); + printk(" gen 0x%8.8x ib <0x%x 0x%x 0x%x>\n", + inode->u.ufs_i.ui_gen, inode->u.ufs_i.ui_ib[0], + inode->u.ufs_i.ui_ib[1], inode->u.ufs_i.ui_ib[2]); +} + +/* XXX - ufs_read_inode is a mess */ +void ufs_read_inode(struct inode * inode) +{ + struct super_block * sb; + struct ufs_inode * ufsip; + struct buffer_head * bh; + + sb = inode->i_sb; + + if (ufs_ino_ok(inode)) { + printk("ufs_read_inode: bad inum %lu", inode->i_ino); + + return; + } + +#if 0 + printk("ufs_read_inode: ino %lu cg %u cgino %u ipg %u inopb %u\n", + inode->i_ino, ufs_ino2cg(inode), + (inode->i_ino%sb->u.ufs_sb.s_inopb), + sb->u.ufs_sb.s_ipg, sb->u.ufs_sb.s_inopb); +#endif + bh = bread(inode->i_dev, + ufs_cgimin(inode->i_sb, ufs_ino2cg(inode)) + + (inode->i_ino%sb->u.ufs_sb.s_ipg)/(sb->u.ufs_sb.s_inopb/sb->u.ufs_sb.s_fsfrag), + BLOCK_SIZE); + if (!bh) { + printk("ufs_read_inode: can't read inode %lu from dev %d/%d", + inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev)); + return; + } + + ufsip = (struct ufs_inode *)bh->b_data; + ufsip += (inode->i_ino%(sb->u.ufs_sb.s_inopb/sb->u.ufs_sb.s_fsfrag)); + + /* + * Copy data to the in-core inode. + */ + inode->i_mode = ufsip->ui_mode; + inode->i_nlink = ufsip->ui_nlink; + if (inode->i_nlink == 0) { + /* XXX */ + printk("ufs_read_inode: zero nlink ino %lu dev %u/%u\n", + inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev)); + inode->i_nlink = 1; + printk("ufs_read_inode: fishy ino %lu pblk %lu dev %u/%u\n", + inode->i_ino, + ufs_cgimin(inode->i_sb, ufs_ino2cg(inode)) + + (inode->i_ino%sb->u.ufs_sb.s_ipg)/sb->u.ufs_sb.s_inopb, + MAJOR(inode->i_dev), MINOR(inode->i_dev)); + } + /* XXX - debugging */ + if (ufsip->ui_gen == 0) { + printk("ufs_read_inode: zero gen ino %lu pblk %lu dev %u/%u\n", + inode->i_ino, + ufs_cgimin(inode->i_sb, ufs_ino2cg(inode)) + + (inode->i_ino%sb->u.ufs_sb.s_ipg)/sb->u.ufs_sb.s_inopb, + MAJOR(inode->i_dev), MINOR(inode->i_dev)); + } + /* + * Since Linux currently only has 16-bit uid_t and gid_t, we can't + * really support EFTs. For the moment, we use 0 as the uid and gid + * if an inode has a uid or gid that won't fit in 16 bits. This way + * random users can't get at these files, since they get dynamically + * "chown()ed" to root. + */ + if (ufsip->ui_suid == UFS_USEEFT) { + /* EFT */ + inode->i_uid = 0; + printk("ufs_read_inode: EFT uid %u ino %lu dev %u/%u, using %u\n", + ufsip->ui_uid, inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev), + inode->i_uid); + } else { + inode->i_uid = ufsip->ui_suid; + } + if (ufsip->ui_suid == UFS_USEEFT) { + /* EFT */ + inode->i_uid = 0; + printk("ufs_read_inode: EFT gid %u ino %lu dev %u/%u, using %u\n", + ufsip->ui_gid, inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev), + inode->i_gid); + } else { + inode->i_gid = ufsip->ui_sgid; + } + + /* + * Linux i_size is 32 bits, so some files on a UFS filesystem may not + * be readable. I let people access the first 32 bits worth of them. + * for the rw code, we may want to mark these inodes as read-only. + * XXX - bug Linus to make i_size a __u64 instead of a __u32. + */ + inode->u.ufs_i.ui_size = ((__u64)(ufsip->ui_size.val[0])<<32) | (__u64)(ufsip->ui_size.val[1]); + inode->i_size = ufsip->ui_size.val[1]; /* XXX - endianity */ + if (ufsip->ui_size.val[0] != 0) { + inode->i_size = 0xffffffff; + printk("ufs_read_inode: file too big ino %lu dev %u/%u, faking size\n", + inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev)); + } + /* + * Linux doesn't keep tv_usec around in the kernel, so we discard it. + * XXX - I'm not sure what I should do about writing things. I may + * want to keep this data, but for the moment I think I'll just write + * zeros for these fields when writing out inodes. + */ + inode->i_atime = ufsip->ui_atime.tv_sec; + inode->i_mtime = ufsip->ui_mtime.tv_sec; + inode->i_ctime = ufsip->ui_ctime.tv_sec; + inode->i_blksize = sb->u.ufs_sb.s_fsize; + inode->i_blocks = ufsip->ui_blocks; + inode->i_version = ++event; /* see linux/kernel/sched.c */ + + if (S_ISREG(inode->i_mode)) { + inode->i_op = &ufs_file_inode_operations; + } else if (S_ISDIR(inode->i_mode)) { + inode->i_op = &ufs_dir_inode_operations; + } else if (S_ISLNK(inode->i_mode)) { + inode->i_op = &ufs_symlink_inode_operations; + } else if (S_ISCHR(inode->i_mode)) { + inode->i_op = &chrdev_inode_operations; + } else if (S_ISBLK(inode->i_mode)) { + inode->i_op = &blkdev_inode_operations; + } else if (S_ISFIFO(inode->i_mode)) { + init_fifo(inode); + } else { + printk("ufs_read_inode: unknown file type 0%o ino %lu dev %d/%d\n", + inode->i_mode, inode->i_ino, MAJOR(inode->i_dev), + MINOR(inode->i_dev)); + /* XXX - debugging */ + ufs_print_inode(inode); + inode->i_op = &ufs_file_inode_operations; + } + + /* + * ufs_read_super makes sure that UFS_NDADDR and UFS_NINDIR are sane. + */ + if (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || + S_ISLNK(inode->i_mode)) { + int i; + + for (i = 0; i < UFS_NDADDR; i++) { + inode->u.ufs_i.ui_db[i] = ufsip->ui_db[i]; + } + for (i = 0; i < UFS_NINDIR; i++) { + inode->u.ufs_i.ui_ib[i] = ufsip->ui_ib[i]; + } + } + + if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) { + /* XXX - should be ui_db[1] on little endian ufs filesystems */ + inode->i_rdev = ufsip->ui_db[0]; + } + + /* XXX - implement fast and slow symlinks */ + + inode->u.ufs_i.ui_flags = ufsip->ui_flags; + inode->u.ufs_i.ui_gen = ufsip->ui_gen; /* XXX - is this i_version? */ + inode->u.ufs_i.ui_shadow = ufsip->ui_shadow; /* XXX */ + inode->u.ufs_i.ui_uid = ufsip->ui_uid; + inode->u.ufs_i.ui_gid = ufsip->ui_gid; + inode->u.ufs_i.ui_oeftflag = ufsip->ui_oeftflag; + + brelse(bh); + + if (inode->i_sb->u.ufs_sb.s_flags & (UFS_DEBUG|UFS_DEBUG_INODE)) { + ufs_print_inode(inode); + } + + return; +} + +void ufs_put_inode (struct inode * inode) +{ + if (inode->i_nlink) + return; + + printk("ufs_put_inode: nlink == 0 for inum %lu on dev %d/%d\n", + inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev)); + ufs_print_inode(inode); + panic("ufs_put_inode: fs is read only, and nlink == 0"); + + /* XXX - this code goes here eventually + inode->i_size = 0; + if (inode->i_blocks) + ufs_truncate(inode); + ufs_free_inode(inode); + */ + + return; +} + +/* + * Local Variables: *** + * c-indent-level: 8 *** + * c-continued-statement-offset: 8 *** + * c-brace-offset: -8 *** + * c-argdecl-indent: 0 *** + * c-label-offset: -8 *** + * End: *** + */ diff -u --recursive --new-file v1.3.93/linux/fs/ufs/ufs_namei.c linux/fs/ufs/ufs_namei.c --- v1.3.93/linux/fs/ufs/ufs_namei.c Thu Jan 1 02:00:00 1970 +++ linux/fs/ufs/ufs_namei.c Mon Apr 22 10:59:39 1996 @@ -0,0 +1,154 @@ +/* + * linux/fs/ufs/ufs_namei.c + * + * Copyright (C) 1996 + * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu) + * Laboratory for Computer Science Research Computing Facility + * Rutgers, The State University of New Jersey + * + * $Id: ufs_namei.c,v 1.1 1996/04/21 14:41:15 davem Exp $ + * + */ + +#include + +extern unsigned int ufs_bmap(struct inode * inode, int block); /* XXX */ + +/* + * NOTE! unlike strncmp, ext2_match returns 1 for success, 0 for failure. + * stolen from ext2fs + */ +static int ufs_match (int len, const char * const name, struct direct * d) +{ + if (!d || len > MAXNAMLEN) /* XXX - name space */ + return 0; + /* + * "" means "." ---> so paths like "/usr/lib//libc.a" work + */ + if (!len && (d->d_namlen == 1) && (d->d_name[0] == '.') && + (d->d_name[1] == '\0')) + return 1; + if (len != d->d_namlen) + return 0; + return !memcmp(name, d->d_name, len); +} + +/* XXX - this is a mess, especially for endianity */ +int ufs_lookup (struct inode * dir, const char * name, int len, + struct inode ** result) +{ + unsigned long int lfragno, fragno; + struct buffer_head * bh; + struct direct * d; + + /* + * Touching /xyzzy in a filesystem toggles debugging messages. + */ + if ((len == 5) && !(memcmp(name, "xyzzy", len)) && + (dir->i_ino == UFS_ROOTINO)) { + dir->i_sb->u.ufs_sb.s_flags ^= UFS_DEBUG; + printk("UFS debugging %s\n", + (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) ? + "on": "off"); + return(-ENOENT); + } + + /* + * Touching /xyzzy.i in a filesystem toggles debugging for ufs_inode.c. + */ + if ((len == 7) && !(memcmp(name, "xyzzy.i", len)) && + (dir->i_ino == UFS_ROOTINO)) { + dir->i_sb->u.ufs_sb.s_flags ^= UFS_DEBUG_INODE; + printk("UFS inode debugging %s\n", + (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG_INODE) ? + "on": "off"); + return(-ENOENT); + } + + if ((len == 7) && !(memcmp(name, "xyzzy.n", len)) && + (dir->i_ino == UFS_ROOTINO)) { + dir->i_sb->u.ufs_sb.s_flags ^= UFS_DEBUG_NAMEI; + printk("UFS namei debugging %s\n", + (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG_NAMEI) ? + "on": "off"); + return(-ENOENT); + } + + if ((len == 7) && !(memcmp(name, "xyzzy.l", len)) && + (dir->i_ino == UFS_ROOTINO)) { + dir->i_sb->u.ufs_sb.s_flags ^= UFS_DEBUG_LINKS; + printk("UFS symlink debugging %s\n", + (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG_LINKS) ? + "on": "off"); + return(-ENOENT); + } + + if (dir->i_sb->u.ufs_sb.s_flags & (UFS_DEBUG|UFS_DEBUG_NAMEI)) { + printk("ufs_lookup: called for ino %lu name %s\n", + dir->i_ino, name); + } + + /* XXX - do I want i_blocks in 512-blocks or 1024-blocks? */ + for (lfragno = 0; lfragno < (dir->i_blocks)>>1; lfragno++) { + fragno = ufs_bmap(dir, lfragno); + /* XXX - ufs_bmap() call needs error checking */ + /* XXX - s_blocksize is actually the UFS frag size */ + if (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) { + printk("ufs_lookup: ino %lu lfragno %lu fragno %lu\n", + dir->i_ino, lfragno, fragno); + } + if (fragno == 0) { + /* XXX - bug bug bug */ + return(-ENOENT); + } + bh = bread(dir->i_dev, fragno, dir->i_sb->s_blocksize); + if (bh == NULL) { + printk("ufs_lookup: bread failed: ino %lu, lfragno %u", + dir->i_ino, lfragno); + return(-EIO); + } + d = (struct direct *)(bh->b_data); + while (((char *)d - bh->b_data + d->d_reclen) <= + dir->i_sb->s_blocksize) { + /* XXX - skip block if d_reclen or d_namlen is 0 */ + if ((d->d_reclen == 0) || (d->d_namlen == 0)) { + if (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) { + printk("ufs_lookup: skipped space in directory, ino %lu\n", + dir->i_ino); + } + break; + } + if (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) { + printk("lfragno 0x%x direct d 0x%x d_ino %u d_reclen %u d_namlen %u d_name `%s'\n", + lfragno, (unsigned int)d, d->d_ino, d->d_reclen, d->d_namlen, d->d_name); + } + if ((d->d_namlen == len) && + /* XXX - don't use strncmp() - see ext2fs */ + (ufs_match(len, name, d))) { + /* We have a match */ + *result = iget(dir->i_sb, d->d_ino); + brelse(bh); + return(0); + } else { + /* XXX - bounds checking */ + if (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) { + printk("ufs_lookup: wanted (%s,%d) got (%s,%d)\n", + name, len, d->d_name, d->d_namlen); + } + } + d = (struct direct *)((char *)d + d->d_reclen); + } + brelse(bh); + } + return(-ENOENT); +} + +/* + * Local Variables: *** + * c-indent-level: 8 *** + * c-continued-statement-offset: 8 *** + * c-brace-offset: -8 *** + * c-argdecl-indent: 0 *** + * c-label-offset: -8 *** + * End: *** + */ diff -u --recursive --new-file v1.3.93/linux/fs/ufs/ufs_super.c linux/fs/ufs/ufs_super.c --- v1.3.93/linux/fs/ufs/ufs_super.c Thu Jan 1 02:00:00 1970 +++ linux/fs/ufs/ufs_super.c Mon Apr 22 10:59:39 1996 @@ -0,0 +1,265 @@ +/* + * linux/fs/ufs/ufs_super.c + * + * Copyright (C) 1996 + * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu) + * Laboratory for Computer Science Research Computing Facility + * Rutgers, The State University of New Jersey + * + * $Id: ufs_super.c,v 1.1 1996/04/21 14:41:19 davem Exp $ + * + */ + +#include +#include +#include +#include +#include + +struct super_block * ufs_read_super(struct super_block * sb, void * data, int silent); +void ufs_put_super (struct super_block * sb); +void ufs_statfs(struct super_block * sb, struct statfs * buf, int bufsize); + +extern void ufs_read_inode(struct inode * inode); +extern void ufs_put_inode(struct inode * inode); + +static struct super_operations ufs_super_ops = { + &ufs_read_inode, + NULL, /* notify_change() */ + NULL, /* XXX - ufs_write_inode() */ + &ufs_put_inode, + &ufs_put_super, + NULL, /* XXX - ufs_write_super() */ + &ufs_statfs, + NULL, /* XXX - ufs_remount() */ +}; + +static struct file_system_type ufs_fs_type = { + &ufs_read_super, "ufs", 1, NULL +}; + +int +init_ufs_fs(void) +{ + return(register_filesystem(&ufs_fs_type)); +} + +static void +ufs_print_super_stuff(struct super_block * sb, struct ufs_superblock * usb) +{ + + printk("fs_sblkno: 0x%8.8x\n", usb->fs_sblkno); + printk("fs_size: 0x%8.8x\n", usb->fs_size); + printk("fs_ncg: 0x%8.8x\n", usb->fs_ncg); + printk("fs_bsize: 0x%8.8x\n", usb->fs_bsize); + printk("fs_frag: 0x%8.8x\n", usb->fs_frag); + printk("fs_nindir: 0x%8.8x\n", usb->fs_nindir); + printk("fs_inopb: 0x%8.8x\n", usb->fs_inopb); + printk("fs_optim: 0x%8.8x\n", usb->fs_optim); + printk("fs_ncyl: 0x%8.8x\n", usb->fs_ncyl); + printk("fs_state: 0x%8.8x\n", usb->fs_state); + printk("fs_magic: 0x%8.8x\n", usb->fs_magic); + printk("fs_fsmnt: `%s'\n", usb->fs_fsmnt); + + return; +} + +struct super_block * +ufs_read_super(struct super_block * sb, void * data, int silent) +{ + struct ufs_superblock * usb; + struct buffer_head * bh1, *bh2; + + /* sb->s_dev and sb->s_flags are set by our caller + * data is the mystery argument to sys_mount() + * + * Our caller also sets s_dev, s_covered, s_rd_only, s_dirt, + * and s_type when we return. + */ + + lock_super (sb); + + /* XXX - make everything read only for testing */ + sb->s_flags |= MS_RDONLY; + + if (!(bh1 = bread(sb->s_dev, UFS_SBLOCK/BLOCK_SIZE, BLOCK_SIZE)) || + !(bh2 = bread(sb->s_dev, (UFS_SBLOCK + BLOCK_SIZE)/BLOCK_SIZE, + BLOCK_SIZE))) { + sb->s_dev = 0; + unlock_super (sb); + if (bh1) { + brelse(bh1); + } + printk ("ufs_read_super: unable to read superblock\n"); + + return 0; + } + /* XXX - redo this so we can free it later... */ + usb = (struct ufs_superblock *)__get_free_page(GFP_KERNEL); + if (usb == NULL) { + printk ("ufs_read_super: get_free_page() failed\n"); + } + + memcpy((char *)usb, bh1->b_data, BLOCK_SIZE); + memcpy((char *)usb + BLOCK_SIZE, bh2->b_data, + sizeof(struct ufs_superblock) - BLOCK_SIZE); + + brelse(bh1); + brelse(bh2); + + if (usb->fs_magic != UFS_MAGIC) { + /* XXX - replace hard-coded constant with a byte-swap macro */ + if (usb->fs_magic == 0x54190100) { + printk ("ufs_read_super: can't grok byteswapped fs on dev %d/%d\n", + MAJOR(sb->s_dev), MINOR(sb->s_dev)); + silent = 1; + } + sb->s_dev = 0; + unlock_super (sb); + if (!silent) + printk ("ufs_read_super: bad magic number 0x%8.8x on dev %d/%d\n", + usb->fs_magic, MAJOR(sb->s_dev), + MINOR(sb->s_dev)); + return(NULL); + } + + /* We found a UFS filesystem on this device. */ + + /* XXX - parse args */ + + if (usb->fs_bsize != UFS_BSIZE) { + printk("ufs_read_super: fs_bsize %d != %d\n", usb->fs_bsize, + UFS_BSIZE); + goto ufs_read_super_lose; + } + + if (usb->fs_fsize != UFS_FSIZE) { + printk("ufs_read_super: fs_fsize %d != %d\n", usb->fs_fsize, + UFS_FSIZE); + goto ufs_read_super_lose; + } + + if (usb->fs_nindir != UFS_NINDIR) { + printk("ufs_read_super: fs_nindir %d != %d\n", usb->fs_nindir, + UFS_NINDIR); + printk("ufs_read_super: fucking Sun blows me\n"); + } + + printk("ufs_read_super: fs last mounted on \"%s\"\n", usb->fs_fsmnt); + + if (usb->fs_state == UFS_FSOK - usb->fs_time) { + switch(usb->fs_clean) { + case UFS_FSCLEAN: + printk("ufs_read_super: fs is clean\n"); + break; + case UFS_FSSTABLE: + printk("ufs_read_super: fs is stable\n"); + break; + case UFS_FSACTIVE: + printk("ufs_read_super: fs is active\n"); + sb->s_flags |= MS_RDONLY; + break; + case UFS_FSBAD: + printk("ufs_read_super: fs is bad\n"); + sb->s_flags |= MS_RDONLY; + break; + default: + printk("ufs_read_super: can't grok fs_clean 0x%x\n", + usb->fs_clean); + sb->s_flags |= MS_RDONLY; + break; + } + } else { + printk("ufs_read_super: fs needs fsck\n"); + sb->s_flags |= MS_RDONLY; + /* XXX - make it read only or barf if it's not (/, /usr) */ + } + + /* XXX - sanity check sb fields */ + + sb->s_blocksize = usb->fs_fsize; + sb->s_blocksize_bits = 10; /* XXX */ + /* XXX - sb->s_lock */ + sb->s_op = &ufs_super_ops; + sb->dq_op = 0; /* XXX */ + sb->s_magic = usb->fs_magic; + /* sb->s_time */ + /* sb->s_wait */ + /* XXX - sb->u.ufs_sb */ + sb->u.ufs_sb.s_raw_sb = usb; /* XXX - maybe move this to the top */ + sb->u.ufs_sb.s_flags = 0; + sb->u.ufs_sb.s_ncg = usb->fs_ncg; + sb->u.ufs_sb.s_ipg = usb->fs_ipg; + sb->u.ufs_sb.s_fpg = usb->fs_fpg; + sb->u.ufs_sb.s_fsize = usb->fs_fsize; + sb->u.ufs_sb.s_bsize = usb->fs_bsize; + sb->u.ufs_sb.s_iblkno = usb->fs_iblkno; + sb->u.ufs_sb.s_dblkno = usb->fs_dblkno; + sb->u.ufs_sb.s_cgoffset = usb->fs_cgoffset; + sb->u.ufs_sb.s_cgmask = usb->fs_cgmask; + sb->u.ufs_sb.s_inopb = usb->fs_inopb; + sb->u.ufs_sb.s_fsfrag = usb->fs_frag; /* XXX - rename this later */ + sb->s_mounted = iget(sb, UFS_ROOTINO); + + printk("ufs_read_super: inopb %lu\n", sb->u.ufs_sb.s_inopb); + /* + * XXX - read cg structs? + */ + + unlock_super(sb); + return(sb); + + ufs_read_super_lose: + /* XXX - clean up */ + return(0); +} + +void ufs_put_super (struct super_block * sb) +{ + + printk("ufs_put_super\n"); /* XXX */ + + lock_super (sb); + /* XXX - sync fs data, set state to ok, and flush buffers */ + sb->s_dev = 0; + + /* XXX - free allocated kernel memory */ + + unlock_super (sb); + MOD_DEC_USE_COUNT; + + return; +} + +void ufs_statfs(struct super_block * sb, struct statfs * buf, int bufsiz) +{ + struct statfs tmp; + + printk("ufs_statfs\n"); /* XXX */ + tmp.f_type = sb->s_magic; + tmp.f_bsize = PAGE_SIZE; + tmp.f_blocks = sb->u.ufs_sb.s_raw_sb->fs_dsize; + tmp.f_bfree = sb->u.ufs_sb.s_raw_sb->fs_cstotal.cs_nbfree; + tmp.f_bavail = sb->u.ufs_sb.s_raw_sb->fs_cstotal.cs_nbfree; /* XXX */ + tmp.f_files = sb->u.ufs_sb.s_ncg * sb->u.ufs_sb.s_ipg; + tmp.f_ffree = sb->u.ufs_sb.s_raw_sb->fs_cstotal.cs_nifree; + tmp.f_fsid.val[0] = sb->u.ufs_sb.s_raw_sb->fs_id[0]; + tmp.f_fsid.val[1] = sb->u.ufs_sb.s_raw_sb->fs_id[1]; + tmp.f_namelen = MAXNAMLEN; +/* tmp.f_spare[6] */ + + memcpy_tofs(buf, &tmp, bufsiz); + + return; +} + + +/* + * Local Variables: *** + * c-indent-level: 8 *** + * c-continued-statement-offset: 8 *** + * c-brace-offset: -8 *** + * c-argdecl-indent: 0 *** + * c-label-offset: -8 *** + * End: *** + */ diff -u --recursive --new-file v1.3.93/linux/fs/ufs/ufs_symlink.c linux/fs/ufs/ufs_symlink.c --- v1.3.93/linux/fs/ufs/ufs_symlink.c Thu Jan 1 02:00:00 1970 +++ linux/fs/ufs/ufs_symlink.c Mon Apr 22 10:59:39 1996 @@ -0,0 +1,181 @@ +/* + * linux/fs/ufs/ufs_symlink.c + * + * Copyright (C) 1996 + * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu) + * Laboratory for Computer Science Research Computing Facility + * Rutgers, The State University of New Jersey + * + * $Id: ufs_symlink.c,v 1.1 1996/04/21 14:41:23 davem Exp $ + * + */ + +#include +#include + +static int +ufs_readlink(struct inode * inode, char * buffer, int buflen) +{ + unsigned long int block; + struct buffer_head * bh = NULL; + char * link; + int i, err; + char c; + + if (inode->i_sb->u.ufs_sb.s_flags & (UFS_DEBUG|UFS_DEBUG_LINKS)) { + printk("ufs_readlink: called on ino %lu dev %u/%u\n", + inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev)); + } + + if (!S_ISLNK(inode->i_mode)) { + iput (inode); + return -EINVAL; + } + if (buflen > inode->i_sb->s_blocksize - 1) + buflen = inode->i_sb->s_blocksize - 1; + if (inode->i_blocks) { + /* XXX - error checking */ + block = ufs_bmap(inode, 0); + if (inode->i_sb->u.ufs_sb.s_flags &(UFS_DEBUG|UFS_DEBUG_LINKS)) { + printk("ufs_readlink: bmap got %lu for ino %lu\n", + block, inode->i_ino); +} + bh = bread(inode->i_dev, block, BLOCK_SIZE); + if (!bh) { + iput (inode); + printk("ufs_readlink: can't read block 0 for ino %lu on dev %u/%u\n", + inode->i_ino, MAJOR(inode->i_dev), + MINOR(inode->i_dev)); + return 0; + } + link = bh->b_data; + } + else { + link = (char *)&(inode->u.ufs_i.ui_db[0]); + } + i = 0; + while (i < buflen && (c = link[i])) { + i++; + put_user (c, buffer++); + } + iput (inode); + if (bh) + brelse (bh); + return i; + + return(0); +} + +/* + * XXX - blatantly stolen from ext2fs + */ +static int +ufs_follow_link(struct inode * dir, struct inode * inode, + int flag, int mode, struct inode ** res_inode) +{ + unsigned long int block; + int error; + struct buffer_head * bh; + char * link; + + bh = NULL; + + if (inode->i_sb->u.ufs_sb.s_flags & (UFS_DEBUG|UFS_DEBUG_LINKS)) { + printk("ufs_follow_link: called on ino %lu dev %u/%u\n", + dir->i_ino, MAJOR(dir->i_dev), MINOR(dir->i_dev)); + } + + *res_inode = NULL; + if (!dir) { + dir = current->fs->root; + dir->i_count++; + } + if (!inode) { + iput (dir); + return -ENOENT; + } + if (!S_ISLNK(inode->i_mode)) { + iput (dir); + *res_inode = inode; + return 0; + } + if (current->link_count > 5) { + iput (dir); + iput (inode); + return -ELOOP; + } + if (inode->i_blocks) { + /* read the link from disk */ + /* XXX - error checking */ + block = ufs_bmap(inode, 0); + bh = bread(inode->i_dev, block, BLOCK_SIZE); + if (bh == NULL) { + printk("ufs_follow_link: can't read block 0 for ino %lu on dev %u/%u\n", + inode->i_ino, MAJOR(inode->i_dev), + MINOR(inode->i_dev)); + iput(dir); + iput(inode); + return(-EIO); + } + link = bh->b_data; + } else { + /* fast symlink */ + link = (char *)&(inode->u.ufs_i.ui_db[0]); + } + current->link_count++; + error = open_namei (link, flag, mode, res_inode, dir); + current->link_count--; + iput (inode); + if (bh) { + brelse (bh); + } + return(error); +} + + +static struct file_operations ufs_symlink_operations = { + NULL, /* lseek */ + NULL, /* read */ + NULL, /* write */ + NULL, /* readdir */ + NULL, /* select */ + NULL, /* ioctl */ + NULL, /* mmap */ + NULL, /* open */ + NULL, /* release */ + NULL, /* fsync */ /* XXX - is this ok? */ + NULL, /* fasync */ + NULL, /* check_media_change */ + NULL, /* revalidate */ +}; + +struct inode_operations ufs_symlink_inode_operations = { + &ufs_symlink_operations, /* default directory file operations */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + &ufs_readlink, /* readlink */ + &ufs_follow_link, /* follow_link */ + NULL, /* readpage */ + NULL, /* writepage */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL, /* permission */ + NULL, /* smap */ +}; + +/* + * Local Variables: *** + * c-indent-level: 8 *** + * c-continued-statement-offset: 8 *** + * c-brace-offset: -8 *** + * c-argdecl-indent: 0 *** + * c-label-offset: -8 *** + * End: *** + */ diff -u --recursive --new-file v1.3.93/linux/include/asm-i386/pgtable.h linux/include/asm-i386/pgtable.h --- v1.3.93/linux/include/asm-i386/pgtable.h Fri Apr 12 15:52:05 1996 +++ linux/include/asm-i386/pgtable.h Mon Apr 22 12:21:13 1996 @@ -290,7 +290,7 @@ do { \ (tsk)->tss.cr3 = (unsigned long) (pgdir); \ if ((tsk) == current) \ - __asm__ __volatile__("movl %0,%%cr3": :"a" ((tsk)->tss.cr3)); \ + __asm__ __volatile__("movl %0,%%cr3": :"a" (pgdir)); \ } while (0) extern inline int pte_none(pte_t pte) { return !pte_val(pte); } diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/a.out.h linux/include/asm-m68k/a.out.h --- v1.3.93/linux/include/asm-m68k/a.out.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/a.out.h Wed Dec 27 22:46:42 1995 @@ -0,0 +1,26 @@ +#ifndef __M68K_A_OUT_H__ +#define __M68K_A_OUT_H__ + +struct exec +{ + unsigned long a_info; /* Use macros N_MAGIC, etc for access */ + unsigned a_text; /* length of text, in bytes */ + unsigned a_data; /* length of data, in bytes */ + unsigned a_bss; /* length of uninitialized data area for file, in bytes */ + unsigned a_syms; /* length of symbol table data in file, in bytes */ + unsigned a_entry; /* start address */ + unsigned a_trsize; /* length of relocation info for text, in bytes */ + unsigned a_drsize; /* length of relocation info for data, in bytes */ +}; + +#define N_TRSIZE(a) ((a).a_trsize) +#define N_DRSIZE(a) ((a).a_drsize) +#define N_SYMSIZE(a) ((a).a_syms) + +#ifdef __KERNEL__ + +#define STACK_TOP TASK_SIZE + +#endif + +#endif /* __M68K_A_OUT_H__ */ diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/amifd.h linux/include/asm-m68k/amifd.h --- v1.3.93/linux/include/asm-m68k/amifd.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/amifd.h Sun Mar 3 03:59:14 1996 @@ -0,0 +1,57 @@ +#ifndef _ASM_M68K_AMIFD_H +#define _ASM_M68K_AMIFD_H + +/* Definitions for the Amiga floppy driver */ + +#include + +#define FD_MAX_UNITS 4 + +struct fd_data_type { + char *name; /* description of data type */ + int sects; /* sectors per track */ +#ifdef __STDC__ + int (*read_fkt)(int, unsigned char *, unsigned long, int); + void (*write_fkt)(int, unsigned long, unsigned char *, int); +#else + int (*read_fkt)(); /* read whole track */ + void (*write_fkt)(); /* write whole track */ +#endif +}; + +#ifndef ASSEMBLER +/* +** Floppy type descriptions +*/ + +struct fd_drive_type { + unsigned long code; /* code returned from drive */ + char *name; /* description of drive */ + unsigned int tracks; /* number of tracks */ + unsigned int heads; /* number of heads */ + unsigned int read_size; /* raw read size for one track */ + unsigned int write_size; /* raw write size for one track */ + unsigned int sect_mult; /* sectors and gap multiplier (HD = 2) */ + unsigned int precomp1; /* start track for precomp 1 */ + unsigned int precomp2; /* start track for precomp 2 */ + unsigned int step_delay; /* time (in ms) for delay after step */ + unsigned int settle_time; /* time to settle after dir change */ + unsigned int side_time; /* time needed to change sides */ +}; + +struct amiga_floppy_struct { + struct fd_drive_type *type; /* type of floppy for this unit */ + struct fd_data_type *dtype; /* type of floppy for this unit */ + int track; /* current track (-1 == unknown) */ + + int blocks; /* total # blocks on disk */ + int sects; /* number of sectors per track */ + + int disk; /* disk in drive (-1 == unknown) */ + int motor; /* true when motor is at speed */ + int busy; /* true when drive is active */ + int status; /* current error code for unit */ +}; +#endif + +#endif diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/amifdreg.h linux/include/asm-m68k/amifdreg.h --- v1.3.93/linux/include/asm-m68k/amifdreg.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/amifdreg.h Wed Dec 27 22:46:43 1995 @@ -0,0 +1,81 @@ +#ifndef _LINUX_AMIFDREG_H +#define _LINUX_AMIFDREG_H + +/* +** CIAAPRA bits (read only) +*/ + +#define DSKRDY (0x1<<5) /* disk ready when low */ +#define DSKTRACK0 (0x1<<4) /* head at track zero when low */ +#define DSKPROT (0x1<<3) /* disk protected when low */ +#define DSKCHANGE (0x1<<2) /* low when disk removed */ + +/* +** CIAAPRB bits (read/write) +*/ + +#define DSKMOTOR (0x1<<7) /* motor on when low */ +#define DSKSEL3 (0x1<<6) /* select drive 3 when low */ +#define DSKSEL2 (0x1<<5) /* select drive 2 when low */ +#define DSKSEL1 (0x1<<4) /* select drive 1 when low */ +#define DSKSEL0 (0x1<<3) /* select drive 0 when low */ +#define DSKSIDE (0x1<<2) /* side selection: 0 = upper, 1 = lower */ +#define DSKDIREC (0x1<<1) /* step direction: 0=in, 1=out (to trk 0) */ +#define DSKSTEP (0x1) /* pulse low to step head 1 track */ + +/* +** DSKBYTR bits (read only) +*/ + +#define DSKBYT (1<<15) /* register contains valid byte when set */ +#define DMAON (1<<14) /* disk DMA enabled */ +#define DISKWRITE (1<<13) /* disk write bit in DSKLEN enabled */ +#define WORDEQUAL (1<<12) /* DSKSYNC register match when true */ +/* bits 7-0 are data */ + +/* +** ADKCON/ADKCONR bits +*/ + +#ifndef SETCLR +#define ADK_SETCLR (1<<15) /* control bit */ +#endif +#define ADK_PRECOMP1 (1<<14) /* precompensation selection */ +#define ADK_PRECOMP0 (1<<13) /* 00=none, 01=140ns, 10=280ns, 11=500ns */ +#define ADK_MFMPREC (1<<12) /* 0=GCR precomp., 1=MFM precomp. */ +#define ADK_WORDSYNC (1<<10) /* enable DSKSYNC auto DMA */ +#define ADK_MSBSYNC (1<<9) /* when 1, enable sync on MSbit (for GCR) */ +#define ADK_FAST (1<<8) /* bit cell: 0=2us (GCR), 1=1us (MFM) */ + +/* +** DSKLEN bits +*/ + +#define DSKLEN_DMAEN (1<<15) +#define DSKLEN_WRITE (1<<14) + +/* +** INTENA/INTREQ bits +*/ + +#define DSKINDEX (0x1<<4) /* DSKINDEX bit */ + +/* +** Misc +*/ + +#define MFM_SYNC 0x4489 /* standard MFM sync value */ + +/* Values for FD_COMMAND */ +#define FD_RECALIBRATE 0x07 /* move to track 0 */ +#define FD_SEEK 0x0F /* seek track */ +#define FD_READ 0xE6 /* read with MT, MFM, SKip deleted */ +#define FD_WRITE 0xC5 /* write with MT, MFM */ +#define FD_SENSEI 0x08 /* Sense Interrupt Status */ +#define FD_SPECIFY 0x03 /* specify HUT etc */ +#define FD_FORMAT 0x4D /* format one track */ +#define FD_VERSION 0x10 /* get version code */ +#define FD_CONFIGURE 0x13 /* configure FIFO operation */ +#define FD_PERPENDICULAR 0x12 /* perpendicular r/w mode */ + +#endif /* _LINUX_AMIFDREG_H */ diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/amigahw.h linux/include/asm-m68k/amigahw.h --- v1.3.93/linux/include/asm-m68k/amigahw.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/amigahw.h Wed Dec 27 22:46:43 1995 @@ -0,0 +1,246 @@ +/* +** asm-m68k/amigahw.h -- This header defines some macros and pointers for +** the various Amiga custom hardware registers. +** The naming conventions used here conform to those +** used in the Amiga Hardware Reference Manual, 3rd Edition +** +** Copyright 1992 by Greg Harp +** +** This file is subject to the terms and conditions of the GNU General Public +** License. See the file README.legal in the main directory of this archive +** for more details. +** +** Created: 9/24/92 by Greg Harp +*/ + +#ifndef _ASMm68k_AMIGAHW_H_ +#define _ASMm68k_AMIGAHW_H_ + +struct CUSTOM { + u_short bltddat; + u_short dmaconr; + u_short vposr; + u_short vhposr; + u_short dskdatr; + u_short joy0dat; + u_short joy1dat; + u_short clxdat; + u_short adkconr; + u_short pot0dat; + u_short pot1dat; + u_short potgor; + u_short serdatr; + u_short dskbytr; + u_short intenar; + u_short intreqr; + u_char *dskptr; + u_short dsklen; + u_short dskdat; + u_short refptr; + u_short vposw; + u_short vhposw; + u_short copcon; + u_short serdat; + u_short serper; + u_short potgo; + u_short joytest; + u_short strequ; + u_short strvbl; + u_short strhor; + u_short strlong; + u_short bltcon0; + u_short bltcon1; + u_short bltafwm; + u_short bltalwm; + u_char *bltcpt; + u_char *bltbpt; + u_char *bltapt; + u_char *bltdpt; + u_short bltsize; + u_char pad2d; + u_char bltcon0l; + u_short bltsizv; + u_short bltsizh; + u_short bltcmod; + u_short bltbmod; + u_short bltamod; + u_short bltdmod; + u_short spare2[4]; + u_short bltcdat; + u_short bltbdat; + u_short bltadat; + u_short spare3[3]; + u_short deniseid; + u_short dsksync; + u_short *cop1lc; + u_short *cop2lc; + u_short copjmp1; + u_short copjmp2; + u_short copins; + u_short diwstrt; + u_short diwstop; + u_short ddfstrt; + u_short ddfstop; + u_short dmacon; + u_short clxcon; + u_short intena; + u_short intreq; + u_short adkcon; + struct { + u_short *audlc; + u_short audlen; + u_short audper; + u_short audvol; + u_short auddat; + u_short audspare[2]; + } aud[4]; + u_char *bplpt[8]; + u_short bplcon0; + u_short bplcon1; + u_short bplcon2; + u_short bplcon3; + u_short bpl1mod; + u_short bpl2mod; + u_short bplcon4; + u_short clxcon2; + u_short bpldat[8]; + u_char *sprpt[8]; + struct { + u_short pos; + u_short ctl; + u_short dataa; + u_short datab; + } spr[8]; + u_short color[32]; + u_short htotal; + u_short hsstop; + u_short hbstrt; + u_short hbstop; + u_short vtotal; + u_short vsstop; + u_short vbstrt; + u_short vbstop; + u_short sprhstrt; + u_short sprhstop; + u_short bplhstrt; + u_short bplhstop; + u_short hhposw; + u_short hhposr; + u_short beamcon0; + u_short hsstrt; + u_short vsstrt; + u_short hcenter; + u_short diwhigh; + u_short spare4[11]; + u_short fmode; +}; + +/* + * DMA register bits + */ +#define DMAF_SETCLR (0x8000) +#define DMAF_AUD0 (0x0001) +#define DMAF_AUD1 (0x0002) +#define DMAF_AUD2 (0x0004) +#define DMAF_AUD3 (0x0008) +#define DMAF_DISK (0x0010) +#define DMAF_SPRITE (0x0020) +#define DMAF_BLITTER (0x0040) +#define DMAF_COPPER (0x0080) +#define DMAF_RASTER (0x0100) +#define DMAF_MASTER (0x0200) +#define DMAF_BLITHOG (0x0400) +#define DMAF_BLTNZERO (0x2000) +#define DMAF_BLTDONE (0x4000) +#define DMAF_ALL (0x01FF) + +struct CIA { + u_char pra; char pad0[0xff]; + u_char prb; char pad1[0xff]; + u_char ddra; char pad2[0xff]; + u_char ddrb; char pad3[0xff]; + u_char talo; char pad4[0xff]; + u_char tahi; char pad5[0xff]; + u_char tblo; char pad6[0xff]; + u_char tbhi; char pad7[0xff]; + u_char todlo; char pad8[0xff]; + u_char todmid; char pad9[0xff]; + u_char todhi; char pada[0x1ff]; + u_char sdr; char padb[0xff]; + u_char icr; char padc[0xff]; + u_char cra; char padd[0xff]; + u_char crb; char pade[0xff]; +}; + +#if 1 +#define zTwoBase (0x80000000) +#define ZTWO_PADDR(x) (((unsigned long)(x))-zTwoBase) +#define ZTWO_VADDR(x) (((unsigned long)(x))+zTwoBase) +#else +#define zTwoBase 0 +#define ZTWO_PADDR(x) (x) +#define ZTWO_VADDR(x) (x) +#endif + +#define CUSTOM_PHYSADDR (0xdff000) +#define custom ((*(volatile struct CUSTOM *)(zTwoBase+CUSTOM_PHYSADDR))) + +#define CIAA_PHYSADDR (0xbfe001) +#define CIAB_PHYSADDR (0xbfd000) +#define ciaa ((*(volatile struct CIA *)(zTwoBase + CIAA_PHYSADDR))) +#define ciab ((*(volatile struct CIA *)(zTwoBase + CIAB_PHYSADDR))) + +#define CHIP_PHYSADDR (0x000000) +#define chipaddr ((unsigned long)(zTwoBase + CHIP_PHYSADDR)) +void amiga_chip_init (void); +void *amiga_chip_alloc (long size); +void amiga_chip_free (void *); + +struct tod3000 { + unsigned int :28, second2:4; /* lower digit */ + unsigned int :28, second1:4; /* upper digit */ + unsigned int :28, minute2:4; /* lower digit */ + unsigned int :28, minute1:4; /* upper digit */ + unsigned int :28, hour2:4; /* lower digit */ + unsigned int :28, hour1:4; /* upper digit */ + unsigned int :28, weekday:4; + unsigned int :28, day2:4; /* lower digit */ + unsigned int :28, day1:4; /* upper digit */ + unsigned int :28, month2:4; /* lower digit */ + unsigned int :28, month1:4; /* upper digit */ + unsigned int :28, year2:4; /* lower digit */ + unsigned int :28, year1:4; /* upper digit */ + unsigned int :28, cntrl1:4; /* control-byte 1 */ + unsigned int :28, cntrl2:4; /* control-byte 2 */ + unsigned int :28, cntrl3:4; /* control-byte 3 */ +}; +#define TOD3000_CNTRL1_HOLD 0 +#define TOD3000_CNTRL1_FREE 9 +#define TOD_3000 ((struct tod3000 *)(zTwoBase+0xDC0000)) + +struct tod2000 { + unsigned int :28, second2:4; /* lower digit */ + unsigned int :28, second1:4; /* upper digit */ + unsigned int :28, minute2:4; /* lower digit */ + unsigned int :28, minute1:4; /* upper digit */ + unsigned int :28, hour2:4; /* lower digit */ + unsigned int :28, hour1:4; /* upper digit */ + unsigned int :28, day2:4; /* lower digit */ + unsigned int :28, day1:4; /* upper digit */ + unsigned int :28, month2:4; /* lower digit */ + unsigned int :28, month1:4; /* upper digit */ + unsigned int :28, year2:4; /* lower digit */ + unsigned int :28, year1:4; /* upper digit */ + unsigned int :28, weekday:4; + unsigned int :28, cntrl1:4; /* control-byte 1 */ + unsigned int :28, cntrl2:4; /* control-byte 2 */ + unsigned int :28, cntrl3:4; /* control-byte 3 */ +}; + +#define TOD2000_CNTRL1_HOLD (1<<0) +#define TOD2000_CNTRL1_BUSY (1<<1) +#define TOD2000_CNTRL3_24HMODE (1<<2) +#define TOD2000_HOUR1_PM (1<<2) +#define TOD_2000 ((struct tod2000 *)(zTwoBase+0xDC0000)) + +#endif /* asm-m68k/amigahw.h */ diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/amigaints.h linux/include/asm-m68k/amigaints.h --- v1.3.93/linux/include/asm-m68k/amigaints.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/amigaints.h Fri Mar 1 00:29:19 1996 @@ -0,0 +1,99 @@ +/* +** amigaints.h -- Amiga Linux interrupt handling structs and prototypes +** +** Copyright 1992 by Greg Harp +** +** This file is subject to the terms and conditions of the GNU General Public +** License. See the file README.legal in the main directory of this archive +** for more details. +** +** Created 10/2/92 by Greg Harp +*/ + +#ifndef _ASMm68k_AMIGAINTS_H_ +#define _ASMm68k_AMIGAINTS_H_ + +/* +** Amiga Interrupt sources. +** +*/ + +#define NUM_AMIGA_SOURCES (24) + +/* vertical blanking interrupt */ +#define IRQ_AMIGA_VERTB (IRQ_MACHSPEC | 0) + +/* copper interrupt */ +#define IRQ_AMIGA_COPPER (IRQ_MACHSPEC | 1) + +/* Audio interrupts */ +#define IRQ_AMIGA_AUD0 (IRQ_MACHSPEC | 2) +#define IRQ_AMIGA_AUD1 (IRQ_MACHSPEC | 3) +#define IRQ_AMIGA_AUD2 (IRQ_MACHSPEC | 4) +#define IRQ_AMIGA_AUD3 (IRQ_MACHSPEC | 5) + +/* Blitter done interrupt */ +#define IRQ_AMIGA_BLIT (IRQ_MACHSPEC | 6) + +/* floppy disk interrupts */ +#define IRQ_AMIGA_DSKSYN (IRQ_MACHSPEC | 7) +#define IRQ_AMIGA_DSKBLK (IRQ_MACHSPEC | 8) + +/* builtin serial port interrupts */ +#define IRQ_AMIGA_RBF (IRQ_MACHSPEC | 9) +#define IRQ_AMIGA_TBE (IRQ_MACHSPEC | 10) + +/* CIA interrupt sources */ +#define IRQ_AMIGA_CIAA_TA (IRQ_MACHSPEC | 11) +#define IRQ_AMIGA_CIAA_TB (IRQ_MACHSPEC | 12) +#define IRQ_AMIGA_CIAA_ALRM (IRQ_MACHSPEC | 13) +#define IRQ_AMIGA_CIAA_SP (IRQ_MACHSPEC | 14) +#define IRQ_AMIGA_CIAA_FLG (IRQ_MACHSPEC | 15) +#define IRQ_AMIGA_CIAB_TA (IRQ_MACHSPEC | 16) +#define IRQ_AMIGA_CIAB_TB (IRQ_MACHSPEC | 17) +#define IRQ_AMIGA_CIAB_ALRM (IRQ_MACHSPEC | 18) +#define IRQ_AMIGA_CIAB_SP (IRQ_MACHSPEC | 19) +#define IRQ_AMIGA_CIAB_FLG (IRQ_MACHSPEC | 20) + +#define IRQ_AMIGA_SOFT (IRQ_MACHSPEC | 21) + +#define IRQ_AMIGA_PORTS (IRQ_MACHSPEC | 22) +#define IRQ_AMIGA_EXTER (IRQ_MACHSPEC | 23) + +#define IRQ_FLOPPY IRQ_AMIGA_DSKBLK + +/* INTREQR masks */ +#define IRQ1_MASK 0x0007 /* INTREQR mask for IRQ 1 */ +#define IRQ2_MASK 0x0008 /* INTREQR mask for IRQ 2 */ +#define IRQ3_MASK 0x0070 /* INTREQR mask for IRQ 3 */ +#define IRQ4_MASK 0x0780 /* INTREQR mask for IRQ 4 */ +#define IRQ5_MASK 0x1800 /* INTREQR mask for IRQ 5 */ +#define IRQ6_MASK 0x2000 /* INTREQR mask for IRQ 6 */ +#define IRQ7_MASK 0x4000 /* INTREQR mask for IRQ 7 */ + +#define IF_SETCLR 0x8000 /* set/clr bit */ +#define IF_INTEN 0x4000 /* master interrupt bit in INT* registers */ +#define IF_EXTER 0x2000 /* external level 6 and CIA B interrupt */ +#define IF_DSKSYN 0x1000 /* disk sync interrupt */ +#define IF_RBF 0x0800 /* serial receive buffer full interrupt */ +#define IF_AUD3 0x0400 /* audio channel 3 done interrupt */ +#define IF_AUD2 0x0200 /* audio channel 2 done interrupt */ +#define IF_AUD1 0x0100 /* audio channel 1 done interrupt */ +#define IF_AUD0 0x0080 /* audio channel 0 done interrupt */ +#define IF_BLIT 0x0040 /* blitter done interrupt */ +#define IF_VERTB 0x0020 /* vertical blanking interrupt */ +#define IF_COPER 0x0010 /* copper interrupt */ +#define IF_PORTS 0x0008 /* external level 2 and CIA A interrupt */ +#define IF_SOFT 0x0004 /* software initiated interrupt */ +#define IF_DSKBLK 0x0002 /* diskblock DMA finished */ +#define IF_TBE 0x0001 /* serial transmit buffer empty interrupt */ + +/* CIA interrupt control register bits */ + +#define CIA_ICR_TA 0x01 +#define CIA_ICR_TB 0x02 +#define CIA_ICR_ALRM 0x04 +#define CIA_ICR_SP 0x08 +#define CIA_ICR_FLG 0x10 + +#endif /* asm-m68k/amigaints.h */ diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/amigamouse.h linux/include/asm-m68k/amigamouse.h --- v1.3.93/linux/include/asm-m68k/amigamouse.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/amigamouse.h Thu Feb 29 17:41:01 1996 @@ -0,0 +1,26 @@ +#ifndef _ASMm68k_AMIGAMOUSE_H +#define _ASMm68k_AMIGAMOUSE_H + +/* + * linux/include/asm-m68k/amigamouse.h: header file for Amiga Mouse driver + * by Michael Rausch + */ + +/* +#define MSE_INT_OFF() outb(MSE_DISABLE_INTERRUPTS, MSE_CONTROL_PORT) +#define MSE_INT_ON() outb(MSE_ENABLE_INTERRUPTS, MSE_CONTROL_PORT) +*/ + +struct mouse_status { + unsigned char buttons; + unsigned char latch_buttons; + int dx; + int dy; + int present; + int ready; + int active; + struct wait_queue *wait; + struct fasync_struct *fasyncptr; +}; + +#endif diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/amigardb.h linux/include/asm-m68k/amigardb.h --- v1.3.93/linux/include/asm-m68k/amigardb.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/amigardb.h Wed Dec 27 22:46:44 1995 @@ -0,0 +1,126 @@ +#ifndef _LINUX_AMIGARDB_H +#define _LINUX_AMIGARDB_H 1 + +#define ULONG u_long +#define LONG long +#define UBYTE u_char + +/* definitions for the Amiga RigidDiskBlock layout, which always starts in + cylinder 0 of a medium. Taken from page 254f of the RKM: Devices */ + +struct RigidDiskBlock { + ULONG rdb_ID; /* 4 character identifier */ + ULONG rdb_SummedLongs; /* size of this checksummed structure */ + LONG rdb_ChkSum; /* block checksum (longword sum to zero) */ + ULONG rdb_HostID; /* SCSI Target ID of host */ + ULONG rdb_BlockBytes; /* size of disk blocks */ + ULONG rdb_Flags; /* see below for defines */ + /* block list heads */ + ULONG rdb_BadBlockList; /* optional bad block list */ + ULONG rdb_PartitionList; /* optional first partition block */ + ULONG rdb_FileSysHeaderList; /* optional file system header block */ + ULONG rdb_DriveInit; /* optional drive-specific init code */ + /* DriveInit(lun,rdb,ior): "C" stk & d0/a0/a1 */ + ULONG rdb_Reserved1[6]; /* set to $ffffffff */ + /* physical drive characteristics */ + ULONG rdb_Cylinders; /* number of drive cylinders */ + ULONG rdb_Sectors; /* sectors per track */ + ULONG rdb_Heads; /* number of drive heads */ + ULONG rdb_Interleave; /* interleave */ + ULONG rdb_Park; /* landing zone cylinder */ + ULONG rdb_Reserved2[3]; + ULONG rdb_WritePreComp; /* starting cylinder: write precompensation */ + ULONG rdb_ReducedWrite; /* starting cylinder: reduced write current */ + ULONG rdb_StepRate; /* drive step rate */ + ULONG rdb_Reserved3[5]; + /* logical drive characteristics */ + ULONG rdb_RDBBlocksLo; /* low block of range reserved for hardblocks */ + ULONG rdb_RDBBlocksHi; /* high block of range for these hardblocks */ + ULONG rdb_LoCylinder; /* low cylinder of partitionable disk area */ + ULONG rdb_HiCylinder; /* high cylinder of partitionable data area */ + ULONG rdb_CylBlocks; /* number of blocks available per cylinder */ + ULONG rdb_AutoParkSeconds; /* zero for no auto park */ + ULONG rdb_HighRDSKBlock; /* highest block used by RDSK */ + /* (not including replacement bad blocks) */ + ULONG rdb_Reserved4; + /* drive identification */ + char rdb_DiskVendor[8]; + char rdb_DiskProduct[16]; + char rdb_DiskRevision[4]; + char rdb_ControllerVendor[8]; + char rdb_ControllerProduct[16]; + char rdb_ControllerRevision[4]; + ULONG rdb_Reserved5[10]; +}; + +#define IDNAME_RIGIDDISK 0x5244534B /* 'RDSK' */ + +#define RDB_LOCATION_LIMIT 16 + +#define RDBFB_LAST 0 /* no disks exist to be configured after */ +#define RDBFF_LAST 0x01L /* this one on this controller */ +#define RDBFB_LASTLUN 1 /* no LUNs exist to be configured greater */ +#define RDBFF_LASTLUN 0x02L /* than this one at this SCSI Target ID */ +#define RDBFB_LASTTID 2 /* no Target IDs exist to be configured */ +#define RDBFF_LASTTID 0x04L /* greater than this one on this SCSI bus */ +#define RDBFB_NORESELECT 3 /* don't bother trying to perform reselection */ +#define RDBFF_NORESELECT 0x08L /* when talking to this drive */ +#define RDBFB_DISKID 4 /* rdb_Disk... identification valid */ +#define RDBFF_DISKID 0x10L +#define RDBFB_CTRLRID 5 /* rdb_Controller... identification valid */ +#define RDBFF_CTRLRID 0x20L + /* added 7/20/89 by commodore: */ +#define RDBFB_SYNCH 6 /* drive supports scsi synchronous mode */ +#define RDBFF_SYNCH 0x40L /* CAN BE DANGEROUS TO USE IF IT DOESN'T! */ + +struct PartitionBlock { + ULONG pb_ID; /* 4 character identifier */ + ULONG pb_SummedLongs; /* size of this checksummed structure */ + LONG pb_ChkSum; /* block checksum (longword sum to zero) */ + ULONG pb_HostID; /* SCSI Target ID of host */ + ULONG pb_Next; /* block number of the next PartitionBlock */ + ULONG pb_Flags; /* see below for defines */ + ULONG pb_Reserved1[2]; + ULONG pb_DevFlags; /* preferred flags for OpenDevice */ + UBYTE pb_DriveName[32]; /* preferred DOS device name: BSTR form */ + /* (not used if this name is in use) */ + ULONG pb_Reserved2[15]; /* filler to 32 longwords */ + ULONG pb_Environment[17]; /* environment vector for this partition */ + ULONG pb_EReserved[15]; /* reserved for future environment vector */ +}; + +#define IDNAME_PARTITION 0x50415254 /* 'PART' */ + +#define PBFB_BOOTABLE 0 /* this partition is intended to be bootable */ +#define PBFF_BOOTABLE 1L /* (expected directories and files exist) */ +#define PBFB_NOMOUNT 1 /* do not mount this partition (e.g. manually */ +#define PBFF_NOMOUNT 2L /* mounted, but space reserved here) */ + +/* this is from */ + +#define DE_TABLESIZE 0 /* minimum value is 11 (includes NumBuffers) */ +#define DE_SIZEBLOCK 1 /* in longwords: standard value is 128 */ +#define DE_SECORG 2 /* not used; must be 0 */ +#define DE_NUMHEADS 3 /* # of heads (surfaces). drive specific */ +#define DE_SECSPERBLK 4 /* not used; must be 1 */ +#define DE_BLKSPERTRACK 5 /* blocks per track. drive specific */ +#define DE_RESERVEDBLKS 6 /* unavailable blocks at start. usually 2 */ +#define DE_PREFAC 7 /* not used; must be 0 */ +#define DE_INTERLEAVE 8 /* usually 0 */ +#define DE_LOWCYL 9 /* starting cylinder. typically 0 */ +#define DE_UPPERCYL 10 /* max cylinder. drive specific */ +#define DE_NUMBUFFERS 11 /* starting # of buffers. typically 5 */ +#define DE_MEMBUFTYPE 12 /* type of mem to allocate for buffers. */ +#define DE_BUFMEMTYPE 12 /* same as above, better name + * 1 is public, 3 is chip, 5 is fast */ +#define DE_MAXTRANSFER 13 /* Max number bytes to transfer at a time */ +#define DE_MASK 14 /* Address Mask to block out certain memory */ +#define DE_BOOTPRI 15 /* Boot priority for autoboot */ +#define DE_DOSTYPE 16 /* ASCII (HEX) string showing filesystem type; + * 0X444F5300 is old filesystem, + * 0X444F5301 is fast file system */ +#define DE_BAUD 17 /* Baud rate for serial handler */ +#define DE_CONTROL 18 /* Control word for handler/filesystem */ +#define DE_BOOTBLOCKS 19 /* Number of blocks containing boot code */ + +#endif /* _LINUX_AMIGARDB_H */ diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/amigatypes.h linux/include/asm-m68k/amigatypes.h --- v1.3.93/linux/include/asm-m68k/amigatypes.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/amigatypes.h Thu Mar 7 18:54:36 1996 @@ -0,0 +1,59 @@ +/* +** linux/amigatypes.h -- Types used in Amiga Linux kernel source +** +** Copyright 1992 by Greg Harp +** +** This file is subject to the terms and conditions of the GNU General Public +** License. See the file README.legal in the main directory of this archive +** for more details. +** +** Created 09/29/92 by Greg Harp +** +** Moved all Zorro definitions to asm/zorro.h which is where they +** really belong - 24/11/95 Jes Sorensen +*/ + +#ifndef _LINUX_AMIGATYPES_H_ +#define _LINUX_AMIGATYPES_H_ + +#ifdef __KERNEL__ /* only if compiling the kernel */ +#include +#endif + +/* + * Different models of Amiga + */ +#define AMI_UNKNOWN (0) +#define AMI_500 (1) +#define AMI_500PLUS (2) +#define AMI_600 (3) +#define AMI_1000 (4) +#define AMI_1200 (5) +#define AMI_2000 (6) +#define AMI_2500 (7) +#define AMI_3000 (8) +#define AMI_3000T (9) +#define AMI_3000PLUS (10) +#define AMI_4000 (11) +#define AMI_4000T (12) +#define AMI_CDTV (13) +#define AMI_CD32 (14) +#define AMI_DRACO (15) + +/* + * chipsets + */ +#define CS_STONEAGE (0) +#define CS_OCS (1) +#define CS_ECS (2) +#define CS_AGA (3) + +/* + * Amiga clocks + */ + +extern u_long amiga_masterclock; /* 28 MHz */ +extern u_long amiga_colorclock; /* 3.5 MHz */ +#define amiga_eclock boot_info.bi_amiga.eclock /* 700 kHz */ + +#endif /* asm-m68k/amigatypes.h */ diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/amihdreg.h linux/include/asm-m68k/amihdreg.h --- v1.3.93/linux/include/asm-m68k/amihdreg.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/amihdreg.h Mon Apr 1 00:50:11 1996 @@ -0,0 +1,31 @@ +#ifndef _LINUX_AMIHDREG_H +#define _LINUX_AMIHDREG_H + +/* + * This file contains some defines for the Amiga IDE hd controller. + * Various sources. Check out some definitions (see comments with + * a ques). + */ + +#define IDE_DISABLE_IRQ 0x02 +#define IDE_ENABLE_IRQ 0x00 + +/* Bases of the hard drive controller */ +#define HD_BASE_A4000 0xdd2020 +#define HD_BASE_A1200 0xda0000 + +/* Offsets from one of the above bases */ +#define AMI_HD_ERROR (0x06) /* see err-bits */ +#define AMI_HD_NSECTOR (0x0a) /* nr of sectors to read/write */ +#define AMI_HD_SECTOR (0x0e) /* starting sector */ +#define AMI_HD_LCYL (0x12) /* starting cylinder */ +#define AMI_HD_HCYL (0x16) /* high byte of starting cyl */ +#define AMI_HD_SELECT (0x1a) /* 101dhhhh , d=drive, hhhh=head */ +#define AMI_HD_STATUS (0x1e) /* see status-bits */ +#define AMI_HD_CMD (0x101a) + +/* These are at different offsets from the base */ +#define HD_A4000_IRQ (0xdd3020) /* MSB = 1, Harddisk is source of interrupt */ +#define HD_A1200_IRQ (0xda9000) /* MSB = 1, Harddisk is source of interrupt */ + +#endif diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/atafd.h linux/include/asm-m68k/atafd.h --- v1.3.93/linux/include/asm-m68k/atafd.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/atafd.h Thu Mar 7 21:59:49 1996 @@ -0,0 +1,12 @@ +#ifndef _ASM_M68K_FD_H +#define _ASM_M68K_FD_H + +/* Definitions for the Atari Floppy driver */ + +struct atari_format_descr { + int track; /* to be formatted */ + int head; /* "" "" */ + int sect_offset; /* offset of first sector */ +}; + +#endif diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/atafdreg.h linux/include/asm-m68k/atafdreg.h --- v1.3.93/linux/include/asm-m68k/atafdreg.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/atafdreg.h Mon Mar 4 22:47:31 1996 @@ -0,0 +1,79 @@ +#ifndef _LINUX_FDREG_H +#define _LINUX_FDREG_H + +/* +** WD1772 stuff + */ + +/* register codes */ + +#define FDCSELREG_STP (0x80) /* command/status register */ +#define FDCSELREG_TRA (0x82) /* track register */ +#define FDCSELREG_SEC (0x84) /* sector register */ +#define FDCSELREG_DTA (0x86) /* data register */ + +/* register names for FDC_READ/WRITE macros */ + +#define FDCREG_CMD 0 +#define FDCREG_STATUS 0 +#define FDCREG_TRACK 2 +#define FDCREG_SECTOR 4 +#define FDCREG_DATA 6 + +/* command opcodes */ + +#define FDCCMD_RESTORE (0x00) /* - */ +#define FDCCMD_SEEK (0x10) /* | */ +#define FDCCMD_STEP (0x20) /* | TYP 1 Commands */ +#define FDCCMD_STIN (0x40) /* | */ +#define FDCCMD_STOT (0x60) /* - */ +#define FDCCMD_RDSEC (0x80) /* - TYP 2 Commands */ +#define FDCCMD_WRSEC (0xa0) /* - " */ +#define FDCCMD_RDADR (0xc0) /* - */ +#define FDCCMD_RDTRA (0xe0) /* | TYP 3 Commands */ +#define FDCCMD_WRTRA (0xf0) /* - */ +#define FDCCMD_FORCI (0xd0) /* - TYP 4 Command */ + +/* command modifier bits */ + +#define FDCCMDADD_SR6 (0x00) /* step rate settings */ +#define FDCCMDADD_SR12 (0x01) +#define FDCCMDADD_SR2 (0x02) +#define FDCCMDADD_SR3 (0x03) +#define FDCCMDADD_V (0x04) /* verify */ +#define FDCCMDADD_H (0x08) /* wait for spin-up */ +#define FDCCMDADD_U (0x10) /* update track register */ +#define FDCCMDADD_M (0x10) /* multiple sector access */ +#define FDCCMDADD_E (0x04) /* head settling flag */ +#define FDCCMDADD_P (0x02) /* precompensation off */ +#define FDCCMDADD_A0 (0x01) /* DAM flag */ + +/* status register bits */ + +#define FDCSTAT_MOTORON (0x80) /* motor on */ +#define FDCSTAT_WPROT (0x40) /* write protected (FDCCMD_WR*) */ +#define FDCSTAT_SPINUP (0x20) /* motor speed stable (Type I) */ +#define FDCSTAT_DELDAM (0x20) /* sector has deleted DAM (Type II+III) */ +#define FDCSTAT_RECNF (0x10) /* record not found */ +#define FDCSTAT_CRC (0x08) /* CRC error */ +#define FDCSTAT_TR00 (0x04) /* Track 00 flag (Type I) */ +#define FDCSTAT_LOST (0x04) /* Lost Data (Type II+III) */ +#define FDCSTAT_IDX (0x02) /* Index status (Type I) */ +#define FDCSTAT_DRQ (0x02) /* DRQ status (Type II+III) */ +#define FDCSTAT_BUSY (0x01) /* FDC is busy */ + + +/* PSG Port A Bit Nr 0 .. Side Sel .. 0 -> Side 1 1 -> Side 2 */ +#define DSKSIDE (0x01) + +#define DSKDRVNONE (0x06) +#define DSKDRV0 (0x02) +#define DSKDRV1 (0x04) + +/* step rates */ +#define FDCSTEP_6 0x00 +#define FDCSTEP_12 0x01 +#define FDCSTEP_2 0x02 +#define FDCSTEP_3 0x03 + +#endif diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/atari_joystick.h linux/include/asm-m68k/atari_joystick.h --- v1.3.93/linux/include/asm-m68k/atari_joystick.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/atari_joystick.h Sat Mar 30 14:11:24 1996 @@ -0,0 +1,22 @@ +#ifndef _LINUX_ATARI_JOYSTICK_H +#define _LINUX_ATARI_JOYSTICK_H + +/* + * linux/include/linux/atari_joystick.h + * header file for Atari Joystick driver + * by Robert de Vries (robert@and.nl) on 19Jul93 + */ + +void atari_joystick_interrupt(char*); +int atari_joystick_init(void); +extern int atari_mouse_buttons; + +struct joystick_status { + char fire; + char dir; + int ready; + int active; + struct wait_queue *wait; +}; + +#endif diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/atari_mouse.h linux/include/asm-m68k/atari_mouse.h --- v1.3.93/linux/include/asm-m68k/atari_mouse.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/atari_mouse.h Mon Mar 4 22:47:32 1996 @@ -0,0 +1,20 @@ +#ifndef _LINUX_ATARI_MOUSE_H +#define _LINUX_ATARI_MOUSE_H + +/* + * linux/include/linux/atari_mouse.h + * header file for Atari Mouse driver + * by Robert de Vries (robert@and.nl) on 19Jul93 + */ + +struct mouse_status { + char buttons; + short dx; + short dy; + int ready; + int active; + struct wait_queue *wait; + struct fasync_struct *fasyncptr; +}; + +#endif diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/atari_rootsec.h linux/include/asm-m68k/atari_rootsec.h --- v1.3.93/linux/include/asm-m68k/atari_rootsec.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/atari_rootsec.h Wed Dec 27 22:46:46 1995 @@ -0,0 +1,34 @@ +#ifndef _LINUX_ATARI_ROOTSEC_H +#define _LINUX_ATARI_ROOTSEC_H + +/* + * linux/include/linux/atari_rootsec.h + * definitions for Atari Rootsector layout + * by Andreas Schwab (schwab@ls5.informatik.uni-dortmund.de) + * + * modified for ICD/Supra partitioning scheme restricted to at most 12 + * partitions + * by Guenther Kelleter (guenther@pool.informatik.rwth-aachen.de) + */ + +struct partition_info +{ + u_char flg; /* bit 0: active; bit 7: bootable */ + char id[3]; /* "GEM", "BGM", "XGM", or other */ + u_long st; /* start of partition */ + u_long siz; /* length of partition */ +}; + +struct rootsector +{ + char unused[0x156]; /* room for boot code */ + struct partition_info icdpart[8]; /* info for ICD-partitions 5..12 */ + char unused2[0xc]; + u_long hd_siz; /* size of disk in blocks */ + struct partition_info part[4]; + u_long bsl_st; /* start of bad sector list */ + u_long bsl_cnt; /* length of bad sector list */ + u_short checksum; /* checksum for bootable disks */ +}; + +#endif /* _LINUX_ATARI_ROOTSEC_H */ diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/atari_stdma.h linux/include/asm-m68k/atari_stdma.h --- v1.3.93/linux/include/asm-m68k/atari_stdma.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/atari_stdma.h Fri Apr 19 02:35:24 1996 @@ -0,0 +1,22 @@ + +#ifndef _atari_stdma_h +#define _atari_stdma_h + + +#include + + +/***************************** Prototypes *****************************/ + +void stdma_lock(isrfunc isr, void *data); +void stdma_release( void ); +int stdma_others_waiting( void ); +int stdma_islocked( void ); +void *stdma_locked_by( void ); +void stdma_init( void ); + +/************************* End of Prototypes **************************/ + + + +#endif /* _atari_stdma_h */ diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/atarihdreg.h linux/include/asm-m68k/atarihdreg.h --- v1.3.93/linux/include/asm-m68k/atarihdreg.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/atarihdreg.h Fri Apr 19 02:35:24 1996 @@ -0,0 +1,24 @@ +#ifndef _LINUX_ATAHDREG_H +#define _LINUX_ATAHDREG_H + +/* + * This file contains some defines for the Falcon IDE hd controller. + * Various sources. Check out some definitions (see comments with + * a ques). + */ + +#define ATA_HD_BASE 0xfff00000 + +#define ATA_HD_DATA 0x00 /* _CTL when writing */ +#define ATA_HD_ERROR 0x05 /* see err-bits */ +#define ATA_HD_NSECTOR 0x09 /* nr of sectors to read/write */ +#define ATA_HD_SECTOR 0x0d /* starting sector */ +#define ATA_HD_LCYL 0x11 /* starting cylinder */ +#define ATA_HD_HCYL 0x15 /* high byte of starting cyl */ +#define ATA_HD_CURRENT 0x19 /* 101dhhhh , d=drive, hhhh=head */ +#define ATA_HD_STATUS 0x1d /* see status-bits */ + +#define ATA_HD_CMD 0x39 +#define ATA_HD_ALTSTATUS 0x39 /* same as HD_STATUS but doesn't clear irq */ + +#endif /* _LINUX_ATAHDREG_H */ diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/atarihw.h linux/include/asm-m68k/atarihw.h --- v1.3.93/linux/include/asm-m68k/atarihw.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/atarihw.h Mon Mar 4 22:47:32 1996 @@ -0,0 +1,633 @@ +/* +** linux/atarihw.h -- This header defines some macros and pointers for +** the various Atari custom hardware registers. +** +** Copyright 1994 by Bj”rn Brauel +** +** 5/1/94 Roman Hodek: +** Added definitions for TT specific chips. +** +** This file is subject to the terms and conditions of the GNU General Public +** License. See the file README.legal in the main directory of this archive +** for more details. +** +*/ + +#ifndef _LINUX_ATARIHW_H_ +#define _LINUX_ATARIHW_H_ + +#include + +/* Reading the MFP port register gives a machine independant delay, since the + * MFP always has a 8 MHz clock. This avoids problems with the varying length + * of nops on various machines. Somebody claimed that the tstb takes 600 ns. + */ +#define MFPDELAY() \ + __asm__ __volatile__ ( "tstb %0" : : "m" (mfp.par_dt_reg) : "cc" ); + +/* Memory used for screen ram and stdma buffers */ +void atari_stram_init (void); +void *atari_stram_alloc (long size, unsigned long *start_mem ); +void atari_stram_free (void *); + +extern int is_medusa; + +/* Do cache push/invalidate for DMA read/write. This function obeys the + * snooping on some machines (Medusa) and processors: The Medusa itself can + * snoop, but only the '040 can source data from its cache to DMA writes i.e., + * reads from memory). Both '040 and '060 invalidate cache entries on snooped + * DMA reads (i.e., writes to memory). + */ + +#include +#include + +static inline void dma_cache_maintainance( unsigned long paddr, + unsigned long len, + int writeflag ) + +{ + if (writeflag) { + if (!is_medusa || m68k_is040or060 == 6) + cache_push( paddr, len ); + } + else { + if (!is_medusa) + cache_clear( paddr, len ); + } +} + + +/* +** Shifter + */ +#define ST_LOW 0 +#define ST_MID 1 +#define ST_HIGH 2 +#define TT_LOW 7 +#define TT_MID 4 +#define TT_HIGH 6 + +#define SHF_BAS (0xffff8200) +struct SHIFTER + { + u_char pad1; + u_char bas_hi; + u_char pad2; + u_char bas_md; + u_char pad3; + u_char volatile vcounthi; + u_char pad4; + u_char volatile vcountmid; + u_char pad5; + u_char volatile vcountlow; + u_char volatile syncmode; + u_char pad6; + u_char pad7; + u_char bas_lo; + }; +# define shifter ((*(volatile struct SHIFTER *)SHF_BAS)) + +#define SHF_FBAS (0xffff820e) +struct SHIFTER_F030 + { + u_short off_next; + u_short scn_width; + }; +# define shifter_f030 ((*(volatile struct SHIFTER_F030 *)SHF_FBAS)) + + +#define SHF_TBAS (0xffff8200) +struct SHIFTER_TT { + u_char char_dummy0; + u_char bas_hi; /* video mem base addr, high and mid byte */ + u_char char_dummy1; + u_char bas_md; + u_char char_dummy2; + u_char vcount_hi; /* pointer to currently displayed byte */ + u_char char_dummy3; + u_char vcount_md; + u_char char_dummy4; + u_char vcount_lo; + u_short st_sync; /* ST compatible sync mode register, unused */ + u_char char_dummy5; + u_char bas_lo; /* video mem addr, low byte */ + u_char char_dummy6[2+3*16]; + /* $ffff8240: */ + u_short color_reg[16]; /* 16 color registers */ + u_char st_shiftmode; /* ST compatible shift mode register, unused */ + u_char char_dummy7; + u_short tt_shiftmode; /* TT shift mode register */ + + +}; +#define shifter_tt ((*(volatile struct SHIFTER_TT *)SHF_TBAS)) + +/* values for shifter_tt->tt_shiftmode */ +#define TT_SHIFTER_STLOW 0x0000 +#define TT_SHIFTER_STMID 0x0100 +#define TT_SHIFTER_STHIGH 0x0200 +#define TT_SHIFTER_TTLOW 0x0700 +#define TT_SHIFTER_TTMID 0x0400 +#define TT_SHIFTER_TTHIGH 0x0600 +#define TT_SHIFTER_MODEMASK 0x0700 +#define TT_SHIFTER_NUMMODE 0x0008 +#define TT_SHIFTER_PALETTE_MASK 0x000f +#define TT_SHIFTER_GRAYMODE 0x1000 + +/* 256 TT palette registers */ +#define TT_PALETTE_BASE (0xffff8400) +#define tt_palette ((volatile u_short *)TT_PALETTE_BASE) + +#define TT_PALETTE_RED_MASK 0x0f00 +#define TT_PALETTE_GREEN_MASK 0x00f0 +#define TT_PALETTE_BLUE_MASK 0x000f + +/* +** Falcon030 VIDEL Video Controller +** for description see File 'linux\tools\atari\hardware.txt + */ +#define f030_col ((u_long *) 0xffff9800) +#define f030_xreg ((u_short*) 0xffff8282) +#define f030_yreg ((u_short*) 0xffff82a2) +#define f030_creg ((u_short*) 0xffff82c0) +#define f030_sreg ((u_short*) 0xffff8260) +#define f030_mreg ((u_short*) 0xffff820a) +#define f030_linewidth ((u_short*) 0xffff820e) +#define f030_hscroll ((u_char*) 0xffff8265) + +#define VIDEL_BAS (0xffff8260) +struct VIDEL { + u_short st_shift; + u_short pad1; + u_char xoffset_s; + u_char xoffset; + u_short f_shift; + u_char pad2[0x1a]; + u_short hht; + u_short hbb; + u_short hbe; + u_short hdb; + u_short hde; + u_short hss; + u_char pad3[0x14]; + u_short vft; + u_short vbb; + u_short vbe; + u_short vdb; + u_short vde; + u_short vss; + u_char pad4[0x12]; + u_short control; + u_short mode; +}; +#define videl ((*(volatile struct VIDEL *)VIDEL_BAS)) + +/* +** DMA/WD1772 Disk Controller + */ + +#define FWD_BAS (0xffff8604) +struct DMA_WD + { + u_short fdc_acces_seccount; + u_short dma_mode_status; + u_char dma_vhi; /* Some extended ST-DMAs can handle 32 bit addresses */ + u_char dma_hi; + u_char char_dummy2; + u_char dma_md; + u_char char_dummy3; + u_char dma_lo; + u_short fdc_speed; + }; +# define dma_wd ((*(volatile struct DMA_WD *)FWD_BAS)) +/* alias */ +#define st_dma dma_wd +/* The two highest bytes of an extended DMA as a short; this is a must + * for the Medusa. + */ +#define st_dma_ext_dmahi (*((volatile unsigned short *)0xffff8608)) + +/* +** YM2149 Sound Chip +** access in bytes + */ + +#define YM_BAS (0xffff8800) +struct SOUND_YM + { + u_char rd_data_reg_sel; + u_char char_dummy1; + u_char wd_data; + }; +#define sound_ym ((*(volatile struct SOUND_YM *)YM_BAS)) + +/* TT SCSI DMA */ + +#define TT_SCSI_DMA_BAS (0xffff8700) +struct TT_DMA { + u_char char_dummy0; + u_char dma_addr_hi; + u_char char_dummy1; + u_char dma_addr_hmd; + u_char char_dummy2; + u_char dma_addr_lmd; + u_char char_dummy3; + u_char dma_addr_lo; + u_char char_dummy4; + u_char dma_cnt_hi; + u_char char_dummy5; + u_char dma_cnt_hmd; + u_char char_dummy6; + u_char dma_cnt_lmd; + u_char char_dummy7; + u_char dma_cnt_lo; + u_long dma_restdata; + u_short dma_ctrl; +}; +#define tt_scsi_dma ((*(volatile struct TT_DMA *)TT_SCSI_DMA_BAS)) + +/* TT SCSI Controller 5380 */ + +#define TT_5380_BAS (0xffff8781) +struct TT_5380 { + u_char scsi_data; + u_char char_dummy1; + u_char scsi_icr; + u_char char_dummy2; + u_char scsi_mode; + u_char char_dummy3; + u_char scsi_tcr; + u_char char_dummy4; + u_char scsi_idstat; + u_char char_dummy5; + u_char scsi_dmastat; + u_char char_dummy6; + u_char scsi_targrcv; + u_char char_dummy7; + u_char scsi_inircv; +}; +#define tt_scsi ((*(volatile struct TT_5380 *)TT_5380_BAS)) +#define tt_scsi_regp ((volatile char *)TT_5380_BAS) + + +/* +** Falcon DMA Sound Subsystem +** not implemented yet + */ + +/* +** Falcon Blitter +*/ + +#define BLT_BAS (0xffff8a00) + +struct BLITTER + { + u_short halftone[16]; + u_short src_x_inc; + u_short src_y_inc; + u_long src_address; + u_short endmask1; + u_short endmask2; + u_short endmask3; + u_short dst_x_inc; + u_short dst_y_inc; + u_long dst_adress; + u_short wd_per_line; + u_short ln_per_bb; + u_short hlf_op_reg; + u_short log_op_reg; + u_short lin_nm_reg; + u_short skew_reg; + }; +# define blitter ((*(volatile struct BLITTER *)BLT_BAS)) + + +/* +** SCC Z8530 + */ + +#define SCC_BAS (0xffff8c81) +struct SCC + { + u_char cha_a_ctrl; + u_char char_dummy1; + u_char cha_a_data; + u_char char_dummy2; + u_char cha_b_ctrl; + u_char char_dummy3; + u_char cha_b_data; + }; +# define scc ((*(volatile struct SCC*)SCC_BAS)) + +/* The ESCC (Z85230) in an Atari ST. The channels are revered! */ +# define st_escc ((*(volatile struct SCC*)0xfffffa31)) +# define st_escc_dsr ((*(volatile char *)0xfffffa39)) + +/* TT SCC DMA Controller (same chip as SCSI DMA) */ + +#define TT_SCC_DMA_BAS (0xffff8c01) +#define tt_scc_dma ((*(volatile struct TT_DMA *)TT_SCC_DMA_BAS)) + +/* +** VIDEL Palette Register + */ + +#define FPL_BAS (0xffff9800) +struct VIDEL_PALETTE + { + u_long reg[256]; + }; +# define videl_palette ((*(volatile struct VIDEL_PALETTE*)FPL_BAS)) + + +/* +** Falcon DSP Host Interface +** not implemented yet + */ + +/* +** MFP 68901 + */ + +#define MFP_BAS (0xfffffa01) +struct MFP + { + u_char par_dt_reg; + u_char char_dummy1; + u_char active_edge; + u_char char_dummy2; + u_char data_dir; + u_char char_dummy3; + u_char int_en_a; + u_char char_dummy4; + u_char int_en_b; + u_char char_dummy5; + u_char int_pn_a; + u_char char_dummy6; + u_char int_pn_b; + u_char char_dummy7; + u_char int_sv_a; + u_char char_dummy8; + u_char int_sv_b; + u_char char_dummy9; + u_char int_mk_a; + u_char char_dummy10; + u_char int_mk_b; + u_char char_dummy11; + u_char vec_adr; + u_char char_dummy12; + u_char tim_ct_a; + u_char char_dummy13; + u_char tim_ct_b; + u_char char_dummy14; + u_char tim_ct_cd; + u_char char_dummy15; + u_char tim_dt_a; + u_char char_dummy16; + u_char tim_dt_b; + u_char char_dummy17; + u_char tim_dt_c; + u_char char_dummy18; + u_char tim_dt_d; + u_char char_dummy19; + u_char sync_char; + u_char char_dummy20; + u_char usart_ctr; + u_char char_dummy21; + u_char rcv_stat; + u_char char_dummy22; + u_char trn_stat; + u_char char_dummy23; + u_char usart_dta; + }; +# define mfp ((*(volatile struct MFP*)MFP_BAS)) + +/* TT's second MFP */ + +#define TT_MFP_BAS (0xfffffa81) +# define tt_mfp ((*(volatile struct MFP*)TT_MFP_BAS)) + + +/* TT System Control Unit */ + +#define TT_SCU_BAS (0xffff8e01) +struct TT_SCU { + u_char sys_mask; + u_char char_dummy1; + u_char sys_stat; + u_char char_dummy2; + u_char softint; + u_char char_dummy3; + u_char vmeint; + u_char char_dummy4; + u_char gp_reg1; + u_char char_dummy5; + u_char gp_reg2; + u_char char_dummy6; + u_char vme_mask; + u_char char_dummy7; + u_char vme_stat; +}; +#define tt_scu ((*(volatile struct TT_SCU *)TT_SCU_BAS)) + +/* TT real time clock */ + +#define TT_RTC_BAS (0xffff8961) +struct TT_RTC { + u_char regsel; + u_char dummy; + u_char data; +}; +#define tt_rtc ((*(volatile struct TT_RTC *)TT_RTC_BAS)) + + +/* +** ACIA 6850 + */ +/* constants for the ACIA registers */ + +/* baudrate selection and reset (Baudrte = clock/factor) */ +#define ACIA_DIV1 0 +#define ACIA_DIV16 1 +#define ACIA_DIV64 2 +#define ACIA_RESET 3 + +/* character format */ +#define ACIA_D7E2S (0<<2) /* 7 data, even parity, 2 stop */ +#define ACIA_D7O2S (1<<2) /* 7 data, odd parity, 2 stop */ +#define ACIA_D7E1S (2<<2) /* 7 data, even parity, 1 stop */ +#define ACIA_D7O1S (3<<2) /* 7 data, odd parity, 1 stop */ +#define ACIA_D8N2S (4<<2) /* 8 data, no parity, 2 stop */ +#define ACIA_D8N1S (5<<2) /* 8 data, no parity, 1 stop */ +#define ACIA_D8E1S (6<<2) /* 8 data, even parity, 1 stop */ +#define ACIA_D8O1S (7<<2) /* 8 data, odd parity, 1 stop */ + +/* transmit control */ +#define ACIA_RLTID (0<<5) /* RTS low, TxINT disabled */ +#define ACIA_RLTIE (1<<5) /* RTS low, TxINT enabled */ +#define ACIA_RHTID (2<<5) /* RTS high, TxINT disabled */ +#define ACIA_RLTIDSB (3<<5) /* RTS low, TxINT disabled, send break */ + +/* receive control */ +#define ACIA_RID (0<<7) /* RxINT disabled */ +#define ACIA_RIE (1<<7) /* RxINT enabled */ + +/* status fields of the ACIA */ +#define ACIA_RDRF 1 /* Receive Data Register Full */ +#define ACIA_TDRE (1<<1) /* Transmit Data Register Empty */ +#define ACIA_DCD (1<<2) /* Data Carrier Detect */ +#define ACIA_CTS (1<<3) /* Clear To Send */ +#define ACIA_FE (1<<4) /* Framing Error */ +#define ACIA_OVRN (1<<5) /* Receiver Overrun */ +#define ACIA_PE (1<<6) /* Parity Error */ +#define ACIA_IRQ (1<<7) /* Interrupt Request */ + +#define ACIA_BAS (0xfffffc00) +struct ACIA + { + u_char key_ctrl; + u_char char_dummy1; + u_char key_data; + u_char char_dummy2; + u_char mid_ctrl; + u_char char_dummy3; + u_char mid_data; + }; +# define acia ((*(volatile struct ACIA*)ACIA_BAS)) + +#define TT_DMASND_BAS (0xffff8900) +struct TT_DMASND { + u_char int_ctrl; /* Falcon: Interrupt control */ + u_char ctrl; + u_char pad2; + u_char bas_hi; + u_char pad3; + u_char bas_mid; + u_char pad4; + u_char bas_low; + u_char pad5; + u_char addr_hi; + u_char pad6; + u_char addr_mid; + u_char pad7; + u_char addr_low; + u_char pad8; + u_char end_hi; + u_char pad9; + u_char end_mid; + u_char pad10; + u_char end_low; + u_char pad11[12]; + u_char track_select; /* Falcon */ + u_char mode; + u_char pad12[14]; + /* Falcon only: */ + u_short cbar_src; + u_short cbar_dst; + u_char ext_div; + u_char int_div; + u_char rec_track_select; + u_char dac_src; + u_char adc_src; + u_char input_gain; + u_short output_atten; +}; +# define tt_dmasnd ((*(volatile struct TT_DMASND *)TT_DMASND_BAS)) + +#define DMASND_CTRL_OFF 0x00 +#define DMASND_CTRL_ON 0x01 +#define DMASND_CTRL_REPEAT 0x02 +#define DMASND_MODE_MONO 0x80 +#define DMASND_MODE_STEREO 0x00 +#define DMASND_MODE_8BIT 0x00 +#define DMASND_MODE_16BIT 0x40 /* Falcon only */ +#define DMASND_MODE_6KHZ 0x00 /* Falcon: mute */ +#define DMASND_MODE_12KHZ 0x01 +#define DMASND_MODE_25KHZ 0x02 +#define DMASND_MODE_50KHZ 0x03 + +#define DMASNDSetBase(bufstart) \ + do { \ + tt_dmasnd.bas_hi = (unsigned char)(((bufstart) & 0xff0000) >> 16); \ + tt_dmasnd.bas_mid = (unsigned char)(((bufstart) & 0x00ff00) >> 8); \ + tt_dmasnd.bas_low = (unsigned char) ((bufstart) & 0x0000ff); \ + } while( 0 ) + +#define DMASNDGetAdr() ((tt_dmasnd.addr_hi << 16) + \ + (tt_dmasnd.addr_mid << 8) + \ + (tt_dmasnd.addr_low)) + +#define DMASNDSetEnd(bufend) \ + do { \ + tt_dmasnd.end_hi = (unsigned char)(((bufend) & 0xff0000) >> 16); \ + tt_dmasnd.end_mid = (unsigned char)(((bufend) & 0x00ff00) >> 8); \ + tt_dmasnd.end_low = (unsigned char) ((bufend) & 0x0000ff); \ + } while( 0 ) + + +#define TT_MICROWIRE_BAS (0xffff8922) +struct TT_MICROWIRE { + u_short data; + u_short mask; +}; +# define tt_microwire ((*(volatile struct TT_MICROWIRE *)TT_MICROWIRE_BAS)) + +#define MW_LM1992_ADDR 0x0400 + +#define MW_LM1992_VOLUME(dB) \ + (0x0c0 | ((dB) < -80 ? 0 : (dB) > 0 ? 40 : (((dB) + 80) / 2))) +#define MW_LM1992_BALLEFT(dB) \ + (0x140 | ((dB) < -40 ? 0 : (dB) > 0 ? 20 : (((dB) + 40) / 2))) +#define MW_LM1992_BALRIGHT(dB) \ + (0x100 | ((dB) < -40 ? 0 : (dB) > 0 ? 20 : (((dB) + 40) / 2))) +#define MW_LM1992_TREBLE(dB) \ + (0x080 | ((dB) < -12 ? 0 : (dB) > 12 ? 12 : (((dB) / 2) + 6))) +#define MW_LM1992_BASS(dB) \ + (0x040 | ((dB) < -12 ? 0 : (dB) > 12 ? 12 : (((dB) / 2) + 6))) + +#define MW_LM1992_PSG_LOW 0x000 +#define MW_LM1992_PSG_HIGH 0x001 +#define MW_LM1992_PSG_OFF 0x002 + +#define MSTE_RTC_BAS (0xfffffc21) + +struct MSTE_RTC { + u_char sec_ones; + u_char dummy1; + u_char sec_tens; + u_char dummy2; + u_char min_ones; + u_char dummy3; + u_char min_tens; + u_char dummy4; + u_char hr_ones; + u_char dummy5; + u_char hr_tens; + u_char dummy6; + u_char weekday; + u_char dummy7; + u_char day_ones; + u_char dummy8; + u_char day_tens; + u_char dummy9; + u_char mon_ones; + u_char dummy10; + u_char mon_tens; + u_char dummy11; + u_char year_ones; + u_char dummy12; + u_char year_tens; + u_char dummy13; + u_char mode; + u_char dummy14; + u_char test; + u_char dummy15; + u_char reset; +}; + +#define mste_rtc ((*(volatile struct MSTE_RTC *)MSTE_RTC_BAS)) + +#endif /* linux/atarihw.h */ + diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/atariints.h linux/include/asm-m68k/atariints.h --- v1.3.93/linux/include/asm-m68k/atariints.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/atariints.h Mon Mar 4 22:47:32 1996 @@ -0,0 +1,220 @@ +/* +** atariints.h -- Atari Linux interrupt handling structs and prototypes +** +** Copyright 1994 by Bj”rn Brauel +** +** 5/2/94 Roman Hodek: +** TT interupt definitions added. +** +** 12/02/96: (Roman) +** Adapted to new int handling scheme (see ataints.c); revised numbering +** +** This file is subject to the terms and conditions of the GNU General Public +** License. See the file README.legal in the main directory of this archive +** for more details. +** +*/ + +#ifndef _LINUX_ATARIINTS_H_ +#define _LINUX_ATARIINTS_H_ + +#include +#include + +/* +** Atari Interrupt sources. +** +*/ + +#define STMFP_SOURCE_BASE 8 +#define TTMFP_SOURCE_BASE 24 +#define SCC_SOURCE_BASE 40 +#define VME_SOURCE_BASE 56 +#define VME_MAX_SOURCES 16 + +#define NUM_ATARI_SOURCES (VME_SOURCE_BASE+VME_MAX_SOURCES-STMFP_SOURCE_BASE) + +/* convert vector number to int source number */ +#define IRQ_VECTOR_TO_SOURCE(v) ((v) - ((v) < 0x20 ? 0x18 : (0x40-8))) + +/* convert irq_handler index to vector number */ +#define IRQ_SOURCE_TO_VECTOR(i) ((i) + ((i) < 8 ? 0x18 : (0x40-8))) + +/* interrupt service types */ +#define IRQ_TYPE_SLOW 0 +#define IRQ_TYPE_FAST 1 +#define IRQ_TYPE_PRIO 2 + +#define IRQ_SUPRIOUS (IRQ_MACHSPEC | 0) + +/* auto-vector interrupts */ +#define IRQ_AUTO_1 (IRQ_MACHSPEC | 1) +#define IRQ_AUTO_2 (IRQ_MACHSPEC | 2) +#define IRQ_AUTO_3 (IRQ_MACHSPEC | 3) +#define IRQ_AUTO_4 (IRQ_MACHSPEC | 4) +#define IRQ_AUTO_5 (IRQ_MACHSPEC | 5) +#define IRQ_AUTO_6 (IRQ_MACHSPEC | 6) +#define IRQ_AUTO_7 (IRQ_MACHSPEC | 7) + +/* ST-MFP interrupts */ +#define IRQ_MFP_BUSY (IRQ_MACHSPEC | 8) +#define IRQ_MFP_DCD (IRQ_MACHSPEC | 9) +#define IRQ_MFP_CTS (IRQ_MACHSPEC | 10) +#define IRQ_MFP_GPU (IRQ_MACHSPEC | 11) +#define IRQ_MFP_TIMD (IRQ_MACHSPEC | 12) +#define IRQ_MFP_TIMC (IRQ_MACHSPEC | 13) +#define IRQ_MFP_ACIA (IRQ_MACHSPEC | 14) +#define IRQ_MFP_FDC (IRQ_MACHSPEC | 15) +#define IRQ_MFP_ACSI IRQ_MFP_FDC +#define IRQ_MFP_FSCSI IRQ_MFP_FDC +#define IRQ_MFP_IDE IRQ_MFP_FDC +#define IRQ_MFP_TIMB (IRQ_MACHSPEC | 16) +#define IRQ_MFP_SERERR (IRQ_MACHSPEC | 17) +#define IRQ_MFP_SEREMPT (IRQ_MACHSPEC | 18) +#define IRQ_MFP_RECERR (IRQ_MACHSPEC | 19) +#define IRQ_MFP_RECFULL (IRQ_MACHSPEC | 20) +#define IRQ_MFP_TIMA (IRQ_MACHSPEC | 21) +#define IRQ_MFP_RI (IRQ_MACHSPEC | 22) +#define IRQ_MFP_MMD (IRQ_MACHSPEC | 23) + +/* TT-MFP interrupts */ +#define IRQ_TT_MFP_IO0 (IRQ_MACHSPEC | 24) +#define IRQ_TT_MFP_IO1 (IRQ_MACHSPEC | 25) +#define IRQ_TT_MFP_SCC (IRQ_MACHSPEC | 26) +#define IRQ_TT_MFP_RI (IRQ_MACHSPEC | 27) +#define IRQ_TT_MFP_TIMD (IRQ_MACHSPEC | 28) +#define IRQ_TT_MFP_TIMC (IRQ_MACHSPEC | 29) +#define IRQ_TT_MFP_DRVRDY (IRQ_MACHSPEC | 30) +#define IRQ_TT_MFP_SCSIDMA (IRQ_MACHSPEC | 31) +#define IRQ_TT_MFP_TIMB (IRQ_MACHSPEC | 32) +#define IRQ_TT_MFP_SERERR (IRQ_MACHSPEC | 33) +#define IRQ_TT_MFP_SEREMPT (IRQ_MACHSPEC | 34) +#define IRQ_TT_MFP_RECERR (IRQ_MACHSPEC | 35) +#define IRQ_TT_MFP_RECFULL (IRQ_MACHSPEC | 36) +#define IRQ_TT_MFP_TIMA (IRQ_MACHSPEC | 37) +#define IRQ_TT_MFP_RTC (IRQ_MACHSPEC | 38) +#define IRQ_TT_MFP_SCSI (IRQ_MACHSPEC | 39) + +/* SCC interrupts */ +#define IRQ_SCCB_TX (IRQ_MACHSPEC | 40) +#define IRQ_SCCB_STAT (IRQ_MACHSPEC | 42) +#define IRQ_SCCB_RX (IRQ_MACHSPEC | 44) +#define IRQ_SCCB_SPCOND (IRQ_MACHSPEC | 46) +#define IRQ_SCCA_TX (IRQ_MACHSPEC | 48) +#define IRQ_SCCA_STAT (IRQ_MACHSPEC | 50) +#define IRQ_SCCA_RX (IRQ_MACHSPEC | 52) +#define IRQ_SCCA_SPCOND (IRQ_MACHSPEC | 54) + + +#define INT_CLK 24576 /* CLK while int_clk =2.456MHz and divide = 100 */ +#define INT_TICKS 246 /* to make sched_time = 99.902... HZ */ + + +#define MFP_ENABLE 0 +#define MFP_PENDING 1 +#define MFP_SERVICE 2 +#define MFP_MASK 3 + +/* Utility functions for setting/clearing bits in the interrupt registers of + * the MFP. 'type' should be constant, if 'irq' is constant, too, code size is + * reduced. set_mfp_bit() is nonsense for PENDING and SERVICE registers. */ + +static inline int get_mfp_bit( unsigned irq, int type ) + +{ unsigned char mask, *reg; + + mask = 1 << (irq & 7); + reg = (unsigned char *)&mfp.int_en_a + type*4 + + ((irq & 8) >> 2) + (((irq-8) & 16) << 3); + return( *reg & mask ); +} + +static inline void set_mfp_bit( unsigned irq, int type ) + +{ unsigned char mask, *reg; + + mask = 1 << (irq & 7); + reg = (unsigned char *)&mfp.int_en_a + type*4 + + ((irq & 8) >> 2) + (((irq-8) & 16) << 3); + __asm__ __volatile__ ( "orb %0,%1" + : : "di" (mask), "m" (*reg) : "memory" ); +} + +static inline void clear_mfp_bit( unsigned irq, int type ) + +{ unsigned char mask, *reg; + + mask = ~(1 << (irq & 7)); + reg = (unsigned char *)&mfp.int_en_a + type*4 + + ((irq & 8) >> 2) + (((irq-8) & 16) << 3); + if (type == MFP_PENDING || type == MFP_SERVICE) + __asm__ __volatile__ ( "moveb %0,%1" + : : "di" (mask), "m" (*reg) : "memory" ); + else + __asm__ __volatile__ ( "andb %0,%1" + : : "di" (mask), "m" (*reg) : "memory" ); +} + +/* + * {en,dis}able_irq have the usual semantics of temporary blocking the + * interrupt, but not loosing requests that happen between disabling and + * enabling. This is done with the MFP mask registers. + */ + +static inline void atari_enable_irq( unsigned irq ) + +{ + irq &= ~IRQ_MACHSPEC; + if (irq < STMFP_SOURCE_BASE || irq >= SCC_SOURCE_BASE) return; + set_mfp_bit( irq, MFP_MASK ); +} + +static inline void atari_disable_irq( unsigned irq ) + +{ + irq &= ~IRQ_MACHSPEC; + if (irq < STMFP_SOURCE_BASE || irq >= SCC_SOURCE_BASE) return; + clear_mfp_bit( irq, MFP_MASK ); +} + +/* + * In opposite to {en,dis}able_irq, requests between turn{off,on}_irq are not + * "stored" + */ + +extern inline void atari_turnon_irq( unsigned irq ) + +{ + irq &= ~IRQ_MACHSPEC; + if (irq < STMFP_SOURCE_BASE || irq >= SCC_SOURCE_BASE) return; + set_mfp_bit( irq, MFP_ENABLE ); +} + +extern inline void atari_turnoff_irq( unsigned irq ) + +{ + irq &= ~IRQ_MACHSPEC; + if (irq < STMFP_SOURCE_BASE || irq >= SCC_SOURCE_BASE) return; + clear_mfp_bit( irq, MFP_ENABLE ); + clear_mfp_bit( irq, MFP_PENDING ); +} + +extern inline void atari_clear_pending_irq( unsigned irq ) + +{ + irq &= ~IRQ_MACHSPEC; + if (irq < STMFP_SOURCE_BASE || irq >= SCC_SOURCE_BASE) return; + clear_mfp_bit( irq, MFP_PENDING ); +} + +extern inline int atari_irq_pending( unsigned irq ) + +{ + irq &= ~IRQ_MACHSPEC; + if (irq < STMFP_SOURCE_BASE || irq >= SCC_SOURCE_BASE) return( 0 ); + return( get_mfp_bit( irq, MFP_PENDING ) ); +} + +unsigned long atari_register_vme_int( void ); + +#endif /* linux/atariints.h */ diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/atarikb.h linux/include/asm-m68k/atarikb.h --- v1.3.93/linux/include/asm-m68k/atarikb.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/atarikb.h Mon Mar 4 22:47:32 1996 @@ -0,0 +1,40 @@ +/* +** atarikb.h -- This header contains the prototypes of functions of +** the intelligent keyboard of the Atari needed by the +** mouse and joystick drivers. +** +** Copyright 1994 by Robert de Vries +** +** This file is subject to the terms and conditions of the GNU General Public +** License. See the file README.legal in the main directory of this archive +** for more details. +** +** Created: 20 Feb 1994 by Robert de Vries +*/ + +#ifndef _LINUX_ATARIKB_H +#define _LINUX_ATARIKB_H + +void ikbd_write(const char *, int); +void ikbd_mouse_button_action(int mode); +void ikbd_mouse_rel_pos(void); +void ikbd_mouse_abs_pos(int xmax, int ymax); +void ikbd_mouse_kbd_mode(int dx, int dy); +void ikbd_mouse_thresh(int x, int y); +void ikbd_mouse_scale(int x, int y); +void ikbd_mouse_pos_get(int *x, int *y); +void ikbd_mouse_pos_set(int x, int y); +void ikbd_mouse_y0_bot(void); +void ikbd_mouse_y0_top(void); +void ikbd_mouse_disable(void); +void ikbd_joystick_event_on(void); +void ikbd_joystick_event_off(void); +void ikbd_joystick_get_state(void); +void ikbd_joystick_disable(void); + +/* Hook for MIDI serial driver */ +extern void (*atari_MIDI_interrupt_hook) (void); +/* Hook for mouse driver */ +extern void (*atari_mouse_interrupt_hook) (char *); + +#endif /* _LINUX_ATARIKB_H */ diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/atomic.h linux/include/asm-m68k/atomic.h --- v1.3.93/linux/include/asm-m68k/atomic.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/atomic.h Fri Apr 5 19:33:18 1996 @@ -0,0 +1,63 @@ +#ifndef __ARCH_M68K_ATOMIC__ +#define __ARCH_M68K_ATOMIC__ + +/* + * Atomic operations that C can't guarantee us. Useful for + * resource counting etc.. + */ + +/* + * We do not have SMP m68k systems, so we don't have to deal with that. + */ + +/* + * Make sure gcc doesn't try to be clever and move things around + * on us. We need to use _exactly_ the address the user gave us, + * not some alias that contains the same information. + */ +#define __atomic_fool_gcc(x) (*(struct { int a[100]; } *)x) + +typedef int atomic_t; + +static __inline__ void atomic_add(atomic_t i, atomic_t *v) +{ + __asm__ __volatile__( + "addl %1,%0" + :"=m" (__atomic_fool_gcc(v)) + :"ir" (i), "m" (__atomic_fool_gcc(v))); +} + +static __inline__ void atomic_sub(atomic_t i, atomic_t *v) +{ + __asm__ __volatile__( + "subl %1,%0" + :"=m" (__atomic_fool_gcc(v)) + :"ir" (i), "m" (__atomic_fool_gcc(v))); +} + +static __inline__ void atomic_inc(atomic_t *v) +{ + __asm__ __volatile__( + "addql #1,%0" + :"=m" (__atomic_fool_gcc(v)) + :"m" (__atomic_fool_gcc(v))); +} + +static __inline__ void atomic_dec(atomic_t *v) +{ + __asm__ __volatile__( + "subql #1,%0" + :"=m" (__atomic_fool_gcc(v)) + :"m" (__atomic_fool_gcc(v))); +} + +static __inline__ int atomic_dec_and_test(atomic_t *v) +{ + __asm__ __volatile__( + "subql #1,%0" + :"=m" (__atomic_fool_gcc(v)) + :"m" (__atomic_fool_gcc(v))); + return (*v <= 0); +} + +#endif /* __ARCH_M68K_ATOMIC __ */ diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/bitops.h linux/include/asm-m68k/bitops.h --- v1.3.93/linux/include/asm-m68k/bitops.h Tue Nov 29 22:15:49 1994 +++ linux/include/asm-m68k/bitops.h Wed Mar 6 20:01:26 1996 @@ -11,10 +11,7 @@ /* * Require 68020 or better. * - * They don't use the standard m680x0 bit ordering. - * Instead, the use the standard m680x0 bitfield ordering. - * - * Thus, bit 0 is the MSB of addr; bit 32 is the MSB of (addr+1). + * They use the standard big-endian m680x0 bit ordering. */ extern __inline__ int set_bit(int nr,void * vaddr) @@ -22,7 +19,7 @@ char retval; __asm__ __volatile__ ("bfset %2@{%1:#1}; sne %0" - : "=d" (retval) : "d" (nr), "a" (vaddr)); + : "=d" (retval) : "d" (nr^31), "a" (vaddr)); return retval; } @@ -32,7 +29,7 @@ char retval; __asm__ __volatile__ ("bfclr %2@{%1:#1}; sne %0" - : "=d" (retval) : "d" (nr), "a" (vaddr)); + : "=d" (retval) : "d" (nr^31), "a" (vaddr)); return retval; } @@ -42,7 +39,7 @@ char retval; __asm__ __volatile__ ("bfchg %2@{%1:#1}; sne %0" - : "=d" (retval) : "d" (nr), "a" (vaddr)); + : "=d" (retval) : "d" (nr^31), "a" (vaddr)); return retval; } @@ -52,51 +49,52 @@ char retval; __asm__ __volatile__ ("bftst %2@{%1:#1}; sne %0" - : "=d" (retval) : "d" (nr), "a" (vaddr)); + : "=d" (retval) : "d" (nr^31), "a" (vaddr)); return retval; } -extern inline int find_first_zero_bit(void * vaddr, unsigned size) +extern __inline__ int find_first_zero_bit(void * vaddr, unsigned size) { - unsigned long res; - unsigned long *p; - unsigned long *addr = vaddr; + unsigned long *p = vaddr, *addr = vaddr; + unsigned long allones = ~0UL; + int res; + unsigned long num; if (!size) return 0; - __asm__ __volatile__ (" moveq #-1,d0\n\t" - "1:" - " cmpl %1@+,d0\n\t" - " bne 2f\n\t" - " subql #1,%0\n\t" - " bne 1b\n\t" - " bra 5f\n\t" - "2:" - " movel %1@-,d0\n\t" - " notl d0\n\t" - " bfffo d0{#0,#0},%0\n\t" - "5:" - : "=d" (res), "=a" (p) - : "0" ((size + 31) >> 5), "1" (addr) - : "d0"); - return ((p - addr) << 5) + res; + + while (*p++ == allones) + { + if (size <= 32) + return (p - addr) << 5; + size -= 32; + } + + num = ~*--p; + __asm__ __volatile__ ("bfffo %1{#0,#0},%0" + : "=d" (res) : "d" (num & -num)); + return ((p - addr) << 5) + (res ^ 31); } -static inline int find_next_zero_bit (void *vaddr, int size, +extern __inline__ int find_next_zero_bit (void *vaddr, int size, int offset) { unsigned long *addr = vaddr; unsigned long *p = addr + (offset >> 5); - int set = 0, bit = offset & 31, res; + int set = 0, bit = offset & 31UL, res; + + if (offset >= size) + return size; if (bit) { + unsigned long num = ~*p & (~0UL << bit); + /* Look for zero in first longword */ - __asm__("bfffo %1{#0,#0},%0" - : "=d" (set) - : "d" (~*p << bit)); - if (set < (32 - bit)) - return set + offset; + __asm__ __volatile__ ("bfffo %1{#0,#0},%0" + : "=d" (res) : "d" (num & -num)); + if (res < 32) + return (offset & ~31UL) + (res ^ 31); set = 32 - bit; p++; } @@ -109,12 +107,151 @@ * ffz = Find First Zero in word. Undefined if no zero exists, * so code should check against ~0UL first.. */ -extern inline unsigned long ffz(unsigned long word) +extern __inline__ unsigned long ffz(unsigned long word) { + int res; + __asm__ __volatile__ ("bfffo %1{#0,#0},%0" - : "=d" (word) - : "d" (~(word))); - return word; + : "=d" (res) : "d" (~word & -~word)); + return res ^ 31; +} + +/* Bitmap functions for the minix filesystem */ + +extern __inline__ int +minix_find_first_zero_bit (const void *vaddr, unsigned size) +{ + const unsigned short *p = vaddr, *addr = vaddr; + int res; + unsigned short num; + + if (!size) + return 0; + + while (*p++ == 0xffff) + { + if (size <= 16) + return (p - addr) << 4; + size -= 16; + } + + num = ~*--p; + __asm__ __volatile__ ("bfffo %1{#16,#16},%0" + : "=d" (res) : "d" (num & -num)); + return ((p - addr) << 4) + (res ^ 31); +} + +extern __inline__ int +minix_set_bit (int nr, void *vaddr) +{ + char retval; + + __asm__ __volatile__ ("bfset %2{%1:#1}; sne %0" + : "=d" (retval) : "d" (nr^15), "m" (*(char *)vaddr)); + + return retval; +} + +extern __inline__ int +minix_clear_bit (int nr, void *vaddr) +{ + char retval; + + __asm__ __volatile__ ("bfclr %2{%1:#1}; sne %0" + : "=d" (retval) : "d" (nr^15), "m" (*(char *) vaddr)); + + return retval; +} + +extern __inline__ int +minix_test_bit (int nr, const void *vaddr) +{ + char retval; + + __asm__ __volatile__ ("bftst %2{%1:#1}; sne %0" + : "=d" (retval) : "d" (nr^15), "m" (*(const char *) vaddr)); + + return retval; +} + +/* Bitmap functions for the ext2 filesystem. */ + +extern __inline__ int +ext2_set_bit (int nr, void *vaddr) +{ + char retval; + + __asm__ __volatile__ ("bfset %2{%1,#1}; sne %0" + : "=d" (retval) : "d" (nr^7), "m" (*(char *) vaddr)); + + return retval; +} + +extern __inline__ int +ext2_clear_bit (int nr, void *vaddr) +{ + char retval; + + __asm__ __volatile__ ("bfclr %2{%1,#1}; sne %0" + : "=d" (retval) : "d" (nr^7), "m" (*(char *) vaddr)); + + return retval; +} + +extern __inline__ int +ext2_test_bit (int nr, const void *vaddr) +{ + char retval; + + __asm__ __volatile__ ("bftst %2{%1,#1}; sne %0" + : "=d" (retval) : "d" (nr^7), "m" (*(const char *) vaddr)); + + return retval; +} + +extern __inline__ int +ext2_find_first_zero_bit (const void *vaddr, unsigned size) +{ + const unsigned long *p = vaddr, *addr = vaddr; + int res; + + if (!size) + return 0; + + while (*p++ == ~0UL) + { + if (size <= 32) + return (p - addr) << 5; + size -= 32; + } + + --p; + for (res = 0; res < 32; res++) + if (!ext2_test_bit (res, p)) + break; + return (p - addr) * 32 + res; +} + +extern __inline__ int +ext2_find_next_zero_bit (const void *vaddr, unsigned size, unsigned offset) +{ + const unsigned long *addr = vaddr; + const unsigned long *p = addr + (offset >> 5); + int bit = offset & 31UL, res; + + if (offset >= size) + return size; + + if (bit) { + /* Look for zero in first longword */ + for (res = bit; res < 32; res++) + if (!ext2_test_bit (res, p)) + return (p - addr) * 32 + res; + p++; + } + /* No zero yet, search remaining full bytes for a zero */ + res = ext2_find_first_zero_bit (p, size - 32 * (p - addr)); + return (p - addr) * 32 + res; } #endif /* _M68K_BITOPS_H */ diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/bootinfo.h linux/include/asm-m68k/bootinfo.h --- v1.3.93/linux/include/asm-m68k/bootinfo.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/bootinfo.h Tue Apr 9 00:13:55 1996 @@ -0,0 +1,237 @@ +/* +** asm/bootinfo.h -- Definition of the Linux/68K boot information structure +** +** Copyright 1992 by Greg Harp +** +** This file is subject to the terms and conditions of the GNU General Public +** License. See the file README.legal in the main directory of this archive +** for more details. +** +** Created 09/29/92 by Greg Harp +** +** 5/2/94 Roman Hodek: +** Added bi_atari part of the machine dependant union bi_un; for now it +** contains just a model field to distinguish between TT and Falcon. +*/ + +#ifndef BOOTINFO_H +#define BOOTINFO_H + +#ifndef __ASSEMBLY__ + +#include + +/* + * Amiga specific part of bootinfo structure. + */ + +#define NUM_AUTO 16 + +#define AMIGAHW_DECLARE(name) unsigned name : 1 +#define AMIGAHW_SET(name) (boot_info.bi_amiga.hw_present.name = 1) +#define AMIGAHW_PRESENT(name) (boot_info.bi_amiga.hw_present.name) + +struct bi_Amiga { + int model; /* Amiga Model (3000?) */ + int num_autocon; /* # of autoconfig devices found */ + struct ConfigDev autocon[NUM_AUTO]; /* up to 16 autoconfig devices */ + unsigned long chip_size; /* size of chip memory (bytes) */ + unsigned char vblank; /* VBLANK frequency */ + unsigned char psfreq; /* power supply frequency */ + unsigned long eclock; /* EClock frequency */ + unsigned long chipset; /* native chipset present */ + struct { + /* video hardware */ + AMIGAHW_DECLARE(AMI_VIDEO); /* Amiga Video */ + AMIGAHW_DECLARE(AMI_BLITTER); /* Amiga Blitter */ + AMIGAHW_DECLARE(AMBER_FF); /* Amber Flicker Fixer */ + /* sound hardware */ + AMIGAHW_DECLARE(AMI_AUDIO); /* Amiga Audio */ + /* disk storage interfaces */ + AMIGAHW_DECLARE(AMI_FLOPPY); /* Amiga Floppy */ + AMIGAHW_DECLARE(A3000_SCSI); /* SCSI (wd33c93, A3000 alike) */ + AMIGAHW_DECLARE(A4000_SCSI); /* SCSI (ncr53c710, A4000T alike) */ + AMIGAHW_DECLARE(A1200_IDE); /* IDE (A1200 alike) */ + AMIGAHW_DECLARE(A4000_IDE); /* IDE (A4000 alike) */ + AMIGAHW_DECLARE(CD_ROM); /* CD ROM drive */ + /* other I/O hardware */ + AMIGAHW_DECLARE(AMI_KEYBOARD); /* Amiga Keyboard */ + AMIGAHW_DECLARE(AMI_MOUSE); /* Amiga Mouse */ + AMIGAHW_DECLARE(AMI_SERIAL); /* Amiga Serial */ + AMIGAHW_DECLARE(AMI_PARALLEL); /* Amiga Parallel */ + /* real time clocks */ + AMIGAHW_DECLARE(A2000_CLK); /* Hardware Clock (A2000 alike) */ + AMIGAHW_DECLARE(A3000_CLK); /* Hardware Clock (A3000 alike) */ + /* supporting hardware */ + AMIGAHW_DECLARE(CHIP_RAM); /* Chip RAM */ + AMIGAHW_DECLARE(PAULA); /* Paula (8364) */ + AMIGAHW_DECLARE(DENISE); /* Denise (8362) */ + AMIGAHW_DECLARE(DENISE_HR); /* Denise (8373) */ + AMIGAHW_DECLARE(LISA); /* Lisa (8375) */ + AMIGAHW_DECLARE(AGNUS_PAL); /* Normal/Fat PAL Agnus (8367/8371) */ + AMIGAHW_DECLARE(AGNUS_NTSC); /* Normal/Fat NTSC Agnus (8361/8370) */ + AMIGAHW_DECLARE(AGNUS_HR_PAL); /* Fat Hires PAL Agnus (8372) */ + AMIGAHW_DECLARE(AGNUS_HR_NTSC); /* Fat Hires NTSC Agnus (8372) */ + AMIGAHW_DECLARE(ALICE_PAL); /* PAL Alice (8374) */ + AMIGAHW_DECLARE(ALICE_NTSC); /* NTSC Alice (8374) */ + AMIGAHW_DECLARE(MAGIC_REKICK); /* A3000 Magic Hard Rekick */ + AMIGAHW_DECLARE(ZORRO); /* Zorro AutoConfig */ + } hw_present; +}; + + +/* Atari specific part of bootinfo */ + +/* + * Define several Hardware-Chips for indication so that for the ATARI we do + * no longer decide whether it is a Falcon or other machine . It's just + * important what hardware the machine uses + */ + +/* ++roman 08/08/95: rewritten from ORing constants to a C bitfield */ + +#define ATARIHW_DECLARE(name) unsigned name : 1 +#define ATARIHW_SET(name) (boot_info.bi_atari.hw_present.name = 1) +#define ATARIHW_PRESENT(name) (boot_info.bi_atari.hw_present.name) + +struct bi_Atari { + struct { + /* video hardware */ + ATARIHW_DECLARE(STND_SHIFTER); /* ST-Shifter - no base low ! */ + ATARIHW_DECLARE(EXTD_SHIFTER); /* STe-Shifter - 24 bit adress */ + ATARIHW_DECLARE(TT_SHIFTER); /* TT-Shifter */ + ATARIHW_DECLARE(VIDEL_SHIFTER); /* Falcon-Shifter */ + /* sound hardware */ + ATARIHW_DECLARE(YM_2149); /* Yamaha YM 2149 */ + ATARIHW_DECLARE(PCM_8BIT); /* PCM-Sound in STe-ATARI */ + ATARIHW_DECLARE(CODEC); /* CODEC Sound (Falcon) */ + /* disk storage interfaces */ + ATARIHW_DECLARE(TT_SCSI); /* Directly mapped NCR5380 */ + ATARIHW_DECLARE(ST_SCSI); /* NCR5380 via ST-DMA (Falcon) */ + ATARIHW_DECLARE(ACSI); /* Standard ACSI like in STs */ + ATARIHW_DECLARE(IDE); /* IDE Interface */ + ATARIHW_DECLARE(FDCSPEED); /* 8/16 MHz switch for FDC */ + /* other I/O hardware */ + ATARIHW_DECLARE(ST_MFP); /* The ST-MFP (there should + be no Atari without + it... but who knows?) */ + ATARIHW_DECLARE(TT_MFP); /* 2nd MFP */ + ATARIHW_DECLARE(SCC); /* Serial Communications Contr. */ + ATARIHW_DECLARE(ST_ESCC); /* SCC Z83230 in an ST */ + ATARIHW_DECLARE(ANALOG_JOY); /* Paddle Interface for STe + and Falcon */ + ATARIHW_DECLARE(MICROWIRE); /* Microwire Interface */ + /* DMA */ + ATARIHW_DECLARE(STND_DMA); /* 24 Bit limited ST-DMA */ + ATARIHW_DECLARE(EXTD_DMA); /* 32 Bit ST-DMA */ + ATARIHW_DECLARE(SCSI_DMA); /* DMA for the NCR5380 */ + ATARIHW_DECLARE(SCC_DMA); /* DMA for the SCC */ + /* real time clocks */ + ATARIHW_DECLARE(TT_CLK); /* TT compatible clock chip */ + ATARIHW_DECLARE(MSTE_CLK); /* Mega ST(E) clock chip */ + /* supporting hardware */ + ATARIHW_DECLARE(SCU); /* System Control Unit */ + ATARIHW_DECLARE(BLITTER); /* Blitter */ + ATARIHW_DECLARE(VME); /* VME Bus */ + } hw_present; + unsigned long mch_cookie; /* _MCH cookie from TOS */ +}; + +/* mch_cookie values (upper word) */ +#define ATARI_MCH_ST 0 +#define ATARI_MCH_STE 1 +#define ATARI_MCH_TT 2 +#define ATARI_MCH_FALCON 3 + +/* + * CPU and FPU types + */ +#define CPU_68020 (1) +#define CPU_68030 (2) +#define CPU_68040 (4) +#define CPU_68060 (8) +#define CPU_MASK (31) +#define FPU_68881 (32) +#define FPU_68882 (64) +#define FPU_68040 (128) /* Internal FPU */ +#define FPU_68060 (256) /* Internal FPU */ + +struct mem_info { + unsigned long addr; /* physical address of memory chunk */ + unsigned long size; /* length of memory chunk (in bytes) */ +}; + +#define NUM_MEMINFO 4 + +#endif /* __ASSEMBLY__ */ + +#define MACH_AMIGA 1 +#define MACH_ATARI 2 +#define MACH_MAC 3 + +#ifndef __ASSEMBLY__ + +#define MACH_IS_AMIGA (boot_info.machtype == MACH_AMIGA) +#define MACH_IS_ATARI (boot_info.machtype == MACH_ATARI) + +#define CL_SIZE (256) + +struct bootinfo { + unsigned long machtype; /* machine type */ + unsigned long cputype; /* system CPU & FPU */ + struct mem_info memory[NUM_MEMINFO]; /* memory description */ + int num_memory; /* # of memory blocks found */ + unsigned long ramdisk_size; /* ramdisk size in 1024 byte blocks */ + unsigned long ramdisk_addr; /* address of the ram disk in mem */ + char command_line[CL_SIZE]; /* kernel command line parameters */ + union { + struct bi_Amiga bi_ami; /* Amiga specific information */ + struct bi_Atari bi_ata; /* Atari specific information */ + } bi_un; +}; +#define bi_amiga bi_un.bi_ami +#define bi_atari bi_un.bi_ata +#define bi_mac bi_un.bi_mac + +extern struct bootinfo + boot_info; + +#endif /* __ASSEMBLY__ */ + + +/* + * Stuff for bootinfo interface versioning + * + * At the start of kernel code, a 'struct bootversion' is located. bootstrap + * checks for a matching version of the interface before booting a kernel, to + * avoid user confusion if kernel and bootstrap don't work together :-) + * + * If incompatible changes are made to the bootinfo interface, the major + * number below should be stepped (and the minor reset to 0) for the + * appropriate machine. If a change is backward-compatible, the minor should + * be stepped. "Backwards-compatible" means that booting will work, but + * certain features may not. + */ + +#define BOOTINFOV_MAGIC 0x4249561A /* 'BIV^Z' */ +#define MK_BI_VERSION(major,minor) (((major)<<16)+(minor)) +#define BI_VERSION_MAJOR(v) (((v) >> 16) & 0xffff) +#define BI_VERSION_MINOR(v) ((v) & 0xffff) + +#ifndef __ASSEMBLY__ + +struct bootversion { + unsigned short branch; + unsigned long magic; + struct { + unsigned long machtype; + unsigned long version; + } machversions[0]; +}; + +#endif /* __ASSEMBLY__ */ + +#define AMIGA_BOOTI_VERSION MK_BI_VERSION( 1, 0 ) +#define ATARI_BOOTI_VERSION MK_BI_VERSION( 1, 0 ) + +#endif /* BOOTINFO_H */ diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/bugs.h linux/include/asm-m68k/bugs.h --- v1.3.93/linux/include/asm-m68k/bugs.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/bugs.h Wed Dec 27 22:46:49 1995 @@ -0,0 +1,16 @@ +/* + * include/asm-m68k/bugs.h + * + * Copyright (C) 1994 Linus Torvalds + */ + +/* + * This is included by init/main.c to check for architecture-dependent bugs. + * + * Needs: + * void check_bugs(void); + */ + +static void check_bugs(void) +{ +} diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/byteorder.h linux/include/asm-m68k/byteorder.h --- v1.3.93/linux/include/asm-m68k/byteorder.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/byteorder.h Sun Mar 31 01:09:52 1996 @@ -0,0 +1,14 @@ +#ifndef _M68K_BYTEORDER_H +#define _M68K_BYTEORDER_H + +#ifdef __KERNEL__ +#define __BIG_ENDIAN +#endif +#define __BIG_ENDIAN_BITFIELD + +#define ntohl(x) x +#define ntohs(x) x +#define htonl(x) x +#define htons(x) x + +#endif diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/checksum.h linux/include/asm-m68k/checksum.h --- v1.3.93/linux/include/asm-m68k/checksum.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/checksum.h Sat Apr 6 12:42:22 1996 @@ -0,0 +1,175 @@ +#ifndef _M68K_CHECKSUM_H +#define _M68K_CHECKSUM_H + +/* + * computes the checksum of a memory block at buff, length len, + * and adds in "sum" (32-bit) + * + * returns a 32-bit number suitable for feeding into itself + * or csum_tcpudp_magic + * + * this function must be called with even lengths, except + * for the last fragment, which may be odd + * + * it's best to have buff aligned on a 32-bit boundary + */ +unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum); + +/* + * the same as csum_partial_copy, but copies from src while it + * checksums + * + * here even more important to align src and dst on a 32-bit (or even + * better 64-bit) boundary + */ + +unsigned int csum_partial_copy(const char *src, char *dst, int len, int sum); + + +/* + * the same as csum_partial_copy, but copies from user space. + * + * here even more important to align src and dst on a 32-bit (or even + * better 64-bit) boundary + */ + +unsigned int csum_partial_copy_fromuser(const char *src, char *dst, int len, int sum); + + +/* + * This is a version of ip_compute_csum() optimized for IP headers, + * which always checksum on 4 octet boundaries. + * + */ +static inline unsigned short +ip_fast_csum(unsigned char *iph, unsigned int ihl) +{ + unsigned int sum = 0; + + __asm__ ("subqw #1,%2\n" + "1:\t" + "movel %1@+,%/d0\n\t" + "addxl %/d0,%0\n\t" + "dbra %2,1b\n\t" + "movel %0,%/d0\n\t" + "swap %/d0\n\t" + "addxw %/d0,%0\n\t" + "clrw %/d0\n\t" + "addxw %/d0,%0\n\t" + : "=d" (sum), "=a" (iph), "=d" (ihl) + : "0" (sum), "1" (iph), "2" (ihl) + : "d0"); + return ~sum; +} + + + +/* + * computes the checksum of the TCP/UDP pseudo-header + * returns a 16-bit checksum, already complemented + */ + +static inline unsigned short int +csum_tcpudp_magic(unsigned long saddr, unsigned long daddr, unsigned short len, + unsigned short proto, unsigned int sum) +{ + __asm__ ("addl %1,%0\n\t" + "addxl %4,%0\n\t" + "addxl %5,%0\n\t" + "movl %0,%1\n\t" + "swap %1\n\t" + "addxw %1,%0\n\t" + "clrw %1\n\t" + "addxw %1,%0\n\t" + : "=&d" (sum), "=&d" (saddr) + : "0" (daddr), "1" (saddr), "d" (len + proto), + "d"(sum)); + return ~sum; +} + +/* + * Fold a partial checksum without adding pseudo headers + */ + +static inline unsigned int csum_fold(unsigned int sum) +{ + unsigned int tmp = sum; + __asm__("swap %1\n\t" + "addw %1, %0\n\t" + "clrw %1\n\t" + "addxw %1, %0" + : "=&d" (sum), "=&d" (tmp) + : "0" (sum), "1" (sum)); + return ~sum; +} + +/* + * this routine is used for miscellaneous IP-like checksums, mainly + * in icmp.c + */ + +#if 1 +static inline unsigned short +ip_compute_csum(unsigned char * buff, int len) +{ + unsigned int sum; + unsigned int scratch; + + __asm__("movel %0,%1\n\t" + "swap %1\n\t" + "addw %1,%0\n\t" + "clrw %1\n\t" + "addxw %1,%0\n\t" + : "=d" (sum), "=d" (scratch) + : "0" (csum_partial(buff, len, 0))); + return ~sum; +} +#else +static inline unsigned short +ip_compute_csum(unsigned char * buff, int len) +{ + unsigned long sum = 0; + + /* Do the first multiple of 4 bytes and convert to 16 bits. */ + if (len > 3) + { + int dummy; + __asm__ ("subql #1,%2\n\t" + "1:\t" + "movel %1@+,%/d0\n\t" + "addxl %/d0,%0\n\t" + "dbra %2,1b\n\t" + "movel %0,%/d0\n\t" + "swap %/d0\n\t" + "addxw %/d0,%0\n\t" + "clrw %/d0\n\t" + "addxw %/d0,%0" + : "=d" (sum), "=a" (buff), "=d" (dummy) + : "0" (sum), "1" (buff), "2" (len >> 2) + : "d0"); + } + if (len & 2) + { + __asm__ ("addw %1@+,%0\n\t" + "addxw %2,%0" + : "=d" (sum), "=a" (buff) + : "d" (0), "0" (sum), "1" (buff)); + } + if (len & 1) + { + __asm__ ("movew %1@,%/d0\n\t" + "clrb %/d0\n\t" + "addw %/d0,%0\n\t" + "clrw %/d0\n\t" + "addxw %/d0,%0" + : "=d" (sum) + : "a" (buff), "0" (sum) + : "d0"); + } + + sum =~sum; + return(sum & 0xffff); +} +#endif + +#endif /* _M68K_CHECKSUM_H */ diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/delay.h linux/include/asm-m68k/delay.h --- v1.3.93/linux/include/asm-m68k/delay.h Mon Nov 28 20:41:29 1994 +++ linux/include/asm-m68k/delay.h Sat Feb 24 19:42:43 1996 @@ -9,16 +9,13 @@ extern __inline__ void __delay(int loops) { - __asm__("\n\tmovel %0,d0\n1:\tsubql #1,d0\n\tbpls 1b\n" + __asm__("\n\tmovel %0,%/d0\n1:\tsubql #1,%/d0\n\tbpls 1b\n" : /* no outputs */ : "g" (loops) : "d0"); } /* - * division by multiplication: you don't have to worry about - * loss of precision. - * * Use only for very small delays ( < 1 msec). Should probably use a * lookup table, really, as the multiplications take much too long with * short delays. This is a "reasonable" implementation, though (and the @@ -27,14 +24,24 @@ */ extern __inline__ void udelay(unsigned long usecs) { - asm ("mulul %1,d0,%0\n\t" - "divul %2,d0,%0" + usecs *= 0x000010c6; /* 2**32 / 1000000 */ + + asm ("mulul %1,%0:%2" : "=d" (usecs) : "d" (usecs), - "i" (1000000), - "0" (loops_per_sec) - : "d0"); + "d" (loops_per_sec)); __delay(usecs); +} + +extern __inline__ unsigned long muldiv(unsigned long a, unsigned long b, unsigned long c) +{ + __asm__("mulul %1,%/d0:%0\n\tdivul %2,%/d0:%0" + :"=d" (a) + :"d" (b), + "d" (c), + "0" (a) + :"d0"); + return a; } #endif /* defined(_M68K_DELAY_H) */ diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/dma.h linux/include/asm-m68k/dma.h --- v1.3.93/linux/include/asm-m68k/dma.h Mon Nov 28 21:44:45 1994 +++ linux/include/asm-m68k/dma.h Sat Apr 13 14:31:08 1996 @@ -1,6 +1,12 @@ #ifndef _M68K_DMA_H #define _M68K_DMA_H 1 -/* dummy for m68k */ +/* Don't define MAX_DMA_ADDRESS; it's useless on the m68k and any + occurence should be flagged as an error. */ + +#define MAX_DMA_CHANNELS 8 + +extern int request_dma(unsigned int dmanr, const char * device_id); /* reserve a DMA channel */ +extern void free_dma(unsigned int dmanr); /* release it again */ #endif /* _M68K_DMA_H */ diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/elf.h linux/include/asm-m68k/elf.h --- v1.3.93/linux/include/asm-m68k/elf.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/elf.h Tue Mar 12 21:25:20 1996 @@ -0,0 +1,22 @@ +#ifndef __ASMm68k_ELF_H +#define __ASMm68k_ELF_H + +/* + * ELF register definitions.. + */ + +#include + +typedef unsigned long elf_greg_t; + +#define ELF_NGREG 20 /* d1-d7/a0-a6/d0/usp/orig_d0/sr/pc/fmtvec */ +typedef elf_greg_t elf_gregset_t[ELF_NGREG]; + +/* XXX temporary */ +/* +typedef unsigned long elf_fpregset_t; +*/ + +typedef struct user_m68kfp_struct elf_fpregset_t; + +#endif diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/errno.h linux/include/asm-m68k/errno.h --- v1.3.93/linux/include/asm-m68k/errno.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/errno.h Wed Dec 27 22:46:55 1995 @@ -0,0 +1,127 @@ +#ifndef _M68K_ERRNO_H +#define _M68K_ERRNO_H + +#define EPERM 1 /* Operation not permitted */ +#define ENOENT 2 /* No such file or directory */ +#define ESRCH 3 /* No such process */ +#define EINTR 4 /* Interrupted system call */ +#define EIO 5 /* I/O error */ +#define ENXIO 6 /* No such device or address */ +#define E2BIG 7 /* Arg list too long */ +#define ENOEXEC 8 /* Exec format error */ +#define EBADF 9 /* Bad file number */ +#define ECHILD 10 /* No child processes */ +#define EAGAIN 11 /* Try again */ +#define ENOMEM 12 /* Out of memory */ +#define EACCES 13 /* Permission denied */ +#define EFAULT 14 /* Bad address */ +#define ENOTBLK 15 /* Block device required */ +#define EBUSY 16 /* Device or resource busy */ +#define EEXIST 17 /* File exists */ +#define EXDEV 18 /* Cross-device link */ +#define ENODEV 19 /* No such device */ +#define ENOTDIR 20 /* Not a directory */ +#define EISDIR 21 /* Is a directory */ +#define EINVAL 22 /* Invalid argument */ +#define ENFILE 23 /* File table overflow */ +#define EMFILE 24 /* Too many open files */ +#define ENOTTY 25 /* Not a typewriter */ +#define ETXTBSY 26 /* Text file busy */ +#define EFBIG 27 /* File too large */ +#define ENOSPC 28 /* No space left on device */ +#define ESPIPE 29 /* Illegal seek */ +#define EROFS 30 /* Read-only file system */ +#define EMLINK 31 /* Too many links */ +#define EPIPE 32 /* Broken pipe */ +#define EDOM 33 /* Math argument out of domain of func */ +#define ERANGE 34 /* Math result not representable */ +#define EDEADLK 35 /* Resource deadlock would occur */ +#define ENAMETOOLONG 36 /* File name too long */ +#define ENOLCK 37 /* No record locks available */ +#define ENOSYS 38 /* Function not implemented */ +#define ENOTEMPTY 39 /* Directory not empty */ +#define ELOOP 40 /* Too many symbolic links encountered */ +#define EWOULDBLOCK EAGAIN /* Operation would block */ +#define ENOMSG 42 /* No message of desired type */ +#define EIDRM 43 /* Identifier removed */ +#define ECHRNG 44 /* Channel number out of range */ +#define EL2NSYNC 45 /* Level 2 not synchronized */ +#define EL3HLT 46 /* Level 3 halted */ +#define EL3RST 47 /* Level 3 reset */ +#define ELNRNG 48 /* Link number out of range */ +#define EUNATCH 49 /* Protocol driver not attached */ +#define ENOCSI 50 /* No CSI structure available */ +#define EL2HLT 51 /* Level 2 halted */ +#define EBADE 52 /* Invalid exchange */ +#define EBADR 53 /* Invalid request descriptor */ +#define EXFULL 54 /* Exchange full */ +#define ENOANO 55 /* No anode */ +#define EBADRQC 56 /* Invalid request code */ +#define EBADSLT 57 /* Invalid slot */ +#define EDEADLOCK 58 /* File locking deadlock error */ +#define EBFONT 59 /* Bad font file format */ +#define ENOSTR 60 /* Device not a stream */ +#define ENODATA 61 /* No data available */ +#define ETIME 62 /* Timer expired */ +#define ENOSR 63 /* Out of streams resources */ +#define ENONET 64 /* Machine is not on the network */ +#define ENOPKG 65 /* Package not installed */ +#define EREMOTE 66 /* Object is remote */ +#define ENOLINK 67 /* Link has been severed */ +#define EADV 68 /* Advertise error */ +#define ESRMNT 69 /* Srmount error */ +#define ECOMM 70 /* Communication error on send */ +#define EPROTO 71 /* Protocol error */ +#define EMULTIHOP 72 /* Multihop attempted */ +#define EDOTDOT 73 /* RFS specific error */ +#define EBADMSG 74 /* Not a data message */ +#define EOVERFLOW 75 /* Value too large for defined data type */ +#define ENOTUNIQ 76 /* Name not unique on network */ +#define EBADFD 77 /* File descriptor in bad state */ +#define EREMCHG 78 /* Remote address changed */ +#define ELIBACC 79 /* Can not access a needed shared library */ +#define ELIBBAD 80 /* Accessing a corrupted shared library */ +#define ELIBSCN 81 /* .lib section in a.out corrupted */ +#define ELIBMAX 82 /* Attempting to link in too many shared libraries */ +#define ELIBEXEC 83 /* Cannot exec a shared library directly */ +#define EILSEQ 84 /* Illegal byte sequence */ +#define ERESTART 85 /* Interrupted system call should be restarted */ +#define ESTRPIPE 86 /* Streams pipe error */ +#define EUSERS 87 /* Too many users */ +#define ENOTSOCK 88 /* Socket operation on non-socket */ +#define EDESTADDRREQ 89 /* Destination address required */ +#define EMSGSIZE 90 /* Message too long */ +#define EPROTOTYPE 91 /* Protocol wrong type for socket */ +#define ENOPROTOOPT 92 /* Protocol not available */ +#define EPROTONOSUPPORT 93 /* Protocol not supported */ +#define ESOCKTNOSUPPORT 94 /* Socket type not supported */ +#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */ +#define EPFNOSUPPORT 96 /* Protocol family not supported */ +#define EAFNOSUPPORT 97 /* Address family not supported by protocol */ +#define EADDRINUSE 98 /* Address already in use */ +#define EADDRNOTAVAIL 99 /* Cannot assign requested address */ +#define ENETDOWN 100 /* Network is down */ +#define ENETUNREACH 101 /* Network is unreachable */ +#define ENETRESET 102 /* Network dropped connection because of reset */ +#define ECONNABORTED 103 /* Software caused connection abort */ +#define ECONNRESET 104 /* Connection reset by peer */ +#define ENOBUFS 105 /* No buffer space available */ +#define EISCONN 106 /* Transport endpoint is already connected */ +#define ENOTCONN 107 /* Transport endpoint is not connected */ +#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */ +#define ETOOMANYREFS 109 /* Too many references: cannot splice */ +#define ETIMEDOUT 110 /* Connection timed out */ +#define ECONNREFUSED 111 /* Connection refused */ +#define EHOSTDOWN 112 /* Host is down */ +#define EHOSTUNREACH 113 /* No route to host */ +#define EALREADY 114 /* Operation already in progress */ +#define EINPROGRESS 115 /* Operation now in progress */ +#define ESTALE 116 /* Stale NFS file handle */ +#define EUCLEAN 117 /* Structure needs cleaning */ +#define ENOTNAM 118 /* Not a XENIX named type file */ +#define ENAVAIL 119 /* No XENIX semaphores available */ +#define EISNAM 120 /* Is a named type file */ +#define EREMOTEIO 121 /* Remote I/O error */ +#define EDQUOT 122 /* Quota exceeded */ + +#endif /* _M68K_ERRNO_H */ diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/fcntl.h linux/include/asm-m68k/fcntl.h --- v1.3.93/linux/include/asm-m68k/fcntl.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/fcntl.h Wed Dec 27 22:46:55 1995 @@ -0,0 +1,64 @@ +#ifndef _M68K_FCNTL_H +#define _M68K_FCNTL_H + +/* open/fcntl - O_SYNC is only implemented on blocks devices and on files + located on an ext2 file system */ +#define O_ACCMODE 0003 +#define O_RDONLY 00 +#define O_WRONLY 01 +#define O_RDWR 02 +#define O_CREAT 0100 /* not fcntl */ +#define O_EXCL 0200 /* not fcntl */ +#define O_NOCTTY 0400 /* not fcntl */ +#define O_TRUNC 01000 /* not fcntl */ +#define O_APPEND 02000 +#define O_NONBLOCK 04000 +#define O_NDELAY O_NONBLOCK +#define O_SYNC 010000 +#define FASYNC 020000 /* fcntl, for BSD compatibility */ + +#define F_DUPFD 0 /* dup */ +#define F_GETFD 1 /* get f_flags */ +#define F_SETFD 2 /* set f_flags */ +#define F_GETFL 3 /* more flags (cloexec) */ +#define F_SETFL 4 +#define F_GETLK 5 +#define F_SETLK 6 +#define F_SETLKW 7 + +#define F_SETOWN 8 /* for sockets. */ +#define F_GETOWN 9 /* for sockets. */ + +/* for F_[GET|SET]FL */ +#define FD_CLOEXEC 1 /* actually anything with low bit set goes */ + +/* for posix fcntl() and lockf() */ +#define F_RDLCK 0 +#define F_WRLCK 1 +#define F_UNLCK 2 + +/* for old implementation of bsd flock () */ +#define F_EXLCK 4 /* or 3 */ +#define F_SHLCK 8 /* or 4 */ + +/* operations for bsd flock(), also used by the kernel implementation */ +#define LOCK_SH 1 /* shared lock */ +#define LOCK_EX 2 /* exclusive lock */ +#define LOCK_NB 4 /* or'd with one of the above to prevent + blocking */ +#define LOCK_UN 8 /* remove lock */ + +#ifdef __KERNEL__ +#define F_POSIX 1 +#define F_FLOCK 2 +#endif /* __KERNEL__ */ + +struct flock { + short l_type; + short l_whence; + off_t l_start; + off_t l_len; + pid_t l_pid; +}; + +#endif /* _M68K_FCNTL_H */ diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/font.h linux/include/asm-m68k/font.h --- v1.3.93/linux/include/asm-m68k/font.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/font.h Mon Apr 1 21:11:19 1996 @@ -0,0 +1,32 @@ +/* + * asm-m68k/font.h -- `Soft' font definitions + * + * Created 1995 by Geert Uytterhoeven + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file README.legal in the main directory of this archive + * for more details. + */ + +#ifndef _ASM_M68K_FONT_H_ +#define _ASM_M68K_FONT_H_ + +#include + + + /* + * Find a font with a specific name + */ + +extern int findsoftfont(char *name, int *width, int *heigth, u_char *data[]); + + + /* + * Get the default font for a specific screen size + */ + +extern void getdefaultfont(int xres, int yres, char *name[], int *width, + int *height, u_char *data[]); + + +#endif /* _ASM_M68K_FONT_H_ */ diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/ide.h linux/include/asm-m68k/ide.h --- v1.3.93/linux/include/asm-m68k/ide.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/ide.h Tue Apr 9 00:13:55 1996 @@ -0,0 +1,221 @@ +#ifndef _M68K_IDE_H +#define _M68K_IDE_H + +/* Copyright(c) 1996 Kars de Jong */ +/* Based on the ide driver from 1.2.13pl8 */ + +#include + +#ifdef CONFIG_AMIGA +#include +#include +#include +#endif /* CONFIG_AMIGA */ + +#ifdef CONFIG_ATARI +#include +#include +#include +#include +#endif /* CONFIG_ATARI */ + +#include + +struct hd_regs_struct { + unsigned int hd_error, + hd_nsector, + hd_sector, + hd_lcyl, + hd_hcyl, + hd_select, + hd_status; +}; + +static struct hd_regs_struct hd_regs; +static void probe_m68k_ide (void); + +/* Undefine these again, they were defined for the PC. */ +#undef IDE_ERROR_OFFSET +#undef IDE_NSECTOR_OFFSET +#undef IDE_SECTOR_OFFSET +#undef IDE_LCYL_OFFSET +#undef IDE_HCYL_OFFSET +#undef IDE_SELECT_OFFSET +#undef IDE_STATUS_OFFSET +#undef IDE_FEATURE_OFFSET +#undef IDE_COMMAND_OFFSET +#undef SELECT_DRIVE + +#define IDE_ERROR_OFFSET hd_regs.hd_error +#define IDE_NSECTOR_OFFSET hd_regs.hd_nsector +#define IDE_SECTOR_OFFSET hd_regs.hd_sector +#define IDE_LCYL_OFFSET hd_regs.hd_lcyl +#define IDE_HCYL_OFFSET hd_regs.hd_hcyl +#define IDE_SELECT_OFFSET hd_regs.hd_select +#define IDE_STATUS_OFFSET hd_regs.hd_status +#define IDE_FEATURE_OFFSET IDE_ERROR_OFFSET +#define IDE_COMMAND_OFFSET IDE_STATUS_OFFSET + +#undef SUPPORT_VLB_SYNC +#define SUPPORT_VLB_SYNC 0 + +#undef HD_DATA +#define HD_DATA NULL + +#define SELECT_DRIVE(hwif,drive) OUT_BYTE((drive)->select.all, hwif->io_base+IDE_SELECT_OFFSET); + +#define insl(data_reg, buffer, wcount) insw(data_reg, buffer, wcount<<1) +#define outsl(data_reg, buffer, wcount) outsw(data_reg, buffer, wcount<<1) + +#define insw(port, buf, nr) \ + if (nr % 16) \ + __asm__ __volatile__ \ + ("movel %0,%/a0; \ + movel %1,%/a1; \ + movel %2,%/d6; \ + subql #1,%/d6; \ + 1:movew %/a0@,%/a1@+; \ + dbra %/d6,1b" : \ + : "g" (port), "g" (buf), "g" (nr) \ + : "a0", "a1", "d6"); \ + else \ + __asm__ __volatile__ \ + ("movel %0,%/a0; \ + movel %1,%/a1; \ + movel %2,%/d6; \ + lsrl #4,%/d6; \ + subql #1,%/d6; \ + 1:movew %/a0@,%/a1@+; \ + movew %/a0@,%/a1@+; \ + movew %/a0@,%/a1@+; \ + movew %/a0@,%/a1@+; \ + movew %/a0@,%/a1@+; \ + movew %/a0@,%/a1@+; \ + movew %/a0@,%/a1@+; \ + movew %/a0@,%/a1@+; \ + movew %/a0@,%/a1@+; \ + movew %/a0@,%/a1@+; \ + movew %/a0@,%/a1@+; \ + movew %/a0@,%/a1@+; \ + movew %/a0@,%/a1@+; \ + movew %/a0@,%/a1@+; \ + movew %/a0@,%/a1@+; \ + movew %/a0@,%/a1@+; \ + dbra %/d6,1b" : \ + : "g" (port), "g" (buf), "g" (nr) \ + : "a0", "a1", "d6"); + +#define outsw(port, buf, nr) \ + if (nr % 16) \ + __asm__ __volatile__ \ + ("movel %0,%/a0; \ + movel %1,%/a1; \ + movel %2,%/d6; \ + subql #1,%/d6; \ + 1:movew %/a1@+,%/a0@; \ + dbra %/d6,1b" : \ + : "g" (port), "g" (buf), "g" (nr) \ + : "a0", "a1", "d6"); \ + else \ + __asm__ __volatile__ \ + ("movel %0,%/a0; \ + movel %1,%/a1; \ + movel %2,%/d6; \ + lsrl #4,%/d6; \ + subql #1,%/d6; \ + 1:movew %/a1@+,%/a0@; \ + movew %/a1@+,%/a0@; \ + movew %/a1@+,%/a0@; \ + movew %/a1@+,%/a0@; \ + movew %/a1@+,%/a0@; \ + movew %/a1@+,%/a0@; \ + movew %/a1@+,%/a0@; \ + movew %/a1@+,%/a0@; \ + movew %/a1@+,%/a0@; \ + movew %/a1@+,%/a0@; \ + movew %/a1@+,%/a0@; \ + movew %/a1@+,%/a0@; \ + movew %/a1@+,%/a0@; \ + movew %/a1@+,%/a0@; \ + movew %/a1@+,%/a0@; \ + movew %/a1@+,%/a0@; \ + dbra %/d6,1b" : \ + : "g" (port), "g" (buf), "g" (nr) \ + : "a0", "a1", "d6"); + +#define T_CHAR (0x0000) /* char: don't touch */ +#define T_SHORT (0x4000) /* short: 12 -> 21 */ +#define T_INT (0x8000) /* int: 1234 -> 4321 */ +#define T_TEXT (0xc000) /* text: 12 -> 21 */ + +#define T_MASK_TYPE (0xc000) +#define T_MASK_COUNT (0x3fff) + +#define D_CHAR(cnt) (T_CHAR | (cnt)) +#define D_SHORT(cnt) (T_SHORT | (cnt)) +#define D_INT(cnt) (T_INT | (cnt)) +#define D_TEXT(cnt) (T_TEXT | (cnt)) + +static u_short driveid_types[] = { + D_SHORT(10), /* config - vendor2 */ + D_TEXT(20), /* serial_no */ + D_SHORT(3), /* buf_type - ecc_bytes */ + D_TEXT(48), /* fw_rev - model */ + D_CHAR(2), /* max_multsect - vendor3 */ + D_SHORT(1), /* dword_io */ + D_CHAR(2), /* vendor4 - capability */ + D_SHORT(1), /* reserved50 */ + D_CHAR(4), /* vendor5 - tDMA */ + D_SHORT(4), /* field_valid - cur_sectors */ + D_INT(1), /* cur_capacity */ + D_CHAR(2), /* multsect - multsect_valid */ + D_INT(1), /* lba_capacity */ + D_SHORT(194) /* dma_1word - reservedyy */ +}; + +#define num_driveid_types (sizeof(driveid_types)/sizeof(*driveid_types)) + +static __inline__ void big_endianize_driveid(struct hd_driveid *id) +{ + u_char *p = (u_char *)id; + int i, j, cnt; + u_char t; + + for (i = 0; i < num_driveid_types; i++) { + cnt = driveid_types[i] & T_MASK_COUNT; + switch (driveid_types[i] & T_MASK_TYPE) { + case T_CHAR: + p += cnt; + break; + case T_SHORT: + for (j = 0; j < cnt; j++) { + t = p[0]; + p[0] = p[1]; + p[1] = t; + p += 2; + } + break; + case T_INT: + for (j = 0; j < cnt; j++) { + t = p[0]; + p[0] = p[3]; + p[3] = t; + t = p[1]; + p[1] = p[2]; + p[2] = t; + p += 4; + } + break; + case T_TEXT: + for (j = 0; j < cnt; j += 2) { + t = p[0]; + p[0] = p[1]; + p[1] = t; + p += 2; + } + break; + } + } +} + +#endif /* _M68K_IDE_H */ diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/io.h linux/include/asm-m68k/io.h --- v1.3.93/linux/include/asm-m68k/io.h Mon Nov 28 20:59:32 1994 +++ linux/include/asm-m68k/io.h Wed Dec 27 22:46:55 1995 @@ -5,7 +5,7 @@ { register unsigned char _v; - __asm__ __volatile__ ("moveb %1,%0":"=r" (_v):"m" (*addr)); + __asm__ __volatile__ ("moveb %1,%0":"=dm" (_v):"m" (*addr)); return _v; } #define inb_p(addr) get_user_byte_io((char *)(addr)) @@ -15,10 +15,36 @@ { __asm__ __volatile__ ("moveb %0,%1" : /* no outputs */ - :"r" (val),"m" (*addr) + :"idm" (val),"m" (*addr) : "memory"); } #define outb_p(x,addr) put_user_byte_io((x),(char *)(addr)) #define outb(x,addr) put_user_byte_io((x),(char *)(addr)) + +/* + * Change virtual addresses to physical addresses and vv. + * These are trivial on the 1:1 Linux/i386 mapping (but if we ever + * make the kernel segment mapped at 0, we need to do translation + * on the i386 as well) + */ +extern unsigned long mm_vtop(unsigned long addr); +extern unsigned long mm_ptov(unsigned long addr); + +extern inline unsigned long virt_to_phys(volatile void * address) +{ + return (unsigned long) mm_vtop((unsigned long)address); +} + +extern inline void * phys_to_virt(unsigned long address) +{ + return (void *) mm_ptov(address); +} + +/* + * IO bus memory addresses are also 1:1 with the physical address + */ +#define virt_to_bus virt_to_phys +#define bus_to_virt phys_to_virt + #endif /* _M68K_IO_H */ diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/ioctl.h linux/include/asm-m68k/ioctl.h --- v1.3.93/linux/include/asm-m68k/ioctl.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/ioctl.h Sat Mar 23 14:31:14 1996 @@ -0,0 +1,80 @@ +/* $Id: ioctl.h,v 1.4 1996/03/23 12:31:12 root Exp root $ + * + * linux/ioctl.h for Linux by H.H. Bergman. + */ + +#ifndef _M68K_IOCTL_H +#define _M68K_IOCTL_H + +/* ioctl command encoding: 32 bits total, command in lower 16 bits, + * size of the parameter structure in the lower 14 bits of the + * upper 16 bits. + * Encoding the size of the parameter structure in the ioctl request + * is useful for catching programs compiled with old versions + * and to avoid overwriting user space outside the user buffer area. + * The highest 2 bits are reserved for indicating the ``access mode''. + * NOTE: This limits the max parameter size to 16kB -1 ! + */ + +/* + * I don't really have any idea about what this should look like, so + * for the time being, this is heavily based on the PC definitions. + */ + +/* + * The following is for compatibility across the various Linux + * platforms. The i386 ioctl numbering scheme doesn't really enforce + * a type field. De facto, however, the top 8 bits of the lower 16 + * bits are indeed used as a type field, so we might just as well make + * this explicit here. Please be sure to use the decoding macros + * below from now on. + */ +#define _IOC_NRBITS 8 +#define _IOC_TYPEBITS 8 +#define _IOC_SIZEBITS 14 +#define _IOC_DIRBITS 2 + +#define _IOC_NRMASK ((1 << _IOC_NRBITS)-1) +#define _IOC_TYPEMASK ((1 << _IOC_TYPEBITS)-1) +#define _IOC_SIZEMASK ((1 << _IOC_SIZEBITS)-1) +#define _IOC_DIRMASK ((1 << _IOC_DIRBITS)-1) + +#define _IOC_NRSHIFT 0 +#define _IOC_TYPESHIFT (_IOC_NRSHIFT+_IOC_NRBITS) +#define _IOC_SIZESHIFT (_IOC_TYPESHIFT+_IOC_TYPEBITS) +#define _IOC_DIRSHIFT (_IOC_SIZESHIFT+_IOC_SIZEBITS) + +/* + * Direction bits. + */ +#define _IOC_NONE 0U +#define _IOC_WRITE 1U +#define _IOC_READ 2U + +#define _IOC(dir,type,nr,size) \ + (((dir) << _IOC_DIRSHIFT) | \ + ((type) << _IOC_TYPESHIFT) | \ + ((nr) << _IOC_NRSHIFT) | \ + ((size) << _IOC_SIZESHIFT)) + +/* used to create numbers */ +#define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0) +#define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),sizeof(size)) +#define _IOW(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),sizeof(size)) +#define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size)) + +/* used to decode ioctl numbers.. */ +#define _IOC_DIR(nr) (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK) +#define _IOC_TYPE(nr) (((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK) +#define _IOC_NR(nr) (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK) +#define _IOC_SIZE(nr) (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK) + +/* ...and for the drivers/sound files... */ + +#define IOC_IN (_IOC_WRITE << _IOC_DIRSHIFT) +#define IOC_OUT (_IOC_READ << _IOC_DIRSHIFT) +#define IOC_INOUT ((_IOC_WRITE|_IOC_READ) << _IOC_DIRSHIFT) +#define IOCSIZE_MASK (_IOC_SIZEMASK << _IOC_SIZESHIFT) +#define IOCSIZE_SHIFT (_IOC_SIZESHIFT) + +#endif /* _M68K_IOCTL_H */ diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/ioctls.h linux/include/asm-m68k/ioctls.h --- v1.3.93/linux/include/asm-m68k/ioctls.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/ioctls.h Fri Apr 5 14:08:13 1996 @@ -0,0 +1,74 @@ +#ifndef __ARCH_M68K_IOCTLS_H__ +#define __ARCH_M68K_IOCTLS_H__ + +#include + +/* 0x54 is just a magic number to make these relatively unique ('T') */ + +#define TCGETS 0x5401 +#define TCSETS 0x5402 +#define TCSETSW 0x5403 +#define TCSETSF 0x5404 +#define TCGETA 0x5405 +#define TCSETA 0x5406 +#define TCSETAW 0x5407 +#define TCSETAF 0x5408 +#define TCSBRK 0x5409 +#define TCXONC 0x540A +#define TCFLSH 0x540B +#define TIOCEXCL 0x540C +#define TIOCNXCL 0x540D +#define TIOCSCTTY 0x540E +#define TIOCGPGRP 0x540F +#define TIOCSPGRP 0x5410 +#define TIOCOUTQ 0x5411 +#define TIOCSTI 0x5412 +#define TIOCGWINSZ 0x5413 +#define TIOCSWINSZ 0x5414 +#define TIOCMGET 0x5415 +#define TIOCMBIS 0x5416 +#define TIOCMBIC 0x5417 +#define TIOCMSET 0x5418 +#define TIOCGSOFTCAR 0x5419 +#define TIOCSSOFTCAR 0x541A +#define FIONREAD 0x541B +#define TIOCINQ FIONREAD +#define TIOCLINUX 0x541C +#define TIOCCONS 0x541D +#define TIOCGSERIAL 0x541E +#define TIOCSSERIAL 0x541F +#define TIOCPKT 0x5420 +#define FIONBIO 0x5421 +#define TIOCNOTTY 0x5422 +#define TIOCSETD 0x5423 +#define TIOCGETD 0x5424 +#define TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */ +#define TIOCTTYGSTRUCT 0x5426 /* For debugging only */ +#define FIONCLEX 0x5450 /* these numbers need to be adjusted. */ +#define FIOCLEX 0x5451 +#define FIOASYNC 0x5452 +#define TIOCSERCONFIG 0x5453 +#define TIOCSERGWILD 0x5454 +#define TIOCSERSWILD 0x5455 +#define TIOCGLCKTRMIOS 0x5456 +#define TIOCSLCKTRMIOS 0x5457 +#define TIOCSERGSTRUCT 0x5458 /* For debugging only */ +#define TIOCSERGETLSR 0x5459 /* Get line status register */ +#define TIOCSERGETMULTI 0x545A /* Get multiport config */ +#define TIOCSERSETMULTI 0x545B /* Set multiport config */ + +#define TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ +#define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ + +/* Used for packet mode */ +#define TIOCPKT_DATA 0 +#define TIOCPKT_FLUSHREAD 1 +#define TIOCPKT_FLUSHWRITE 2 +#define TIOCPKT_STOP 4 +#define TIOCPKT_START 8 +#define TIOCPKT_NOSTOP 16 +#define TIOCPKT_DOSTOP 32 + +#define TIOCSER_TEMT 0x01 /* Transmitter physically empty */ + +#endif /* __ARCH_M68K_IOCTLS_H__ */ diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/irq.h linux/include/asm-m68k/irq.h --- v1.3.93/linux/include/asm-m68k/irq.h Mon Nov 28 21:03:09 1994 +++ linux/include/asm-m68k/irq.h Mon Apr 1 22:16:35 1996 @@ -1,6 +1,116 @@ #ifndef _M68K_IRQ_H_ #define _M68K_IRQ_H_ -/* dummy for m68k */ +extern void disable_irq(unsigned int); +extern void enable_irq(unsigned int); + +#include + +/* + * This should be the same as the max(NUM_X_SOURCES) for all the + * different m68k hosts compiled into the kernel. + * Currently the Atari has 72 and the Amiga 24, but if both are + * supported in the kernel it is better to make room for 72. + */ +#if defined(CONFIG_ATARI) +#define NR_IRQS 72 +#else +#define NR_IRQS 24 +#endif + +/* + * Interrupt source definitions + * General interrupt sources are the level 1-7. + * Adding an interrupt service routine for one of these sources + * results in the addition of that routine to a chain of routines. + * Each one is called in succession. Each individual interrupt + * service routine should determine if the device associated with + * that routine requires service. + */ + +#define IRQ1 (1) /* level 1 interrupt */ +#define IRQ2 (2) /* level 2 interrupt */ +#define IRQ3 (3) /* level 3 interrupt */ +#define IRQ4 (4) /* level 4 interrupt */ +#define IRQ5 (5) /* level 5 interrupt */ +#define IRQ6 (6) /* level 6 interrupt */ +#define IRQ7 (7) /* level 7 interrupt (non-maskable) */ + +/* + * "Generic" interrupt sources + */ + +#define IRQ_SCHED_TIMER (8) /* interrupt source for scheduling timer */ + +/* + * Machine specific interrupt sources. + * + * Adding an interrupt service routine for a source with this bit + * set indicates a special machine specific interrupt source. + * The machine specific files define these sources. + */ + +#define IRQ_MACHSPEC (0x10000000L) + +#ifndef ISRFUNC_T +struct pt_regs; +typedef void (*isrfunc) (int irq, struct pt_regs * regs, void *data); +#define ISRFUNC_T +#endif /* ISRFUNC_T */ + +/* + * This structure is used to chain together the ISRs for a particular + * interrupt source (if it supports chaining). + */ +typedef struct isr_node { + isrfunc isr; + int pri; + void *data; + char *name; + struct isr_node *next; +} isr_node_t; + +/* count of spurious interrupts */ +extern volatile unsigned long num_spurious; + +/* + * This function returns a new isr_node_t + */ +extern isr_node_t *new_isr_node(void); + +/* + * This function is used to add a specific interrupt service routine + * for the specified interrupt source. + * + * If the source is machine specific, it will be passed along to the + * machine specific routine. + * + * "data" is user specified data which will be passed to the isr routine. + * + * (isrfunc is defined in linux/config.h) + */ +extern int add_isr (unsigned long source, isrfunc isr, int pri, void + *data, char *name); + +/* + * This routine will remove an isr for the specified interrupt source. + */ +extern int remove_isr (unsigned long source, isrfunc isr); + +/* + * This routine will insert an isr_node_t into a chain of nodes, using + * the priority stored in the node. + */ +extern void insert_isr (isr_node_t **listp, isr_node_t *node); + +/* + * This routine will delete the isr node for isr from a chain of nodes + */ +extern void delete_isr (isr_node_t **listp, isrfunc isr); + +/* + * This routine may be used to call the isr routines in the passed list. + */ +extern void call_isr_list (int irq, isr_node_t *p, struct pt_regs *fp); #endif /* _M68K_IRQ_H_ */ diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/machdep.h linux/include/asm-m68k/machdep.h --- v1.3.93/linux/include/asm-m68k/machdep.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/machdep.h Tue Apr 9 00:15:45 1996 @@ -0,0 +1,46 @@ +#ifndef _M68K_MACHDEP_H +#define _M68K_MACHDEP_H + +struct pt_regs; +struct kbd_repeat; +struct mktime; +struct hwclk_time; +struct gendisk; +struct buffer_head; + +#ifndef ISRFUNC_T +typedef void (*isrfunc) (int irq, struct pt_regs *fp, void *data); +#define ISRFUNC_T +#endif /* ISRFUNC_T */ + +extern void (*mach_sched_init)(isrfunc); +extern int (*mach_keyb_init) (void); +extern int (*mach_kbdrate) (struct kbd_repeat *); +extern void (*mach_kbd_leds) (unsigned int); +extern void (*mach_init_INTS) (void); +extern int (*mach_add_isr) (unsigned long source, isrfunc handler, + int pri, void *data, char *name); +extern int (*mach_remove_isr) (unsigned long source, isrfunc handler); +extern int (*mach_get_irq_list)(char *buf, int len); +extern void (*mach_process_int) (int level, struct pt_regs *fp); +extern void (*mach_enable_irq) (unsigned); +extern void (*mach_disable_irq) (unsigned); +extern unsigned long (*mach_gettimeoffset)(void); +extern void (*mach_gettod)(int *year, int *mon, int *day, int *hour, + int *min, int *sec); +extern int (*mach_hwclk)(int, struct hwclk_time*); +extern int (*mach_set_clock_mmss)(unsigned long); +extern void (*mach_check_partition) (struct gendisk *hd, unsigned int dev); +extern void (*mach_mksound)( unsigned int count, unsigned int ticks ); +extern void (*mach_reset)( void ); +extern int (*mach_floppy_init) (void); +extern unsigned long (*mach_hd_init) (unsigned long, unsigned long); +extern void (*mach_hd_setup)(char *, int *); +extern void (*waitbut)(void); +extern struct fb_info *(*mach_fb_init)(long *); +extern long mach_max_dma_address; +extern void (*mach_debug_init)(void); +extern void (*mach_video_setup)(char *, int *); +extern void (*mach_floppy_setup)(char *, int *); + +#endif /* _M68K_MACHDEP_H */ diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/mman.h linux/include/asm-m68k/mman.h --- v1.3.93/linux/include/asm-m68k/mman.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/mman.h Sat Mar 23 22:23:19 1996 @@ -0,0 +1,31 @@ +#ifndef __M68K_MMAN_H__ +#define __M68K_MMAN_H__ + +#define PROT_READ 0x1 /* page can be read */ +#define PROT_WRITE 0x2 /* page can be written */ +#define PROT_EXEC 0x4 /* page can be executed */ +#define PROT_NONE 0x0 /* page can not be accessed */ + +#define MAP_SHARED 0x01 /* Share changes */ +#define MAP_PRIVATE 0x02 /* Changes are private */ +#define MAP_TYPE 0x0f /* Mask for type of mapping */ +#define MAP_FIXED 0x10 /* Interpret addr exactly */ +#define MAP_ANONYMOUS 0x20 /* don't use a file */ + +#define MAP_GROWSDOWN 0x0100 /* stack-like segment */ +#define MAP_DENYWRITE 0x0800 /* ETXTBSY */ +#define MAP_EXECUTABLE 0x1000 /* mark it as a executable */ +#define MAP_LOCKED 0x2000 /* pages are locked */ + +#define MS_ASYNC 1 /* sync memory asynchronously */ +#define MS_INVALIDATE 2 /* invalidate the caches */ +#define MS_SYNC 4 /* synchronous memory sync */ + +#define MCL_CURRENT 1 /* lock all current mappings */ +#define MCL_FUTURE 2 /* lock all future mappings */ + +/* compatibility flags */ +#define MAP_ANON MAP_ANONYMOUS +#define MAP_FILE 0 + +#endif /* __M68K_MMAN_H__ */ diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/mmu_context.h linux/include/asm-m68k/mmu_context.h --- v1.3.93/linux/include/asm-m68k/mmu_context.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/mmu_context.h Wed Mar 27 22:45:37 1996 @@ -0,0 +1,9 @@ +#ifndef __68K_MMU_CONTEXT_H +#define __68K_MMU_CONTEXT_H + +/* + * get a new mmu context.. do we need this on the m68k? + */ +#define get_mmu_context(x) do { } while (0) + +#endif diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/page.h linux/include/asm-m68k/page.h --- v1.3.93/linux/include/asm-m68k/page.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/page.h Sat Mar 23 22:26:13 1996 @@ -0,0 +1,72 @@ +#ifndef _M68K_PAGE_H +#define _M68K_PAGE_H + +/* PAGE_SHIFT determines the page size */ +#define PAGE_SHIFT 12 +#define PAGE_SIZE (1UL << PAGE_SHIFT) +#define PAGE_MASK (~(PAGE_SIZE-1)) + +#ifdef __KERNEL__ + +#define STRICT_MM_TYPECHECKS + +#ifdef STRICT_MM_TYPECHECKS +/* + * These are used to make use of C type-checking.. + */ +typedef struct { unsigned long pte; } pte_t; +typedef struct { unsigned long pmd[16]; } pmd_t; +typedef struct { unsigned long pgd; } pgd_t; +typedef struct { unsigned long pgprot; } pgprot_t; + +#define pte_val(x) ((x).pte) +#define pmd_val(x) ((&x)->pmd[0]) +#define pgd_val(x) ((x).pgd) +#define pgprot_val(x) ((x).pgprot) + +#define __pte(x) ((pte_t) { (x) } ) +#define __pmd(x) ((pmd_t) { (x) } ) +#define __pgd(x) ((pgd_t) { (x) } ) +#define __pgprot(x) ((pgprot_t) { (x) } ) + +#else +/* + * .. while these make it easier on the compiler + */ +typedef unsigned long pte_t; +typedef struct { unsigned long pmd[16]; } pmd_t; +typedef unsigned long pgd_t; +typedef unsigned long pgprot_t; + +#define pte_val(x) (x) +#define pmd_val(x) ((&x)->pmd[0]) +#define pgd_val(x) (x) +#define pgprot_val(x) (x) + +#define __pte(x) (x) +#define __pmd(x) ((pmd_t) { (x) } ) +#define __pgd(x) (x) +#define __pgprot(x) (x) + +#endif + +/* m68k_is040or060 is != 0 for a '040 or higher; used numbers are 4 for 68040 + * and 6 for 68060 */ +extern int m68k_is040or060; + +/* This is the cache mode to be used for pages containing page descriptors for + * processors >= '040. It is in pte_mknocache(), and the variable is defined + * and initialized in head.S */ +extern int m68k_pgtable_cachemode; + +/* to align the pointer to the (next) page boundary */ +#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK) + +/* This handles the memory map.. */ +#define PAGE_OFFSET 0 +#define MAP_NR(addr) (((unsigned long)(addr)) >> PAGE_SHIFT) +#define MAP_PAGE_RESERVED (1<<15) + +#endif /* __KERNEL__ */ + +#endif /* _M68K_PAGE_H */ diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/param.h linux/include/asm-m68k/param.h --- v1.3.93/linux/include/asm-m68k/param.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/param.h Wed Dec 27 22:47:20 1995 @@ -0,0 +1,20 @@ +#ifndef _M68K_PARAM_H +#define _M68K_PARAM_H + +#ifndef HZ +#define HZ 100 +#endif + +#define EXEC_PAGESIZE 4096 + +#ifndef NGROUPS +#define NGROUPS 32 +#endif + +#ifndef NOGROUP +#define NOGROUP (-1) +#endif + +#define MAXHOSTNAMELEN 64 /* max length of hostname */ + +#endif /* _M68K_PARAM_H */ diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/pgtable.h linux/include/asm-m68k/pgtable.h --- v1.3.93/linux/include/asm-m68k/pgtable.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/pgtable.h Thu Apr 18 03:00:00 1996 @@ -0,0 +1,586 @@ +#ifndef _M68K_PGTABLE_H +#define _M68K_PGTABLE_H + +/* + * This file contains the functions and defines necessary to modify and use + * the m68k page table tree. + */ + +#define __flush_tlb() \ +do { \ + if (m68k_is040or060) \ + __asm__ __volatile__(".word 0xf510\n"::); /* pflushan */ \ + else \ + __asm__ __volatile__("pflusha\n"::); \ +} while (0) + +#if 1 +static inline void __flush_tlb_one(unsigned long addr) +{ + if (m68k_is040or060) { + register unsigned long a0 __asm__ ("a0") = addr; + __asm__ __volatile__(".word 0xf508" /* pflush (%a0) */ + : : "a" (a0)); + } else + __asm__ __volatile__("pflush #0,#0,(%0)" : : "a" (addr)); +} +#else +#define __flush_tlb_one(addr) __flush_tlb() +#endif + +#define flush_tlb() __flush_tlb() +#define flush_tlb_all() flush_tlb() + +static inline void flush_tlb_mm(struct mm_struct *mm) +{ + if (mm == current->mm) + __flush_tlb(); +} + +static inline void flush_tlb_page(struct vm_area_struct *vma, + unsigned long addr) +{ + if (vma->vm_mm == current->mm) + __flush_tlb_one(addr); +} + +static inline void flush_tlb_range(struct mm_struct *mm, + unsigned long start, unsigned long end) +{ + if (mm == current->mm) + __flush_tlb(); +} + +/* Certain architectures need to do special things when pte's + * within a page table are directly modified. Thus, the following + * hook is made available. + */ +#define set_pte(pteptr, pteval) ((*(pteptr)) = (pteval)) + +/* PMD_SHIFT determines the size of the area a second-level page table can map */ +#define PMD_SHIFT 22 +#define PMD_SIZE (1UL << PMD_SHIFT) +#define PMD_MASK (~(PMD_SIZE-1)) + +/* PGDIR_SHIFT determines what a third-level page table entry can map */ +#define PGDIR_SHIFT 25 +#define PGDIR_SIZE (1UL << PGDIR_SHIFT) +#define PGDIR_MASK (~(PGDIR_SIZE-1)) + +/* + * entries per page directory level: the m68k is configured as three-level, + * so we do have PMD level physically. + */ +#define PTRS_PER_PTE 1024 +#define PTRS_PER_PMD 8 +#define PTRS_PER_PGD 128 + +/* the no. of pointers that fit on a page: this will go away */ +#define PTRS_PER_PAGE (PAGE_SIZE/sizeof(void*)) + +/* Just any arbitrary offset to the start of the vmalloc VM area: the + * current 8MB value just means that there will be a 8MB "hole" after the + * physical memory until the kernel virtual memory starts. That means that + * any out-of-bounds memory accesses will hopefully be caught. + * The vmalloc() routines leaves a hole of 4kB between each vmalloced + * area for the same reason. ;) + */ +#define VMALLOC_OFFSET (8*1024*1024) +#define VMALLOC_START ((high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)) +#define VMALLOC_VMADDR(x) ((unsigned long)(x)) + +/* + * Definitions for MMU descriptors + */ +#define _PAGE_PRESENT 0x001 +#define _PAGE_SHORT 0x002 +#define _PAGE_RONLY 0x004 +#define _PAGE_ACCESSED 0x008 +#define _PAGE_DIRTY 0x010 +#define _PAGE_GLOBAL040 0x400 /* 68040 global bit, used for kva descs */ +#define _PAGE_COW 0x800 /* implemented in software */ +#define _PAGE_NOCACHE030 0x040 /* 68030 no-cache mode */ +#define _PAGE_NOCACHE 0x060 /* 68040 cache mode, non-serialized */ +#define _PAGE_NOCACHE_S 0x040 /* 68040 no-cache mode, serialized */ +#define _PAGE_CACHE040 0x020 /* 68040 cache mode, cachable, copyback */ +#define _PAGE_CACHE040W 0x000 /* 68040 cache mode, cachable, write-through */ + +#define _DESCTYPE_MASK 0x003 + +#define _CACHEMASK040 (~0x060) +#define _TABLE_MASK (0xfffffff0) + +#define _PAGE_TABLE (_PAGE_SHORT) +#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_NOCACHE) + +#define PAGE_NONE __pgprot(_PAGE_PRESENT | _PAGE_RONLY | _PAGE_ACCESSED | _PAGE_CACHE040) +#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_CACHE040) +#define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_RONLY | _PAGE_ACCESSED | _PAGE_CACHE040) +#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_RONLY | _PAGE_ACCESSED | _PAGE_CACHE040) +#define PAGE_KERNEL __pgprot(_PAGE_PRESENT | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_CACHE040) + +/* + * The m68k can't do page protection for execute, and considers that the same are read. + * Also, write permissions imply read permissions. This is the closest we can get.. + */ +#define __P000 PAGE_NONE +#define __P001 PAGE_READONLY +#define __P010 PAGE_COPY +#define __P011 PAGE_COPY +#define __P100 PAGE_READONLY +#define __P101 PAGE_READONLY +#define __P110 PAGE_COPY +#define __P111 PAGE_COPY + +#define __S000 PAGE_NONE +#define __S001 PAGE_READONLY +#define __S010 PAGE_SHARED +#define __S011 PAGE_SHARED +#define __S100 PAGE_READONLY +#define __S101 PAGE_READONLY +#define __S110 PAGE_SHARED +#define __S111 PAGE_SHARED + +/* zero page used for unitialized stuff */ +extern unsigned long empty_zero_page; + +/* + * BAD_PAGETABLE is used when we need a bogus page-table, while + * BAD_PAGE is used for a bogus page. + * + * ZERO_PAGE is a global shared page that is always zero: used + * for zero-mapped memory areas etc.. + */ +extern pte_t __bad_page(void); +extern pte_t * __bad_pagetable(void); + +#define BAD_PAGETABLE __bad_pagetable() +#define BAD_PAGE __bad_page() +#define ZERO_PAGE empty_zero_page + +/* number of bits that fit into a memory pointer */ +#define BITS_PER_PTR (8*sizeof(unsigned long)) + +/* to align the pointer to a pointer address */ +#define PTR_MASK (~(sizeof(void*)-1)) + +/* sizeof(void*)==1<>(PAGE_SHIFT-SIZEOF_PTR_LOG2)&PTR_MASK&~PAGE_MASK) + +extern unsigned long high_memory; + +/* For virtual address to physical address conversion */ +extern unsigned long mm_vtop(unsigned long addr) __attribute__ ((const)); +extern unsigned long mm_ptov(unsigned long addr) __attribute__ ((const)); +#define VTOP(addr) (mm_vtop((unsigned long)(addr))) +#define PTOV(addr) (mm_ptov((unsigned long)(addr))) + +/* + * Conversion functions: convert a page and protection to a page entry, + * and a page entry and page directory to the page they refer to. + */ +extern inline pte_t mk_pte(unsigned long page, pgprot_t pgprot) +{ pte_t pte; pte_val(pte) = VTOP(page) | pgprot_val(pgprot); return pte; } + +extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot) +{ pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); return pte; } + +extern inline void pmd_set(pmd_t * pmdp, pte_t * ptep) +{ + int i; + + ptep = (pte_t *) VTOP(ptep); + for (i = 0; i < 16; i++, ptep += PTRS_PER_PTE/16) + pmdp->pmd[i] = _PAGE_TABLE | (unsigned long)ptep; +} + +/* early termination version of the above */ +extern inline void pmd_set_et(pmd_t * pmdp, pte_t * ptep) +{ + int i; + + ptep = (pte_t *) VTOP(ptep); + for (i = 0; i < 16; i++, ptep += PTRS_PER_PTE/16) + pmdp->pmd[i] = _PAGE_PRESENT | (unsigned long)ptep; +} + +extern inline void pgd_set(pgd_t * pgdp, pmd_t * pmdp) +{ pgd_val(*pgdp) = _PAGE_TABLE | VTOP(pmdp); } + +extern inline unsigned long pte_page(pte_t pte) +{ return PTOV(pte_val(pte) & PAGE_MASK); } + +extern inline unsigned long pmd_page2(pmd_t *pmd) +{ return PTOV(pmd_val(*pmd) & _TABLE_MASK); } +#define pmd_page(pmd) pmd_page2(&(pmd)) + +extern inline unsigned long pgd_page(pgd_t pgd) +{ return PTOV(pgd_val(pgd) & _TABLE_MASK); } + +extern inline int pte_none(pte_t pte) { return !pte_val(pte); } +extern inline int pte_present(pte_t pte) { return pte_val(pte) & _PAGE_PRESENT; } +extern inline void pte_clear(pte_t *ptep) { pte_val(*ptep) = 0; } + +extern inline int pmd_none2(pmd_t *pmd) { return !pmd_val(*pmd); } +#define pmd_none(pmd) pmd_none2(&(pmd)) +extern inline int pmd_bad2(pmd_t *pmd) { return (pmd_val(*pmd) & _DESCTYPE_MASK) != _PAGE_TABLE || pmd_page(*pmd) > high_memory; } +#define pmd_bad(pmd) pmd_bad2(&(pmd)) +extern inline int pmd_present2(pmd_t *pmd) { return pmd_val(*pmd) & _PAGE_TABLE; } +#define pmd_present(pmd) pmd_present2(&(pmd)) +extern inline void pmd_clear(pmd_t * pmdp) +{ + int i; + + for (i = 0; i < 16; i++) + pmdp->pmd[i] = 0; +} + +extern inline int pgd_none(pgd_t pgd) { return !pgd_val(pgd); } +extern inline int pgd_bad(pgd_t pgd) { return (pgd_val(pgd) & _DESCTYPE_MASK) != _PAGE_TABLE || pgd_page(pgd) > high_memory; } +extern inline int pgd_present(pgd_t pgd) { return pgd_val(pgd) & _PAGE_TABLE; } + +extern inline void pgd_clear(pgd_t * pgdp) { pgd_val(*pgdp) = 0; } + +/* + * The following only work if pte_present() is true. + * Undefined behaviour if not.. + */ +extern inline int pte_read(pte_t pte) { return 1; } +extern inline int pte_write(pte_t pte) { return !(pte_val(pte) & _PAGE_RONLY); } +extern inline int pte_exec(pte_t pte) { return 1; } +extern inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; } +extern inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; } + +extern inline pte_t pte_wrprotect(pte_t pte) { pte_val(pte) |= _PAGE_RONLY; return pte; } +extern inline pte_t pte_rdprotect(pte_t pte) { return pte; } +extern inline pte_t pte_exprotect(pte_t pte) { return pte; } +extern inline pte_t pte_mkclean(pte_t pte) { pte_val(pte) &= ~_PAGE_DIRTY; return pte; } +extern inline pte_t pte_mkold(pte_t pte) { pte_val(pte) &= ~_PAGE_ACCESSED; return pte; } +extern inline pte_t pte_mkwrite(pte_t pte) { pte_val(pte) &= ~_PAGE_RONLY; return pte; } +extern inline pte_t pte_mkread(pte_t pte) { return pte; } +extern inline pte_t pte_mkexec(pte_t pte) { return pte; } +extern inline pte_t pte_mkdirty(pte_t pte) { pte_val(pte) |= _PAGE_DIRTY; return pte; } +extern inline pte_t pte_mkyoung(pte_t pte) { pte_val(pte) |= _PAGE_ACCESSED; return pte; } +extern inline pte_t pte_mknocache(pte_t pte) +{ + pte_val(pte) = (pte_val(pte) & _CACHEMASK040) | m68k_pgtable_cachemode; + return pte; +} +extern inline pte_t pte_mkcache(pte_t pte) { pte_val(pte) = (pte_val(pte) & _CACHEMASK040) | _PAGE_CACHE040; return pte; } + +/* to set the page-dir */ +extern inline void SET_PAGE_DIR(struct task_struct * tsk, pgd_t * pgdir) +{ + tsk->tss.pagedir_v = (unsigned long *)pgdir; + tsk->tss.pagedir_p = VTOP(pgdir); + tsk->tss.crp[0] = 0x80000000 | _PAGE_SHORT; + tsk->tss.crp[1] = tsk->tss.pagedir_p; + if (tsk == current) { + if (m68k_is040or060) + __asm__ __volatile__ (".word 0xf510\n\t" /* pflushan */ + "movel %0@,%/d0\n\t" + ".long 0x4e7b0806\n\t" + /* movec d0,urp */ + : : "a" (&tsk->tss.crp[1]) + : "d0"); + else + __asm__ __volatile__ ("movec %/cacr,%/d0\n\t" + "oriw #0x0808,%/d0\n\t" + "movec %/d0,%/cacr\n\t" + "pmove %0@,%/crp\n\t" + : : "a" (&tsk->tss.crp[0]) + : "d0"); + } +} + +#define PAGE_DIR_OFFSET(tsk,address) pgd_offset((tsk),(address)) + +/* to find an entry in a page-table-directory */ +extern inline pgd_t * pgd_offset(struct mm_struct * mm, unsigned long address) +{ + return mm->pgd + (address >> PGDIR_SHIFT); +} + +extern pgd_t swapper_pg_dir[128]; +extern pgd_t kernel_pg_dir[128]; + +extern inline pgd_t * pgd_offset_k(unsigned long address) +{ + return kernel_pg_dir + (address >> PGDIR_SHIFT); +} + + +/* Find an entry in the second-level page table.. */ +extern inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address) +{ + return (pmd_t *) pgd_page(*dir) + ((address >> PMD_SHIFT) & (PTRS_PER_PMD-1)); +} + +/* Find an entry in the third-level page table.. */ +extern inline pte_t * pte_offset(pmd_t * pmdp, unsigned long address) +{ + return (pte_t *) pmd_page(*pmdp) + ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)); +} + +/* + * Allocate and free page tables. The xxx_kernel() versions are + * used to allocate a kernel page table - this turns on ASN bits + * if any. + */ + +extern inline void nocache_page (unsigned long vaddr) +{ + if (m68k_is040or060) { + pgd_t *dir; + pmd_t *pmdp; + pte_t *ptep; + + dir = pgd_offset_k(vaddr); + pmdp = pmd_offset(dir,vaddr); + ptep = pte_offset(pmdp,vaddr); + *ptep = pte_mknocache(*ptep); + } +} + +static inline void cache_page (unsigned long vaddr) +{ + if (m68k_is040or060) { + pgd_t *dir; + pmd_t *pmdp; + pte_t *ptep; + + dir = pgd_offset_k(vaddr); + pmdp = pmd_offset(dir,vaddr); + ptep = pte_offset(pmdp,vaddr); + *ptep = pte_mkcache(*ptep); + } +} + + +extern inline void pte_free(pte_t * pte) +{ + cache_page((unsigned long)pte); + free_page((unsigned long) pte); +} + +extern inline pte_t * pte_alloc(pmd_t * pmd, unsigned long address) +{ + address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1); + if (pmd_none(*pmd)) { + pte_t * page = (pte_t *)get_free_page(GFP_KERNEL); + if (pmd_none(*pmd)) { + if (page) { + nocache_page((unsigned long)page); + pmd_set(pmd,page); + return page + address; + } + pmd_set(pmd, BAD_PAGETABLE); + return NULL; + } + free_page((unsigned long)page); + } + if (pmd_bad(*pmd)) { + printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd)); + pmd_set(pmd, BAD_PAGETABLE); + return NULL; + } + return (pte_t *) pmd_page(*pmd) + address; +} + +extern pmd_t *get_pointer_table (void); +extern void free_pointer_table (pmd_t *); +extern pmd_t *get_kpointer_table (void); +extern void free_kpointer_table (pmd_t *); + +extern inline void pmd_free(pmd_t * pmd) +{ + free_pointer_table (pmd); +} + +extern inline pmd_t * pmd_alloc(pgd_t * pgd, unsigned long address) +{ + address = (address >> PMD_SHIFT) & (PTRS_PER_PMD - 1); + if (pgd_none(*pgd)) { + pmd_t *page = get_pointer_table(); + if (pgd_none(*pgd)) { + if (page) { + pgd_set(pgd, page); + return page + address; + } + pgd_set(pgd, (pmd_t *)BAD_PAGETABLE); + return NULL; + } + free_pointer_table(page); + } + if (pgd_bad(*pgd)) { + printk("Bad pgd in pmd_alloc: %08lx\n", pgd_val(*pgd)); + pgd_set(pgd, (pmd_t *)BAD_PAGETABLE); + return NULL; + } + return (pmd_t *) pgd_page(*pgd) + address; +} + +extern inline void pte_free_kernel(pte_t * pte) +{ + cache_page((unsigned long)pte); + free_page((unsigned long) pte); +} + +extern inline pte_t * pte_alloc_kernel(pmd_t * pmd, unsigned long address) +{ + address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1); + if (pmd_none(*pmd)) { + pte_t * page = (pte_t *) get_free_page(GFP_KERNEL); + if (pmd_none(*pmd)) { + if (page) { + nocache_page((unsigned long)page); + pmd_set(pmd, page); + return page + address; + } + pmd_set(pmd, BAD_PAGETABLE); + return NULL; + } + free_page((unsigned long) page); + } + if (pmd_bad(*pmd)) { + printk("Bad pmd in pte_alloc_kernel: %08lx\n", pmd_val(*pmd)); + pmd_set(pmd, BAD_PAGETABLE); + return NULL; + } + return (pte_t *) pmd_page(*pmd) + address; +} + +extern inline void pmd_free_kernel(pmd_t * pmd) +{ + free_kpointer_table(pmd); +} + +extern inline pmd_t * pmd_alloc_kernel(pgd_t * pgd, unsigned long address) +{ + address = (address >> PMD_SHIFT) & (PTRS_PER_PMD - 1); + if (pgd_none(*pgd)) { + pmd_t *page = get_kpointer_table(); + if (pgd_none(*pgd)) { + if (page) { + pgd_set(pgd, page); + return page + address; + } + pgd_set(pgd, (pmd_t *)BAD_PAGETABLE); + return NULL; + } + free_kpointer_table(page); + } + if (pgd_bad(*pgd)) { + printk("Bad pgd in pmd_alloc_kernel: %08lx\n", pgd_val(*pgd)); + pgd_set(pgd, (pmd_t *)BAD_PAGETABLE); + return NULL; + } + return (pmd_t *) pgd_page(*pgd) + address; +} + +extern inline void pgd_free(pgd_t * pgd) +{ + free_pointer_table ((pmd_t *) pgd); +} + +extern inline pgd_t * pgd_alloc(void) +{ + return (pgd_t *)get_pointer_table (); +} + +#define flush_icache() \ +do { \ + if (m68k_is040or060) \ + asm (".word 0xf498"); /* CINVA I */ \ + else \ + asm ("movec %/cacr,%/d0;" \ + "oriw %0,%/d0;" \ + "movec %/d0,%/cacr" \ + : /* no outputs */ \ + : "i" (FLUSH_I) \ + : "d0"); \ +} while (0) + +/* + * invalidate the cache for the specified memory range. + * It starts at the physical address specified for + * the given number of bytes. + */ +extern void cache_clear (unsigned long paddr, int len); +/* + * push any dirty cache in the specified memory range. + * It starts at the physical address specified for + * the given number of bytes. + */ +extern void cache_push (unsigned long paddr, int len); + +/* + * push and invalidate pages in the specified user virtual + * memory range. + */ +extern void cache_push_v (unsigned long vaddr, int len); + +#if 0 +#define flush_cache_all() do { \ + if (m68k_is040or060 >= 4) \ + __asm__ __volatile__ (".word 0xf478\n" ::); \ + } while (0) +#define flush_cache_mm(mm) flush_cache_all() +#define flush_cache_range(mm, start, end) flush_cache_all() +#define flush_cache_page(vma, vmaddr) flush_cache_all() +#define flush_page_to_ram(page) flush_cache_all() +#else +#define flush_cache_all() do { } while (0) +#define flush_cache_mm(mm) do { } while (0) +#define flush_cache_range(mm, start, end) do { } while (0) +#define flush_cache_page(vma, vmaddr) do { } while (0) +#define flush_page_to_ram(page) do { } while (0) +#endif + +/* cache code */ +#define FLUSH_I_AND_D (0x00000808) +#define FLUSH_I (0x00000008) + +/* + * Check if the addr/len goes up to the end of a physical + * memory chunk. Used for DMA functions. + */ +int mm_end_of_chunk (unsigned long addr, int len); + +/* + * Map some physical address range into the kernel address space. The + * code is copied and adapted from map_chunk(). + */ +extern unsigned long kernel_map(unsigned long paddr, unsigned long size, + int nocacheflag, unsigned long *memavailp ); +/* + * Change the cache mode of some kernel address range. + */ +extern void kernel_set_cachemode( unsigned long address, unsigned long size, + unsigned cmode ); + +/* Values for nocacheflag and cmode */ +#define KERNELMAP_FULL_CACHING 0 +#define KERNELMAP_NOCACHE_SER 1 +#define KERNELMAP_NOCACHE_NONSER 2 +#define KERNELMAP_NO_COPYBACK 3 + +/* + * The m68k doesn't have any external MMU info: the kernel page + * tables contain all the necessary information. + */ +extern inline void update_mmu_cache(struct vm_area_struct * vma, + unsigned long address, pte_t pte) +{ +} + +#define SWP_TYPE(entry) (((entry) >> 2) & 0x7f) +#define SWP_OFFSET(entry) ((entry) >> 9) +#define SWP_ENTRY(type,offset) (((type) << 2) | ((offset) << 9)) + +#endif /* _M68K_PGTABLE_H */ diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/posix_types.h linux/include/asm-m68k/posix_types.h --- v1.3.93/linux/include/asm-m68k/posix_types.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/posix_types.h Fri Apr 5 14:08:18 1996 @@ -0,0 +1,42 @@ +#ifndef __ARCH_I386_POSIX_TYPES_H +#define __ARCH_I386_POSIX_TYPES_H + +/* + * This file is generally used by user-level software, so you need to + * be a little careful about namespace pollution etc. Also, we cannot + * assume GCC is being used. + */ + +typedef unsigned short __kernel_dev_t; +typedef unsigned long __kernel_ino_t; +typedef unsigned short __kernel_mode_t; +typedef unsigned short __kernel_nlink_t; +typedef long __kernel_off_t; +typedef int __kernel_pid_t; +typedef unsigned short __kernel_uid_t; +typedef unsigned short __kernel_gid_t; +typedef unsigned int __kernel_size_t; +typedef int __kernel_ssize_t; +typedef int __kernel_ptrdiff_t; +typedef long __kernel_time_t; +typedef long __kernel_clock_t; +typedef int __kernel_daddr_t; +typedef char * __kernel_caddr_t; + +#ifdef __GNUC__ +typedef long long __kernel_loff_t; +#endif + +#undef __FD_SET +#define __FD_SET(d, set) ((set)->fds_bits[__FDELT(d)] |= __FDMASK(d)) + +#undef __FD_CLR +#define __FD_CLR(d, set) ((set)->fds_bits[__FDELT(d)] &= ~__FDMASK(d)) + +#undef __FD_ISSET +#define __FD_ISSET(d, set) ((set)->fds_bits[__FDELT(d)] & __FDMASK(d)) + +#undef __FD_ZERO +#define __FD_ZERO(fdsetp) (memset (fdsetp, 0, sizeof(*(fd_set *)fdsetp))) + +#endif diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/processor.h linux/include/asm-m68k/processor.h --- v1.3.93/linux/include/asm-m68k/processor.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/processor.h Sun Mar 24 12:21:16 1996 @@ -0,0 +1,92 @@ +/* + * include/asm-m68k/processor.h + * + * Copyright (C) 1995 Hamish Macdonald + */ + +#ifndef __ASM_M68K_PROCESSOR_H +#define __ASM_M68K_PROCESSOR_H + +#include + +/* + * User space process size: 3.75GB. This is hardcoded into a few places, + * so don't change it unless you know what you are doing. + */ +#define TASK_SIZE (0xF0000000UL) + +/* + * Bus types + */ +#define EISA_bus__is_a_macro 1 +#define EISA_bus 0 +#define MCA_bus__is_a_macro 1 +#define MCA_bus 0 + +/* + * The m68k has no problems with write protection + */ +#define wp_works_ok__is_a_macro 1 +#define wp_works_ok 1 + +/* MAX floating point unit state size (FSAVE/FRESTORE) */ +#define FPSTATESIZE (216/sizeof(unsigned short)) + +/* + * if you change this structure, you must change the code and offsets + * in m68k/machasm.S + */ + +struct thread_struct { + unsigned long ksp; /* kernel stack pointer */ + unsigned long usp; /* user stack pointer */ + unsigned short sr; /* saved status register */ + unsigned short fs; /* saved fs (sfc, dfc) */ + unsigned long *pagedir_v; /* root page table virtual addr */ + unsigned long pagedir_p; /* root page table physaddr */ + unsigned long crp[2]; /* cpu root pointer */ + unsigned long esp0; /* points to SR of stack frame */ + unsigned long fp[8*3]; + unsigned long fpcntl[3]; /* fp control regs */ + unsigned short fpstate[FPSTATESIZE]; /* floating point state */ +}; + +#define INIT_MMAP { &init_mm, 0, 0x40000000, __pgprot(_PAGE_PRESENT|_PAGE_ACCESSED), VM_READ | VM_WRITE | VM_EXEC } + +#define INIT_TSS { \ + sizeof(init_kernel_stack) + (long) init_kernel_stack, 0, \ + PS_S, KERNEL_DS, \ + NULL, 0, {0, 0}, 0 \ +} + +#define alloc_kernel_stack() get_free_page(GFP_KERNEL) +#define free_kernel_stack(page) free_page((page)) + +/* + * Do necessary setup to start up a newly executed thread. + */ +static inline void start_thread(struct pt_regs * regs, unsigned long pc, + unsigned long usp) +{ + unsigned long nilstate = 0; + + /* clear floating point state */ + __asm__ __volatile__ ("frestore %0@" : : "a" (&nilstate)); + + /* reads from user space */ + set_fs(USER_DS); + + regs->pc = pc; + regs->sr &= ~0x2000; + wrusp(usp); +} + +/* + * Return saved PC of a blocked thread. + */ +extern inline unsigned long thread_saved_pc(struct thread_struct *t) +{ + return ((unsigned long *)((struct switch_stack *)t->ksp)->a6)[1]; +} + +#endif diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/ptrace.h linux/include/asm-m68k/ptrace.h --- v1.3.93/linux/include/asm-m68k/ptrace.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/ptrace.h Wed Mar 20 22:03:24 1996 @@ -0,0 +1,73 @@ +#ifndef _M68K_PTRACE_H +#define _M68K_PTRACE_H + +#define PT_D1 0 +#define PT_D2 1 +#define PT_D3 2 +#define PT_D4 3 +#define PT_D5 4 +#define PT_D6 5 +#define PT_D7 6 +#define PT_A0 7 +#define PT_A1 8 +#define PT_A2 9 +#define PT_A3 10 +#define PT_A4 11 +#define PT_A5 12 +#define PT_A6 13 +#define PT_D0 14 +#define PT_USP 15 +#define PT_ORIG_D0 16 +#define PT_SR 17 +#define PT_PC 18 + +#ifndef __ASSEMBLY__ + +/* this struct defines the way the registers are stored on the + stack during a system call. */ + +struct pt_regs { + long d1; + long d2; + long d3; + long d4; + long d5; + long a0; + long a1; + long d0; + long orig_d0; + long stkadj; + unsigned short sr; + unsigned long pc; + unsigned format : 4; /* frame format specifier */ + unsigned vector : 12; /* vector offset */ +}; + +/* + * This is the extended stack used by signal handlers and the context + * switcher: it's pushed after the normal "struct pt_regs". + */ +struct switch_stack { + unsigned long d6; + unsigned long d7; + unsigned long a2; + unsigned long a3; + unsigned long a4; + unsigned long a5; + unsigned long a6; + unsigned long retpc; +}; + +#ifdef __KERNEL__ + +#ifndef PS_S +#define PS_S (0x2000) +#define PS_M (0x1000) +#endif + +#define user_mode(regs) (!((regs)->sr & PS_S)) +#define instruction_pointer(regs) ((regs)->pc) +extern void show_regs(struct pt_regs *); +#endif /* __KERNEL__ */ +#endif /* __ASSEMBLY__ */ +#endif /* _M68K_PTRACE_H */ diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/resource.h linux/include/asm-m68k/resource.h --- v1.3.93/linux/include/asm-m68k/resource.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/resource.h Sat Mar 23 14:56:25 1996 @@ -0,0 +1,37 @@ +#ifndef _M68K_RESOURCE_H +#define _M68K_RESOURCE_H + +/* + * Resource limits + */ + +#define RLIMIT_CPU 0 /* CPU time in ms */ +#define RLIMIT_FSIZE 1 /* Maximum filesize */ +#define RLIMIT_DATA 2 /* max data size */ +#define RLIMIT_STACK 3 /* max stack size */ +#define RLIMIT_CORE 4 /* max core file size */ +#define RLIMIT_RSS 5 /* max resident set size */ +#define RLIMIT_NPROC 6 /* max number of processes */ +#define RLIMIT_NOFILE 7 /* max number of open files */ +#define RLIMIT_MEMLOCK 8 /* max locked-in-memory address space*/ + +#define RLIM_NLIMITS 9 + +#ifdef __KERNEL__ + +#define INIT_RLIMITS \ +{ \ + {LONG_MAX, LONG_MAX}, \ + {LONG_MAX, LONG_MAX}, \ + {LONG_MAX, LONG_MAX}, \ + {_STK_LIM, _STK_LIM}, \ + { 0, LONG_MAX}, \ + {LONG_MAX, LONG_MAX}, \ + {MAX_TASKS_PER_USER, MAX_TASKS_PER_USER}, \ + {NR_OPEN, NR_OPEN}, \ + {LONG_MAX, LONG_MAX} \ +} + +#endif /* __KERNEL__ */ + +#endif /* _M68K_RESOURCE_H */ diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/segment.h linux/include/asm-m68k/segment.h --- v1.3.93/linux/include/asm-m68k/segment.h Tue Nov 29 22:08:54 1994 +++ linux/include/asm-m68k/segment.h Sat Apr 13 14:31:08 1996 @@ -1,197 +1,326 @@ +#ifndef _M68K_SEGMENT_H +#define _M68K_SEGMENT_H + +/* define constants */ +/* Address spaces (FC0-FC2) */ +#define USER_DATA (1) +#ifndef USER_DS +#define USER_DS (USER_DATA) +#endif +#define USER_PROGRAM (2) +#define SUPER_DATA (5) +#ifndef KERNEL_DS +#define KERNEL_DS (SUPER_DATA) +#endif +#define SUPER_PROGRAM (6) +#define CPU_SPACE (7) + +#ifndef __ASSEMBLY__ + /* - * linux/include/asm-m68k/segment.h - * - * Copyright (C) 1991, 1992 Linus Torvalds - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file README.legal in the main directory of this archive - * for more details. + * Uh, these should become the main single-value transfer routines.. + * They automatically use the right size if we just have the right + * pointer type.. */ +#define put_user(x,ptr) __put_user((unsigned long)(x),(ptr),sizeof(*(ptr))) +#define get_user(ptr) ((__typeof__(*(ptr)))__get_user((ptr),sizeof(*(ptr)))) /* - * 680x0 support added by Hamish Macdonald + * This is a silly but good way to make sure that + * the __put_user function is indeed always optimized, + * and that we use the correct sizes.. */ +extern int bad_user_access_length(void); -#ifndef _M68K_SEGMENT_H -#define _M68K_SEGMENT_H +#define __ptr(x) ((unsigned long *)(x)) -static inline unsigned char get_user_byte(const char * addr) +static inline void __put_user(unsigned long x, void * y, int size) { - register unsigned char _v; - - __asm__ __volatile__ ("movesb %1,%0":"=r" (_v):"m" (*addr)); - return _v; + switch (size) { + case 1: + __asm__ ("movesb %0,%1" + : /* no outputs */ + :"r" (x),"m" (*__ptr(y)) : "memory"); + break; + case 2: + __asm__ ("movesw %0,%1" + : /* no outputs */ + :"r" (x),"m" (*__ptr(y)) : "memory"); + break; + case 4: + __asm__ ("movesl %0,%1" + : /* no outputs */ + :"r" (x),"m" (*__ptr(y)) : "memory"); + break; + default: + bad_user_access_length(); + } } -#define get_fs_byte(addr) get_user_byte((char *)(addr)) - -static inline unsigned short get_user_word(const short *addr) +static inline unsigned long __get_user(const void * y, int size) { - unsigned short _v; + unsigned long result; - __asm__ __volatile__ ("movesw %1,%0":"=r" (_v):"m" (*addr)); - return _v; + switch (size) { + case 1: + __asm__ ("movesb %1,%0" + :"=r" (result) + :"m" (*__ptr(y))); + return (unsigned char) result; + case 2: + __asm__ ("movesw %1,%0" + :"=r" (result) + :"m" (*__ptr(y))); + return (unsigned short) result; + case 4: + __asm__ ("movesl %1,%0" + :"=r" (result) + :"m" (*__ptr(y))); + return result; + default: + return bad_user_access_length(); + } } +#undef __ptr -#define get_fs_word(addr) get_user_word((short *)(addr)) +/* + * These are deprecated.. + * + * Use "put_user()" and "get_user()" with the proper pointer types instead. + */ -static inline unsigned long get_user_long(const int *addr) +#define get_fs_byte(addr) __get_user((const unsigned char *)(addr),1) +#define get_fs_word(addr) __get_user((const unsigned short *)(addr),2) +#define get_fs_long(addr) __get_user((const unsigned int *)(addr),4) + +#define put_fs_byte(x,addr) __put_user((x),(unsigned char *)(addr),1) +#define put_fs_word(x,addr) __put_user((x),(unsigned short *)(addr),2) +#define put_fs_long(x,addr) __put_user((x),(unsigned int *)(addr),4) + +#ifdef WE_REALLY_WANT_TO_USE_A_BROKEN_INTERFACE + +static inline unsigned char get_user_byte(const char * addr) { - unsigned long _v; + return __get_user(addr,1); +} - __asm__ __volatile__ ("movesl %1,%0":"=r" (_v):"m" (*addr)); \ - return _v; +static inline unsigned short get_user_word(const short *addr) +{ + return __get_user(addr,2); } -#define get_fs_long(addr) get_user_long((int *)(addr)) +static inline unsigned long get_user_long(const int *addr) +{ + return __get_user(addr,4); +} static inline void put_user_byte(char val,char *addr) { - __asm__ __volatile__ ("movesb %0,%1": /* no outputs */ :"r" (val),"m" (*addr) : "memory"); + __put_user(val, addr, 1); } -#define put_fs_byte(x,addr) put_user_byte((x),(char *)(addr)) - static inline void put_user_word(short val,short * addr) { - __asm__ __volatile__ ("movesw %0,%1": /* no outputs */ :"r" (val),"m" (*addr) : "memory"); + __put_user(val, addr, 2); } -#define put_fs_word(x,addr) put_user_word((x),(short *)(addr)) - static inline void put_user_long(unsigned long val,int * addr) { - __asm__ __volatile__ ("movesl %0,%1": /* no outputs */ :"r" (val),"m" (*addr) : "memory"); + __put_user(val, addr, 4); } -#define put_fs_long(x,addr) put_user_long((x),(int *)(addr)) +#endif static inline void __generic_memcpy_tofs(void * to, const void * from, unsigned long n) { + unsigned long tmp; if (n == 0) return; - __asm__ __volatile__ ("1:\n\t" - "moveb %1@+,d0\n\t" - "movesb d0,%2@+\n\t" + tmp = n; + n >>= 2; + if (n != 0) + __asm__ ("1:\t" + "movel %1@+,%/d0\n\t" + "movesl %/d0,%2@+\n\t" "dbra %0,1b\n\t" "clrw %0\n\t" "subql #1,%0\n\t" - "bccs 1b" + "bccs 1b\n\t" : "=d" (n), "=a" (from), "=a" (to) - : "1" (from), "2" (to), "0" (n-1) + : "0" (n-1), "1" (from), "2" (to) + : "d0", "memory"); + if (tmp & 2) + __asm__ ("movew %0@+,%/d0\n\t" + "movesw %/d0,%1@+\n\t" + : "=a" (from), "=a" (to) + : "0" (from), "1" (to) + : "d0", "memory"); + if (tmp & 1) + __asm__ ("moveb %0@,%/d0\n\t" + "movesb %/d0,%1@\n\t" + : /* no outputs */ + : "a" (from), "a" (to) : "d0", "memory"); } static inline void __constant_memcpy_tofs(void * to, const void * from, unsigned long n) { - if (n == 0) { - return; - } else if (n == 1) { - put_user_byte(*(const char *) from, (char *) to); - return; - } else if (n == 2) { - put_user_word(*(const short *) from, (short *) to); - return; - } else if (n == 3) { - put_user_word(*(const short *) from, (short *) to); - put_user_byte(*(2+(const char *) from), 2+(char *) to); - return; - } else if (n == 4) { - put_user_long(*(const int *) from, (int *) to); - return; - } -#if 0 -#define COMMON(x) \ -__asm__("cld\n\t" \ - "push %%es\n\t" \ - "push %%fs\n\t" \ - "pop %%es\n\t" \ - "rep ; movsl\n\t" \ - x \ - "pop %%es" \ - : /* no outputs */ \ - :"c" (n/4),"D" ((long) to),"S" ((long) from) \ - :"cx","di","si") - - switch (n % 4) { + switch (n) { case 0: - COMMON(""); return; case 1: - COMMON("movsb\n\t"); + __put_user(*(const char *) from, (char *) to, 1); return; case 2: - COMMON("movsw\n\t"); + __put_user(*(const short *) from, (short *) to, 2); return; case 3: - COMMON("movsw\n\tmovsb\n\t"); + __put_user(*(const short *) from, (short *) to, 2); + __put_user(*(2+(const char *) from), 2+(char *) to, 1); + return; + case 4: + __put_user(*(const int *) from, (int *) to, 4); + return; + case 8: + __put_user(*(const int *) from, (int *) to, 4); + __put_user(*(1+(const int *) from), 1+(int *) to, 4); + return; + case 12: + __put_user(*(const int *) from, (int *) to, 4); + __put_user(*(1+(const int *) from), 1+(int *) to, 4); + __put_user(*(2+(const int *) from), 2+(int *) to, 4); + return; + case 16: + __put_user(*(const int *) from, (int *) to, 4); + __put_user(*(1+(const int *) from), 1+(int *) to, 4); + __put_user(*(2+(const int *) from), 2+(int *) to, 4); + __put_user(*(3+(const int *) from), 3+(int *) to, 4); return; } +#define COMMON(x) \ +__asm__ __volatile__ ("1:\n\t" \ + "movel %1@+,%/d0\n\t" \ + "movesl %/d0,%2@+\n\t" \ + "dbra %0,1b\n\t" \ + "clrw %0\n\t" \ + "subql #1,%0\n\t" \ + "bccs 1b\n\t" \ + x \ + : "=d" (n), "=a" (from), "=a" (to) \ + : "1" (from), "2" (to), "0" (n/4-1) \ + : "d0", "memory"); + + switch (n % 4) { + case 0: + COMMON(""); + return; + case 1: + COMMON("moveb %1@+,%/d0; movesb %/d0,%2@+"); + return; + case 2: + COMMON("movew %1@+,%/d0; movesw %/d0,%2@+"); + return; + case 3: + COMMON("movew %1@+,%/d0; movesw %/d0,%2@+\n\t" + "moveb %1@+,%/d0; movesb %/d0,%2@+"); + return; + } #undef COMMON -#else - __generic_memcpy_tofs(to,from,n); -#endif } static inline void __generic_memcpy_fromfs(void * to, const void * from, unsigned long n) { + unsigned long tmp; if (n == 0) return; - __asm__ __volatile__ ("1:\n\t" - "movesb %1@+,d0\n\t" - "moveb d0,%2@+\n\t" + tmp = n; + n >>= 2; + if (n != 0) + __asm__ ("1:\t" + "movesl %1@+,%/d0\n\t" + "movel %/d0,%2@+\n\t" "dbra %0,1b\n\t" "clrw %0\n\t" "subql #1,%0\n\t" - "bccs 1b" + "bccs 1b\n\t" : "=d" (n), "=a" (from), "=a" (to) - : "1" (from), "2" (to), "0" (n-1) + : "0" (n-1), "1" (from), "2" (to) + : "d0", "memory"); + if (tmp & 2) + __asm__ ("movesw %0@+,%/d0\n\t" + "movew %/d0,%1@+\n\t" + : "=a" (from), "=a" (to) + : "0" (from), "1" (to) + : "d0", "memory"); + if (tmp & 1) + __asm__ ("movesb %0@,%/d0\n\t" + "moveb %/d0,%1@\n\t" + : /* no outputs */ + : "a" (from), "a" (to) : "d0", "memory"); } static inline void __constant_memcpy_fromfs(void * to, const void * from, unsigned long n) { - if (n == 0) { - return; - } else if (n == 1) { - *(char *)to = get_user_byte((const char *) from); - return; - } else if (n == 2) { - *(short *)to = get_user_word((const short *) from); - return; - } else if (n == 3) { - *(short *) to = get_user_word((const short *) from); - *(2+(char *) to) = get_user_byte(2+(const char *) from); - return; - } else if (n == 4) { - *(int *) to = get_user_long((const int *) from); - return; - } -#if 0 -#define COMMON(x) \ -__asm__("cld\n\t" \ - "rep ; fs ; movsl\n\t" \ - x \ - : /* no outputs */ \ - :"c" (n/4),"D" ((long) to),"S" ((long) from) \ - :"cx","di","si","memory") - - switch (n % 4) { + switch (n) { case 0: - COMMON(""); return; case 1: - COMMON("fs ; movsb"); + *(char *)to = __get_user((const char *) from, 1); return; case 2: - COMMON("fs ; movsw"); + *(short *)to = __get_user((const short *) from, 2); return; case 3: - COMMON("fs ; movsw\n\tfs ; movsb"); + *(short *) to = __get_user((const short *) from, 2); + *((char *) to + 2) = __get_user(2+(const char *) from, 1); + return; + case 4: + *(int *) to = __get_user((const int *) from, 4); + return; + case 8: + *(int *) to = __get_user((const int *) from, 4); + *(1+(int *) to) = __get_user(1+(const int *) from, 4); + return; + case 12: + *(int *) to = __get_user((const int *) from, 4); + *(1+(int *) to) = __get_user(1+(const int *) from, 4); + *(2+(int *) to) = __get_user(2+(const int *) from, 4); + return; + case 16: + *(int *) to = __get_user((const int *) from, 4); + *(1+(int *) to) = __get_user(1+(const int *) from, 4); + *(2+(int *) to) = __get_user(2+(const int *) from, 4); + *(3+(int *) to) = __get_user(3+(const int *) from, 4); return; } +#define COMMON(x) \ +__asm__ __volatile__ ("1:\n\t" \ + "movesl %1@+,%/d0\n\t" \ + "movel %/d0,%2@+\n\t" \ + "dbra %0,1b\n\t" \ + "clrw %0\n\t" \ + "subql #1,%0\n\t" \ + "bccs 1b\n\t" \ + x \ + : "=d" (n), "=a" (from), "=a" (to) \ + : "1" (from), "2" (to), "0" (n/4-1) \ + : "d0", "memory"); + + switch (n % 4) { + case 0: + COMMON(""); + return; + case 1: + COMMON("movesb %1@+,%/d0; moveb %/d0,%2@+"); + return; + case 2: + COMMON("movesw %1@+,%/d0; movew %/d0,%2@+"); + return; + case 3: + COMMON("movesw %1@+,%/d0; movew %/d0,%2@+\n\t" + "movesb %1@+,%/d0; moveb %/d0,%2@+"); + return; + } #undef COMMON -#else - __generic_memcpy_fromfs(to,from,n); -#endif } #define memcpy_fromfs(to, from, n) \ @@ -211,7 +340,7 @@ static inline unsigned long get_fs(void) { unsigned long _v; - __asm__ ("movec dfc,%0":"=r" (_v):); + __asm__ ("movec %/dfc,%0":"=r" (_v):); return _v; } @@ -219,23 +348,16 @@ static inline unsigned long get_ds(void) { /* return the supervisor data space code */ - return 0x5; + return KERNEL_DS; } static inline void set_fs(unsigned long val) { - __asm__ __volatile__ ("movec %0,sfc\n\t" - "movec %0,dfc\n\t" - : /* no outputs */ : "r" (val), "r" (val) : "memory"); + __asm__ __volatile__ ("movec %0,%/sfc\n\t" + "movec %0,%/dfc\n\t" + : /* no outputs */ : "r" (val) : "memory"); } -/* define constants */ -/* Address spaces (FC0-FC2) */ -#ifndef USER_DS -#define USER_DS (1) -#endif -#ifndef KERNEL_DS -#define KERNEL_DS (5) -#endif +#endif /* __ASSEMBLY__ */ #endif /* _M68K_SEGMENT_H */ diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/shm.h linux/include/asm-m68k/shm.h --- v1.3.93/linux/include/asm-m68k/shm.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/shm.h Wed Dec 27 22:47:22 1995 @@ -0,0 +1,24 @@ +#ifndef _M68K_SHM_H +#define _M68K_SHM_H + +/* format of page table entries that correspond to shared memory pages + currently out in swap space (see also mm/swap.c): + bits 0-1 (PAGE_PRESENT) is = 0 + bits 8..2 (SWP_TYPE) are = SHM_SWP_TYPE + bits 31..9 are used like this: + bits 15..9 (SHM_ID) the id of the shared memory segment + bits 30..16 (SHM_IDX) the index of the page within the shared memory segment + (actually only bits 25..16 get used since SHMMAX is so low) + bit 31 (SHM_READ_ONLY) flag whether the page belongs to a read-only attach +*/ +/* on the m68k both bits 0 and 1 must be zero */ + +#define SHM_ID_SHIFT 9 +#define _SHM_ID_BITS 7 +#define SHM_ID_MASK ((1<<_SHM_ID_BITS)-1) + +#define SHM_IDX_SHIFT (SHM_ID_SHIFT+_SHM_ID_BITS) +#define _SHM_IDX_BITS 15 +#define SHM_IDX_MASK ((1<<_SHM_IDX_BITS)-1) + +#endif /* _M68K_SHM_H */ diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/shmparam.h linux/include/asm-m68k/shmparam.h --- v1.3.93/linux/include/asm-m68k/shmparam.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/shmparam.h Sat Mar 30 14:11:42 1996 @@ -0,0 +1,44 @@ +#ifndef _M68K_SHMPARAM_H +#define _M68K_SHMPARAM_H + +/* address range for shared memory attaches if no address passed to shmat() */ +#define SHM_RANGE_START 0xC0000000 +#define SHM_RANGE_END 0xD0000000 + +/* + * Format of a swap-entry for shared memory pages currently out in + * swap space (see also mm/swap.c). + * + * SWP_TYPE = SHM_SWP_TYPE + * SWP_OFFSET is used as follows: + * + * bits 0..6 : id of shared memory segment page belongs to (SHM_ID) + * bits 7..21: index of page within shared memory segment (SHM_IDX) + * (actually fewer bits get used since SHMMAX is so low) + */ + +/* + * Keep _SHM_ID_BITS as low as possible since SHMMNI depends on it and + * there is a static array of size SHMMNI. + */ +#define _SHM_ID_BITS 7 +#define SHM_ID_MASK ((1<<_SHM_ID_BITS)-1) + +#define SHM_IDX_SHIFT (_SHM_ID_BITS) +#define _SHM_IDX_BITS 15 +#define SHM_IDX_MASK ((1<<_SHM_IDX_BITS)-1) + +/* + * _SHM_ID_BITS + _SHM_IDX_BITS must be <= 24 on the i386 and + * SHMMAX <= (PAGE_SIZE << _SHM_IDX_BITS). + */ + +#define SHMMAX 0x1000000 /* max shared seg size (bytes) */ +#define SHMMIN 1 /* really PAGE_SIZE */ /* min shared seg size (bytes) */ +#define SHMMNI (1<<_SHM_ID_BITS) /* max num of segs system wide */ +#define SHMALL /* max shm system wide (pages) */ \ + (1<<(_SHM_IDX_BITS+_SHM_ID_BITS)) +#define SHMLBA PAGE_SIZE /* attach addr a multiple of this */ +#define SHMSEG SHMMNI /* max shared segs per process */ + +#endif /* _M68K_SHMPARAM_H */ diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/sigcontext.h linux/include/asm-m68k/sigcontext.h --- v1.3.93/linux/include/asm-m68k/sigcontext.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/sigcontext.h Thu Mar 7 20:28:49 1996 @@ -0,0 +1,19 @@ +#ifndef _ASMm68k_SIGCONTEXT_H +#define _ASMm68k_SIGCONTEXT_H + +struct sigcontext_struct { + unsigned long sc_mask; /* old sigmask */ + unsigned long sc_usp; /* old user stack pointer */ + unsigned long sc_d0; + unsigned long sc_d1; + unsigned long sc_a0; + unsigned long sc_a1; + unsigned short sc_sr; + unsigned long sc_pc; + unsigned short sc_formatvec; + unsigned long sc_fpregs[2*3]; /* room for two fp registers */ + unsigned long sc_fpcntl[3]; + unsigned char sc_fpstate[216]; +}; + +#endif diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/signal.h linux/include/asm-m68k/signal.h --- v1.3.93/linux/include/asm-m68k/signal.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/signal.h Tue Apr 9 00:36:14 1996 @@ -0,0 +1,96 @@ +#ifndef _M68K_SIGNAL_H +#define _M68K_SIGNAL_H + +typedef unsigned long sigset_t; /* at least 32 bits */ + +#define _NSIG 32 +#define NSIG _NSIG + +#define SIGHUP 1 +#define SIGINT 2 +#define SIGQUIT 3 +#define SIGILL 4 +#define SIGTRAP 5 +#define SIGABRT 6 +#define SIGIOT 6 +#define SIGBUS 7 +#define SIGFPE 8 +#define SIGKILL 9 +#define SIGUSR1 10 +#define SIGSEGV 11 +#define SIGUSR2 12 +#define SIGPIPE 13 +#define SIGALRM 14 +#define SIGTERM 15 +#define SIGSTKFLT 16 +#define SIGCHLD 17 +#define SIGCONT 18 +#define SIGSTOP 19 +#define SIGTSTP 20 +#define SIGTTIN 21 +#define SIGTTOU 22 +#define SIGURG 23 +#define SIGXCPU 24 +#define SIGXFSZ 25 +#define SIGVTALRM 26 +#define SIGPROF 27 +#define SIGWINCH 28 +#define SIGIO 29 +#define SIGPOLL SIGIO +/* +#define SIGLOST 29 +*/ +#define SIGPWR 30 +#define SIGUNUSED 31 + +/* + * sa_flags values: SA_STACK is not currently supported, but will allow the + * usage of signal stacks by using the (now obsolete) sa_restorer field in + * the sigaction structure as a stack pointer. This is now possible due to + * the changes in signal handling. LBT 010493. + * SA_INTERRUPT is a no-op, but left due to historical reasons. Use the + * SA_RESTART flag to get restarting signals (which were the default long ago) + * SA_SHIRQ flag is for shared interrupt support on PCI and EISA. + */ +#define SA_NOCLDSTOP 1 +#define SA_SHIRQ 0x04000000 +#define SA_STACK 0x08000000 +#define SA_RESTART 0x10000000 +#define SA_INTERRUPT 0x20000000 +#define SA_NOMASK 0x40000000 +#define SA_ONESHOT 0x80000000 + +#ifdef __KERNEL__ +/* + * These values of sa_flags are used only by the kernel as part of the + * irq handling routines. + * + * SA_INTERRUPT is also used by the irq handling routines. + */ +#define SA_PROBE SA_ONESHOT +#define SA_SAMPLE_RANDOM SA_RESTART +#endif + +#define SIG_BLOCK 0 /* for blocking signals */ +#define SIG_UNBLOCK 1 /* for unblocking signals */ +#define SIG_SETMASK 2 /* for setting the signal mask */ + +/* Type of a signal handler. */ +typedef void (*__sighandler_t)(int); + +#define SIG_DFL ((__sighandler_t)0) /* default signal handling */ +#define SIG_IGN ((__sighandler_t)1) /* ignore signal */ +#define SIG_ERR ((__sighandler_t)-1) /* error return from signal */ + +struct sigaction { + __sighandler_t sa_handler; + sigset_t sa_mask; + unsigned long sa_flags; + void (*sa_restorer)(void); +}; + +#ifdef __KERNEL__ +#include +#endif + +#endif /* _M68K_SIGNAL_H */ diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/socket.h linux/include/asm-m68k/socket.h --- v1.3.93/linux/include/asm-m68k/socket.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/socket.h Fri Apr 5 14:08:26 1996 @@ -0,0 +1,25 @@ +#ifndef _ASM_SOCKET_H +#define _ASM_SOCKET_H + +#include + +/* For setsockoptions(2) */ +#define SOL_SOCKET 1 + +#define SO_DEBUG 1 +#define SO_REUSEADDR 2 +#define SO_TYPE 3 +#define SO_ERROR 4 +#define SO_DONTROUTE 5 +#define SO_BROADCAST 6 +#define SO_SNDBUF 7 +#define SO_RCVBUF 8 +#define SO_KEEPALIVE 9 +#define SO_OOBINLINE 10 +#define SO_NO_CHECK 11 +#define SO_PRIORITY 12 +#define SO_LINGER 13 +#define SO_BSDCOMPAT 14 +/* To add :#define SO_REUSEPORT 15 */ + +#endif /* _ASM_SOCKET_H */ diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/sockios.h linux/include/asm-m68k/sockios.h --- v1.3.93/linux/include/asm-m68k/sockios.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/sockios.h Fri Apr 5 14:08:30 1996 @@ -0,0 +1,12 @@ +#ifndef __ARCH_M68K_SOCKIOS__ +#define __ARCH_M68K_SOCKIOS__ + +/* Socket-level I/O control calls. */ +#define FIOSETOWN 0x8901 +#define SIOCSPGRP 0x8902 +#define FIOGETOWN 0x8903 +#define SIOCGPGRP 0x8904 +#define SIOCATMARK 0x8905 +#define SIOCGSTAMP 0x8906 /* Get stamp */ + +#endif /* __ARCH_M68K_SOCKIOS__ */ diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/stat.h linux/include/asm-m68k/stat.h --- v1.3.93/linux/include/asm-m68k/stat.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/stat.h Wed Dec 27 22:47:26 1995 @@ -0,0 +1,41 @@ +#ifndef _M68K_STAT_H +#define _M68K_STAT_H + +struct old_stat { + unsigned short st_dev; + unsigned short st_ino; + unsigned short st_mode; + unsigned short st_nlink; + unsigned short st_uid; + unsigned short st_gid; + unsigned short st_rdev; + unsigned long st_size; + unsigned long st_atime; + unsigned long st_mtime; + unsigned long st_ctime; +}; + +struct new_stat { + unsigned short st_dev; + unsigned short __pad1; + unsigned long st_ino; + unsigned short st_mode; + unsigned short st_nlink; + unsigned short st_uid; + unsigned short st_gid; + unsigned short st_rdev; + unsigned short __pad2; + unsigned long st_size; + unsigned long st_blksize; + unsigned long st_blocks; + unsigned long st_atime; + unsigned long __unused1; + unsigned long st_mtime; + unsigned long __unused2; + unsigned long st_ctime; + unsigned long __unused3; + unsigned long __unused4; + unsigned long __unused5; +}; + +#endif /* _M68K_STAT_H */ diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/statfs.h linux/include/asm-m68k/statfs.h --- v1.3.93/linux/include/asm-m68k/statfs.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/statfs.h Wed Dec 27 22:47:26 1995 @@ -0,0 +1,21 @@ +#ifndef _M68K_STATFS_H +#define _M68K_STATFS_H + +typedef struct { + long val[2]; +} fsid_t; + +struct statfs { + long f_type; + long f_bsize; + long f_blocks; + long f_bfree; + long f_bavail; + long f_files; + long f_ffree; + fsid_t f_fsid; + long f_namelen; + long f_spare[6]; +}; + +#endif /* _M68K_STATFS_H */ diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/string.h linux/include/asm-m68k/string.h --- v1.3.93/linux/include/asm-m68k/string.h Sat Jan 7 12:39:37 1995 +++ linux/include/asm-m68k/string.h Sat Mar 30 14:11:50 1996 @@ -1,20 +1,20 @@ #ifndef _M68K_STRING_H_ #define _M68K_STRING_H_ -#define __USE_PORTABLE_STRINGS_H_ - +#define __HAVE_ARCH_STRCPY extern inline char * strcpy(char * dest,const char *src) { char *xdest = dest; __asm__ __volatile__ ("1:\tmoveb %1@+,%0@+\n\t" - "bne 1b" + "jne 1b" : "=a" (dest), "=a" (src) : "0" (dest), "1" (src) : "memory"); return xdest; } +#define __HAVE_ARCH_STRNCPY extern inline char * strncpy(char *dest, const char *src, size_t n) { char *xdest = dest; @@ -24,9 +24,9 @@ __asm__ __volatile__ ("1:\tmoveb %1@+,%0@+\n\t" - "beq 2f\n\t" + "jeq 2f\n\t" "subql #1,%2\n\t" - "bne 1b\n\t" + "jne 1b\n\t" "2:" : "=a" (dest), "=a" (src), "=d" (n) : "0" (dest), "1" (src), "2" (n) @@ -34,10 +34,116 @@ return xdest; } -#define __USE_PORTABLE_strcat +#define __HAVE_ARCH_STRCAT +extern inline char * strcat(char * dest, const char * src) +{ + char *tmp = dest; + + while (*dest) + dest++; + while ((*dest++ = *src++)) + ; + + return tmp; +} + +#define __HAVE_ARCH_STRNCAT +extern inline char * strncat(char *dest, const char *src, size_t count) +{ + char *tmp = dest; + + if (count) { + while (*dest) + dest++; + while ((*dest++ = *src++)) { + if (--count == 0) { + *dest++='\0'; + break; + } + } + } + + return tmp; +} + +#define __HAVE_ARCH_STRCHR +extern inline char * strchr(const char * s, int c) +{ + const char ch = c; + + for(; *s != ch; ++s) + if (*s == '\0') + return( NULL ); + return( (char *) s); +} + +#define __HAVE_ARCH_STRPBRK +extern inline char * strpbrk(const char * cs,const char * ct) +{ + const char *sc1,*sc2; + + for( sc1 = cs; *sc1 != '\0'; ++sc1) + for( sc2 = ct; *sc2 != '\0'; ++sc2) + if (*sc1 == *sc2) + return((char *) sc1); + return( NULL ); +} + +#define __HAVE_ARCH_STRSPN +extern inline size_t strspn(const char *s, const char *accept) +{ + const char *p; + const char *a; + size_t count = 0; + + for (p = s; *p != '\0'; ++p) + { + for (a = accept; *a != '\0'; ++a) + if (*p == *a) + break; + if (*a == '\0') + return count; + else + ++count; + } + + return count; +} + +#define __HAVE_ARCH_STRTOK +extern inline char * strtok(char * s,const char * ct) +{ + char *sbegin, *send; + + sbegin = s ? s : ___strtok; + if (!sbegin) { + return NULL; + } + sbegin += strspn(sbegin,ct); + if (*sbegin == '\0') { + ___strtok = NULL; + return( NULL ); + } + send = strpbrk( sbegin, ct); + if (send && *send != '\0') + *send++ = '\0'; + ___strtok = send; + return (sbegin); +} + +/* strstr !! */ + +#define __HAVE_ARCH_STRLEN +extern inline size_t strlen(const char * s) +{ + const char *sc; + for (sc = s; *sc != '\0'; ++sc) ; + return(sc - s); +} -#define __USE_PORTABLE_strncat +/* strnlen !! */ +#define __HAVE_ARCH_STRCMP extern inline int strcmp(const char * cs,const char * ct) { char __res; @@ -45,10 +151,10 @@ __asm__ ("1:\tmoveb %0@+,%2\n\t" /* get *cs */ "cmpb %1@+,%2\n\t" /* compare a byte */ - "bne 2f\n\t" /* not equal, break out */ + "jne 2f\n\t" /* not equal, break out */ "tstb %2\n\t" /* at end of cs? */ - "bne 1b\n\t" /* no, keep going */ - "bra 3f\n\t" /* strings are equal */ + "jne 1b\n\t" /* no, keep going */ + "jra 3f\n\t" /* strings are equal */ "2:\tsubb %1@-,%2\n\t" /* *cs - *ct */ "3:" : "=a" (cs), "=a" (ct), "=d" (__res) @@ -56,6 +162,7 @@ return __res; } +#define __HAVE_ARCH_STRNCMP extern inline int strncmp(const char * cs,const char * ct,size_t count) { char __res; @@ -65,13 +172,13 @@ __asm__ ("1:\tmovb %0@+,%3\n\t" /* get *cs */ "cmpb %1@+,%3\n\t" /* compare a byte */ - "bne 3f\n\t" /* not equal, break out */ + "jne 3f\n\t" /* not equal, break out */ "tstb %3\n\t" /* at end of cs? */ - "beq 4f\n\t" /* yes, all done */ + "jeq 4f\n\t" /* yes, all done */ "subql #1,%2\n\t" /* no, adjust count */ - "bne 1b\n\t" /* more to do, keep going */ + "jne 1b\n\t" /* more to do, keep going */ "2:\tmoveq #0,%3\n\t" /* strings are equal */ - "bra 4f\n\t" + "jra 4f\n\t" "3:\tsubb %1@-,%3\n\t" /* *cs - *ct */ "4:" : "=a" (cs), "=a" (ct), "=d" (count), "=d" (__res) @@ -79,76 +186,173 @@ return __res; } -#define __USE_PORTABLE_strchr - -#define __USE_PORTABLE_strlen - -#define __USE_PORTABLE_strspn - -#define __USE_PORTABLE_strpbrk - -#define __USE_PORTABLE_strtok - -extern inline void * memset(void * s,char c,size_t count) +#define __HAVE_ARCH_MEMSET +extern inline void * memset(void * s,int c,size_t count) { void *xs = s; + size_t temp; if (!count) return xs; - __asm__ __volatile__ - ("1:\tmoveb %3,%0@+\n\t" - "subql #1,%1\n\t" - "bne 1b" - : "=a" (s), "=d" (count) - : "0" (s), "d" (c), "1" (count) - : "memory"); + c &= 0xff; + if ((long) s & 1) + { + char *cs = s; + *cs++ = c; + s = cs; + count--; + } + c |= c << 8; + if (count > 2 && (long) s & 2) + { + short *ss = s; + *ss++ = c; + s = ss; + count -= 2; + } + temp = count >> 2; + if (temp) + { + long *ls = s; + c |= c << 16; + temp--; + do + *ls++ = c; + while (temp--); + s = ls; + } + if (count & 2) + { + short *ss = s; + *ss++ = c; + s = ss; + } + if (count & 1) + { + char *cs = s; + *cs = c; + } return xs; } -extern inline void * memcpy(void * to, const void * from, size_t n) -{ - void *xto = to; - - if (!n) - return xto; - __asm__ __volatile__ - ("1:\tmoveb %1@+,%0@+\n\t" - "subql #1,%2\n\t" - "bne 1b" - : "=a" (to), "=a" (from), "=d" (n) - : "0" (to), "1" (from), "2" (n) - : "memory" ); - return xto; -} +#define __HAVE_ARCH_MEMCPY +#define memcpy(to, from, n) \ +(__builtin_constant_p(n) ? \ + __builtin_memcpy((to),(from),(n)) : \ + memcpy((to),(from),(n))) +#define __HAVE_ARCH_MEMMOVE extern inline void * memmove(void * dest,const void * src, size_t n) { void *xdest = dest; + size_t temp; if (!n) return xdest; if (dest < src) - __asm__ __volatile__ - ("1:\tmoveb %1@+,%0@+\n\t" - "subql #1,%2\n\t" - "bne 1b" - : "=a" (dest), "=a" (src), "=d" (n) - : "0" (dest), "1" (src), "2" (n) - : "memory" ); + { + if ((long) dest & 1) + { + char *cdest = dest; + const char *csrc = src; + *cdest++ = *csrc++; + dest = cdest; + src = csrc; + n--; + } + if (n > 2 && (long) dest & 2) + { + short *sdest = dest; + const short *ssrc = src; + *sdest++ = *ssrc++; + dest = sdest; + src = ssrc; + n -= 2; + } + temp = n >> 2; + if (temp) + { + long *ldest = dest; + const long *lsrc = src; + temp--; + do + *ldest++ = *lsrc++; + while (temp--); + dest = ldest; + src = lsrc; + } + if (n & 2) + { + short *sdest = dest; + const short *ssrc = src; + *sdest++ = *ssrc++; + dest = sdest; + src = ssrc; + } + if (n & 1) + { + char *cdest = dest; + const char *csrc = src; + *cdest = *csrc; + } + } else - __asm__ __volatile__ - ("1:\tmoveb %1@-,%0@-\n\t" - "subql #1,%2\n\t" - "bne 1b" - : "=a" (dest), "=a" (src), "=d" (n) - : "0" (dest+n), "1" (src+n), "2" (n) - : "memory" ); + { + dest = (char *) dest + n; + src = (const char *) src + n; + if ((long) dest & 1) + { + char *cdest = dest; + const char *csrc = src; + *--cdest = *--csrc; + dest = cdest; + src = csrc; + n--; + } + if (n > 2 && (long) dest & 2) + { + short *sdest = dest; + const short *ssrc = src; + *--sdest = *--ssrc; + dest = sdest; + src = ssrc; + n -= 2; + } + temp = n >> 2; + if (temp) + { + long *ldest = dest; + const long *lsrc = src; + temp--; + do + *--ldest = *--lsrc; + while (temp--); + dest = ldest; + src = lsrc; + } + if (n & 2) + { + short *sdest = dest; + const short *ssrc = src; + *--sdest = *--ssrc; + dest = sdest; + src = ssrc; + } + if (n & 1) + { + char *cdest = dest; + const char *csrc = src; + *--cdest = *--csrc; + } + } return xdest; } -#define __USE_PORTABLE_memcmp - -#define __USE_PORTABLE_memscan +#define __HAVE_ARCH_MEMCMP +#define memcmp(cs, ct, n) \ +(__builtin_constant_p(n) ? \ + __builtin_memcmp((cs),(ct),(n)) : \ + memcmp((cs),(ct),(n))) #endif /* _M68K_STRING_H_ */ diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/system.h linux/include/asm-m68k/system.h --- v1.3.93/linux/include/asm-m68k/system.h Thu Jan 5 13:47:08 1995 +++ linux/include/asm-m68k/system.h Sun Mar 31 18:38:57 1996 @@ -1,53 +1,140 @@ +#ifndef _M68K_SYSTEM_H +#define _M68K_SYSTEM_H + +#include /* get configuration macros */ +#include +#include + +extern inline unsigned long rdusp(void) { + unsigned long usp; + + __asm__ __volatile__("movec %/usp,%0" + : "=d" (usp)); + return usp; +} + +extern inline void wrusp(unsigned long usp) { + __asm__ __volatile__("movec %0,%/usp" + : + : "d" (usp)); +} + /* - * linux/include/asm-m68k/system.h - * - * Copyright (C) 1991, 1992 Linus Torvalds - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file README.legal in the main directory of this archive - * for more details. + * switch_to(n) should switch tasks to task ptr, first checking that + * ptr isn't the current task, in which case it does nothing. This + * also clears the TS-flag if the task we switched to has used the + * math co-processor latest. */ - /* - * 680x0 support added by Hamish Macdonald + * switch_to() saves the extra registers, that are not saved + * automatically by SAVE_SWITCH_STACK in resume(), ie. d0-d5 and + * a0-a1. Some of these are used by schedule() and its predecessors + * and so we might get see unexpected behaviors when a task returns + * with unexpected register values. + * + * syscall stores these regsiters itself and none of them are used + * by syscall after the function in the syscall has been called. + * + * Beware that resume now expects *next to be in d1 and the offset of + * tss to be in a1. This saves a few instructions as we no longer have + * to push them onto the stack and read them back right after. + * + * 02/17/96 - Jes Sorensen (jds@kom.auc.dk) */ +asmlinkage void resume(void); +#define switch_to(prev,next) { \ + register int k __asm__ ("a1") = (int)&((struct task_struct *)0)->tss; \ + register int n __asm__ ("d1") = (int)next; \ + __asm__ __volatile__("jbsr " SYMBOL_NAME_STR(resume) "\n\t" \ + : : "a" (k), "d" (n) \ + : "d0", "d1", "d2", "d3", "d4", "d5", "a0", "a1"); \ +} -#ifndef _M68K_SYSTEM_H -#define _M68K_SYSTEM_H +#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) +#define tas(ptr) (xchg((ptr),1)) -#include /* get configuration macros */ +struct __xchg_dummy { unsigned long a[100]; }; +#define __xg(x) ((volatile struct __xchg_dummy *)(x)) #if defined(CONFIG_ATARI) && !defined(CONFIG_AMIGA) && !defined(CONFIG_MAC) /* block out HSYNC on the atari */ -#define sti() __asm__ __volatile__ ("andiw #0xfbff,sr": : : "memory") +#define sti() __asm__ __volatile__ ("andiw #0xfbff,%/sr": : : "memory") #else /* portable version */ -#define sti() __asm__ __volatile__ ("andiw #0xf8ff,sr": : : "memory") +#define sti() __asm__ __volatile__ ("andiw #0xf8ff,%/sr": : : "memory") #endif /* machine compilation types */ -#define cli() __asm__ __volatile__ ("oriw #0x0700,sr": : : "memory") +#define cli() __asm__ __volatile__ ("oriw #0x0700,%/sr": : : "memory") #define nop() __asm__ __volatile__ ("nop"::) #define save_flags(x) \ -__asm__ __volatile__("movew sr,%0":"=d" (x) : /* no input */ :"memory") +__asm__ __volatile__("movew %/sr,%0":"=d" (x) : /* no input */ :"memory") #define restore_flags(x) \ -__asm__ __volatile__("movew %0,sr": /* no outputs */ :"d" (x) : "memory") +__asm__ __volatile__("movew %0,%/sr": /* no outputs */ :"d" (x) : "memory") #define iret() __asm__ __volatile__ ("rte": : :"memory", "sp", "cc") -#define move_to_user_mode() \ - __asm__ __volatile__ ("movel sp,usp\n\t" /* setup user sp */ \ - "movec %0,msp\n\t" /* setup kernel sp */ \ - "andiw #0xdfff,sr" /* return to user mode */ \ - : /* no output */ \ - : "r" (current->kernel_stack_page + PAGE_SIZE) \ - : "memory", "sp") - -static inline void clear_fpu(void) { - unsigned long nilstate = 0; - __asm__ __volatile__ ("frestore %0@" : : "a" (&nilstate)); +#if 1 +static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size) +{ + unsigned long tmp, flags; + + save_flags(flags); + cli(); + + switch (size) { + case 1: + __asm__ __volatile__ + ("moveb %2,%0\n\t" + "moveb %1,%2" + : "=&d" (tmp) : "d" (x), "m" (*__xg(ptr)) : "memory"); + break; + case 2: + __asm__ __volatile__ + ("movew %2,%0\n\t" + "movew %1,%2" + : "=&d" (tmp) : "d" (x), "m" (*__xg(ptr)) : "memory"); + break; + case 4: + __asm__ __volatile__ + ("movel %2,%0\n\t" + "movel %1,%2" + : "=&d" (tmp) : "d" (x), "m" (*__xg(ptr)) : "memory"); + break; + } + restore_flags(flags); + return tmp; } - -#define halt() \ - __asm__ __volatile__ ("halt") +#else +static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size) +{ + switch (size) { + case 1: + __asm__ __volatile__ + ("moveb %2,%0\n\t" + "1:\n\t" + "casb %0,%1,%2\n\t" + "jne 1b" + : "=&d" (x) : "d" (x), "m" (*__xg(ptr)) : "memory"); + break; + case 2: + __asm__ __volatile__ + ("movew %2,%0\n\t" + "1:\n\t" + "casw %0,%1,%2\n\t" + "jne 1b" + : "=&d" (x) : "d" (x), "m" (*__xg(ptr)) : "memory"); + break; + case 4: + __asm__ __volatile__ + ("movel %2,%0\n\t" + "1:\n\t" + "casl %0,%1,%2\n\t" + "jne 1b" + : "=&d" (x) : "d" (x), "m" (*__xg(ptr)) : "memory"); + break; + } + return x; +} +#endif #endif /* _M68K_SYSTEM_H */ diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/termbits.h linux/include/asm-m68k/termbits.h --- v1.3.93/linux/include/asm-m68k/termbits.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/termbits.h Fri Apr 5 14:51:56 1996 @@ -0,0 +1,161 @@ +#ifndef __ARCH_M68K_TERMBITS_H__ +#define __ARCH_M68K_TERMBITS_H__ + +#include + +typedef unsigned char cc_t; +typedef unsigned int speed_t; +typedef unsigned int tcflag_t; + +#define NCCS 19 +struct termios { + tcflag_t c_iflag; /* input mode flags */ + tcflag_t c_oflag; /* output mode flags */ + tcflag_t c_cflag; /* control mode flags */ + tcflag_t c_lflag; /* local mode flags */ + cc_t c_line; /* line discipline */ + cc_t c_cc[NCCS]; /* control characters */ +}; + +/* c_cc characters */ +#define VINTR 0 +#define VQUIT 1 +#define VERASE 2 +#define VKILL 3 +#define VEOF 4 +#define VTIME 5 +#define VMIN 6 +#define VSWTC 7 +#define VSTART 8 +#define VSTOP 9 +#define VSUSP 10 +#define VEOL 11 +#define VREPRINT 12 +#define VDISCARD 13 +#define VWERASE 14 +#define VLNEXT 15 +#define VEOL2 16 + + +/* c_iflag bits */ +#define IGNBRK 0000001 +#define BRKINT 0000002 +#define IGNPAR 0000004 +#define PARMRK 0000010 +#define INPCK 0000020 +#define ISTRIP 0000040 +#define INLCR 0000100 +#define IGNCR 0000200 +#define ICRNL 0000400 +#define IUCLC 0001000 +#define IXON 0002000 +#define IXANY 0004000 +#define IXOFF 0010000 +#define IMAXBEL 0020000 + +/* c_oflag bits */ +#define OPOST 0000001 +#define OLCUC 0000002 +#define ONLCR 0000004 +#define OCRNL 0000010 +#define ONOCR 0000020 +#define ONLRET 0000040 +#define OFILL 0000100 +#define OFDEL 0000200 +#define NLDLY 0000400 +#define NL0 0000000 +#define NL1 0000400 +#define CRDLY 0003000 +#define CR0 0000000 +#define CR1 0001000 +#define CR2 0002000 +#define CR3 0003000 +#define TABDLY 0014000 +#define TAB0 0000000 +#define TAB1 0004000 +#define TAB2 0010000 +#define TAB3 0014000 +#define XTABS 0014000 +#define BSDLY 0020000 +#define BS0 0000000 +#define BS1 0020000 +#define VTDLY 0040000 +#define VT0 0000000 +#define VT1 0040000 +#define FFDLY 0100000 +#define FF0 0000000 +#define FF1 0100000 + +/* c_cflag bit meaning */ +#define CBAUD 0010017 +#define B0 0000000 /* hang up */ +#define B50 0000001 +#define B75 0000002 +#define B110 0000003 +#define B134 0000004 +#define B150 0000005 +#define B200 0000006 +#define B300 0000007 +#define B600 0000010 +#define B1200 0000011 +#define B1800 0000012 +#define B2400 0000013 +#define B4800 0000014 +#define B9600 0000015 +#define B19200 0000016 +#define B38400 0000017 +#define EXTA B19200 +#define EXTB B38400 +#define CSIZE 0000060 +#define CS5 0000000 +#define CS6 0000020 +#define CS7 0000040 +#define CS8 0000060 +#define CSTOPB 0000100 +#define CREAD 0000200 +#define PARENB 0000400 +#define PARODD 0001000 +#define HUPCL 0002000 +#define CLOCAL 0004000 +#define CBAUDEX 0010000 +#define B57600 0010001 +#define B115200 0010002 +#define B230400 0010003 +#define CIBAUD 002003600000 /* input baud rate (not used) */ +#define CRTSCTS 020000000000 /* flow control */ + +/* c_lflag bits */ +#define ISIG 0000001 +#define ICANON 0000002 +#define XCASE 0000004 +#define ECHO 0000010 +#define ECHOE 0000020 +#define ECHOK 0000040 +#define ECHONL 0000100 +#define NOFLSH 0000200 +#define TOSTOP 0000400 +#define ECHOCTL 0001000 +#define ECHOPRT 0002000 +#define ECHOKE 0004000 +#define FLUSHO 0010000 +#define PENDIN 0040000 +#define IEXTEN 0100000 + + +/* tcflow() and TCXONC use these */ +#define TCOOFF 0 +#define TCOON 1 +#define TCIOFF 2 +#define TCION 3 + +/* tcflush() and TCFLSH use these */ +#define TCIFLUSH 0 +#define TCOFLUSH 1 +#define TCIOFLUSH 2 + +/* tcsetattr uses these */ +#define TCSANOW 0 +#define TCSADRAIN 1 +#define TCSAFLUSH 2 + +#endif /* __ARCH_M68K_TERMBITS_H__ */ diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/termios.h linux/include/asm-m68k/termios.h --- v1.3.93/linux/include/asm-m68k/termios.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/termios.h Fri Apr 5 14:52:09 1996 @@ -0,0 +1,89 @@ +#ifndef _M68K_TERMIOS_H +#define _M68K_TERMIOS_H + +#include +#include + +struct winsize { + unsigned short ws_row; + unsigned short ws_col; + unsigned short ws_xpixel; + unsigned short ws_ypixel; +}; + +#define NCC 8 +struct termio { + unsigned short c_iflag; /* input mode flags */ + unsigned short c_oflag; /* output mode flags */ + unsigned short c_cflag; /* control mode flags */ + unsigned short c_lflag; /* local mode flags */ + unsigned char c_line; /* line discipline */ + unsigned char c_cc[NCC]; /* control characters */ +}; + +#ifdef __KERNEL__ +/* intr=^C quit=^| erase=del kill=^U + eof=^D vtime=\0 vmin=\1 sxtc=\0 + start=^Q stop=^S susp=^Z eol=\0 + reprint=^R discard=^U werase=^W lnext=^V + eol2=\0 +*/ +#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0" +#endif + +/* modem lines */ +#define TIOCM_LE 0x001 +#define TIOCM_DTR 0x002 +#define TIOCM_RTS 0x004 +#define TIOCM_ST 0x008 +#define TIOCM_SR 0x010 +#define TIOCM_CTS 0x020 +#define TIOCM_CAR 0x040 +#define TIOCM_RNG 0x080 +#define TIOCM_DSR 0x100 +#define TIOCM_CD TIOCM_CAR +#define TIOCM_RI TIOCM_RNG + +/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */ + +/* line disciplines */ +#define N_TTY 0 +#define N_SLIP 1 +#define N_MOUSE 2 +#define N_PPP 3 +#define N_STRIP 4 + +#ifdef __KERNEL__ + +/* + * Translate a "termio" structure into a "termios". Ugh. + */ +extern inline void trans_from_termio(struct termio * termio, + struct termios * termios) +{ +#define SET_LOW_BITS(x,y) ((x) = (0xffff0000 & (x)) | (y)) + SET_LOW_BITS(termios->c_iflag, termio->c_iflag); + SET_LOW_BITS(termios->c_oflag, termio->c_oflag); + SET_LOW_BITS(termios->c_cflag, termio->c_cflag); + SET_LOW_BITS(termios->c_lflag, termio->c_lflag); +#undef SET_LOW_BITS + memcpy(termios->c_cc, termio->c_cc, NCC); +} + +/* + * Translate a "termios" structure into a "termio". Ugh. + */ +extern inline void trans_to_termio(struct termios * termios, + struct termio * termio) +{ + termio->c_iflag = termios->c_iflag; + termio->c_oflag = termios->c_oflag; + termio->c_cflag = termios->c_cflag; + termio->c_lflag = termios->c_lflag; + termio->c_line = termios->c_line; + memcpy(termio->c_cc, termios->c_cc, NCC); +} + +#endif /* __KERNEL__ */ + +#endif /* _M68K_TERMIOS_H */ diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/traps.h linux/include/asm-m68k/traps.h --- v1.3.93/linux/include/asm-m68k/traps.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/traps.h Mon Apr 1 21:07:26 1996 @@ -0,0 +1,241 @@ +/* + * linux/include/asm/traps.h + * + * Copyright (C) 1993 Hamish Macdonald + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file README.legal in the main directory of this archive + * for more details. + */ + +#ifndef _M68K_TRAPS_H +#define _M68K_TRAPS_H + +typedef void (*e_vector)(void); + +extern e_vector vectors[]; + +#define VEC_BUSERR (2) +#define VEC_ADDRERR (3) +#define VEC_ILLEGAL (4) +#define VEC_ZERODIV (5) +#define VEC_CHK (6) +#define VEC_TRAP (7) +#define VEC_PRIV (8) +#define VEC_TRACE (9) +#define VEC_LINE10 (10) +#define VEC_LINE11 (11) +#define VEC_RESV1 (12) +#define VEC_COPROC (13) +#define VEC_FORMAT (14) +#define VEC_UNINT (15) +#define VEC_SPUR (24) +#define VEC_INT1 (25) +#define VEC_INT2 (26) +#define VEC_INT3 (27) +#define VEC_INT4 (28) +#define VEC_INT5 (29) +#define VEC_INT6 (30) +#define VEC_INT7 (31) +#define VEC_SYS (32) +#define VEC_TRAP1 (33) +#define VEC_TRAP2 (34) +#define VEC_TRAP3 (35) +#define VEC_TRAP4 (36) +#define VEC_TRAP5 (37) +#define VEC_TRAP6 (38) +#define VEC_TRAP7 (39) +#define VEC_TRAP8 (40) +#define VEC_TRAP9 (41) +#define VEC_TRAP10 (42) +#define VEC_TRAP11 (43) +#define VEC_TRAP12 (44) +#define VEC_TRAP13 (45) +#define VEC_TRAP14 (46) +#define VEC_TRAP15 (47) +#define VEC_FPBRUC (48) +#define VEC_FPIR (49) +#define VEC_FPDIVZ (50) +#define VEC_FPUNDER (51) +#define VEC_FPOE (52) +#define VEC_FPOVER (53) +#define VEC_FPNAN (54) +#define VEC_FPUNSUP (55) +#define VEC_UNIMPEA (60) +#define VEC_UNIMPII (61) + +#define VECOFF(vec) ((vec)<<2) + +/* Status register bits */ +#define PS_T (0x8000) +#define PS_S (0x2000) +#define PS_M (0x1000) +#define PS_C (0x0001) + +/* bits for 68020/68030 special status word */ + +#define FC (0x8000) +#define FB (0x4000) +#define RC (0x2000) +#define RB (0x1000) +#define DF (0x0100) +#define RM (0x0080) +#define RW (0x0040) +#define SZ (0x0030) +#define DFC (0x0007) + +/* bits for 68030 MMU status register (mmusr,psr) */ + +#define MMU_B (0x8000) /* bus error */ +#define MMU_L (0x4000) /* limit violation */ +#define MMU_S (0x2000) /* supervisor violation */ +#define MMU_WP (0x0800) /* write-protected */ +#define MMU_I (0x0400) /* invalid descriptor */ +#define MMU_M (0x0200) /* ATC entry modified */ +#define MMU_T (0x0040) /* transparent translation */ +#define MMU_NUM (0x0007) /* number of levels traversed */ + + +/* bits for 68040 special status word */ +#define CP_040 (0x8000) +#define CU_040 (0x4000) +#define CT_040 (0x2000) +#define CM_040 (0x1000) +#define MA_040 (0x0800) +#define ATC_040 (0x0400) +#define LK_040 (0x0200) +#define RW_040 (0x0100) +#define SIZ_040 (0x0060) +#define TT_040 (0x0018) +#define TM_040 (0x0007) + +/* bits for 68040 write back status word */ +#define WBV_040 (0x80) +#define WBSIZ_040 (0x60) +#define WBBYT_040 (0x20) +#define WBWRD_040 (0x40) +#define WBLNG_040 (0x00) +#define WBTT_040 (0x18) +#define WBTM_040 (0x07) + +/* bus access size codes */ +#define BA_SIZE_BYTE (0x20) +#define BA_SIZE_WORD (0x40) +#define BA_SIZE_LONG (0x00) +#define BA_SIZE_LINE (0x60) + +/* bus access transfer type codes */ +#define BA_TT_MOVE16 (0x08) + +/* bits for 68040 MMU status register (mmusr) */ +#define MMU_B_040 (0x0800) +#define MMU_G_040 (0x0400) +#define MMU_S_040 (0x0080) +#define MMU_CM_040 (0x0060) +#define MMU_M_040 (0x0010) +#define MMU_WP_040 (0x0004) +#define MMU_T_040 (0x0002) +#define MMU_R_040 (0x0001) + +/* bits in the 68060 fault status long word (FSLW) */ +#define MMU060_MA (0x08000000) /* misaligned */ +#define MMU060_LK (0x02000000) /* locked transfer */ +#define MMU060_RW (0x01800000) /* read/write */ +# define MMU060_RW_W (0x00800000) /* write */ +# define MMU060_RW_R (0x01000000) /* read */ +# define MMU060_RW_RMW (0x01800000) /* read/modify/write */ +# define MMU060_W (0x00800000) /* general write, includes rmw */ +#define MMU060_SIZ (0x00600000) /* transfer size */ +#define MMU060_TT (0x00180000) /* transfer type (TT) bits */ +#define MMU060_TM (0x00070000) /* transfer modifier (TM) bits */ +#define MMU060_IO (0x00008000) /* intruction or operand */ +#define MMU060_PBE (0x00004000) /* push buffer bus error */ +#define MMU060_SBE (0x00002000) /* store buffer bus error */ +#define MMU060_PTA (0x00001000) /* pointer A fault */ +#define MMU060_PTB (0x00000800) /* pointer B fault */ +#define MMU060_IL (0x00000400) /* double indirect descr fault */ +#define MMU060_PF (0x00000200) /* page fault (invalid descr) */ +#define MMU060_SP (0x00000100) /* supervisor protection */ +#define MMU060_WP (0x00000080) /* write protection */ +#define MMU060_TWE (0x00000040) /* bus error on table search */ +#define MMU060_RE (0x00000020) /* bus error on read */ +#define MMU060_WE (0x00000010) /* bus error on write */ +#define MMU060_TTR (0x00000008) /* error caused by TTR translation */ +#define MMU060_BPE (0x00000004) /* branch prediction error */ +#define MMU060_SEE (0x00000001) /* software emulated error */ + +/* cases of missing or invalid descriptors */ +#define MMU060_DESC_ERR (MMU060_TWE | MMU060_PTA | MMU060_PTB | \ + MMU060_IL | MMU060_PF) +/* bits that indicate real errors */ +#define MMU060_ERR_BITS (MMU060_PBE | MMU060_SBE | MMU060_DESC_ERR | \ + MMU060_SP | MMU060_WP | MMU060_RE | \ + MMU060_WE) + +/* structure for stack frames */ + +struct frame { + struct pt_regs ptregs; + union { + struct { + unsigned long iaddr; /* instruction address */ + } fmt2; + struct { + unsigned long effaddr; /* effective address */ + } fmt3; + struct { + unsigned long effaddr; /* effective address */ + unsigned long pc; /* pc of faulted instr */ + } fmt4; + struct { + unsigned long effaddr; /* effective address */ + unsigned short ssw; /* special status word */ + unsigned short wb3s; /* write back 3 status */ + unsigned short wb2s; /* write back 2 status */ + unsigned short wb1s; /* write back 1 status */ + unsigned long faddr; /* fault address */ + unsigned long wb3a; /* write back 3 address */ + unsigned long wb3d; /* write back 3 data */ + unsigned long wb2a; /* write back 2 address */ + unsigned long wb2d; /* write back 2 data */ + unsigned long wb1a; /* write back 1 address */ + unsigned long wb1dpd0; /* write back 1 data/push data 0*/ + unsigned long pd1; /* push data 1*/ + unsigned long pd2; /* push data 2*/ + unsigned long pd3; /* push data 3*/ + } fmt7; + struct { + unsigned long iaddr; /* instruction address */ + unsigned short int1[4]; /* internal registers */ + } fmt9; + struct { + unsigned short int1; + unsigned short ssw; /* special status word */ + unsigned short isc; /* instruction stage c */ + unsigned short isb; /* instruction stage b */ + unsigned long daddr; /* data cycle fault address */ + unsigned short int2[2]; + unsigned long dobuf; /* data cycle output buffer */ + unsigned short int3[2]; + } fmta; + struct { + unsigned short int1; + unsigned short ssw; /* special status word */ + unsigned short isc; /* instruction stage c */ + unsigned short isb; /* instruction stage b */ + unsigned long daddr; /* data cycle fault address */ + unsigned short int2[2]; + unsigned long dobuf; /* data cycle output buffer */ + unsigned short int3[4]; + unsigned long baddr; /* stage B address */ + unsigned short int4[2]; + unsigned long dibuf; /* data cycle input buffer */ + unsigned short int5[3]; + unsigned ver : 4; /* stack frame version # */ + unsigned int6:12; + unsigned short int7[18]; + } fmtb; + } un; +}; + +#endif /* _M68K_TRAPS_H */ diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/types.h linux/include/asm-m68k/types.h --- v1.3.93/linux/include/asm-m68k/types.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/types.h Fri Apr 5 14:08:41 1996 @@ -0,0 +1,52 @@ +#ifndef _M68K_TYPES_H +#define _M68K_TYPES_H + +/* + * This file is never included by application software unless + * explicitly requested (e.g., via linux/types.h) in which case the + * application is Linux specific so (user-) name space pollution is + * not a major issue. However, for interoperability, libraries still + * need to be careful to avoid a name clashes. + */ + +typedef unsigned short umode_t; + +/* + * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the + * header files exported to user space + */ + +typedef __signed__ char __s8; +typedef unsigned char __u8; + +typedef __signed__ short __s16; +typedef unsigned short __u16; + +typedef __signed__ int __s32; +typedef unsigned int __u32; + +#if defined(__GNUC__) && !defined(__STRICT_ANSI__) +typedef __signed__ long long __s64; +typedef unsigned long long __u64; +#endif + +/* + * These aren't exported outside the kernel to avoid name space clashes + */ +#ifdef __KERNEL__ + +typedef signed char s8; +typedef unsigned char u8; + +typedef signed short s16; +typedef unsigned short u16; + +typedef signed int s32; +typedef unsigned int u32; + +typedef signed long long s64; +typedef unsigned long long u64; + +#endif /* __KERNEL__ */ + +#endif /* _M68K_TYPES_H */ diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/unistd.h linux/include/asm-m68k/unistd.h --- v1.3.93/linux/include/asm-m68k/unistd.h Mon Nov 28 20:49:07 1994 +++ linux/include/asm-m68k/unistd.h Thu Apr 18 03:00:00 1996 @@ -1,6 +1,288 @@ #ifndef _ASM_M68K_UNISTD_H_ #define _ASM_M68K_UNISTD_H_ +/* + * This file contains the system call numbers. + */ + +#define __NR_setup 0 /* used only by init, to get system going */ +#define __NR_exit 1 +#define __NR_fork 2 +#define __NR_read 3 +#define __NR_write 4 +#define __NR_open 5 +#define __NR_close 6 +#define __NR_waitpid 7 +#define __NR_creat 8 +#define __NR_link 9 +#define __NR_unlink 10 +#define __NR_execve 11 +#define __NR_chdir 12 +#define __NR_time 13 +#define __NR_mknod 14 +#define __NR_chmod 15 +#define __NR_chown 16 +#define __NR_break 17 +#define __NR_oldstat 18 +#define __NR_lseek 19 +#define __NR_getpid 20 +#define __NR_mount 21 +#define __NR_umount 22 +#define __NR_setuid 23 +#define __NR_getuid 24 +#define __NR_stime 25 +#define __NR_ptrace 26 +#define __NR_alarm 27 +#define __NR_oldfstat 28 +#define __NR_pause 29 +#define __NR_utime 30 +#define __NR_stty 31 +#define __NR_gtty 32 +#define __NR_access 33 +#define __NR_nice 34 +#define __NR_ftime 35 +#define __NR_sync 36 +#define __NR_kill 37 +#define __NR_rename 38 +#define __NR_mkdir 39 +#define __NR_rmdir 40 +#define __NR_dup 41 +#define __NR_pipe 42 +#define __NR_times 43 +#define __NR_prof 44 +#define __NR_brk 45 +#define __NR_setgid 46 +#define __NR_getgid 47 +#define __NR_signal 48 +#define __NR_geteuid 49 +#define __NR_getegid 50 +#define __NR_acct 51 +#define __NR_phys 52 +#define __NR_lock 53 +#define __NR_ioctl 54 +#define __NR_fcntl 55 +#define __NR_mpx 56 +#define __NR_setpgid 57 +#define __NR_ulimit 58 +#define __NR_oldolduname 59 +#define __NR_umask 60 +#define __NR_chroot 61 +#define __NR_ustat 62 +#define __NR_dup2 63 +#define __NR_getppid 64 +#define __NR_getpgrp 65 +#define __NR_setsid 66 +#define __NR_sigaction 67 +#define __NR_sgetmask 68 +#define __NR_ssetmask 69 +#define __NR_setreuid 70 +#define __NR_setregid 71 +#define __NR_sigsuspend 72 +#define __NR_sigpending 73 +#define __NR_sethostname 74 +#define __NR_setrlimit 75 +#define __NR_getrlimit 76 +#define __NR_getrusage 77 +#define __NR_gettimeofday 78 +#define __NR_settimeofday 79 +#define __NR_getgroups 80 +#define __NR_setgroups 81 +#define __NR_select 82 +#define __NR_symlink 83 +#define __NR_oldlstat 84 +#define __NR_readlink 85 +#define __NR_uselib 86 +#define __NR_swapon 87 +#define __NR_reboot 88 +#define __NR_readdir 89 +#define __NR_mmap 90 +#define __NR_munmap 91 +#define __NR_truncate 92 +#define __NR_ftruncate 93 +#define __NR_fchmod 94 +#define __NR_fchown 95 +#define __NR_getpriority 96 +#define __NR_setpriority 97 +#define __NR_profil 98 +#define __NR_statfs 99 +#define __NR_fstatfs 100 +#define __NR_ioperm 101 +#define __NR_socketcall 102 +#define __NR_syslog 103 +#define __NR_setitimer 104 +#define __NR_getitimer 105 +#define __NR_stat 106 +#define __NR_lstat 107 +#define __NR_fstat 108 +#define __NR_olduname 109 +#define __NR_iopl /* 110 */ not supported +#define __NR_vhangup 111 +#define __NR_idle 112 +#define __NR_vm86 /* 113 */ not supported +#define __NR_wait4 114 +#define __NR_swapoff 115 +#define __NR_sysinfo 116 +#define __NR_ipc 117 +#define __NR_fsync 118 +#define __NR_sigreturn 119 +#define __NR_clone 120 +#define __NR_setdomainname 121 +#define __NR_uname 122 +#define __NR_modify_ldt 123 +#define __NR_adjtimex 124 +#define __NR_mprotect 125 +#define __NR_sigprocmask 126 +#define __NR_create_module 127 +#define __NR_init_module 128 +#define __NR_delete_module 129 +#define __NR_get_kernel_syms 130 +#define __NR_quotactl 131 +#define __NR_getpgid 132 +#define __NR_fchdir 133 +#define __NR_bdflush 134 +#define __NR_sysfs 135 +#define __NR_personality 136 +#define __NR_afs_syscall 137 /* Syscall for Andrew File System */ +#define __NR_setfsuid 138 +#define __NR_setfsgid 139 +#define __NR__llseek 140 +#define __NR_getdents 141 +#define __NR__newselect 142 +#define __NR_flock 143 +#define __NR_msync 144 +#define __NR_readv 145 +#define __NR_writev 146 +#define __NR_getsid 147 +#define __NR_fdatasync 148 +#define __NR__sysctl 149 +#define __NR_mlock 150 +#define __NR_munlock 151 +#define __NR_mlockall 152 +#define __NR_munlockall 153 +#define __NR_sched_setparam 154 +#define __NR_sched_getparam 155 +#define __NR_sched_setscheduler 156 +#define __NR_sched_getscheduler 157 +#define __NR_sched_yield 158 +#define __NR_sched_get_priority_max 159 +#define __NR_sched_get_priority_min 160 +#define __NR_sched_rr_get_interval 161 +#define __NR_nanosleep 162 +#define __NR_mremap 163 + +#ifdef __ELF__ + +#define _syscall0(type,name) \ +type name(void) \ +{ \ +register long __res __asm__ ("%d0") = __NR_##name; \ +__asm__ __volatile__ ("trap #0" \ + : "=g" (__res) \ + : "0" (__NR_##name) \ + : "%d0"); \ +if (__res >= 0) \ + return (type) __res; \ +errno = -__res; \ +return -1; \ +} + +#define _syscall1(type,name,atype,a) \ +type name(atype a) \ +{ \ +register long __res __asm__ ("%d0") = __NR_##name; \ +__asm__ __volatile__ ("movel %2,%/d1\n\t" \ + "trap #0" \ + : "=g" (__res) \ + : "0" (__NR_##name), "g" ((long)(a)) \ + : "%d0", "%d1"); \ +if (__res >= 0) \ + return (type) __res; \ +errno = -__res; \ +return -1; \ +} + +#define _syscall2(type,name,atype,a,btype,b) \ +type name(atype a,btype b) \ +{ \ +register long __res __asm__ ("%d0") = __NR_##name; \ +__asm__ __volatile__ ("movel %2,%/d1\n\t" \ + "movel %3,%/d2\n\t" \ + "trap #0" \ + : "=g" (__res) \ + : "0" (__NR_##name), "g" ((long)(a)), \ + "g" ((long)(b)) \ + : "%d0", "%d1", "%d2"); \ +if (__res >= 0) \ + return (type) __res; \ +errno = -__res; \ +return -1; \ +} + +#define _syscall3(type,name,atype,a,btype,b,ctype,c) \ +type name(atype a,btype b,ctype c) \ +{ \ +register long __res __asm__ ("%d0") = __NR_##name; \ +__asm__ __volatile__ ("movel %2,%/d1\n\t" \ + "movel %3,%/d2\n\t" \ + "movel %4,%/d3\n\t" \ + "trap #0" \ + : "=g" (__res) \ + : "0" (__NR_##name), "g" ((long)(a)), \ + "g" ((long)(b)), \ + "g" ((long)(c)) \ + : "%d0", "%d1", "%d2", "%d3"); \ +if (__res >= 0) \ + return (type) __res; \ +errno = -__res; \ +return -1; \ +} + +#define _syscall4(type,name,atype,a,btype,b,ctype,c,dtype,d) \ +type name (atype a, btype b, ctype c, dtype d) \ +{ \ +register long __res __asm__ ("%d0") = __NR_##name; \ +__asm__ __volatile__ ("movel %2,%/d1\n\t" \ + "movel %3,%/d2\n\t" \ + "movel %4,%/d3\n\t" \ + "movel %5,%/d4\n\t" \ + "trap #0" \ + : "=g" (__res) \ + : "0" (__NR_##name), "g" ((long)(a)), \ + "g" ((long)(b)), \ + "g" ((long)(c)), \ + "g" ((long)(d)) \ + : "%d0", "%d1", "%d2", "%d3", "%d4"); \ +if (__res >= 0) \ + return (type) __res; \ +errno = -__res; \ +return -1; \ +} + +#define _syscall5(type,name,atype,a,btype,b,ctype,c,dtype,d,etype,e) \ +type name (atype a,btype b,ctype c,dtype d,etype e) \ +{ \ +register long __res __asm__ ("%d0") = __NR_##name; \ +__asm__ __volatile__ ("movel %2,%/d1\n\t" \ + "movel %3,%/d2\n\t" \ + "movel %4,%/d3\n\t" \ + "movel %5,%/d4\n\t" \ + "movel %6,%/d5\n\t" \ + "trap #0" \ + : "=g" (__res) \ + : "0" (__NR_##name), "g" ((long)(a)), \ + "g" ((long)(b)), \ + "g" ((long)(c)), \ + "g" ((long)(d)), \ + "g" ((long)(e)) \ + : "%d0", "%d1", "%d2", "%d3", "%d4", "%d5"); \ +if (__res >= 0) \ + return (type) __res; \ +errno = -__res; \ +return -1; \ +} + +#else /* not ELF; a.out */ + /* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */ #define _syscall0(type,name) \ type name(void) \ @@ -110,5 +392,75 @@ errno = -__res; \ return -1; \ } + +#endif /* ELF or otherwise */ + +#ifdef __KERNEL_SYSCALLS__ + +/* + * we need this inline - forking from kernel space will result + * in NO COPY ON WRITE (!!!), until an execve is executed. This + * is no problem, but for the stack. This is handled by not letting + * main() use the stack at all after fork(). Thus, no function + * calls - which means inline code for fork too, as otherwise we + * would use the stack upon exit from 'fork()'. + * + * Actually only pause and fork are needed inline, so that there + * won't be any messing with the stack from main(), but we define + * some others too. + */ +#define __NR__exit __NR_exit +static inline _syscall0(int,idle) +static inline _syscall0(int,fork) +static inline _syscall2(int,clone,unsigned long,flags,char *,usp) +static inline _syscall0(int,pause) +static inline _syscall0(int,setup) +static inline _syscall0(int,sync) +static inline _syscall0(pid_t,setsid) +static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count) +static inline _syscall1(int,dup,int,fd) +static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp) +static inline _syscall3(int,open,const char *,file,int,flag,int,mode) +static inline _syscall1(int,close,int,fd) +static inline _syscall1(int,_exit,int,exitcode) +static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) + +/* + * This is the mechanism for creating a new kernel thread. + * + * NOTE! Only a kernel-only process(ie the swapper or direct descendants + * who haven't done an "execve()") should use this: it will work within + * a system call from a "real" process, but the process memory space will + * not be free'd until both the parent and the child have exited. + */ +static inline pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) +{ + register long retval __asm__ ("d0") = __NR_clone; + register long clone_arg __asm__ ("d1") = flags | CLONE_VM; + + __asm__ __volatile__ + ("movel %%sp,%%d2\n\t" + "trap #0\n\t" /* Linux/m68k system call */ + "cmpl %%sp,%%d2\n\t" /* child or parent */ + "jeq 1f\n\t" /* parent - jump */ + "movel %3,%%sp@-\n\t" /* push argument */ + "jsr %4@\n\t" /* call fn */ + "movel %2,%0\n\t" /* exit */ + "trap #0\n" + "1:" + : "=d" (retval) + : "0" (__NR_clone), "i" (__NR_exit), + "r" (arg), "a" (fn), "d" (clone_arg) + : "d0", "d2"); + + return retval; +} + +static inline pid_t wait(int * wait_stat) +{ + return waitpid(-1,wait_stat,0); +} + +#endif #endif /* _ASM_M68K_UNISTD_H_ */ diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/user.h linux/include/asm-m68k/user.h --- v1.3.93/linux/include/asm-m68k/user.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/user.h Wed Mar 13 22:31:42 1996 @@ -0,0 +1,72 @@ +#ifndef _M68K_USER_H +#define _M68K_USER_H + +#include +#include +/* Core file format: The core file is written in such a way that gdb + can understand it and provide useful information to the user (under + linux we use the 'trad-core' bfd). There are quite a number of + obstacles to being able to view the contents of the floating point + registers, and until these are solved you will not be able to view the + contents of them. Actually, you can read in the core file and look at + the contents of the user struct to find out what the floating point + registers contain. + The actual file contents are as follows: + UPAGE: 1 page consisting of a user struct that tells gdb what is present + in the file. Directly after this is a copy of the task_struct, which + is currently not used by gdb, but it may come in useful at some point. + All of the registers are stored as part of the upage. The upage should + always be only one page. + DATA: The data area is stored. We use current->end_text to + current->brk to pick up all of the user variables, plus any memory + that may have been malloced. No attempt is made to determine if a page + is demand-zero or if a page is totally unused, we just cover the entire + range. All of the addresses are rounded in such a way that an integral + number of pages is written. + STACK: We need the stack information in order to get a meaningful + backtrace. We need to write the data from (esp) to + current->start_stack, so we round each of these off in order to be able + to write an integer number of pages. + The minimum core file size is 3 pages, or 12288 bytes. +*/ + +struct user_m68kfp_struct { + unsigned long fpregs[8*3]; /* fp0-fp7 registers */ + unsigned long fpcntl[3]; /* fp control regs */ +}; + +/* When the kernel dumps core, it starts by dumping the user struct - + this will be used by gdb to figure out where the data and stack segments + are within the file, and what virtual addresses to use. */ +struct user{ +/* We start with the registers, to mimic the way that "memory" is returned + from the ptrace(3,...) function. */ + struct pt_regs regs; /* Where the registers are actually stored */ + struct switch_stack regs2; /* Backward compatibility, sort of */ +/* ptrace does not yet supply these. Someday.... */ + int u_fpvalid; /* True if math co-processor being used. */ + /* for this mess. Not yet used. */ + struct user_m68kfp_struct m68kfp; /* Math Co-processor registers. */ +/* The rest of this junk is to help gdb figure out what goes where */ + unsigned long int u_tsize; /* Text segment size (pages). */ + unsigned long int u_dsize; /* Data segment size (pages). */ + unsigned long int u_ssize; /* Stack segment size (pages). */ + unsigned long start_code; /* Starting virtual address of text. */ + unsigned long start_stack; /* Starting virtual address of stack area. + This is actually the bottom of the stack, + the top of the stack is always found in the + esp register. */ + long int signal; /* Signal that caused the core dump. */ + int reserved; /* No longer used */ + struct pt_regs * u_ar0; /* Used by gdb to help find the values for */ + /* the registers. */ + struct user_m68kfp_struct* u_fpstate; /* Math Co-processor pointer. */ + unsigned long magic; /* To uniquely identify a core file */ + char u_comm[32]; /* User command that was responsible */ +}; +#define NBPG PAGE_SIZE +#define UPAGES 1 +#define HOST_TEXT_START_ADDR (u.start_code) +#define HOST_STACK_END_ADDR (u.start_stack + u.u_ssize * NBPG) + +#endif diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/zorro.h linux/include/asm-m68k/zorro.h --- v1.3.93/linux/include/asm-m68k/zorro.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/zorro.h Wed Mar 20 19:53:26 1996 @@ -0,0 +1,345 @@ +/* + * asm-m68k/zorro.h -- Amiga AutoConfig (Zorro) Expansion Device Definitions + * + * Copyright (C) 1995 Geert Uytterhoeven + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file README.legal in the main directory of this archive + * for more details. + */ + +#ifndef _ASM_M68K_ZORRO_H_ +#define _ASM_M68K_ZORRO_H_ + +#include +#include + + +/* + * Defined Board Manufacturers + * + * Please update arch/m68k/amiga/zorro.c if you make changes here + * Many IDs were obtained by using ExpName V1.4 ((C) Richard Körber) + * and by looking at the NetBSD-Amiga kernel source + */ + +#define MANUF_MEMPHIS (0x0100) /* Memphis */ +#define PROD_STORMBRINGER (0x00) /* Stormbringer */ + +#define MANUF_COMMODORE2 (0x0201) /* Commodore Germany */ +#define PROD_A2088 (0x01) /* CBM A2088 Bridgeboard */ +#define PROD_A2386SX (0x67) /* CBM A2386-SX Bridgeboard */ + +#define MANUF_COMMODORE (0x0202) /* Commodore USA */ +#define PROD_A2090A (0x01) /* CBM A2090/A2090A HD Controller */ +#define PROD_A590 (0x02) /* CBM A590 SCSI Controller */ +#define PROD_A2091 (0x03) /* CBM A2091 SCSI Controller */ +#define PROD_A2090B (0x04) /* CBM A2090B 2090 Autoboot Card */ +#define PROD_ARCNET (0x09) /* CBM A2060 Arcnet Card */ +#define PROD_CBMRAM (0x0A) /* CBM A2052/58.RAM | 590/2091.RAM */ +#define PROD_A560RAM (0x20) /* CBM A560 Memory Module */ +#define PROD_A2232PROTO (0x45) /* CBM A2232 Serial Prototype */ +#define PROD_A2232 (0x46) /* CBM A2232 Serial Production */ +#define PROD_A2620 (0x50) /* CBM A2620 68020/RAM Card */ +#define PROD_A2630 (0x51) /* CBM A2630 68030/RAM Card */ +#define PROD_A4091 (0x54) /* CBM A4091 SCSI Controller */ +#define PROD_ROMULATOR (0x60) /* CBM Romulator Card */ +#define PROD_A3000TESTFIX (0x61) /* CBM A3000 Test Fixture */ +#define PROD_A2065 (0x70) /* CBM A2065 Ethernet Card */ + +#define MANUF_CARDCO (0x03EC) /* Cardco */ +#define PROD_CC_A2410 (0xF5) /* Cardco A2410 Hires Graphics Card */ + +#define MANUF_MICROBOTICS (0x03F2) /* MicroBotics */ +#define PROD_VXL_30 (0x45) /* VXL-30 Turbo Board */ + +#define MANUF_ASDG (0x03FF) /* ASDG */ +#define PROD_LAN_ROVER (0xFE) /* Lan Rover Ethernet */ +#define PROD_ASDG_DUAL_SERIAL (0xFF) /* Dual Serial Card */ + +#define MANUF_UNIV_OF_LOWELL (0x0406) /* University of Lowell */ +#define PROD_A2410 (0x00) /* CBM A2410 Hires Graphics Card */ + +#define MANUF_AMERISTAR (0x041D) /* Ameristar */ +#define PROD_AMERISTAR2065 (0x01) /* A2065 Ethernet Card */ +#define PROD_A560 (0x09) /* Arcnet Card */ +#define PROD_A4066 (0x0A) /* A4066 Ethernet Card */ + +#define MANUF_SUPRA (0x0420) /* Supra */ +#define PROD_WORDSYNC (0x0C) /* Supra Wordsync SCSI Controller */ +#define PROD_WORDSYNC_II (0x0D) /* Supra Wordsync II SCSI Controller */ +#define PROD_SUPRA_2400MODEM (0x10) /* Supra 2400 Modem */ + +#define MANUF_CSA (0x0422) /* CSA */ +#define PROD_MAGNUM (0x11) /* Magnum 40 SCSI Controller */ +#define PROD_12GAUGE (0x15) /* 12 Gauge SCSI Controller */ + +#define MANUF_HACKER (0x07DB) /* Test only: no product definitions */ + +#define MANUF_POWER_COMPUTING (0x07DC) /* Power Computing */ +#define PROD_DKB_1240 (0x12) /* Viper II Turbo Board (DKB 1240) */ + +#define MANUF_GVP (0x07E1) /* Great Valley Products */ +#define PROD_GVPIISCSI (0x0B) /* GVP Series II SCSI Controller */ +#define PROD_GVPIISCSI_2 (0x09) /* evidence that the driver works + for this product code also */ +#define PROD_GVPIIRAM (0x0A) /* GVP Series II RAM */ +#define PROD_GFORCE_040_SCSI (0x16) /* GForce 040 with SCSI (new) */ +#define PROD_GVPIV_24 (0x20) /* GVP IV-24 Graphics Board */ +#define PROD_GVP (0x0B) /* This code is used by a wide range of + GVP products - use the epc to + identify it correctly */ +/* #define PROD_GVPIO_EXT (0xFF)*/ /* GVP I/O Extender */ + +#define MANUF_PPI (0x07EA) /* Progressive Peripherals Inc. */ +#define PROD_MERCURY (0x00) /* Mercury Turbo Board */ +#define PROD_PPS_A3000_040 (0x01) /* PP&S A3000 68040 Turbo Board */ +#define PROD_PPS_A2000_040 (0x69) /* PP&S A2000 68040 Turbo Board */ +#define PROD_ZEUS (0x96) /* Zeus SCSI Controller */ +#define PROD_PPS_A500_040 (0xBB) /* PP&S A500 68040 Turbo Board */ + +#define MANUF_BSC (0x07FE) /* BSC */ +#define PROD_ALF_3_SCSI (0x03) /* BSC ALF 3 SCSI Controller */ + +#define MANUF_C_LTD (0x0802) /* C Ltd. */ +#define PROD_KRONOS_SCSI (0x04) /* Kronos SCSI Controller */ + +#define MANUF_JOCHHEIM (0x0804) /* Jochheim */ +#define PROD_JOCHHEIM_RAM (0x01) /* Jochheim RAM */ + +#define MANUF_CHECKPOINT (0x0807) /* Checkpoint Technologies */ +#define PROD_SERIAL_SOLUTION (0x00) /* Serial Solution */ + +#define MANUF_GOLEM (0x0819) /* Golem */ +#define PROD_GOLEM_SCSI_II (0x02) /* Golem SCSI-II Controller */ + +#define MANUF_HARDITAL_SYNTHES (0x0817) /* Hardital Synthesis */ +#define PROD_HARDITAL_SCSI (0x01) /* Hardital Synthesis SCSI Controller */ + +#define MANUF_BSC2 (0x082C) /* BSC */ +#define PROD_OKTAGON_SCSI (0x05) /* BSC Oktagon 2008 SCSI Controller */ +#define PROD_TANDEM (0x06) /* BSC Tandem */ +#define PROD_OKTAGON_RAM (0x08) /* BSC Oktagon 2008 RAM */ +#define PROD_MULTIFACE_I (0x10) /* Alfa Data MultiFace I */ +#define PROD_MULTIFACE_II (0x11) /* Alfa Data MultiFace II */ +#define PROD_MULTIFACE_III (0x12) /* Alfa Data MultiFace III */ +#define PROD_ISDN_MASTER (0x40) /* BSC ISDN Master */ + +#define MANUF_ADV_SYS_SOFT (0x0836) /* Advanced Systems & Software */ +#define PROD_NEXUS_SCSI (0x01) /* Nexus SCSI Controller */ +#define PROD_NEXUS_RAM (0x08) /* Nexus RAM */ + +#define MANUF_IVS (0x0840) /* IVS */ +#define PROD_TRUMPCARD_500 (0x30) /* Trumpcard 500 SCSI Controller */ +#define PROD_TRUMPCARD (0x34) /* Trumpcard SCSI Controller */ +#define PROD_VECTOR (0xF3) /* Vector SCSI Controller */ + +#define MANUF_XPERT_PRODEV (0x0845) /* XPert/ProDev */ +#define PROD_MERLIN_RAM (0x03) /* Merlin Graphics Board */ +#define PROD_MERLIN_REG (0x04) + +#define MANUF_HYDRA_SYSTEMS (0x0849) /* Hydra Systems */ +#define PROD_AMIGANET (0x01) /* Amiganet Board */ + +#define MANUF_DIG_MICRONICS (0x0851) /* Digital Micronics Inc */ +#define PROD_DMI_RESOLVER (0x01) /* DMI Resolver Graphics Board */ + +#define MANUF_HELFRICH1 (0x0861) /* Helfrich */ +#define PROD_RAINBOW3 (0x21) /* Rainbow3 Graphics Board */ + +#define MANUF_SW_RESULT_ENTS (0x0866) /* Software Result Enterprises */ +#define PROD_GG2PLUS (0x01) /* GG2+ Bus Converter */ + +#define MANUF_VILLAGE_TRONIC (0x0877) /* Village Tronic */ +#define PROD_PICASSO_II_RAM (0x0B) /* Picasso II Graphics Board */ +#define PROD_PICASSO_II_REG (0x0C) +#define PROD_ARIADNE (0xC9) /* Ariadne Ethernet */ + +#define MANUF_UTILITIES_ULTD (0x087B) /* Utilities Unlimited */ +#define PROD_EMPLANT_DELUXE (0x15) /* Emplant Deluxe SCSI Controller */ +#define PROD_EMPLANT_DELUXE2 (0x20) /* Emplant Deluxe SCSI Controller */ + +#define MANUF_MTEC (0x0890) /* MTEC Germany */ +#define PROD_MTEC_68030 (0x03) /* 68030 Turbo Board */ +#define PROD_MTEC_T1230 (0x20) /* MTEC T1230/28 Turbo Board */ + +#define MANUF_GVP2 (0x0891) /* Great Valley Products */ +#define PROD_SPECTRUM_RAM (0x01) /* GVP Spectrum Graphics Board */ +#define PROD_SPECTRUM_REG (0x02) + +#define MANUF_HELFRICH2 (0x0893) /* Helfrich */ +#define PROD_PICCOLO_RAM (0x05) /* Piccolo Graphics Board */ +#define PROD_PICCOLO_REG (0x06) +#define PROD_PEGGY_PLUS (0x07) /* PeggyPlus MPEG Decoder Board */ +#define PROD_SD64_RAM (0x0A) /* SD64 Graphics Board */ +#define PROD_SD64_REG (0x0B) + +#define MANUF_MACROSYSTEMS (0x089B) /* MacroSystems USA */ +#define PROD_WARP_ENGINE (0x13) /* Warp Engine SCSI Controller */ + +#define MANUF_HARMS_PROF (0x0A00) /* Harms Professional */ +#define PROD_3500_TURBO (0xD0) /* 3500 Turbo board */ + +#define MANUF_VORTEX (0x2017) /* Vortex */ +#define PROD_GOLDEN_GATE_386 (0x07) /* Golden Gate 80386 Board */ +#define PROD_GOLDEN_GATE_RAM (0x08) /* Golden Gate RAM */ +#define PROD_GOLDEN_GATE_486 (0x09) /* Golden Gate 80486 Board */ + +#define MANUF_DATAFLYER (0x2062) /* DataFlyer */ +#define PROD_DATAFLYER_4000SX (0x01) /* DataFlyer 4000SX SCSI Controller */ + +#define MANUF_PHASE5 (0x2140) /* Phase5 */ +#define PROD_FASTLANE_RAM (0x0A) /* FastLane RAM */ +#define PROD_FASTLANE_SCSI (0x0B) /* FastLane/Blizzard 1230-II SCSI */ +#define PROD_BLIZZARD_1230_III (0x0D) /* Blizzard 1230-III Turbo Board */ +#define PROD_BLIZZARD_1230_IV (0x11) /* Blizzard 1230-IV Turbo Board */ +#define PROD_CYBERVISION (0x22) /* CyberVision64 Graphics Board */ + +#define MANUF_APOLLO (0x2222) /* Apollo */ +#define PROD_AT_APOLLO (0x22) /* AT-Apollo */ +#define PROD_APOLLO_TURBO (0x23) /* Apollo Turbo Board */ + +#define MANUF_UWE_GERLACH (0x3FF7) /* Uwe Gerlach */ +#define PROD_UG_RAM_ROM (0xd4) /* RAM/ROM */ + +#define MANUF_MACROSYSTEMS2 (0x4754) /* MacroSystems Germany */ +#define PROD_MAESTRO (0x03) /* Maestro */ +#define PROD_VLAB (0x04) /* VLab */ +#define PROD_MAESTRO_PRO (0x05) /* Maestro Pro */ +#define PROD_RETINA_Z2 (0x06) /* Retina Z2 Graphics Board */ +#define PROD_MULTI_EVOLUTION (0x08) /* MultiEvolution */ +#define PROD_RETINA_Z3 (0x10) /* Retina Z3 Graphics Board */ + + +/* Illegal Manufacturer IDs. These do NOT appear in amiga/zorro.c! */ + +#define MANUF_HACKER_INC (0x07DB) /* Hacker Inc. */ +#define PROD_HACKER_SCSI (0x01) /* Hacker Inc. SCSI Controller */ + +#define MANUF_RES_MNGT_FORCE (0x07DB) /* Resource Management Force */ +#define PROD_QUICKNET (0x02) /* QuickNet Ethernet */ + + +/* + * GVP's identifies most of their product through the 'extended + * product code' (epc). The epc has to be and'ed with the GVPEPCMASK + * before the identification. + */ + +#define GVP_EPCMASK (0xf8) + +enum GVP_ident { + GVP_GFORCE_040 = 0x20, + GVP_GFORCE_040_SCSI = 0x30, + GVP_A1291_SCSI = 0x40, + GVP_COMBO_R4 = 0x60, + GVP_COMBO_R4_SCSI = 0x70, + GVP_PHONEPAK = 0x78, + GVP_IOEXT = 0x98, + GVP_GFORCE_030 = 0xa0, + GVP_GFORCE_030_SCSI = 0xb0, + GVP_A530 = 0xc0, + GVP_A530_SCSI = 0xd0, + GVP_COMBO_R3 = 0xe0, + GVP_COMBO_R3_SCSI = 0xf0, + GVP_SERIESII = 0xf8, +}; + +enum GVP_flags { + GVP_IO = 0x01, + GVP_ACCEL = 0x02, + GVP_SCSI = 0x04, + GVP_24BITDMA = 0x08, + GVP_25BITDMA = 0x10, + GVP_NOBANK = 0x20, + GVP_14MHZ = 0x40, +}; + + +struct Node { + struct Node *ln_Succ; /* Pointer to next (successor) */ + struct Node *ln_Pred; /* Pointer to previous (predecessor) */ + u_char ln_Type; + char ln_Pri; /* Priority, for sorting */ + char *ln_Name; /* ID string, null terminated */ +}; + +struct ExpansionRom { + /* -First 16 bytes of the expansion ROM */ + u_char er_Type; /* Board type, size and flags */ + u_char er_Product; /* Product number, assigned by manufacturer */ + u_char er_Flags; /* Flags */ + u_char er_Reserved03; /* Must be zero ($ff inverted) */ + u_short er_Manufacturer; /* Unique ID,ASSIGNED BY COMMODORE-AMIGA! */ + u_long er_SerialNumber; /* Available for use by manufacturer */ + u_short er_InitDiagVec; /* Offset to optional "DiagArea" structure */ + u_char er_Reserved0c; + u_char er_Reserved0d; + u_char er_Reserved0e; + u_char er_Reserved0f; +}; + +/* er_Type board type bits */ +#define ERT_TYPEMASK 0xc0 +#define ERT_ZORROII 0xc0 +#define ERT_ZORROIII 0x80 + +/* other bits defined in er_Type */ +#define ERTB_MEMLIST 5 /* Link RAM into free memory list */ +#define ERTF_MEMLIST (1<<5) + +struct ConfigDev { + struct Node cd_Node; + u_char cd_Flags; /* (read/write) */ + u_char cd_Pad; /* reserved */ + struct ExpansionRom cd_Rom; /* copy of board's expansion ROM */ + void *cd_BoardAddr; /* where in memory the board was placed */ + u_long cd_BoardSize; /* size of board in bytes */ + u_short cd_SlotAddr; /* which slot number (PRIVATE) */ + u_short cd_SlotSize; /* number of slots (PRIVATE) */ + void *cd_Driver; /* pointer to node of driver */ + struct ConfigDev *cd_NextCD; /* linked list of drivers to config */ + u_long cd_Unused[4]; /* for whatever the driver wants */ +}; + + +/* + * Zorro Functions + */ + +extern int zorro_find(int manuf, int prod, int part, int index); +extern struct ConfigDev *zorro_get_board(int key); +extern void zorro_config_board(int key, int part); +extern void zorro_unconfig_board(int key, int part); + + +/* + * Bitmask indicating portions of available Zorro II RAM that are unused + * by the system. Every bit represents a 64K chunk, for a maximum of 8MB + * (128 chunks, physical 0x00200000-0x009fffff). + * + * If you want to use (= allocate) portions of this RAM, you should clear + * the corresponding bits. + */ + +extern u_long zorro_unused_z2ram[4]; + +#define Z2RAM_START (0x00200000) +#define Z2RAM_END (0x00a00000) +#define Z2RAM_SIZE (0x00800000) +#define Z2RAM_CHUNKSIZE (0x00010000) +#define Z2RAM_CHUNKMASK (0x0000ffff) +#define Z2RAM_CHUNKSHIFT (16) + + +/* + * Verbose Board Identification + */ + +#ifdef CONFIG_ZORRO +extern void zorro_identify(void); +extern int zorro_get_list(char *buffer); +#endif CONFIG_ZORRO + + +#endif /* _ASM_M68K_ZORRO_H_ */ diff -u --recursive --new-file v1.3.93/linux/include/asm-sparc/pgtable.h linux/include/asm-sparc/pgtable.h --- v1.3.93/linux/include/asm-sparc/pgtable.h Sun Apr 21 19:22:12 1996 +++ linux/include/asm-sparc/pgtable.h Mon Apr 22 10:59:40 1996 @@ -1,4 +1,4 @@ -/* $Id: pgtable.h,v 1.45 1996/04/18 03:29:21 davem Exp $ */ +/* $Id: pgtable.h,v 1.46 1996/04/21 11:01:53 davem Exp $ */ #ifndef _SPARC_PGTABLE_H #define _SPARC_PGTABLE_H diff -u --recursive --new-file v1.3.93/linux/include/asm-sparc/smp.h linux/include/asm-sparc/smp.h --- v1.3.93/linux/include/asm-sparc/smp.h Sun Apr 21 19:22:12 1996 +++ linux/include/asm-sparc/smp.h Mon Apr 22 10:59:40 1996 @@ -6,10 +6,7 @@ #ifndef _SPARC_SMP_H #define _SPARC_SMP_H -#ifdef __SMP__ - #ifndef __ASSEMBLY__ - /* PROM provided per-processor information we need * to start them all up. */ @@ -18,6 +15,11 @@ int prom_node; int mid; }; +#endif /* !(__ASSEMBLY__) */ + +#ifdef __SMP__ + +#ifndef __ASSEMBLY__ extern struct prom_cpuinfo linux_cpus[NCPUS]; diff -u --recursive --new-file v1.3.93/linux/include/linux/affs_fs.h linux/include/linux/affs_fs.h --- v1.3.93/linux/include/linux/affs_fs.h Thu Jan 1 02:00:00 1970 +++ linux/include/linux/affs_fs.h Fri Apr 5 16:04:01 1996 @@ -0,0 +1,101 @@ + +#ifndef _AFFS_FS_H +#define _AFFS_FS_H + +#include +/* + * The affs filesystem constants/structures + */ + +#define AFFS_BLOCK_BITS 9 +#define AFFS_BLOCK_SIZE 512 + +#define AFFS_BUFFER_BITS 9 +#define AFFS_BUFFER_SIZE 512 + +#define AFFS_BLOCK_NUMBER(X) (X<<1) + +#define AFFS_SUPER_MAGIC 0xadff + +/* Get the filesystem block size given an inode. */ +#define AFFS_I2BSIZE(inode) ((inode)->i_sb->u.affs_sb.s_block_size) + +/* Read the device block that contains filesystem block ("sector"). */ + +static inline struct buffer_head *affs_sread(int dev,int sector,void **start) +{ + struct buffer_head *bh; + int mask; + + bh = bread (dev, sector >> (BLOCK_SIZE_BITS - AFFS_BLOCK_BITS), 1024); + if (!bh) + return NULL; + mask = (1 << (BLOCK_SIZE_BITS - AFFS_BLOCK_BITS)) - 1; + *start = bh->b_data + ((sector & mask) << AFFS_BLOCK_BITS); + return bh; +} + +/* Use affs_sread() to read a "sector", but take the filesystems partition + offset into account. */ + +static inline struct buffer_head *affs_pread(struct inode *inode, + int sector, void **start) +{ + int offset = inode->i_sb->u.affs_sb.s_partition_offset; + return affs_sread (inode->i_dev, sector + offset, start); +} + +/* amigaffs.c prototypes */ + +extern int affs_get_key_entry (int bsize, void *data, int entry_pos); +extern int affs_find_next_hash_entry (int bsize, void *dir_data, int *hash_pos); +extern int affs_get_fh_hash_link (int bsize, void *fh_data); +extern int affs_get_file_name (int bsize, void *fh_data, char **name); +extern int affs_get_extension (int bsize, void *fh_data); +extern int affs_checksum_block (int bsize, void *data, int *ptype, int *stype); + +/* The stuff that follows may be totally unneeded. I have not checked to see + which prototypes we are still using. */ + +extern int affs_open(struct inode * inode, struct file * filp); +extern void affs_release(struct inode * inode, struct file * filp); +extern int affs_lookup(struct inode * dir,const char * name, int len, + struct inode ** result); +extern unsigned long affs_count_free_inodes(struct super_block *sb); +extern int affs_new_block(int dev); +extern int affs_free_block(int dev, int block); +extern int affs_bmap(struct inode *,int); + +extern void affs_put_super(struct super_block *); +extern struct super_block *affs_read_super(struct super_block *,void *,int); +extern void affs_read_inode(struct inode *); +extern void affs_put_inode(struct inode *); +extern void affs_statfs(struct super_block *, struct statfs *, int); +extern int affs_parent_ino(struct inode *dir); +extern int affs_lseek(struct inode *, struct file *, off_t, int); +extern int affs_read(struct inode *, struct file *, char *, int); +extern int affs_file_read(struct inode *, struct file *, char *, int); +extern int init_affs_fs(void); + +extern struct inode_operations affs_file_inode_operations; +extern struct inode_operations affs_dir_inode_operations; +extern struct inode_operations affs_symlink_inode_operations; +extern struct inode_operations affs_chrdev_inode_operations; +extern struct inode_operations affs_blkdev_inode_operations; + +extern struct file_operations affs_file_operations; +extern struct file_operations affs_dir_operations; + +/* The following macros are used to check for memory leaks. */ +#ifdef LEAK_CHECK +#define free_s leak_check_free_s +#define malloc leak_check_malloc +#define bread leak_check_bread +#define brelse leak_check_brelse +extern void * leak_check_malloc(unsigned int size); +extern void leak_check_free_s(void * obj, int size); +extern struct buffer_head * leak_check_bread(int dev, int block, int size); +extern void leak_check_brelse(struct buffer_head * bh); +#endif /* LEAK_CHECK */ + +#endif diff -u --recursive --new-file v1.3.93/linux/include/linux/affs_fs_i.h linux/include/linux/affs_fs_i.h --- v1.3.93/linux/include/linux/affs_fs_i.h Thu Jan 1 02:00:00 1970 +++ linux/include/linux/affs_fs_i.h Sun Feb 25 19:22:45 1996 @@ -0,0 +1,12 @@ +#ifndef _AFFS_FS_I +#define _AFFS_FS_I + +/* + * affs fs inode data in memory + */ +struct affs_inode_info { + int i_protect; /* unused attribute bits */ + int i_parent; /* parent ino */ +}; + +#endif diff -u --recursive --new-file v1.3.93/linux/include/linux/affs_fs_sb.h linux/include/linux/affs_fs_sb.h --- v1.3.93/linux/include/linux/affs_fs_sb.h Thu Jan 1 02:00:00 1970 +++ linux/include/linux/affs_fs_sb.h Sun Feb 25 19:22:45 1996 @@ -0,0 +1,37 @@ +#ifndef _AFFS_FS_SB +#define _AFFS_FS_SB + +/* + * super-block data in memory + * + * Block numbers are for FFS-sized (normally 512 bytes) blocks. + * + */ + +/* Mount options */ + +struct affs_options { + int offset; + int size; + int root; + int nocase:1; /* Ignore case in filenames. */ + int conv_links:1; /* convert pathnames symlinks point to */ +}; + +struct affs_sb_info { + int s_partition_offset; /* Offset to start in blocks. */ + int s_partition_size; /* Partition size in blocks. */ + int s_root_block; /* Absolute FFS root block number. */ + int s_block_size; /* Block size in bytes. */ + char s_volume_name[42]; + struct affs_options s_options; +}; + +#endif + + + + + + + diff -u --recursive --new-file v1.3.93/linux/include/linux/console.h linux/include/linux/console.h --- v1.3.93/linux/include/linux/console.h Thu Jan 1 02:00:00 1970 +++ linux/include/linux/console.h Fri Apr 5 17:46:12 1996 @@ -0,0 +1,122 @@ +/* + * linux/include/linux/console.h + * + * Copyright (C) 1993 Hamish Macdonald + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file README.legal in the main directory of this archive + * for more details. + * + * Changed: + * 10-Mar-94: Arno Griffioen: Conversion for vt100 emulator port from PC LINUX + */ + +#ifndef _LINUX_CONSOLE_H_ +#define _LINUX_CONSOLE_H_ 1 + +#define NPAR 16 + +struct vc_data { + unsigned long vc_screenbuf_size; + unsigned short vc_num; /* Console number */ + unsigned short vc_video_erase_char; /* Background erase character */ + unsigned char vc_attr; /* Current attributes */ + unsigned char vc_def_color; /* Default colors */ + unsigned char vc_color; /* Foreground & background */ + unsigned char vc_s_color; /* Saved foreground & background */ + unsigned char vc_ulcolor; /* Colour for underline mode */ + unsigned char vc_halfcolor; /* Colour for half intensity mode */ + unsigned long vc_origin; /* Used for EGA/VGA fast scroll */ + unsigned long vc_scr_end; /* Used for EGA/VGA fast scroll */ + unsigned short *vc_pos; + unsigned long vc_x,vc_y; + unsigned long vc_top,vc_bottom; + unsigned long vc_rows,vc_cols; + unsigned long vc_size_row; + unsigned long vc_state; + unsigned long vc_npar,vc_par[NPAR]; + unsigned short *vc_video_mem_start; + unsigned long vc_video_mem_end; /* End of video RAM (sort of) */ + unsigned long vc_saved_x; + unsigned long vc_saved_y; + /* mode flags */ + unsigned long vc_charset : 1; /* Character set G0 / G1 */ + unsigned long vc_s_charset : 1; /* Saved character set */ + unsigned long vc_disp_ctrl : 1; /* Display chars < 32? */ + unsigned long vc_toggle_meta : 1; /* Toggle high bit? */ + unsigned long vc_decscnm : 1; /* Screen Mode */ + unsigned long vc_decom : 1; /* Origin Mode */ + unsigned long vc_decawm : 1; /* Autowrap Mode */ + unsigned long vc_deccm : 1; /* Cursor Visible */ + unsigned long vc_decim : 1; /* Insert Mode */ + unsigned long vc_deccolm : 1; /* 80/132 Column Mode */ + /* attribute flags */ + unsigned long vc_intensity : 2; /* 0=half-bright, 1=normal, 2=bold */ + unsigned long vc_underline : 1; + unsigned long vc_blink : 1; + unsigned long vc_reverse : 1; + unsigned long vc_s_intensity : 2; /* saved rendition */ + unsigned long vc_s_underline : 1; + unsigned long vc_s_blink : 1; + unsigned long vc_s_reverse : 1; + /* misc */ + unsigned long vc_ques : 1; + unsigned long vc_need_wrap : 1; + unsigned long vc_can_do_color : 1; + unsigned long vc_has_scrolled : 1; /* Info for unblank_screen */ + unsigned long vc_kmalloced : 1; /* kfree_s() needed */ + unsigned long vc_report_mouse : 2; + unsigned char vc_utf : 1; /* Unicode UTF-8 encoding */ + unsigned char vc_utf_count; + unsigned long vc_utf_char; + unsigned long vc_tab_stop[5]; /* Tab stops. 160 columns. */ + unsigned short *vc_translate; + unsigned char vc_G0_charset; + unsigned char vc_G1_charset; + unsigned char vc_saved_G0; + unsigned char vc_saved_G1; + unsigned int vc_bell_pitch; /* Console bell pitch */ + unsigned int vc_bell_duration; /* Console bell duration */ + struct consw *vc_sw; + /* additional information is in vt_kern.h */ +}; + +/* + * this is what the terminal answers to a ESC-Z or csi0c query. + */ +#define VT100ID "\033[?1;2c" +#define VT102ID "\033[?6c" + +/* DPC: 1994-04-13 !!! con_putcs is new entry !!! */ + +struct consw { + unsigned long (*con_startup)(unsigned long, char **); + void (*con_init)(struct vc_data *); + int (*con_deinit)(struct vc_data *); + int (*con_clear)(struct vc_data *, int, int, int, int); + int (*con_putc)(struct vc_data *, int, int, int); + int (*con_putcs)(struct vc_data *, const char *, int, int, int); + int (*con_cursor)(struct vc_data *, int); + int (*con_scroll)(struct vc_data *, int, int, int, int); + int (*con_bmove)(struct vc_data *, int, int, int, int, int, int); + int (*con_switch)(struct vc_data *); + int (*con_blank)(int); +}; + +extern struct consw *conswitchp; + +/* flag bits */ +#define CON_INITED (1) + +/* scroll */ +#define SM_UP (1) +#define SM_DOWN (2) +#define SM_LEFT (3) +#define SM_RIGHT (4) + +/* cursor */ +#define CM_DRAW (1) +#define CM_ERASE (2) +#define CM_MOVE (3) + +#endif /* linux/console.h */ diff -u --recursive --new-file v1.3.93/linux/include/linux/fb.h linux/include/linux/fb.h --- v1.3.93/linux/include/linux/fb.h Thu Jan 1 02:00:00 1970 +++ linux/include/linux/fb.h Fri Apr 19 08:14:38 1996 @@ -0,0 +1,293 @@ +#ifndef _LINUX_FB_H +#define _LINUX_FB_H + +/* Definitions of frame buffers */ + +#ifdef __KERNEL__ +#include +#include +#endif + +/* ioctls + 0x46 is 'F' */ +#define FBIOGET_VSCREENINFO 0x4600 +#define FBIOPUT_VSCREENINFO 0x4601 +#define FBIOGET_FSCREENINFO 0x4602 +#define FBIOGETCMAP 0x4604 +#define FBIOPUTCMAP 0x4605 +#define FBIOPAN_DISPLAY 0x4606 + +#define FB_TYPE_PACKED_PIXELS 0 /* Packed Pixels */ +#define FB_TYPE_PLANES 1 /* Non interleaved planes */ +#define FB_TYPE_INTERLEAVED_PLANES 2 /* Interleaved planes */ + +#define FB_VISUAL_MONO01 0 /* Monochr. 1=Black 0=White */ +#define FB_VISUAL_MONO10 1 /* Monochr. 1=White 0=Black */ +#define FB_VISUAL_TRUECOLOR 2 /* True color */ +#define FB_VISUAL_PSEUDOCOLOR 3 /* Pseudo color (like atari) */ +#define FB_VISUAL_DIRECTCOLOR 4 /* Direct color */ +#define FB_VISUAL_STATIC_PSEUDOCOLOR 5 /* Pseudo color readonly */ +#define FB_VISUAL_STATIC_DIRECTCOLOR 6 /* Direct color readonly */ + +struct fb_fix_screeninfo { + char id[16]; /* identification string eg "TT Builtin" */ + unsigned long smem_start; /* Start of frame buffer mem */ + unsigned long smem_len; /* Length of frame buffer mem */ + int type; /* see FB_TYPE_* */ + int type_aux; /* Interleave for interleaved Planes */ + int visual; /* see FB_VISUAL_* */ + u_short xpanstep; /* zero if no hardware panning */ + u_short ypanstep; /* zero if no hardware panning */ + u_short ywrapstep; /* zero if no hardware ywrap */ + short reserved[11]; /* Reserved for future compatibility */ +}; + +struct fb_bitfield { + int offset; /* beginning of bitfield */ + int length; /* length of bitfield */ + int msb_right; /* != 0 : Most significant bit is */ + /* right */ +}; + +#define FB_NONSTD_HAM 1 /* Hold-And-Modify (HAM) */ + +#define FB_ACTIVATE_NOW 0 /* set values immediately (or vbl)*/ +#define FB_ACTIVATE_NXTOPEN 1 /* activate on next open */ +#define FB_ACTIVATE_TEST 2 /* don't set, round up impossible */ +#define FB_ACTIVATE_MASK 15 + /* values */ +#define FB_ACTIVATE_VBL 16 /* activate values on next vbl */ +#define FB_CHANGE_CMAP_VBL 32 /* change colormap on vbl */ + +#define FB_ACCEL_NONE 0 /* no hardware accelerator */ +#define FB_ACCEL_ATARIBLITT 1 /* Atari Blitter */ +#define FB_ACCEL_AMIGABLITT 2 /* Amiga Blitter */ +#define FB_ACCEL_CYBERVISION 3 /* Cybervision64 (S3 Trio64) */ + +#define FB_SYNC_HOR_HIGH_ACT 1 /* horizontal sync high active */ +#define FB_SYNC_VERT_HIGH_ACT 2 /* vertical sync high active */ +#define FB_SYNC_EXT 4 /* external sync */ +#define FB_SYNC_COMP_HIGH_ACT 8 /* composite sync high active */ +#define FB_SYNC_BROADCAST 16 /* broadcast video timings */ + /* vtotal = 144d/288n/576i => PAL */ + /* vtotal = 121d/242n/484i => NTSC */ + +#define FB_VMODE_NONINTERLACED 0 /* non interlaced */ +#define FB_VMODE_INTERLACED 1 /* interlaced */ +#define FB_VMODE_DOUBLE 2 /* double scan */ +#define FB_VMODE_MASK 255 + +#define FB_VMODE_YWRAP 256 /* ywrap instead of panning */ + +struct fb_var_screeninfo { + int xres; /* visible resolution */ + int yres; + int xres_virtual; /* virtual resolution */ + int yres_virtual; + int xoffset; /* offset from virtual to visible */ + int yoffset; /* resolution */ + + int bits_per_pixel; /* guess what */ + int grayscale; /* != 0 Graylevels instead of colors */ + + struct fb_bitfield red; /* bitfield in fb mem if true color, */ + struct fb_bitfield green; /* else only length is significant */ + struct fb_bitfield blue; + struct fb_bitfield transp; /* transparency */ + + int nonstd; /* != 0 Non standard pixel format */ + + int activate; /* see FB_ACTIVATE_* */ + + int height; /* height of picture in mm */ + int width; /* width of picture in mm */ + + int accel; /* see FB_ACCEL_* */ + + /* Timing: All values in pixclocks, except pixclock (of course) */ + unsigned long pixclock; /* pixel clock in ps (pico seconds) */ + unsigned long left_margin; /* time from sync to picture */ + unsigned long right_margin; /* time from picture to sync */ + unsigned long upper_margin; /* time from sync to picture */ + unsigned long lower_margin; + unsigned long hsync_len; /* length of horizontal sync */ + unsigned long vsync_len; /* length of vertical sync */ + int sync; /* see FB_SYNC_* */ + int vmode; /* see FB_VMODE_* */ + int reserved[6]; /* Reserved for future compatibility */ +}; + +struct fb_cmap { + int start; /* First entry */ + int len; /* Number of entries */ + unsigned short *red; /* Red values */ + unsigned short *green; + unsigned short *blue; + unsigned short *transp; /* transparency, can be NULL */ +}; + +#ifdef __KERNEL__ + +struct fb_ops { + /* get non setable parameters */ + int (*fb_get_fix) (struct fb_fix_screeninfo *, int); + /* get setable parameters */ + int (*fb_get_var) (struct fb_var_screeninfo *, int); + /* set setable parameters */ + int (*fb_set_var) (struct fb_var_screeninfo *, int); + /* get colormap */ + int (*fb_get_cmap) (struct fb_cmap *, int, int); + /* set colormap */ + int (*fb_set_cmap) (struct fb_cmap *, int, int); + /* pan display */ + int (*fb_pan_display) (struct fb_var_screeninfo *, int); + /* perform fb specific ioctl */ + int (*fb_ioctl)(struct inode *, struct file *, unsigned int, + unsigned long, int); +}; + +int register_framebuffer(char *, int *, struct fb_ops *, int, + struct fb_var_screeninfo *); +int unregister_framebuffer(int); + + /* + * This is the interface between the low-level console driver and the + * low-level frame buffer device + */ + +struct display { +/* + * As long as the old Amiga screen driver is being used, we have to + * include these old parameters. + */ +#if defined(CONFIG_AMIGA) + ushort scr_max_height; /* screen dimensions */ + ushort scr_max_width; + ushort scr_height; + ushort scr_width; + ushort scr_depth; + int bytes_per_row; /* offset to one line below */ + + ulong crsrcol; + + ushort scroll_latch; /* Vblank support for hardware scroll */ + ushort y_wrap; + ushort cursor_latch; /* Hardware cursor */ + ushort *cursor, *dummy; + ushort cursor_flash; + ushort cursor_visible; + + /* Some chipreg values we need to rebuild copper lists */ + ushort diwstrt_v, diwstrt_h; /* display window control */ + ushort diwstop_v, diwstop_h; + ushort bplcon0; /* display mode */ + ushort htotal; + + u_char *bitplane[8]; /* pointers to display bitplanes */ + ulong plane_size; + + ushort *coplist1hdr; /* List 1 static component */ + ushort *coplist1dyn; /* List 1 dynamic component */ + ushort *coplist2hdr; /* List 2 static component */ + ushort *coplist2dyn; /* List 2 dynamic component */ + +#endif + + /* Filled in by the frame buffer device */ + + struct fb_var_screeninfo var; /* variable infos. yoffset and vmode */ + /* are updated by fbcon.c */ + struct fb_cmap cmap; /* colormap */ + u_char *screen_base; /* pointer to top of virtual screen */ + int visual; + int type; /* see FB_TYPE_* */ + int type_aux; /* Interleave for interleaved Planes */ + u_short ypanstep; /* zero if no hardware ypan */ + u_short ywrapstep; /* zero if no hardware ywrap */ + u_short can_soft_blank; /* zero if no hardware blanking */ + u_short inverse; /* != 0 text black on white as default */ + +#if 0 + struct fb_fix_cursorinfo fcrsr; + struct fb_var_cursorinfo *vcrsr; + struct fb_cursorstate crsrstate; +#endif + + /* Filled in by the low-level console driver */ + + struct vc_data *conp; /* pointer to console data */ + int cursor_x; /* current cursor position */ + int cursor_y; + int fgcol; /* text colors */ + int bgcol; + u_long next_line; /* offset to one line below */ + u_long next_plane; /* offset to next plane */ + u_char *fontdata; /* Font associated to this display */ + int fontheight; + int fontwidth; + struct display_switch *dispsw; /* low level operations */ + u_short scrollmode; /* Scroll Method */ + short yscroll; /* Hardware scrolling */ +}; + + +struct fb_info { + char modename[40]; /* at boottime detected video mode */ + struct display *disp; /* pointer to display variables */ + char fontname[40]; /* default font name */ + int (*changevar)(int); /* tell console var has changed */ + int (*switch_con)(int); /* tell fb to switch consoles */ + int (*updatevar)(int); /* tell fb to update the vars */ + void (*blank)(int); /* tell fb to (un)blank the screen */ +}; + +#endif /* __KERNEL__ */ + +#if 1 + +#define FBCMD_GET_CURRENTPAR 0xDEAD0005 +#define FBCMD_SET_CURRENTPAR 0xDEAD8005 + +#endif + + +#if 1 /* Preliminary */ + + /* + * Hardware Cursor + */ + +#define FBIOGET_FCURSORINFO 0x4607 +#define FBIOGET_VCURSORINFO 0x4608 +#define FBIOPUT_VCURSORINFO 0x4609 +#define FBIOGET_CURSORSTATE 0x460A +#define FBIOPUT_CURSORSTATE 0x460B + + +struct fb_fix_cursorinfo { + u_short crsr_width; /* width and height of the cursor in */ + u_short crsr_height; /* pixels (zero if no cursor) */ + u_short crsr_xsize; /* cursor size in display pixels */ + u_short crsr_ysize; + u_short crsr_color1; /* colormap entry for cursor color1 */ + u_short crsr_color2; /* colormap entry for cursor color2 */ +}; + +struct fb_var_cursorinfo { + u_long data[256]; /* max. 64x64 (ilbm, 2 planes) */ +}; + +struct fb_cursorstate { + short xoffset; + short yoffset; + u_short mode; +}; + +#define FB_CURSOR_OFF 0 +#define FB_CURSOR_ON 1 +#define FB_CURSOR_FLASH 2 + +#endif /* Preliminary */ + + +#endif /* _LINUX_FB_H */ diff -u --recursive --new-file v1.3.93/linux/include/linux/fdreg.h linux/include/linux/fdreg.h --- v1.3.93/linux/include/linux/fdreg.h Sun Apr 21 19:22:16 1996 +++ linux/include/linux/fdreg.h Mon Apr 22 11:32:02 1996 @@ -120,7 +120,7 @@ #define FDC_8272A 0x20 /* Intel 8272a, NEC 765 */ #define FDC_765ED 0x30 /* Non-Intel 1MB-compatible FDC, can't detect */ #define FDC_82072 0x40 /* Intel 82072; 8272a + FIFO + DUMPREGS */ -#define FDC_82072A 0x50 /* 82072A (on Sparcs) */ +#define FDC_82072A 0x45 /* 82072A (on Sparcs) */ #define FDC_82077_ORIG 0x51 /* Original version of 82077AA, sans LOCK */ #define FDC_82077 0x52 /* 82077AA-1 */ #define FDC_82078_UNKN 0x5f /* Unknown 82078 variant */ diff -u --recursive --new-file v1.3.93/linux/include/linux/fs.h linux/include/linux/fs.h --- v1.3.93/linux/include/linux/fs.h Sun Apr 21 19:22:16 1996 +++ linux/include/linux/fs.h Mon Apr 22 15:42:17 1996 @@ -224,6 +224,7 @@ #include #include #include +#include /* * Attribute flags. These should be or-ed together to figure out what @@ -311,6 +312,7 @@ struct nfs_inode_info nfs_i; struct xiafs_inode_info xiafs_i; struct sysv_inode_info sysv_i; + struct ufs_inode_info ufs_i; struct socket socket_i; void * generic_ip; } u; @@ -400,6 +402,7 @@ #include #include #include +#include struct super_block { kdev_t s_dev; @@ -427,6 +430,7 @@ struct nfs_sb_info nfs_sb; struct xiafs_sb_info xiafs_sb; struct sysv_sb_info sysv_sb; + struct ufs_sb_info ufs_sb; void *generic_sbp; } u; }; diff -u --recursive --new-file v1.3.93/linux/include/linux/interrupt.h linux/include/linux/interrupt.h --- v1.3.93/linux/include/linux/interrupt.h Wed Apr 3 16:06:57 1996 +++ linux/include/linux/interrupt.h Mon Apr 22 07:14:01 1996 @@ -31,6 +31,7 @@ TQUEUE_BH, DIGI_BH, SERIAL_BH, + RISCOM8_BH, NET_BH, IMMEDIATE_BH, KEYBOARD_BH, diff -u --recursive --new-file v1.3.93/linux/include/linux/lp_intern.h linux/include/linux/lp_intern.h --- v1.3.93/linux/include/linux/lp_intern.h Thu Jan 1 02:00:00 1970 +++ linux/include/linux/lp_intern.h Mon Mar 4 22:55:14 1996 @@ -0,0 +1,22 @@ +#ifndef _LINUX_LP_INTERN_H_ +#define _LINUX_LP_INTERN_H_ + +/* + * split in two parts by Joerg Dorchain + * usr/include/linux/lp.h modified for Amiga by Michael Rausch + * modified for Atari by Andreas Schwab + * bug fixed by Jes Sorensen 18/8-94: + * It was not possible to compile the kernel only for Atari or Amiga. + * + * linux i386 version c.1991-1992 James Wiegand + * many modifications copyright (C) 1992 Michael K. Johnson + * Interrupt support added 1993 Nigel Gamble + */ + +#include +#include + +int lp_internal_init(struct lp_struct *, int, int, int); + +#endif + diff -u --recursive --new-file v1.3.93/linux/include/linux/lp_m68k.h linux/include/linux/lp_m68k.h --- v1.3.93/linux/include/linux/lp_m68k.h Thu Jan 1 02:00:00 1970 +++ linux/include/linux/lp_m68k.h Thu Mar 14 22:38:20 1996 @@ -0,0 +1,109 @@ +#ifndef _LINUX_LP_H +#define _LINUX_LP_H + +/* + * split in two parts by Joerg Dorchain + * usr/include/linux/lp.h modified for Amiga by Michael Rausch + * modified for Atari by Andreas Schwab + * bug fixed by Jes Sorensen 18/8-94: + * It was not possible to compile the kernel only for Atari or Amiga. + * + * linux i386 version c.1991-1992 James Wiegand + * many modifications copyright (C) 1992 Michael K. Johnson + * Interrupt support added 1993 Nigel Gamble + */ + +#include +#include + +/* + * Per POSIX guidelines, this module reserves the LP and lp prefixes + * These are the lp_table[minor].flags flags... + */ +#define LP_EXIST 0x0001 +#define LP_BUSY 0x0004 +#define LP_ABORT 0x0040 +#define LP_CAREFUL 0x0080 +#define LP_ABORTOPEN 0x0100 + +/* timeout for each character. This is relative to bus cycles -- it + * is the count in a busy loop. THIS IS THE VALUE TO CHANGE if you + * have extremely slow printing, or if the machine seems to slow down + * a lot when you print. If you have slow printing, increase this + * number and recompile, and if your system gets bogged down, decrease + * this number. This can be changed with the tunelp(8) command as well. + */ + +#define LP_INIT_CHAR 1000 + +/* The parallel port specs apparently say that there needs to be + * a .5usec wait before and after the strobe. Since there are wildly + * different computers running linux, I can't come up with a perfect + * value, but since it worked well on most printers before without, + * I'll initialize it to 0. + */ + +#define LP_INIT_WAIT 0 + +/* This is the amount of time that the driver waits for the printer to + * catch up when the printer's buffer appears to be filled. If you + * want to tune this and have a fast printer (i.e. HPIIIP), decrease + * this number, and if you have a slow printer, increase this number. + * This is in hundredths of a second, the default 2 being .05 second. + * Or use the tunelp(8) command, which is especially nice if you want + * change back and forth between character and graphics printing, which + * are wildly different... + */ + +#define LP_INIT_TIME 40 + +/* IOCTL numbers */ +#define LPCHAR 0x0601 /* corresponds to LP_INIT_CHAR */ +#define LPTIME 0x0602 /* corresponds to LP_INIT_TIME */ +#define LPABORT 0x0604 /* call with TRUE arg to abort on error, + FALSE to retry. Default is retry. */ +#define LPSETIRQ 0x0605 /* call with new IRQ number, + or 0 for polling (no IRQ) */ +#define LPGETIRQ 0x0606 /* get the current IRQ number */ +#define LPWAIT 0x0608 /* corresponds to LP_INIT_WAIT */ +#define LPCAREFUL 0x0609 /* call with TRUE arg to require out-of-paper, off- + line, and error indicators good on all writes, + FALSE to ignore them. Default is ignore. */ +#define LPABORTOPEN 0x060a /* call with TRUE arg to abort open() on error, + FALSE to ignore error. Default is ignore. */ +#define LPGETSTATUS 0x060b /* return LP_S(minor) */ +#define LPRESET 0x060c /* reset printer */ + +/* timeout for printk'ing a timeout, in jiffies (100ths of a second). + This is also used for re-checking error conditions if LP_ABORT is + not set. This is the default behavior. */ + +#define LP_TIMEOUT_INTERRUPT (60 * HZ) +#define LP_TIMEOUT_POLLED (10 * HZ) + + +#define LP_BUFFER_SIZE 1024 /*256*/ + +struct lp_struct { + char *name; + unsigned int irq; + void (*lp_out)(int,int); /*output char function*/ + int (*lp_is_busy)(int); + int (*lp_has_pout)(int); + int (*lp_is_online)(int); + int (*lp_my_interrupt)(int); + int flags; /*for BUSY... */ + unsigned int chars; /*busy timeout */ + unsigned int time; /*wait time */ + unsigned int wait; + struct wait_queue *lp_wait_q; /*strobe wait */ + char lp_buffer[LP_BUFFER_SIZE]; + int do_print; + unsigned long copy_size,bytes_written; +}; + +extern struct lp_struct lp_table[]; + +extern int lp_init(void); + +#endif diff -u --recursive --new-file v1.3.93/linux/include/linux/major.h linux/include/linux/major.h --- v1.3.93/linux/include/linux/major.h Sun Apr 21 19:22:16 1996 +++ linux/include/linux/major.h Mon Apr 22 07:14:01 1996 @@ -61,6 +61,8 @@ #define IDE3_MAJOR 34 #define NETLINK_MAJOR 36 #define IDETAPE_MAJOR 37 +#define RISCOM8_NORMAL_MAJOR 48 +#define RISCOM8_CALLOUT_MAJOR 49 #define APBLOCK_MAJOR 60 /* AP1000 Block device */ #define DDV_MAJOR 61 /* AP1000 DDV block device */ /* diff -u --recursive --new-file v1.3.93/linux/include/linux/mm.h linux/include/linux/mm.h --- v1.3.93/linux/include/linux/mm.h Fri Apr 19 10:08:02 1996 +++ linux/include/linux/mm.h Mon Apr 22 15:42:17 1996 @@ -252,7 +252,7 @@ extern unsigned long put_dirty_page(struct task_struct * tsk,unsigned long page, unsigned long address); -extern void free_page_tables(struct task_struct * tsk); +extern void free_page_tables(struct mm_struct * mm); extern void clear_page_tables(struct task_struct * tsk); extern int new_page_tables(struct task_struct * tsk); extern int copy_page_tables(struct task_struct * to); diff -u --recursive --new-file v1.3.93/linux/include/linux/mtio.h linux/include/linux/mtio.h --- v1.3.93/linux/include/linux/mtio.h Mon Apr 8 19:01:46 1996 +++ linux/include/linux/mtio.h Mon Apr 22 11:13:22 1996 @@ -234,6 +234,7 @@ #define MT_ST_AUTO_LOCK 0x40 #define MT_ST_DEF_WRITES 0x80 #define MT_ST_CAN_BSR 0x100 +#define MT_ST_NO_BLKLIMS 0x200 /* The mode parameters to be controlled. Parameter chosen with bits 20-28 */ #define MT_ST_CLEAR_DEFAULT 0xfffff diff -u --recursive --new-file v1.3.93/linux/include/linux/sched.h linux/include/linux/sched.h --- v1.3.93/linux/include/linux/sched.h Sun Apr 21 12:39:03 1996 +++ linux/include/linux/sched.h Mon Apr 22 15:42:17 1996 @@ -63,6 +63,7 @@ #define CT_TO_USECS(x) (((x) % HZ) * 1000000/HZ) extern int nr_running, nr_tasks; +extern int last_pid; #define FIRST_TASK task[0] #define LAST_TASK task[NR_TASKS-1] diff -u --recursive --new-file v1.3.93/linux/include/linux/tty.h linux/include/linux/tty.h --- v1.3.93/linux/include/linux/tty.h Sun Apr 21 19:22:16 1996 +++ linux/include/linux/tty.h Mon Apr 22 15:42:17 1996 @@ -291,6 +291,7 @@ extern int cy_init(void); extern int stl_init(void); extern int stli_init(void); +extern int riscom8_init(void); extern int tty_paranoia_check(struct tty_struct *tty, kdev_t device, const char *routine); diff -u --recursive --new-file v1.3.93/linux/include/linux/ufs_fs.h linux/include/linux/ufs_fs.h --- v1.3.93/linux/include/linux/ufs_fs.h Thu Jan 1 02:00:00 1970 +++ linux/include/linux/ufs_fs.h Mon Apr 22 11:01:45 1996 @@ -0,0 +1,198 @@ +/* + * linux/include/linux/ufs_fs.h + * + * Copyright (C) 1996 + * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu) + * Laboratory for Computer Science Research Computing Facility + * Rutgers, The State University of New Jersey + * + * $Id: ufs_fs.h,v 1.1 1996/04/21 14:45:11 davem Exp $ + * + */ + +#ifndef __LINUX_UFS_FS_H +#define __LINUX_UFS_FS_H + +#include +#include +#include +#include + +#define UFS_BBLOCK 0 +#define UFS_BBSIZE 8192 +#define UFS_SBLOCK 8192 +#define UFS_SBSIZE 8192 + +#define UFS_MAGIC 0x00011954 + +#define UFS_FSIZE 1024 +#define UFS_BSIZE 8192 + +#define UFS_NDADDR 12 +#define UFS_NINDIR 3 + +#define UFS_ROOTINO 2 + +#define UFS_USEEFT ((__u16)65535) + +#define UFS_FSOK 0x7c269d38 +#define UFS_FSACTIVE ((char)0x00) +#define UFS_FSCLEAN ((char)0x01) +#define UFS_FSSTABLE ((char)0x02) +#define UFS_FSBAD ((char)0xff) + +/* Flags for ufs_sb_info */ +#define UFS_DEBUG 0x00000001 +#define UFS_DEBUG_INODE 0x00000002 +#define UFS_DEBUG_NAMEI 0x00000004 +#define UFS_DEBUG_LINKS 0x00000008 + + +/* Test if the inode number is valid. */ +#define ufs_ino_ok(inode) ((inode->i_ino < 2) && \ + (inode->i_ino > (inode->i_sb->u.ufs_sb.s_ncg * inode->i_sb->u.ufs_sb.s_ipg - 1))) + +/* Convert (sb,cg) to the first physical block number for that cg. */ +#define ufs_cgstart(sb, cg) \ + (((sb)->u.ufs_sb.s_fpg * (cg)) + (sb)->u.ufs_sb.s_cgoffset * ((cg) & ~((sb)->u.ufs_sb.s_cgmask))) + +/* Convert (sb,cg) to the first phys. block number for inodes in that cg. */ +#define ufs_cgimin(sb, cg) (ufs_cgstart((sb), (cg)) + (sb)->u.ufs_sb.s_iblkno) +#define ufs_cgdmin(sb, cg) (ufs_cgstart((sb), (cg)) + (sb)->u.ufs_sb.s_dblkno) + +/* Convert an inode number to a cg number. */ +/* XXX - this can be optimized if s_ipg is a power of 2. */ +#define ufs_ino2cg(inode) ((inode)->i_ino/(inode)->i_sb->u.ufs_sb.s_ipg) + +#define MAXNAMLEN 255 + +struct direct { + __u32 d_ino; /* inode number of this entry */ + __u16 d_reclen; /* length of this entry */ + __u16 d_namlen; /* actual length of d_name */ + char d_name[MAXNAMLEN + 1]; /* file name */ +}; + +#define MAXMNTLEN 512 +#define MAXCSBUFS 32 + +struct csum { + __u32 cs_ndir; /* number of directories */ + __u32 cs_nbfree; /* number of free blocks */ + __u32 cs_nifree; /* number of free inodes */ + __u32 cs_nffree; /* number of free frags */ +}; + +typedef struct _ufsquad { + __u32 val[2]; +} ufsquad; + +/* + * This is the actual superblock, as it is laid out on the disk. + */ +struct ufs_superblock { + __u32 fs_link; /* UNUSED */ + __u32 fs_rlink; /* UNUSED */ + __u32 fs_sblkno; + __u32 fs_cblkno; + __u32 fs_iblkno; + __u32 fs_dblkno; + __u32 fs_cgoffset; + __u32 fs_cgmask; + time_t fs_time; /* XXX - check type */ + __u32 fs_size; + __u32 fs_dsize; + __u32 fs_ncg; + __u32 fs_bsize; + __u32 fs_fsize; + __u32 fs_frag; + __u32 fs_minfree; + __u32 fs_rotdelay; + __u32 fs_rps; + __u32 fs_bmask; + __u32 fs_fmask; + __u32 fs_bshift; + __u32 fs_fshift; + __u32 fs_maxcontig; + __u32 fs_maxbpg; + __u32 fs_fragshift; + __u32 fs_fsbtodb; + __u32 fs_sbsize; + __u32 fs_csmask; + __u32 fs_csshift; + __u32 fs_nindir; + __u32 fs_inopb; + __u32 fs_nspf; + __u32 fs_optim; + __u32 fs_XXX1; + __u32 fs_interleave; + __u32 fs_trackskew; + __u32 fs_id[2]; + __u32 fs_csaddr; + __u32 fs_cssize; + __u32 fs_cgsize; + __u32 fs_ntrak; + __u32 fs_nsect; + __u32 fs_spc; + __u32 fs_ncyl; + __u32 fs_cpg; + __u32 fs_ipg; + __u32 fs_fpg; + struct csum fs_cstotal; + __u8 fs_fmod; + __u8 fs_clean; + __u8 fs_ronly; + __u8 fs_flags; + __u8 fs_fsmnt[MAXMNTLEN]; + __u32 fs_cgrotor; + struct csum * fs_csp[MAXCSBUFS]; + __u32 fs_cpc; + __u16 fs_opostbl[16][8]; /* old rotation block list head */ + __s32 fs_sparecon[55]; /* reserved for future constants */ + __s32 fs_state; /* file system state time stamp */ + ufsquad fs_qbmask; /* ~usb_bmask - for use with __s64 size */ + ufsquad fs_qfmask; /* ~usb_fmask - for use with __s64 size */ + __s32 fs_postblformat; /* format of positional layout tables */ + __s32 fs_nrpos; /* number of rotaional positions */ + __s32 fs_postbloff; /* (__s16) rotation block list head */ + __s32 fs_rotbloff; /* (__u8) blocks for each rotation */ + __s32 fs_magic; /* magic number */ + __u8 fs_space[1]; /* list of blocks for each rotation */ + +}; + +/* + * structure of an on-disk inode + */ +struct ufs_inode { + __u16 ui_mode; /* 0x0 */ + __u16 ui_nlink; /* 0x2 */ + __u16 ui_suid; /* 0x4 */ + __u16 ui_sgid; /* 0x6 */ + ufsquad ui_size; /* 0x8 */ /* XXX - should be __u64 */ + struct timeval ui_atime; /* 0x10 */ + struct timeval ui_mtime; /* 0x18 */ + struct timeval ui_ctime; /* 0x20 */ + __u32 ui_db[UFS_NDADDR]; /* 0x28 data blocks */ + __u32 ui_ib[UFS_NINDIR]; /* 0x58 indirect blocks */ + __u32 ui_flags; /* 0x64 unused */ + __u32 ui_blocks; /* 0x68 blocks in use */ + __u32 ui_gen; /* 0x6c generation number XXX - what is this? */ + __u32 ui_shadow; /* 0x70 shadow inode XXX - what is this?*/ + __u32 ui_uid; /* 0x74 long EFT version of uid */ + __u32 ui_gid; /* 0x78 long EFT version of gid */ + __u32 ui_oeftflag; /* 0x7c reserved */ +}; + +extern int init_ufs_fs(void); + +#endif /* __LINUX_UFS_FS_H */ +/* + * Local Variables: *** + * c-indent-level: 8 *** + * c-continued-statement-offset: 8 *** + * c-brace-offset: -8 *** + * c-argdecl-indent: 0 *** + * c-label-offset: -8 *** + * End: *** + */ diff -u --recursive --new-file v1.3.93/linux/include/linux/ufs_fs_i.h linux/include/linux/ufs_fs_i.h --- v1.3.93/linux/include/linux/ufs_fs_i.h Thu Jan 1 02:00:00 1970 +++ linux/include/linux/ufs_fs_i.h Mon Apr 22 12:46:59 1996 @@ -0,0 +1,30 @@ +/* + * linux/include/linux/ufs_fs_i.h + * + * Copyright (C) 1996 + * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu) + * Laboratory for Computer Science Research Computing Facility + * Rutgers, The State University of New Jersey + * + * $Id: ufs_fs_i.h,v 1.1 1996/04/21 14:45:13 davem Exp $ + * + */ + +#ifndef _LINUX_UFS_FS_I_H +#define _LINUX_UFS_FS_I_H + +#include + +struct ufs_inode_info { + __u64 ui_size; + __u32 ui_flags; + __u32 ui_gen; + __u32 ui_shadow; + __u32 ui_uid; + __u32 ui_gid; + __u32 ui_oeftflag; + __u32 ui_db[UFS_NDADDR]; + __u32 ui_ib[UFS_NINDIR]; +}; + +#endif /* _LINUX_UFS_FS_I_H */ diff -u --recursive --new-file v1.3.93/linux/include/linux/ufs_fs_sb.h linux/include/linux/ufs_fs_sb.h --- v1.3.93/linux/include/linux/ufs_fs_sb.h Thu Jan 1 02:00:00 1970 +++ linux/include/linux/ufs_fs_sb.h Mon Apr 22 10:59:40 1996 @@ -0,0 +1,43 @@ +/* + * linux/include/linux/ufs_fs_sb.h + * + * Copyright (C) 1996 + * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu) + * Laboratory for Computer Science Research Computing Facility + * Rutgers, The State University of New Jersey + * + * $Id: ufs_fs_sb.h,v 1.1 1996/04/21 14:45:15 davem Exp $ + * + */ + +#ifndef __LINUX_UFS_FS_SB_H +#define __LINUX_UFS_FS_SB_H + + +struct ufs_sb_info { + struct ufs_superblock * s_raw_sb; + __u32 s_flags; /* internal flags for UFS code */ + __u32 s_ncg; /* used in ufs_read_inode */ + __u32 s_ipg; /* used in ufs_read_inode */ + __u32 s_fpg; + __u32 s_fsize; + __u32 s_bsize; + __u32 s_iblkno; + __u32 s_dblkno; + __u32 s_cgoffset; + __u32 s_cgmask; + __u32 s_inopb; + __u32 s_fsfrag; +}; + +#endif /* __LINUX_UFS_FS_SB_H */ + +/* + * Local Variables: *** + * c-indent-level: 8 *** + * c-continued-statement-offset: 8 *** + * c-brace-offset: -8 *** + * c-argdecl-indent: 0 *** + * c-label-offset: -8 *** + * End: *** + */ diff -u --recursive --new-file v1.3.93/linux/include/net/ip_masq.h linux/include/net/ip_masq.h --- v1.3.93/linux/include/net/ip_masq.h Wed Apr 10 17:02:26 1996 +++ linux/include/net/ip_masq.h Mon Apr 22 15:48:38 1996 @@ -27,6 +27,7 @@ #define IP_MASQ_F_NO_DADDR 0x08 /* no daddr yet */ #define IP_MASQ_F_HASHED 0x10 /* hashed entry */ #define IP_MASQ_F_SAW_FIN 0x20 /* tcp fin pkt seen */ +#define IP_MASQ_F_SAW_RST 0x40 /* tcp rst pkt seen */ #ifdef __KERNEL__ @@ -52,6 +53,7 @@ __u32 saddr, daddr, maddr; /* src, dst & masq addresses */ struct ip_masq_seq out_seq, in_seq; struct ip_masq_app *app; /* bound ip_masq_app object */ + void *app_data; /* Application private data */ unsigned flags; /* status flags */ }; @@ -101,6 +103,7 @@ struct ip_masq_app { struct ip_masq_app *next; + char *name; /* name of application proxy */ unsigned type; /* type = proto<<16 | port (host byte order)*/ int n_attach; int (*masq_init_1) /* ip_masq initializer */ @@ -141,6 +144,11 @@ */ extern int ip_masq_app_pkt_out(struct ip_masq *, struct sk_buff **skb_p, struct device *dev); extern int ip_masq_app_pkt_in(struct ip_masq *, struct sk_buff **skb_p, struct device *dev); + +/* + * service routine(s). + */ +extern struct ip_masq * ip_masq_out_get_2(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port); /* * /proc/net entry diff -u --recursive --new-file v1.3.93/linux/init/main.c linux/init/main.c --- v1.3.93/linux/init/main.c Sun Apr 21 19:22:16 1996 +++ linux/init/main.c Mon Apr 22 15:12:29 1996 @@ -138,6 +138,9 @@ #ifdef CONFIG_ISDN_DRV_PCBIT extern void pcbit_setup(char *str, int *ints); #endif +#ifdef CONFIG_RISCOM8 +extern void riscom8_setup(char *str, int *ints); +#endif #if defined(CONFIG_SYSVIPC) || defined(CONFIG_KERNELD) @@ -346,6 +349,9 @@ #ifdef CONFIG_DIGI { "digi=", pcxx_setup }, #endif +#ifdef CONFIG_RISCOM8 + { "riscom8=", riscom8_setup }, +#endif { 0, 0 } }; @@ -639,6 +645,8 @@ for (i=1; iprocessor=j; + cli(); + n = task[i]->next_run; + p = task[i]->prev_run; + nr_running--; + n->prev_run = p; + p->next_run = n; + task[i]->next_run = task[i]->prev_run = task[i]; + sti(); } } diff -u --recursive --new-file v1.3.93/linux/kernel/exit.c linux/kernel/exit.c --- v1.3.93/linux/kernel/exit.c Tue Apr 2 13:32:23 1996 +++ linux/kernel/exit.c Mon Apr 22 12:14:50 1996 @@ -17,6 +17,8 @@ #include #include +#include + extern void sem_exit (void); extern void acct_process (long exitcode); extern void kerneld_exit(void); @@ -423,21 +425,26 @@ void exit_sighand(struct task_struct *tsk) { - __exit_sighand(tsk); + __exit_sighand(tsk); } static inline void exit_mm(void) { struct mm_struct * mm = current->mm; + /* Set us up to use the kernel mm state */ + flush_cache_mm(mm); + flush_tlb_mm(mm); + init_mm.count++; + current->mm = &init_mm; current->swappable = 0; - if (mm) { - if (!--mm->count) { - exit_mmap(mm); - free_page_tables(current); - kfree(mm); - } - current->mm = NULL; + SET_PAGE_DIR(current, swapper_pg_dir); + + /* free the old state - not used any more */ + if (!--mm->count) { + exit_mmap(mm); + free_page_tables(mm); + kfree(mm); } } diff -u --recursive --new-file v1.3.93/linux/kernel/fork.c linux/kernel/fork.c --- v1.3.93/linux/kernel/fork.c Sun Mar 24 20:07:01 1996 +++ linux/kernel/fork.c Mon Apr 22 13:08:47 1996 @@ -29,6 +29,7 @@ int nr_tasks=1; int nr_running=1; unsigned long int total_forks=0; /* Handle normal Linux uptimes. */ +int last_pid=0; static inline int find_empty_process(void) { @@ -59,7 +60,6 @@ static int get_pid(unsigned long flags) { - static int last_pid = 0; struct task_struct *p; if (flags & CLONE_PID) @@ -114,26 +114,27 @@ static inline int copy_mm(unsigned long clone_flags, struct task_struct * tsk) { - if (clone_flags & CLONE_VM) { - SET_PAGE_DIR(tsk, current->mm->pgd); - current->mm->count++; + if (!(clone_flags & CLONE_VM)) { + struct mm_struct * mm = kmalloc(sizeof(*tsk->mm), GFP_KERNEL); + if (!mm) + return -1; + *mm = *current->mm; + mm->count = 1; + mm->def_flags = 0; + tsk->mm = mm; + tsk->min_flt = tsk->maj_flt = 0; + tsk->cmin_flt = tsk->cmaj_flt = 0; + tsk->nswap = tsk->cnswap = 0; + if (new_page_tables(tsk)) + return -1; + if (dup_mmap(mm)) { + free_page_tables(mm); + return -1; + } return 0; } - tsk->mm = kmalloc(sizeof(*tsk->mm), GFP_KERNEL); - if (!tsk->mm) - return -1; - *tsk->mm = *current->mm; - tsk->mm->count = 1; - tsk->mm->def_flags = 0; - tsk->min_flt = tsk->maj_flt = 0; - tsk->cmin_flt = tsk->cmaj_flt = 0; - tsk->nswap = tsk->cnswap = 0; - if (new_page_tables(tsk)) - return -1; - if (dup_mmap(tsk->mm)) { - free_page_tables(tsk); - return -1; - } + SET_PAGE_DIR(tsk, current->mm->pgd); + current->mm->count++; return 0; } diff -u --recursive --new-file v1.3.93/linux/kernel/sched.c linux/kernel/sched.c --- v1.3.93/linux/kernel/sched.c Fri Apr 12 15:52:10 1996 +++ linux/kernel/sched.c Mon Apr 22 15:14:08 1996 @@ -336,7 +336,10 @@ /* * This is safe as we do not permit re-entry of schedule() */ - prev->processor = NO_PROC_ID; + prev->processor = NO_PROC_ID; +#define idle_task (task[this_cpu]) +#else +#define idle_task (&init_task) #endif /* @@ -346,7 +349,7 @@ */ /* this is the scheduler proper: */ c = -1000; - next = &init_task; + next = idle_task; while (p != &init_task) { int weight = goodness(p, prev, this_cpu); if (weight > c) @@ -359,20 +362,13 @@ for_each_task(p) p->counter = (p->counter >> 1) + p->priority; } -#ifdef __SMP__ - - /* - * Context switching between two idle threads is pointless. - */ - if(!prev->pid && !next->pid) - next=prev; +#ifdef __SMP__ /* * Allocate process to CPU */ next->processor = this_cpu; next->last_processor = this_cpu; - #endif #ifdef __SMP_PROF__ /* mark processor running an idle thread */ @@ -1437,9 +1433,12 @@ * process right in SMP mode. */ int cpu=smp_processor_id(); +#ifndef __SMP__ current_set[cpu]=&init_task; -#ifdef __SMP__ +#else init_task.processor=cpu; + for(cpu = 0; cpu < NR_CPUS; cpu++) + current_set[cpu] = &init_task; #endif init_bh(TIMER_BH, timer_bh); init_bh(TQUEUE_BH, tqueue_bh); diff -u --recursive --new-file v1.3.93/linux/mm/filemap.c linux/mm/filemap.c --- v1.3.93/linux/mm/filemap.c Sun Apr 21 19:22:17 1996 +++ linux/mm/filemap.c Mon Apr 22 08:48:09 1996 @@ -424,8 +424,8 @@ * We try to have a limit of MAX_READWINDOW = 48K. */ -#define MAX_READWINDOW (PAGE_SIZE*12) -#define MAX_READAHEAD (PAGE_SIZE*7) +#define MAX_READWINDOW (PAGE_SIZE*32) +#define MAX_READAHEAD (PAGE_SIZE*16) #define MIN_READAHEAD (PAGE_SIZE) static inline unsigned long generic_file_readahead(struct file * filp, struct inode * inode, diff -u --recursive --new-file v1.3.93/linux/mm/memory.c linux/mm/memory.c --- v1.3.93/linux/mm/memory.c Sun Apr 21 19:22:17 1996 +++ linux/mm/memory.c Mon Apr 22 12:14:21 1996 @@ -147,20 +147,16 @@ * page table directory to the kernel page tables and then frees the old * page table directory. */ -void free_page_tables(struct task_struct * tsk) +void free_page_tables(struct mm_struct * mm) { int i; pgd_t * page_dir; - page_dir = tsk->mm->pgd; + page_dir = mm->pgd; if (!page_dir || page_dir == swapper_pg_dir) { - printk("%s trying to free kernel page-directory: not good\n", tsk->comm); + printk("Trying to free kernel page-directory: not good\n"); return; } - flush_cache_mm(tsk->mm); - flush_tlb_mm(tsk->mm); - SET_PAGE_DIR(tsk, swapper_pg_dir); - tsk->mm->pgd = swapper_pg_dir; /* or else... */ for (i = 0 ; i < USER_PTRS_PER_PGD ; i++) free_one_pgd(page_dir + i); pgd_free(page_dir); diff -u --recursive --new-file v1.3.93/linux/mm/page_io.c linux/mm/page_io.c --- v1.3.93/linux/mm/page_io.c Wed Apr 17 09:06:33 1996 +++ linux/mm/page_io.c Mon Apr 22 08:43:45 1996 @@ -67,8 +67,10 @@ return; } /* Make sure we are the only process doing I/O with this swap page. */ - while (set_bit(offset,p->swap_lockmap)) + while (set_bit(offset,p->swap_lockmap)) { + run_task_queue(&tq_disk); sleep_on(&lock_queue); + } if (rw == READ) kstat.pswpin++; else diff -u --recursive --new-file v1.3.93/linux/net/ipv4/ip_masq.c linux/net/ipv4/ip_masq.c --- v1.3.93/linux/net/ipv4/ip_masq.c Wed Apr 17 09:06:33 1996 +++ linux/net/ipv4/ip_masq.c Mon Apr 22 11:27:00 1996 @@ -73,6 +73,7 @@ X(ip_masq_set_expire), X(ip_masq_free_ports), X(ip_masq_expire), + X(ip_masq_out_get_2), #include }; @@ -127,14 +128,14 @@ hash = ip_masq_hash_key(ms->protocol, ms->maddr, ms->mport); ms->m_link = ip_masq_m_tab[hash]; ip_masq_m_tab[hash] = ms; - + /* * Hash by proto,s{addr,port} */ hash = ip_masq_hash_key(ms->protocol, ms->saddr, ms->sport); ms->s_link = ip_masq_s_tab[hash]; ip_masq_s_tab[hash] = ms; - + ms->flags |= IP_MASQ_F_HASHED; return 1; @@ -172,7 +173,7 @@ *ms_p = ms->s_link; break; } - + ms->flags &= ~IP_MASQ_F_HASHED; return 1; } @@ -204,7 +205,7 @@ s_port = portptr[0]; d_addr = iph->daddr; d_port = portptr[1]; - + hash = ip_masq_hash_key(protocol, d_addr, d_port); for(ms = ip_masq_m_tab[hash]; ms ; ms = ms->m_link) { if ( protocol==ms->protocol && @@ -224,8 +225,6 @@ struct ip_masq * ip_masq_out_get(struct iphdr *iph) { - unsigned hash; - struct ip_masq *ms; __u16 *portptr; int protocol; __u32 s_addr, d_addr; @@ -237,7 +236,24 @@ s_port = portptr[0]; d_addr = iph->daddr; d_port = portptr[1]; - + + return ip_masq_out_get_2(protocol, s_addr, s_port, d_addr, d_port); +} + +/* + * Returns ip_masq associated with supplied parameters, either + * broken out of the ip/tcp headers or directly supplied for those + * pathological protocols with address/port in the data stream + * (ftp, irc). addresses and ports are in network order. + * called for pkts coming from inside-to-OUTside the firewall. + */ + +struct ip_masq * +ip_masq_out_get_2(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port) +{ + unsigned hash; + struct ip_masq *ms; + hash = ip_masq_hash_key(protocol, s_addr, s_port); for(ms = ip_masq_s_tab[hash]; ms ; ms = ms->s_link) { if (protocol == ms->protocol && @@ -245,7 +261,7 @@ d_addr == ms->daddr && d_port == ms->dport ) return ms; } - + return NULL; } @@ -259,7 +275,7 @@ { unsigned hash; struct ip_masq *ms; - + hash = ip_masq_hash_key(protocol, m_addr, m_port); for(ms = ip_masq_m_tab[hash]; ms ; ms = ms->m_link) { if ( protocol==ms->protocol && @@ -288,7 +304,7 @@ ip_masq_unbind_app(ms); kfree_s(ms,sizeof(*ms)); } - + restore_flags(flags); } @@ -304,9 +320,9 @@ int ports_tried, *free_ports_p; unsigned long flags; static int n_fails = 0; - + free_ports_p = &ip_masq_free_ports[proto==IPPROTO_TCP]; - + if (*free_ports_p == 0) { if (++n_fails < 5) printk("ip_masq_new(proto=%s): no free ports.\n", @@ -330,7 +346,8 @@ ms->daddr = daddr; ms->dport = dport; ms->flags = mflags; - + ms->app_data = NULL; + if (proto == IPPROTO_UDP) ms->flags |= IP_MASQ_F_NO_DADDR; @@ -434,7 +451,7 @@ ntohl(iph->saddr), ntohs(portptr[0]), ntohl(iph->daddr), ntohs(portptr[1])); #endif - + ms = ip_masq_out_get(iph); if (ms!=NULL) ip_masq_set_expire(ms,0); @@ -442,8 +459,8 @@ /* * Nope, not found, create a new entry for it */ - - if (ms==NULL) + + if (ms==NULL) { ms = ip_masq_new(dev, iph->protocol, iph->saddr, portptr[0], @@ -452,18 +469,18 @@ if (ms == NULL) return; } - + /* * Change the fragments origin */ - + size = skb->len - ((unsigned char *)portptr - skb->h.raw); /* * Set iph addr and port from ip_masq obj. */ iph->saddr = ms->maddr; portptr[0] = ms->mport; - + /* * Attempt ip_masq_app call. * will fix ip_masq and iph seq stuff @@ -478,42 +495,48 @@ portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]); size = skb->len - ((unsigned char *)portptr-skb->h.raw); } - + /* * Adjust packet accordingly to protocol */ - - if (iph->protocol==IPPROTO_UDP) + + if (iph->protocol==IPPROTO_UDP) { timeout = ip_masq_expire->udp_timeout; recalc_check((struct udphdr *)portptr,iph->saddr,iph->daddr,size); } - else + else { struct tcphdr *th; th = (struct tcphdr *)portptr; - + /* * Timeout depends if FIN packet was seen + * Very short timeout if RST packet seen. */ - if (ms->flags & IP_MASQ_F_SAW_FIN || th->fin) + if (ms->flags & IP_MASQ_F_SAW_RST || th->rst) + { + timeout = 1; + ms->flags |= IP_MASQ_F_SAW_RST; + } + else if (ms->flags & IP_MASQ_F_SAW_FIN || th->fin) { timeout = ip_masq_expire->tcp_fin_timeout; ms->flags |= IP_MASQ_F_SAW_FIN; } else timeout = ip_masq_expire->tcp_timeout; - + skb->csum = csum_partial((void *)(th + 1), size - sizeof(*th), 0); tcp_send_check(th,iph->saddr,iph->daddr,size,skb); } ip_masq_set_expire(ms, timeout); ip_send_check(iph); - + #ifdef DEBUG_CONFIG_IP_MASQUERADE printk("O-routed from %lX:%X over %s\n",ntohl(ms->maddr),ntohs(ms->mport),dev->name); #endif } - + /* * Check if it's an masqueraded port, look it up, * and send it on it's way... @@ -530,10 +553,10 @@ __u16 *portptr; struct ip_masq *ms; unsigned short frag; - + if (iph->protocol!=IPPROTO_UDP && iph->protocol!=IPPROTO_TCP) return 0; - + /* * Toss fragments, since we handle them in ip_rcv() */ @@ -549,7 +572,7 @@ if (ntohs(portptr[1]) < PORT_MASQ_BEGIN || ntohs(portptr[1]) > PORT_MASQ_END) return 0; - + #ifdef DEBUG_CONFIG_IP_MASQUERADE printk("Incoming %s %lX:%X -> %lX:%X\n", masq_proto_name(iph->protocol), @@ -559,17 +582,17 @@ /* * reroute to original host:port if found... */ - + ms = ip_masq_in_get(iph); - + if (ms != NULL) { int size; - + /* * Set dport if not defined yet. */ - + if ( ms->flags & IP_MASQ_F_NO_DPORT && ms->protocol == IPPROTO_TCP ) { ms->flags &= ~IP_MASQ_F_NO_DPORT; ms->dport = portptr[0]; @@ -589,34 +612,53 @@ size = skb->len - ((unsigned char *)portptr - skb->h.raw); iph->daddr = ms->saddr; portptr[1] = ms->sport; - + /* * Attempt ip_masq_app call. * will fix ip_masq and iph ack_seq stuff */ - + if (ip_masq_app_pkt_in(ms, skb_p, dev) != 0) { /* * skb has changed, update pointers. */ - + skb = *skb_p; iph = skb->h.iph; portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]); size = skb->len - ((unsigned char *)portptr-skb->h.raw); } - + /* - * Yug! adjust UDP/TCP and IP checksums + * Yug! adjust UDP/TCP and IP checksums, also update + * UDP timeouts since you cannot depend on traffic + * going through the other way to hold the timeout open. + * (With TCP the ACK packets hold the tunnel open). + * If a TCP RST is seen collapse the tunnel! */ if (iph->protocol==IPPROTO_UDP) + { + unsigned long timeout; recalc_check((struct udphdr *)portptr,iph->saddr,iph->daddr,size); + ip_masq_set_expire(ms, 0); + ip_masq_set_expire(ms, ip_masq_expire->udp_timeout); + } else { + struct tcphdr *th; skb->csum = csum_partial((void *)(((struct tcphdr *)portptr) + 1), size - sizeof(struct tcphdr), 0); tcp_send_check((struct tcphdr *)portptr,iph->saddr,iph->daddr,size,skb); + /* Check if TCP RST */ + th = (struct tcphdr *)portptr; + if (th->rst) + { + ip_masq_set_expire(ms, 0); + ms->flags |= IP_MASQ_F_SAW_RST; + ip_masq_set_expire(ms, 1); + } + } ip_send_check(iph); #ifdef DEBUG_CONFIG_IP_MASQUERADE @@ -624,7 +666,7 @@ #endif return 1; } - + /* sorry, all this trouble for a no-hit :) */ return 0; } @@ -695,7 +737,7 @@ * Initialize ip masquerading */ int ip_masq_init(void) -{ +{ register_symtab (&ip_masq_syms); proc_net_register(&(struct proc_dir_entry) { PROC_NET_IPMSQHST, 13, "ip_masquerade", @@ -704,6 +746,6 @@ ip_msqhst_procinfo }); ip_masq_app_init(); - + return 0; } diff -u --recursive --new-file v1.3.93/linux/net/ipv4/ip_masq_app.c linux/net/ipv4/ip_masq_app.c --- v1.3.93/linux/net/ipv4/ip_masq_app.c Fri Apr 12 15:52:12 1996 +++ linux/net/ipv4/ip_masq_app.c Mon Apr 22 11:27:00 1996 @@ -437,24 +437,35 @@ int len=0; struct ip_masq_app * mapp; unsigned idx; - len=sprintf(buffer,"prot port n_attach\n"); + + if (offset < 22) + len=sprintf(buffer,"%-21s\n", "prot port n_attach"); + pos = 22; + for (idx=0 ; idx < IP_MASQ_APP_TAB_SIZE; idx++) for (mapp = ip_masq_app_base[idx]; mapp ; mapp = mapp->next) { - len += sprintf(buffer+len, "%s %-7u %-7d\n", + /* + * If you change the length of this sprintf, then all + * the length calculations need fixing too! + * Line length = 22 (3 + 2 + 7 + 1 + 7 + 1 + 1) + */ + pos += 22; + if (pos < offset) + continue; + + len += sprintf(buffer+len, "%-3s %-7u %-7d \n", masq_proto_name(IP_MASQ_APP_PROTO(mapp->type)), IP_MASQ_APP_PORT(mapp->type), mapp->n_attach); - pos=begin+len; - if(posoffset+length) - break; + + if(len >= length) + goto done; } - *start=buffer+(offset-begin); - len-=(offset-begin); - if(len>length) - len=length; +done: + begin = len - (pos - offset); + *start = buffer + begin; + len -= begin; + if (len > length) + len = length; return len; } diff -u --recursive --new-file v1.3.93/linux/net/ipv4/ip_masq_ftp.c linux/net/ipv4/ip_masq_ftp.c --- v1.3.93/linux/net/ipv4/ip_masq_ftp.c Wed Apr 10 17:02:28 1996 +++ linux/net/ipv4/ip_masq_ftp.c Mon Apr 22 11:27:00 1996 @@ -66,12 +66,12 @@ iph = skb->h.iph; th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]); data = (char *)&th[1]; - + data_limit = skb->h.raw + skb->len - 18; while (data < data_limit) { - if (memcmp(data,"PORT ",5) && memcmp(data,"port ",5)) + if (memcmp(data,"PORT ",5) && memcmp(data,"port ",5)) { data ++; continue; @@ -99,21 +99,38 @@ from = (p1<<24) | (p2<<16) | (p3<<8) | p4; port = (p5<<8) | p6; #if DEBUG_CONFIG_IP_MASQ_FTP - printk("PORT %lX:%X detected\n",from,port); + printk("PORT %X:%X detected\n",from,port); #endif /* - * Now create an masquerade entry for it + * Now update or create an masquerade entry for it */ - n_ms = ip_masq_new(dev, IPPROTO_TCP, - htonl(from), htons(port), - iph->daddr, 0, - IP_MASQ_F_NO_DPORT); - - if (n_ms==NULL) - return 0; +#if DEBUG_CONFIG_IP_MASQ_FTP + printk("protocol %d %lX:%X %X:%X\n", iph->protocol, htonl(from), htons(port), iph->daddr, 0); + +#endif + n_ms = ip_masq_out_get_2(iph->protocol, + htonl(from), htons(port), + iph->daddr, 0); + if (n_ms) { + /* existing masquerade, clear timer */ + ip_masq_set_expire(n_ms,0); + } + else { + n_ms = ip_masq_new(dev, IPPROTO_TCP, + htonl(from), htons(port), + iph->daddr, 0, + IP_MASQ_F_NO_DPORT); + + if (n_ms==NULL) + return 0; + } + + /* + * keep for a bit longer than tcp_fin, caller may not reissue + * PORT before tcp_fin_timeout. + */ + ip_masq_set_expire(n_ms, ip_masq_expire->tcp_fin_timeout*3); - ip_masq_set_expire(n_ms, ip_masq_expire->tcp_fin_timeout); - /* * Replace the old PORT with the new one */ @@ -123,7 +140,10 @@ from>>24&255,from>>16&255,from>>8&255,from&255, port>>8&255,port&255); buf_len = strlen(buf); - +#if DEBUG_CONFIG_IP_MASQ_FTP + printk("new PORT %X:%X\n",from,port); +#endif + /* * Calculate required delta-offset to keep TCP happy */ @@ -133,8 +153,8 @@ /* * No shift. */ - - if (diff==0) + + if (diff==0) { /* * simple case, just replace the old PORT cmd @@ -153,6 +173,7 @@ struct ip_masq_app ip_masq_ftp = { NULL, /* next */ + "ftp", /* name */ 0, /* type */ 0, /* n_attach */ masq_ftp_init_1, /* ip_masq_init_1 */ diff -u --recursive --new-file v1.3.93/linux/net/ipv4/ip_masq_irc.c linux/net/ipv4/ip_masq_irc.c --- v1.3.93/linux/net/ipv4/ip_masq_irc.c Wed Apr 10 17:02:28 1996 +++ linux/net/ipv4/ip_masq_irc.c Mon Apr 22 11:27:00 1996 @@ -224,6 +224,7 @@ struct ip_masq_app ip_masq_irc = { NULL, /* next */ + "irc", /* name */ 0, /* type */ 0, /* n_attach */ masq_irc_init_1, /* init_1 */ diff -u --recursive --new-file v1.3.93/linux/net/ipv4/ipip.c linux/net/ipv4/ipip.c --- v1.3.93/linux/net/ipv4/ipip.c Sun Apr 21 12:39:03 1996 +++ linux/net/ipv4/ipip.c Mon Apr 22 12:31:47 1996 @@ -74,6 +74,25 @@ skb->h.iph=(struct iphdr *)skb->data; skb->ip_hdr=(struct iphdr *)skb->data; memset(skb->proto_priv, 0, sizeof(struct options)); + if (skb->ip_hdr->ihl > 5) + { + if (ip_options_compile(NULL, skb)) + return 0; + } + +#ifdef CONFIG_FIREWALL + /* + * Check the firewall [well spotted Olaf] + */ + + if((err=call_in_firewall(PF_INET, skb->dev, skb->ip_hdr))&2; exit 1; } # -# Cache function definitions +# Cache function definitions, turn off posix compliance # -set -h +set -h +o posix @@ -84,7 +84,7 @@ echo -ne "'$2' '[$flag] $1' " >>MCmenu - echo -e "function $2 () { l_bool '$2' \"\$1\" }\n" >>MCradiolists + echo -e "function $2 () { l_bool '$2' \"\$1\" ;}\n" >>MCradiolists } # @@ -109,7 +109,7 @@ echo -ne "'$2' '<$flag> $1' " >>MCmenu echo -e " - function $2 () { l_tristate '$2' \"\$1\" }" >>MCradiolists + function $2 () { l_tristate '$2' \"\$1\" ;}" >>MCradiolists fi } @@ -147,7 +147,7 @@ echo -ne "'$2' '($x) $1' " >>MCmenu - echo -e "function $2 () { l_int '$1' '$2' '$3' '$x' }" >>MCradiolists + echo -e "function $2 () { l_int '$1' '$2' '$3' '$x' ;}" >>MCradiolists } # @@ -158,7 +158,7 @@ echo -ne "'$2' '($x) $1' " >>MCmenu - echo -e "function $2 () { l_hex '$1' '$2' '$3' '$x' }" >>MCradiolists + echo -e "function $2 () { l_hex '$1' '$2' '$3' '$x' ;}" >>MCradiolists } # @@ -196,7 +196,7 @@ echo -e " function $firstchoice () \ - { l_choice '$title' \"$choices\" $current }" >>MCradiolists + { l_choice '$title' \"$choices\" $current ;}" >>MCradiolists } } # END load_functions() @@ -331,7 +331,7 @@ echo -ne "'$2' '<$flag> $1' " >>MCmenu - echo -e "function $2 () { l_mod_bool '$2' \"\$1\" }" >>MCradiolists + echo -e "function $2 () { l_mod_bool '$2' \"\$1\" ;}" >>MCradiolists } # @@ -1020,7 +1020,7 @@ set_geometry () { # Some distributions export these with incorrect values # which can really screw up some ncurses programs. - unset LINES COLUMNS + LINES= COLUMNS= ROWS=${1:-24} COLS=${2:-80}