]> www.infradead.org Git - users/rw/ppcboot.git/commitdiff
First public version of PPCBOOT.
authorwdenk <wdenk>
Wed, 19 Jul 2000 14:09:16 +0000 (14:09 +0000)
committerwdenk <wdenk>
Wed, 19 Jul 2000 14:09:16 +0000 (14:09 +0000)
Add a lot of files :-)

72 files changed:
CREDITS [new file with mode: 0644]
README [new file with mode: 0644]
TODO [new file with mode: 0644]
common/Makefile [new file with mode: 0644]
common/board.c [new file with mode: 0644]
common/cmd_boot.c [new file with mode: 0644]
common/cmd_bootm.c [new file with mode: 0644]
common/cmd_cache.c [new file with mode: 0644]
common/cmd_flash.c [new file with mode: 0644]
common/cmd_mem.c [new file with mode: 0644]
common/cmd_nvedit.c [new file with mode: 0644]
common/command.c [new file with mode: 0644]
common/dlmalloc.c [new file with mode: 0644]
common/dlmalloc.src [new file with mode: 0644]
common/main.c [new file with mode: 0644]
common/s_record.c [new file with mode: 0644]
config.mk [new file with mode: 0644]
examples/Makefile [new file with mode: 0644]
examples/hello_world.c [new file with mode: 0644]
examples/timer.c [new file with mode: 0644]
include/asm/8xx_immap.h [new file with mode: 0644]
include/asm/mmu.h [new file with mode: 0644]
include/cmd_boot.h [new file with mode: 0644]
include/cmd_bootm.h [new file with mode: 0644]
include/cmd_cache.h [new file with mode: 0644]
include/cmd_flash.h [new file with mode: 0644]
include/cmd_mem.h [new file with mode: 0644]
include/cmd_nvedit.h [new file with mode: 0644]
include/command.h [new file with mode: 0644]
include/commproc.h [new file with mode: 0644]
include/config.h [new file with mode: 0644]
include/config_TQM850L.h [new file with mode: 0644]
include/flash.h [new file with mode: 0644]
include/image.h [new file with mode: 0644]
include/malloc.h [new file with mode: 0644]
include/mpc8xx.h [new file with mode: 0644]
include/mpc8xx_irq.h [new file with mode: 0644]
include/ppc_asm.tmpl [new file with mode: 0644]
include/ppc_defs.h [new file with mode: 0644]
include/ppcboot.h [new file with mode: 0644]
include/ppcboot.lds [new file with mode: 0644]
include/s_record.h [new file with mode: 0644]
include/version.h [new file with mode: 0644]
include/zlib.h [new file with mode: 0644]
mpc8xx/Makefile [new file with mode: 0644]
mpc8xx/config.mk [new file with mode: 0644]
mpc8xx/cpu.c [new file with mode: 0644]
mpc8xx/interrupts.c [new file with mode: 0644]
mpc8xx/serial.c [new file with mode: 0644]
mpc8xx/speed.c [new file with mode: 0644]
mpc8xx/speed.h [new file with mode: 0644]
mpc8xx/start.S [new file with mode: 0644]
mpc8xx/traps.c [new file with mode: 0644]
ppc/Makefile [new file with mode: 0644]
ppc/config.mk [new file with mode: 0644]
ppc/crc32.c [new file with mode: 0644]
ppc/ctype.c [new file with mode: 0644]
ppc/display_options.c [new file with mode: 0644]
ppc/extable.c [new file with mode: 0644]
ppc/ppcstring.S [new file with mode: 0644]
ppc/string.c [new file with mode: 0644]
ppc/vsprintf.c [new file with mode: 0644]
ppc/zlib.c [new file with mode: 0644]
tools/Makefile [new file with mode: 0644]
tools/crc32.c [new file with mode: 0644]
tools/img2srec.c [new file with mode: 0644]
tools/mkimage.c [new file with mode: 0644]
tqm8xx/Makefile [new file with mode: 0644]
tqm8xx/config.mk [new file with mode: 0644]
tqm8xx/flash.c [new file with mode: 0644]
tqm8xx/tqm8xx.c [new file with mode: 0644]
tqm8xx/tqm8xx.h [new file with mode: 0644]

diff --git a/CREDITS b/CREDITS
new file mode 100644 (file)
index 0000000..5ddbc12
--- /dev/null
+++ b/CREDITS
@@ -0,0 +1,42 @@
+
+    This is at least a partial credits-file of people that have
+    contributed to the PPCBOOT project. It is sorted by name and
+    formatted to allow easy grepping and beautification by scripts.
+    The fields are: name (N), email (E), web-address (W), PGP key ID
+    and fingerprint (P), description (D), and snail-mail address (S).
+    Thanks,
+
+                        Wolfgang Denk
+----------
+
+N: Roland Borde
+E: 100.130266@germanynet.de
+D: TFTP / BOOTP
+
+N: Raphael Bossek
+E: raphael.bossek@solutions4linux.de
+D: 8xxrom-0.3.0
+
+N: David Brown
+E: DBrown03@harris.com
+D: Extensions to 8xxrom-0.3.0
+
+N: Magnus Damm
+E: eramdam@kieray1.p.y.ki.era.ericsson.se
+D: 8xxrom
+
+N: Wolfgang Denk
+E: wd@denx.de
+D: PPCBOOT initial version
+
+N: Kirk Haderlie
+E: khaderlie@vividimage.com
+D: Added TFTP to 8xxrom (-> 0.3.1)
+
+N: Dan Malek
+E: dan@netx4.com
+D: FADSROM, the grandfather of all of this
+
+N: Neil Russell
+E: caret@c-side.com
+D: Author of LiMon-1.4.2, which contributed some ideas
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..4618585
--- /dev/null
+++ b/README
@@ -0,0 +1,833 @@
+#
+# (C) Copyright 2000
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+Summary:
+========
+
+This directory contains the source code for PPCBOOT, a monitor for
+Embedded PowerPC boards, which can be installed in a boot ROM and
+used to test the hardware or download and run application code.
+
+The development of PPCBOOT is closely related to Linux: some parts of
+the source code originate in the Linux source tree, we still have
+some header files in common, and special provision has been made to
+support booting of Linux images.
+
+Some attention has been paid to make this software easily
+configurable and extendable. For instance, all monitor commands are
+implemented with the same call interface, so that it's very easy to
+add new commands. Also, instead of permanently adding rarely used
+code (for instance hardware test utilities) to the monitor, you can
+load and run it dynamically.
+
+
+Where we come from:
+===================
+
+- start from 8xxrom sources
+- clean up code
+- make it easier to add custom boards
+- eventually make it possible to add other [PowerPC] CPUs
+- extend functions, especially:
+  * Provide extended interface to Linux boot loader
+  * S-Record download
+  * network boot
+  * PCMCIA / ATA disk boot
+
+
+Directory Hierarchy:
+====================
+
+- include      Header Files
+
+- mpc8xx       Files specific to Motorola MPC8xx CPUs
+
+= cpu          Symbolic Link to currently used CPU directory
+               [eventually created by config tool]
+
+- tqm8xx       Files specific to TQM8xxL boards
+
+- ads          Files specific to ADS boards
+
+- fads         Files specific to FADS boards
+
+- mbx          Files specific to MBX boards
+
+= board                Symbolic Link to currently used board directory
+               [eventually created by config tool]
+
+- ppc          Files generic to PowerPC architecture
+
+
+Software Configuration:
+=======================
+
+Configuration is usually done using C preprocessor defines; the
+rationale behind that is to avoid dead code whenever possible.
+
+There are two classes of configuration variables:
+
+* Configuration _OPTIONS_:
+  These are selectable by the user and have names beginning with
+  "CONFIG_".
+
+* Configuration _SETTINGS_:
+  These depend on the hardware etc. and should not be meddled with if
+  you don't know what you're doing; they have names beginning with
+  "CFG_".
+
+Later we will add a configuration tool - probably similar to or even
+identical to what's used for the Linux kernel. Right now, we have to
+do the configuration by hand, which means creating some symbolic
+links and editing some configuration files. We use the TQM8xxL boards
+as an example here.
+
+
+Selection of Processor Architecture and Board Type:
+---------------------------------------------------
+
+To select a specific processor architecture, create a symbolic link
+with the name "cpu" pointing to the directory for your CPU. [At the
+moment, only Motorola MPC8xx is supported.]
+
+To select a board type, create a symbolic link with the name  "board"
+pointing  to  the  directory  for your board. [At the moment, only TQ
+Components TQM8xxL modules are supported.]
+
+Example: TQM8xxL modules using MPC8xx CPUs:
+
+       cd ppcboot
+       ln -sf mpc8xx cpu
+       ln -sf tqm8xx board
+
+
+Configuration Options:
+----------------------
+
+Configuration depends on the combination of board and CPU type; all
+such information is kept in include/config.h ; usually you keep your
+definitions in a file with a more descriptive name, and make
+include/config.h a symbolic link pointing to that file.
+
+Example: TQM8xxL modules using a MPC850 CPU:
+
+       cd include
+       ln -sf config_TQM850L.h config.h
+
+The following options need to be configured:
+
+- CPU Type:    Define exactly one of
+                CONFIG_MPC823, CONFIG_MPC850, CONFIG_MPC855 or
+               CONFIG_MPC860
+
+- Board Type:  Define exactly one of
+                CONFIG_TQM823L, CONFIG_TQM850L, CONFIG_TQM855L,
+               CONFIG_TQM860L,
+--- FIXME --- not tested yet:
+                CONFIG_TQM860, CONFIG_FPS850L, CONFIG_MBX,
+                CONFIG_ADS, CONFIG_FADS, CONFIG_RPXLITE,
+                CONFIG_RPXCLASSIC, CONFIG_BSEIP
+
+- CPU Clock:   CONFIG_8xx_CPUCLOCK - in MHz
+--- FIXME --- obsolete
+
+- Bus Clock:   CONFIG_8xx_BUSCLOCK - in MHz
+                For MPC8xx systems usually the same as the CPU Clock
+--- FIXME --- use clock divider instead
+
+- DRAM Speed:  CONFIG_DRAM_SPEED
+--- FIXME --- obsolete?
+
+- Console Interface:
+               Define exactly one of
+               CONFIG_8xx_CONS_SMC1, CONFIG_8xx_CONS_SMC2
+
+- Console Baudrate:
+               CONFIG_8xx_BAUDRATE - in bps
+               Select one of 9600, 19200, 38400, 57600, 115200
+
+- Boot Delay:  CONFIG_8xx_BOOTDELAY - in seconds
+               Delay before automatically booting the default image;
+               set to 0 to disable autoboot.
+
+- Autoboot Command:
+               CONFIG_8xx_BOOTCOMMAND
+                Only needed when CONFIG_8xx_BOOTDELAY is enabled;
+                define a command string thatis automatically executed
+                when no character is read on the console interface
+                withing "Boot Delay" after reset.
+
+
+Configuration Settings:
+-----------------------
+
+- CFG_PROMPT:  This is what PPCBOOT prints on the console to
+               prompt for user input.
+
+- CFG_CBSIZE:  Buffer size for input from the Console
+
+- CFG_PBSIZE:  Buffer size for Console output
+
+- CFG_MAXARGS: max. Number of arguments accepted for monitor commands
+
+- CFG_BARGSIZE: Buffer size for Boot Arguments which are passed to
+               the application (usually a Linux kernel) when it is
+               bootet
+
+- CFG_MEMTEST_START, CFG_MEMTEST_END:
+                Begin and End addresses of the area used by the
+                simple memory test.
+
+- CFG_SDRAM_BASE:
+               Physical start address of SDRAM. _Must_ be 0 here.
+
+- CFG_FLASH_BASE:
+               Physical start address of Flash memory.
+
+- CFG_MONITOR_LEN:
+               Size of memory reserved for monitor code
+
+- CFG_HWINFO_LEN:
+               Size of Hardware Information stored with monitor
+
+- CFG_HWINFO_ADDR:
+               Physical start address of HW Information
+
+- CFG_MALLOC_LEN:
+               Size of DRAM reserved for malloc() use.
+
+- CFG_BOOTMAPSZ:
+                Maximum size of memory mapped by the startup code of
+                the Linux kernel; all data that must be processed by
+                the Linux kernel (bd_info, boot arguments, initrd
+                image) must be put below this limit.
+
+- CFG_MAX_FLASH_BANKS:
+               Max number of Flash memory banks
+
+- CFG_MAX_FLASH_SECT:
+               Max number of sectors on a Flash chip
+
+- CFG_FLASH_ERASE_TOUT:
+               Timeout for Flash erase operations (in ms)
+
+- CFG_FLASH_WRITE_TOUT:
+               Timeout for Flash write operations (in ms)
+
+
+Many of the remaining options are named exactly as the corresponding
+Linux kernel configuration options. The intention is to make it
+easier to build a config tool - later.
+
+Low Level (hardware related) configuration options:
+
+- CFG_CACHELINE_SIZE:
+               Cache Line Size of the CPU.
+
+- CFG_IMMR:    Physical address of the Internal Memory Mapped
+               Register; DO NOT CHANGE! (11-4)
+
+- CFG_SIUMCR:  SIU Module Configuration (11-6)
+
+- CFG_SYPCR:   System Protection Control (11-9)
+
+- CFG_TBSCR:   Time Base Status and Control (11-26)
+
+- CFG_PISCR:   Periodic Interrupt Status and Control (11-31)
+
+- CFG_PLPRCR:  PLL, Low-Power, and Reset Control Register (15-30)
+
+- CFG_SCCR:    System Clock and reset Control Register (15-27)
+
+- CFG_OR_TIMING_SDRAM:
+               SDRAM timing
+
+- CFG_MAMR_PTA:
+               periodic timer for refresh
+
+- MPC8XX_FACT: obsolete ???
+
+- CFG_DER:     Debug Event Register (37-47)
+
+- FLASH_BASE0_PRELIM, FLASH_BASE1_PRELIM, CFG_REMAP_OR_AM,
+  CFG_PRELIM_OR_AM, CFG_OR_TIMING_FLASH, CFG_OR0_REMAP,
+  CFG_OR0_PRELIM, CFG_BR0_PRELIM, CFG_OR1_REMAP, CFG_OR1_PRELIM,
+  CFG_BR1_PRELIM:
+               Memory Controller Definitions: BR0/1 and OR0/1 (FLASH)
+
+- SDRAM_BASE2_PRELIM, SDRAM_BASE3_PRELIM, SDRAM_MAX_SIZE,
+  CFG_OR_TIMING_SDRAM, CFG_OR2_PRELIM, CFG_BR2_PRELIM,
+  CFG_OR3_PRELIM, CFG_BR3_PRELIM:
+               Memory Controller Definitions: BR2/3 and OR2/3 (SDRAM)
+
+- CFG_MAMR_PTA, CFG_MPTPR_2BK_4K, CFG_MPTPR_1BK_4K, CFG_MPTPR_2BK_8K,
+  CFG_MPTPR_1BK_8K, CFG_MAMR_8COL, CFG_MAMR_9COL:
+                Machine Mode Register and Memory Periodic Timer
+                Prescaler definitions (SDRAM timing)
+
+
+Building the Software:
+======================
+
+Building PPCBOOT has been tested in native PPC environments (on a
+PowerBook G# running LinuxPPC 2000) and in cross environments
+(running RedHat 6.0 and 6.2 Linux on x86, and Solaris 2.6 on a
+SPARC).
+
+Especially after installing the PPCBOOT sources to a new directory
+hierarchy it is important to re-build all Makefile dependencies by
+running:
+
+       make dep
+
+Then a simple "make all" should build "ppcboot".
+
+
+Monitor Commands - Overview:
+============================
+
+go      - start application at address 'addr'
+bootm   - boot application image from memory
+loads   - load S-Record file over serial line
+md      - memory display
+mm      - memory modify (auto-incrementing)
+nm      - memory modify (constant address)
+mw      - memory write (fill)
+cp      - memory copy
+crc32   - checksum calculation
+base    - print or set address offset
+printenv- print environment variables
+setenv  - set environment variables
+saveenv - save environment variables to persistent storage
+bdinfo  - print Board Info structure
+flinfo  - print FLASH memory information
+iminfo  - print header information for application image
+erase   - erase FLASH memory
+protect - enable or disable FLASH write protection
+loop    - infinite loop on address range
+mtest   - simple RAM test
+icache  - enable or disable instruction cache
+dcache  - enable or disable data cache
+reset   - Perform RESET of the CPU
+version - print monitor version
+help    - print online help
+?       - alias for 'help'
+
+
+Monitor Commands - Detailed Description:
+========================================
+
+TODO.
+
+For now: just type "help <command>".
+
+
+Image Formats:
+==============
+
+The "boot" commands of this monitor operate on "image" files which
+can be basicly anything, preceeded by a special header; see the
+definitions in include/image.h for details; basicly, the header
+defines the following image properties:
+
+* Target Operating System (Provisions for OpenBSD, NetBSD, FreeBSD,
+  4.4BSD, Linux, SVR4, Esix, Solaris, Irix, SCO, Dell, NCR, VxWorks,
+  LynxOS, pSOS, QNX; Currently supported: Linux).
+* Target CPU Architecture (Provisions for Alpha, ARM, Intel x86,
+  IA64, MIPS, MIPS, PowerPC, IBM S390, SuperH, Sparc, Sparc 64 Bit;
+  Currently supported: PowerPC).
+* Compression Type (Provisions for uncompressed, gzip, bzip2;
+  Currently supported: uncompressed, gzip).
+* Load Address
+* Entry Point
+* Image Name
+* Image Timestamp
+
+The header is marked by a special Magic Number, and both the header
+and the data portions of the image are secured against corruption by
+CRC32 checksums.
+
+
+Linux Support:
+==============
+
+Although PPCBOOT should support any OS or standalone application
+easily, Linux has always been in the focus during the design of
+PPCBOOT.
+
+PPCBOOT includes many features that so far have been part of some
+special "boot loader" code within the Linux kernel. Also, any
+"initrd" images to be used are no longer part of one big Linux image;
+instead, kernel and "initrd" are separate images. This implementation
+serves serveral purposes:
+
+- the same features can be used for other OS or standalone
+  applications (for instance: using compressed images to reduce the
+  Flash memory footprint)
+
+- it becomes much easier to port new Linux kernel versions because
+  lots of low-level, hardware dependend stuff are done by PPCBOOT
+
+- the same Linux kernel image can now be used with different "initrd"
+  images; of course this also means that different kernel images can
+  be run with the same "initrd". This makes testing easier (you don't
+  have to build a new "zImage.initrd" Linux image when you just
+  change a file in your "initrd"). Also, a field-upgrade of the
+  software is easier now.
+
+
+Linux HOWTO:
+============
+
+Porting Linux to PPCBOOT based systems:
+---------------------------------------
+
+PPCBOOT cannot save you from doing all the necessary modifications to
+configure the Linux device drivers for use with your target hardware
+(no, we don't intend to provide a full virtual machine interface to
+Linux :-).
+
+But now you can ignore ALL boot loader code (in arch/ppc/mbxboot).
+
+Just make sure your machine specific header file (for instance
+include/asm-ppc/tqm8xx.h) includes the same definition of the Board
+Information structure as we define in include/ppcboot.h
+
+
+Configuring the Linux kernel:
+-----------------------------
+
+No specific requirements for PPCBOOT. Make sure you have some root
+device (initial ramdisk, NFS) for your target system.
+
+
+Building a Linux Image:
+-----------------------
+
+No specific requirements for PPCBOOT. There is no need to add a
+"ramdisk.image.gz" file when building the kernel, even when you
+intend to run it with initial ramdisk.
+
+Example:
+
+       make TQM850L_config
+       make oldconfig
+       make dep
+       make zImage
+
+However, we don't use the 'zImage' (= 'arch/ppc/mbxboot/zvmlinux') we
+build this way. The 'zImage' includes the old boot loader code which
+we don't ned any more. Instead, we use the raw (compressed) Linux
+kernel image in 'arch/ppc/coffboot/vmlinux.gz'.
+
+There is a special tool (in 'tools/mkimage') to encapsulate this
+image with header information, CRC32 checksum etc. for use with
+PPCBOOT:
+
+In the first form (with "-l" option) mkimage  lists  the  information
+contained  in  the header of an existing PPCBOOT image; this includes
+checksum verification:
+
+       tools/mkimage -l image
+         -l ==> list image header information
+
+The second form (with "-d" option) is used to build a PPCBOOT image
+from a "data file" which is used as image payload:
+
+       tools/mkimage -A arch -O os -T type -C comp -a addr -e ep \
+                     -n name -d data_file image
+         -A ==> set architecture to 'arch'
+         -O ==> set operating system to 'os'
+         -T ==> set image type to 'type'
+         -C ==> set compression type 'comp'
+         -a ==> set load address to 'addr' (hex)
+         -e ==> set entry point to 'ep' (hex)
+         -n ==> set image name to 'name'
+         -d ==> use image data from 'datafile'
+
+Right now, all Linux kernels use the same load  address  (0x00000000)
+and  entry  point  address (0x0000000C). So a typical call to build a
+PPCBOOT image would read:
+
+       -> tools/mkimage -n '2.2.13 for initrd on TQM850L' \
+       > -A ppc -O linux -T kernel -C gzip -a 00000000 -e 0000000C \
+       > -d /opt/mpc8xx/src/linux-2.2.13/arch/ppc/coffboot/vmlinux.gz \
+       > examples/image-2.2.13-initrd
+       Image Name:   2.2.13 for initrd on TQM850L
+       Created:      Wed Jul 19 02:34:59 2000
+       Image Type:   PowerPC Linux Kernel Image (gzip compressed)
+       Data Size:    335725 Bytes = 327.86 kB = 0.32 MB
+       Load Address: 0x00000000
+       Entry Point:  0x0000000c
+
+To verify the contents of the image (or check for corruption):
+
+       -> tools/mkimage -l examples/image-2.2.13-initrd
+       Image Name:   2.2.13 for initrd on TQM850L
+       Created:      Wed Jul 19 02:34:59 2000
+       Image Type:   PowerPC Linux Kernel Image (gzip compressed)
+       Data Size:    335725 Bytes = 327.86 kB = 0.32 MB
+       Load Address: 0x00000000
+       Entry Point:  0x0000000c
+
+NOTE: for embedded systems where boot time is critical you can trade
+speed for memory and install an UNCOMPRESSED image instead: this
+needs more space in Flash, but boots much faster since it does not
+need to be uncompressed:
+
+       -> gunzip /opt/mpc8xx/src/linux-2.2.13/arch/ppc/coffboot/vmlinux.gz
+       -> tools/mkimage -n '2.2.13 for initrd on TQM850L' \
+       > -A ppc -O linux -T kernel -C none -a 00000000 -e 0000000C \
+       > -d /opt/mpc8xx/src/linux-2.2.13/arch/ppc/coffboot/vmlinux \
+       > examples/image-2.2.13-initrd-uncompressed
+       Image Name:   2.2.13 for initrd on TQM850L
+       Created:      Wed Jul 19 02:34:59 2000
+       Image Type:   PowerPC Linux Kernel Image (uncompressed)
+       Data Size:    792160 Bytes = 773.59 kB = 0.76 MB
+       Load Address: 0x00000000
+       Entry Point:  0x0000000c
+
+
+Similar you can build PPCBOOT images from a 'ramdisk.image.gz' file
+when your kernel is intended to use an initial ramdisk:
+
+       -> tools/mkimage -n 'Simple Ramdisk Image' \
+       > -A ppc -O linux -T ramdisk -C gzip \
+       > -d /LinuxPPC/images/SIMPLE-ramdisk.image.gz examples/simple-initrd
+       Image Name:   Simple Ramdisk Image
+       Created:      Wed Jan 12 14:01:50 2000
+       Image Type:   PowerPC Linux RAMDisk Image (gzip compressed)
+       Data Size:    566530 Bytes = 553.25 kB = 0.54 MB
+       Load Address: 0x00000000
+       Entry Point:  0x00000000
+
+
+Installing a Linux Image:
+-------------------------
+
+To downloading a PPCBOOT image over the serial (console) interface,
+you must convert the image to S-Record format:
+
+       objcopy -I binary -O srec examples/image examples/image.srec
+
+The 'objcopy' does not understand the information in the PPCBOOT
+image header, so the resulting S-Record file will be relative to
+address 0x00000000. To load it to a given address, you need to
+specify the target address as 'offset' parameter with the 'loads'
+command.
+
+Example: install the image to address 0x40100000 (which on the
+TQM8xxL is in the first Flash bank):
+
+       => erase 40100000 401FFFFF
+
+       .......... done
+       Erased 8 sectors
+
+       => loads 40100000
+       ## Ready for S-Record download ...
+       ~>examples/image.srec
+       1 2 3 4 5 6 7 8 9 10 11 12 13 ...
+       ...
+       15989 15990 15991 15992 
+       [file transfer complete]
+       [connected]
+       ## Start Addr = 0x00000000
+
+
+You can check the success of the download using the 'iminfo' command;
+this includes a checksum verification so you  can  be  sure  no  data
+corruption happened:
+
+       => imi 40100000
+
+       ## Checking Image at 40100000 ...
+          Image Name:   2.2.13 for initrd on TQM850L
+          Image Type:   PowerPC Linux Kernel Image (gzip compressed)
+          Data Size:    335725 Bytes = 327 kB = 0 MB
+          Load Address: 00000000
+          Entry Point:  0000000c
+          Verifying Checksum ... OK
+
+
+
+Boot Linux:
+-----------
+
+The "bootm" command is used to boot an application that is stored in
+memory (RAM or Flash). In case of a Linux kernel image, the contents
+of the "bootargs" environment variable is passed to the kernel as
+parameters. You can check and modify this vriable using the
+"printenv" and "setenv" commands:
+
+
+       => printenv bootargs
+       bootargs=root=/dev/ram
+
+       => setenv bootargs root=/dev/nfs rw nfsroot=10.0.0.2:/LinuxPPC nfsaddrs=10.0.0.99:10.0.0.2
+
+       => printenv bootargs
+       bootargs=root=/dev/nfs rw nfsroot=10.0.0.2:/LinuxPPC nfsaddrs=10.0.0.99:10.0.0.2
+
+       => bootm 40020000
+       ## Booting Linux kernel at 40020000 ...
+          Image Name:   2.2.13 for NFS on TQM850L
+          Image Type:   PowerPC Linux Kernel Image (gzip compressed)
+          Data Size:    381681 Bytes = 372 kB = 0 MB
+          Load Address: 00000000
+          Entry Point:  0000000c
+          Verifying Checksum ... OK
+          Uncompressing Kernel Image ... OK
+       Linux version 2.2.13 (wd@denx.local.net) (gcc version 2.95.2 19991024 (release)) #1 Wed Jul 19 02:35:17 MEST 2000
+       Boot arguments: root=/dev/nfs rw nfsroot=10.0.0.2:/LinuxPPC nfsaddrs=10.0.0.99:10.0.0.2
+       time_init: decrementer frequency = 187500000/60
+       Calibrating delay loop... 49.77 BogoMIPS
+       Memory: 15208k available (700k kernel code, 444k data, 32k init) [c0000000,c1000000]
+       ...
+
+If you want to boot a Linux kernel with initial ram disk, you pass
+the memory addreses of both the kernel and the initrd image (PPBCOOT
+format!) to the "bootm" command:
+
+       => imi 40100000 40200000
+
+       ## Checking Image at 40100000 ...
+          Image Name:   2.2.13 for initrd on TQM850L
+          Image Type:   PowerPC Linux Kernel Image (gzip compressed)
+          Data Size:    335725 Bytes = 327 kB = 0 MB
+          Load Address: 00000000
+          Entry Point:  0000000c
+          Verifying Checksum ... OK
+
+       ## Checking Image at 40200000 ...
+          Image Name:   Simple Ramdisk Image
+          Image Type:   PowerPC Linux RAMDisk Image (gzip compressed)
+          Data Size:    566530 Bytes = 553 kB = 0 MB
+          Load Address: 00000000
+          Entry Point:  00000000
+          Verifying Checksum ... OK
+
+       => bootm 40100000 40200000
+       ## Booting Linux kernel at 40100000 ...
+          Image Name:   2.2.13 for initrd on TQM850L
+          Image Type:   PowerPC Linux Kernel Image (gzip compressed)
+          Data Size:    335725 Bytes = 327 kB = 0 MB
+          Load Address: 00000000
+          Entry Point:  0000000c
+          Verifying Checksum ... OK
+          Uncompressing Kernel Image ... OK
+       ## Loading RAMDisk Image at 40200000 ...
+          Image Name:   Simple Ramdisk Image
+          Image Type:   PowerPC Linux RAMDisk Image (gzip compressed)
+          Data Size:    566530 Bytes = 553 kB = 0 MB
+          Load Address: 00000000
+          Entry Point:  00000000
+          Verifying Checksum ... OK
+          Loading Ramdisk ... OK
+       Linux version 2.2.13 (wd@denx.local.net) (gcc version 2.95.2 19991024 (release)) #1 Wed Jul 19 02:32:08 MEST 2000
+       Boot arguments: root=/dev/ram
+       time_init: decrementer frequency = 187500000/60
+       Calibrating delay loop... 49.77 BogoMIPS
+       ...
+       RAMDISK: Compressed image found at block 0
+       VFS: Mounted root (ext2 filesystem).
+
+       bash# 
+
+
+Standalone HOWTO:
+=================
+
+One of the features of PPCBOOT is that you can dynamically load and
+run "standalone" applications, which can use some resources of
+PPCBOOT like console I/O functions or interrupt services.
+
+Two simple examples are included with the sources:
+
+"Hello World" Demo:
+-------------------
+
+'examples/hello_world.c' contains a small "Hello World" Demo
+application; it is automatically compiled when you build PPCBOOT.
+It's configured to run at address 0x00040004, so you can play with it
+like that:
+
+       => loads
+       ## Ready for S-Record download ...
+       ~>examples/hello_world.srec
+       1 2 3 4 5 6 7 8 9 10 11 ...
+       [file transfer complete]
+       [connected]
+       ## Start Addr = 0x00040004
+
+       => go 40004 Hello World! This is a test.
+       ## Starting application at 0x00040004 ...
+       Hello World
+       argc = 7
+       argv[0] = "40004"
+       argv[1] = "Hello"
+       argv[2] = "World!"
+       argv[3] = "This"
+       argv[4] = "is"
+       argv[5] = "a"
+       argv[6] = "test."
+       argv[7] = "<NULL>"
+       Hit any key to exit ... 
+
+       ## Application terminated, rc = 0x0
+
+Another example, which demonstrates how to register a CPM interrupt
+handler with the PPCBOOT code, can be found in 'examples/timer.c'.
+Here, a CPM timer is set up to generate an interrupt every second.
+The interrupt service routine is trivial, just printing a '.'
+character, but this is just a demo program. The application can be
+controlled by the following keys:
+
+       ? - print current values og the CPM Timer registers
+       b - enable interrupts and start timer
+       e - stop timer and disable interrupts
+       q - quit application
+
+       => loads
+       ## Ready for S-Record download ...
+       ~>examples/timer.srec
+       1 2 3 4 5 6 7 8 9 10 11 ...
+       [file transfer complete]
+       [connected]
+       ## Start Addr = 0x00040004
+
+       => go 40004
+       ## Starting application at 0x00040004 ...
+       TIMERS=0xfff00980
+       Using timer 1
+         tgcr @ 0xfff00980, tmr @ 0xfff00990, trr @ 0xfff00994, tcr @ 0xfff00998, tcn @ 0xfff0099c, ter @ 0xfff009b0
+
+Hit 'b':
+       [q, b, e, ?] Set interval 1000000 us
+       Enabling timer
+Hit '?':
+       [q, b, e, ?] ........
+       tgcr=0x1, tmr=0xff1c, trr=0x3d09, tcr=0x0, tcn=0xef6, ter=0x0
+Hit '?':
+       [q, b, e, ?] .
+       tgcr=0x1, tmr=0xff1c, trr=0x3d09, tcr=0x0, tcn=0x2ad4, ter=0x0
+Hit '?':
+       [q, b, e, ?] .
+       tgcr=0x1, tmr=0xff1c, trr=0x3d09, tcr=0x0, tcn=0x1efc, ter=0x0
+Hit '?':
+       [q, b, e, ?] .
+       tgcr=0x1, tmr=0xff1c, trr=0x3d09, tcr=0x0, tcn=0x169d, ter=0x0
+Hit 'e':
+       [q, b, e, ?] ...Stopping timer
+Hit 'q':
+       [q, b, e, ?] ## Application terminated, rc = 0x0
+
+
+
+
+Implementation Internals:
+=========================
+
+The following is not intended to be a complete description of every
+implementation detail. However, it should help to understand the
+inner workings of PPCBOOT and make it easier to port it to custom
+hardware.
+
+
+Memory Management:
+------------------
+
+PPCBOOT runs in system state and uses physical addresses, i.e. the
+MMU is not used either for address mapping nor for memory protection.
+
+The available memory is mapped to fixed addresses usuing the memory
+controller. In this process, a contiguous block is formed for each
+memory type (Flash, SDRAM, SRAM), even when it consists out of
+several physical memory banks.
+
+PPCBOOT is installed in the first 128 kB of the first Flash bank (on
+TQM8xxL modules this is the range 0x40000000 ... 0x4001FFFF). After
+booting and sizing and initializing DRAM, the code relocates itself
+to the upper end of DRAM. Immediately below the PPCBOOT code some
+memory is reserved for use by malloc() [see CFG_MALLOC_LEN
+configuration setting]. Below that, a structure with global Board
+Info data is placed, followed by the stack (growing downward).
+
+Additionally, some exception handler code is copied to the low 8 kB
+of DRAM (0x00000000 ... 0x00001FFF).
+
+So a typical memory configuration with 16 MB of DRAM could look like
+this:
+
+       0x0000 0000     Exception Vector code
+             :
+       0x0000 1FFF
+       0x0000 2000     Free for Application Use
+             :
+             :
+
+             :
+             :
+       0x00FB FF20     Monitor Stack (Growing downward)
+       0x00FB FFAC     Board Info Data
+       0x00FC 0000     Malloc Arena
+             :
+       0x00FD FFFF
+       0x00FE 0000     RAM Copy of Monitor Code
+       0x00FF FFFF     [End of RAM]
+
+
+System Initialization:
+----------------------
+
+In the reset configuration, PPCBOOT starts at address 0x00000100.
+Because of the reset configuration for CS0# this is a mirror of the
+onboard Flash memory. To be able to re-map memory PPCBOOT then jumps
+to it's link address. To be able to implement the initialization code
+in C, a (small!) initial stack is set up in the internal Dual Ported
+RAM of the MPC8xx. After that, PPCBOOT initialises the CPU core, the
+caches and the SIU.
+
+Next, all (potentially) available memory banks are mapped using a
+prelimonary mapping, which puts them on 512 MB boundaries (multiples
+of 0x20000000: SDRAM on 0x00000000 and 0x20000000, Flash on
+0x40000000 and 0x60000000, SRAM on 0x80000000). Then UPM A is
+programmed for SDRAM access. Using the temporary configuration, a
+simple memory test is run that determines the size of the SDRAM
+banks.
+
+When there is more than one SDRAM bank, and the banks are of
+different size, the larger is mapped first. For equal size, the first
+bank (CS2#) is mapped first. The first mapping is always for address
+0x00000000, with any additional banks following immediately to create
+contiguous memory starting from 0.
+
+Then, the monitor installs itself at the upper end of the SDRAM area
+and allocates memory for use by malloc() and for the global Board
+Info data; also, the exception vector code is copied to the low RAM
+pages, and the final stack is set up.
+
+Only after this relocation you have a "normal" C environment; until
+that you are restricted in several ways, mostly because you are
+running from ROM, and because the code will have to be relocated to a
+new address in RAM.
diff --git a/TODO b/TODO
new file mode 100644 (file)
index 0000000..495c703
--- /dev/null
+++ b/TODO
@@ -0,0 +1,60 @@
+* mkimage:
+
+  BUG: mkimage -d does not truncate an existing image
+
+* loads:
+
+  Printing error messages does not work because "cu" is eating all
+  output.
+
+* iminfo:
+
+  Print timestamp information, too.
+
+* NEW:
+
+  Set system clock.
+
+* saveenv:
+
+  Implement writing environment variables to Flash. Needs special
+  layout of monitor image to reserve one of the small Flash "boot"
+  sectors. Make sure we fall back to useful defaults in case somebody
+  erases the Flash contents.
+
+* INIT:
+
+  get ethernet address from environment
+
+* INIT:
+
+  Replace `serial_io' and `intr_util' structs in bd_info by generic
+  structure containing `monitor functions'; add things like malloc()
+  and free().
+
+* protect:
+
+  Bug in sector limit check:
+
+       => protect off 40000000 40008000
+       Un-Protected 35 sectors
+
+* ALL:
+
+  Put `implementation' features in #ifdef's to make it possible to
+  shrink monitor size to specific needs
+
+* command:
+
+  Make "long help" texts configurable by a #ifdef to reduce monitor
+  size
+
+* bootm:
+
+  Make checksum verification of images optional (depending on
+  "verify" environment variable?) to allow for fast boot is speed is
+  more important than safety.
+
+* NEW:
+
+  Implement equivalent to TQ "sethwi" command
diff --git a/common/Makefile b/common/Makefile
new file mode 100644 (file)
index 0000000..1482f37
--- /dev/null
@@ -0,0 +1,328 @@
+#
+# (C) Copyright 2000
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB    = libcommon.a
+
+OBJS   = board.o main.o command.o \
+         cmd_cache.o cmd_mem.o cmd_boot.o cmd_flash.o \
+         cmd_bootm.o cmd_nvedit.o \
+         s_record.o dlmalloc.o
+
+CPPFLAGS += -I..
+
+$(LIB):        $(OBJS)
+       $(AR) crv $@ $(OBJS)
+
+clean:
+       rm -f $(OBJS)
+
+distclean:     clean
+       rm -f $(LIB) core *.bak
+
+#########################################################################
+
+depend dep:
+       $(MAKEDEPEND) -- $(CFLAGS) -- $(OBJS:.o=.c)
+
+#########################################################################
+
+# DO NOT DELETE
+
+board.o: /home/wd/ppc/ppcboot/include/ppcboot.h
+board.o: /home/wd/ppc/ppcboot/include/config.h
+board.o: /LinuxPPC/CDK/include/linux/bitops.h
+board.o: /LinuxPPC/CDK/include/asm/bitops.h
+board.o: /LinuxPPC/CDK/include/asm/system.h
+board.o: /LinuxPPC/CDK/include/linux/kdev_t.h
+board.o: /LinuxPPC/CDK/include/asm/processor.h
+board.o: /LinuxPPC/CDK/include/linux/config.h
+board.o: /LinuxPPC/CDK/include/asm/ptrace.h
+board.o: /LinuxPPC/CDK/include/asm/residual.h /LinuxPPC/CDK/include/asm/pnp.h
+board.o: /LinuxPPC/CDK/include/asm/atomic.h
+board.o: /LinuxPPC/CDK/include/asm/byteorder.h
+board.o: /LinuxPPC/CDK/include/asm/types.h
+board.o: /LinuxPPC/CDK/include/linux/byteorder/big_endian.h
+board.o: /LinuxPPC/CDK/include/linux/byteorder/swab.h
+board.o: /LinuxPPC/CDK/include/linux/byteorder/generic.h
+board.o: /LinuxPPC/CDK/include/linux/types.h
+board.o: /LinuxPPC/CDK/include/linux/posix_types.h
+board.o: /LinuxPPC/CDK/include/linux/stddef.h
+board.o: /LinuxPPC/CDK/include/asm/posix_types.h
+board.o: /LinuxPPC/CDK/include/linux/string.h
+board.o: /LinuxPPC/CDK/include/asm/string.h
+board.o: /home/wd/ppc/ppcboot/include/asm/8xx_immap.h
+board.o: /home/wd/ppc/ppcboot/include/flash.h
+board.o: /home/wd/ppc/ppcboot/include/command.h
+board.o: /home/wd/ppc/ppcboot/include/mpc8xx.h
+main.o: /home/wd/ppc/ppcboot/include/ppcboot.h
+main.o: /home/wd/ppc/ppcboot/include/config.h
+main.o: /LinuxPPC/CDK/include/linux/bitops.h
+main.o: /LinuxPPC/CDK/include/asm/bitops.h /LinuxPPC/CDK/include/asm/system.h
+main.o: /LinuxPPC/CDK/include/linux/kdev_t.h
+main.o: /LinuxPPC/CDK/include/asm/processor.h
+main.o: /LinuxPPC/CDK/include/linux/config.h
+main.o: /LinuxPPC/CDK/include/asm/ptrace.h
+main.o: /LinuxPPC/CDK/include/asm/residual.h /LinuxPPC/CDK/include/asm/pnp.h
+main.o: /LinuxPPC/CDK/include/asm/atomic.h
+main.o: /LinuxPPC/CDK/include/asm/byteorder.h
+main.o: /LinuxPPC/CDK/include/asm/types.h
+main.o: /LinuxPPC/CDK/include/linux/byteorder/big_endian.h
+main.o: /LinuxPPC/CDK/include/linux/byteorder/swab.h
+main.o: /LinuxPPC/CDK/include/linux/byteorder/generic.h
+main.o: /LinuxPPC/CDK/include/linux/types.h
+main.o: /LinuxPPC/CDK/include/linux/posix_types.h
+main.o: /LinuxPPC/CDK/include/linux/stddef.h
+main.o: /LinuxPPC/CDK/include/asm/posix_types.h
+main.o: /LinuxPPC/CDK/include/linux/string.h
+main.o: /LinuxPPC/CDK/include/asm/string.h
+main.o: /home/wd/ppc/ppcboot/include/asm/8xx_immap.h
+main.o: /home/wd/ppc/ppcboot/include/flash.h
+main.o: /home/wd/ppc/ppcboot/include/command.h
+command.o: /home/wd/ppc/ppcboot/include/ppcboot.h
+command.o: /home/wd/ppc/ppcboot/include/config.h
+command.o: /LinuxPPC/CDK/include/linux/bitops.h
+command.o: /LinuxPPC/CDK/include/asm/bitops.h
+command.o: /LinuxPPC/CDK/include/asm/system.h
+command.o: /LinuxPPC/CDK/include/linux/kdev_t.h
+command.o: /LinuxPPC/CDK/include/asm/processor.h
+command.o: /LinuxPPC/CDK/include/linux/config.h
+command.o: /LinuxPPC/CDK/include/asm/ptrace.h
+command.o: /LinuxPPC/CDK/include/asm/residual.h
+command.o: /LinuxPPC/CDK/include/asm/pnp.h /LinuxPPC/CDK/include/asm/atomic.h
+command.o: /LinuxPPC/CDK/include/asm/byteorder.h
+command.o: /LinuxPPC/CDK/include/asm/types.h
+command.o: /LinuxPPC/CDK/include/linux/byteorder/big_endian.h
+command.o: /LinuxPPC/CDK/include/linux/byteorder/swab.h
+command.o: /LinuxPPC/CDK/include/linux/byteorder/generic.h
+command.o: /LinuxPPC/CDK/include/linux/types.h
+command.o: /LinuxPPC/CDK/include/linux/posix_types.h
+command.o: /LinuxPPC/CDK/include/linux/stddef.h
+command.o: /LinuxPPC/CDK/include/asm/posix_types.h
+command.o: /LinuxPPC/CDK/include/linux/string.h
+command.o: /LinuxPPC/CDK/include/asm/string.h
+command.o: /home/wd/ppc/ppcboot/include/asm/8xx_immap.h
+command.o: /home/wd/ppc/ppcboot/include/flash.h
+command.o: /home/wd/ppc/ppcboot/include/command.h
+command.o: /home/wd/ppc/ppcboot/include/cmd_cache.h
+command.o: /home/wd/ppc/ppcboot/include/cmd_mem.h
+command.o: /home/wd/ppc/ppcboot/include/cmd_boot.h
+command.o: /home/wd/ppc/ppcboot/include/cmd_flash.h
+command.o: /home/wd/ppc/ppcboot/include/cmd_bootm.h
+command.o: /home/wd/ppc/ppcboot/include/cmd_nvedit.h
+cmd_cache.o: /home/wd/ppc/ppcboot/include/ppcboot.h
+cmd_cache.o: /home/wd/ppc/ppcboot/include/config.h
+cmd_cache.o: /LinuxPPC/CDK/include/linux/bitops.h
+cmd_cache.o: /LinuxPPC/CDK/include/asm/bitops.h
+cmd_cache.o: /LinuxPPC/CDK/include/asm/system.h
+cmd_cache.o: /LinuxPPC/CDK/include/linux/kdev_t.h
+cmd_cache.o: /LinuxPPC/CDK/include/asm/processor.h
+cmd_cache.o: /LinuxPPC/CDK/include/linux/config.h
+cmd_cache.o: /LinuxPPC/CDK/include/asm/ptrace.h
+cmd_cache.o: /LinuxPPC/CDK/include/asm/residual.h
+cmd_cache.o: /LinuxPPC/CDK/include/asm/pnp.h
+cmd_cache.o: /LinuxPPC/CDK/include/asm/atomic.h
+cmd_cache.o: /LinuxPPC/CDK/include/asm/byteorder.h
+cmd_cache.o: /LinuxPPC/CDK/include/asm/types.h
+cmd_cache.o: /LinuxPPC/CDK/include/linux/byteorder/big_endian.h
+cmd_cache.o: /LinuxPPC/CDK/include/linux/byteorder/swab.h
+cmd_cache.o: /LinuxPPC/CDK/include/linux/byteorder/generic.h
+cmd_cache.o: /LinuxPPC/CDK/include/linux/types.h
+cmd_cache.o: /LinuxPPC/CDK/include/linux/posix_types.h
+cmd_cache.o: /LinuxPPC/CDK/include/linux/stddef.h
+cmd_cache.o: /LinuxPPC/CDK/include/asm/posix_types.h
+cmd_cache.o: /LinuxPPC/CDK/include/linux/string.h
+cmd_cache.o: /LinuxPPC/CDK/include/asm/string.h
+cmd_cache.o: /home/wd/ppc/ppcboot/include/asm/8xx_immap.h
+cmd_cache.o: /home/wd/ppc/ppcboot/include/flash.h
+cmd_cache.o: /home/wd/ppc/ppcboot/include/command.h
+cmd_cache.o: /home/wd/ppc/ppcboot/include/cmd_cache.h
+cmd_mem.o: /home/wd/ppc/ppcboot/include/ppcboot.h
+cmd_mem.o: /home/wd/ppc/ppcboot/include/config.h
+cmd_mem.o: /LinuxPPC/CDK/include/linux/bitops.h
+cmd_mem.o: /LinuxPPC/CDK/include/asm/bitops.h
+cmd_mem.o: /LinuxPPC/CDK/include/asm/system.h
+cmd_mem.o: /LinuxPPC/CDK/include/linux/kdev_t.h
+cmd_mem.o: /LinuxPPC/CDK/include/asm/processor.h
+cmd_mem.o: /LinuxPPC/CDK/include/linux/config.h
+cmd_mem.o: /LinuxPPC/CDK/include/asm/ptrace.h
+cmd_mem.o: /LinuxPPC/CDK/include/asm/residual.h
+cmd_mem.o: /LinuxPPC/CDK/include/asm/pnp.h /LinuxPPC/CDK/include/asm/atomic.h
+cmd_mem.o: /LinuxPPC/CDK/include/asm/byteorder.h
+cmd_mem.o: /LinuxPPC/CDK/include/asm/types.h
+cmd_mem.o: /LinuxPPC/CDK/include/linux/byteorder/big_endian.h
+cmd_mem.o: /LinuxPPC/CDK/include/linux/byteorder/swab.h
+cmd_mem.o: /LinuxPPC/CDK/include/linux/byteorder/generic.h
+cmd_mem.o: /LinuxPPC/CDK/include/linux/types.h
+cmd_mem.o: /LinuxPPC/CDK/include/linux/posix_types.h
+cmd_mem.o: /LinuxPPC/CDK/include/linux/stddef.h
+cmd_mem.o: /LinuxPPC/CDK/include/asm/posix_types.h
+cmd_mem.o: /LinuxPPC/CDK/include/linux/string.h
+cmd_mem.o: /LinuxPPC/CDK/include/asm/string.h
+cmd_mem.o: /home/wd/ppc/ppcboot/include/asm/8xx_immap.h
+cmd_mem.o: /home/wd/ppc/ppcboot/include/flash.h
+cmd_mem.o: /home/wd/ppc/ppcboot/include/command.h
+cmd_mem.o: /home/wd/ppc/ppcboot/include/cmd_mem.h
+cmd_boot.o: /home/wd/ppc/ppcboot/include/ppcboot.h
+cmd_boot.o: /home/wd/ppc/ppcboot/include/config.h
+cmd_boot.o: /LinuxPPC/CDK/include/linux/bitops.h
+cmd_boot.o: /LinuxPPC/CDK/include/asm/bitops.h
+cmd_boot.o: /LinuxPPC/CDK/include/asm/system.h
+cmd_boot.o: /LinuxPPC/CDK/include/linux/kdev_t.h
+cmd_boot.o: /LinuxPPC/CDK/include/asm/processor.h
+cmd_boot.o: /LinuxPPC/CDK/include/linux/config.h
+cmd_boot.o: /LinuxPPC/CDK/include/asm/ptrace.h
+cmd_boot.o: /LinuxPPC/CDK/include/asm/residual.h
+cmd_boot.o: /LinuxPPC/CDK/include/asm/pnp.h
+cmd_boot.o: /LinuxPPC/CDK/include/asm/atomic.h
+cmd_boot.o: /LinuxPPC/CDK/include/asm/byteorder.h
+cmd_boot.o: /LinuxPPC/CDK/include/asm/types.h
+cmd_boot.o: /LinuxPPC/CDK/include/linux/byteorder/big_endian.h
+cmd_boot.o: /LinuxPPC/CDK/include/linux/byteorder/swab.h
+cmd_boot.o: /LinuxPPC/CDK/include/linux/byteorder/generic.h
+cmd_boot.o: /LinuxPPC/CDK/include/linux/types.h
+cmd_boot.o: /LinuxPPC/CDK/include/linux/posix_types.h
+cmd_boot.o: /LinuxPPC/CDK/include/linux/stddef.h
+cmd_boot.o: /LinuxPPC/CDK/include/asm/posix_types.h
+cmd_boot.o: /LinuxPPC/CDK/include/linux/string.h
+cmd_boot.o: /LinuxPPC/CDK/include/asm/string.h
+cmd_boot.o: /home/wd/ppc/ppcboot/include/asm/8xx_immap.h
+cmd_boot.o: /home/wd/ppc/ppcboot/include/flash.h
+cmd_boot.o: /home/wd/ppc/ppcboot/include/command.h
+cmd_boot.o: /home/wd/ppc/ppcboot/include/cmd_boot.h
+cmd_boot.o: /home/wd/ppc/ppcboot/include/s_record.h
+cmd_boot.o: /home/wd/ppc/ppcboot/include/mpc8xx.h
+cmd_flash.o: /home/wd/ppc/ppcboot/include/ppcboot.h
+cmd_flash.o: /home/wd/ppc/ppcboot/include/config.h
+cmd_flash.o: /LinuxPPC/CDK/include/linux/bitops.h
+cmd_flash.o: /LinuxPPC/CDK/include/asm/bitops.h
+cmd_flash.o: /LinuxPPC/CDK/include/asm/system.h
+cmd_flash.o: /LinuxPPC/CDK/include/linux/kdev_t.h
+cmd_flash.o: /LinuxPPC/CDK/include/asm/processor.h
+cmd_flash.o: /LinuxPPC/CDK/include/linux/config.h
+cmd_flash.o: /LinuxPPC/CDK/include/asm/ptrace.h
+cmd_flash.o: /LinuxPPC/CDK/include/asm/residual.h
+cmd_flash.o: /LinuxPPC/CDK/include/asm/pnp.h
+cmd_flash.o: /LinuxPPC/CDK/include/asm/atomic.h
+cmd_flash.o: /LinuxPPC/CDK/include/asm/byteorder.h
+cmd_flash.o: /LinuxPPC/CDK/include/asm/types.h
+cmd_flash.o: /LinuxPPC/CDK/include/linux/byteorder/big_endian.h
+cmd_flash.o: /LinuxPPC/CDK/include/linux/byteorder/swab.h
+cmd_flash.o: /LinuxPPC/CDK/include/linux/byteorder/generic.h
+cmd_flash.o: /LinuxPPC/CDK/include/linux/types.h
+cmd_flash.o: /LinuxPPC/CDK/include/linux/posix_types.h
+cmd_flash.o: /LinuxPPC/CDK/include/linux/stddef.h
+cmd_flash.o: /LinuxPPC/CDK/include/asm/posix_types.h
+cmd_flash.o: /LinuxPPC/CDK/include/linux/string.h
+cmd_flash.o: /LinuxPPC/CDK/include/asm/string.h
+cmd_flash.o: /home/wd/ppc/ppcboot/include/asm/8xx_immap.h
+cmd_flash.o: /home/wd/ppc/ppcboot/include/flash.h
+cmd_flash.o: /home/wd/ppc/ppcboot/include/command.h
+cmd_flash.o: /home/wd/ppc/ppcboot/include/cmd_boot.h
+cmd_bootm.o: /home/wd/ppc/ppcboot/include/ppcboot.h
+cmd_bootm.o: /home/wd/ppc/ppcboot/include/config.h
+cmd_bootm.o: /LinuxPPC/CDK/include/linux/bitops.h
+cmd_bootm.o: /LinuxPPC/CDK/include/asm/bitops.h
+cmd_bootm.o: /LinuxPPC/CDK/include/asm/system.h
+cmd_bootm.o: /LinuxPPC/CDK/include/linux/kdev_t.h
+cmd_bootm.o: /LinuxPPC/CDK/include/asm/processor.h
+cmd_bootm.o: /LinuxPPC/CDK/include/linux/config.h
+cmd_bootm.o: /LinuxPPC/CDK/include/asm/ptrace.h
+cmd_bootm.o: /LinuxPPC/CDK/include/asm/residual.h
+cmd_bootm.o: /LinuxPPC/CDK/include/asm/pnp.h
+cmd_bootm.o: /LinuxPPC/CDK/include/asm/atomic.h
+cmd_bootm.o: /LinuxPPC/CDK/include/asm/byteorder.h
+cmd_bootm.o: /LinuxPPC/CDK/include/asm/types.h
+cmd_bootm.o: /LinuxPPC/CDK/include/linux/byteorder/big_endian.h
+cmd_bootm.o: /LinuxPPC/CDK/include/linux/byteorder/swab.h
+cmd_bootm.o: /LinuxPPC/CDK/include/linux/byteorder/generic.h
+cmd_bootm.o: /LinuxPPC/CDK/include/linux/types.h
+cmd_bootm.o: /LinuxPPC/CDK/include/linux/posix_types.h
+cmd_bootm.o: /LinuxPPC/CDK/include/linux/stddef.h
+cmd_bootm.o: /LinuxPPC/CDK/include/asm/posix_types.h
+cmd_bootm.o: /LinuxPPC/CDK/include/linux/string.h
+cmd_bootm.o: /LinuxPPC/CDK/include/asm/string.h
+cmd_bootm.o: /home/wd/ppc/ppcboot/include/asm/8xx_immap.h
+cmd_bootm.o: /home/wd/ppc/ppcboot/include/flash.h
+cmd_bootm.o: /home/wd/ppc/ppcboot/include/command.h
+cmd_bootm.o: /home/wd/ppc/ppcboot/include/cmd_boot.h
+cmd_bootm.o: /home/wd/ppc/ppcboot/include/image.h
+cmd_bootm.o: /home/wd/ppc/ppcboot/include/malloc.h
+cmd_bootm.o: /LinuxPPC/CDK/lib/gcc-lib/powerpc-linux/2.95.2/include/stddef.h
+cmd_bootm.o: /home/wd/ppc/ppcboot/include/zlib.h
+cmd_nvedit.o: /home/wd/ppc/ppcboot/include/ppcboot.h
+cmd_nvedit.o: /home/wd/ppc/ppcboot/include/config.h
+cmd_nvedit.o: /LinuxPPC/CDK/include/linux/bitops.h
+cmd_nvedit.o: /LinuxPPC/CDK/include/asm/bitops.h
+cmd_nvedit.o: /LinuxPPC/CDK/include/asm/system.h
+cmd_nvedit.o: /LinuxPPC/CDK/include/linux/kdev_t.h
+cmd_nvedit.o: /LinuxPPC/CDK/include/asm/processor.h
+cmd_nvedit.o: /LinuxPPC/CDK/include/linux/config.h
+cmd_nvedit.o: /LinuxPPC/CDK/include/asm/ptrace.h
+cmd_nvedit.o: /LinuxPPC/CDK/include/asm/residual.h
+cmd_nvedit.o: /LinuxPPC/CDK/include/asm/pnp.h
+cmd_nvedit.o: /LinuxPPC/CDK/include/asm/atomic.h
+cmd_nvedit.o: /LinuxPPC/CDK/include/asm/byteorder.h
+cmd_nvedit.o: /LinuxPPC/CDK/include/asm/types.h
+cmd_nvedit.o: /LinuxPPC/CDK/include/linux/byteorder/big_endian.h
+cmd_nvedit.o: /LinuxPPC/CDK/include/linux/byteorder/swab.h
+cmd_nvedit.o: /LinuxPPC/CDK/include/linux/byteorder/generic.h
+cmd_nvedit.o: /LinuxPPC/CDK/include/linux/types.h
+cmd_nvedit.o: /LinuxPPC/CDK/include/linux/posix_types.h
+cmd_nvedit.o: /LinuxPPC/CDK/include/linux/stddef.h
+cmd_nvedit.o: /LinuxPPC/CDK/include/asm/posix_types.h
+cmd_nvedit.o: /LinuxPPC/CDK/include/linux/string.h
+cmd_nvedit.o: /LinuxPPC/CDK/include/asm/string.h
+cmd_nvedit.o: /home/wd/ppc/ppcboot/include/asm/8xx_immap.h
+cmd_nvedit.o: /home/wd/ppc/ppcboot/include/flash.h
+cmd_nvedit.o: /home/wd/ppc/ppcboot/include/command.h
+cmd_nvedit.o: /home/wd/ppc/ppcboot/include/cmd_nvedit.h
+s_record.o: /home/wd/ppc/ppcboot/include/ppcboot.h
+s_record.o: /home/wd/ppc/ppcboot/include/config.h
+s_record.o: /LinuxPPC/CDK/include/linux/bitops.h
+s_record.o: /LinuxPPC/CDK/include/asm/bitops.h
+s_record.o: /LinuxPPC/CDK/include/asm/system.h
+s_record.o: /LinuxPPC/CDK/include/linux/kdev_t.h
+s_record.o: /LinuxPPC/CDK/include/asm/processor.h
+s_record.o: /LinuxPPC/CDK/include/linux/config.h
+s_record.o: /LinuxPPC/CDK/include/asm/ptrace.h
+s_record.o: /LinuxPPC/CDK/include/asm/residual.h
+s_record.o: /LinuxPPC/CDK/include/asm/pnp.h
+s_record.o: /LinuxPPC/CDK/include/asm/atomic.h
+s_record.o: /LinuxPPC/CDK/include/asm/byteorder.h
+s_record.o: /LinuxPPC/CDK/include/asm/types.h
+s_record.o: /LinuxPPC/CDK/include/linux/byteorder/big_endian.h
+s_record.o: /LinuxPPC/CDK/include/linux/byteorder/swab.h
+s_record.o: /LinuxPPC/CDK/include/linux/byteorder/generic.h
+s_record.o: /LinuxPPC/CDK/include/linux/types.h
+s_record.o: /LinuxPPC/CDK/include/linux/posix_types.h
+s_record.o: /LinuxPPC/CDK/include/linux/stddef.h
+s_record.o: /LinuxPPC/CDK/include/asm/posix_types.h
+s_record.o: /LinuxPPC/CDK/include/linux/string.h
+s_record.o: /LinuxPPC/CDK/include/asm/string.h
+s_record.o: /home/wd/ppc/ppcboot/include/asm/8xx_immap.h
+s_record.o: /home/wd/ppc/ppcboot/include/flash.h
+s_record.o: /home/wd/ppc/ppcboot/include/s_record.h
+dlmalloc.o: /home/wd/ppc/ppcboot/include/malloc.h
+dlmalloc.o: /LinuxPPC/CDK/lib/gcc-lib/powerpc-linux/2.95.2/include/stddef.h
diff --git a/common/board.c b/common/board.c
new file mode 100644 (file)
index 0000000..8db763c
--- /dev/null
@@ -0,0 +1,340 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <ppcboot.h>
+#include <command.h>
+
+#include <mpc8xx.h>
+
+/*
+ * Begin and End of memory area for malloc(), and current "brk"
+ */
+static ulong   mem_malloc_start = 0;
+static ulong   mem_malloc_end   = 0;
+static ulong   mem_malloc_brk   = 0;
+
+/*
+ * The Malloc area is immediately below the monitor copy in DRAM
+ */
+static void mem_malloc_init (ulong dest_addr)
+{
+       mem_malloc_end   = dest_addr;
+       mem_malloc_start = dest_addr - CFG_MALLOC_LEN;
+       mem_malloc_brk = mem_malloc_start;
+
+       memset ((void *)mem_malloc_start, 0, mem_malloc_end - mem_malloc_start);
+}
+
+void *sbrk (ptrdiff_t increment)
+{
+       ulong old = mem_malloc_brk;
+       ulong new = old + increment;
+
+       if ((new < mem_malloc_start) ||
+           (new > mem_malloc_end) ) {
+               return (NULL);
+       }
+       mem_malloc_brk = new;
+       return ((void *)old);
+}
+
+/*
+ * Breath some life into the board...
+ *
+ * Set up the memory map, initialise a bunch of registers, initialise the
+ * UPM's, initialise an SMC for serial comms, and carry out some hardware
+ * tests.
+ *
+ * The first part of initialization is running from Flash memory;
+ * its main purpose is to initialize the CPU and DRAM so that we
+ * can relocate the monitor code to RAM.
+ */
+void
+board_init_f (volatile immap_t *immr, unsigned long bootflag)
+{
+    volatile   memctl8xx_t *memctl = &immr->im_memctl;
+    bd_t       *bd;
+    ulong      reg, len;
+    int                board_type;
+    ulong      addr_moni, addr_sp;
+    ulong      dram_size, cpu_speed;
+
+    /* SYPCR - contains watchdog control (11-9) */
+
+    immr->im_siu_conf.sc_sypcr = CFG_SYPCR;
+
+
+    /* SIUMCR - contains debug pin configuration (11-6) */
+
+    immr->im_siu_conf.sc_siumcr |= CFG_SIUMCR;
+
+    /* initialize timebase status and control register (11-26) */
+    /* unlock TBSCRK */
+
+    immr->im_sitk.sitk_tbscrk = KAPWR_KEY;
+    immr->im_sit.sit_tbscr = CFG_TBSCR;
+
+    /* initialize the PIT (11-31) */
+
+    immr->im_sitk.sitk_piscrk = KAPWR_KEY;
+    immr->im_sit.sit_piscr = CFG_PISCR;
+
+    /* PLL (CPU clock) settings (15-30) */
+
+    immr->im_clkrstk.cark_plprcrk = KAPWR_KEY;
+    reg = immr->im_clkrst.car_plprcr;
+    reg &= PLPRCR_MF_MSK;              /* isolate MF field     */
+    reg |= CFG_PLPRCR;         /* reset control bits   */
+    immr->im_clkrst.car_plprcr = reg;
+
+    /* System integration timers. Don't change EBDF! (15-27) */
+
+    immr->im_clkrstk.cark_sccrk = KAPWR_KEY;
+    reg = immr->im_clkrst.car_sccr;
+    reg &= SCCR_MASK;
+    reg |= CFG_SCCR;
+    immr->im_clkrst.car_sccr = reg;
+
+    /*
+     * Memory Controller:
+     */
+
+    /* perform BR0 reset that MPC850 Rev. A can't guarantee */
+    memctl->memc_br0 = 0x00000001;     /* just "bank valid" bit */
+
+    /* Map banks 0 and 1 to the FLASH banks 0 and 1 at preliminary
+     * addresses - these have to be modified later when FLASH size
+     * has been determined
+     */
+
+    memctl->memc_or0 = CFG_OR0_REMAP;
+    memctl->memc_or1 = CFG_OR1_REMAP;
+
+    /* now restrict to preliminary range */
+    memctl->memc_br0 = CFG_BR0_PRELIM;
+
+    memctl->memc_or0 = CFG_OR0_PRELIM;
+    memctl->memc_or1 = CFG_OR1_PRELIM;
+
+    memctl->memc_br1 = CFG_BR1_PRELIM;
+
+    /* set up serial port */
+    serial_init ();
+
+    display_options();
+
+    printf ("Initializing...\n");
+
+    /* CPU Clock Speed */
+    cpu_speed = get_gclk_freq () / 1000 / 1000;                /* in MHz */
+
+    printf ("  CPU:   ");              /* Check CPU            */
+
+    if (checkcpu(cpu_speed) < 0) {
+       printf ("*** failed ***\n");
+       hang();
+    }
+
+    printf ("  Board: ");              /* Check Board          */
+
+    if ((board_type = checkboard()) < 0) {
+       printf ("*** failed ***\n");
+       hang();
+    }
+
+    /* Map bank 4: SRAM */
+
+    printf ("  DRAM:  ");
+
+    if ((dram_size = initdram (board_type)) > 0) {
+       printf ("%2ld MB\n", dram_size >> 20);
+    } else {
+       printf ("*** failed ***\n");
+       hang();
+    }
+
+    /*
+     * Now that we have DRAM mapped and working, we can
+     * relocate the code and continue running from DRAM.
+     *
+     * First reserve memory for monitor code at end of DRAM.
+     */
+    len = get_endaddr() - CFG_FLASH_BASE;
+    if (CFG_MONITOR_LEN > len)
+       len = CFG_MONITOR_LEN;
+    /* round up to next 4 kB limit */
+    len = (len + (4096 - 1)) & ~(4096 - 1);
+
+    addr_moni = CFG_SDRAM_BASE + dram_size - len;
+
+    /*
+     * Then we (permanently) allocate a Board Info struct.
+     *
+     * We leave room for the malloc() arena.
+     */
+    bd = (bd_t *)(addr_moni - sizeof(bd_t) - CFG_MALLOC_LEN);
+
+    /*
+     * Finally, we set up a new (bigger) stack.
+     *
+     * Leave some safety gap for SP, force alignment on 16 byte boundary
+     */
+    addr_sp  = (ulong)bd - 128;
+    addr_sp &= ~0xF;
+
+    /*
+     * Save local variables to board info struct
+     */
+
+    bd->bi_memstart    = CFG_SDRAM_BASE;  /* start of  DRAM memory             */
+    bd->bi_memsize     = dram_size;      /* size  of  DRAM memory in bytes     */
+    bd->bi_flashstart  = CFG_FLASH_BASE;  /* start of FLASH memory             */
+    bd->bi_flashsize   = 0;              /* size  of FLASH memory (PRELIM)     */
+    bd->bi_flashoffset = CFG_MONITOR_LEN; /* reserved area for startup monitor */
+    bd->bi_sramstart   = 0; /* FIXME */          /* start of  SRAM memory              */
+    bd->bi_sramsize    = 0; /* FIXME */          /* size  of  SRAM memory              */
+    bd->bi_immr_base   = (ulong)immr;    /* base  of IMMR register             */
+    bd->bi_bootflags   = bootflag;       /* boot / reboot flag (for LynxOS)    */
+
+    bd->bi_ip_addr     = (10<<24)|99;    /* Default IP Address: 10.0.0.99      */
+    bd->bi_enetaddr[0] = 0x00;           /* Default Ethernet adress            */
+    bd->bi_enetaddr[1] = 0xD0;
+    bd->bi_enetaddr[2] = 0x93;
+    bd->bi_enetaddr[3] = 0x00;
+    bd->bi_enetaddr[4] = 0x02;
+    bd->bi_enetaddr[5] = 0x6C;
+    bd->bi_intfreq     = cpu_speed;            /* Internal Freq, in MHz        */
+    bd->bi_busfreq     = CONFIG_8xx_BUSCLOCK;  /* Bus Freq,      in MHz        */
+    bd->bi_baudrate    = CONFIG_8xx_BAUDRATE;  /* Console Baudrate             */
+
+    /* Function pointers must be added after code relocation */
+#if 0
+    bd->bi_serial_io.getc   = NULL;    /* Addr of getc() from Console  */
+    bd->bi_serial_io.tstc   = NULL;    /* Addr of tstc() from Console  */
+    bd->bi_serial_io.putc   = NULL;    /* Addr of tstc() from Console  */
+    bd->bi_serial_io.printf = NULL;    /* Addr of printf() to Console  */
+
+    bd->bi_interrupt.install_hdlr = NULL;
+    bd->bi_interrupt.free_hdlr    = NULL;
+#endif
+
+    relocate_code (addr_sp, bd, addr_moni);
+
+    /* NOTREACHED - relocate_code() does not return */
+}
+
+void hang(void)
+{
+       printf ("### ERROR ### Please RESET the board ###\n");
+       for (;;);
+}
+
+void    board_init_r  (bd_t *bd, ulong dest_addr)
+{
+    volatile immap_t *immr = (volatile immap_t *)(bd->bi_immr_base);
+    cmd_tbl_t  *cmdtp;
+    ulong      flash_size;
+    ulong      reloc_off = dest_addr - CFG_FLASH_BASE;
+
+    extern void malloc_bin_reloc (ulong);
+    /*
+     * We have to relocate the command table manually
+     */
+    for (cmdtp=&cmd_tbl[0]; cmdtp->name; cmdtp++) {
+       ulong addr;
+       
+       addr = (ulong)(cmdtp->cmd) + reloc_off;
+#if 0
+       printf ("Command \"%s\": 0x%08lx => 0x%08lx\n",
+           cmdtp->name, (ulong)(cmdtp->cmd), addr);
+#endif
+       cmdtp->cmd = (void (*)(struct cmd_tbl_s*,bd_t*,int,int,char*[]))addr;
+    }
+
+    /*
+     * Setup trap handlers
+     */
+    trap_init(dest_addr);
+
+    printf ("  FLASH: ");
+
+    if ((flash_size = flash_init ()) > 0) {
+       printf ("%2ld MB\n", flash_size >> 20);
+    } else {
+       printf ("*** failed ***\n");
+       hang();
+    }
+    bd->bi_flashsize = flash_size;   /* size of FLASH memory (final value)     */
+
+    /*
+     * Unlock Time Base (TBU - upper & TBL - lower) registers (11-24)
+     */
+    immr->im_sitk.sitk_tbk  = KAPWR_KEY;
+
+    /* Enable Time Base so udelay() works */
+    immr->im_sit.sit_tbscr |= TBSCR_TBE;
+
+    /*
+     * Enable Interrupts
+     */
+    interrupt_init (bd);
+
+    udelay(20);
+
+#if 0
+  {
+    volatile   memctl8xx_t *memctl = &immr->im_memctl;
+    printf ("\n");
+    printf ("# BR0: 0x%08x  OR0: 0x%08x\n", memctl->memc_br0, memctl->memc_or0);
+    printf ("# BR1: 0x%08x  OR1: 0x%08x\n", memctl->memc_br1, memctl->memc_or1);
+    printf ("# BR2: 0x%08x  OR2: 0x%08x\n", memctl->memc_br2, memctl->memc_or2);
+    printf ("# BR3: 0x%08x  OR3: 0x%08x\n", memctl->memc_br3, memctl->memc_or3);
+    printf ("# BR4: 0x%08x  OR4: 0x%08x\n", memctl->memc_br4, memctl->memc_or4);
+    printf ("# BR5: 0x%08x  OR5: 0x%08x\n", memctl->memc_br5, memctl->memc_or5);
+    printf ("# BR6: 0x%08x  OR6: 0x%08x\n", memctl->memc_br6, memctl->memc_or6);
+    printf ("# BR7: 0x%08x  OR7: 0x%08x\n", memctl->memc_br7, memctl->memc_or7);
+  }
+#endif
+
+    /* Insert function pointers now that we have relocated the code */
+
+    bd->bi_serial_io.getc   = serial_getc;
+    bd->bi_serial_io.tstc   = serial_tstc;
+    bd->bi_serial_io.putc   = serial_putc;
+    bd->bi_serial_io.printf = printf;
+
+    bd->bi_interrupt.install_hdlr = cpm_install_handler;
+    bd->bi_interrupt.free_hdlr    = cpm_free_handler;
+
+    /* initialize malloc() area */
+    mem_malloc_init (dest_addr);
+    malloc_bin_reloc (reloc_off);
+
+    /* Initialization complete - start the monitor */
+
+    main_loop (bd);
+
+    /* NOTREACHED - start_main does not return; just in case: loop here */
+    for (;;)
+       ;
+}
diff --git a/common/cmd_boot.c b/common/cmd_boot.c
new file mode 100644 (file)
index 0000000..1bc68ff
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * Boot support
+ */
+#include <ppcboot.h>
+#include <command.h>
+#include <cmd_boot.h>
+#include <s_record.h>
+#include <mpc8xx.h>
+
+
+static ulong load_serial (ulong offset);
+static int read_record (char *buf, ulong len);
+
+void do_bdinfo (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
+{
+       printf ("  memstart    = 0x%08lx\n",  bd->bi_memstart   );
+       printf ("  memsize     = 0x%08lx\n",  bd->bi_memsize    );
+       printf ("  flashstart  = 0x%08lx\n",  bd->bi_flashstart );
+       printf ("  flashsize   = 0x%08lx\n",  bd->bi_flashsize  );
+       printf ("  flashoffset = 0x%08lx\n",  bd->bi_flashoffset);
+       printf ("  sramstart   = 0x%08lx\n",  bd->bi_sramstart  );
+       printf ("  sramsize    = 0x%08lx\n",  bd->bi_sramsize   );
+       printf ("  immr_base   = 0x%08lx\n",  bd->bi_immr_base  );
+       printf ("  bootflags   = 0x%08lx\n",  bd->bi_bootflags  );
+       printf ("  intfreq     = %6ld MHz\n", bd->bi_intfreq    );
+       printf ("  busfreq     = %6ld MHz\n", bd->bi_busfreq    );
+       printf ("  baudrate    = %6ld bps\n", bd->bi_baudrate   );
+       printf ("  getc        = 0x%08lx\n",(ulong)bd->bi_serial_io.getc);
+       printf ("  tstc        = 0x%08lx\n",(ulong)bd->bi_serial_io.tstc);
+       printf ("  putc        = 0x%08lx\n",(ulong)bd->bi_serial_io.putc);
+       printf ("  printf      = 0x%08lx\n",(ulong)bd->bi_serial_io.printf);
+       printf ("  install_hdlr= 0x%08lx\n",(ulong)bd->bi_interrupt.install_hdlr);
+       printf ("  free_hdr    = 0x%08lx\n",(ulong)bd->bi_interrupt.free_hdlr);
+}
+
+void do_go (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
+{
+       ulong   addr, rc;
+
+       if (argc < 2) {
+               printf ("Usage:\n%s\n", cmdtp->usage);
+               return;
+       }
+
+       asc_to_hex(argv[1], &addr);
+
+       printf ("## Starting application at 0x%08lx ...\n", addr);
+
+       /*
+        * pass address parameter as argv[0] (aka command name),
+        * and all remaining args
+        */
+       rc = ((ulong (*)(bd_t *, int, char *[]))addr) (bd, --argc, &argv[1]);
+
+       printf ("## Application terminated, rc = 0x%lx\n", rc);
+}
+
+void do_reset (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
+{
+       ulong msr, addr;
+
+       volatile immap_t *immap = (immap_t *)CFG_IMMR;
+
+       immap->im_clkrst.car_plprcr |= PLPRCR_CSR; /* Checkstop Reset enable */
+
+       /* Interrupts and MMU off */
+       __asm__ ("mtspr    81, 0
+                 mfmsr    %0": "=r"(msr) : );
+       msr &= ~0x1030;
+       __asm__ ("mtmsr    %0"::"r"(msr) );
+
+       /*
+       * Trying to execute the next instruction at a non-existing address
+       * should cause a machine check, resulting in reset
+       */
+       addr = (ulong)-1;
+       ((void (*)(void ))addr)();
+
+}
+
+void do_load_serial (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
+{
+       ulong offset = 0;
+       ulong addr;
+       int i;
+
+       if (argc == 2) {
+               asc_to_hex(argv[1], &offset);
+       }
+
+       command_repeat_off();
+
+       printf ("## Ready for S-Record download ...\n");
+
+       addr = load_serial (offset);
+
+       /*
+        * Gather any trailing characters (for instance, the ^D which
+        * is sent by 'cu' after sending a file), and give the
+        * box some time (100 * 1 ms)
+        */
+       for (i=0; i<100; ++i) {
+               if (serial_tstc()) {
+                       (void) serial_getc();
+               }
+               udelay(1000);
+       }
+
+       if (addr == ~0) {
+               printf ("## S-Record download aborted\n");
+       } else {
+               printf ("## Start Addr = 0x%08lx\n", addr);
+       }
+}
+
+static ulong
+load_serial (ulong offset)
+{
+       char    record[SREC_MAXRECLEN + 1];     /* buffer for one S-Record      */
+       char    binbuf[SREC_MAXBINLEN];         /* buffer for binary data       */
+       int     binlen;                         /* no. of data bytes in S-Rec.  */
+       int     type;                           /* return code for record type  */
+       ulong   addr;                           /* load address from S-Record   */
+
+       while (read_record(record, SREC_MAXRECLEN + 1) >= 0) {
+               type = srec_decode (record, &binlen, &addr, binbuf);
+
+               if (type < 0) {
+                       return (~0);            /* Invalid S-Record             */
+               }
+
+               switch (type) {
+               case SREC_DATA2:
+               case SREC_DATA3:
+               case SREC_DATA4:
+                   if (addr2info(addr+offset)) {
+                       int rc; 
+
+                       switch (rc=flash_write((uchar *)binbuf,addr+offset,binlen))
+                       {
+                       case 0: break;
+                       case 1: printf ("\nError: Timeout writing to Flash\n");
+                               return (~0);
+                       case 2: printf ("\nError: Flash not Erased\n");
+                               return (~0);
+                       case 4: printf ("\nError: Can't write to protected Flash sectors\n");
+                               return (~0);
+                       default:
+                               printf ("%s[%d] FIXME: rc=%d\n",
+                                       __FILE__,__LINE__,rc);
+                               return (~0);
+                       }
+                   } else {
+                       memcpy ((char *)(addr+offset), binbuf, binlen);
+                   }
+                   break;
+               case SREC_END2:
+               case SREC_END3:
+               case SREC_END4:
+                   return (addr);
+               case SREC_START:
+                   break;
+               default:
+                   break;
+               }
+       }
+
+       return (~0);                    /* Download aborted             */
+}
+
+static int
+read_record (char *buf, ulong len)
+{
+       char *p;
+       char c;
+
+       --len;  /* always leave room for terminating '\0' byte */
+
+       for (p=buf; p < buf+len; ++p) {
+               c = serial_getc();              /* read character               */
+               serial_putc (c);                /* ... and echo it              */
+
+               switch (c) {
+               case '\r':
+               case '\n':
+                       *p = '\0';
+                       return (p - buf);
+               case '\0':
+               case 0x03:                      /* ^C - Control C               */
+                       return (-1);
+               default:
+                       *p = c;
+               }
+       }
+
+       /* line too long - truncate */
+       *p = '\0';
+       return (p - buf);
+}
diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c
new file mode 100644 (file)
index 0000000..63ee6ae
--- /dev/null
@@ -0,0 +1,449 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * Boot support
+ */
+#include <ppcboot.h>
+#include <command.h>
+#include <cmd_boot.h>
+#include <image.h>
+#include <malloc.h>
+#include <zlib.h>
+
+int gunzip(void *, int, unsigned char *, int *);
+
+static void *zalloc(void *, unsigned, unsigned);
+static void zfree(void *, void *, unsigned);
+
+static void print_header (image_header_t *hdr);
+static void print_type (image_header_t *hdr);
+
+image_header_t header;
+
+void do_bootm (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
+{
+       ulong   iflag;
+       ulong   addr;
+       ulong   sp;
+       ulong   data, len, checksum;
+       ulong   initrd_start, initrd_end;
+       ulong   cmd_start, cmd_end;
+       char    *cmdline;
+       char    *name, *s;
+       bd_t    *kbd;
+       int     (*appl)(cmd_tbl_t *, bd_t *, int, int, char *[]);
+       void    (*kernel)(bd_t *, ulong, ulong, ulong, ulong);
+       image_header_t *hdr = &header;
+
+       if (argc < 2) {
+               printf ("Usage:\n%s\n", cmdtp->usage);
+               return;
+       }
+
+       asc_to_hex(argv[1], &addr);
+
+       printf ("## Booting Linux kernel at %08lx ...\n", addr);
+
+       /* Copy header so we can blank CRC field for re-calculation */
+       memcpy (&header, (char *)addr, sizeof(image_header_t));
+
+       if (hdr->ih_magic  != IH_MAGIC) {
+               printf ("Bad Magic Number\n");
+               return;
+       }
+
+       data = (ulong)&header;
+       len  = sizeof(image_header_t);
+
+       checksum = hdr->ih_hcrc;
+       hdr->ih_hcrc = 0;
+
+       if (crc32 (0, (char *)data, len) != checksum) {
+               printf ("Bad Header Checksum\n");
+               return;
+       }
+
+       print_header (hdr);
+
+       data = addr + sizeof(image_header_t);
+       len  = hdr->ih_size;
+
+       printf ("   Verifying Checksum ... ");
+       if (crc32 (0, (char *)data, len) != hdr->ih_dcrc) {
+               printf ("Bad Data CRC\n");
+               return;
+       }
+       printf ("OK\n");
+
+       if ((hdr->ih_os != IH_OS_LINUX) || (hdr->ih_arch != IH_CPU_PPC)) {
+               printf ("Unsupported OS or Architecture\n");
+               return;
+       }
+
+       switch (hdr->ih_type) {
+       case IH_TYPE_STANDALONE:        name = "Standalone Application";
+                                       break;
+       case IH_TYPE_KERNEL:            name = "Kernel Image";
+                                       break;
+       default: printf ("Wrong Image Type for %s command\n", cmdtp->name);
+                return;
+       }
+
+       /*
+         * We have reached the point of no return: we are going to
+         * overwrite all exception vector code, so we cannot easily
+         * recover from any failures any more...
+        */
+
+       iflag = disable_interrupts();
+
+       switch (hdr->ih_comp) {
+       case IH_COMP_NONE:
+               printf ("   Loading %s ... ", name);
+               memcpy ((void *)hdr->ih_load, (uchar *)data, len);
+               break;
+       case IH_COMP_GZIP:
+               printf ("   Uncompressing %s ... ", name);
+               if (gunzip ((void *)hdr->ih_load, 0x400000,
+                           (uchar *)data, (int *)&len) != 0) {
+                       printf ("GUNZIP ERROR - must RESET board to recover\n");
+                       do_reset (cmdtp, bd, flag, argc, argv);
+               }
+               break;
+       default:
+               if (iflag)
+                       enable_interrupts();
+               printf ("Unimplemented compression type %d\n", hdr->ih_comp);
+               return;
+       }
+       printf ("OK\n");
+
+       switch (hdr->ih_type) {
+       case IH_TYPE_STANDALONE:
+               appl = (int (*)(cmd_tbl_t *, bd_t *, int, int, char *[]))hdr->ih_ep;  
+
+               (*appl)(cmdtp, bd, flag, argc-1, &argv[1]);
+               /* just in case we return */
+               if (iflag)
+                       enable_interrupts();
+               break;
+       case IH_TYPE_KERNEL:
+               /* handled below */
+               break;
+       default:
+               if (iflag)
+                       enable_interrupts();
+               printf ("Can't boot image type %d\n", hdr->ih_type);
+               return;
+       }
+
+       /*
+        * Booting a (Linux) kernel image
+        *
+         * Allocate space for command line and board info - the
+         * address should be as high as possible within the reach of
+         * the kernel (see CFG_BOOTMAPSZ settings), but in unused
+         * memory, which means far enough below the current stack
+         * pointer.
+        */
+
+       asm( "mr %0,1": "=r"(sp) : );
+
+       sp -= 1024;             /* just to be sure */
+       if (sp > CFG_BOOTMAPSZ)
+               sp = CFG_BOOTMAPSZ;
+       sp &= ~0xF;
+
+       cmdline = (char *)((sp - CFG_BARGSIZE) & ~0xF);
+       kbd = (bd_t *)(((ulong)cmdline - sizeof(bd_t)) & ~0xF);
+
+       if ((s = getenv("bootargs")) == NULL)
+               s = "";
+
+       strcpy (cmdline, s);
+
+       cmd_start    = (ulong)&cmdline[0];
+       cmd_end      = cmd_start + strlen(cmdline);
+
+       *kbd = *bd;
+
+       kernel = (void (*)(bd_t *, ulong, ulong, ulong, ulong))hdr->ih_ep;
+
+       /*
+        * Check if there is an initrd image
+        */
+       if (argc >= 3) {
+               asc_to_hex(argv[2], &addr);
+
+               printf ("## Loading RAMDisk Image at %08lx ...\n", addr);
+
+               /* Copy header so we can blank CRC field for re-calculation */
+               memcpy (&header, (char *)addr, sizeof(image_header_t));
+
+               if (hdr->ih_magic  != IH_MAGIC) {
+                       printf ("Bad Magic Number\n");
+                       do_reset (cmdtp, bd, flag, argc, argv);
+               }
+
+               data = (ulong)&header;
+               len  = sizeof(image_header_t);
+
+               checksum = hdr->ih_hcrc;
+               hdr->ih_hcrc = 0;
+
+               if (crc32 (0, (char *)data, len) != checksum) {
+                       printf ("Bad Header Checksum\n");
+                       do_reset (cmdtp, bd, flag, argc, argv);
+               }
+
+               print_header (hdr);
+
+               data = addr + sizeof(image_header_t);
+               len  = hdr->ih_size;
+
+               printf ("   Verifying Checksum ... ");
+               if (crc32 (0, (char *)data, len) != hdr->ih_dcrc) {
+                       printf ("Bad Data CRC\n");
+                       do_reset (cmdtp, bd, flag, argc, argv);
+               }
+               printf ("OK\n");
+
+               if ((hdr->ih_os   != IH_OS_LINUX)       ||
+                   (hdr->ih_arch != IH_CPU_PPC)        ||
+                   (hdr->ih_type != IH_TYPE_RAMDISK)   ) {
+                       printf ("No Linux PPC Ramdisk Image\n");
+                       do_reset (cmdtp, bd, flag, argc, argv);
+               }
+
+               initrd_start  = (ulong)kbd - hdr->ih_size;
+               initrd_start &= ~(4096 - 1);    /* align on page */
+               initrd_end    = initrd_start + hdr->ih_size;
+               printf ("   Loading Ramdisk ... ");
+               memcpy ((void *)initrd_start,
+                       (void *)(addr + sizeof(image_header_t)),
+                       hdr->ih_size );
+               printf ("OK\n");
+       } else {
+               /*
+                * no initrd image
+                */
+               initrd_start = 0;
+               initrd_end   = 0;
+       }
+
+       /*
+        * Linux Kernel Parameters:
+        *   r3: ptr to board info data
+        *   r4: initrd_start or 0 if no initrd
+        *   r5: initrd_end - unused if r4 is 0
+        *   r6: Start of command line string
+        *   r7: End   of command line string
+        */
+       (*kernel) (kbd, initrd_start, initrd_end, cmd_start, cmd_end);
+}
+
+void do_iminfo (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
+{
+       int     arg;
+       ulong   addr, data, len, checksum;
+       image_header_t *hdr = &header;
+
+       if (argc < 2) {
+               printf ("Usage:\n%s\n", cmdtp->usage);
+               return;
+       }
+
+       for (arg=1; arg <argc; ++arg) {
+               asc_to_hex(argv[arg], &addr);
+
+               printf ("\n## Checking Image at %08lx ...\n", addr);
+
+               /* Copy header so we can blank CRC field for re-calculation */
+               memcpy (&header, (char *)addr, sizeof(image_header_t));
+
+               if (hdr->ih_magic  != IH_MAGIC) {
+                       printf ("   Bad Magic Number\n");
+                       continue;
+               }
+
+               data = (ulong)&header;
+               len  = sizeof(image_header_t);
+
+               checksum = hdr->ih_hcrc;
+               hdr->ih_hcrc = 0;
+
+               if (crc32 (0, (char *)data, len) != checksum) {
+                       printf ("   Bad Header Checksum\n");
+                       continue;
+               }
+
+               print_header (hdr);
+
+               data = addr + sizeof(image_header_t);
+               len  = hdr->ih_size;
+
+               printf ("   Verifying Checksum ... ");
+               if (crc32 (0, (char *)data, len) != hdr->ih_dcrc) {
+                       printf ("   Bad Data CRC\n");
+                       continue;
+               }
+               printf ("OK\n");
+       }
+}
+
+static void
+print_header (image_header_t *hdr)
+{
+/*     time_t timestamp = (time_t)hdr->ih_time;        */
+
+       printf ("   Image Name:   %.*s\n", IH_NMLEN, hdr->ih_name);
+/*     printf ("   Created:      %s", ctime(&timestamp)); */
+       printf ("   Image Type:   "); print_type(hdr); printf ("\n");
+       printf ("   Data Size:    %d Bytes = %d kB = %d MB\n",
+               hdr->ih_size, hdr->ih_size>>10, hdr->ih_size>>20);
+       printf ("   Load Address: %08x\n", hdr->ih_load);
+       printf ("   Entry Point:  %08x\n", hdr->ih_ep);
+}
+
+
+static void
+print_type (image_header_t *hdr)
+{
+       char *os, *arch, *type, *comp;
+
+       switch (hdr->ih_os) {
+       case IH_OS_INVALID:     os = "Invalid OS";              break;
+       case IH_OS_LINUX:       os = "Linux";                   break;  
+       default:                os = "Unknown OS";              break;
+       }
+
+       switch (hdr->ih_arch) {
+       case IH_CPU_INVALID:    arch = "Invalid CPU";           break;  
+       case IH_CPU_ALPHA:      arch = "Alpha";                 break;
+       case IH_CPU_ARM:        arch = "ARM";                   break;
+       case IH_CPU_I386:       arch = "Intel x86";             break;
+       case IH_CPU_IA64:       arch = "IA64";                  break;
+       case IH_CPU_MIPS:       arch = "MIPS";                  break;
+       case IH_CPU_MIPS64:     arch = "MIPS 64 Bit";           break;
+       case IH_CPU_PPC:        arch = "PowerPC";               break;
+       case IH_CPU_S390:       arch = "IBM S390";              break;
+       case IH_CPU_SH:         arch = "SuperH";                break;
+       case IH_CPU_SPARC:      arch = "SPARC";                 break;
+       case IH_CPU_SPARC64:    arch = "SPARC 64 Bit";          break;
+       default:                arch = "Unknown Architecture";  break;
+       }
+
+       switch (hdr->ih_type) {
+       case IH_TYPE_INVALID:   type = "Invalid Image";         break;
+       case IH_TYPE_STANDALONE:type = "Standalone Program";    break;
+       case IH_TYPE_KERNEL:    type = "Kernel Image";          break;
+       case IH_TYPE_RAMDISK:   type = "RAMDisk Image";         break;
+       default:                type = "Unknown Image";         break;
+       }
+
+       switch (hdr->ih_comp) {
+       case IH_COMP_NONE:      comp = "uncompressed";          break;
+       case IH_COMP_GZIP:      comp = "gzip compressed";       break;
+       case IH_COMP_BZIP2:     comp = "bzip2 compressed";      break;
+       default:                comp = "unknown compression";   break;
+       }
+
+       printf ("%s %s %s (%s)", arch, os, type, comp);
+}
+
+#define        ZALLOC_ALIGNMENT        16
+
+static void *zalloc(void *x, unsigned items, unsigned size)
+{
+       void *p;
+
+       size *= items;
+       size = (size + ZALLOC_ALIGNMENT - 1) & ~(ZALLOC_ALIGNMENT - 1);
+
+       p = malloc (size);
+
+       return (p);
+}
+
+static void zfree(void *x, void *addr, unsigned nb)
+{
+       free (addr);
+}
+
+#define HEAD_CRC       2
+#define EXTRA_FIELD    4
+#define ORIG_NAME      8
+#define COMMENT                0x10
+#define RESERVED       0xe0
+
+#define DEFLATED       8
+
+int gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
+{
+       z_stream s;
+       int r, i, flags;
+       
+       /* skip header */
+       i = 10;
+       flags = src[3];
+       if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
+               printf ("Error: Bad gzipped data\n");
+               return (-1);
+       }
+       if ((flags & EXTRA_FIELD) != 0)
+               i = 12 + src[10] + (src[11] << 8);
+       if ((flags & ORIG_NAME) != 0)
+               while (src[i++] != 0)
+                       ;
+       if ((flags & COMMENT) != 0)
+               while (src[i++] != 0)
+                       ;
+       if ((flags & HEAD_CRC) != 0)
+               i += 2;
+       if (i >= *lenp) {
+               printf ("Error: gunzip out of data in header\n");
+               return (-1);
+       }
+       
+       s.zalloc = zalloc;
+       s.zfree = zfree;
+       r = inflateInit2(&s, -MAX_WBITS);
+       if (r != Z_OK) {
+               printf ("Error: inflateInit2() returned %d\n", r);
+               return (-1);
+       }
+       s.next_in = src + i;
+       s.avail_in = *lenp - i;
+       s.next_out = dst;
+       s.avail_out = dstlen;
+       r = inflate(&s, Z_FINISH);
+       if (r != Z_OK && r != Z_STREAM_END) {
+               printf ("Error: inflate() returned %d\n", r);
+               return (-1);
+       }
+       *lenp = s.next_out - (unsigned char *) dst;
+       inflateEnd(&s);
+       
+       return (0);
+}
diff --git a/common/cmd_cache.c b/common/cmd_cache.c
new file mode 100644 (file)
index 0000000..675708c
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * Cache support: switch on or off, get status
+ */
+#include <ppcboot.h>
+#include <command.h>
+#include <cmd_cache.h>
+
+static int on_off (const char *);
+
+void do_icache (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
+{
+       switch (argc) {
+       case 2:                 /* on / off     */
+               switch (on_off(argv[1])) {
+#if 0  /* prevented by marargs handling; FALLTROUGH is harmless, too */
+               default: printf ("Usage:\n%s\n", cmdtp->usage);
+                       return;
+#endif
+               case 0: icache_disable();
+                       break;
+               case 1: icache_enable ();
+                       break;
+               }
+               /* FALL TROUGH */
+       case 1:                 /* get status */
+               printf ("Instruction Cache is %s\n",
+                       icache_status() ? "ON" : "OFF");
+               return;
+       default:
+               printf ("Usage:\n%s\n", cmdtp->usage);
+       }
+}
+
+void do_dcache (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
+{
+       switch (argc) {
+       case 2:                 /* on / off     */
+               switch (on_off(argv[1])) {
+#if 0  /* prevented by marargs handling; FALLTROUGH is harmless, too */
+               default: printf ("Usage:\n%s\n", cmdtp->usage);
+                       return;
+#endif
+               case 0: dcache_disable();
+                       break;
+               case 1: dcache_enable ();
+                       break;
+               }
+               /* FALL TROUGH */
+       case 1:                 /* get status */
+               printf ("Data (writethrough) Cache is %s\n",
+                       dcache_status() ? "ON" : "OFF");
+               return;
+       default:
+               printf ("Usage:\n%s\n", cmdtp->usage);
+       }
+}
+
+static int on_off (const char *s)
+{
+       if (strcmp(s, "on") == 0) {
+               return (1);
+       } else if (strcmp(s, "off") == 0) {
+               return (0);
+       }
+       return (-1);
+}
diff --git a/common/cmd_flash.c b/common/cmd_flash.c
new file mode 100644 (file)
index 0000000..4fce39f
--- /dev/null
@@ -0,0 +1,269 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * FLASH support
+ */
+#include <ppcboot.h>
+#include <command.h>
+#include <cmd_boot.h>
+
+extern flash_info_t flash_info[];      /* info for FLASH chips */
+
+/*
+ * The user interface starts numbering for Flash banks with 1. The
+ * main reason is that asc_to_hex() returns 0 for invalid input, so
+ * any invalid input would blow up all of Flash bank 0, potentially
+ * including the mobitor itself, rendering the board useless to the
+ * noraml User (without BDM tools).
+ */
+
+void do_flinfo (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
+{
+       ulong bank;
+
+       if (argc == 1) {        /* print info for all FLASH banks */
+               for (bank=0; bank <CFG_MAX_FLASH_BANKS; ++bank) {
+                       printf ("\nBank # %ld: ", bank+1);
+
+                       flash_print_info (&flash_info[bank]);
+               }
+               return;
+       }
+
+       asc_to_hex (argv[1], &bank);
+       if ((bank < 1) || (bank > CFG_MAX_FLASH_BANKS)) {
+               printf ("Only FLASH Banks # 1 ... # %d supported\n",
+                       CFG_MAX_FLASH_BANKS);
+               return;
+       }
+       printf ("\nBank # %ld: ", bank);
+       flash_print_info (&flash_info[bank-1]);
+}
+
+void do_flerase(cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
+{
+       flash_info_t *info;
+       ulong bank, addr_first, addr_last;
+       int s_first, s_last;
+       int erased;
+
+       if (argc < 2) {
+               printf ("Usage:\n%s\n", cmdtp->usage);
+               return;
+       }
+
+       if (strcmp(argv[1], "all") == 0) {
+               for (bank=1; bank<=CFG_MAX_FLASH_BANKS; ++bank) {
+                       printf ("Erase Flash Bank # %ld ", bank);
+                       info = &flash_info[bank-1];
+                       flash_erase (info, 0, info->sector_count-1);
+               }
+               return;
+       }
+
+       if (argc != 3) {
+               printf ("Usage:\n%s\n", cmdtp->usage);
+               return;
+       }
+
+       if (strcmp(argv[1], "bank") == 0) {
+               asc_to_hex (argv[2], &bank);
+               if ((bank < 1) || (bank > CFG_MAX_FLASH_BANKS)) {
+                       printf ("Only FLASH Banks # 1 ... # %d supported\n",
+                               CFG_MAX_FLASH_BANKS);
+                       return;
+               }
+               printf ("Erase Flash Bank # %ld ", bank);
+               info = &flash_info[bank-1];
+               flash_erase (info, 0, info->sector_count-1);
+               return;
+       }
+
+       asc_to_hex (argv[1], &addr_first);
+       asc_to_hex (argv[2], &addr_last );
+
+       if (addr_first >= addr_last) {
+               printf ("Usage:\n%s\n", cmdtp->usage);
+               return;
+       }
+
+       erased = 0;
+
+       for (bank=0,info=&flash_info[0]; bank < CFG_MAX_FLASH_BANKS; ++bank, ++info) {
+               ulong b_end = info->start[0] + info->size - 1; /* bank end addr */
+               int sect;
+
+               s_first = -1;           /* first sector to erase        */
+               s_last  = -1;           /* last  sector to erase        */
+
+               for (sect=0; sect < info->sector_count; ++sect) {
+                       ulong end;              /* last address in current sect */
+                       short s_end;
+
+                       s_end = info->sector_count - 1;
+
+                       end = (sect == s_end) ? b_end : info->start[sect + 1] - 1;
+
+                       if (addr_first > end)
+                               continue;
+                       if (addr_last < info->start[sect])
+                               continue;
+
+                       if (addr_first == info->start[sect]) {
+                               s_first = sect;
+                               if (s_last < 0)
+                                       s_last = s_end;
+                       }
+                       if (addr_last  == end) {
+                               s_last  = sect;
+                               if (s_first < 0)
+                                       s_first = 0;
+                       }
+               }
+               if (s_first>=0 && s_first<=s_last) {
+                       erased += s_last - s_first + 1;
+                       flash_erase (info, s_first, s_last);
+               }
+       }
+       if (erased) {
+               printf ("Erased %d sectors\n", erased);
+       } else {
+               printf ("Error: start and/or end address"
+                       " not on sector boundary\n");
+       }
+}
+
+
+void do_protect(cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
+{
+       flash_info_t *info;
+       ulong bank, addr_first, addr_last;
+       int s_first, s_last;
+       int protected;
+       int i;
+       int p;
+
+       if (argc < 3) {
+               printf ("Usage:\n%s\n", cmdtp->usage);
+               return;
+       }
+
+       if (strcmp(argv[1], "off") == 0)
+               p = 0;
+       else if (strcmp(argv[1], "on") == 0)
+               p = 1;
+       else {
+               printf ("Usage:\n%s\n", cmdtp->usage);
+               return;
+       }
+
+       if (strcmp(argv[2], "all") == 0) {
+               for (bank=1; bank<=CFG_MAX_FLASH_BANKS; ++bank) {
+                       printf ("%sProtect Flash Bank # %ld\n",
+                               p ? "" : "Un-", bank);
+                       info = &flash_info[bank-1];
+                       for (i=0; i<info->sector_count; ++i) {
+                               info->protect[i] = p;
+                       }
+               }
+               return;
+       }
+
+       if (argc != 4) {
+               printf ("Usage:\n%s\n", cmdtp->usage);
+               return;
+       }
+
+       if (strcmp(argv[2], "bank") == 0) {
+               asc_to_hex (argv[3], &bank);
+               if ((bank < 1) || (bank > CFG_MAX_FLASH_BANKS)) {
+                       printf ("Only FLASH Banks # 1 ... # %d supported\n",
+                               CFG_MAX_FLASH_BANKS);
+                       return;
+               }
+               printf ("%sProtect Flash Bank # %ld\n",
+                       p ? "" : "Un-", bank);
+               info = &flash_info[bank-1];
+               for (i=0; i<info->sector_count; ++i) {
+                       info->protect[i] = p;
+               }
+               return;
+       }
+
+       asc_to_hex (argv[2], &addr_first);
+       asc_to_hex (argv[3], &addr_last );
+
+       if (addr_first >= addr_last) {
+               printf ("Usage:\n%s\n", cmdtp->usage);
+               return;
+       }
+
+       protected = 0;
+
+       for (bank=0,info=&flash_info[0]; bank < CFG_MAX_FLASH_BANKS; ++bank, ++info) {
+               ulong b_end = info->start[0] + info->size - 1; /* bank end addr */
+               int sect;
+
+               s_first = -1;           /* first sector to erase        */
+               s_last  = -1;           /* last  sector to erase        */
+
+               for (sect=0; sect < info->sector_count; ++sect) {
+                       ulong end;              /* last address in current sect */
+                       short s_end;
+
+                       s_end = info->sector_count - 1;
+
+                       end = (sect == s_end) ? b_end : info->start[sect + 1] - 1;
+
+                       if (addr_first > end)
+                               continue;
+                       if (addr_last < info->start[sect])
+                               continue;
+
+                       if (addr_first == info->start[sect]) {
+                               s_first = sect;
+                               if (s_last < 0)
+                                       s_last = s_end;
+                       }
+                       if (addr_last  == end) {
+                               s_last  = sect;
+                               if (s_first < 0)
+                                       s_first = 0;
+                       }
+               }
+               if (s_first>=0 && s_first<=s_last) {
+                       protected += s_last - s_first + 1;
+                       for (i=s_first; i<=s_last; ++i) {
+                               info->protect[i] = p;
+                       }
+               }
+       }
+       if (protected) {
+               printf ("%sProtected %d sectors\n",
+                       p ? "" : "Un-", protected);
+       } else {
+               printf ("Error: start and/or end address"
+                       " not on sector boundary\n");
+       }
+}
diff --git a/common/cmd_mem.c b/common/cmd_mem.c
new file mode 100644 (file)
index 0000000..d9e695a
--- /dev/null
@@ -0,0 +1,481 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * Memory Functions
+ *
+ * Copied from FADS ROM, Dan Malek (dmalek@jlc.net)
+ */
+
+#include <ppcboot.h>
+#include <command.h>
+#include <cmd_mem.h>
+
+static void mod_mem(int incrflag, int flag, int argc, char *argv[]);
+
+/* Display values from last command.
+ * Memory modify remembered values are different from display memory.
+ */
+uint   dp_last_addr, dp_last_size;
+uint   dp_last_length = 0x40;
+uint   mm_last_addr, mm_last_size;
+
+static ulong   base_address = 0;
+
+/* Memory Display
+ *
+ * Syntax:
+ *     md{.b, .w, .l} {addr} {len}
+ */
+#define DISP_LINE_LEN  16
+
+void do_mem_md    (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
+{
+       ulong   addr, size, length;
+       ulong   i, nbytes, linebytes;
+       u_char  *cp;
+
+       /* We use the last specified parameters, unless new ones are
+        * entered.
+        */
+       addr = dp_last_addr;
+       size = dp_last_size;
+       length = dp_last_length;
+
+       if (argc < 2) {
+               printf ("Usage:\n%s\n", cmdtp->usage);
+               return;
+       }
+
+       if ((flag & CMD_FLAG_REPEAT) == 0) {
+               /* New command specified.  Check for a size spefication.
+                * Defaults to long if no or incorrect specification.
+                */
+               size = 4;
+               if (argv[0][2] == '.') {
+                       if (argv[0][3] == 'b') {
+                               size = 1;
+                       } else if (argv[0][3] == 'w') {
+                               size = 2;
+                       }
+               }
+
+               /* Address is specified since argc > 1
+               */
+               asc_to_hex(argv[1], &addr);
+               addr += base_address;
+
+               /* If another parameter, it is the length to display.
+                * Length is the number of objects, not number of bytes.
+                */
+               if (argc > 2)
+                       asc_to_hex(argv[2], &length);
+       }
+
+       /* Print the lines.
+        *
+        * We buffer all read data, so we can make sure data is read only
+        * once, and all accesses are with the specified bus width.
+        */
+       nbytes = length * size;
+       do {
+               char    linebuf[DISP_LINE_LEN];
+               uint    *uip = (uint   *)linebuf;
+               ushort  *usp = (ushort *)linebuf;
+               u_char  *ucp = (u_char *)linebuf;
+
+               printf("%08lx:", addr);
+               linebytes = (nbytes>DISP_LINE_LEN)?DISP_LINE_LEN:nbytes;
+               for (i=0; i<linebytes; i+= size) {
+                       if (size == 4) {
+                               printf(" %08x", (*uip++ = *((uint *)addr)));
+                       } else if (size == 2) {
+                               printf(" %04x", (*usp++ = *((ushort *)addr)));
+                       } else {
+                               printf(" %02x", (*ucp++ = *((u_char *)addr)));
+                       }
+                       addr += size;
+               }
+               printf("    ");
+               cp = linebuf;
+               for (i=0; i<linebytes; i++) {
+                       if ((*cp < 0x20) || (*cp > 0x7e))
+                               printf(".");
+                       else
+                               printf("%c", *cp);
+                       cp++;
+               }
+               printf("\n");
+               nbytes -= linebytes;
+       } while (nbytes > 0);
+
+       dp_last_addr = addr;
+       dp_last_length = length;
+       dp_last_size = size;
+}
+
+
+void do_mem_mm    (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
+{
+       mod_mem (1, flag, argc, argv);
+}
+
+
+void do_mem_nm    (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
+{
+       mod_mem (0, flag, argc, argv);
+}
+
+
+void do_mem_mw    (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
+{
+       ulong   addr, size, writeval, count;
+
+       if ((argc < 3) || (argc > 4)) {
+               printf ("Usage:\n%s\n", cmdtp->usage);
+               return;
+       }
+
+       /* Check for size specification.
+       */
+       size = 4;
+       if (argv[0][2] == '.') {
+               if (argv[0][3] == 'b') {
+                       size = 1;
+               } else if (argv[0][3] == 'w') {
+                       size = 2;
+               }
+       }
+
+       /* Address is specified since argc > 1
+       */
+       asc_to_hex(argv[1], &addr);
+       addr += base_address;
+
+       /* Get the value to write.
+       */
+       asc_to_hex(argv[2], &writeval);
+
+       /* Count ? */
+       if (argc == 4) {
+               asc_to_hex(argv[3], &count);
+       } else {
+               count = 1;
+       }
+
+       while (count-- > 0) {
+               if (size == 4)
+                       *((ulong  *)addr) = (ulong )writeval;
+               else if (size == 2)
+                       *((ushort *)addr) = (ushort)writeval;
+               else
+                       *((u_char *)addr) = (u_char)writeval;
+               addr += size;
+       }
+}
+
+
+void do_mem_cp    (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
+{
+       ulong   addr, size, dest, count;
+
+       if (argc != 4) {
+               printf ("Usage:\n%s\n", cmdtp->usage);
+               return;
+       }
+
+       /* Check for size specification.
+       */
+       size = 4;
+       if (argv[0][2] == '.') {
+               if (argv[0][3] == 'b') {
+                       size = 1;
+               } else if (argv[0][3] == 'w') {
+                       size = 2;
+               }
+       }
+
+       asc_to_hex(argv[1], &addr);
+       addr += base_address;
+
+       asc_to_hex(argv[2], &dest);
+       dest += base_address;
+
+       asc_to_hex(argv[3], &count);
+
+       /* check if we are copying to Flash */
+       if (addr2info(dest) != NULL) {
+               int rc;
+               
+               printf ("Copy to Flash... ");
+               switch (rc = flash_write ((uchar *)addr, dest, count*size)) {
+               case 0: printf ("done\n");
+                       return;
+               case 1: printf ("Timeout writing to Flash\n");
+                       return;
+               case 2: printf ("Flash not Erased\n");
+                       return;
+               case 4: printf ("Can't write to protected Flash sectors\n");
+                       return;
+               default:
+                       printf ("%s[%d] FIXME: rc=%d\n",__FILE__,__LINE__,rc);
+                       return;
+               }
+       }
+
+       while (count-- > 0) {
+               if (size == 4)
+                       *((ulong  *)dest) = *((ulong  *)addr);
+               else if (size == 2)
+                       *((ushort *)dest) = *((ushort *)addr);
+               else
+                       *((u_char *)dest) = *((u_char *)addr);
+               addr += size;
+               dest += size;
+       }
+}
+
+
+void do_mem_base  (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
+{
+       if (argc > 1) {
+               /* Set new base address.
+               */
+               asc_to_hex(argv[1], &base_address);
+       }
+       /* Print the current base address.
+       */
+       printf("Base Address: 0x%08lx\n", base_address);
+}
+
+
+void do_mem_loop  (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
+{
+       ulong   addr, size, length, i, junk;
+       volatile uint   *longp;
+       volatile ushort *shortp;
+       volatile u_char *cp;
+
+       if (argc < 3) {
+               printf ("Usage:\n%s\n", cmdtp->usage);
+               return;
+       }
+
+       /* Check for a size spefication.
+        * Defaults to long if no or incorrect specification.
+        */
+       size = 4;
+       if (argv[0][4] == '.') {
+               if (argv[0][5] == 'b')
+                       size = 1;
+               else if (argv[0][5] == 'w')
+                       size = 2;
+       }
+
+       /* Address is always specified.
+       */
+       asc_to_hex(argv[1], &addr);
+
+       /* Length is the number of objects, not number of bytes.
+       */
+       asc_to_hex(argv[2], &length);
+
+       /* We want to optimize the loops to run as fast as possible.
+        * If we have only one object, just run infinite loops.
+        */
+       if (length == 1) {
+               if (size == 4) {
+                       longp = (uint *)addr;
+                       for (;;)
+                               i = *longp;
+               }
+               if (size == 2) {
+                       shortp = (ushort *)addr;
+                       for (;;)
+                               i = *shortp;
+               }
+               cp = (u_char *)addr;
+               for (;;)
+                       i = *cp;
+       }
+
+       if (size == 4) {
+               for (;;) {
+                       longp = (uint *)addr;
+                       i = length;
+                       while (i-- > 0)
+                               junk = *longp++;
+               }
+       }
+       if (size == 2) {
+               for (;;) {
+                       shortp = (ushort *)addr;
+                       i = length;
+                       while (i-- > 0)
+                               junk = *shortp++;
+               }
+       }
+       for (;;) {
+               cp = (u_char *)addr;
+               i = length;
+               while (i-- > 0)
+                       junk = *cp++;
+       }
+}
+
+/* Just a quickie to walk through some memory.
+ */
+uint baseval = 0;
+
+void do_mem_mtest (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
+{
+       int     *memaddr;
+       int     memval;
+
+       for (;;) {
+               memaddr = (uint *)CFG_MEMTEST_START;
+               printf("\nWriting: %08x, ", baseval);
+               memval = baseval;
+               do {
+                       *memaddr++ = memval++;
+               } while ((uint)memaddr < CFG_MEMTEST_END);
+
+               memaddr = (uint *)CFG_MEMTEST_START;
+               printf("Reading: %08x", baseval);
+               memval = baseval;
+               do {
+                       if (*memaddr != memval) {
+                               printf ("Mem error @ 0x%08x: "
+                                       "found %08x, expected 0x%08x\n",
+                                       (uint)memaddr, *memaddr, memval);
+                       }
+                       memaddr++;
+                       memval++;
+               } while ((uint)memaddr < CFG_MEMTEST_END);
+
+               baseval++;
+       }
+}
+
+
+
+
+/* Modify memory.
+ *
+ * Syntax:
+ *     mm{.b, .w, .l} {addr}
+ *     nm{.b, .w, .l} {addr}
+ */
+
+static void
+mod_mem(int incrflag, int flag, int argc, char *argv[])
+{
+       ulong   addr, size, i;
+       uint    nbytes;
+       extern char console_buffer[];
+
+       /* We use the last specified parameters, unless new ones are
+        * entered.
+        */
+       addr = mm_last_addr;
+       size = mm_last_size;
+
+       if ((flag & CMD_FLAG_REPEAT) == 0) {
+               /* New command specified.  Check for a size spefication.
+                * Defaults to long if no or incorrect specification.
+                */
+               size = 4;
+               if (argv[0][2] == '.') {
+                       if (argv[0][3] == 'b') {
+                               size = 1;
+                       } else if (argv[0][3] == 'w') {
+                               size = 2;
+                       }
+               }
+
+               /* Address is specified since argc > 1
+               */
+               asc_to_hex(argv[1], &addr);
+               addr += base_address;
+       }
+
+       /* Print the address, followed by value.  Then accept input for
+        * the next value.  A non-converted value exits.
+        */
+       do {
+               printf("%08lx:", addr);
+               if (size == 4)
+                       printf(" %08x", *((uint   *)addr));
+               else if (size == 2)
+                       printf(" %04x", *((ushort *)addr));
+               else
+                       printf(" %02x", *((u_char *)addr));
+               nbytes = readline (" ? ");
+
+               /* If <CR> is pressed as only input, don't modify current
+                * location and move to next.
+                */
+               if (!nbytes) {
+                       if (incrflag)
+                               addr += size;
+                       nbytes = 1;
+               }
+               else {
+                       nbytes = asc_to_hex(console_buffer, &i);
+                       if (nbytes) {
+                               if (size == 4)
+                                       *((uint   *)addr) = i;
+                               else if (size == 2)
+                                       *((ushort *)addr) = i;
+                               else
+                                       *((u_char *)addr) = i;
+                               if (incrflag)
+                                       addr += size;
+                       }
+               }
+       } while (nbytes);
+
+       mm_last_addr = addr;
+       mm_last_size = size;
+}
+
+void do_mem_crc (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
+{
+       ulong   addr, length;
+       ulong   crc;
+
+       if (argc < 3) {
+               printf ("Usage:\n%s\n", cmdtp->usage);
+               return;
+       }
+
+       asc_to_hex(argv[1], &addr);
+       addr += base_address;
+
+       asc_to_hex(argv[2], &length);
+
+       crc = crc32 (0, (const uchar *)addr, length);
+
+       printf ("CRC32 for %08lx ... %08lx ==> %08lx\n",
+               addr, addr + length -1, crc);
+}
diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
new file mode 100644 (file)
index 0000000..9b193dd
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * Support for persistent environment data
+ */
+#include <ppcboot.h>
+#include <command.h>
+#include <cmd_nvedit.h>
+
+/*
+ * FIXME:
+ *
+ * XXX DUMMY IMPLEMENTATION ONLY! XXX
+ */
+
+/*
+ * The environment storages is simply a list of '\0'-terminated
+ * "name=value" strings, the end of the list marked by a double '\0'.
+ * New entries are always addrd at the end. Deleting an entry shifts
+ * the remaining entries to the front. Replacing an entry is a
+ * combination of deleting the old and adding the new value.
+ */
+
+#define        CFG_ENVSIZE     1024
+char environment[CFG_ENVSIZE] = {
+       "bootargs="     "root=/dev/nfs rw "
+                       "nfsroot=10.0.0.2:/LinuxPPC "
+                       "nfsaddrs=10.0.0.98:10.0.0.2"
+                       "\0"
+       "ethaddr="      "00:D0:93:00:02:6C\0"
+       "ipaddr="       "10.0.0.98\0"
+       "verify="       "y\0"
+};
+
+static char *envmatch (char *, char *);
+
+char *getenv (char *name)
+{
+       char *env, *nxt;
+
+       for (env=environment; *env; env=nxt+1) {
+               char *val;
+
+               for (nxt=env; *nxt; ++nxt)
+                       ;
+               val=envmatch(name, env);
+               if (!val)
+                       continue;
+               return (val);
+       }
+
+       return (NULL);
+}
+
+void do_printenv (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
+{
+       char *env, *nxt;
+       int i;
+
+       if (argc == 1) {                /* Print all env variables      */
+               for (env=environment; *env; env=nxt+1) {
+                       for (nxt=env; *nxt; ++nxt)
+                               ;
+                       serial_putstr (env);
+                       serial_putc  ('\n');
+               }
+               return;
+       }
+
+       for (i=1; i<argc; ++i) {        /* print single env variables   */
+               char *name = argv[i];
+               char *val = NULL;
+
+               for (env=environment; *env; env=nxt+1) {
+
+                       for (nxt=env; *nxt; ++nxt)
+                               ;
+                       val=envmatch(name, env);
+                       if (val) {
+                               serial_putstr (name);
+                               serial_putc   ('=');
+                               serial_putstr (val);
+                               serial_putc  ('\n');
+                               break;
+                       }
+               }
+               if (!val)
+                       printf ("## Error: \"%s\" not defined\n", name);
+       }
+}
+
+void do_setenv   (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
+{
+       int  i, len;
+       char *env, *nxt;
+       char *oldval = NULL;
+       char *name;
+
+       if (argc < 2) {
+               printf ("Usage:\n%s\n", cmdtp->usage);
+               return;
+       }
+
+       name = argv[1];
+
+       /*
+        * search if variable with this name already exists
+        */
+       for (env=environment; *env; env=nxt+1) {
+               for (nxt=env; *nxt; ++nxt)
+                       ;
+               if ((oldval=envmatch(name, env)) != NULL)
+                       break;
+       }
+
+       /*
+        * Delete any existing definition
+        */
+       if (oldval) {
+               if (*++nxt == '\0') {
+                       *env = '\0';
+               } else {
+                       for (;;) {
+                               *env = *nxt++;
+                               if ((*env == '\0') && (*nxt == '\0'))
+                                       break;
+                               ++env;
+                       }
+               }
+               *++env = '\0';
+       }
+
+       /* Delete only ? */
+       if (argc < 3)
+               return;
+
+       /*
+        * Append new definition at the end
+        */
+       for (env=environment; *env || *(env+1); ++env)
+               ;
+       ++env;
+       /*
+        * Overflow when:
+        * "name" + "=" + "val" +"\0\0"  > CFG_ENVSIZE - (env-environment)
+        */
+       len = strlen(name) + 2;
+       /* add '=' for first arg, ' ' for all others */
+       for (i=2; i<argc; ++i) {
+               len += strlen(argv[i]) + 1;
+       }
+printf ("FREE: %d   NEED: %d\n", &environment[CFG_ENVSIZE]-env, len);
+       if (len > (&environment[CFG_ENVSIZE] - env)) {
+               printf ("## Error: environment overflow, \"%s\" deleted\n", name);
+               return;
+       }
+       while ((*env = *name++) != '\0')
+               env++;
+       for (i=2; i<argc; ++i) {
+               char *val = argv[i];
+
+               *env = (i==2) ? '=' : ' ';
+               while ((*++env = *val++) != '\0')
+                       ;
+       }
+
+       /* end is marked with double '\0' */
+       *++env = '\0';
+}
+void do_saveenv  (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
+{
+       printf ("XXX - not yet implemented\n");
+}
+
+/*
+ * s1 is either a simple 'name', or a 'name=value' pair.
+ * s2 is a 'name=value' pair.
+ * If the names match, return the value of s2, else NULL.
+ */
+
+static char *
+envmatch (char *s1, char *s2)
+{
+
+       while (*s1 == *s2++)
+               if (*s1++ == '=')
+                       return(s2);
+       if (*s1 == '\0' && *(s2-1) == '=')
+               return(s2);
+       return(NULL);
+}
diff --git a/common/command.c b/common/command.c
new file mode 100644 (file)
index 0000000..bd6907b
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ *  Command Processor Table
+ */
+
+#include <ppcboot.h>
+#include <command.h>
+#include <cmd_cache.h>
+#include <cmd_mem.h>
+#include <cmd_boot.h>
+#include <cmd_flash.h>
+#include <cmd_bootm.h>
+#include <cmd_nvedit.h>
+
+/*
+ * HELP command
+ */
+#define        CMD_TBL_HELP    {                                                       \
+       "help",         1,      CFG_MAXARGS,    do_help,                        \
+       "help    - print online help\n",                                        \
+       "[command ...]\n"                                                       \
+       "    - show help information (for 'command')\n"                         \
+       "'help' prints online help for the monitor commands.\n\n"               \
+       "Without arguments, it prints a short usage message for all commands.\n\n" \
+       "To get detailed help information for specific commands you can type\n" \
+       "'help' with one or more command names as arguments.\n",                \
+    }
+
+#define        CMD_TBL_QUES    {                                                       \
+       "?",            1,      CFG_MAXARGS,    do_help,                        \
+       "?       - alias for 'help'\n",                                         \
+       NULL,                                                                   \
+    }
+
+#define CMD_TBL_VERS   {                                                       \
+       "version",      4,      1,              do_version,                     \
+       "version - print monitor version\n",                                    \
+       NULL,                                                                   \
+    }
+
+void
+do_version (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
+{
+       extern char version_string[];
+       printf ("\n%s\n", version_string);
+}
+
+/*
+ * Use serial_putstr() instead of printf() to avoid printf buffer overflow
+ * for long help messages
+ */
+void
+do_help (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
+{
+       int i;
+
+       if (argc == 1) {        /* print short help (usage) */
+
+               for (cmdtp=&cmd_tbl[0]; cmdtp->name; cmdtp++) {
+                       if (cmdtp->usage == NULL)
+                               continue;
+                       serial_putstr (cmdtp->usage);
+               }
+
+               return;
+       }
+
+       /*
+        * command help (long version)
+        */
+       for (i=1; i<argc; ++i) {
+               for (cmdtp=&cmd_tbl[0]; cmdtp->name; cmdtp++) {
+                       if (strncmp(argv[i], cmdtp->name, cmdtp->lmin) == 0) {
+                               /* found - print (long) help info */
+                               serial_putstr (cmdtp->name);
+                               serial_putc   (' ');
+                               if (cmdtp->help) {
+                                       serial_putstr (cmdtp->help);
+                               } else {
+                                       serial_putstr ("- No help available.\n");
+                               }
+                               serial_putc ('\n');
+                               goto done;
+                       }
+               }
+               printf ("Unknown command '%s' - try 'help'"
+                       " without arguments for list of all known commands\n\n",
+                       argv[i]
+               );
+done:          ;
+       }
+}
+
+cmd_tbl_t cmd_tbl[] = {
+       CMD_TBL_GO,
+       CMD_TBL_BOOTM,
+       CMD_TBL_LOADS,
+       CMD_TBL_MD,
+       CMD_TBL_MM,
+       CMD_TBL_NM,
+       CMD_TBL_MW,
+       CMD_TBL_CP,
+       CMD_TBL_CRC,
+       CMD_TBL_BASE,
+       CMD_TBL_PRINTENV,
+       CMD_TBL_SETENV,
+       CMD_TBL_SAVEENV,
+       CMD_TBL_BDINFO,
+       CMD_TBL_FLINFO,
+       CMD_TBL_IMINFO,
+       CMD_TBL_FLERASE,
+       CMD_TBL_PROTECT,
+       CMD_TBL_LOOP,
+       CMD_TBL_MTEST,
+       CMD_TBL_ICACHE,
+       CMD_TBL_DCACHE,
+       CMD_TBL_RESET,
+       CMD_TBL_VERS,
+       CMD_TBL_HELP,
+       CMD_TBL_QUES,
+       /* the following entry terminates this table */
+       {       NULL,   0,      0,      NULL,   NULL,   NULL,   },
+};
diff --git a/common/dlmalloc.c b/common/dlmalloc.c
new file mode 100644 (file)
index 0000000..fcca2f3
--- /dev/null
@@ -0,0 +1,3315 @@
+#if 0  /* Moved to malloc.h */
+/* ---------- To make a malloc.h, start cutting here ------------ */
+
+/*
+  A version of malloc/free/realloc written by Doug Lea and released to the
+  public domain.  Send questions/comments/complaints/performance data
+  to dl@cs.oswego.edu
+
+* VERSION 2.6.6  Sun Mar  5 19:10:03 2000  Doug Lea  (dl at gee)
+
+   Note: There may be an updated version of this malloc obtainable at
+           ftp://g.oswego.edu/pub/misc/malloc.c
+         Check before installing!
+
+* Why use this malloc?
+
+  This is not the fastest, most space-conserving, most portable, or
+  most tunable malloc ever written. However it is among the fastest
+  while also being among the most space-conserving, portable and tunable.
+  Consistent balance across these factors results in a good general-purpose
+  allocator. For a high-level description, see
+     http://g.oswego.edu/dl/html/malloc.html
+
+* Synopsis of public routines
+
+  (Much fuller descriptions are contained in the program documentation below.)
+
+  malloc(size_t n);
+     Return a pointer to a newly allocated chunk of at least n bytes, or null
+     if no space is available.
+  free(Void_t* p);
+     Release the chunk of memory pointed to by p, or no effect if p is null.
+  realloc(Void_t* p, size_t n);
+     Return a pointer to a chunk of size n that contains the same data
+     as does chunk p up to the minimum of (n, p's size) bytes, or null
+     if no space is available. The returned pointer may or may not be
+     the same as p. If p is null, equivalent to malloc.  Unless the
+     #define REALLOC_ZERO_BYTES_FREES below is set, realloc with a
+     size argument of zero (re)allocates a minimum-sized chunk.
+  memalign(size_t alignment, size_t n);
+     Return a pointer to a newly allocated chunk of n bytes, aligned
+     in accord with the alignment argument, which must be a power of
+     two.
+  valloc(size_t n);
+     Equivalent to memalign(pagesize, n), where pagesize is the page
+     size of the system (or as near to this as can be figured out from
+     all the includes/defines below.)
+  pvalloc(size_t n);
+     Equivalent to valloc(minimum-page-that-holds(n)), that is,
+     round up n to nearest pagesize.
+  calloc(size_t unit, size_t quantity);
+     Returns a pointer to quantity * unit bytes, with all locations
+     set to zero.
+  cfree(Void_t* p);
+     Equivalent to free(p).
+  malloc_trim(size_t pad);
+     Release all but pad bytes of freed top-most memory back
+     to the system. Return 1 if successful, else 0.
+  malloc_usable_size(Void_t* p);
+     Report the number usable allocated bytes associated with allocated
+     chunk p. This may or may not report more bytes than were requested,
+     due to alignment and minimum size constraints.
+  malloc_stats();
+     Prints brief summary statistics.
+  mallinfo()
+     Returns (by copy) a struct containing various summary statistics.
+  mallopt(int parameter_number, int parameter_value)
+     Changes one of the tunable parameters described below. Returns
+     1 if successful in changing the parameter, else 0.
+
+* Vital statistics:
+
+  Alignment:                            8-byte
+       8 byte alignment is currently hardwired into the design.  This
+       seems to suffice for all current machines and C compilers.
+
+  Assumed pointer representation:       4 or 8 bytes
+       Code for 8-byte pointers is untested by me but has worked
+       reliably by Wolfram Gloger, who contributed most of the
+       changes supporting this.
+
+  Assumed size_t  representation:       4 or 8 bytes
+       Note that size_t is allowed to be 4 bytes even if pointers are 8.
+
+  Minimum overhead per allocated chunk: 4 or 8 bytes
+       Each malloced chunk has a hidden overhead of 4 bytes holding size
+       and status information.
+
+  Minimum allocated size: 4-byte ptrs:  16 bytes    (including 4 overhead)
+                          8-byte ptrs:  24/32 bytes (including, 4/8 overhead)
+
+       When a chunk is freed, 12 (for 4byte ptrs) or 20 (for 8 byte
+       ptrs but 4 byte size) or 24 (for 8/8) additional bytes are
+       needed; 4 (8) for a trailing size field
+       and 8 (16) bytes for free list pointers. Thus, the minimum
+       allocatable size is 16/24/32 bytes.
+
+       Even a request for zero bytes (i.e., malloc(0)) returns a
+       pointer to something of the minimum allocatable size.
+
+  Maximum allocated size: 4-byte size_t: 2^31 -  8 bytes
+                          8-byte size_t: 2^63 - 16 bytes
+
+       It is assumed that (possibly signed) size_t bit values suffice to
+       represent chunk sizes. `Possibly signed' is due to the fact
+       that `size_t' may be defined on a system as either a signed or
+       an unsigned type. To be conservative, values that would appear
+       as negative numbers are avoided.
+       Requests for sizes with a negative sign bit when the request
+       size is treaded as a long will return null.
+
+  Maximum overhead wastage per allocated chunk: normally 15 bytes
+
+       Alignnment demands, plus the minimum allocatable size restriction
+       make the normal worst-case wastage 15 bytes (i.e., up to 15
+       more bytes will be allocated than were requested in malloc), with
+       two exceptions:
+         1. Because requests for zero bytes allocate non-zero space,
+            the worst case wastage for a request of zero bytes is 24 bytes.
+         2. For requests >= mmap_threshold that are serviced via
+            mmap(), the worst case wastage is 8 bytes plus the remainder
+            from a system page (the minimal mmap unit); typically 4096 bytes.
+
+* Limitations
+
+    Here are some features that are NOT currently supported
+
+    * No user-definable hooks for callbacks and the like.
+    * No automated mechanism for fully checking that all accesses
+      to malloced memory stay within their bounds.
+    * No support for compaction.
+
+* Synopsis of compile-time options:
+
+    People have reported using previous versions of this malloc on all
+    versions of Unix, sometimes by tweaking some of the defines
+    below. It has been tested most extensively on Solaris and
+    Linux. It is also reported to work on WIN32 platforms.
+    People have also reported adapting this malloc for use in
+    stand-alone embedded systems.
+
+    The implementation is in straight, hand-tuned ANSI C.  Among other
+    consequences, it uses a lot of macros.  Because of this, to be at
+    all usable, this code should be compiled using an optimizing compiler
+    (for example gcc -O2) that can simplify expressions and control
+    paths.
+
+  __STD_C                  (default: derived from C compiler defines)
+     Nonzero if using ANSI-standard C compiler, a C++ compiler, or
+     a C compiler sufficiently close to ANSI to get away with it.
+  DEBUG                    (default: NOT defined)
+     Define to enable debugging. Adds fairly extensive assertion-based
+     checking to help track down memory errors, but noticeably slows down
+     execution.
+  REALLOC_ZERO_BYTES_FREES (default: NOT defined)
+     Define this if you think that realloc(p, 0) should be equivalent
+     to free(p). Otherwise, since malloc returns a unique pointer for
+     malloc(0), so does realloc(p, 0).
+  HAVE_MEMCPY               (default: defined)
+     Define if you are not otherwise using ANSI STD C, but still
+     have memcpy and memset in your C library and want to use them.
+     Otherwise, simple internal versions are supplied.
+  USE_MEMCPY               (default: 1 if HAVE_MEMCPY is defined, 0 otherwise)
+     Define as 1 if you want the C library versions of memset and
+     memcpy called in realloc and calloc (otherwise macro versions are used).
+     At least on some platforms, the simple macro versions usually
+     outperform libc versions.
+  HAVE_MMAP                 (default: defined as 1)
+     Define to non-zero to optionally make malloc() use mmap() to
+     allocate very large blocks.
+  HAVE_MREMAP                 (default: defined as 0 unless Linux libc set)
+     Define to non-zero to optionally make realloc() use mremap() to
+     reallocate very large blocks.
+  malloc_getpagesize        (default: derived from system #includes)
+     Either a constant or routine call returning the system page size.
+  HAVE_USR_INCLUDE_MALLOC_H (default: NOT defined)
+     Optionally define if you are on a system with a /usr/include/malloc.h
+     that declares struct mallinfo. It is not at all necessary to
+     define this even if you do, but will ensure consistency.
+  INTERNAL_SIZE_T           (default: size_t)
+     Define to a 32-bit type (probably `unsigned int') if you are on a
+     64-bit machine, yet do not want or need to allow malloc requests of
+     greater than 2^31 to be handled. This saves space, especially for
+     very small chunks.
+  INTERNAL_LINUX_C_LIB      (default: NOT defined)
+     Defined only when compiled as part of Linux libc.
+     Also note that there is some odd internal name-mangling via defines
+     (for example, internally, `malloc' is named `mALLOc') needed
+     when compiling in this case. These look funny but don't otherwise
+     affect anything.
+  WIN32                     (default: undefined)
+     Define this on MS win (95, nt) platforms to compile in sbrk emulation.
+  LACKS_UNISTD_H            (default: undefined if not WIN32)
+     Define this if your system does not have a <unistd.h>.
+  LACKS_SYS_PARAM_H         (default: undefined if not WIN32)
+     Define this if your system does not have a <sys/param.h>.
+  MORECORE                  (default: sbrk)
+     The name of the routine to call to obtain more memory from the system.
+  MORECORE_FAILURE          (default: -1)
+     The value returned upon failure of MORECORE.
+  MORECORE_CLEARS           (default 1)
+     True (1) if the routine mapped to MORECORE zeroes out memory (which
+     holds for sbrk).
+  DEFAULT_TRIM_THRESHOLD
+  DEFAULT_TOP_PAD
+  DEFAULT_MMAP_THRESHOLD
+  DEFAULT_MMAP_MAX
+     Default values of tunable parameters (described in detail below)
+     controlling interaction with host system routines (sbrk, mmap, etc).
+     These values may also be changed dynamically via mallopt(). The
+     preset defaults are those that give best performance for typical
+     programs/systems.
+  USE_DL_PREFIX             (default: undefined)
+     Prefix all public routines with the string 'dl'.  Useful to
+     quickly avoid procedure declaration conflicts and linker symbol
+     conflicts with existing memory allocation routines.
+
+
+*/
+
+\f
+
+
+/* Preliminaries */
+
+#ifndef __STD_C
+#ifdef __STDC__
+#define __STD_C     1
+#else
+#if __cplusplus
+#define __STD_C     1
+#else
+#define __STD_C     0
+#endif /*__cplusplus*/
+#endif /*__STDC__*/
+#endif /*__STD_C*/
+
+#ifndef Void_t
+#if (__STD_C || defined(WIN32))
+#define Void_t      void
+#else
+#define Void_t      char
+#endif
+#endif /*Void_t*/
+
+#if __STD_C
+#include <stddef.h>   /* for size_t */
+#else
+#include <sys/types.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>    /* needed for malloc_stats */
+
+
+/*
+  Compile-time options
+*/
+
+
+/*
+    Debugging:
+
+    Because freed chunks may be overwritten with link fields, this
+    malloc will often die when freed memory is overwritten by user
+    programs.  This can be very effective (albeit in an annoying way)
+    in helping track down dangling pointers.
+
+    If you compile with -DDEBUG, a number of assertion checks are
+    enabled that will catch more memory errors. You probably won't be
+    able to make much sense of the actual assertion errors, but they
+    should help you locate incorrectly overwritten memory.  The
+    checking is fairly extensive, and will slow down execution
+    noticeably. Calling malloc_stats or mallinfo with DEBUG set will
+    attempt to check every non-mmapped allocated and free chunk in the
+    course of computing the summmaries. (By nature, mmapped regions
+    cannot be checked very much automatically.)
+
+    Setting DEBUG may also be helpful if you are trying to modify
+    this code. The assertions in the check routines spell out in more
+    detail the assumptions and invariants underlying the algorithms.
+
+*/
+
+#if DEBUG
+#include <assert.h>
+#else
+#define assert(x) ((void)0)
+#endif
+
+
+/*
+  INTERNAL_SIZE_T is the word-size used for internal bookkeeping
+  of chunk sizes. On a 64-bit machine, you can reduce malloc
+  overhead by defining INTERNAL_SIZE_T to be a 32 bit `unsigned int'
+  at the expense of not being able to handle requests greater than
+  2^31. This limitation is hardly ever a concern; you are encouraged
+  to set this. However, the default version is the same as size_t.
+*/
+
+#ifndef INTERNAL_SIZE_T
+#define INTERNAL_SIZE_T size_t
+#endif
+
+/*
+  REALLOC_ZERO_BYTES_FREES should be set if a call to
+  realloc with zero bytes should be the same as a call to free.
+  Some people think it should. Otherwise, since this malloc
+  returns a unique pointer for malloc(0), so does realloc(p, 0).
+*/
+
+
+/*   #define REALLOC_ZERO_BYTES_FREES */
+
+
+/*
+  WIN32 causes an emulation of sbrk to be compiled in
+  mmap-based options are not currently supported in WIN32.
+*/
+
+/* #define WIN32 */
+#ifdef WIN32
+#define MORECORE wsbrk
+#define HAVE_MMAP 0
+
+#define LACKS_UNISTD_H
+#define LACKS_SYS_PARAM_H
+
+/*
+  Include 'windows.h' to get the necessary declarations for the
+  Microsoft Visual C++ data structures and routines used in the 'sbrk'
+  emulation.
+
+  Define WIN32_LEAN_AND_MEAN so that only the essential Microsoft
+  Visual C++ header files are included.
+*/
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#endif
+
+
+/*
+  HAVE_MEMCPY should be defined if you are not otherwise using
+  ANSI STD C, but still have memcpy and memset in your C library
+  and want to use them in calloc and realloc. Otherwise simple
+  macro versions are defined here.
+
+  USE_MEMCPY should be defined as 1 if you actually want to
+  have memset and memcpy called. People report that the macro
+  versions are often enough faster than libc versions on many
+  systems that it is better to use them.
+
+*/
+
+#define HAVE_MEMCPY
+
+#ifndef USE_MEMCPY
+#ifdef HAVE_MEMCPY
+#define USE_MEMCPY 1
+#else
+#define USE_MEMCPY 0
+#endif
+#endif
+
+#if (__STD_C || defined(HAVE_MEMCPY))
+
+#if __STD_C
+void* memset(void*, int, size_t);
+void* memcpy(void*, const void*, size_t);
+#else
+#ifdef WIN32
+// On Win32 platforms, 'memset()' and 'memcpy()' are already declared in
+// 'windows.h'
+#else
+Void_t* memset();
+Void_t* memcpy();
+#endif
+#endif
+#endif
+
+#if USE_MEMCPY
+
+/* The following macros are only invoked with (2n+1)-multiples of
+   INTERNAL_SIZE_T units, with a positive integer n. This is exploited
+   for fast inline execution when n is small. */
+
+#define MALLOC_ZERO(charp, nbytes)                                            \
+do {                                                                          \
+  INTERNAL_SIZE_T mzsz = (nbytes);                                            \
+  if(mzsz <= 9*sizeof(mzsz)) {                                                \
+    INTERNAL_SIZE_T* mz = (INTERNAL_SIZE_T*) (charp);                         \
+    if(mzsz >= 5*sizeof(mzsz)) {     *mz++ = 0;                               \
+                                     *mz++ = 0;                               \
+      if(mzsz >= 7*sizeof(mzsz)) {   *mz++ = 0;                               \
+                                     *mz++ = 0;                               \
+        if(mzsz >= 9*sizeof(mzsz)) { *mz++ = 0;                               \
+                                     *mz++ = 0; }}}                           \
+                                     *mz++ = 0;                               \
+                                     *mz++ = 0;                               \
+                                     *mz   = 0;                               \
+  } else memset((charp), 0, mzsz);                                            \
+} while(0)
+
+#define MALLOC_COPY(dest,src,nbytes)                                          \
+do {                                                                          \
+  INTERNAL_SIZE_T mcsz = (nbytes);                                            \
+  if(mcsz <= 9*sizeof(mcsz)) {                                                \
+    INTERNAL_SIZE_T* mcsrc = (INTERNAL_SIZE_T*) (src);                        \
+    INTERNAL_SIZE_T* mcdst = (INTERNAL_SIZE_T*) (dest);                       \
+    if(mcsz >= 5*sizeof(mcsz)) {     *mcdst++ = *mcsrc++;                     \
+                                     *mcdst++ = *mcsrc++;                     \
+      if(mcsz >= 7*sizeof(mcsz)) {   *mcdst++ = *mcsrc++;                     \
+                                     *mcdst++ = *mcsrc++;                     \
+        if(mcsz >= 9*sizeof(mcsz)) { *mcdst++ = *mcsrc++;                     \
+                                     *mcdst++ = *mcsrc++; }}}                 \
+                                     *mcdst++ = *mcsrc++;                     \
+                                     *mcdst++ = *mcsrc++;                     \
+                                     *mcdst   = *mcsrc  ;                     \
+  } else memcpy(dest, src, mcsz);                                             \
+} while(0)
+
+#else /* !USE_MEMCPY */
+
+/* Use Duff's device for good zeroing/copying performance. */
+
+#define MALLOC_ZERO(charp, nbytes)                                            \
+do {                                                                          \
+  INTERNAL_SIZE_T* mzp = (INTERNAL_SIZE_T*)(charp);                           \
+  long mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T), mcn;                         \
+  if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; }             \
+  switch (mctmp) {                                                            \
+    case 0: for(;;) { *mzp++ = 0;                                             \
+    case 7:           *mzp++ = 0;                                             \
+    case 6:           *mzp++ = 0;                                             \
+    case 5:           *mzp++ = 0;                                             \
+    case 4:           *mzp++ = 0;                                             \
+    case 3:           *mzp++ = 0;                                             \
+    case 2:           *mzp++ = 0;                                             \
+    case 1:           *mzp++ = 0; if(mcn <= 0) break; mcn--; }                \
+  }                                                                           \
+} while(0)
+
+#define MALLOC_COPY(dest,src,nbytes)                                          \
+do {                                                                          \
+  INTERNAL_SIZE_T* mcsrc = (INTERNAL_SIZE_T*) src;                            \
+  INTERNAL_SIZE_T* mcdst = (INTERNAL_SIZE_T*) dest;                           \
+  long mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T), mcn;                         \
+  if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; }             \
+  switch (mctmp) {                                                            \
+    case 0: for(;;) { *mcdst++ = *mcsrc++;                                    \
+    case 7:           *mcdst++ = *mcsrc++;                                    \
+    case 6:           *mcdst++ = *mcsrc++;                                    \
+    case 5:           *mcdst++ = *mcsrc++;                                    \
+    case 4:           *mcdst++ = *mcsrc++;                                    \
+    case 3:           *mcdst++ = *mcsrc++;                                    \
+    case 2:           *mcdst++ = *mcsrc++;                                    \
+    case 1:           *mcdst++ = *mcsrc++; if(mcn <= 0) break; mcn--; }       \
+  }                                                                           \
+} while(0)
+
+#endif
+
+
+/*
+  Define HAVE_MMAP to optionally make malloc() use mmap() to
+  allocate very large blocks.  These will be returned to the
+  operating system immediately after a free().
+*/
+
+#ifndef HAVE_MMAP
+#define HAVE_MMAP 1
+#endif
+
+/*
+  Define HAVE_MREMAP to make realloc() use mremap() to re-allocate
+  large blocks.  This is currently only possible on Linux with
+  kernel versions newer than 1.3.77.
+*/
+
+#ifndef HAVE_MREMAP
+#ifdef INTERNAL_LINUX_C_LIB
+#define HAVE_MREMAP 1
+#else
+#define HAVE_MREMAP 0
+#endif
+#endif
+
+#if HAVE_MMAP
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
+#define MAP_ANONYMOUS MAP_ANON
+#endif
+
+#endif /* HAVE_MMAP */
+
+/*
+  Access to system page size. To the extent possible, this malloc
+  manages memory from the system in page-size units.
+
+  The following mechanics for getpagesize were adapted from
+  bsd/gnu getpagesize.h
+*/
+
+#ifndef LACKS_UNISTD_H
+#  include <unistd.h>
+#endif
+
+#ifndef malloc_getpagesize
+#  ifdef _SC_PAGESIZE         /* some SVR4 systems omit an underscore */
+#    ifndef _SC_PAGE_SIZE
+#      define _SC_PAGE_SIZE _SC_PAGESIZE
+#    endif
+#  endif
+#  ifdef _SC_PAGE_SIZE
+#    define malloc_getpagesize sysconf(_SC_PAGE_SIZE)
+#  else
+#    if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE)
+       extern size_t getpagesize();
+#      define malloc_getpagesize getpagesize()
+#    else
+#      ifdef WIN32
+#        define malloc_getpagesize (4096) /* TBD: Use 'GetSystemInfo' instead */
+#      else
+#        ifndef LACKS_SYS_PARAM_H
+#          include <sys/param.h>
+#        endif
+#        ifdef EXEC_PAGESIZE
+#          define malloc_getpagesize EXEC_PAGESIZE
+#        else
+#          ifdef NBPG
+#            ifndef CLSIZE
+#              define malloc_getpagesize NBPG
+#            else
+#              define malloc_getpagesize (NBPG * CLSIZE)
+#            endif
+#          else
+#            ifdef NBPC
+#              define malloc_getpagesize NBPC
+#            else
+#              ifdef PAGESIZE
+#                define malloc_getpagesize PAGESIZE
+#              else
+#                define malloc_getpagesize (4096) /* just guess */
+#              endif
+#            endif
+#          endif
+#        endif
+#      endif
+#    endif
+#  endif
+#endif
+
+
+
+/*
+
+  This version of malloc supports the standard SVID/XPG mallinfo
+  routine that returns a struct containing the same kind of
+  information you can get from malloc_stats. It should work on
+  any SVID/XPG compliant system that has a /usr/include/malloc.h
+  defining struct mallinfo. (If you'd like to install such a thing
+  yourself, cut out the preliminary declarations as described above
+  and below and save them in a malloc.h file. But there's no
+  compelling reason to bother to do this.)
+
+  The main declaration needed is the mallinfo struct that is returned
+  (by-copy) by mallinfo().  The SVID/XPG malloinfo struct contains a
+  bunch of fields, most of which are not even meaningful in this
+  version of malloc. Some of these fields are are instead filled by
+  mallinfo() with other numbers that might possibly be of interest.
+
+  HAVE_USR_INCLUDE_MALLOC_H should be set if you have a
+  /usr/include/malloc.h file that includes a declaration of struct
+  mallinfo.  If so, it is included; else an SVID2/XPG2 compliant
+  version is declared below.  These must be precisely the same for
+  mallinfo() to work.
+
+*/
+
+/* #define HAVE_USR_INCLUDE_MALLOC_H */
+
+#if HAVE_USR_INCLUDE_MALLOC_H
+#include "/usr/include/malloc.h"
+#else
+
+/* SVID2/XPG mallinfo structure */
+
+struct mallinfo {
+  int arena;    /* total space allocated from system */
+  int ordblks;  /* number of non-inuse chunks */
+  int smblks;   /* unused -- always zero */
+  int hblks;    /* number of mmapped regions */
+  int hblkhd;   /* total space in mmapped regions */
+  int usmblks;  /* unused -- always zero */
+  int fsmblks;  /* unused -- always zero */
+  int uordblks; /* total allocated space */
+  int fordblks; /* total non-inuse space */
+  int keepcost; /* top-most, releasable (via malloc_trim) space */
+};
+
+/* SVID2/XPG mallopt options */
+
+#define M_MXFAST  1    /* UNUSED in this malloc */
+#define M_NLBLKS  2    /* UNUSED in this malloc */
+#define M_GRAIN   3    /* UNUSED in this malloc */
+#define M_KEEP    4    /* UNUSED in this malloc */
+
+#endif
+
+/* mallopt options that actually do something */
+
+#define M_TRIM_THRESHOLD    -1
+#define M_TOP_PAD           -2
+#define M_MMAP_THRESHOLD    -3
+#define M_MMAP_MAX          -4
+
+
+
+#ifndef DEFAULT_TRIM_THRESHOLD
+#define DEFAULT_TRIM_THRESHOLD (128 * 1024)
+#endif
+
+/*
+    M_TRIM_THRESHOLD is the maximum amount of unused top-most memory
+      to keep before releasing via malloc_trim in free().
+
+      Automatic trimming is mainly useful in long-lived programs.
+      Because trimming via sbrk can be slow on some systems, and can
+      sometimes be wasteful (in cases where programs immediately
+      afterward allocate more large chunks) the value should be high
+      enough so that your overall system performance would improve by
+      releasing.
+
+      The trim threshold and the mmap control parameters (see below)
+      can be traded off with one another. Trimming and mmapping are
+      two different ways of releasing unused memory back to the
+      system. Between these two, it is often possible to keep
+      system-level demands of a long-lived program down to a bare
+      minimum. For example, in one test suite of sessions measuring
+      the XF86 X server on Linux, using a trim threshold of 128K and a
+      mmap threshold of 192K led to near-minimal long term resource
+      consumption.
+
+      If you are using this malloc in a long-lived program, it should
+      pay to experiment with these values.  As a rough guide, you
+      might set to a value close to the average size of a process
+      (program) running on your system.  Releasing this much memory
+      would allow such a process to run in memory.  Generally, it's
+      worth it to tune for trimming rather tham memory mapping when a
+      program undergoes phases where several large chunks are
+      allocated and released in ways that can reuse each other's
+      storage, perhaps mixed with phases where there are no such
+      chunks at all.  And in well-behaved long-lived programs,
+      controlling release of large blocks via trimming versus mapping
+      is usually faster.
+
+      However, in most programs, these parameters serve mainly as
+      protection against the system-level effects of carrying around
+      massive amounts of unneeded memory. Since frequent calls to
+      sbrk, mmap, and munmap otherwise degrade performance, the default
+      parameters are set to relatively high values that serve only as
+      safeguards.
+
+      The default trim value is high enough to cause trimming only in
+      fairly extreme (by current memory consumption standards) cases.
+      It must be greater than page size to have any useful effect.  To
+      disable trimming completely, you can set to (unsigned long)(-1);
+
+
+*/
+
+
+#ifndef DEFAULT_TOP_PAD
+#define DEFAULT_TOP_PAD        (0)
+#endif
+
+/*
+    M_TOP_PAD is the amount of extra `padding' space to allocate or
+      retain whenever sbrk is called. It is used in two ways internally:
+
+      * When sbrk is called to extend the top of the arena to satisfy
+        a new malloc request, this much padding is added to the sbrk
+        request.
+
+      * When malloc_trim is called automatically from free(),
+        it is used as the `pad' argument.
+
+      In both cases, the actual amount of padding is rounded
+      so that the end of the arena is always a system page boundary.
+
+      The main reason for using padding is to avoid calling sbrk so
+      often. Having even a small pad greatly reduces the likelihood
+      that nearly every malloc request during program start-up (or
+      after trimming) will invoke sbrk, which needlessly wastes
+      time.
+
+      Automatic rounding-up to page-size units is normally sufficient
+      to avoid measurable overhead, so the default is 0.  However, in
+      systems where sbrk is relatively slow, it can pay to increase
+      this value, at the expense of carrying around more memory than
+      the program needs.
+
+*/
+
+
+#ifndef DEFAULT_MMAP_THRESHOLD
+#define DEFAULT_MMAP_THRESHOLD (128 * 1024)
+#endif
+
+/*
+
+    M_MMAP_THRESHOLD is the request size threshold for using mmap()
+      to service a request. Requests of at least this size that cannot
+      be allocated using already-existing space will be serviced via mmap.
+      (If enough normal freed space already exists it is used instead.)
+
+      Using mmap segregates relatively large chunks of memory so that
+      they can be individually obtained and released from the host
+      system. A request serviced through mmap is never reused by any
+      other request (at least not directly; the system may just so
+      happen to remap successive requests to the same locations).
+
+      Segregating space in this way has the benefit that mmapped space
+      can ALWAYS be individually released back to the system, which
+      helps keep the system level memory demands of a long-lived
+      program low. Mapped memory can never become `locked' between
+      other chunks, as can happen with normally allocated chunks, which
+      menas that even trimming via malloc_trim would not release them.
+
+      However, it has the disadvantages that:
+
+         1. The space cannot be reclaimed, consolidated, and then
+            used to service later requests, as happens with normal chunks.
+         2. It can lead to more wastage because of mmap page alignment
+            requirements
+         3. It causes malloc performance to be more dependent on host
+            system memory management support routines which may vary in
+            implementation quality and may impose arbitrary
+            limitations. Generally, servicing a request via normal
+            malloc steps is faster than going through a system's mmap.
+
+      All together, these considerations should lead you to use mmap
+      only for relatively large requests.
+
+
+*/
+
+
+
+#ifndef DEFAULT_MMAP_MAX
+#if HAVE_MMAP
+#define DEFAULT_MMAP_MAX       (64)
+#else
+#define DEFAULT_MMAP_MAX       (0)
+#endif
+#endif
+
+/*
+    M_MMAP_MAX is the maximum number of requests to simultaneously
+      service using mmap. This parameter exists because:
+
+         1. Some systems have a limited number of internal tables for
+            use by mmap.
+         2. In most systems, overreliance on mmap can degrade overall
+            performance.
+         3. If a program allocates many large regions, it is probably
+            better off using normal sbrk-based allocation routines that
+            can reclaim and reallocate normal heap memory. Using a
+            small value allows transition into this mode after the
+            first few allocations.
+
+      Setting to 0 disables all use of mmap.  If HAVE_MMAP is not set,
+      the default value is 0, and attempts to set it to non-zero values
+      in mallopt will fail.
+*/
+
+
+
+
+/*
+    USE_DL_PREFIX will prefix all public routines with the string 'dl'.
+      Useful to quickly avoid procedure declaration conflicts and linker
+      symbol conflicts with existing memory allocation routines.
+
+*/
+
+/* #define USE_DL_PREFIX */
+
+
+
+
+/*
+
+  Special defines for linux libc
+
+  Except when compiled using these special defines for Linux libc
+  using weak aliases, this malloc is NOT designed to work in
+  multithreaded applications.  No semaphores or other concurrency
+  control are provided to ensure that multiple malloc or free calls
+  don't run at the same time, which could be disasterous. A single
+  semaphore could be used across malloc, realloc, and free (which is
+  essentially the effect of the linux weak alias approach). It would
+  be hard to obtain finer granularity.
+
+*/
+
+
+#ifdef INTERNAL_LINUX_C_LIB
+
+#if __STD_C
+
+Void_t * __default_morecore_init (ptrdiff_t);
+Void_t *(*__morecore)(ptrdiff_t) = __default_morecore_init;
+
+#else
+
+Void_t * __default_morecore_init ();
+Void_t *(*__morecore)() = __default_morecore_init;
+
+#endif
+
+#define MORECORE (*__morecore)
+#define MORECORE_FAILURE 0
+#define MORECORE_CLEARS 1
+
+#else /* INTERNAL_LINUX_C_LIB */
+
+#if __STD_C
+extern Void_t*     sbrk(ptrdiff_t);
+#else
+extern Void_t*     sbrk();
+#endif
+
+#ifndef MORECORE
+#define MORECORE sbrk
+#endif
+
+#ifndef MORECORE_FAILURE
+#define MORECORE_FAILURE -1
+#endif
+
+#ifndef MORECORE_CLEARS
+#define MORECORE_CLEARS 1
+#endif
+
+#endif /* INTERNAL_LINUX_C_LIB */
+
+#if defined(INTERNAL_LINUX_C_LIB) && defined(__ELF__)
+
+#define cALLOc         __libc_calloc
+#define fREe           __libc_free
+#define mALLOc         __libc_malloc
+#define mEMALIGn       __libc_memalign
+#define rEALLOc                __libc_realloc
+#define vALLOc         __libc_valloc
+#define pvALLOc                __libc_pvalloc
+#define mALLINFo       __libc_mallinfo
+#define mALLOPt                __libc_mallopt
+
+#pragma weak calloc = __libc_calloc
+#pragma weak free = __libc_free
+#pragma weak cfree = __libc_free
+#pragma weak malloc = __libc_malloc
+#pragma weak memalign = __libc_memalign
+#pragma weak realloc = __libc_realloc
+#pragma weak valloc = __libc_valloc
+#pragma weak pvalloc = __libc_pvalloc
+#pragma weak mallinfo = __libc_mallinfo
+#pragma weak mallopt = __libc_mallopt
+
+#else
+
+#ifdef USE_DL_PREFIX
+#define cALLOc         dlcalloc
+#define fREe           dlfree
+#define mALLOc         dlmalloc
+#define mEMALIGn       dlmemalign
+#define rEALLOc                dlrealloc
+#define vALLOc         dlvalloc
+#define pvALLOc                dlpvalloc
+#define mALLINFo       dlmallinfo
+#define mALLOPt                dlmallopt
+#else /* USE_DL_PREFIX */
+#define cALLOc         calloc
+#define fREe           free
+#define mALLOc         malloc
+#define mEMALIGn       memalign
+#define rEALLOc                realloc
+#define vALLOc         valloc
+#define pvALLOc                pvalloc
+#define mALLINFo       mallinfo
+#define mALLOPt                mallopt
+#endif /* USE_DL_PREFIX */
+
+#endif
+
+/* Public routines */
+
+#if __STD_C
+
+Void_t* mALLOc(size_t);
+void    fREe(Void_t*);
+Void_t* rEALLOc(Void_t*, size_t);
+Void_t* mEMALIGn(size_t, size_t);
+Void_t* vALLOc(size_t);
+Void_t* pvALLOc(size_t);
+Void_t* cALLOc(size_t, size_t);
+void    cfree(Void_t*);
+int     malloc_trim(size_t);
+size_t  malloc_usable_size(Void_t*);
+void    malloc_stats();
+int     mALLOPt(int, int);
+struct mallinfo mALLINFo(void);
+#else
+Void_t* mALLOc();
+void    fREe();
+Void_t* rEALLOc();
+Void_t* mEMALIGn();
+Void_t* vALLOc();
+Void_t* pvALLOc();
+Void_t* cALLOc();
+void    cfree();
+int     malloc_trim();
+size_t  malloc_usable_size();
+void    malloc_stats();
+int     mALLOPt();
+struct mallinfo mALLINFo();
+#endif
+
+
+#ifdef __cplusplus
+};  /* end of extern "C" */
+#endif
+
+/* ---------- To make a malloc.h, end cutting here ------------ */
+#else                          /* Moved to malloc.h */
+
+#include <malloc.h>
+#if 0
+#if __STD_C
+static void malloc_update_mallinfo (void);
+void malloc_stats (void);
+#else
+static void malloc_update_mallinfo ();
+void malloc_stats();
+#endif
+#endif /* 0 */
+
+#endif /* 0 */                 /* Moved to malloc.h */
+
+
+/*
+  Emulation of sbrk for WIN32
+  All code within the ifdef WIN32 is untested by me.
+
+  Thanks to Martin Fong and others for supplying this.
+*/
+
+
+#ifdef WIN32
+
+#define AlignPage(add) (((add) + (malloc_getpagesize-1)) & \
+~(malloc_getpagesize-1))
+#define AlignPage64K(add) (((add) + (0x10000 - 1)) & ~(0x10000 - 1))
+
+/* resrve 64MB to insure large contiguous space */
+#define RESERVED_SIZE (1024*1024*64)
+#define NEXT_SIZE (2048*1024)
+#define TOP_MEMORY ((unsigned long)2*1024*1024*1024)
+
+struct GmListElement;
+typedef struct GmListElement GmListElement;
+
+struct GmListElement
+{
+       GmListElement* next;
+       void* base;
+};
+
+static GmListElement* head = 0;
+static unsigned int gNextAddress = 0;
+static unsigned int gAddressBase = 0;
+static unsigned int gAllocatedSize = 0;
+
+static
+GmListElement* makeGmListElement (void* bas)
+{
+       GmListElement* this;
+       this = (GmListElement*)(void*)LocalAlloc (0, sizeof (GmListElement));
+       assert (this);
+       if (this)
+       {
+               this->base = bas;
+               this->next = head;
+               head = this;
+       }
+       return this;
+}
+
+void gcleanup ()
+{
+       BOOL rval;
+       assert ( (head == NULL) || (head->base == (void*)gAddressBase));
+       if (gAddressBase && (gNextAddress - gAddressBase))
+       {
+               rval = VirtualFree ((void*)gAddressBase,
+                                                       gNextAddress - gAddressBase,
+                                                       MEM_DECOMMIT);
+        assert (rval);
+       }
+       while (head)
+       {
+               GmListElement* next = head->next;
+               rval = VirtualFree (head->base, 0, MEM_RELEASE);
+               assert (rval);
+               LocalFree (head);
+               head = next;
+       }
+}
+
+static
+void* findRegion (void* start_address, unsigned long size)
+{
+       MEMORY_BASIC_INFORMATION info;
+       if (size >= TOP_MEMORY) return NULL;
+
+       while ((unsigned long)start_address + size < TOP_MEMORY)
+       {
+               VirtualQuery (start_address, &info, sizeof (info));
+               if ((info.State == MEM_FREE) && (info.RegionSize >= size))
+                       return start_address;
+               else
+               {
+                       // Requested region is not available so see if the
+                       // next region is available.  Set 'start_address'
+                       // to the next region and call 'VirtualQuery()'
+                       // again.
+
+                       start_address = (char*)info.BaseAddress + info.RegionSize;
+
+                       // Make sure we start looking for the next region
+                       // on the *next* 64K boundary.  Otherwise, even if
+                       // the new region is free according to
+                       // 'VirtualQuery()', the subsequent call to
+                       // 'VirtualAlloc()' (which follows the call to
+                       // this routine in 'wsbrk()') will round *down*
+                       // the requested address to a 64K boundary which
+                       // we already know is an address in the
+                       // unavailable region.  Thus, the subsequent call
+                       // to 'VirtualAlloc()' will fail and bring us back
+                       // here, causing us to go into an infinite loop.
+
+                       start_address =
+                               (void *) AlignPage64K((unsigned long) start_address);
+               }
+       }
+       return NULL;
+
+}
+
+
+void* wsbrk (long size)
+{
+       void* tmp;
+       if (size > 0)
+       {
+               if (gAddressBase == 0)
+               {
+                       gAllocatedSize = max (RESERVED_SIZE, AlignPage (size));
+                       gNextAddress = gAddressBase =
+                               (unsigned int)VirtualAlloc (NULL, gAllocatedSize,
+                                                                                       MEM_RESERVE, PAGE_NOACCESS);
+               } else if (AlignPage (gNextAddress + size) > (gAddressBase +
+gAllocatedSize))
+               {
+                       long new_size = max (NEXT_SIZE, AlignPage (size));
+                       void* new_address = (void*)(gAddressBase+gAllocatedSize);
+                       do
+                       {
+                               new_address = findRegion (new_address, new_size);
+
+                               if (new_address == 0)
+                                       return (void*)-1;
+
+                               gAddressBase = gNextAddress =
+                                       (unsigned int)VirtualAlloc (new_address, new_size,
+                                                                                               MEM_RESERVE, PAGE_NOACCESS);
+                               // repeat in case of race condition
+                               // The region that we found has been snagged
+                               // by another thread
+                       }
+                       while (gAddressBase == 0);
+
+                       assert (new_address == (void*)gAddressBase);
+
+                       gAllocatedSize = new_size;
+
+                       if (!makeGmListElement ((void*)gAddressBase))
+                               return (void*)-1;
+               }
+               if ((size + gNextAddress) > AlignPage (gNextAddress))
+               {
+                       void* res;
+                       res = VirtualAlloc ((void*)AlignPage (gNextAddress),
+                                                               (size + gNextAddress -
+                                                                AlignPage (gNextAddress)),
+                                                               MEM_COMMIT, PAGE_READWRITE);
+                       if (res == 0)
+                               return (void*)-1;
+               }
+               tmp = (void*)gNextAddress;
+               gNextAddress = (unsigned int)tmp + size;
+               return tmp;
+       }
+       else if (size < 0)
+       {
+               unsigned int alignedGoal = AlignPage (gNextAddress + size);
+               /* Trim by releasing the virtual memory */
+               if (alignedGoal >= gAddressBase)
+               {
+                       VirtualFree ((void*)alignedGoal, gNextAddress - alignedGoal,
+                                                MEM_DECOMMIT);
+                       gNextAddress = gNextAddress + size;
+                       return (void*)gNextAddress;
+               }
+               else
+               {
+                       VirtualFree ((void*)gAddressBase, gNextAddress - gAddressBase,
+                                                MEM_DECOMMIT);
+                       gNextAddress = gAddressBase;
+                       return (void*)-1;
+               }
+       }
+       else
+       {
+               return (void*)gNextAddress;
+       }
+}
+
+#endif
+
+\f
+
+/*
+  Type declarations
+*/
+
+
+struct malloc_chunk
+{
+  INTERNAL_SIZE_T prev_size; /* Size of previous chunk (if free). */
+  INTERNAL_SIZE_T size;      /* Size in bytes, including overhead. */
+  struct malloc_chunk* fd;   /* double links -- used only if free. */
+  struct malloc_chunk* bk;
+};
+
+typedef struct malloc_chunk* mchunkptr;
+
+/*
+
+   malloc_chunk details:
+
+    (The following includes lightly edited explanations by Colin Plumb.)
+
+    Chunks of memory are maintained using a `boundary tag' method as
+    described in e.g., Knuth or Standish.  (See the paper by Paul
+    Wilson ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a
+    survey of such techniques.)  Sizes of free chunks are stored both
+    in the front of each chunk and at the end.  This makes
+    consolidating fragmented chunks into bigger chunks very fast.  The
+    size fields also hold bits representing whether chunks are free or
+    in use.
+
+    An allocated chunk looks like this:
+
+
+    chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Size of previous chunk, if allocated            | |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Size of chunk, in bytes                         |P|
+      mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             User data starts here...                          .
+            .                                                               .
+            .             (malloc_usable_space() bytes)                     .
+            .                                                               |
+nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Size of chunk                                     |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+
+    Where "chunk" is the front of the chunk for the purpose of most of
+    the malloc code, but "mem" is the pointer that is returned to the
+    user.  "Nextchunk" is the beginning of the next contiguous chunk.
+
+    Chunks always begin on even word boundries, so the mem portion
+    (which is returned to the user) is also on an even word boundary, and
+    thus double-word aligned.
+
+    Free chunks are stored in circular doubly-linked lists, and look like this:
+
+    chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Size of previous chunk                            |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    `head:' |             Size of chunk, in bytes                         |P|
+      mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Forward pointer to next chunk in list             |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Back pointer to previous chunk in list            |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Unused space (may be 0 bytes long)                .
+            .                                                               .
+            .                                                               |
+nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    `foot:' |             Size of chunk, in bytes                           |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+    The P (PREV_INUSE) bit, stored in the unused low-order bit of the
+    chunk size (which is always a multiple of two words), is an in-use
+    bit for the *previous* chunk.  If that bit is *clear*, then the
+    word before the current chunk size contains the previous chunk
+    size, and can be used to find the front of the previous chunk.
+    (The very first chunk allocated always has this bit set,
+    preventing access to non-existent (or non-owned) memory.)
+
+    Note that the `foot' of the current chunk is actually represented
+    as the prev_size of the NEXT chunk. (This makes it easier to
+    deal with alignments etc).
+
+    The two exceptions to all this are
+
+     1. The special chunk `top', which doesn't bother using the
+        trailing size field since there is no
+        next contiguous chunk that would have to index off it. (After
+        initialization, `top' is forced to always exist.  If it would
+        become less than MINSIZE bytes long, it is replenished via
+        malloc_extend_top.)
+
+     2. Chunks allocated via mmap, which have the second-lowest-order
+        bit (IS_MMAPPED) set in their size fields.  Because they are
+        never merged or traversed from any other chunk, they have no
+        foot size or inuse information.
+
+    Available chunks are kept in any of several places (all declared below):
+
+    * `av': An array of chunks serving as bin headers for consolidated
+       chunks. Each bin is doubly linked.  The bins are approximately
+       proportionally (log) spaced.  There are a lot of these bins
+       (128). This may look excessive, but works very well in
+       practice.  All procedures maintain the invariant that no
+       consolidated chunk physically borders another one. Chunks in
+       bins are kept in size order, with ties going to the
+       approximately least recently used chunk.
+
+       The chunks in each bin are maintained in decreasing sorted order by
+       size.  This is irrelevant for the small bins, which all contain
+       the same-sized chunks, but facilitates best-fit allocation for
+       larger chunks. (These lists are just sequential. Keeping them in
+       order almost never requires enough traversal to warrant using
+       fancier ordered data structures.)  Chunks of the same size are
+       linked with the most recently freed at the front, and allocations
+       are taken from the back.  This results in LRU or FIFO allocation
+       order, which tends to give each chunk an equal opportunity to be
+       consolidated with adjacent freed chunks, resulting in larger free
+       chunks and less fragmentation.
+
+    * `top': The top-most available chunk (i.e., the one bordering the
+       end of available memory) is treated specially. It is never
+       included in any bin, is used only if no other chunk is
+       available, and is released back to the system if it is very
+       large (see M_TRIM_THRESHOLD).
+
+    * `last_remainder': A bin holding only the remainder of the
+       most recently split (non-top) chunk. This bin is checked
+       before other non-fitting chunks, so as to provide better
+       locality for runs of sequentially allocated chunks.
+
+    *  Implicitly, through the host system's memory mapping tables.
+       If supported, requests greater than a threshold are usually
+       serviced via calls to mmap, and then later released via munmap.
+
+*/
+
+
+
+\f
+
+
+/*  sizes, alignments */
+
+#define SIZE_SZ                (sizeof(INTERNAL_SIZE_T))
+#define MALLOC_ALIGNMENT       (SIZE_SZ + SIZE_SZ)
+#define MALLOC_ALIGN_MASK      (MALLOC_ALIGNMENT - 1)
+#define MINSIZE                (sizeof(struct malloc_chunk))
+
+/* conversion from malloc headers to user pointers, and back */
+
+#define chunk2mem(p)   ((Void_t*)((char*)(p) + 2*SIZE_SZ))
+#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - 2*SIZE_SZ))
+
+/* pad request bytes into a usable size */
+
+#define request2size(req) \
+ (((long)((req) + (SIZE_SZ + MALLOC_ALIGN_MASK)) < \
+  (long)(MINSIZE + MALLOC_ALIGN_MASK)) ? MINSIZE : \
+   (((req) + (SIZE_SZ + MALLOC_ALIGN_MASK)) & ~(MALLOC_ALIGN_MASK)))
+
+/* Check if m has acceptable alignment */
+
+#define aligned_OK(m)    (((unsigned long)((m)) & (MALLOC_ALIGN_MASK)) == 0)
+
+
+\f
+
+/*
+  Physical chunk operations
+*/
+
+
+/* size field is or'ed with PREV_INUSE when previous adjacent chunk in use */
+
+#define PREV_INUSE 0x1
+
+/* size field is or'ed with IS_MMAPPED if the chunk was obtained with mmap() */
+
+#define IS_MMAPPED 0x2
+
+/* Bits to mask off when extracting size */
+
+#define SIZE_BITS (PREV_INUSE|IS_MMAPPED)
+
+
+/* Ptr to next physical malloc_chunk. */
+
+#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->size & ~PREV_INUSE) ))
+
+/* Ptr to previous physical malloc_chunk */
+
+#define prev_chunk(p)\
+   ((mchunkptr)( ((char*)(p)) - ((p)->prev_size) ))
+
+
+/* Treat space at ptr + offset as a chunk */
+
+#define chunk_at_offset(p, s)  ((mchunkptr)(((char*)(p)) + (s)))
+
+
+\f
+
+/*
+  Dealing with use bits
+*/
+
+/* extract p's inuse bit */
+
+#define inuse(p)\
+((((mchunkptr)(((char*)(p))+((p)->size & ~PREV_INUSE)))->size) & PREV_INUSE)
+
+/* extract inuse bit of previous chunk */
+
+#define prev_inuse(p)  ((p)->size & PREV_INUSE)
+
+/* check for mmap()'ed chunk */
+
+#define chunk_is_mmapped(p) ((p)->size & IS_MMAPPED)
+
+/* set/clear chunk as in use without otherwise disturbing */
+
+#define set_inuse(p)\
+((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size |= PREV_INUSE
+
+#define clear_inuse(p)\
+((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size &= ~(PREV_INUSE)
+
+/* check/set/clear inuse bits in known places */
+
+#define inuse_bit_at_offset(p, s)\
+ (((mchunkptr)(((char*)(p)) + (s)))->size & PREV_INUSE)
+
+#define set_inuse_bit_at_offset(p, s)\
+ (((mchunkptr)(((char*)(p)) + (s)))->size |= PREV_INUSE)
+
+#define clear_inuse_bit_at_offset(p, s)\
+ (((mchunkptr)(((char*)(p)) + (s)))->size &= ~(PREV_INUSE))
+
+
+\f
+
+/*
+  Dealing with size fields
+*/
+
+/* Get size, ignoring use bits */
+
+#define chunksize(p)          ((p)->size & ~(SIZE_BITS))
+
+/* Set size at head, without disturbing its use bit */
+
+#define set_head_size(p, s)   ((p)->size = (((p)->size & PREV_INUSE) | (s)))
+
+/* Set size/use ignoring previous bits in header */
+
+#define set_head(p, s)        ((p)->size = (s))
+
+/* Set size at footer (only when chunk is not in use) */
+
+#define set_foot(p, s)   (((mchunkptr)((char*)(p) + (s)))->prev_size = (s))
+
+
+\f
+
+
+/*
+   Bins
+
+    The bins, `av_' are an array of pairs of pointers serving as the
+    heads of (initially empty) doubly-linked lists of chunks, laid out
+    in a way so that each pair can be treated as if it were in a
+    malloc_chunk. (This way, the fd/bk offsets for linking bin heads
+    and chunks are the same).
+
+    Bins for sizes < 512 bytes contain chunks of all the same size, spaced
+    8 bytes apart. Larger bins are approximately logarithmically
+    spaced. (See the table below.) The `av_' array is never mentioned
+    directly in the code, but instead via bin access macros.
+
+    Bin layout:
+
+    64 bins of size       8
+    32 bins of size      64
+    16 bins of size     512
+     8 bins of size    4096
+     4 bins of size   32768
+     2 bins of size  262144
+     1 bin  of size what's left
+
+    There is actually a little bit of slop in the numbers in bin_index
+    for the sake of speed. This makes no difference elsewhere.
+
+    The special chunks `top' and `last_remainder' get their own bins,
+    (this is implemented via yet more trickery with the av_ array),
+    although `top' is never properly linked to its bin since it is
+    always handled specially.
+
+*/
+
+#define NAV             128   /* number of bins */
+
+typedef struct malloc_chunk* mbinptr;
+
+/* access macros */
+
+#define bin_at(i)      ((mbinptr)((char*)&(av_[2*(i) + 2]) - 2*SIZE_SZ))
+#define next_bin(b)    ((mbinptr)((char*)(b) + 2 * sizeof(mbinptr)))
+#define prev_bin(b)    ((mbinptr)((char*)(b) - 2 * sizeof(mbinptr)))
+
+/*
+   The first 2 bins are never indexed. The corresponding av_ cells are instead
+   used for bookkeeping. This is not to save space, but to simplify
+   indexing, maintain locality, and avoid some initialization tests.
+*/
+
+#define top            (bin_at(0)->fd)   /* The topmost chunk */
+#define last_remainder (bin_at(1))       /* remainder from last split */
+
+
+/*
+   Because top initially points to its own bin with initial
+   zero size, thus forcing extension on the first malloc request,
+   we avoid having any special code in malloc to check whether
+   it even exists yet. But we still need to in malloc_extend_top.
+*/
+
+#define initial_top    ((mchunkptr)(bin_at(0)))
+
+/* Helper macro to initialize bins */
+
+#define IAV(i)  bin_at(i), bin_at(i)
+
+static mbinptr av_[NAV * 2 + 2] = {
+ 0, 0,
+ IAV(0),   IAV(1),   IAV(2),   IAV(3),   IAV(4),   IAV(5),   IAV(6),   IAV(7),
+ IAV(8),   IAV(9),   IAV(10),  IAV(11),  IAV(12),  IAV(13),  IAV(14),  IAV(15),
+ IAV(16),  IAV(17),  IAV(18),  IAV(19),  IAV(20),  IAV(21),  IAV(22),  IAV(23),
+ IAV(24),  IAV(25),  IAV(26),  IAV(27),  IAV(28),  IAV(29),  IAV(30),  IAV(31),
+ IAV(32),  IAV(33),  IAV(34),  IAV(35),  IAV(36),  IAV(37),  IAV(38),  IAV(39),
+ IAV(40),  IAV(41),  IAV(42),  IAV(43),  IAV(44),  IAV(45),  IAV(46),  IAV(47),
+ IAV(48),  IAV(49),  IAV(50),  IAV(51),  IAV(52),  IAV(53),  IAV(54),  IAV(55),
+ IAV(56),  IAV(57),  IAV(58),  IAV(59),  IAV(60),  IAV(61),  IAV(62),  IAV(63),
+ IAV(64),  IAV(65),  IAV(66),  IAV(67),  IAV(68),  IAV(69),  IAV(70),  IAV(71),
+ IAV(72),  IAV(73),  IAV(74),  IAV(75),  IAV(76),  IAV(77),  IAV(78),  IAV(79),
+ IAV(80),  IAV(81),  IAV(82),  IAV(83),  IAV(84),  IAV(85),  IAV(86),  IAV(87),
+ IAV(88),  IAV(89),  IAV(90),  IAV(91),  IAV(92),  IAV(93),  IAV(94),  IAV(95),
+ IAV(96),  IAV(97),  IAV(98),  IAV(99),  IAV(100), IAV(101), IAV(102), IAV(103),
+ IAV(104), IAV(105), IAV(106), IAV(107), IAV(108), IAV(109), IAV(110), IAV(111),
+ IAV(112), IAV(113), IAV(114), IAV(115), IAV(116), IAV(117), IAV(118), IAV(119),
+ IAV(120), IAV(121), IAV(122), IAV(123), IAV(124), IAV(125), IAV(126), IAV(127)
+};
+
+void malloc_bin_reloc (unsigned long offset)
+{
+       unsigned long *p = (unsigned long *)(&av_[2]);
+       int i;
+       for (i=2; i<(sizeof(av_)/sizeof(mbinptr)); ++i) {
+               *p++ += offset;
+       }
+}
+\f
+
+/* field-extraction macros */
+
+#define first(b) ((b)->fd)
+#define last(b)  ((b)->bk)
+
+/*
+  Indexing into bins
+*/
+
+#define bin_index(sz)                                                          \
+(((((unsigned long)(sz)) >> 9) ==    0) ?       (((unsigned long)(sz)) >>  3): \
+ ((((unsigned long)(sz)) >> 9) <=    4) ?  56 + (((unsigned long)(sz)) >>  6): \
+ ((((unsigned long)(sz)) >> 9) <=   20) ?  91 + (((unsigned long)(sz)) >>  9): \
+ ((((unsigned long)(sz)) >> 9) <=   84) ? 110 + (((unsigned long)(sz)) >> 12): \
+ ((((unsigned long)(sz)) >> 9) <=  340) ? 119 + (((unsigned long)(sz)) >> 15): \
+ ((((unsigned long)(sz)) >> 9) <= 1364) ? 124 + (((unsigned long)(sz)) >> 18): \
+                                          126)
+/*
+  bins for chunks < 512 are all spaced 8 bytes apart, and hold
+  identically sized chunks. This is exploited in malloc.
+*/
+
+#define MAX_SMALLBIN         63
+#define MAX_SMALLBIN_SIZE   512
+#define SMALLBIN_WIDTH        8
+
+#define smallbin_index(sz)  (((unsigned long)(sz)) >> 3)
+
+/*
+   Requests are `small' if both the corresponding and the next bin are small
+*/
+
+#define is_small_request(nb) (nb < MAX_SMALLBIN_SIZE - SMALLBIN_WIDTH)
+
+\f
+
+/*
+    To help compensate for the large number of bins, a one-level index
+    structure is used for bin-by-bin searching.  `binblocks' is a
+    one-word bitvector recording whether groups of BINBLOCKWIDTH bins
+    have any (possibly) non-empty bins, so they can be skipped over
+    all at once during during traversals. The bits are NOT always
+    cleared as soon as all bins in a block are empty, but instead only
+    when all are noticed to be empty during traversal in malloc.
+*/
+
+#define BINBLOCKWIDTH     4   /* bins per block */
+
+#define binblocks      (bin_at(0)->size) /* bitvector of nonempty blocks */
+
+/* bin<->block macros */
+
+#define idx2binblock(ix)    ((unsigned)1 << (ix / BINBLOCKWIDTH))
+#define mark_binblock(ii)   (binblocks |= idx2binblock(ii))
+#define clear_binblock(ii)  (binblocks &= ~(idx2binblock(ii)))
+
+
+\f
+
+
+/*  Other static bookkeeping data */
+
+/* variables holding tunable values */
+
+static unsigned long trim_threshold   = DEFAULT_TRIM_THRESHOLD;
+static unsigned long top_pad          = DEFAULT_TOP_PAD;
+static unsigned int  n_mmaps_max      = DEFAULT_MMAP_MAX;
+static unsigned long mmap_threshold   = DEFAULT_MMAP_THRESHOLD;
+
+/* The first value returned from sbrk */
+static char* sbrk_base = (char*)(-1);
+
+/* The maximum memory obtained from system via sbrk */
+static unsigned long max_sbrked_mem = 0;
+
+/* The maximum via either sbrk or mmap */
+static unsigned long max_total_mem = 0;
+
+/* internal working copy of mallinfo */
+static struct mallinfo current_mallinfo = {  0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+/* The total memory obtained from system via sbrk */
+#define sbrked_mem  (current_mallinfo.arena)
+
+/* Tracking mmaps */
+
+#if 0
+static unsigned int n_mmaps = 0;
+#endif /* 0 */
+static unsigned long mmapped_mem = 0;
+#if HAVE_MMAP
+static unsigned int max_n_mmaps = 0;
+static unsigned long max_mmapped_mem = 0;
+#endif
+
+\f
+
+/*
+  Debugging support
+*/
+
+#if DEBUG
+
+
+/*
+  These routines make a number of assertions about the states
+  of data structures that should be true at all times. If any
+  are not true, it's very likely that a user program has somehow
+  trashed memory. (It's also possible that there is a coding error
+  in malloc. In which case, please report it!)
+*/
+
+#if __STD_C
+static void do_check_chunk(mchunkptr p)
+#else
+static void do_check_chunk(p) mchunkptr p;
+#endif
+{
+#if 0  /* causes warnings because assert() is off */
+  INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE;
+#endif /* 0 */
+
+  /* No checkable chunk is mmapped */
+  assert(!chunk_is_mmapped(p));
+
+  /* Check for legal address ... */
+  assert((char*)p >= sbrk_base);
+  if (p != top)
+    assert((char*)p + sz <= (char*)top);
+  else
+    assert((char*)p + sz <= sbrk_base + sbrked_mem);
+
+}
+
+
+#if __STD_C
+static void do_check_free_chunk(mchunkptr p)
+#else
+static void do_check_free_chunk(p) mchunkptr p;
+#endif
+{
+  INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE;
+#if 0  /* causes warnings because assert() is off */
+  mchunkptr next = chunk_at_offset(p, sz);
+#endif /* 0 */
+
+  do_check_chunk(p);
+
+  /* Check whether it claims to be free ... */
+  assert(!inuse(p));
+
+  /* Unless a special marker, must have OK fields */
+  if ((long)sz >= (long)MINSIZE)
+  {
+    assert((sz & MALLOC_ALIGN_MASK) == 0);
+    assert(aligned_OK(chunk2mem(p)));
+    /* ... matching footer field */
+    assert(next->prev_size == sz);
+    /* ... and is fully consolidated */
+    assert(prev_inuse(p));
+    assert (next == top || inuse(next));
+
+    /* ... and has minimally sane links */
+    assert(p->fd->bk == p);
+    assert(p->bk->fd == p);
+  }
+  else /* markers are always of size SIZE_SZ */
+    assert(sz == SIZE_SZ);
+}
+
+#if __STD_C
+static void do_check_inuse_chunk(mchunkptr p)
+#else
+static void do_check_inuse_chunk(p) mchunkptr p;
+#endif
+{
+  mchunkptr next = next_chunk(p);
+  do_check_chunk(p);
+
+  /* Check whether it claims to be in use ... */
+  assert(inuse(p));
+
+  /* ... and is surrounded by OK chunks.
+    Since more things can be checked with free chunks than inuse ones,
+    if an inuse chunk borders them and debug is on, it's worth doing them.
+  */
+  if (!prev_inuse(p))
+  {
+    mchunkptr prv = prev_chunk(p);
+    assert(next_chunk(prv) == p);
+    do_check_free_chunk(prv);
+  }
+  if (next == top)
+  {
+    assert(prev_inuse(next));
+    assert(chunksize(next) >= MINSIZE);
+  }
+  else if (!inuse(next))
+    do_check_free_chunk(next);
+
+}
+
+#if __STD_C
+static void do_check_malloced_chunk(mchunkptr p, INTERNAL_SIZE_T s)
+#else
+static void do_check_malloced_chunk(p, s) mchunkptr p; INTERNAL_SIZE_T s;
+#endif
+{
+#if 0  /* causes warnings because assert() is off */
+  INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE;
+  long room = sz - s;
+#endif /* 0 */
+
+  do_check_inuse_chunk(p);
+
+  /* Legal size ... */
+  assert((long)sz >= (long)MINSIZE);
+  assert((sz & MALLOC_ALIGN_MASK) == 0);
+  assert(room >= 0);
+  assert(room < (long)MINSIZE);
+
+  /* ... and alignment */
+  assert(aligned_OK(chunk2mem(p)));
+
+
+  /* ... and was allocated at front of an available chunk */
+  assert(prev_inuse(p));
+
+}
+
+
+#define check_free_chunk(P)  do_check_free_chunk(P)
+#define check_inuse_chunk(P) do_check_inuse_chunk(P)
+#define check_chunk(P) do_check_chunk(P)
+#define check_malloced_chunk(P,N) do_check_malloced_chunk(P,N)
+#else
+#define check_free_chunk(P)
+#define check_inuse_chunk(P)
+#define check_chunk(P)
+#define check_malloced_chunk(P,N)
+#endif
+
+\f
+
+/*
+  Macro-based internal utilities
+*/
+
+
+/*
+  Linking chunks in bin lists.
+  Call these only with variables, not arbitrary expressions, as arguments.
+*/
+
+/*
+  Place chunk p of size s in its bin, in size order,
+  putting it ahead of others of same size.
+*/
+
+
+#define frontlink(P, S, IDX, BK, FD)                                          \
+{                                                                             \
+  if (S < MAX_SMALLBIN_SIZE)                                                  \
+  {                                                                           \
+    IDX = smallbin_index(S);                                                  \
+    mark_binblock(IDX);                                                       \
+    BK = bin_at(IDX);                                                         \
+    FD = BK->fd;                                                              \
+    P->bk = BK;                                                               \
+    P->fd = FD;                                                               \
+    FD->bk = BK->fd = P;                                                      \
+  }                                                                           \
+  else                                                                        \
+  {                                                                           \
+    IDX = bin_index(S);                                                       \
+    BK = bin_at(IDX);                                                         \
+    FD = BK->fd;                                                              \
+    if (FD == BK) mark_binblock(IDX);                                         \
+    else                                                                      \
+    {                                                                         \
+      while (FD != BK && S < chunksize(FD)) FD = FD->fd;                      \
+      BK = FD->bk;                                                            \
+    }                                                                         \
+    P->bk = BK;                                                               \
+    P->fd = FD;                                                               \
+    FD->bk = BK->fd = P;                                                      \
+  }                                                                           \
+}
+
+
+/* take a chunk off a list */
+
+#define unlink(P, BK, FD)                                                     \
+{                                                                             \
+  BK = P->bk;                                                                 \
+  FD = P->fd;                                                                 \
+  FD->bk = BK;                                                                \
+  BK->fd = FD;                                                                \
+}                                                                             \
+
+/* Place p as the last remainder */
+
+#define link_last_remainder(P)                                                \
+{                                                                             \
+  last_remainder->fd = last_remainder->bk =  P;                               \
+  P->fd = P->bk = last_remainder;                                             \
+}
+
+/* Clear the last_remainder bin */
+
+#define clear_last_remainder \
+  (last_remainder->fd = last_remainder->bk = last_remainder)
+
+
+
+\f
+
+
+/* Routines dealing with mmap(). */
+
+#if HAVE_MMAP
+
+#if __STD_C
+static mchunkptr mmap_chunk(size_t size)
+#else
+static mchunkptr mmap_chunk(size) size_t size;
+#endif
+{
+  size_t page_mask = malloc_getpagesize - 1;
+  mchunkptr p;
+
+#ifndef MAP_ANONYMOUS
+  static int fd = -1;
+#endif
+
+  if(n_mmaps >= n_mmaps_max) return 0; /* too many regions */
+
+  /* For mmapped chunks, the overhead is one SIZE_SZ unit larger, because
+   * there is no following chunk whose prev_size field could be used.
+   */
+  size = (size + SIZE_SZ + page_mask) & ~page_mask;
+
+#ifdef MAP_ANONYMOUS
+  p = (mchunkptr)mmap(0, size, PROT_READ|PROT_WRITE,
+                     MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
+#else /* !MAP_ANONYMOUS */
+  if (fd < 0)
+  {
+    fd = open("/dev/zero", O_RDWR);
+    if(fd < 0) return 0;
+  }
+  p = (mchunkptr)mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
+#endif
+
+  if(p == (mchunkptr)-1) return 0;
+
+  n_mmaps++;
+  if (n_mmaps > max_n_mmaps) max_n_mmaps = n_mmaps;
+
+  /* We demand that eight bytes into a page must be 8-byte aligned. */
+  assert(aligned_OK(chunk2mem(p)));
+
+  /* The offset to the start of the mmapped region is stored
+   * in the prev_size field of the chunk; normally it is zero,
+   * but that can be changed in memalign().
+   */
+  p->prev_size = 0;
+  set_head(p, size|IS_MMAPPED);
+
+  mmapped_mem += size;
+  if ((unsigned long)mmapped_mem > (unsigned long)max_mmapped_mem)
+    max_mmapped_mem = mmapped_mem;
+  if ((unsigned long)(mmapped_mem + sbrked_mem) > (unsigned long)max_total_mem)
+    max_total_mem = mmapped_mem + sbrked_mem;
+  return p;
+}
+
+#if __STD_C
+static void munmap_chunk(mchunkptr p)
+#else
+static void munmap_chunk(p) mchunkptr p;
+#endif
+{
+  INTERNAL_SIZE_T size = chunksize(p);
+  int ret;
+
+  assert (chunk_is_mmapped(p));
+  assert(! ((char*)p >= sbrk_base && (char*)p < sbrk_base + sbrked_mem));
+  assert((n_mmaps > 0));
+  assert(((p->prev_size + size) & (malloc_getpagesize-1)) == 0);
+
+  n_mmaps--;
+  mmapped_mem -= (size + p->prev_size);
+
+  ret = munmap((char *)p - p->prev_size, size + p->prev_size);
+
+  /* munmap returns non-zero on failure */
+  assert(ret == 0);
+}
+
+#if HAVE_MREMAP
+
+#if __STD_C
+static mchunkptr mremap_chunk(mchunkptr p, size_t new_size)
+#else
+static mchunkptr mremap_chunk(p, new_size) mchunkptr p; size_t new_size;
+#endif
+{
+  size_t page_mask = malloc_getpagesize - 1;
+  INTERNAL_SIZE_T offset = p->prev_size;
+  INTERNAL_SIZE_T size = chunksize(p);
+  char *cp;
+
+  assert (chunk_is_mmapped(p));
+  assert(! ((char*)p >= sbrk_base && (char*)p < sbrk_base + sbrked_mem));
+  assert((n_mmaps > 0));
+  assert(((size + offset) & (malloc_getpagesize-1)) == 0);
+
+  /* Note the extra SIZE_SZ overhead as in mmap_chunk(). */
+  new_size = (new_size + offset + SIZE_SZ + page_mask) & ~page_mask;
+
+  cp = (char *)mremap((char *)p - offset, size + offset, new_size, 1);
+
+  if (cp == (char *)-1) return 0;
+
+  p = (mchunkptr)(cp + offset);
+
+  assert(aligned_OK(chunk2mem(p)));
+
+  assert((p->prev_size == offset));
+  set_head(p, (new_size - offset)|IS_MMAPPED);
+
+  mmapped_mem -= size + offset;
+  mmapped_mem += new_size;
+  if ((unsigned long)mmapped_mem > (unsigned long)max_mmapped_mem)
+    max_mmapped_mem = mmapped_mem;
+  if ((unsigned long)(mmapped_mem + sbrked_mem) > (unsigned long)max_total_mem)
+    max_total_mem = mmapped_mem + sbrked_mem;
+  return p;
+}
+
+#endif /* HAVE_MREMAP */
+
+#endif /* HAVE_MMAP */
+
+
+\f
+
+/*
+  Extend the top-most chunk by obtaining memory from system.
+  Main interface to sbrk (but see also malloc_trim).
+*/
+
+#if __STD_C
+static void malloc_extend_top(INTERNAL_SIZE_T nb)
+#else
+static void malloc_extend_top(nb) INTERNAL_SIZE_T nb;
+#endif
+{
+  char*     brk;                  /* return value from sbrk */
+  INTERNAL_SIZE_T front_misalign; /* unusable bytes at front of sbrked space */
+  INTERNAL_SIZE_T correction;     /* bytes for 2nd sbrk call */
+  char*     new_brk;              /* return of 2nd sbrk call */
+  INTERNAL_SIZE_T top_size;       /* new size of top chunk */
+
+  mchunkptr old_top     = top;  /* Record state of old top */
+  INTERNAL_SIZE_T old_top_size = chunksize(old_top);
+  char*     old_end      = (char*)(chunk_at_offset(old_top, old_top_size));
+
+  /* Pad request with top_pad plus minimal overhead */
+
+  INTERNAL_SIZE_T    sbrk_size     = nb + top_pad + MINSIZE;
+  unsigned long pagesz    = malloc_getpagesize;
+
+  /* If not the first time through, round to preserve page boundary */
+  /* Otherwise, we need to correct to a page size below anyway. */
+  /* (We also correct below if an intervening foreign sbrk call.) */
+
+  if (sbrk_base != (char*)(-1))
+    sbrk_size = (sbrk_size + (pagesz - 1)) & ~(pagesz - 1);
+
+  brk = (char*)(MORECORE (sbrk_size));
+
+  /* Fail if sbrk failed or if a foreign sbrk call killed our space */
+  if (brk == (char*)(MORECORE_FAILURE) ||
+      (brk < old_end && old_top != initial_top))
+    return;
+
+  sbrked_mem += sbrk_size;
+
+  if (brk == old_end) /* can just add bytes to current top */
+  {
+    top_size = sbrk_size + old_top_size;
+    set_head(top, top_size | PREV_INUSE);
+  }
+  else
+  {
+    if (sbrk_base == (char*)(-1))  /* First time through. Record base */
+      sbrk_base = brk;
+    else  /* Someone else called sbrk().  Count those bytes as sbrked_mem. */
+      sbrked_mem += brk - (char*)old_end;
+
+    /* Guarantee alignment of first new chunk made from this space */
+    front_misalign = (unsigned long)chunk2mem(brk) & MALLOC_ALIGN_MASK;
+    if (front_misalign > 0)
+    {
+      correction = (MALLOC_ALIGNMENT) - front_misalign;
+      brk += correction;
+    }
+    else
+      correction = 0;
+
+    /* Guarantee the next brk will be at a page boundary */
+
+    correction += ((((unsigned long)(brk + sbrk_size))+(pagesz-1)) &
+                   ~(pagesz - 1)) - ((unsigned long)(brk + sbrk_size));
+
+    /* Allocate correction */
+    new_brk = (char*)(MORECORE (correction));
+    if (new_brk == (char*)(MORECORE_FAILURE)) return;
+
+    sbrked_mem += correction;
+
+    top = (mchunkptr)brk;
+    top_size = new_brk - brk + correction;
+    set_head(top, top_size | PREV_INUSE);
+
+    if (old_top != initial_top)
+    {
+
+      /* There must have been an intervening foreign sbrk call. */
+      /* A double fencepost is necessary to prevent consolidation */
+
+      /* If not enough space to do this, then user did something very wrong */
+      if (old_top_size < MINSIZE)
+      {
+        set_head(top, PREV_INUSE); /* will force null return from malloc */
+        return;
+      }
+
+      /* Also keep size a multiple of MALLOC_ALIGNMENT */
+      old_top_size = (old_top_size - 3*SIZE_SZ) & ~MALLOC_ALIGN_MASK;
+      set_head_size(old_top, old_top_size);
+      chunk_at_offset(old_top, old_top_size          )->size =
+        SIZE_SZ|PREV_INUSE;
+      chunk_at_offset(old_top, old_top_size + SIZE_SZ)->size =
+        SIZE_SZ|PREV_INUSE;
+      /* If possible, release the rest. */
+      if (old_top_size >= MINSIZE)
+        fREe(chunk2mem(old_top));
+    }
+  }
+
+  if ((unsigned long)sbrked_mem > (unsigned long)max_sbrked_mem)
+    max_sbrked_mem = sbrked_mem;
+  if ((unsigned long)(mmapped_mem + sbrked_mem) > (unsigned long)max_total_mem)
+    max_total_mem = mmapped_mem + sbrked_mem;
+
+  /* We always land on a page boundary */
+  assert(((unsigned long)((char*)top + top_size) & (pagesz - 1)) == 0);
+}
+
+
+\f
+
+/* Main public routines */
+
+
+/*
+  Malloc Algorthim:
+
+    The requested size is first converted into a usable form, `nb'.
+    This currently means to add 4 bytes overhead plus possibly more to
+    obtain 8-byte alignment and/or to obtain a size of at least
+    MINSIZE (currently 16 bytes), the smallest allocatable size.
+    (All fits are considered `exact' if they are within MINSIZE bytes.)
+
+    From there, the first successful of the following steps is taken:
+
+      1. The bin corresponding to the request size is scanned, and if
+         a chunk of exactly the right size is found, it is taken.
+
+      2. The most recently remaindered chunk is used if it is big
+         enough.  This is a form of (roving) first fit, used only in
+         the absence of exact fits. Runs of consecutive requests use
+         the remainder of the chunk used for the previous such request
+         whenever possible. This limited use of a first-fit style
+         allocation strategy tends to give contiguous chunks
+         coextensive lifetimes, which improves locality and can reduce
+         fragmentation in the long run.
+
+      3. Other bins are scanned in increasing size order, using a
+         chunk big enough to fulfill the request, and splitting off
+         any remainder.  This search is strictly by best-fit; i.e.,
+         the smallest (with ties going to approximately the least
+         recently used) chunk that fits is selected.
+
+      4. If large enough, the chunk bordering the end of memory
+         (`top') is split off. (This use of `top' is in accord with
+         the best-fit search rule.  In effect, `top' is treated as
+         larger (and thus less well fitting) than any other available
+         chunk since it can be extended to be as large as necessary
+         (up to system limitations).
+
+      5. If the request size meets the mmap threshold and the
+         system supports mmap, and there are few enough currently
+         allocated mmapped regions, and a call to mmap succeeds,
+         the request is allocated via direct memory mapping.
+
+      6. Otherwise, the top of memory is extended by
+         obtaining more space from the system (normally using sbrk,
+         but definable to anything else via the MORECORE macro).
+         Memory is gathered from the system (in system page-sized
+         units) in a way that allows chunks obtained across different
+         sbrk calls to be consolidated, but does not require
+         contiguous memory. Thus, it should be safe to intersperse
+         mallocs with other sbrk calls.
+
+
+      All allocations are made from the the `lowest' part of any found
+      chunk. (The implementation invariant is that prev_inuse is
+      always true of any allocated chunk; i.e., that each allocated
+      chunk borders either a previously allocated and still in-use chunk,
+      or the base of its memory arena.)
+
+*/
+
+#if __STD_C
+Void_t* mALLOc(size_t bytes)
+#else
+Void_t* mALLOc(bytes) size_t bytes;
+#endif
+{
+  mchunkptr victim;                  /* inspected/selected chunk */
+  INTERNAL_SIZE_T victim_size;       /* its size */
+  int       idx;                     /* index for bin traversal */
+  mbinptr   bin;                     /* associated bin */
+  mchunkptr remainder;               /* remainder from a split */
+  long      remainder_size;          /* its size */
+  int       remainder_index;         /* its bin index */
+  unsigned long block;               /* block traverser bit */
+  int       startidx;                /* first bin of a traversed block */
+  mchunkptr fwd;                     /* misc temp for linking */
+  mchunkptr bck;                     /* misc temp for linking */
+  mbinptr q;                         /* misc temp */
+
+  INTERNAL_SIZE_T nb;
+
+  if ((long)bytes < 0) return 0;
+
+  nb = request2size(bytes);  /* padded request size; */
+
+  /* Check for exact match in a bin */
+
+  if (is_small_request(nb))  /* Faster version for small requests */
+  {
+    idx = smallbin_index(nb);
+
+    /* No traversal or size check necessary for small bins.  */
+
+    q = bin_at(idx);
+    victim = last(q);
+
+    /* Also scan the next one, since it would have a remainder < MINSIZE */
+    if (victim == q)
+    {
+      q = next_bin(q);
+      victim = last(q);
+    }
+    if (victim != q)
+    {
+      victim_size = chunksize(victim);
+      unlink(victim, bck, fwd);
+      set_inuse_bit_at_offset(victim, victim_size);
+      check_malloced_chunk(victim, nb);
+      return chunk2mem(victim);
+    }
+
+    idx += 2; /* Set for bin scan below. We've already scanned 2 bins. */
+
+  }
+  else
+  {
+    idx = bin_index(nb);
+    bin = bin_at(idx);
+
+    for (victim = last(bin); victim != bin; victim = victim->bk)
+    {
+      victim_size = chunksize(victim);
+      remainder_size = victim_size - nb;
+
+      if (remainder_size >= (long)MINSIZE) /* too big */
+      {
+        --idx; /* adjust to rescan below after checking last remainder */
+        break;
+      }
+
+      else if (remainder_size >= 0) /* exact fit */
+      {
+        unlink(victim, bck, fwd);
+        set_inuse_bit_at_offset(victim, victim_size);
+        check_malloced_chunk(victim, nb);
+        return chunk2mem(victim);
+      }
+    }
+
+    ++idx;
+
+  }
+
+  /* Try to use the last split-off remainder */
+
+  if ( (victim = last_remainder->fd) != last_remainder)
+  {
+    victim_size = chunksize(victim);
+    remainder_size = victim_size - nb;
+
+    if (remainder_size >= (long)MINSIZE) /* re-split */
+    {
+      remainder = chunk_at_offset(victim, nb);
+      set_head(victim, nb | PREV_INUSE);
+      link_last_remainder(remainder);
+      set_head(remainder, remainder_size | PREV_INUSE);
+      set_foot(remainder, remainder_size);
+      check_malloced_chunk(victim, nb);
+      return chunk2mem(victim);
+    }
+
+    clear_last_remainder;
+
+    if (remainder_size >= 0)  /* exhaust */
+    {
+      set_inuse_bit_at_offset(victim, victim_size);
+      check_malloced_chunk(victim, nb);
+      return chunk2mem(victim);
+    }
+
+    /* Else place in bin */
+
+    frontlink(victim, victim_size, remainder_index, bck, fwd);
+  }
+
+  /*
+     If there are any possibly nonempty big-enough blocks,
+     search for best fitting chunk by scanning bins in blockwidth units.
+  */
+
+  if ( (block = idx2binblock(idx)) <= binblocks)
+  {
+
+    /* Get to the first marked block */
+
+    if ( (block & binblocks) == 0)
+    {
+      /* force to an even block boundary */
+      idx = (idx & ~(BINBLOCKWIDTH - 1)) + BINBLOCKWIDTH;
+      block <<= 1;
+      while ((block & binblocks) == 0)
+      {
+        idx += BINBLOCKWIDTH;
+        block <<= 1;
+      }
+    }
+
+    /* For each possibly nonempty block ... */
+    for (;;)
+    {
+      startidx = idx;          /* (track incomplete blocks) */
+      q = bin = bin_at(idx);
+
+      /* For each bin in this block ... */
+      do
+      {
+        /* Find and use first big enough chunk ... */
+
+        for (victim = last(bin); victim != bin; victim = victim->bk)
+        {
+          victim_size = chunksize(victim);
+          remainder_size = victim_size - nb;
+
+          if (remainder_size >= (long)MINSIZE) /* split */
+          {
+            remainder = chunk_at_offset(victim, nb);
+            set_head(victim, nb | PREV_INUSE);
+            unlink(victim, bck, fwd);
+            link_last_remainder(remainder);
+            set_head(remainder, remainder_size | PREV_INUSE);
+            set_foot(remainder, remainder_size);
+            check_malloced_chunk(victim, nb);
+            return chunk2mem(victim);
+          }
+
+          else if (remainder_size >= 0)  /* take */
+          {
+            set_inuse_bit_at_offset(victim, victim_size);
+            unlink(victim, bck, fwd);
+            check_malloced_chunk(victim, nb);
+            return chunk2mem(victim);
+          }
+
+        }
+
+       bin = next_bin(bin);
+
+      } while ((++idx & (BINBLOCKWIDTH - 1)) != 0);
+
+      /* Clear out the block bit. */
+
+      do   /* Possibly backtrack to try to clear a partial block */
+      {
+        if ((startidx & (BINBLOCKWIDTH - 1)) == 0)
+        {
+          binblocks &= ~block;
+          break;
+        }
+        --startidx;
+       q = prev_bin(q);
+      } while (first(q) == q);
+
+      /* Get to the next possibly nonempty block */
+
+      if ( (block <<= 1) <= binblocks && (block != 0) )
+      {
+        while ((block & binblocks) == 0)
+        {
+          idx += BINBLOCKWIDTH;
+          block <<= 1;
+        }
+      }
+      else
+        break;
+    }
+  }
+
+
+  /* Try to use top chunk */
+
+  /* Require that there be a remainder, ensuring top always exists  */
+  if ( (remainder_size = chunksize(top) - nb) < (long)MINSIZE)
+  {
+
+#if HAVE_MMAP
+    /* If big and would otherwise need to extend, try to use mmap instead */
+    if ((unsigned long)nb >= (unsigned long)mmap_threshold &&
+        (victim = mmap_chunk(nb)) != 0)
+      return chunk2mem(victim);
+#endif
+
+    /* Try to extend */
+    malloc_extend_top(nb);
+    if ( (remainder_size = chunksize(top) - nb) < (long)MINSIZE)
+      return 0; /* propagate failure */
+  }
+
+  victim = top;
+  set_head(victim, nb | PREV_INUSE);
+  top = chunk_at_offset(victim, nb);
+  set_head(top, remainder_size | PREV_INUSE);
+  check_malloced_chunk(victim, nb);
+  return chunk2mem(victim);
+
+}
+
+
+\f
+
+/*
+
+  free() algorithm :
+
+    cases:
+
+       1. free(0) has no effect.
+
+       2. If the chunk was allocated via mmap, it is release via munmap().
+
+       3. If a returned chunk borders the current high end of memory,
+          it is consolidated into the top, and if the total unused
+          topmost memory exceeds the trim threshold, malloc_trim is
+          called.
+
+       4. Other chunks are consolidated as they arrive, and
+          placed in corresponding bins. (This includes the case of
+          consolidating with the current `last_remainder').
+
+*/
+
+
+#if __STD_C
+void fREe(Void_t* mem)
+#else
+void fREe(mem) Void_t* mem;
+#endif
+{
+  mchunkptr p;         /* chunk corresponding to mem */
+  INTERNAL_SIZE_T hd;  /* its head field */
+  INTERNAL_SIZE_T sz;  /* its size */
+  int       idx;       /* its bin index */
+  mchunkptr next;      /* next contiguous chunk */
+  INTERNAL_SIZE_T nextsz; /* its size */
+  INTERNAL_SIZE_T prevsz; /* size of previous contiguous chunk */
+  mchunkptr bck;       /* misc temp for linking */
+  mchunkptr fwd;       /* misc temp for linking */
+  int       islr;      /* track whether merging with last_remainder */
+
+  if (mem == 0)                              /* free(0) has no effect */
+    return;
+
+  p = mem2chunk(mem);
+  hd = p->size;
+
+#if HAVE_MMAP
+  if (hd & IS_MMAPPED)                       /* release mmapped memory. */
+  {
+    munmap_chunk(p);
+    return;
+  }
+#endif
+
+  check_inuse_chunk(p);
+
+  sz = hd & ~PREV_INUSE;
+  next = chunk_at_offset(p, sz);
+  nextsz = chunksize(next);
+
+  if (next == top)                            /* merge with top */
+  {
+    sz += nextsz;
+
+    if (!(hd & PREV_INUSE))                    /* consolidate backward */
+    {
+      prevsz = p->prev_size;
+      p = chunk_at_offset(p, -((long) prevsz));
+      sz += prevsz;
+      unlink(p, bck, fwd);
+    }
+
+    set_head(p, sz | PREV_INUSE);
+    top = p;
+    if ((unsigned long)(sz) >= (unsigned long)trim_threshold)
+      malloc_trim(top_pad);
+    return;
+  }
+
+  set_head(next, nextsz);                    /* clear inuse bit */
+
+  islr = 0;
+
+  if (!(hd & PREV_INUSE))                    /* consolidate backward */
+  {
+    prevsz = p->prev_size;
+    p = chunk_at_offset(p, -((long) prevsz));
+    sz += prevsz;
+
+    if (p->fd == last_remainder)             /* keep as last_remainder */
+      islr = 1;
+    else
+      unlink(p, bck, fwd);
+  }
+
+  if (!(inuse_bit_at_offset(next, nextsz)))   /* consolidate forward */
+  {
+    sz += nextsz;
+
+    if (!islr && next->fd == last_remainder)  /* re-insert last_remainder */
+    {
+      islr = 1;
+      link_last_remainder(p);
+    }
+    else
+      unlink(next, bck, fwd);
+  }
+
+
+  set_head(p, sz | PREV_INUSE);
+  set_foot(p, sz);
+  if (!islr)
+    frontlink(p, sz, idx, bck, fwd);
+}
+
+
+\f
+
+
+/*
+
+  Realloc algorithm:
+
+    Chunks that were obtained via mmap cannot be extended or shrunk
+    unless HAVE_MREMAP is defined, in which case mremap is used.
+    Otherwise, if their reallocation is for additional space, they are
+    copied.  If for less, they are just left alone.
+
+    Otherwise, if the reallocation is for additional space, and the
+    chunk can be extended, it is, else a malloc-copy-free sequence is
+    taken.  There are several different ways that a chunk could be
+    extended. All are tried:
+
+       * Extending forward into following adjacent free chunk.
+       * Shifting backwards, joining preceding adjacent space
+       * Both shifting backwards and extending forward.
+       * Extending into newly sbrked space
+
+    Unless the #define REALLOC_ZERO_BYTES_FREES is set, realloc with a
+    size argument of zero (re)allocates a minimum-sized chunk.
+
+    If the reallocation is for less space, and the new request is for
+    a `small' (<512 bytes) size, then the newly unused space is lopped
+    off and freed.
+
+    The old unix realloc convention of allowing the last-free'd chunk
+    to be used as an argument to realloc is no longer supported.
+    I don't know of any programs still relying on this feature,
+    and allowing it would also allow too many other incorrect
+    usages of realloc to be sensible.
+
+
+*/
+
+
+#if __STD_C
+Void_t* rEALLOc(Void_t* oldmem, size_t bytes)
+#else
+Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes;
+#endif
+{
+  INTERNAL_SIZE_T    nb;      /* padded request size */
+
+  mchunkptr oldp;             /* chunk corresponding to oldmem */
+  INTERNAL_SIZE_T    oldsize; /* its size */
+
+  mchunkptr newp;             /* chunk to return */
+  INTERNAL_SIZE_T    newsize; /* its size */
+  Void_t*   newmem;           /* corresponding user mem */
+
+  mchunkptr next;             /* next contiguous chunk after oldp */
+  INTERNAL_SIZE_T  nextsize;  /* its size */
+
+  mchunkptr prev;             /* previous contiguous chunk before oldp */
+  INTERNAL_SIZE_T  prevsize;  /* its size */
+
+  mchunkptr remainder;        /* holds split off extra space from newp */
+  INTERNAL_SIZE_T  remainder_size;   /* its size */
+
+  mchunkptr bck;              /* misc temp for linking */
+  mchunkptr fwd;              /* misc temp for linking */
+
+#ifdef REALLOC_ZERO_BYTES_FREES
+  if (bytes == 0) { fREe(oldmem); return 0; }
+#endif
+
+  if ((long)bytes < 0) return 0;
+
+  /* realloc of null is supposed to be same as malloc */
+  if (oldmem == 0) return mALLOc(bytes);
+
+  newp    = oldp    = mem2chunk(oldmem);
+  newsize = oldsize = chunksize(oldp);
+
+
+  nb = request2size(bytes);
+
+#if HAVE_MMAP
+  if (chunk_is_mmapped(oldp))
+  {
+#if HAVE_MREMAP
+    newp = mremap_chunk(oldp, nb);
+    if(newp) return chunk2mem(newp);
+#endif
+    /* Note the extra SIZE_SZ overhead. */
+    if(oldsize - SIZE_SZ >= nb) return oldmem; /* do nothing */
+    /* Must alloc, copy, free. */
+    newmem = mALLOc(bytes);
+    if (newmem == 0) return 0; /* propagate failure */
+    MALLOC_COPY(newmem, oldmem, oldsize - 2*SIZE_SZ);
+    munmap_chunk(oldp);
+    return newmem;
+  }
+#endif
+
+  check_inuse_chunk(oldp);
+
+  if ((long)(oldsize) < (long)(nb))
+  {
+
+    /* Try expanding forward */
+
+    next = chunk_at_offset(oldp, oldsize);
+    if (next == top || !inuse(next))
+    {
+      nextsize = chunksize(next);
+
+      /* Forward into top only if a remainder */
+      if (next == top)
+      {
+        if ((long)(nextsize + newsize) >= (long)(nb + MINSIZE))
+        {
+          newsize += nextsize;
+          top = chunk_at_offset(oldp, nb);
+          set_head(top, (newsize - nb) | PREV_INUSE);
+          set_head_size(oldp, nb);
+          return chunk2mem(oldp);
+        }
+      }
+
+      /* Forward into next chunk */
+      else if (((long)(nextsize + newsize) >= (long)(nb)))
+      {
+        unlink(next, bck, fwd);
+        newsize  += nextsize;
+        goto split;
+      }
+    }
+    else
+    {
+      next = 0;
+      nextsize = 0;
+    }
+
+    /* Try shifting backwards. */
+
+    if (!prev_inuse(oldp))
+    {
+      prev = prev_chunk(oldp);
+      prevsize = chunksize(prev);
+
+      /* try forward + backward first to save a later consolidation */
+
+      if (next != 0)
+      {
+        /* into top */
+        if (next == top)
+        {
+          if ((long)(nextsize + prevsize + newsize) >= (long)(nb + MINSIZE))
+          {
+            unlink(prev, bck, fwd);
+            newp = prev;
+            newsize += prevsize + nextsize;
+            newmem = chunk2mem(newp);
+            MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ);
+            top = chunk_at_offset(newp, nb);
+            set_head(top, (newsize - nb) | PREV_INUSE);
+            set_head_size(newp, nb);
+            return newmem;
+          }
+        }
+
+        /* into next chunk */
+        else if (((long)(nextsize + prevsize + newsize) >= (long)(nb)))
+        {
+          unlink(next, bck, fwd);
+          unlink(prev, bck, fwd);
+          newp = prev;
+          newsize += nextsize + prevsize;
+          newmem = chunk2mem(newp);
+          MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ);
+          goto split;
+        }
+      }
+
+      /* backward only */
+      if (prev != 0 && (long)(prevsize + newsize) >= (long)nb)
+      {
+        unlink(prev, bck, fwd);
+        newp = prev;
+        newsize += prevsize;
+        newmem = chunk2mem(newp);
+        MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ);
+        goto split;
+      }
+    }
+
+    /* Must allocate */
+
+    newmem = mALLOc (bytes);
+
+    if (newmem == 0)  /* propagate failure */
+      return 0;
+
+    /* Avoid copy if newp is next chunk after oldp. */
+    /* (This can only happen when new chunk is sbrk'ed.) */
+
+    if ( (newp = mem2chunk(newmem)) == next_chunk(oldp))
+    {
+      newsize += chunksize(newp);
+      newp = oldp;
+      goto split;
+    }
+
+    /* Otherwise copy, free, and exit */
+    MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ);
+    fREe(oldmem);
+    return newmem;
+  }
+
+
+ split:  /* split off extra room in old or expanded chunk */
+
+  if (newsize - nb >= MINSIZE) /* split off remainder */
+  {
+    remainder = chunk_at_offset(newp, nb);
+    remainder_size = newsize - nb;
+    set_head_size(newp, nb);
+    set_head(remainder, remainder_size | PREV_INUSE);
+    set_inuse_bit_at_offset(remainder, remainder_size);
+    fREe(chunk2mem(remainder)); /* let free() deal with it */
+  }
+  else
+  {
+    set_head_size(newp, newsize);
+    set_inuse_bit_at_offset(newp, newsize);
+  }
+
+  check_inuse_chunk(newp);
+  return chunk2mem(newp);
+}
+
+
+\f
+
+/*
+
+  memalign algorithm:
+
+    memalign requests more than enough space from malloc, finds a spot
+    within that chunk that meets the alignment request, and then
+    possibly frees the leading and trailing space.
+
+    The alignment argument must be a power of two. This property is not
+    checked by memalign, so misuse may result in random runtime errors.
+
+    8-byte alignment is guaranteed by normal malloc calls, so don't
+    bother calling memalign with an argument of 8 or less.
+
+    Overreliance on memalign is a sure way to fragment space.
+
+*/
+
+
+#if __STD_C
+Void_t* mEMALIGn(size_t alignment, size_t bytes)
+#else
+Void_t* mEMALIGn(alignment, bytes) size_t alignment; size_t bytes;
+#endif
+{
+  INTERNAL_SIZE_T    nb;      /* padded  request size */
+  char*     m;                /* memory returned by malloc call */
+  mchunkptr p;                /* corresponding chunk */
+  char*     brk;              /* alignment point within p */
+  mchunkptr newp;             /* chunk to return */
+  INTERNAL_SIZE_T  newsize;   /* its size */
+  INTERNAL_SIZE_T  leadsize;  /* leading space befor alignment point */
+  mchunkptr remainder;        /* spare room at end to split off */
+  long      remainder_size;   /* its size */
+
+  if ((long)bytes < 0) return 0;
+
+  /* If need less alignment than we give anyway, just relay to malloc */
+
+  if (alignment <= MALLOC_ALIGNMENT) return mALLOc(bytes);
+
+  /* Otherwise, ensure that it is at least a minimum chunk size */
+
+  if (alignment <  MINSIZE) alignment = MINSIZE;
+
+  /* Call malloc with worst case padding to hit alignment. */
+
+  nb = request2size(bytes);
+  m  = (char*)(mALLOc(nb + alignment + MINSIZE));
+
+  if (m == 0) return 0; /* propagate failure */
+
+  p = mem2chunk(m);
+
+  if ((((unsigned long)(m)) % alignment) == 0) /* aligned */
+  {
+#if HAVE_MMAP
+    if(chunk_is_mmapped(p))
+      return chunk2mem(p); /* nothing more to do */
+#endif
+  }
+  else /* misaligned */
+  {
+    /*
+      Find an aligned spot inside chunk.
+      Since we need to give back leading space in a chunk of at
+      least MINSIZE, if the first calculation places us at
+      a spot with less than MINSIZE leader, we can move to the
+      next aligned spot -- we've allocated enough total room so that
+      this is always possible.
+    */
+
+    brk = (char*)mem2chunk(((unsigned long)(m + alignment - 1)) & -((signed) alignment));
+    if ((long)(brk - (char*)(p)) < MINSIZE) brk = brk + alignment;
+
+    newp = (mchunkptr)brk;
+    leadsize = brk - (char*)(p);
+    newsize = chunksize(p) - leadsize;
+
+#if HAVE_MMAP
+    if(chunk_is_mmapped(p))
+    {
+      newp->prev_size = p->prev_size + leadsize;
+      set_head(newp, newsize|IS_MMAPPED);
+      return chunk2mem(newp);
+    }
+#endif
+
+    /* give back leader, use the rest */
+
+    set_head(newp, newsize | PREV_INUSE);
+    set_inuse_bit_at_offset(newp, newsize);
+    set_head_size(p, leadsize);
+    fREe(chunk2mem(p));
+    p = newp;
+
+    assert (newsize >= nb && (((unsigned long)(chunk2mem(p))) % alignment) == 0);
+  }
+
+  /* Also give back spare room at the end */
+
+  remainder_size = chunksize(p) - nb;
+
+  if (remainder_size >= (long)MINSIZE)
+  {
+    remainder = chunk_at_offset(p, nb);
+    set_head(remainder, remainder_size | PREV_INUSE);
+    set_head_size(p, nb);
+    fREe(chunk2mem(remainder));
+  }
+
+  check_inuse_chunk(p);
+  return chunk2mem(p);
+
+}
+
+\f
+
+
+/*
+    valloc just invokes memalign with alignment argument equal
+    to the page size of the system (or as near to this as can
+    be figured out from all the includes/defines above.)
+*/
+
+#if __STD_C
+Void_t* vALLOc(size_t bytes)
+#else
+Void_t* vALLOc(bytes) size_t bytes;
+#endif
+{
+  return mEMALIGn (malloc_getpagesize, bytes);
+}
+
+/*
+  pvalloc just invokes valloc for the nearest pagesize
+  that will accommodate request
+*/
+
+
+#if __STD_C
+Void_t* pvALLOc(size_t bytes)
+#else
+Void_t* pvALLOc(bytes) size_t bytes;
+#endif
+{
+  size_t pagesize = malloc_getpagesize;
+  return mEMALIGn (pagesize, (bytes + pagesize - 1) & ~(pagesize - 1));
+}
+
+/*
+
+  calloc calls malloc, then zeroes out the allocated chunk.
+
+*/
+
+#if __STD_C
+Void_t* cALLOc(size_t n, size_t elem_size)
+#else
+Void_t* cALLOc(n, elem_size) size_t n; size_t elem_size;
+#endif
+{
+  mchunkptr p;
+  INTERNAL_SIZE_T csz;
+
+  INTERNAL_SIZE_T sz = n * elem_size;
+
+
+  /* check if expand_top called, in which case don't need to clear */
+#if MORECORE_CLEARS
+  mchunkptr oldtop = top;
+  INTERNAL_SIZE_T oldtopsize = chunksize(top);
+#endif
+  Void_t* mem = mALLOc (sz);
+
+  if ((long)n < 0) return 0;
+
+  if (mem == 0)
+    return 0;
+  else
+  {
+    p = mem2chunk(mem);
+
+    /* Two optional cases in which clearing not necessary */
+
+
+#if HAVE_MMAP
+    if (chunk_is_mmapped(p)) return mem;
+#endif
+
+    csz = chunksize(p);
+
+#if MORECORE_CLEARS
+    if (p == oldtop && csz > oldtopsize)
+    {
+      /* clear only the bytes from non-freshly-sbrked memory */
+      csz = oldtopsize;
+    }
+#endif
+
+    MALLOC_ZERO(mem, csz - SIZE_SZ);
+    return mem;
+  }
+}
+
+/*
+
+  cfree just calls free. It is needed/defined on some systems
+  that pair it with calloc, presumably for odd historical reasons.
+
+*/
+
+#if !defined(INTERNAL_LINUX_C_LIB) || !defined(__ELF__)
+#if __STD_C
+void cfree(Void_t *mem)
+#else
+void cfree(mem) Void_t *mem;
+#endif
+{
+  fREe(mem);
+}
+#endif
+
+\f
+
+/*
+
+    Malloc_trim gives memory back to the system (via negative
+    arguments to sbrk) if there is unused memory at the `high' end of
+    the malloc pool. You can call this after freeing large blocks of
+    memory to potentially reduce the system-level memory requirements
+    of a program. However, it cannot guarantee to reduce memory. Under
+    some allocation patterns, some large free blocks of memory will be
+    locked between two used chunks, so they cannot be given back to
+    the system.
+
+    The `pad' argument to malloc_trim represents the amount of free
+    trailing space to leave untrimmed. If this argument is zero,
+    only the minimum amount of memory to maintain internal data
+    structures will be left (one page or less). Non-zero arguments
+    can be supplied to maintain enough trailing space to service
+    future expected allocations without having to re-obtain memory
+    from the system.
+
+    Malloc_trim returns 1 if it actually released any memory, else 0.
+
+*/
+
+#if __STD_C
+int malloc_trim(size_t pad)
+#else
+int malloc_trim(pad) size_t pad;
+#endif
+{
+  long  top_size;        /* Amount of top-most memory */
+  long  extra;           /* Amount to release */
+  char* current_brk;     /* address returned by pre-check sbrk call */
+  char* new_brk;         /* address returned by negative sbrk call */
+
+  unsigned long pagesz = malloc_getpagesize;
+
+  top_size = chunksize(top);
+  extra = ((top_size - pad - MINSIZE + (pagesz-1)) / pagesz - 1) * pagesz;
+
+  if (extra < (long)pagesz)  /* Not enough memory to release */
+    return 0;
+
+  else
+  {
+    /* Test to make sure no one else called sbrk */
+    current_brk = (char*)(MORECORE (0));
+    if (current_brk != (char*)(top) + top_size)
+      return 0;     /* Apparently we don't own memory; must fail */
+
+    else
+    {
+      new_brk = (char*)(MORECORE (-extra));
+
+      if (new_brk == (char*)(MORECORE_FAILURE)) /* sbrk failed? */
+      {
+        /* Try to figure out what we have */
+        current_brk = (char*)(MORECORE (0));
+        top_size = current_brk - (char*)top;
+        if (top_size >= (long)MINSIZE) /* if not, we are very very dead! */
+        {
+          sbrked_mem = current_brk - sbrk_base;
+          set_head(top, top_size | PREV_INUSE);
+        }
+        check_chunk(top);
+        return 0;
+      }
+
+      else
+      {
+        /* Success. Adjust top accordingly. */
+        set_head(top, (top_size - extra) | PREV_INUSE);
+        sbrked_mem -= extra;
+        check_chunk(top);
+        return 1;
+      }
+    }
+  }
+}
+
+\f
+
+/*
+  malloc_usable_size:
+
+    This routine tells you how many bytes you can actually use in an
+    allocated chunk, which may be more than you requested (although
+    often not). You can use this many bytes without worrying about
+    overwriting other allocated objects. Not a particularly great
+    programming practice, but still sometimes useful.
+
+*/
+
+#if __STD_C
+size_t malloc_usable_size(Void_t* mem)
+#else
+size_t malloc_usable_size(mem) Void_t* mem;
+#endif
+{
+  mchunkptr p;
+  if (mem == 0)
+    return 0;
+  else
+  {
+    p = mem2chunk(mem);
+    if(!chunk_is_mmapped(p))
+    {
+      if (!inuse(p)) return 0;
+      check_inuse_chunk(p);
+      return chunksize(p) - SIZE_SZ;
+    }
+    return chunksize(p) - 2*SIZE_SZ;
+  }
+}
+
+
+\f
+
+/* Utility to update current_mallinfo for malloc_stats and mallinfo() */
+
+#if 0
+static void malloc_update_mallinfo()
+{
+  int i;
+  mbinptr b;
+  mchunkptr p;
+#if DEBUG
+  mchunkptr q;
+#endif
+
+  INTERNAL_SIZE_T avail = chunksize(top);
+  int   navail = ((long)(avail) >= (long)MINSIZE)? 1 : 0;
+
+  for (i = 1; i < NAV; ++i)
+  {
+    b = bin_at(i);
+    for (p = last(b); p != b; p = p->bk)
+    {
+#if DEBUG
+      check_free_chunk(p);
+      for (q = next_chunk(p);
+           q < top && inuse(q) && (long)(chunksize(q)) >= (long)MINSIZE;
+           q = next_chunk(q))
+        check_inuse_chunk(q);
+#endif
+      avail += chunksize(p);
+      navail++;
+    }
+  }
+
+  current_mallinfo.ordblks = navail;
+  current_mallinfo.uordblks = sbrked_mem - avail;
+  current_mallinfo.fordblks = avail;
+  current_mallinfo.hblks = n_mmaps;
+  current_mallinfo.hblkhd = mmapped_mem;
+  current_mallinfo.keepcost = chunksize(top);
+
+}
+#endif /* 0 */
+
+\f
+
+/*
+
+  malloc_stats:
+
+    Prints on the amount of space obtain from the system (both
+    via sbrk and mmap), the maximum amount (which may be more than
+    current if malloc_trim and/or munmap got called), the maximum
+    number of simultaneous mmap regions used, and the current number
+    of bytes allocated via malloc (or realloc, etc) but not yet
+    freed. (Note that this is the number of bytes allocated, not the
+    number requested. It will be larger than the number requested
+    because of alignment and bookkeeping overhead.)
+
+*/
+
+#if 0
+void malloc_stats()
+{
+  malloc_update_mallinfo();
+  printf("max system bytes = %10u\n",
+          (unsigned int)(max_total_mem));
+  printf("system bytes     = %10u\n",
+          (unsigned int)(sbrked_mem + mmapped_mem));
+  printf("in use bytes     = %10u\n",
+          (unsigned int)(current_mallinfo.uordblks + mmapped_mem));
+#if HAVE_MMAP
+  printf("max mmap regions = %10u\n",
+          (unsigned int)max_n_mmaps);
+#endif
+}
+#endif /* 0 */
+
+/*
+  mallinfo returns a copy of updated current mallinfo.
+*/
+
+#if 0
+struct mallinfo mALLINFo()
+{
+  malloc_update_mallinfo();
+  return current_mallinfo;
+}
+#endif /* 0 */
+
+
+\f
+
+/*
+  mallopt:
+
+    mallopt is the general SVID/XPG interface to tunable parameters.
+    The format is to provide a (parameter-number, parameter-value) pair.
+    mallopt then sets the corresponding parameter to the argument
+    value if it can (i.e., so long as the value is meaningful),
+    and returns 1 if successful else 0.
+
+    See descriptions of tunable parameters above.
+
+*/
+
+#if __STD_C
+int mALLOPt(int param_number, int value)
+#else
+int mALLOPt(param_number, value) int param_number; int value;
+#endif
+{
+  switch(param_number)
+  {
+    case M_TRIM_THRESHOLD:
+      trim_threshold = value; return 1;
+    case M_TOP_PAD:
+      top_pad = value; return 1;
+    case M_MMAP_THRESHOLD:
+      mmap_threshold = value; return 1;
+    case M_MMAP_MAX:
+#if HAVE_MMAP
+      n_mmaps_max = value; return 1;
+#else
+      if (value != 0) return 0; else  n_mmaps_max = value; return 1;
+#endif
+
+    default:
+      return 0;
+  }
+}
+
+/*
+
+History:
+
+    V2.6.6 Sun Dec  5 07:42:19 1999  Doug Lea  (dl at gee)
+      * return null for negative arguments
+      * Added Several WIN32 cleanups from Martin C. Fong <mcfong@yahoo.com>
+         * Add 'LACKS_SYS_PARAM_H' for those systems without 'sys/param.h'
+          (e.g. WIN32 platforms)
+         * Cleanup up header file inclusion for WIN32 platforms
+         * Cleanup code to avoid Microsoft Visual C++ compiler complaints
+         * Add 'USE_DL_PREFIX' to quickly allow co-existence with existing
+           memory allocation routines
+         * Set 'malloc_getpagesize' for WIN32 platforms (needs more work)
+         * Use 'assert' rather than 'ASSERT' in WIN32 code to conform to
+          usage of 'assert' in non-WIN32 code
+         * Improve WIN32 'sbrk()' emulation's 'findRegion()' routine to
+           avoid infinite loop
+      * Always call 'fREe()' rather than 'free()'
+
+    V2.6.5 Wed Jun 17 15:57:31 1998  Doug Lea  (dl at gee)
+      * Fixed ordering problem with boundary-stamping
+
+    V2.6.3 Sun May 19 08:17:58 1996  Doug Lea  (dl at gee)
+      * Added pvalloc, as recommended by H.J. Liu
+      * Added 64bit pointer support mainly from Wolfram Gloger
+      * Added anonymously donated WIN32 sbrk emulation
+      * Malloc, calloc, getpagesize: add optimizations from Raymond Nijssen
+      * malloc_extend_top: fix mask error that caused wastage after
+        foreign sbrks
+      * Add linux mremap support code from HJ Liu
+
+    V2.6.2 Tue Dec  5 06:52:55 1995  Doug Lea  (dl at gee)
+      * Integrated most documentation with the code.
+      * Add support for mmap, with help from
+        Wolfram Gloger (Gloger@lrz.uni-muenchen.de).
+      * Use last_remainder in more cases.
+      * Pack bins using idea from  colin@nyx10.cs.du.edu
+      * Use ordered bins instead of best-fit threshhold
+      * Eliminate block-local decls to simplify tracing and debugging.
+      * Support another case of realloc via move into top
+      * Fix error occuring when initial sbrk_base not word-aligned.
+      * Rely on page size for units instead of SBRK_UNIT to
+        avoid surprises about sbrk alignment conventions.
+      * Add mallinfo, mallopt. Thanks to Raymond Nijssen
+        (raymond@es.ele.tue.nl) for the suggestion.
+      * Add `pad' argument to malloc_trim and top_pad mallopt parameter.
+      * More precautions for cases where other routines call sbrk,
+        courtesy of Wolfram Gloger (Gloger@lrz.uni-muenchen.de).
+      * Added macros etc., allowing use in linux libc from
+        H.J. Lu (hjl@gnu.ai.mit.edu)
+      * Inverted this history list
+
+    V2.6.1 Sat Dec  2 14:10:57 1995  Doug Lea  (dl at gee)
+      * Re-tuned and fixed to behave more nicely with V2.6.0 changes.
+      * Removed all preallocation code since under current scheme
+        the work required to undo bad preallocations exceeds
+        the work saved in good cases for most test programs.
+      * No longer use return list or unconsolidated bins since
+        no scheme using them consistently outperforms those that don't
+        given above changes.
+      * Use best fit for very large chunks to prevent some worst-cases.
+      * Added some support for debugging
+
+    V2.6.0 Sat Nov  4 07:05:23 1995  Doug Lea  (dl at gee)
+      * Removed footers when chunks are in use. Thanks to
+        Paul Wilson (wilson@cs.texas.edu) for the suggestion.
+
+    V2.5.4 Wed Nov  1 07:54:51 1995  Doug Lea  (dl at gee)
+      * Added malloc_trim, with help from Wolfram Gloger
+        (wmglo@Dent.MED.Uni-Muenchen.DE).
+
+    V2.5.3 Tue Apr 26 10:16:01 1994  Doug Lea  (dl at g)
+
+    V2.5.2 Tue Apr  5 16:20:40 1994  Doug Lea  (dl at g)
+      * realloc: try to expand in both directions
+      * malloc: swap order of clean-bin strategy;
+      * realloc: only conditionally expand backwards
+      * Try not to scavenge used bins
+      * Use bin counts as a guide to preallocation
+      * Occasionally bin return list chunks in first scan
+      * Add a few optimizations from colin@nyx10.cs.du.edu
+
+    V2.5.1 Sat Aug 14 15:40:43 1993  Doug Lea  (dl at g)
+      * faster bin computation & slightly different binning
+      * merged all consolidations to one part of malloc proper
+         (eliminating old malloc_find_space & malloc_clean_bin)
+      * Scan 2 returns chunks (not just 1)
+      * Propagate failure in realloc if malloc returns 0
+      * Add stuff to allow compilation on non-ANSI compilers
+          from kpv@research.att.com
+
+    V2.5 Sat Aug  7 07:41:59 1993  Doug Lea  (dl at g.oswego.edu)
+      * removed potential for odd address access in prev_chunk
+      * removed dependency on getpagesize.h
+      * misc cosmetics and a bit more internal documentation
+      * anticosmetics: mangled names in macros to evade debugger strangeness
+      * tested on sparc, hp-700, dec-mips, rs6000
+          with gcc & native cc (hp, dec only) allowing
+          Detlefs & Zorn comparison study (in SIGPLAN Notices.)
+
+    Trial version Fri Aug 28 13:14:29 1992  Doug Lea  (dl at g.oswego.edu)
+      * Based loosely on libg++-1.2X malloc. (It retains some of the overall
+         structure of old version,  but most details differ.)
+
+*/
+
+
diff --git a/common/dlmalloc.src b/common/dlmalloc.src
new file mode 100644 (file)
index 0000000..12b85bb
--- /dev/null
@@ -0,0 +1,3276 @@
+/* ---------- To make a malloc.h, start cutting here ------------ */
+
+/*
+  A version of malloc/free/realloc written by Doug Lea and released to the
+  public domain.  Send questions/comments/complaints/performance data
+  to dl@cs.oswego.edu
+
+* VERSION 2.6.6  Sun Mar  5 19:10:03 2000  Doug Lea  (dl at gee)
+
+   Note: There may be an updated version of this malloc obtainable at
+           ftp://g.oswego.edu/pub/misc/malloc.c
+         Check before installing!
+
+* Why use this malloc?
+
+  This is not the fastest, most space-conserving, most portable, or
+  most tunable malloc ever written. However it is among the fastest
+  while also being among the most space-conserving, portable and tunable.
+  Consistent balance across these factors results in a good general-purpose
+  allocator. For a high-level description, see
+     http://g.oswego.edu/dl/html/malloc.html
+
+* Synopsis of public routines
+
+  (Much fuller descriptions are contained in the program documentation below.)
+
+  malloc(size_t n);
+     Return a pointer to a newly allocated chunk of at least n bytes, or null
+     if no space is available.
+  free(Void_t* p);
+     Release the chunk of memory pointed to by p, or no effect if p is null.
+  realloc(Void_t* p, size_t n);
+     Return a pointer to a chunk of size n that contains the same data
+     as does chunk p up to the minimum of (n, p's size) bytes, or null
+     if no space is available. The returned pointer may or may not be
+     the same as p. If p is null, equivalent to malloc.  Unless the
+     #define REALLOC_ZERO_BYTES_FREES below is set, realloc with a
+     size argument of zero (re)allocates a minimum-sized chunk.
+  memalign(size_t alignment, size_t n);
+     Return a pointer to a newly allocated chunk of n bytes, aligned
+     in accord with the alignment argument, which must be a power of
+     two.
+  valloc(size_t n);
+     Equivalent to memalign(pagesize, n), where pagesize is the page
+     size of the system (or as near to this as can be figured out from
+     all the includes/defines below.)
+  pvalloc(size_t n);
+     Equivalent to valloc(minimum-page-that-holds(n)), that is,
+     round up n to nearest pagesize.
+  calloc(size_t unit, size_t quantity);
+     Returns a pointer to quantity * unit bytes, with all locations
+     set to zero.
+  cfree(Void_t* p);
+     Equivalent to free(p).
+  malloc_trim(size_t pad);
+     Release all but pad bytes of freed top-most memory back
+     to the system. Return 1 if successful, else 0.
+  malloc_usable_size(Void_t* p);
+     Report the number usable allocated bytes associated with allocated
+     chunk p. This may or may not report more bytes than were requested,
+     due to alignment and minimum size constraints.
+  malloc_stats();
+     Prints brief summary statistics on stderr.
+  mallinfo()
+     Returns (by copy) a struct containing various summary statistics.
+  mallopt(int parameter_number, int parameter_value)
+     Changes one of the tunable parameters described below. Returns
+     1 if successful in changing the parameter, else 0.
+
+* Vital statistics:
+
+  Alignment:                            8-byte
+       8 byte alignment is currently hardwired into the design.  This
+       seems to suffice for all current machines and C compilers.
+
+  Assumed pointer representation:       4 or 8 bytes
+       Code for 8-byte pointers is untested by me but has worked
+       reliably by Wolfram Gloger, who contributed most of the
+       changes supporting this.
+
+  Assumed size_t  representation:       4 or 8 bytes
+       Note that size_t is allowed to be 4 bytes even if pointers are 8.
+
+  Minimum overhead per allocated chunk: 4 or 8 bytes
+       Each malloced chunk has a hidden overhead of 4 bytes holding size
+       and status information.
+
+  Minimum allocated size: 4-byte ptrs:  16 bytes    (including 4 overhead)
+                          8-byte ptrs:  24/32 bytes (including, 4/8 overhead)
+
+       When a chunk is freed, 12 (for 4byte ptrs) or 20 (for 8 byte
+       ptrs but 4 byte size) or 24 (for 8/8) additional bytes are
+       needed; 4 (8) for a trailing size field
+       and 8 (16) bytes for free list pointers. Thus, the minimum
+       allocatable size is 16/24/32 bytes.
+
+       Even a request for zero bytes (i.e., malloc(0)) returns a
+       pointer to something of the minimum allocatable size.
+
+  Maximum allocated size: 4-byte size_t: 2^31 -  8 bytes
+                          8-byte size_t: 2^63 - 16 bytes
+
+       It is assumed that (possibly signed) size_t bit values suffice to
+       represent chunk sizes. `Possibly signed' is due to the fact
+       that `size_t' may be defined on a system as either a signed or
+       an unsigned type. To be conservative, values that would appear
+       as negative numbers are avoided.
+       Requests for sizes with a negative sign bit when the request
+       size is treaded as a long will return null.
+
+  Maximum overhead wastage per allocated chunk: normally 15 bytes
+
+       Alignnment demands, plus the minimum allocatable size restriction
+       make the normal worst-case wastage 15 bytes (i.e., up to 15
+       more bytes will be allocated than were requested in malloc), with
+       two exceptions:
+         1. Because requests for zero bytes allocate non-zero space,
+            the worst case wastage for a request of zero bytes is 24 bytes.
+         2. For requests >= mmap_threshold that are serviced via
+            mmap(), the worst case wastage is 8 bytes plus the remainder
+            from a system page (the minimal mmap unit); typically 4096 bytes.
+
+* Limitations
+
+    Here are some features that are NOT currently supported
+
+    * No user-definable hooks for callbacks and the like.
+    * No automated mechanism for fully checking that all accesses
+      to malloced memory stay within their bounds.
+    * No support for compaction.
+
+* Synopsis of compile-time options:
+
+    People have reported using previous versions of this malloc on all
+    versions of Unix, sometimes by tweaking some of the defines
+    below. It has been tested most extensively on Solaris and
+    Linux. It is also reported to work on WIN32 platforms.
+    People have also reported adapting this malloc for use in
+    stand-alone embedded systems.
+
+    The implementation is in straight, hand-tuned ANSI C.  Among other
+    consequences, it uses a lot of macros.  Because of this, to be at
+    all usable, this code should be compiled using an optimizing compiler
+    (for example gcc -O2) that can simplify expressions and control
+    paths.
+
+  __STD_C                  (default: derived from C compiler defines)
+     Nonzero if using ANSI-standard C compiler, a C++ compiler, or
+     a C compiler sufficiently close to ANSI to get away with it.
+  DEBUG                    (default: NOT defined)
+     Define to enable debugging. Adds fairly extensive assertion-based
+     checking to help track down memory errors, but noticeably slows down
+     execution.
+  REALLOC_ZERO_BYTES_FREES (default: NOT defined)
+     Define this if you think that realloc(p, 0) should be equivalent
+     to free(p). Otherwise, since malloc returns a unique pointer for
+     malloc(0), so does realloc(p, 0).
+  HAVE_MEMCPY               (default: defined)
+     Define if you are not otherwise using ANSI STD C, but still
+     have memcpy and memset in your C library and want to use them.
+     Otherwise, simple internal versions are supplied.
+  USE_MEMCPY               (default: 1 if HAVE_MEMCPY is defined, 0 otherwise)
+     Define as 1 if you want the C library versions of memset and
+     memcpy called in realloc and calloc (otherwise macro versions are used).
+     At least on some platforms, the simple macro versions usually
+     outperform libc versions.
+  HAVE_MMAP                 (default: defined as 1)
+     Define to non-zero to optionally make malloc() use mmap() to
+     allocate very large blocks.
+  HAVE_MREMAP                 (default: defined as 0 unless Linux libc set)
+     Define to non-zero to optionally make realloc() use mremap() to
+     reallocate very large blocks.
+  malloc_getpagesize        (default: derived from system #includes)
+     Either a constant or routine call returning the system page size.
+  HAVE_USR_INCLUDE_MALLOC_H (default: NOT defined)
+     Optionally define if you are on a system with a /usr/include/malloc.h
+     that declares struct mallinfo. It is not at all necessary to
+     define this even if you do, but will ensure consistency.
+  INTERNAL_SIZE_T           (default: size_t)
+     Define to a 32-bit type (probably `unsigned int') if you are on a
+     64-bit machine, yet do not want or need to allow malloc requests of
+     greater than 2^31 to be handled. This saves space, especially for
+     very small chunks.
+  INTERNAL_LINUX_C_LIB      (default: NOT defined)
+     Defined only when compiled as part of Linux libc.
+     Also note that there is some odd internal name-mangling via defines
+     (for example, internally, `malloc' is named `mALLOc') needed
+     when compiling in this case. These look funny but don't otherwise
+     affect anything.
+  WIN32                     (default: undefined)
+     Define this on MS win (95, nt) platforms to compile in sbrk emulation.
+  LACKS_UNISTD_H            (default: undefined if not WIN32)
+     Define this if your system does not have a <unistd.h>.
+  LACKS_SYS_PARAM_H         (default: undefined if not WIN32)
+     Define this if your system does not have a <sys/param.h>.
+  MORECORE                  (default: sbrk)
+     The name of the routine to call to obtain more memory from the system.
+  MORECORE_FAILURE          (default: -1)
+     The value returned upon failure of MORECORE.
+  MORECORE_CLEARS           (default 1)
+     True (1) if the routine mapped to MORECORE zeroes out memory (which
+     holds for sbrk).
+  DEFAULT_TRIM_THRESHOLD
+  DEFAULT_TOP_PAD
+  DEFAULT_MMAP_THRESHOLD
+  DEFAULT_MMAP_MAX
+     Default values of tunable parameters (described in detail below)
+     controlling interaction with host system routines (sbrk, mmap, etc).
+     These values may also be changed dynamically via mallopt(). The
+     preset defaults are those that give best performance for typical
+     programs/systems.
+  USE_DL_PREFIX             (default: undefined)
+     Prefix all public routines with the string 'dl'.  Useful to
+     quickly avoid procedure declaration conflicts and linker symbol
+     conflicts with existing memory allocation routines.
+
+
+*/
+
+\f
+
+
+/* Preliminaries */
+
+#ifndef __STD_C
+#ifdef __STDC__
+#define __STD_C     1
+#else
+#if __cplusplus
+#define __STD_C     1
+#else
+#define __STD_C     0
+#endif /*__cplusplus*/
+#endif /*__STDC__*/
+#endif /*__STD_C*/
+
+#ifndef Void_t
+#if (__STD_C || defined(WIN32))
+#define Void_t      void
+#else
+#define Void_t      char
+#endif
+#endif /*Void_t*/
+
+#if __STD_C
+#include <stddef.h>   /* for size_t */
+#else
+#include <sys/types.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>    /* needed for malloc_stats */
+
+
+/*
+  Compile-time options
+*/
+
+
+/*
+    Debugging:
+
+    Because freed chunks may be overwritten with link fields, this
+    malloc will often die when freed memory is overwritten by user
+    programs.  This can be very effective (albeit in an annoying way)
+    in helping track down dangling pointers.
+
+    If you compile with -DDEBUG, a number of assertion checks are
+    enabled that will catch more memory errors. You probably won't be
+    able to make much sense of the actual assertion errors, but they
+    should help you locate incorrectly overwritten memory.  The
+    checking is fairly extensive, and will slow down execution
+    noticeably. Calling malloc_stats or mallinfo with DEBUG set will
+    attempt to check every non-mmapped allocated and free chunk in the
+    course of computing the summmaries. (By nature, mmapped regions
+    cannot be checked very much automatically.)
+
+    Setting DEBUG may also be helpful if you are trying to modify
+    this code. The assertions in the check routines spell out in more
+    detail the assumptions and invariants underlying the algorithms.
+
+*/
+
+#if DEBUG
+#include <assert.h>
+#else
+#define assert(x) ((void)0)
+#endif
+
+
+/*
+  INTERNAL_SIZE_T is the word-size used for internal bookkeeping
+  of chunk sizes. On a 64-bit machine, you can reduce malloc
+  overhead by defining INTERNAL_SIZE_T to be a 32 bit `unsigned int'
+  at the expense of not being able to handle requests greater than
+  2^31. This limitation is hardly ever a concern; you are encouraged
+  to set this. However, the default version is the same as size_t.
+*/
+
+#ifndef INTERNAL_SIZE_T
+#define INTERNAL_SIZE_T size_t
+#endif
+
+/*
+  REALLOC_ZERO_BYTES_FREES should be set if a call to
+  realloc with zero bytes should be the same as a call to free.
+  Some people think it should. Otherwise, since this malloc
+  returns a unique pointer for malloc(0), so does realloc(p, 0).
+*/
+
+
+/*   #define REALLOC_ZERO_BYTES_FREES */
+
+
+/*
+  WIN32 causes an emulation of sbrk to be compiled in
+  mmap-based options are not currently supported in WIN32.
+*/
+
+/* #define WIN32 */
+#ifdef WIN32
+#define MORECORE wsbrk
+#define HAVE_MMAP 0
+
+#define LACKS_UNISTD_H
+#define LACKS_SYS_PARAM_H
+
+/*
+  Include 'windows.h' to get the necessary declarations for the
+  Microsoft Visual C++ data structures and routines used in the 'sbrk'
+  emulation.
+
+  Define WIN32_LEAN_AND_MEAN so that only the essential Microsoft
+  Visual C++ header files are included.
+*/
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#endif
+
+
+/*
+  HAVE_MEMCPY should be defined if you are not otherwise using
+  ANSI STD C, but still have memcpy and memset in your C library
+  and want to use them in calloc and realloc. Otherwise simple
+  macro versions are defined here.
+
+  USE_MEMCPY should be defined as 1 if you actually want to
+  have memset and memcpy called. People report that the macro
+  versions are often enough faster than libc versions on many
+  systems that it is better to use them.
+
+*/
+
+#define HAVE_MEMCPY
+
+#ifndef USE_MEMCPY
+#ifdef HAVE_MEMCPY
+#define USE_MEMCPY 1
+#else
+#define USE_MEMCPY 0
+#endif
+#endif
+
+#if (__STD_C || defined(HAVE_MEMCPY))
+
+#if __STD_C
+void* memset(void*, int, size_t);
+void* memcpy(void*, const void*, size_t);
+#else
+#ifdef WIN32
+// On Win32 platforms, 'memset()' and 'memcpy()' are already declared in
+// 'windows.h'
+#else
+Void_t* memset();
+Void_t* memcpy();
+#endif
+#endif
+#endif
+
+#if USE_MEMCPY
+
+/* The following macros are only invoked with (2n+1)-multiples of
+   INTERNAL_SIZE_T units, with a positive integer n. This is exploited
+   for fast inline execution when n is small. */
+
+#define MALLOC_ZERO(charp, nbytes)                                            \
+do {                                                                          \
+  INTERNAL_SIZE_T mzsz = (nbytes);                                            \
+  if(mzsz <= 9*sizeof(mzsz)) {                                                \
+    INTERNAL_SIZE_T* mz = (INTERNAL_SIZE_T*) (charp);                         \
+    if(mzsz >= 5*sizeof(mzsz)) {     *mz++ = 0;                               \
+                                     *mz++ = 0;                               \
+      if(mzsz >= 7*sizeof(mzsz)) {   *mz++ = 0;                               \
+                                     *mz++ = 0;                               \
+        if(mzsz >= 9*sizeof(mzsz)) { *mz++ = 0;                               \
+                                     *mz++ = 0; }}}                           \
+                                     *mz++ = 0;                               \
+                                     *mz++ = 0;                               \
+                                     *mz   = 0;                               \
+  } else memset((charp), 0, mzsz);                                            \
+} while(0)
+
+#define MALLOC_COPY(dest,src,nbytes)                                          \
+do {                                                                          \
+  INTERNAL_SIZE_T mcsz = (nbytes);                                            \
+  if(mcsz <= 9*sizeof(mcsz)) {                                                \
+    INTERNAL_SIZE_T* mcsrc = (INTERNAL_SIZE_T*) (src);                        \
+    INTERNAL_SIZE_T* mcdst = (INTERNAL_SIZE_T*) (dest);                       \
+    if(mcsz >= 5*sizeof(mcsz)) {     *mcdst++ = *mcsrc++;                     \
+                                     *mcdst++ = *mcsrc++;                     \
+      if(mcsz >= 7*sizeof(mcsz)) {   *mcdst++ = *mcsrc++;                     \
+                                     *mcdst++ = *mcsrc++;                     \
+        if(mcsz >= 9*sizeof(mcsz)) { *mcdst++ = *mcsrc++;                     \
+                                     *mcdst++ = *mcsrc++; }}}                 \
+                                     *mcdst++ = *mcsrc++;                     \
+                                     *mcdst++ = *mcsrc++;                     \
+                                     *mcdst   = *mcsrc  ;                     \
+  } else memcpy(dest, src, mcsz);                                             \
+} while(0)
+
+#else /* !USE_MEMCPY */
+
+/* Use Duff's device for good zeroing/copying performance. */
+
+#define MALLOC_ZERO(charp, nbytes)                                            \
+do {                                                                          \
+  INTERNAL_SIZE_T* mzp = (INTERNAL_SIZE_T*)(charp);                           \
+  long mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T), mcn;                         \
+  if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; }             \
+  switch (mctmp) {                                                            \
+    case 0: for(;;) { *mzp++ = 0;                                             \
+    case 7:           *mzp++ = 0;                                             \
+    case 6:           *mzp++ = 0;                                             \
+    case 5:           *mzp++ = 0;                                             \
+    case 4:           *mzp++ = 0;                                             \
+    case 3:           *mzp++ = 0;                                             \
+    case 2:           *mzp++ = 0;                                             \
+    case 1:           *mzp++ = 0; if(mcn <= 0) break; mcn--; }                \
+  }                                                                           \
+} while(0)
+
+#define MALLOC_COPY(dest,src,nbytes)                                          \
+do {                                                                          \
+  INTERNAL_SIZE_T* mcsrc = (INTERNAL_SIZE_T*) src;                            \
+  INTERNAL_SIZE_T* mcdst = (INTERNAL_SIZE_T*) dest;                           \
+  long mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T), mcn;                         \
+  if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; }             \
+  switch (mctmp) {                                                            \
+    case 0: for(;;) { *mcdst++ = *mcsrc++;                                    \
+    case 7:           *mcdst++ = *mcsrc++;                                    \
+    case 6:           *mcdst++ = *mcsrc++;                                    \
+    case 5:           *mcdst++ = *mcsrc++;                                    \
+    case 4:           *mcdst++ = *mcsrc++;                                    \
+    case 3:           *mcdst++ = *mcsrc++;                                    \
+    case 2:           *mcdst++ = *mcsrc++;                                    \
+    case 1:           *mcdst++ = *mcsrc++; if(mcn <= 0) break; mcn--; }       \
+  }                                                                           \
+} while(0)
+
+#endif
+
+
+/*
+  Define HAVE_MMAP to optionally make malloc() use mmap() to
+  allocate very large blocks.  These will be returned to the
+  operating system immediately after a free().
+*/
+
+#ifndef HAVE_MMAP
+#define HAVE_MMAP 1
+#endif
+
+/*
+  Define HAVE_MREMAP to make realloc() use mremap() to re-allocate
+  large blocks.  This is currently only possible on Linux with
+  kernel versions newer than 1.3.77.
+*/
+
+#ifndef HAVE_MREMAP
+#ifdef INTERNAL_LINUX_C_LIB
+#define HAVE_MREMAP 1
+#else
+#define HAVE_MREMAP 0
+#endif
+#endif
+
+#if HAVE_MMAP
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
+#define MAP_ANONYMOUS MAP_ANON
+#endif
+
+#endif /* HAVE_MMAP */
+
+/*
+  Access to system page size. To the extent possible, this malloc
+  manages memory from the system in page-size units.
+
+  The following mechanics for getpagesize were adapted from
+  bsd/gnu getpagesize.h
+*/
+
+#ifndef LACKS_UNISTD_H
+#  include <unistd.h>
+#endif
+
+#ifndef malloc_getpagesize
+#  ifdef _SC_PAGESIZE         /* some SVR4 systems omit an underscore */
+#    ifndef _SC_PAGE_SIZE
+#      define _SC_PAGE_SIZE _SC_PAGESIZE
+#    endif
+#  endif
+#  ifdef _SC_PAGE_SIZE
+#    define malloc_getpagesize sysconf(_SC_PAGE_SIZE)
+#  else
+#    if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE)
+       extern size_t getpagesize();
+#      define malloc_getpagesize getpagesize()
+#    else
+#      ifdef WIN32
+#        define malloc_getpagesize (4096) /* TBD: Use 'GetSystemInfo' instead */
+#      else
+#        ifndef LACKS_SYS_PARAM_H
+#          include <sys/param.h>
+#        endif
+#        ifdef EXEC_PAGESIZE
+#          define malloc_getpagesize EXEC_PAGESIZE
+#        else
+#          ifdef NBPG
+#            ifndef CLSIZE
+#              define malloc_getpagesize NBPG
+#            else
+#              define malloc_getpagesize (NBPG * CLSIZE)
+#            endif
+#          else
+#            ifdef NBPC
+#              define malloc_getpagesize NBPC
+#            else
+#              ifdef PAGESIZE
+#                define malloc_getpagesize PAGESIZE
+#              else
+#                define malloc_getpagesize (4096) /* just guess */
+#              endif
+#            endif
+#          endif
+#        endif
+#      endif
+#    endif
+#  endif
+#endif
+
+
+
+/*
+
+  This version of malloc supports the standard SVID/XPG mallinfo
+  routine that returns a struct containing the same kind of
+  information you can get from malloc_stats. It should work on
+  any SVID/XPG compliant system that has a /usr/include/malloc.h
+  defining struct mallinfo. (If you'd like to install such a thing
+  yourself, cut out the preliminary declarations as described above
+  and below and save them in a malloc.h file. But there's no
+  compelling reason to bother to do this.)
+
+  The main declaration needed is the mallinfo struct that is returned
+  (by-copy) by mallinfo().  The SVID/XPG malloinfo struct contains a
+  bunch of fields, most of which are not even meaningful in this
+  version of malloc. Some of these fields are are instead filled by
+  mallinfo() with other numbers that might possibly be of interest.
+
+  HAVE_USR_INCLUDE_MALLOC_H should be set if you have a
+  /usr/include/malloc.h file that includes a declaration of struct
+  mallinfo.  If so, it is included; else an SVID2/XPG2 compliant
+  version is declared below.  These must be precisely the same for
+  mallinfo() to work.
+
+*/
+
+/* #define HAVE_USR_INCLUDE_MALLOC_H */
+
+#if HAVE_USR_INCLUDE_MALLOC_H
+#include "/usr/include/malloc.h"
+#else
+
+/* SVID2/XPG mallinfo structure */
+
+struct mallinfo {
+  int arena;    /* total space allocated from system */
+  int ordblks;  /* number of non-inuse chunks */
+  int smblks;   /* unused -- always zero */
+  int hblks;    /* number of mmapped regions */
+  int hblkhd;   /* total space in mmapped regions */
+  int usmblks;  /* unused -- always zero */
+  int fsmblks;  /* unused -- always zero */
+  int uordblks; /* total allocated space */
+  int fordblks; /* total non-inuse space */
+  int keepcost; /* top-most, releasable (via malloc_trim) space */
+};
+
+/* SVID2/XPG mallopt options */
+
+#define M_MXFAST  1    /* UNUSED in this malloc */
+#define M_NLBLKS  2    /* UNUSED in this malloc */
+#define M_GRAIN   3    /* UNUSED in this malloc */
+#define M_KEEP    4    /* UNUSED in this malloc */
+
+#endif
+
+/* mallopt options that actually do something */
+
+#define M_TRIM_THRESHOLD    -1
+#define M_TOP_PAD           -2
+#define M_MMAP_THRESHOLD    -3
+#define M_MMAP_MAX          -4
+
+
+
+#ifndef DEFAULT_TRIM_THRESHOLD
+#define DEFAULT_TRIM_THRESHOLD (128 * 1024)
+#endif
+
+/*
+    M_TRIM_THRESHOLD is the maximum amount of unused top-most memory
+      to keep before releasing via malloc_trim in free().
+
+      Automatic trimming is mainly useful in long-lived programs.
+      Because trimming via sbrk can be slow on some systems, and can
+      sometimes be wasteful (in cases where programs immediately
+      afterward allocate more large chunks) the value should be high
+      enough so that your overall system performance would improve by
+      releasing.
+
+      The trim threshold and the mmap control parameters (see below)
+      can be traded off with one another. Trimming and mmapping are
+      two different ways of releasing unused memory back to the
+      system. Between these two, it is often possible to keep
+      system-level demands of a long-lived program down to a bare
+      minimum. For example, in one test suite of sessions measuring
+      the XF86 X server on Linux, using a trim threshold of 128K and a
+      mmap threshold of 192K led to near-minimal long term resource
+      consumption.
+
+      If you are using this malloc in a long-lived program, it should
+      pay to experiment with these values.  As a rough guide, you
+      might set to a value close to the average size of a process
+      (program) running on your system.  Releasing this much memory
+      would allow such a process to run in memory.  Generally, it's
+      worth it to tune for trimming rather tham memory mapping when a
+      program undergoes phases where several large chunks are
+      allocated and released in ways that can reuse each other's
+      storage, perhaps mixed with phases where there are no such
+      chunks at all.  And in well-behaved long-lived programs,
+      controlling release of large blocks via trimming versus mapping
+      is usually faster.
+
+      However, in most programs, these parameters serve mainly as
+      protection against the system-level effects of carrying around
+      massive amounts of unneeded memory. Since frequent calls to
+      sbrk, mmap, and munmap otherwise degrade performance, the default
+      parameters are set to relatively high values that serve only as
+      safeguards.
+
+      The default trim value is high enough to cause trimming only in
+      fairly extreme (by current memory consumption standards) cases.
+      It must be greater than page size to have any useful effect.  To
+      disable trimming completely, you can set to (unsigned long)(-1);
+
+
+*/
+
+
+#ifndef DEFAULT_TOP_PAD
+#define DEFAULT_TOP_PAD        (0)
+#endif
+
+/*
+    M_TOP_PAD is the amount of extra `padding' space to allocate or
+      retain whenever sbrk is called. It is used in two ways internally:
+
+      * When sbrk is called to extend the top of the arena to satisfy
+        a new malloc request, this much padding is added to the sbrk
+        request.
+
+      * When malloc_trim is called automatically from free(),
+        it is used as the `pad' argument.
+
+      In both cases, the actual amount of padding is rounded
+      so that the end of the arena is always a system page boundary.
+
+      The main reason for using padding is to avoid calling sbrk so
+      often. Having even a small pad greatly reduces the likelihood
+      that nearly every malloc request during program start-up (or
+      after trimming) will invoke sbrk, which needlessly wastes
+      time.
+
+      Automatic rounding-up to page-size units is normally sufficient
+      to avoid measurable overhead, so the default is 0.  However, in
+      systems where sbrk is relatively slow, it can pay to increase
+      this value, at the expense of carrying around more memory than
+      the program needs.
+
+*/
+
+
+#ifndef DEFAULT_MMAP_THRESHOLD
+#define DEFAULT_MMAP_THRESHOLD (128 * 1024)
+#endif
+
+/*
+
+    M_MMAP_THRESHOLD is the request size threshold for using mmap()
+      to service a request. Requests of at least this size that cannot
+      be allocated using already-existing space will be serviced via mmap.
+      (If enough normal freed space already exists it is used instead.)
+
+      Using mmap segregates relatively large chunks of memory so that
+      they can be individually obtained and released from the host
+      system. A request serviced through mmap is never reused by any
+      other request (at least not directly; the system may just so
+      happen to remap successive requests to the same locations).
+
+      Segregating space in this way has the benefit that mmapped space
+      can ALWAYS be individually released back to the system, which
+      helps keep the system level memory demands of a long-lived
+      program low. Mapped memory can never become `locked' between
+      other chunks, as can happen with normally allocated chunks, which
+      menas that even trimming via malloc_trim would not release them.
+
+      However, it has the disadvantages that:
+
+         1. The space cannot be reclaimed, consolidated, and then
+            used to service later requests, as happens with normal chunks.
+         2. It can lead to more wastage because of mmap page alignment
+            requirements
+         3. It causes malloc performance to be more dependent on host
+            system memory management support routines which may vary in
+            implementation quality and may impose arbitrary
+            limitations. Generally, servicing a request via normal
+            malloc steps is faster than going through a system's mmap.
+
+      All together, these considerations should lead you to use mmap
+      only for relatively large requests.
+
+
+*/
+
+
+
+#ifndef DEFAULT_MMAP_MAX
+#if HAVE_MMAP
+#define DEFAULT_MMAP_MAX       (64)
+#else
+#define DEFAULT_MMAP_MAX       (0)
+#endif
+#endif
+
+/*
+    M_MMAP_MAX is the maximum number of requests to simultaneously
+      service using mmap. This parameter exists because:
+
+         1. Some systems have a limited number of internal tables for
+            use by mmap.
+         2. In most systems, overreliance on mmap can degrade overall
+            performance.
+         3. If a program allocates many large regions, it is probably
+            better off using normal sbrk-based allocation routines that
+            can reclaim and reallocate normal heap memory. Using a
+            small value allows transition into this mode after the
+            first few allocations.
+
+      Setting to 0 disables all use of mmap.  If HAVE_MMAP is not set,
+      the default value is 0, and attempts to set it to non-zero values
+      in mallopt will fail.
+*/
+
+
+
+
+/*
+    USE_DL_PREFIX will prefix all public routines with the string 'dl'.
+      Useful to quickly avoid procedure declaration conflicts and linker
+      symbol conflicts with existing memory allocation routines.
+
+*/
+
+/* #define USE_DL_PREFIX */
+
+
+
+
+/*
+
+  Special defines for linux libc
+
+  Except when compiled using these special defines for Linux libc
+  using weak aliases, this malloc is NOT designed to work in
+  multithreaded applications.  No semaphores or other concurrency
+  control are provided to ensure that multiple malloc or free calls
+  don't run at the same time, which could be disasterous. A single
+  semaphore could be used across malloc, realloc, and free (which is
+  essentially the effect of the linux weak alias approach). It would
+  be hard to obtain finer granularity.
+
+*/
+
+
+#ifdef INTERNAL_LINUX_C_LIB
+
+#if __STD_C
+
+Void_t * __default_morecore_init (ptrdiff_t);
+Void_t *(*__morecore)(ptrdiff_t) = __default_morecore_init;
+
+#else
+
+Void_t * __default_morecore_init ();
+Void_t *(*__morecore)() = __default_morecore_init;
+
+#endif
+
+#define MORECORE (*__morecore)
+#define MORECORE_FAILURE 0
+#define MORECORE_CLEARS 1
+
+#else /* INTERNAL_LINUX_C_LIB */
+
+#if __STD_C
+extern Void_t*     sbrk(ptrdiff_t);
+#else
+extern Void_t*     sbrk();
+#endif
+
+#ifndef MORECORE
+#define MORECORE sbrk
+#endif
+
+#ifndef MORECORE_FAILURE
+#define MORECORE_FAILURE -1
+#endif
+
+#ifndef MORECORE_CLEARS
+#define MORECORE_CLEARS 1
+#endif
+
+#endif /* INTERNAL_LINUX_C_LIB */
+
+#if defined(INTERNAL_LINUX_C_LIB) && defined(__ELF__)
+
+#define cALLOc         __libc_calloc
+#define fREe           __libc_free
+#define mALLOc         __libc_malloc
+#define mEMALIGn       __libc_memalign
+#define rEALLOc                __libc_realloc
+#define vALLOc         __libc_valloc
+#define pvALLOc                __libc_pvalloc
+#define mALLINFo       __libc_mallinfo
+#define mALLOPt                __libc_mallopt
+
+#pragma weak calloc = __libc_calloc
+#pragma weak free = __libc_free
+#pragma weak cfree = __libc_free
+#pragma weak malloc = __libc_malloc
+#pragma weak memalign = __libc_memalign
+#pragma weak realloc = __libc_realloc
+#pragma weak valloc = __libc_valloc
+#pragma weak pvalloc = __libc_pvalloc
+#pragma weak mallinfo = __libc_mallinfo
+#pragma weak mallopt = __libc_mallopt
+
+#else
+
+#ifdef USE_DL_PREFIX
+#define cALLOc         dlcalloc
+#define fREe           dlfree
+#define mALLOc         dlmalloc
+#define mEMALIGn       dlmemalign
+#define rEALLOc                dlrealloc
+#define vALLOc         dlvalloc
+#define pvALLOc                dlpvalloc
+#define mALLINFo       dlmallinfo
+#define mALLOPt                dlmallopt
+#else /* USE_DL_PREFIX */
+#define cALLOc         calloc
+#define fREe           free
+#define mALLOc         malloc
+#define mEMALIGn       memalign
+#define rEALLOc                realloc
+#define vALLOc         valloc
+#define pvALLOc                pvalloc
+#define mALLINFo       mallinfo
+#define mALLOPt                mallopt
+#endif /* USE_DL_PREFIX */
+
+#endif
+
+/* Public routines */
+
+#if __STD_C
+
+Void_t* mALLOc(size_t);
+void    fREe(Void_t*);
+Void_t* rEALLOc(Void_t*, size_t);
+Void_t* mEMALIGn(size_t, size_t);
+Void_t* vALLOc(size_t);
+Void_t* pvALLOc(size_t);
+Void_t* cALLOc(size_t, size_t);
+void    cfree(Void_t*);
+int     malloc_trim(size_t);
+size_t  malloc_usable_size(Void_t*);
+void    malloc_stats();
+int     mALLOPt(int, int);
+struct mallinfo mALLINFo(void);
+#else
+Void_t* mALLOc();
+void    fREe();
+Void_t* rEALLOc();
+Void_t* mEMALIGn();
+Void_t* vALLOc();
+Void_t* pvALLOc();
+Void_t* cALLOc();
+void    cfree();
+int     malloc_trim();
+size_t  malloc_usable_size();
+void    malloc_stats();
+int     mALLOPt();
+struct mallinfo mALLINFo();
+#endif
+
+
+#ifdef __cplusplus
+};  /* end of extern "C" */
+#endif
+
+/* ---------- To make a malloc.h, end cutting here ------------ */
+
+
+/*
+  Emulation of sbrk for WIN32
+  All code within the ifdef WIN32 is untested by me.
+
+  Thanks to Martin Fong and others for supplying this.
+*/
+
+
+#ifdef WIN32
+
+#define AlignPage(add) (((add) + (malloc_getpagesize-1)) & \
+~(malloc_getpagesize-1))
+#define AlignPage64K(add) (((add) + (0x10000 - 1)) & ~(0x10000 - 1))
+
+/* resrve 64MB to insure large contiguous space */
+#define RESERVED_SIZE (1024*1024*64)
+#define NEXT_SIZE (2048*1024)
+#define TOP_MEMORY ((unsigned long)2*1024*1024*1024)
+
+struct GmListElement;
+typedef struct GmListElement GmListElement;
+
+struct GmListElement
+{
+       GmListElement* next;
+       void* base;
+};
+
+static GmListElement* head = 0;
+static unsigned int gNextAddress = 0;
+static unsigned int gAddressBase = 0;
+static unsigned int gAllocatedSize = 0;
+
+static
+GmListElement* makeGmListElement (void* bas)
+{
+       GmListElement* this;
+       this = (GmListElement*)(void*)LocalAlloc (0, sizeof (GmListElement));
+       assert (this);
+       if (this)
+       {
+               this->base = bas;
+               this->next = head;
+               head = this;
+       }
+       return this;
+}
+
+void gcleanup ()
+{
+       BOOL rval;
+       assert ( (head == NULL) || (head->base == (void*)gAddressBase));
+       if (gAddressBase && (gNextAddress - gAddressBase))
+       {
+               rval = VirtualFree ((void*)gAddressBase,
+                                                       gNextAddress - gAddressBase,
+                                                       MEM_DECOMMIT);
+        assert (rval);
+       }
+       while (head)
+       {
+               GmListElement* next = head->next;
+               rval = VirtualFree (head->base, 0, MEM_RELEASE);
+               assert (rval);
+               LocalFree (head);
+               head = next;
+       }
+}
+
+static
+void* findRegion (void* start_address, unsigned long size)
+{
+       MEMORY_BASIC_INFORMATION info;
+       if (size >= TOP_MEMORY) return NULL;
+
+       while ((unsigned long)start_address + size < TOP_MEMORY)
+       {
+               VirtualQuery (start_address, &info, sizeof (info));
+               if ((info.State == MEM_FREE) && (info.RegionSize >= size))
+                       return start_address;
+               else
+               {
+                       // Requested region is not available so see if the
+                       // next region is available.  Set 'start_address'
+                       // to the next region and call 'VirtualQuery()'
+                       // again.
+
+                       start_address = (char*)info.BaseAddress + info.RegionSize;
+
+                       // Make sure we start looking for the next region
+                       // on the *next* 64K boundary.  Otherwise, even if
+                       // the new region is free according to
+                       // 'VirtualQuery()', the subsequent call to
+                       // 'VirtualAlloc()' (which follows the call to
+                       // this routine in 'wsbrk()') will round *down*
+                       // the requested address to a 64K boundary which
+                       // we already know is an address in the
+                       // unavailable region.  Thus, the subsequent call
+                       // to 'VirtualAlloc()' will fail and bring us back
+                       // here, causing us to go into an infinite loop.
+
+                       start_address =
+                               (void *) AlignPage64K((unsigned long) start_address);
+               }
+       }
+       return NULL;
+
+}
+
+
+void* wsbrk (long size)
+{
+       void* tmp;
+       if (size > 0)
+       {
+               if (gAddressBase == 0)
+               {
+                       gAllocatedSize = max (RESERVED_SIZE, AlignPage (size));
+                       gNextAddress = gAddressBase =
+                               (unsigned int)VirtualAlloc (NULL, gAllocatedSize,
+                                                                                       MEM_RESERVE, PAGE_NOACCESS);
+               } else if (AlignPage (gNextAddress + size) > (gAddressBase +
+gAllocatedSize))
+               {
+                       long new_size = max (NEXT_SIZE, AlignPage (size));
+                       void* new_address = (void*)(gAddressBase+gAllocatedSize);
+                       do
+                       {
+                               new_address = findRegion (new_address, new_size);
+
+                               if (new_address == 0)
+                                       return (void*)-1;
+
+                               gAddressBase = gNextAddress =
+                                       (unsigned int)VirtualAlloc (new_address, new_size,
+                                                                                               MEM_RESERVE, PAGE_NOACCESS);
+                               // repeat in case of race condition
+                               // The region that we found has been snagged
+                               // by another thread
+                       }
+                       while (gAddressBase == 0);
+
+                       assert (new_address == (void*)gAddressBase);
+
+                       gAllocatedSize = new_size;
+
+                       if (!makeGmListElement ((void*)gAddressBase))
+                               return (void*)-1;
+               }
+               if ((size + gNextAddress) > AlignPage (gNextAddress))
+               {
+                       void* res;
+                       res = VirtualAlloc ((void*)AlignPage (gNextAddress),
+                                                               (size + gNextAddress -
+                                                                AlignPage (gNextAddress)),
+                                                               MEM_COMMIT, PAGE_READWRITE);
+                       if (res == 0)
+                               return (void*)-1;
+               }
+               tmp = (void*)gNextAddress;
+               gNextAddress = (unsigned int)tmp + size;
+               return tmp;
+       }
+       else if (size < 0)
+       {
+               unsigned int alignedGoal = AlignPage (gNextAddress + size);
+               /* Trim by releasing the virtual memory */
+               if (alignedGoal >= gAddressBase)
+               {
+                       VirtualFree ((void*)alignedGoal, gNextAddress - alignedGoal,
+                                                MEM_DECOMMIT);
+                       gNextAddress = gNextAddress + size;
+                       return (void*)gNextAddress;
+               }
+               else
+               {
+                       VirtualFree ((void*)gAddressBase, gNextAddress - gAddressBase,
+                                                MEM_DECOMMIT);
+                       gNextAddress = gAddressBase;
+                       return (void*)-1;
+               }
+       }
+       else
+       {
+               return (void*)gNextAddress;
+       }
+}
+
+#endif
+
+\f
+
+/*
+  Type declarations
+*/
+
+
+struct malloc_chunk
+{
+  INTERNAL_SIZE_T prev_size; /* Size of previous chunk (if free). */
+  INTERNAL_SIZE_T size;      /* Size in bytes, including overhead. */
+  struct malloc_chunk* fd;   /* double links -- used only if free. */
+  struct malloc_chunk* bk;
+};
+
+typedef struct malloc_chunk* mchunkptr;
+
+/*
+
+   malloc_chunk details:
+
+    (The following includes lightly edited explanations by Colin Plumb.)
+
+    Chunks of memory are maintained using a `boundary tag' method as
+    described in e.g., Knuth or Standish.  (See the paper by Paul
+    Wilson ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a
+    survey of such techniques.)  Sizes of free chunks are stored both
+    in the front of each chunk and at the end.  This makes
+    consolidating fragmented chunks into bigger chunks very fast.  The
+    size fields also hold bits representing whether chunks are free or
+    in use.
+
+    An allocated chunk looks like this:
+
+
+    chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Size of previous chunk, if allocated            | |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Size of chunk, in bytes                         |P|
+      mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             User data starts here...                          .
+            .                                                               .
+            .             (malloc_usable_space() bytes)                     .
+            .                                                               |
+nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Size of chunk                                     |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+
+    Where "chunk" is the front of the chunk for the purpose of most of
+    the malloc code, but "mem" is the pointer that is returned to the
+    user.  "Nextchunk" is the beginning of the next contiguous chunk.
+
+    Chunks always begin on even word boundries, so the mem portion
+    (which is returned to the user) is also on an even word boundary, and
+    thus double-word aligned.
+
+    Free chunks are stored in circular doubly-linked lists, and look like this:
+
+    chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Size of previous chunk                            |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    `head:' |             Size of chunk, in bytes                         |P|
+      mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Forward pointer to next chunk in list             |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Back pointer to previous chunk in list            |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Unused space (may be 0 bytes long)                .
+            .                                                               .
+            .                                                               |
+nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    `foot:' |             Size of chunk, in bytes                           |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+    The P (PREV_INUSE) bit, stored in the unused low-order bit of the
+    chunk size (which is always a multiple of two words), is an in-use
+    bit for the *previous* chunk.  If that bit is *clear*, then the
+    word before the current chunk size contains the previous chunk
+    size, and can be used to find the front of the previous chunk.
+    (The very first chunk allocated always has this bit set,
+    preventing access to non-existent (or non-owned) memory.)
+
+    Note that the `foot' of the current chunk is actually represented
+    as the prev_size of the NEXT chunk. (This makes it easier to
+    deal with alignments etc).
+
+    The two exceptions to all this are
+
+     1. The special chunk `top', which doesn't bother using the
+        trailing size field since there is no
+        next contiguous chunk that would have to index off it. (After
+        initialization, `top' is forced to always exist.  If it would
+        become less than MINSIZE bytes long, it is replenished via
+        malloc_extend_top.)
+
+     2. Chunks allocated via mmap, which have the second-lowest-order
+        bit (IS_MMAPPED) set in their size fields.  Because they are
+        never merged or traversed from any other chunk, they have no
+        foot size or inuse information.
+
+    Available chunks are kept in any of several places (all declared below):
+
+    * `av': An array of chunks serving as bin headers for consolidated
+       chunks. Each bin is doubly linked.  The bins are approximately
+       proportionally (log) spaced.  There are a lot of these bins
+       (128). This may look excessive, but works very well in
+       practice.  All procedures maintain the invariant that no
+       consolidated chunk physically borders another one. Chunks in
+       bins are kept in size order, with ties going to the
+       approximately least recently used chunk.
+
+       The chunks in each bin are maintained in decreasing sorted order by
+       size.  This is irrelevant for the small bins, which all contain
+       the same-sized chunks, but facilitates best-fit allocation for
+       larger chunks. (These lists are just sequential. Keeping them in
+       order almost never requires enough traversal to warrant using
+       fancier ordered data structures.)  Chunks of the same size are
+       linked with the most recently freed at the front, and allocations
+       are taken from the back.  This results in LRU or FIFO allocation
+       order, which tends to give each chunk an equal opportunity to be
+       consolidated with adjacent freed chunks, resulting in larger free
+       chunks and less fragmentation.
+
+    * `top': The top-most available chunk (i.e., the one bordering the
+       end of available memory) is treated specially. It is never
+       included in any bin, is used only if no other chunk is
+       available, and is released back to the system if it is very
+       large (see M_TRIM_THRESHOLD).
+
+    * `last_remainder': A bin holding only the remainder of the
+       most recently split (non-top) chunk. This bin is checked
+       before other non-fitting chunks, so as to provide better
+       locality for runs of sequentially allocated chunks.
+
+    *  Implicitly, through the host system's memory mapping tables.
+       If supported, requests greater than a threshold are usually
+       serviced via calls to mmap, and then later released via munmap.
+
+*/
+
+
+
+\f
+
+
+/*  sizes, alignments */
+
+#define SIZE_SZ                (sizeof(INTERNAL_SIZE_T))
+#define MALLOC_ALIGNMENT       (SIZE_SZ + SIZE_SZ)
+#define MALLOC_ALIGN_MASK      (MALLOC_ALIGNMENT - 1)
+#define MINSIZE                (sizeof(struct malloc_chunk))
+
+/* conversion from malloc headers to user pointers, and back */
+
+#define chunk2mem(p)   ((Void_t*)((char*)(p) + 2*SIZE_SZ))
+#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - 2*SIZE_SZ))
+
+/* pad request bytes into a usable size */
+
+#define request2size(req) \
+ (((long)((req) + (SIZE_SZ + MALLOC_ALIGN_MASK)) < \
+  (long)(MINSIZE + MALLOC_ALIGN_MASK)) ? MINSIZE : \
+   (((req) + (SIZE_SZ + MALLOC_ALIGN_MASK)) & ~(MALLOC_ALIGN_MASK)))
+
+/* Check if m has acceptable alignment */
+
+#define aligned_OK(m)    (((unsigned long)((m)) & (MALLOC_ALIGN_MASK)) == 0)
+
+
+\f
+
+/*
+  Physical chunk operations
+*/
+
+
+/* size field is or'ed with PREV_INUSE when previous adjacent chunk in use */
+
+#define PREV_INUSE 0x1
+
+/* size field is or'ed with IS_MMAPPED if the chunk was obtained with mmap() */
+
+#define IS_MMAPPED 0x2
+
+/* Bits to mask off when extracting size */
+
+#define SIZE_BITS (PREV_INUSE|IS_MMAPPED)
+
+
+/* Ptr to next physical malloc_chunk. */
+
+#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->size & ~PREV_INUSE) ))
+
+/* Ptr to previous physical malloc_chunk */
+
+#define prev_chunk(p)\
+   ((mchunkptr)( ((char*)(p)) - ((p)->prev_size) ))
+
+
+/* Treat space at ptr + offset as a chunk */
+
+#define chunk_at_offset(p, s)  ((mchunkptr)(((char*)(p)) + (s)))
+
+
+\f
+
+/*
+  Dealing with use bits
+*/
+
+/* extract p's inuse bit */
+
+#define inuse(p)\
+((((mchunkptr)(((char*)(p))+((p)->size & ~PREV_INUSE)))->size) & PREV_INUSE)
+
+/* extract inuse bit of previous chunk */
+
+#define prev_inuse(p)  ((p)->size & PREV_INUSE)
+
+/* check for mmap()'ed chunk */
+
+#define chunk_is_mmapped(p) ((p)->size & IS_MMAPPED)
+
+/* set/clear chunk as in use without otherwise disturbing */
+
+#define set_inuse(p)\
+((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size |= PREV_INUSE
+
+#define clear_inuse(p)\
+((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size &= ~(PREV_INUSE)
+
+/* check/set/clear inuse bits in known places */
+
+#define inuse_bit_at_offset(p, s)\
+ (((mchunkptr)(((char*)(p)) + (s)))->size & PREV_INUSE)
+
+#define set_inuse_bit_at_offset(p, s)\
+ (((mchunkptr)(((char*)(p)) + (s)))->size |= PREV_INUSE)
+
+#define clear_inuse_bit_at_offset(p, s)\
+ (((mchunkptr)(((char*)(p)) + (s)))->size &= ~(PREV_INUSE))
+
+
+\f
+
+/*
+  Dealing with size fields
+*/
+
+/* Get size, ignoring use bits */
+
+#define chunksize(p)          ((p)->size & ~(SIZE_BITS))
+
+/* Set size at head, without disturbing its use bit */
+
+#define set_head_size(p, s)   ((p)->size = (((p)->size & PREV_INUSE) | (s)))
+
+/* Set size/use ignoring previous bits in header */
+
+#define set_head(p, s)        ((p)->size = (s))
+
+/* Set size at footer (only when chunk is not in use) */
+
+#define set_foot(p, s)   (((mchunkptr)((char*)(p) + (s)))->prev_size = (s))
+
+
+\f
+
+
+/*
+   Bins
+
+    The bins, `av_' are an array of pairs of pointers serving as the
+    heads of (initially empty) doubly-linked lists of chunks, laid out
+    in a way so that each pair can be treated as if it were in a
+    malloc_chunk. (This way, the fd/bk offsets for linking bin heads
+    and chunks are the same).
+
+    Bins for sizes < 512 bytes contain chunks of all the same size, spaced
+    8 bytes apart. Larger bins are approximately logarithmically
+    spaced. (See the table below.) The `av_' array is never mentioned
+    directly in the code, but instead via bin access macros.
+
+    Bin layout:
+
+    64 bins of size       8
+    32 bins of size      64
+    16 bins of size     512
+     8 bins of size    4096
+     4 bins of size   32768
+     2 bins of size  262144
+     1 bin  of size what's left
+
+    There is actually a little bit of slop in the numbers in bin_index
+    for the sake of speed. This makes no difference elsewhere.
+
+    The special chunks `top' and `last_remainder' get their own bins,
+    (this is implemented via yet more trickery with the av_ array),
+    although `top' is never properly linked to its bin since it is
+    always handled specially.
+
+*/
+
+#define NAV             128   /* number of bins */
+
+typedef struct malloc_chunk* mbinptr;
+
+/* access macros */
+
+#define bin_at(i)      ((mbinptr)((char*)&(av_[2*(i) + 2]) - 2*SIZE_SZ))
+#define next_bin(b)    ((mbinptr)((char*)(b) + 2 * sizeof(mbinptr)))
+#define prev_bin(b)    ((mbinptr)((char*)(b) - 2 * sizeof(mbinptr)))
+
+/*
+   The first 2 bins are never indexed. The corresponding av_ cells are instead
+   used for bookkeeping. This is not to save space, but to simplify
+   indexing, maintain locality, and avoid some initialization tests.
+*/
+
+#define top            (bin_at(0)->fd)   /* The topmost chunk */
+#define last_remainder (bin_at(1))       /* remainder from last split */
+
+
+/*
+   Because top initially points to its own bin with initial
+   zero size, thus forcing extension on the first malloc request,
+   we avoid having any special code in malloc to check whether
+   it even exists yet. But we still need to in malloc_extend_top.
+*/
+
+#define initial_top    ((mchunkptr)(bin_at(0)))
+
+/* Helper macro to initialize bins */
+
+#define IAV(i)  bin_at(i), bin_at(i)
+
+static mbinptr av_[NAV * 2 + 2] = {
+ 0, 0,
+ IAV(0),   IAV(1),   IAV(2),   IAV(3),   IAV(4),   IAV(5),   IAV(6),   IAV(7),
+ IAV(8),   IAV(9),   IAV(10),  IAV(11),  IAV(12),  IAV(13),  IAV(14),  IAV(15),
+ IAV(16),  IAV(17),  IAV(18),  IAV(19),  IAV(20),  IAV(21),  IAV(22),  IAV(23),
+ IAV(24),  IAV(25),  IAV(26),  IAV(27),  IAV(28),  IAV(29),  IAV(30),  IAV(31),
+ IAV(32),  IAV(33),  IAV(34),  IAV(35),  IAV(36),  IAV(37),  IAV(38),  IAV(39),
+ IAV(40),  IAV(41),  IAV(42),  IAV(43),  IAV(44),  IAV(45),  IAV(46),  IAV(47),
+ IAV(48),  IAV(49),  IAV(50),  IAV(51),  IAV(52),  IAV(53),  IAV(54),  IAV(55),
+ IAV(56),  IAV(57),  IAV(58),  IAV(59),  IAV(60),  IAV(61),  IAV(62),  IAV(63),
+ IAV(64),  IAV(65),  IAV(66),  IAV(67),  IAV(68),  IAV(69),  IAV(70),  IAV(71),
+ IAV(72),  IAV(73),  IAV(74),  IAV(75),  IAV(76),  IAV(77),  IAV(78),  IAV(79),
+ IAV(80),  IAV(81),  IAV(82),  IAV(83),  IAV(84),  IAV(85),  IAV(86),  IAV(87),
+ IAV(88),  IAV(89),  IAV(90),  IAV(91),  IAV(92),  IAV(93),  IAV(94),  IAV(95),
+ IAV(96),  IAV(97),  IAV(98),  IAV(99),  IAV(100), IAV(101), IAV(102), IAV(103),
+ IAV(104), IAV(105), IAV(106), IAV(107), IAV(108), IAV(109), IAV(110), IAV(111),
+ IAV(112), IAV(113), IAV(114), IAV(115), IAV(116), IAV(117), IAV(118), IAV(119),
+ IAV(120), IAV(121), IAV(122), IAV(123), IAV(124), IAV(125), IAV(126), IAV(127)
+};
+
+\f
+
+/* field-extraction macros */
+
+#define first(b) ((b)->fd)
+#define last(b)  ((b)->bk)
+
+/*
+  Indexing into bins
+*/
+
+#define bin_index(sz)                                                          \
+(((((unsigned long)(sz)) >> 9) ==    0) ?       (((unsigned long)(sz)) >>  3): \
+ ((((unsigned long)(sz)) >> 9) <=    4) ?  56 + (((unsigned long)(sz)) >>  6): \
+ ((((unsigned long)(sz)) >> 9) <=   20) ?  91 + (((unsigned long)(sz)) >>  9): \
+ ((((unsigned long)(sz)) >> 9) <=   84) ? 110 + (((unsigned long)(sz)) >> 12): \
+ ((((unsigned long)(sz)) >> 9) <=  340) ? 119 + (((unsigned long)(sz)) >> 15): \
+ ((((unsigned long)(sz)) >> 9) <= 1364) ? 124 + (((unsigned long)(sz)) >> 18): \
+                                          126)
+/*
+  bins for chunks < 512 are all spaced 8 bytes apart, and hold
+  identically sized chunks. This is exploited in malloc.
+*/
+
+#define MAX_SMALLBIN         63
+#define MAX_SMALLBIN_SIZE   512
+#define SMALLBIN_WIDTH        8
+
+#define smallbin_index(sz)  (((unsigned long)(sz)) >> 3)
+
+/*
+   Requests are `small' if both the corresponding and the next bin are small
+*/
+
+#define is_small_request(nb) (nb < MAX_SMALLBIN_SIZE - SMALLBIN_WIDTH)
+
+\f
+
+/*
+    To help compensate for the large number of bins, a one-level index
+    structure is used for bin-by-bin searching.  `binblocks' is a
+    one-word bitvector recording whether groups of BINBLOCKWIDTH bins
+    have any (possibly) non-empty bins, so they can be skipped over
+    all at once during during traversals. The bits are NOT always
+    cleared as soon as all bins in a block are empty, but instead only
+    when all are noticed to be empty during traversal in malloc.
+*/
+
+#define BINBLOCKWIDTH     4   /* bins per block */
+
+#define binblocks      (bin_at(0)->size) /* bitvector of nonempty blocks */
+
+/* bin<->block macros */
+
+#define idx2binblock(ix)    ((unsigned)1 << (ix / BINBLOCKWIDTH))
+#define mark_binblock(ii)   (binblocks |= idx2binblock(ii))
+#define clear_binblock(ii)  (binblocks &= ~(idx2binblock(ii)))
+
+
+\f
+
+
+/*  Other static bookkeeping data */
+
+/* variables holding tunable values */
+
+static unsigned long trim_threshold   = DEFAULT_TRIM_THRESHOLD;
+static unsigned long top_pad          = DEFAULT_TOP_PAD;
+static unsigned int  n_mmaps_max      = DEFAULT_MMAP_MAX;
+static unsigned long mmap_threshold   = DEFAULT_MMAP_THRESHOLD;
+
+/* The first value returned from sbrk */
+static char* sbrk_base = (char*)(-1);
+
+/* The maximum memory obtained from system via sbrk */
+static unsigned long max_sbrked_mem = 0;
+
+/* The maximum via either sbrk or mmap */
+static unsigned long max_total_mem = 0;
+
+/* internal working copy of mallinfo */
+static struct mallinfo current_mallinfo = {  0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+/* The total memory obtained from system via sbrk */
+#define sbrked_mem  (current_mallinfo.arena)
+
+/* Tracking mmaps */
+
+static unsigned int n_mmaps = 0;
+static unsigned int max_n_mmaps = 0;
+static unsigned long mmapped_mem = 0;
+static unsigned long max_mmapped_mem = 0;
+
+\f
+
+/*
+  Debugging support
+*/
+
+#if DEBUG
+
+
+/*
+  These routines make a number of assertions about the states
+  of data structures that should be true at all times. If any
+  are not true, it's very likely that a user program has somehow
+  trashed memory. (It's also possible that there is a coding error
+  in malloc. In which case, please report it!)
+*/
+
+#if __STD_C
+static void do_check_chunk(mchunkptr p)
+#else
+static void do_check_chunk(p) mchunkptr p;
+#endif
+{
+  INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE;
+
+  /* No checkable chunk is mmapped */
+  assert(!chunk_is_mmapped(p));
+
+  /* Check for legal address ... */
+  assert((char*)p >= sbrk_base);
+  if (p != top)
+    assert((char*)p + sz <= (char*)top);
+  else
+    assert((char*)p + sz <= sbrk_base + sbrked_mem);
+
+}
+
+
+#if __STD_C
+static void do_check_free_chunk(mchunkptr p)
+#else
+static void do_check_free_chunk(p) mchunkptr p;
+#endif
+{
+  INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE;
+  mchunkptr next = chunk_at_offset(p, sz);
+
+  do_check_chunk(p);
+
+  /* Check whether it claims to be free ... */
+  assert(!inuse(p));
+
+  /* Unless a special marker, must have OK fields */
+  if ((long)sz >= (long)MINSIZE)
+  {
+    assert((sz & MALLOC_ALIGN_MASK) == 0);
+    assert(aligned_OK(chunk2mem(p)));
+    /* ... matching footer field */
+    assert(next->prev_size == sz);
+    /* ... and is fully consolidated */
+    assert(prev_inuse(p));
+    assert (next == top || inuse(next));
+
+    /* ... and has minimally sane links */
+    assert(p->fd->bk == p);
+    assert(p->bk->fd == p);
+  }
+  else /* markers are always of size SIZE_SZ */
+    assert(sz == SIZE_SZ);
+}
+
+#if __STD_C
+static void do_check_inuse_chunk(mchunkptr p)
+#else
+static void do_check_inuse_chunk(p) mchunkptr p;
+#endif
+{
+  mchunkptr next = next_chunk(p);
+  do_check_chunk(p);
+
+  /* Check whether it claims to be in use ... */
+  assert(inuse(p));
+
+  /* ... and is surrounded by OK chunks.
+    Since more things can be checked with free chunks than inuse ones,
+    if an inuse chunk borders them and debug is on, it's worth doing them.
+  */
+  if (!prev_inuse(p))
+  {
+    mchunkptr prv = prev_chunk(p);
+    assert(next_chunk(prv) == p);
+    do_check_free_chunk(prv);
+  }
+  if (next == top)
+  {
+    assert(prev_inuse(next));
+    assert(chunksize(next) >= MINSIZE);
+  }
+  else if (!inuse(next))
+    do_check_free_chunk(next);
+
+}
+
+#if __STD_C
+static void do_check_malloced_chunk(mchunkptr p, INTERNAL_SIZE_T s)
+#else
+static void do_check_malloced_chunk(p, s) mchunkptr p; INTERNAL_SIZE_T s;
+#endif
+{
+  INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE;
+  long room = sz - s;
+
+  do_check_inuse_chunk(p);
+
+  /* Legal size ... */
+  assert((long)sz >= (long)MINSIZE);
+  assert((sz & MALLOC_ALIGN_MASK) == 0);
+  assert(room >= 0);
+  assert(room < (long)MINSIZE);
+
+  /* ... and alignment */
+  assert(aligned_OK(chunk2mem(p)));
+
+
+  /* ... and was allocated at front of an available chunk */
+  assert(prev_inuse(p));
+
+}
+
+
+#define check_free_chunk(P)  do_check_free_chunk(P)
+#define check_inuse_chunk(P) do_check_inuse_chunk(P)
+#define check_chunk(P) do_check_chunk(P)
+#define check_malloced_chunk(P,N) do_check_malloced_chunk(P,N)
+#else
+#define check_free_chunk(P)
+#define check_inuse_chunk(P)
+#define check_chunk(P)
+#define check_malloced_chunk(P,N)
+#endif
+
+\f
+
+/*
+  Macro-based internal utilities
+*/
+
+
+/*
+  Linking chunks in bin lists.
+  Call these only with variables, not arbitrary expressions, as arguments.
+*/
+
+/*
+  Place chunk p of size s in its bin, in size order,
+  putting it ahead of others of same size.
+*/
+
+
+#define frontlink(P, S, IDX, BK, FD)                                          \
+{                                                                             \
+  if (S < MAX_SMALLBIN_SIZE)                                                  \
+  {                                                                           \
+    IDX = smallbin_index(S);                                                  \
+    mark_binblock(IDX);                                                       \
+    BK = bin_at(IDX);                                                         \
+    FD = BK->fd;                                                              \
+    P->bk = BK;                                                               \
+    P->fd = FD;                                                               \
+    FD->bk = BK->fd = P;                                                      \
+  }                                                                           \
+  else                                                                        \
+  {                                                                           \
+    IDX = bin_index(S);                                                       \
+    BK = bin_at(IDX);                                                         \
+    FD = BK->fd;                                                              \
+    if (FD == BK) mark_binblock(IDX);                                         \
+    else                                                                      \
+    {                                                                         \
+      while (FD != BK && S < chunksize(FD)) FD = FD->fd;                      \
+      BK = FD->bk;                                                            \
+    }                                                                         \
+    P->bk = BK;                                                               \
+    P->fd = FD;                                                               \
+    FD->bk = BK->fd = P;                                                      \
+  }                                                                           \
+}
+
+
+/* take a chunk off a list */
+
+#define unlink(P, BK, FD)                                                     \
+{                                                                             \
+  BK = P->bk;                                                                 \
+  FD = P->fd;                                                                 \
+  FD->bk = BK;                                                                \
+  BK->fd = FD;                                                                \
+}                                                                             \
+
+/* Place p as the last remainder */
+
+#define link_last_remainder(P)                                                \
+{                                                                             \
+  last_remainder->fd = last_remainder->bk =  P;                               \
+  P->fd = P->bk = last_remainder;                                             \
+}
+
+/* Clear the last_remainder bin */
+
+#define clear_last_remainder \
+  (last_remainder->fd = last_remainder->bk = last_remainder)
+
+
+
+\f
+
+
+/* Routines dealing with mmap(). */
+
+#if HAVE_MMAP
+
+#if __STD_C
+static mchunkptr mmap_chunk(size_t size)
+#else
+static mchunkptr mmap_chunk(size) size_t size;
+#endif
+{
+  size_t page_mask = malloc_getpagesize - 1;
+  mchunkptr p;
+
+#ifndef MAP_ANONYMOUS
+  static int fd = -1;
+#endif
+
+  if(n_mmaps >= n_mmaps_max) return 0; /* too many regions */
+
+  /* For mmapped chunks, the overhead is one SIZE_SZ unit larger, because
+   * there is no following chunk whose prev_size field could be used.
+   */
+  size = (size + SIZE_SZ + page_mask) & ~page_mask;
+
+#ifdef MAP_ANONYMOUS
+  p = (mchunkptr)mmap(0, size, PROT_READ|PROT_WRITE,
+                     MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
+#else /* !MAP_ANONYMOUS */
+  if (fd < 0)
+  {
+    fd = open("/dev/zero", O_RDWR);
+    if(fd < 0) return 0;
+  }
+  p = (mchunkptr)mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
+#endif
+
+  if(p == (mchunkptr)-1) return 0;
+
+  n_mmaps++;
+  if (n_mmaps > max_n_mmaps) max_n_mmaps = n_mmaps;
+
+  /* We demand that eight bytes into a page must be 8-byte aligned. */
+  assert(aligned_OK(chunk2mem(p)));
+
+  /* The offset to the start of the mmapped region is stored
+   * in the prev_size field of the chunk; normally it is zero,
+   * but that can be changed in memalign().
+   */
+  p->prev_size = 0;
+  set_head(p, size|IS_MMAPPED);
+
+  mmapped_mem += size;
+  if ((unsigned long)mmapped_mem > (unsigned long)max_mmapped_mem)
+    max_mmapped_mem = mmapped_mem;
+  if ((unsigned long)(mmapped_mem + sbrked_mem) > (unsigned long)max_total_mem)
+    max_total_mem = mmapped_mem + sbrked_mem;
+  return p;
+}
+
+#if __STD_C
+static void munmap_chunk(mchunkptr p)
+#else
+static void munmap_chunk(p) mchunkptr p;
+#endif
+{
+  INTERNAL_SIZE_T size = chunksize(p);
+  int ret;
+
+  assert (chunk_is_mmapped(p));
+  assert(! ((char*)p >= sbrk_base && (char*)p < sbrk_base + sbrked_mem));
+  assert((n_mmaps > 0));
+  assert(((p->prev_size + size) & (malloc_getpagesize-1)) == 0);
+
+  n_mmaps--;
+  mmapped_mem -= (size + p->prev_size);
+
+  ret = munmap((char *)p - p->prev_size, size + p->prev_size);
+
+  /* munmap returns non-zero on failure */
+  assert(ret == 0);
+}
+
+#if HAVE_MREMAP
+
+#if __STD_C
+static mchunkptr mremap_chunk(mchunkptr p, size_t new_size)
+#else
+static mchunkptr mremap_chunk(p, new_size) mchunkptr p; size_t new_size;
+#endif
+{
+  size_t page_mask = malloc_getpagesize - 1;
+  INTERNAL_SIZE_T offset = p->prev_size;
+  INTERNAL_SIZE_T size = chunksize(p);
+  char *cp;
+
+  assert (chunk_is_mmapped(p));
+  assert(! ((char*)p >= sbrk_base && (char*)p < sbrk_base + sbrked_mem));
+  assert((n_mmaps > 0));
+  assert(((size + offset) & (malloc_getpagesize-1)) == 0);
+
+  /* Note the extra SIZE_SZ overhead as in mmap_chunk(). */
+  new_size = (new_size + offset + SIZE_SZ + page_mask) & ~page_mask;
+
+  cp = (char *)mremap((char *)p - offset, size + offset, new_size, 1);
+
+  if (cp == (char *)-1) return 0;
+
+  p = (mchunkptr)(cp + offset);
+
+  assert(aligned_OK(chunk2mem(p)));
+
+  assert((p->prev_size == offset));
+  set_head(p, (new_size - offset)|IS_MMAPPED);
+
+  mmapped_mem -= size + offset;
+  mmapped_mem += new_size;
+  if ((unsigned long)mmapped_mem > (unsigned long)max_mmapped_mem)
+    max_mmapped_mem = mmapped_mem;
+  if ((unsigned long)(mmapped_mem + sbrked_mem) > (unsigned long)max_total_mem)
+    max_total_mem = mmapped_mem + sbrked_mem;
+  return p;
+}
+
+#endif /* HAVE_MREMAP */
+
+#endif /* HAVE_MMAP */
+
+
+\f
+
+/*
+  Extend the top-most chunk by obtaining memory from system.
+  Main interface to sbrk (but see also malloc_trim).
+*/
+
+#if __STD_C
+static void malloc_extend_top(INTERNAL_SIZE_T nb)
+#else
+static void malloc_extend_top(nb) INTERNAL_SIZE_T nb;
+#endif
+{
+  char*     brk;                  /* return value from sbrk */
+  INTERNAL_SIZE_T front_misalign; /* unusable bytes at front of sbrked space */
+  INTERNAL_SIZE_T correction;     /* bytes for 2nd sbrk call */
+  char*     new_brk;              /* return of 2nd sbrk call */
+  INTERNAL_SIZE_T top_size;       /* new size of top chunk */
+
+  mchunkptr old_top     = top;  /* Record state of old top */
+  INTERNAL_SIZE_T old_top_size = chunksize(old_top);
+  char*     old_end      = (char*)(chunk_at_offset(old_top, old_top_size));
+
+  /* Pad request with top_pad plus minimal overhead */
+
+  INTERNAL_SIZE_T    sbrk_size     = nb + top_pad + MINSIZE;
+  unsigned long pagesz    = malloc_getpagesize;
+
+  /* If not the first time through, round to preserve page boundary */
+  /* Otherwise, we need to correct to a page size below anyway. */
+  /* (We also correct below if an intervening foreign sbrk call.) */
+
+  if (sbrk_base != (char*)(-1))
+    sbrk_size = (sbrk_size + (pagesz - 1)) & ~(pagesz - 1);
+
+  brk = (char*)(MORECORE (sbrk_size));
+
+  /* Fail if sbrk failed or if a foreign sbrk call killed our space */
+  if (brk == (char*)(MORECORE_FAILURE) ||
+      (brk < old_end && old_top != initial_top))
+    return;
+
+  sbrked_mem += sbrk_size;
+
+  if (brk == old_end) /* can just add bytes to current top */
+  {
+    top_size = sbrk_size + old_top_size;
+    set_head(top, top_size | PREV_INUSE);
+  }
+  else
+  {
+    if (sbrk_base == (char*)(-1))  /* First time through. Record base */
+      sbrk_base = brk;
+    else  /* Someone else called sbrk().  Count those bytes as sbrked_mem. */
+      sbrked_mem += brk - (char*)old_end;
+
+    /* Guarantee alignment of first new chunk made from this space */
+    front_misalign = (unsigned long)chunk2mem(brk) & MALLOC_ALIGN_MASK;
+    if (front_misalign > 0)
+    {
+      correction = (MALLOC_ALIGNMENT) - front_misalign;
+      brk += correction;
+    }
+    else
+      correction = 0;
+
+    /* Guarantee the next brk will be at a page boundary */
+
+    correction += ((((unsigned long)(brk + sbrk_size))+(pagesz-1)) &
+                   ~(pagesz - 1)) - ((unsigned long)(brk + sbrk_size));
+
+    /* Allocate correction */
+    new_brk = (char*)(MORECORE (correction));
+    if (new_brk == (char*)(MORECORE_FAILURE)) return;
+
+    sbrked_mem += correction;
+
+    top = (mchunkptr)brk;
+    top_size = new_brk - brk + correction;
+    set_head(top, top_size | PREV_INUSE);
+
+    if (old_top != initial_top)
+    {
+
+      /* There must have been an intervening foreign sbrk call. */
+      /* A double fencepost is necessary to prevent consolidation */
+
+      /* If not enough space to do this, then user did something very wrong */
+      if (old_top_size < MINSIZE)
+      {
+        set_head(top, PREV_INUSE); /* will force null return from malloc */
+        return;
+      }
+
+      /* Also keep size a multiple of MALLOC_ALIGNMENT */
+      old_top_size = (old_top_size - 3*SIZE_SZ) & ~MALLOC_ALIGN_MASK;
+      set_head_size(old_top, old_top_size);
+      chunk_at_offset(old_top, old_top_size          )->size =
+        SIZE_SZ|PREV_INUSE;
+      chunk_at_offset(old_top, old_top_size + SIZE_SZ)->size =
+        SIZE_SZ|PREV_INUSE;
+      /* If possible, release the rest. */
+      if (old_top_size >= MINSIZE)
+        fREe(chunk2mem(old_top));
+    }
+  }
+
+  if ((unsigned long)sbrked_mem > (unsigned long)max_sbrked_mem)
+    max_sbrked_mem = sbrked_mem;
+  if ((unsigned long)(mmapped_mem + sbrked_mem) > (unsigned long)max_total_mem)
+    max_total_mem = mmapped_mem + sbrked_mem;
+
+  /* We always land on a page boundary */
+  assert(((unsigned long)((char*)top + top_size) & (pagesz - 1)) == 0);
+}
+
+
+\f
+
+/* Main public routines */
+
+
+/*
+  Malloc Algorthim:
+
+    The requested size is first converted into a usable form, `nb'.
+    This currently means to add 4 bytes overhead plus possibly more to
+    obtain 8-byte alignment and/or to obtain a size of at least
+    MINSIZE (currently 16 bytes), the smallest allocatable size.
+    (All fits are considered `exact' if they are within MINSIZE bytes.)
+
+    From there, the first successful of the following steps is taken:
+
+      1. The bin corresponding to the request size is scanned, and if
+         a chunk of exactly the right size is found, it is taken.
+
+      2. The most recently remaindered chunk is used if it is big
+         enough.  This is a form of (roving) first fit, used only in
+         the absence of exact fits. Runs of consecutive requests use
+         the remainder of the chunk used for the previous such request
+         whenever possible. This limited use of a first-fit style
+         allocation strategy tends to give contiguous chunks
+         coextensive lifetimes, which improves locality and can reduce
+         fragmentation in the long run.
+
+      3. Other bins are scanned in increasing size order, using a
+         chunk big enough to fulfill the request, and splitting off
+         any remainder.  This search is strictly by best-fit; i.e.,
+         the smallest (with ties going to approximately the least
+         recently used) chunk that fits is selected.
+
+      4. If large enough, the chunk bordering the end of memory
+         (`top') is split off. (This use of `top' is in accord with
+         the best-fit search rule.  In effect, `top' is treated as
+         larger (and thus less well fitting) than any other available
+         chunk since it can be extended to be as large as necessary
+         (up to system limitations).
+
+      5. If the request size meets the mmap threshold and the
+         system supports mmap, and there are few enough currently
+         allocated mmapped regions, and a call to mmap succeeds,
+         the request is allocated via direct memory mapping.
+
+      6. Otherwise, the top of memory is extended by
+         obtaining more space from the system (normally using sbrk,
+         but definable to anything else via the MORECORE macro).
+         Memory is gathered from the system (in system page-sized
+         units) in a way that allows chunks obtained across different
+         sbrk calls to be consolidated, but does not require
+         contiguous memory. Thus, it should be safe to intersperse
+         mallocs with other sbrk calls.
+
+
+      All allocations are made from the the `lowest' part of any found
+      chunk. (The implementation invariant is that prev_inuse is
+      always true of any allocated chunk; i.e., that each allocated
+      chunk borders either a previously allocated and still in-use chunk,
+      or the base of its memory arena.)
+
+*/
+
+#if __STD_C
+Void_t* mALLOc(size_t bytes)
+#else
+Void_t* mALLOc(bytes) size_t bytes;
+#endif
+{
+  mchunkptr victim;                  /* inspected/selected chunk */
+  INTERNAL_SIZE_T victim_size;       /* its size */
+  int       idx;                     /* index for bin traversal */
+  mbinptr   bin;                     /* associated bin */
+  mchunkptr remainder;               /* remainder from a split */
+  long      remainder_size;          /* its size */
+  int       remainder_index;         /* its bin index */
+  unsigned long block;               /* block traverser bit */
+  int       startidx;                /* first bin of a traversed block */
+  mchunkptr fwd;                     /* misc temp for linking */
+  mchunkptr bck;                     /* misc temp for linking */
+  mbinptr q;                         /* misc temp */
+
+  INTERNAL_SIZE_T nb;
+
+  if ((long)bytes < 0) return 0;
+
+  nb = request2size(bytes);  /* padded request size; */
+
+  /* Check for exact match in a bin */
+
+  if (is_small_request(nb))  /* Faster version for small requests */
+  {
+    idx = smallbin_index(nb);
+
+    /* No traversal or size check necessary for small bins.  */
+
+    q = bin_at(idx);
+    victim = last(q);
+
+    /* Also scan the next one, since it would have a remainder < MINSIZE */
+    if (victim == q)
+    {
+      q = next_bin(q);
+      victim = last(q);
+    }
+    if (victim != q)
+    {
+      victim_size = chunksize(victim);
+      unlink(victim, bck, fwd);
+      set_inuse_bit_at_offset(victim, victim_size);
+      check_malloced_chunk(victim, nb);
+      return chunk2mem(victim);
+    }
+
+    idx += 2; /* Set for bin scan below. We've already scanned 2 bins. */
+
+  }
+  else
+  {
+    idx = bin_index(nb);
+    bin = bin_at(idx);
+
+    for (victim = last(bin); victim != bin; victim = victim->bk)
+    {
+      victim_size = chunksize(victim);
+      remainder_size = victim_size - nb;
+
+      if (remainder_size >= (long)MINSIZE) /* too big */
+      {
+        --idx; /* adjust to rescan below after checking last remainder */
+        break;
+      }
+
+      else if (remainder_size >= 0) /* exact fit */
+      {
+        unlink(victim, bck, fwd);
+        set_inuse_bit_at_offset(victim, victim_size);
+        check_malloced_chunk(victim, nb);
+        return chunk2mem(victim);
+      }
+    }
+
+    ++idx;
+
+  }
+
+  /* Try to use the last split-off remainder */
+
+  if ( (victim = last_remainder->fd) != last_remainder)
+  {
+    victim_size = chunksize(victim);
+    remainder_size = victim_size - nb;
+
+    if (remainder_size >= (long)MINSIZE) /* re-split */
+    {
+      remainder = chunk_at_offset(victim, nb);
+      set_head(victim, nb | PREV_INUSE);
+      link_last_remainder(remainder);
+      set_head(remainder, remainder_size | PREV_INUSE);
+      set_foot(remainder, remainder_size);
+      check_malloced_chunk(victim, nb);
+      return chunk2mem(victim);
+    }
+
+    clear_last_remainder;
+
+    if (remainder_size >= 0)  /* exhaust */
+    {
+      set_inuse_bit_at_offset(victim, victim_size);
+      check_malloced_chunk(victim, nb);
+      return chunk2mem(victim);
+    }
+
+    /* Else place in bin */
+
+    frontlink(victim, victim_size, remainder_index, bck, fwd);
+  }
+
+  /*
+     If there are any possibly nonempty big-enough blocks,
+     search for best fitting chunk by scanning bins in blockwidth units.
+  */
+
+  if ( (block = idx2binblock(idx)) <= binblocks)
+  {
+
+    /* Get to the first marked block */
+
+    if ( (block & binblocks) == 0)
+    {
+      /* force to an even block boundary */
+      idx = (idx & ~(BINBLOCKWIDTH - 1)) + BINBLOCKWIDTH;
+      block <<= 1;
+      while ((block & binblocks) == 0)
+      {
+        idx += BINBLOCKWIDTH;
+        block <<= 1;
+      }
+    }
+
+    /* For each possibly nonempty block ... */
+    for (;;)
+    {
+      startidx = idx;          /* (track incomplete blocks) */
+      q = bin = bin_at(idx);
+
+      /* For each bin in this block ... */
+      do
+      {
+        /* Find and use first big enough chunk ... */
+
+        for (victim = last(bin); victim != bin; victim = victim->bk)
+        {
+          victim_size = chunksize(victim);
+          remainder_size = victim_size - nb;
+
+          if (remainder_size >= (long)MINSIZE) /* split */
+          {
+            remainder = chunk_at_offset(victim, nb);
+            set_head(victim, nb | PREV_INUSE);
+            unlink(victim, bck, fwd);
+            link_last_remainder(remainder);
+            set_head(remainder, remainder_size | PREV_INUSE);
+            set_foot(remainder, remainder_size);
+            check_malloced_chunk(victim, nb);
+            return chunk2mem(victim);
+          }
+
+          else if (remainder_size >= 0)  /* take */
+          {
+            set_inuse_bit_at_offset(victim, victim_size);
+            unlink(victim, bck, fwd);
+            check_malloced_chunk(victim, nb);
+            return chunk2mem(victim);
+          }
+
+        }
+
+       bin = next_bin(bin);
+
+      } while ((++idx & (BINBLOCKWIDTH - 1)) != 0);
+
+      /* Clear out the block bit. */
+
+      do   /* Possibly backtrack to try to clear a partial block */
+      {
+        if ((startidx & (BINBLOCKWIDTH - 1)) == 0)
+        {
+          binblocks &= ~block;
+          break;
+        }
+        --startidx;
+       q = prev_bin(q);
+      } while (first(q) == q);
+
+      /* Get to the next possibly nonempty block */
+
+      if ( (block <<= 1) <= binblocks && (block != 0) )
+      {
+        while ((block & binblocks) == 0)
+        {
+          idx += BINBLOCKWIDTH;
+          block <<= 1;
+        }
+      }
+      else
+        break;
+    }
+  }
+
+
+  /* Try to use top chunk */
+
+  /* Require that there be a remainder, ensuring top always exists  */
+  if ( (remainder_size = chunksize(top) - nb) < (long)MINSIZE)
+  {
+
+#if HAVE_MMAP
+    /* If big and would otherwise need to extend, try to use mmap instead */
+    if ((unsigned long)nb >= (unsigned long)mmap_threshold &&
+        (victim = mmap_chunk(nb)) != 0)
+      return chunk2mem(victim);
+#endif
+
+    /* Try to extend */
+    malloc_extend_top(nb);
+    if ( (remainder_size = chunksize(top) - nb) < (long)MINSIZE)
+      return 0; /* propagate failure */
+  }
+
+  victim = top;
+  set_head(victim, nb | PREV_INUSE);
+  top = chunk_at_offset(victim, nb);
+  set_head(top, remainder_size | PREV_INUSE);
+  check_malloced_chunk(victim, nb);
+  return chunk2mem(victim);
+
+}
+
+
+\f
+
+/*
+
+  free() algorithm :
+
+    cases:
+
+       1. free(0) has no effect.
+
+       2. If the chunk was allocated via mmap, it is release via munmap().
+
+       3. If a returned chunk borders the current high end of memory,
+          it is consolidated into the top, and if the total unused
+          topmost memory exceeds the trim threshold, malloc_trim is
+          called.
+
+       4. Other chunks are consolidated as they arrive, and
+          placed in corresponding bins. (This includes the case of
+          consolidating with the current `last_remainder').
+
+*/
+
+
+#if __STD_C
+void fREe(Void_t* mem)
+#else
+void fREe(mem) Void_t* mem;
+#endif
+{
+  mchunkptr p;         /* chunk corresponding to mem */
+  INTERNAL_SIZE_T hd;  /* its head field */
+  INTERNAL_SIZE_T sz;  /* its size */
+  int       idx;       /* its bin index */
+  mchunkptr next;      /* next contiguous chunk */
+  INTERNAL_SIZE_T nextsz; /* its size */
+  INTERNAL_SIZE_T prevsz; /* size of previous contiguous chunk */
+  mchunkptr bck;       /* misc temp for linking */
+  mchunkptr fwd;       /* misc temp for linking */
+  int       islr;      /* track whether merging with last_remainder */
+
+  if (mem == 0)                              /* free(0) has no effect */
+    return;
+
+  p = mem2chunk(mem);
+  hd = p->size;
+
+#if HAVE_MMAP
+  if (hd & IS_MMAPPED)                       /* release mmapped memory. */
+  {
+    munmap_chunk(p);
+    return;
+  }
+#endif
+
+  check_inuse_chunk(p);
+
+  sz = hd & ~PREV_INUSE;
+  next = chunk_at_offset(p, sz);
+  nextsz = chunksize(next);
+
+  if (next == top)                            /* merge with top */
+  {
+    sz += nextsz;
+
+    if (!(hd & PREV_INUSE))                    /* consolidate backward */
+    {
+      prevsz = p->prev_size;
+      p = chunk_at_offset(p, -((long) prevsz));
+      sz += prevsz;
+      unlink(p, bck, fwd);
+    }
+
+    set_head(p, sz | PREV_INUSE);
+    top = p;
+    if ((unsigned long)(sz) >= (unsigned long)trim_threshold)
+      malloc_trim(top_pad);
+    return;
+  }
+
+  set_head(next, nextsz);                    /* clear inuse bit */
+
+  islr = 0;
+
+  if (!(hd & PREV_INUSE))                    /* consolidate backward */
+  {
+    prevsz = p->prev_size;
+    p = chunk_at_offset(p, -((long) prevsz));
+    sz += prevsz;
+
+    if (p->fd == last_remainder)             /* keep as last_remainder */
+      islr = 1;
+    else
+      unlink(p, bck, fwd);
+  }
+
+  if (!(inuse_bit_at_offset(next, nextsz)))   /* consolidate forward */
+  {
+    sz += nextsz;
+
+    if (!islr && next->fd == last_remainder)  /* re-insert last_remainder */
+    {
+      islr = 1;
+      link_last_remainder(p);
+    }
+    else
+      unlink(next, bck, fwd);
+  }
+
+
+  set_head(p, sz | PREV_INUSE);
+  set_foot(p, sz);
+  if (!islr)
+    frontlink(p, sz, idx, bck, fwd);
+}
+
+
+\f
+
+
+/*
+
+  Realloc algorithm:
+
+    Chunks that were obtained via mmap cannot be extended or shrunk
+    unless HAVE_MREMAP is defined, in which case mremap is used.
+    Otherwise, if their reallocation is for additional space, they are
+    copied.  If for less, they are just left alone.
+
+    Otherwise, if the reallocation is for additional space, and the
+    chunk can be extended, it is, else a malloc-copy-free sequence is
+    taken.  There are several different ways that a chunk could be
+    extended. All are tried:
+
+       * Extending forward into following adjacent free chunk.
+       * Shifting backwards, joining preceding adjacent space
+       * Both shifting backwards and extending forward.
+       * Extending into newly sbrked space
+
+    Unless the #define REALLOC_ZERO_BYTES_FREES is set, realloc with a
+    size argument of zero (re)allocates a minimum-sized chunk.
+
+    If the reallocation is for less space, and the new request is for
+    a `small' (<512 bytes) size, then the newly unused space is lopped
+    off and freed.
+
+    The old unix realloc convention of allowing the last-free'd chunk
+    to be used as an argument to realloc is no longer supported.
+    I don't know of any programs still relying on this feature,
+    and allowing it would also allow too many other incorrect
+    usages of realloc to be sensible.
+
+
+*/
+
+
+#if __STD_C
+Void_t* rEALLOc(Void_t* oldmem, size_t bytes)
+#else
+Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes;
+#endif
+{
+  INTERNAL_SIZE_T    nb;      /* padded request size */
+
+  mchunkptr oldp;             /* chunk corresponding to oldmem */
+  INTERNAL_SIZE_T    oldsize; /* its size */
+
+  mchunkptr newp;             /* chunk to return */
+  INTERNAL_SIZE_T    newsize; /* its size */
+  Void_t*   newmem;           /* corresponding user mem */
+
+  mchunkptr next;             /* next contiguous chunk after oldp */
+  INTERNAL_SIZE_T  nextsize;  /* its size */
+
+  mchunkptr prev;             /* previous contiguous chunk before oldp */
+  INTERNAL_SIZE_T  prevsize;  /* its size */
+
+  mchunkptr remainder;        /* holds split off extra space from newp */
+  INTERNAL_SIZE_T  remainder_size;   /* its size */
+
+  mchunkptr bck;              /* misc temp for linking */
+  mchunkptr fwd;              /* misc temp for linking */
+
+#ifdef REALLOC_ZERO_BYTES_FREES
+  if (bytes == 0) { fREe(oldmem); return 0; }
+#endif
+
+  if ((long)bytes < 0) return 0;
+
+  /* realloc of null is supposed to be same as malloc */
+  if (oldmem == 0) return mALLOc(bytes);
+
+  newp    = oldp    = mem2chunk(oldmem);
+  newsize = oldsize = chunksize(oldp);
+
+
+  nb = request2size(bytes);
+
+#if HAVE_MMAP
+  if (chunk_is_mmapped(oldp))
+  {
+#if HAVE_MREMAP
+    newp = mremap_chunk(oldp, nb);
+    if(newp) return chunk2mem(newp);
+#endif
+    /* Note the extra SIZE_SZ overhead. */
+    if(oldsize - SIZE_SZ >= nb) return oldmem; /* do nothing */
+    /* Must alloc, copy, free. */
+    newmem = mALLOc(bytes);
+    if (newmem == 0) return 0; /* propagate failure */
+    MALLOC_COPY(newmem, oldmem, oldsize - 2*SIZE_SZ);
+    munmap_chunk(oldp);
+    return newmem;
+  }
+#endif
+
+  check_inuse_chunk(oldp);
+
+  if ((long)(oldsize) < (long)(nb))
+  {
+
+    /* Try expanding forward */
+
+    next = chunk_at_offset(oldp, oldsize);
+    if (next == top || !inuse(next))
+    {
+      nextsize = chunksize(next);
+
+      /* Forward into top only if a remainder */
+      if (next == top)
+      {
+        if ((long)(nextsize + newsize) >= (long)(nb + MINSIZE))
+        {
+          newsize += nextsize;
+          top = chunk_at_offset(oldp, nb);
+          set_head(top, (newsize - nb) | PREV_INUSE);
+          set_head_size(oldp, nb);
+          return chunk2mem(oldp);
+        }
+      }
+
+      /* Forward into next chunk */
+      else if (((long)(nextsize + newsize) >= (long)(nb)))
+      {
+        unlink(next, bck, fwd);
+        newsize  += nextsize;
+        goto split;
+      }
+    }
+    else
+    {
+      next = 0;
+      nextsize = 0;
+    }
+
+    /* Try shifting backwards. */
+
+    if (!prev_inuse(oldp))
+    {
+      prev = prev_chunk(oldp);
+      prevsize = chunksize(prev);
+
+      /* try forward + backward first to save a later consolidation */
+
+      if (next != 0)
+      {
+        /* into top */
+        if (next == top)
+        {
+          if ((long)(nextsize + prevsize + newsize) >= (long)(nb + MINSIZE))
+          {
+            unlink(prev, bck, fwd);
+            newp = prev;
+            newsize += prevsize + nextsize;
+            newmem = chunk2mem(newp);
+            MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ);
+            top = chunk_at_offset(newp, nb);
+            set_head(top, (newsize - nb) | PREV_INUSE);
+            set_head_size(newp, nb);
+            return newmem;
+          }
+        }
+
+        /* into next chunk */
+        else if (((long)(nextsize + prevsize + newsize) >= (long)(nb)))
+        {
+          unlink(next, bck, fwd);
+          unlink(prev, bck, fwd);
+          newp = prev;
+          newsize += nextsize + prevsize;
+          newmem = chunk2mem(newp);
+          MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ);
+          goto split;
+        }
+      }
+
+      /* backward only */
+      if (prev != 0 && (long)(prevsize + newsize) >= (long)nb)
+      {
+        unlink(prev, bck, fwd);
+        newp = prev;
+        newsize += prevsize;
+        newmem = chunk2mem(newp);
+        MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ);
+        goto split;
+      }
+    }
+
+    /* Must allocate */
+
+    newmem = mALLOc (bytes);
+
+    if (newmem == 0)  /* propagate failure */
+      return 0;
+
+    /* Avoid copy if newp is next chunk after oldp. */
+    /* (This can only happen when new chunk is sbrk'ed.) */
+
+    if ( (newp = mem2chunk(newmem)) == next_chunk(oldp))
+    {
+      newsize += chunksize(newp);
+      newp = oldp;
+      goto split;
+    }
+
+    /* Otherwise copy, free, and exit */
+    MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ);
+    fREe(oldmem);
+    return newmem;
+  }
+
+
+ split:  /* split off extra room in old or expanded chunk */
+
+  if (newsize - nb >= MINSIZE) /* split off remainder */
+  {
+    remainder = chunk_at_offset(newp, nb);
+    remainder_size = newsize - nb;
+    set_head_size(newp, nb);
+    set_head(remainder, remainder_size | PREV_INUSE);
+    set_inuse_bit_at_offset(remainder, remainder_size);
+    fREe(chunk2mem(remainder)); /* let free() deal with it */
+  }
+  else
+  {
+    set_head_size(newp, newsize);
+    set_inuse_bit_at_offset(newp, newsize);
+  }
+
+  check_inuse_chunk(newp);
+  return chunk2mem(newp);
+}
+
+
+\f
+
+/*
+
+  memalign algorithm:
+
+    memalign requests more than enough space from malloc, finds a spot
+    within that chunk that meets the alignment request, and then
+    possibly frees the leading and trailing space.
+
+    The alignment argument must be a power of two. This property is not
+    checked by memalign, so misuse may result in random runtime errors.
+
+    8-byte alignment is guaranteed by normal malloc calls, so don't
+    bother calling memalign with an argument of 8 or less.
+
+    Overreliance on memalign is a sure way to fragment space.
+
+*/
+
+
+#if __STD_C
+Void_t* mEMALIGn(size_t alignment, size_t bytes)
+#else
+Void_t* mEMALIGn(alignment, bytes) size_t alignment; size_t bytes;
+#endif
+{
+  INTERNAL_SIZE_T    nb;      /* padded  request size */
+  char*     m;                /* memory returned by malloc call */
+  mchunkptr p;                /* corresponding chunk */
+  char*     brk;              /* alignment point within p */
+  mchunkptr newp;             /* chunk to return */
+  INTERNAL_SIZE_T  newsize;   /* its size */
+  INTERNAL_SIZE_T  leadsize;  /* leading space befor alignment point */
+  mchunkptr remainder;        /* spare room at end to split off */
+  long      remainder_size;   /* its size */
+
+  if ((long)bytes < 0) return 0;
+
+  /* If need less alignment than we give anyway, just relay to malloc */
+
+  if (alignment <= MALLOC_ALIGNMENT) return mALLOc(bytes);
+
+  /* Otherwise, ensure that it is at least a minimum chunk size */
+
+  if (alignment <  MINSIZE) alignment = MINSIZE;
+
+  /* Call malloc with worst case padding to hit alignment. */
+
+  nb = request2size(bytes);
+  m  = (char*)(mALLOc(nb + alignment + MINSIZE));
+
+  if (m == 0) return 0; /* propagate failure */
+
+  p = mem2chunk(m);
+
+  if ((((unsigned long)(m)) % alignment) == 0) /* aligned */
+  {
+#if HAVE_MMAP
+    if(chunk_is_mmapped(p))
+      return chunk2mem(p); /* nothing more to do */
+#endif
+  }
+  else /* misaligned */
+  {
+    /*
+      Find an aligned spot inside chunk.
+      Since we need to give back leading space in a chunk of at
+      least MINSIZE, if the first calculation places us at
+      a spot with less than MINSIZE leader, we can move to the
+      next aligned spot -- we've allocated enough total room so that
+      this is always possible.
+    */
+
+    brk = (char*)mem2chunk(((unsigned long)(m + alignment - 1)) & -((signed) alignment));
+    if ((long)(brk - (char*)(p)) < MINSIZE) brk = brk + alignment;
+
+    newp = (mchunkptr)brk;
+    leadsize = brk - (char*)(p);
+    newsize = chunksize(p) - leadsize;
+
+#if HAVE_MMAP
+    if(chunk_is_mmapped(p))
+    {
+      newp->prev_size = p->prev_size + leadsize;
+      set_head(newp, newsize|IS_MMAPPED);
+      return chunk2mem(newp);
+    }
+#endif
+
+    /* give back leader, use the rest */
+
+    set_head(newp, newsize | PREV_INUSE);
+    set_inuse_bit_at_offset(newp, newsize);
+    set_head_size(p, leadsize);
+    fREe(chunk2mem(p));
+    p = newp;
+
+    assert (newsize >= nb && (((unsigned long)(chunk2mem(p))) % alignment) == 0);
+  }
+
+  /* Also give back spare room at the end */
+
+  remainder_size = chunksize(p) - nb;
+
+  if (remainder_size >= (long)MINSIZE)
+  {
+    remainder = chunk_at_offset(p, nb);
+    set_head(remainder, remainder_size | PREV_INUSE);
+    set_head_size(p, nb);
+    fREe(chunk2mem(remainder));
+  }
+
+  check_inuse_chunk(p);
+  return chunk2mem(p);
+
+}
+
+\f
+
+
+/*
+    valloc just invokes memalign with alignment argument equal
+    to the page size of the system (or as near to this as can
+    be figured out from all the includes/defines above.)
+*/
+
+#if __STD_C
+Void_t* vALLOc(size_t bytes)
+#else
+Void_t* vALLOc(bytes) size_t bytes;
+#endif
+{
+  return mEMALIGn (malloc_getpagesize, bytes);
+}
+
+/*
+  pvalloc just invokes valloc for the nearest pagesize
+  that will accommodate request
+*/
+
+
+#if __STD_C
+Void_t* pvALLOc(size_t bytes)
+#else
+Void_t* pvALLOc(bytes) size_t bytes;
+#endif
+{
+  size_t pagesize = malloc_getpagesize;
+  return mEMALIGn (pagesize, (bytes + pagesize - 1) & ~(pagesize - 1));
+}
+
+/*
+
+  calloc calls malloc, then zeroes out the allocated chunk.
+
+*/
+
+#if __STD_C
+Void_t* cALLOc(size_t n, size_t elem_size)
+#else
+Void_t* cALLOc(n, elem_size) size_t n; size_t elem_size;
+#endif
+{
+  mchunkptr p;
+  INTERNAL_SIZE_T csz;
+
+  INTERNAL_SIZE_T sz = n * elem_size;
+
+
+  /* check if expand_top called, in which case don't need to clear */
+#if MORECORE_CLEARS
+  mchunkptr oldtop = top;
+  INTERNAL_SIZE_T oldtopsize = chunksize(top);
+#endif
+  Void_t* mem = mALLOc (sz);
+
+  if ((long)n < 0) return 0;
+
+  if (mem == 0)
+    return 0;
+  else
+  {
+    p = mem2chunk(mem);
+
+    /* Two optional cases in which clearing not necessary */
+
+
+#if HAVE_MMAP
+    if (chunk_is_mmapped(p)) return mem;
+#endif
+
+    csz = chunksize(p);
+
+#if MORECORE_CLEARS
+    if (p == oldtop && csz > oldtopsize)
+    {
+      /* clear only the bytes from non-freshly-sbrked memory */
+      csz = oldtopsize;
+    }
+#endif
+
+    MALLOC_ZERO(mem, csz - SIZE_SZ);
+    return mem;
+  }
+}
+
+/*
+
+  cfree just calls free. It is needed/defined on some systems
+  that pair it with calloc, presumably for odd historical reasons.
+
+*/
+
+#if !defined(INTERNAL_LINUX_C_LIB) || !defined(__ELF__)
+#if __STD_C
+void cfree(Void_t *mem)
+#else
+void cfree(mem) Void_t *mem;
+#endif
+{
+  fREe(mem);
+}
+#endif
+
+\f
+
+/*
+
+    Malloc_trim gives memory back to the system (via negative
+    arguments to sbrk) if there is unused memory at the `high' end of
+    the malloc pool. You can call this after freeing large blocks of
+    memory to potentially reduce the system-level memory requirements
+    of a program. However, it cannot guarantee to reduce memory. Under
+    some allocation patterns, some large free blocks of memory will be
+    locked between two used chunks, so they cannot be given back to
+    the system.
+
+    The `pad' argument to malloc_trim represents the amount of free
+    trailing space to leave untrimmed. If this argument is zero,
+    only the minimum amount of memory to maintain internal data
+    structures will be left (one page or less). Non-zero arguments
+    can be supplied to maintain enough trailing space to service
+    future expected allocations without having to re-obtain memory
+    from the system.
+
+    Malloc_trim returns 1 if it actually released any memory, else 0.
+
+*/
+
+#if __STD_C
+int malloc_trim(size_t pad)
+#else
+int malloc_trim(pad) size_t pad;
+#endif
+{
+  long  top_size;        /* Amount of top-most memory */
+  long  extra;           /* Amount to release */
+  char* current_brk;     /* address returned by pre-check sbrk call */
+  char* new_brk;         /* address returned by negative sbrk call */
+
+  unsigned long pagesz = malloc_getpagesize;
+
+  top_size = chunksize(top);
+  extra = ((top_size - pad - MINSIZE + (pagesz-1)) / pagesz - 1) * pagesz;
+
+  if (extra < (long)pagesz)  /* Not enough memory to release */
+    return 0;
+
+  else
+  {
+    /* Test to make sure no one else called sbrk */
+    current_brk = (char*)(MORECORE (0));
+    if (current_brk != (char*)(top) + top_size)
+      return 0;     /* Apparently we don't own memory; must fail */
+
+    else
+    {
+      new_brk = (char*)(MORECORE (-extra));
+
+      if (new_brk == (char*)(MORECORE_FAILURE)) /* sbrk failed? */
+      {
+        /* Try to figure out what we have */
+        current_brk = (char*)(MORECORE (0));
+        top_size = current_brk - (char*)top;
+        if (top_size >= (long)MINSIZE) /* if not, we are very very dead! */
+        {
+          sbrked_mem = current_brk - sbrk_base;
+          set_head(top, top_size | PREV_INUSE);
+        }
+        check_chunk(top);
+        return 0;
+      }
+
+      else
+      {
+        /* Success. Adjust top accordingly. */
+        set_head(top, (top_size - extra) | PREV_INUSE);
+        sbrked_mem -= extra;
+        check_chunk(top);
+        return 1;
+      }
+    }
+  }
+}
+
+\f
+
+/*
+  malloc_usable_size:
+
+    This routine tells you how many bytes you can actually use in an
+    allocated chunk, which may be more than you requested (although
+    often not). You can use this many bytes without worrying about
+    overwriting other allocated objects. Not a particularly great
+    programming practice, but still sometimes useful.
+
+*/
+
+#if __STD_C
+size_t malloc_usable_size(Void_t* mem)
+#else
+size_t malloc_usable_size(mem) Void_t* mem;
+#endif
+{
+  mchunkptr p;
+  if (mem == 0)
+    return 0;
+  else
+  {
+    p = mem2chunk(mem);
+    if(!chunk_is_mmapped(p))
+    {
+      if (!inuse(p)) return 0;
+      check_inuse_chunk(p);
+      return chunksize(p) - SIZE_SZ;
+    }
+    return chunksize(p) - 2*SIZE_SZ;
+  }
+}
+
+
+\f
+
+/* Utility to update current_mallinfo for malloc_stats and mallinfo() */
+
+static void malloc_update_mallinfo()
+{
+  int i;
+  mbinptr b;
+  mchunkptr p;
+#if DEBUG
+  mchunkptr q;
+#endif
+
+  INTERNAL_SIZE_T avail = chunksize(top);
+  int   navail = ((long)(avail) >= (long)MINSIZE)? 1 : 0;
+
+  for (i = 1; i < NAV; ++i)
+  {
+    b = bin_at(i);
+    for (p = last(b); p != b; p = p->bk)
+    {
+#if DEBUG
+      check_free_chunk(p);
+      for (q = next_chunk(p);
+           q < top && inuse(q) && (long)(chunksize(q)) >= (long)MINSIZE;
+           q = next_chunk(q))
+        check_inuse_chunk(q);
+#endif
+      avail += chunksize(p);
+      navail++;
+    }
+  }
+
+  current_mallinfo.ordblks = navail;
+  current_mallinfo.uordblks = sbrked_mem - avail;
+  current_mallinfo.fordblks = avail;
+  current_mallinfo.hblks = n_mmaps;
+  current_mallinfo.hblkhd = mmapped_mem;
+  current_mallinfo.keepcost = chunksize(top);
+
+}
+
+\f
+
+/*
+
+  malloc_stats:
+
+    Prints on stderr the amount of space obtain from the system (both
+    via sbrk and mmap), the maximum amount (which may be more than
+    current if malloc_trim and/or munmap got called), the maximum
+    number of simultaneous mmap regions used, and the current number
+    of bytes allocated via malloc (or realloc, etc) but not yet
+    freed. (Note that this is the number of bytes allocated, not the
+    number requested. It will be larger than the number requested
+    because of alignment and bookkeeping overhead.)
+
+*/
+
+void malloc_stats()
+{
+  malloc_update_mallinfo();
+  fprintf(stderr, "max system bytes = %10u\n",
+          (unsigned int)(max_total_mem));
+  fprintf(stderr, "system bytes     = %10u\n",
+          (unsigned int)(sbrked_mem + mmapped_mem));
+  fprintf(stderr, "in use bytes     = %10u\n",
+          (unsigned int)(current_mallinfo.uordblks + mmapped_mem));
+#if HAVE_MMAP
+  fprintf(stderr, "max mmap regions = %10u\n",
+          (unsigned int)max_n_mmaps);
+#endif
+}
+
+/*
+  mallinfo returns a copy of updated current mallinfo.
+*/
+
+struct mallinfo mALLINFo()
+{
+  malloc_update_mallinfo();
+  return current_mallinfo;
+}
+
+
+\f
+
+/*
+  mallopt:
+
+    mallopt is the general SVID/XPG interface to tunable parameters.
+    The format is to provide a (parameter-number, parameter-value) pair.
+    mallopt then sets the corresponding parameter to the argument
+    value if it can (i.e., so long as the value is meaningful),
+    and returns 1 if successful else 0.
+
+    See descriptions of tunable parameters above.
+
+*/
+
+#if __STD_C
+int mALLOPt(int param_number, int value)
+#else
+int mALLOPt(param_number, value) int param_number; int value;
+#endif
+{
+  switch(param_number)
+  {
+    case M_TRIM_THRESHOLD:
+      trim_threshold = value; return 1;
+    case M_TOP_PAD:
+      top_pad = value; return 1;
+    case M_MMAP_THRESHOLD:
+      mmap_threshold = value; return 1;
+    case M_MMAP_MAX:
+#if HAVE_MMAP
+      n_mmaps_max = value; return 1;
+#else
+      if (value != 0) return 0; else  n_mmaps_max = value; return 1;
+#endif
+
+    default:
+      return 0;
+  }
+}
+
+/*
+
+History:
+
+    V2.6.6 Sun Dec  5 07:42:19 1999  Doug Lea  (dl at gee)
+      * return null for negative arguments
+      * Added Several WIN32 cleanups from Martin C. Fong <mcfong@yahoo.com>
+         * Add 'LACKS_SYS_PARAM_H' for those systems without 'sys/param.h'
+          (e.g. WIN32 platforms)
+         * Cleanup up header file inclusion for WIN32 platforms
+         * Cleanup code to avoid Microsoft Visual C++ compiler complaints
+         * Add 'USE_DL_PREFIX' to quickly allow co-existence with existing
+           memory allocation routines
+         * Set 'malloc_getpagesize' for WIN32 platforms (needs more work)
+         * Use 'assert' rather than 'ASSERT' in WIN32 code to conform to
+          usage of 'assert' in non-WIN32 code
+         * Improve WIN32 'sbrk()' emulation's 'findRegion()' routine to
+           avoid infinite loop
+      * Always call 'fREe()' rather than 'free()'
+
+    V2.6.5 Wed Jun 17 15:57:31 1998  Doug Lea  (dl at gee)
+      * Fixed ordering problem with boundary-stamping
+
+    V2.6.3 Sun May 19 08:17:58 1996  Doug Lea  (dl at gee)
+      * Added pvalloc, as recommended by H.J. Liu
+      * Added 64bit pointer support mainly from Wolfram Gloger
+      * Added anonymously donated WIN32 sbrk emulation
+      * Malloc, calloc, getpagesize: add optimizations from Raymond Nijssen
+      * malloc_extend_top: fix mask error that caused wastage after
+        foreign sbrks
+      * Add linux mremap support code from HJ Liu
+
+    V2.6.2 Tue Dec  5 06:52:55 1995  Doug Lea  (dl at gee)
+      * Integrated most documentation with the code.
+      * Add support for mmap, with help from
+        Wolfram Gloger (Gloger@lrz.uni-muenchen.de).
+      * Use last_remainder in more cases.
+      * Pack bins using idea from  colin@nyx10.cs.du.edu
+      * Use ordered bins instead of best-fit threshhold
+      * Eliminate block-local decls to simplify tracing and debugging.
+      * Support another case of realloc via move into top
+      * Fix error occuring when initial sbrk_base not word-aligned.
+      * Rely on page size for units instead of SBRK_UNIT to
+        avoid surprises about sbrk alignment conventions.
+      * Add mallinfo, mallopt. Thanks to Raymond Nijssen
+        (raymond@es.ele.tue.nl) for the suggestion.
+      * Add `pad' argument to malloc_trim and top_pad mallopt parameter.
+      * More precautions for cases where other routines call sbrk,
+        courtesy of Wolfram Gloger (Gloger@lrz.uni-muenchen.de).
+      * Added macros etc., allowing use in linux libc from
+        H.J. Lu (hjl@gnu.ai.mit.edu)
+      * Inverted this history list
+
+    V2.6.1 Sat Dec  2 14:10:57 1995  Doug Lea  (dl at gee)
+      * Re-tuned and fixed to behave more nicely with V2.6.0 changes.
+      * Removed all preallocation code since under current scheme
+        the work required to undo bad preallocations exceeds
+        the work saved in good cases for most test programs.
+      * No longer use return list or unconsolidated bins since
+        no scheme using them consistently outperforms those that don't
+        given above changes.
+      * Use best fit for very large chunks to prevent some worst-cases.
+      * Added some support for debugging
+
+    V2.6.0 Sat Nov  4 07:05:23 1995  Doug Lea  (dl at gee)
+      * Removed footers when chunks are in use. Thanks to
+        Paul Wilson (wilson@cs.texas.edu) for the suggestion.
+
+    V2.5.4 Wed Nov  1 07:54:51 1995  Doug Lea  (dl at gee)
+      * Added malloc_trim, with help from Wolfram Gloger
+        (wmglo@Dent.MED.Uni-Muenchen.DE).
+
+    V2.5.3 Tue Apr 26 10:16:01 1994  Doug Lea  (dl at g)
+
+    V2.5.2 Tue Apr  5 16:20:40 1994  Doug Lea  (dl at g)
+      * realloc: try to expand in both directions
+      * malloc: swap order of clean-bin strategy;
+      * realloc: only conditionally expand backwards
+      * Try not to scavenge used bins
+      * Use bin counts as a guide to preallocation
+      * Occasionally bin return list chunks in first scan
+      * Add a few optimizations from colin@nyx10.cs.du.edu
+
+    V2.5.1 Sat Aug 14 15:40:43 1993  Doug Lea  (dl at g)
+      * faster bin computation & slightly different binning
+      * merged all consolidations to one part of malloc proper
+         (eliminating old malloc_find_space & malloc_clean_bin)
+      * Scan 2 returns chunks (not just 1)
+      * Propagate failure in realloc if malloc returns 0
+      * Add stuff to allow compilation on non-ANSI compilers
+          from kpv@research.att.com
+
+    V2.5 Sat Aug  7 07:41:59 1993  Doug Lea  (dl at g.oswego.edu)
+      * removed potential for odd address access in prev_chunk
+      * removed dependency on getpagesize.h
+      * misc cosmetics and a bit more internal documentation
+      * anticosmetics: mangled names in macros to evade debugger strangeness
+      * tested on sparc, hp-700, dec-mips, rs6000
+          with gcc & native cc (hp, dec only) allowing
+          Detlefs & Zorn comparison study (in SIGPLAN Notices.)
+
+    Trial version Fri Aug 28 13:14:29 1992  Doug Lea  (dl at g.oswego.edu)
+      * Based loosely on libg++-1.2X malloc. (It retains some of the overall
+         structure of old version,  but most details differ.)
+
+*/
+
+
diff --git a/common/main.c b/common/main.c
new file mode 100644 (file)
index 0000000..1bbf755
--- /dev/null
@@ -0,0 +1,314 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <ppcboot.h>
+#include <command.h>
+
+int readline (const char *const prompt);
+
+static char * delete_char (char *buffer, char *p, int *colp, int *np, int plen);
+static int parse_line (char *, char *[]);
+
+char        console_buffer[CFG_CBSIZE];                /* console I/O buffer   */
+
+static char erase_seq[] = "\b \b";             /* erase sequence       */
+static char   tab_seq[] = "        ";          /* used to expand TABs  */
+static char   parse_buffer[CFG_CBSIZE];                /* cmd parse buffer     */
+static int   argc;
+static char *argv[CFG_MAXARGS+1];              /* NULL terminated      */
+
+/****************************************************************************/
+
+void main_loop(bd_t *bd)
+{
+       cmd_tbl_t *cmdtp;
+#if (CONFIG_8xx_BOOTDELAY >= 0)
+       int bootdelay = CONFIG_8xx_BOOTDELAY;
+       int autoboot  = 1;
+
+#endif /* CONFIG_8xx_BOOTDELAY */
+
+#if 0
+       printf ("### main_loop entered:\n\n");
+#endif
+
+       /* Set default arguments */
+       argc = 0;
+       argv[ argc ] =  NULL ;
+
+       /*
+        * Main Loop for Monitor Command Processing
+        */
+       
+       for (;;) {
+               int flag = 0;
+               int len;
+
+#if (CONFIG_8xx_BOOTDELAY >= 0)
+
+               if (autoboot)
+                       printf ("Hit any key to stop autoboot: %2d ", bootdelay);
+
+               while (bootdelay > 0) {
+                       int i;
+
+                       --bootdelay;
+                       /* delay 100 * 10ms */
+                       for (i=0; i<100; ++i) {
+                               if (serial_tstc()) {    /* we got a key press   */
+                                       bootdelay = 0;  /* no more delays       */
+                                       autoboot  = 0;  /* don't auto boot      */
+                                       (void) serial_getc();  /* consume input */
+                                       break;
+                               }
+                               udelay (10000);
+                       }
+
+                       printf ("\b\b\b%2d ", bootdelay);
+               }
+
+               serial_putc ('\n');
+
+               if (autoboot) {
+                       strncpy (console_buffer,
+                                CONFIG_8xx_BOOTCOMMAND,
+                                CFG_CBSIZE-1);
+                       console_buffer[CFG_CBSIZE-1] = '\0';    /* just in case */
+                       len = strlen (console_buffer);
+
+                       autoboot = 0;
+               }
+               else                    /* No autoboot: read input              */
+#endif /* CONFIG_8xx_BOOTDELAY */
+               if ((len = readline (CFG_PROMPT)) < 0) {
+                       printf ("<INTERRUPT>\n");
+                       continue;
+               }
+
+               /*
+                * If we have any new input, we parse the new command line.
+                * Otherwise, we re-issue the previous command.
+                */
+               if (len) {
+                       strcpy (parse_buffer, console_buffer);
+
+                       argc = parse_line (parse_buffer, argv);
+               } else {
+                       flag |= CMD_FLAG_REPEAT;
+               }
+#if 0
+       {       int i;
+               printf ("ARGC = %d\n", argc);
+               for (i=0; i<argc; ++i) {
+                       printf (">> ARGV[%d] = \"%s\"\n", i, argv[i]);
+               }
+               printf ("\n");
+       }
+#endif
+
+               if (argc == 0) {        /* nothing to do */
+                       continue;
+               }
+
+               /*
+                * Search command table.
+                * Use linear search - it's a small table
+                */
+               for (cmdtp=&cmd_tbl[0]; cmdtp->name; cmdtp++) {
+                       if (strncmp(argv[0], cmdtp->name, cmdtp->lmin) == 0) {
+                               /* found - check max args */
+                               if (argc > cmdtp->maxargs) {
+                                       printf ("Usage:\n%s\n", cmdtp->usage);
+                                       goto done;
+                               }
+                               /* OK - call function */
+                               (cmdtp->cmd)(cmdtp, bd, flag, argc, argv);
+                               goto done;
+                       }
+               }
+               printf ("Unknown command '%s' - try 'help'\n", argv[0]);
+done:          ;
+       }
+}
+
+/****************************************************************************/
+
+/*
+ * Prompt for input and read a line.
+ * Return number of read characters
+ */
+int readline (const char *const prompt)
+{
+       char   *p = console_buffer;
+       int     n = 0;                          /* buffer index         */
+       int     plen = strlen (prompt);         /* prompt length        */
+       int     col;                            /* output column cnt    */
+       char    c;
+
+       /* print prompt */
+       if (prompt)
+               serial_putstr (prompt);
+       col = plen;
+
+       for (;;) {
+               c = serial_getc();
+
+               /*
+                * Special character handling
+                */
+               switch (c) {
+               case '\r':                              /* Enter                */
+               case '\n':
+                       *p = '\0';
+                       serial_putstr ("\r\n");
+                       return (p - console_buffer);
+               
+               case 0x03:                              /* ^C - break           */
+                       return (-1);
+               
+               case 0x15:                              /* ^U - erase line      */
+                       while (col > plen) {
+                               serial_putstr (erase_seq);
+                               --col;
+                       }
+                       p = console_buffer;
+                       n = 0;
+                       continue;
+
+               case 0x17:                              /* ^W - erase word      */
+                       p=delete_char(console_buffer, p, &col, &n, plen);
+                       while ((n > 0) && (*p != ' ')) {
+                               p=delete_char(console_buffer, p, &col, &n, plen);
+                       }
+                       continue;
+
+               case 0x08:                              /* ^H  - backspace      */
+               case 0x7F:                              /* DEL - backspace      */
+                       p=delete_char(console_buffer, p, &col, &n, plen);
+                       continue;
+
+               default:
+                       /*
+                        * Must be a normal character then
+                        */
+                       if (n < CFG_CBSIZE-2) {
+                               if (c == '\t') {        /* expand TABs          */
+                                       serial_putstr (tab_seq+(col&07));
+                                       col += 8 - (col&07);
+                               } else {
+                                       ++col;          /* echo input           */
+                                       serial_putc (c);
+                               }
+                               *p++ = c;
+                               ++n;
+                       } else {                        /* Buffer full          */
+                               serial_putc ('\a');
+                       }
+               }
+       }
+}
+
+/****************************************************************************/
+
+/*
+ * Some commands are too dangerous to repeat when the user just presses
+ * enter to see if the box is still alive.
+ *
+ * This function will turn off repeating of the current command.
+ */
+
+void   command_repeat_off (void)
+{
+       argc = 0;
+}
+
+/****************************************************************************/
+
+static char * delete_char (char *buffer, char *p, int *colp, int *np, int plen)
+{
+       char *s;
+
+       if (*np == 0) {
+               return (p);
+       }
+
+       if (*(--p) == '\t') {                   /* will retype the whole line   */
+               while (*colp > plen) {
+                       serial_putstr (erase_seq);
+                       (*colp)--;
+               }
+               for (s=buffer; s<p; ++s) {
+                       if (*s == '\t') {
+                               serial_putstr (tab_seq+((*colp) & 07));
+                               *colp += 8 - ((*colp) & 07);
+                       } else {
+                               ++(*colp);
+                               serial_putc (*s);
+                       }
+               }
+       } else {
+               serial_putstr (erase_seq);
+               (*colp)--;
+       }
+       (*np)--;
+       return (p);
+}
+
+/****************************************************************************/
+
+int parse_line (char *line, char *argv[])
+{
+       int nargs = 0;
+
+       while (nargs < CFG_MAXARGS) {
+
+               /* skip any white space */
+               while ((*line == ' ') || (*line == '\t')) {
+                       ++line;
+               }
+
+               if (*line == '\0') {    /* end of line, no more args    */
+                       argv[nargs] = NULL;
+                       return (nargs);
+               }
+
+               argv[nargs++] = line;   /* begin of argument string     */
+
+               /* find end of string */
+               while (*line && (*line != ' ') && (*line != '\t')) {
+                       ++line;
+               }
+
+               if (*line == '\0') {    /* end of line, no more args    */
+                       argv[nargs] = NULL;
+                       return (nargs);
+               }
+
+               *line++ = '\0';         /* terminate current arg         */
+       }
+
+       return (nargs);
+}
+
+/****************************************************************************/
+
diff --git a/common/s_record.c b/common/s_record.c
new file mode 100644 (file)
index 0000000..a36a113
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <ppcboot.h>
+#include <s_record.h>
+
+static int hex1_bin (char  c);
+static int hex2_bin (char *s);
+
+int srec_decode (char *input, int *count, ulong *addr, char *data)
+{
+       int     i;
+       int     v;                              /* conversion buffer    */
+       int     srec_type;                      /* S-Record type        */
+       unsigned char chksum;                   /* buffer for checksum  */
+
+       chksum = 0;
+
+       /* skip anything before 'S', and the 'S' itself.
+        * Return error if not found
+        */
+
+       for (; *input; ++input) {
+               if (*input == 'S') {            /* skip 'S' */
+                       ++input;
+                       break;
+               }
+       }
+       if (*input == '\0') {                   /* no more data?        */
+               return (SREC_EMPTY);
+       }
+
+       v = *input++;                           /* record type          */
+
+       if ((*count = hex2_bin(input)) < 0) {
+               return (SREC_E_NOSREC);
+       }
+
+       chksum += *count;
+       input  += 2;
+
+       switch (v) {                            /* record type          */
+
+       case '0':                               /* start record         */
+               srec_type = SREC_START;         /* 2 byte addr field    */
+               *count   -= 3;                  /* - checksum and addr  */
+               break;
+       case '1':
+               srec_type = SREC_DATA2;         /* 2 byte addr field    */
+               *count   -= 3;                  /* - checksum and addr  */
+               break;
+       case '2':
+               srec_type = SREC_DATA3;         /* 3 byte addr field    */
+               *count   -= 4;                  /* - checksum and addr  */
+               break;
+       case '3':                               /* data record with a   */
+               srec_type = SREC_DATA4;         /* 4 byte addr field    */
+               *count   -= 5;                  /* - checksum and addr  */
+               break;
+/***   case '4'  ***/
+       case '5':                       /* count record, addr field contains */
+               srec_type = SREC_COUNT; /* a 2 byte record counter      */
+               *count    = 0;                  /* no data              */
+               break;
+/***   case '6' -- not used  ***/
+       case '7':                               /* end record with a    */
+               srec_type = SREC_END4;          /* 4 byte addr field    */
+               *count   -= 5;                  /* - checksum and addr  */
+               break;
+       case '8':                               /* end record with a    */
+               srec_type = SREC_END3;          /* 3 byte addr field    */
+               *count   -= 4;                  /* - checksum and addr  */
+               break;
+       case '9':                               /* end record with a    */
+               srec_type = SREC_END2;          /* 2 byte addr field    */
+               *count   -= 3;                  /* - checksum and addr  */
+               break;
+       default:
+               return (SREC_E_BADTYPE);
+       }
+
+       /* read address field */
+       *addr = 0;
+
+       switch (v) {
+       case '3':                               /* 4 byte addr field    */
+       case '7':
+               if ((v = hex2_bin(input)) < 0) {
+                       return (SREC_E_NOSREC);
+               }
+               *addr  += v;
+               chksum += v;
+               input  += 2;
+               /* FALL THRU */
+       case '2':                               /* 3 byte addr field    */
+       case '8':
+               if ((v = hex2_bin(input)) < 0) {
+                       return (SREC_E_NOSREC);
+               }
+               *addr <<= 8;
+               *addr  += v;
+               chksum += v;
+               input  += 2;
+               /* FALL THRU */
+       case '0':                               /* 2 byte addr field    */
+       case '1':
+       case '5':
+       case '9':
+               if ((v = hex2_bin(input)) < 0) {
+                       return (SREC_E_NOSREC);
+               }
+               *addr <<= 8;
+               *addr  += v;
+               chksum += v;
+               input  += 2;
+
+               if ((v = hex2_bin(input)) < 0) {
+                       return (SREC_E_NOSREC);
+               }
+               *addr <<= 8;
+               *addr  += v;
+               chksum += v;
+               input  += 2;
+
+               break;
+       default:
+               return (SREC_E_BADTYPE);
+       }
+
+       /* convert data and calculate checksum */
+       for (i=0; i < *count; ++i) {
+               if ((v = hex2_bin(input)) < 0) {
+                       return (SREC_E_NOSREC);
+               }
+               data[i] = v;
+               chksum += v;
+               input  += 2;
+       }
+
+       /* read anc check checksum */
+       if ((v = hex2_bin(input)) < 0) {
+               return (SREC_E_NOSREC);
+       }
+
+       if ((unsigned char)v != (unsigned char)~chksum) {
+               return (SREC_E_BADCHKS);
+       }
+
+       return (srec_type);
+}
+
+static int hex1_bin (char c)
+{
+       if (c >= '0' && c <= '9')
+               return (c - '0');
+       if (c >= 'a' && c <= 'f')
+               return (c + 10 - 'a');
+       if (c >= 'A' && c <= 'F')
+               return (c + 10 - 'A');
+       return (-1);
+}
+
+static int hex2_bin (char *s)
+{
+       int i, j;
+
+       if ((i = hex1_bin(*s++)) < 0) {
+               return (-1);
+       }
+       if ((j = hex1_bin(*s)) < 0) {
+               return (-1);
+       }
+
+       return ((i<<4) + j);
+}
diff --git a/config.mk b/config.mk
new file mode 100644 (file)
index 0000000..de5758b
--- /dev/null
+++ b/config.mk
@@ -0,0 +1,101 @@
+#
+# (C) Copyright 2000
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+#########################################################################
+
+CONFIG_SHELL   := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
+                   else if [ -x /bin/bash ]; then echo /bin/bash; \
+                   else echo sh; fi ; fi)
+
+#XXX#HPATH             = $(KERNEL)/include
+#XXX#CDKHPATH  = /LinuxPPC/CDK/lib/gcc-lib/powerpc-linux/2.95.2/include
+CDK_DIR                = /LinuxPPC/CDK
+CDKHEADERS     = -I$(CDK_DIR)/include \
+                 -I$(CDK_DIR)/lib/gcc-lib/powerpc-linux/2.95.2/include
+
+HOSTCC         = gcc
+HOSTCFLAGS     = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer
+#########################################################################
+
+#
+# Include the make variables (CC, etc...)
+#
+AS     = $(CROSS_COMPILE)as
+LD     = $(CROSS_COMPILE)ld
+CC     = $(CROSS_COMPILE)gcc
+CPP    = $(CC) -E
+AR     = $(CROSS_COMPILE)ar
+NM     = $(CROSS_COMPILE)nm
+STRIP  = $(CROSS_COMPILE)strip
+OBJCOPY = $(CROSS_COMPILE)objcopy
+OBJDUMP = $(CROSS_COMPILE)objdump
+RANLIB = $(CROSS_COMPILE)RANLIB
+MAKEDEPEND = makedepend -Y
+
+RELFLAGS= -mrelocatable -ffixed-r14
+DBGFLAGS= -g -DDEBUG
+OPTFLAGS= #-O2
+
+CPPFLAGS := $(DBGFLAGS) $(OPTFLAGS) $(RELFLAGS)        \
+       -D__KERNEL__ -D__powerpc__ -DCONFIG_8xx \
+       -I$(TOPDIR)/include                     \
+       $(CDKHEADERS)                           \
+       -mcpu=860 -msoft-float -fno-builtin     \
+       -pipe -ffixed-r2 -mstring               \
+       -Wall -Wno-uninitialized
+
+
+CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -fomit-frame-pointer
+AFLAGS := -D__ASSEMBLY__ $(CPPFLAGS)
+
+LDFLAGS += -Bstatic -T include/ppcboot.lds -Ttext $(TEXT_BASE)
+
+OBJCFLAGS = --remove-section=.stab                     \
+       --remove-section=.comment                       \
+       --remove-section=.stabstr                       \
+       --change-section-lma=.data+$(TEXT_BASE)         \
+       --change-section-lma=__ex_table+$(TEXT_BASE)    \
+       --change-section-lma=.bss+$(TEXT_BASE)          \
+       --set-section-flags=.bss=contents,alloc,load,data
+
+#########################################################################
+
+export CONFIG_SHELL HPATH HOSTCC HOSTCFLAGS CROSS_COMPILE \
+       AS LD CC CPP AR NM STRIP OBJCOPY OBJDUMP \
+       MAKE
+export CPPFLAGS CFLAGS AFLAGS
+
+#########################################################################
+
+%.s:   %.S
+       $(CPP) $(AFLAGS) -o $@ $<
+%.o:   %.S
+       $(CC) $(AFLAGS) -c -o $@ $<
+
+#########################################################################
+
+include $(TOPDIR)/$(ARCH)/config.mk    # include architecture dependend rules
+include $(TOPDIR)/$(CPU)/config.mk     # include  CPU  specific rules
+include $(TOPDIR)/$(BOARD)/config.mk   # include board specific rules
+
+#########################################################################
diff --git a/examples/Makefile b/examples/Makefile
new file mode 100644 (file)
index 0000000..1418fbc
--- /dev/null
@@ -0,0 +1,107 @@
+#
+# (C) Copyright 2000
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+LOAD_ADDR = 0x40000
+
+include $(TOPDIR)/config.mk
+
+SREC   = hello_world.srec timer.srec
+
+OBJS   = $(SREC:.srec=.o)
+
+CPPFLAGS += -I..
+
+all:   $(SREC)
+
+clean:
+       rm -f $(OBJS)
+
+distclean:     clean
+       rm -f $(SREC) $(SREC:.srec=) core *.bak
+
+#########################################################################
+
+%.srec:        %.o
+       $(LD) -s -Ttext $(LOAD_ADDR) -o $(<:.o=) -e $(<:.o=) $<
+       $(OBJCOPY) -O srec $(<:.o=) $@
+
+#########################################################################
+
+depend dep:
+       $(MAKEDEPEND) -- $(CFLAGS) -- $(OBJS:.o=.c)
+
+#########################################################################
+
+# DO NOT DELETE
+
+hello_world.o: /home/wd/ppc/ppcboot/include/ppcboot.h
+hello_world.o: /home/wd/ppc/ppcboot/include/config.h
+hello_world.o: /LinuxPPC/CDK/include/linux/bitops.h
+hello_world.o: /LinuxPPC/CDK/include/asm/bitops.h
+hello_world.o: /LinuxPPC/CDK/include/asm/system.h
+hello_world.o: /LinuxPPC/CDK/include/linux/kdev_t.h
+hello_world.o: /LinuxPPC/CDK/include/asm/processor.h
+hello_world.o: /LinuxPPC/CDK/include/linux/config.h
+hello_world.o: /LinuxPPC/CDK/include/asm/ptrace.h
+hello_world.o: /LinuxPPC/CDK/include/asm/residual.h
+hello_world.o: /LinuxPPC/CDK/include/asm/pnp.h
+hello_world.o: /LinuxPPC/CDK/include/asm/atomic.h
+hello_world.o: /LinuxPPC/CDK/include/asm/byteorder.h
+hello_world.o: /LinuxPPC/CDK/include/asm/types.h
+hello_world.o: /LinuxPPC/CDK/include/linux/byteorder/big_endian.h
+hello_world.o: /LinuxPPC/CDK/include/linux/byteorder/swab.h
+hello_world.o: /LinuxPPC/CDK/include/linux/byteorder/generic.h
+hello_world.o: /LinuxPPC/CDK/include/linux/types.h
+hello_world.o: /LinuxPPC/CDK/include/linux/posix_types.h
+hello_world.o: /LinuxPPC/CDK/include/linux/stddef.h
+hello_world.o: /LinuxPPC/CDK/include/asm/posix_types.h
+hello_world.o: /LinuxPPC/CDK/include/linux/string.h
+hello_world.o: /LinuxPPC/CDK/include/asm/string.h
+hello_world.o: /home/wd/ppc/ppcboot/include/asm/8xx_immap.h
+hello_world.o: /home/wd/ppc/ppcboot/include/flash.h
+timer.o: /home/wd/ppc/ppcboot/include/ppcboot.h
+timer.o: /home/wd/ppc/ppcboot/include/config.h
+timer.o: /LinuxPPC/CDK/include/linux/bitops.h
+timer.o: /LinuxPPC/CDK/include/asm/bitops.h
+timer.o: /LinuxPPC/CDK/include/asm/system.h
+timer.o: /LinuxPPC/CDK/include/linux/kdev_t.h
+timer.o: /LinuxPPC/CDK/include/asm/processor.h
+timer.o: /LinuxPPC/CDK/include/linux/config.h
+timer.o: /LinuxPPC/CDK/include/asm/ptrace.h
+timer.o: /LinuxPPC/CDK/include/asm/residual.h /LinuxPPC/CDK/include/asm/pnp.h
+timer.o: /LinuxPPC/CDK/include/asm/atomic.h
+timer.o: /LinuxPPC/CDK/include/asm/byteorder.h
+timer.o: /LinuxPPC/CDK/include/asm/types.h
+timer.o: /LinuxPPC/CDK/include/linux/byteorder/big_endian.h
+timer.o: /LinuxPPC/CDK/include/linux/byteorder/swab.h
+timer.o: /LinuxPPC/CDK/include/linux/byteorder/generic.h
+timer.o: /LinuxPPC/CDK/include/linux/types.h
+timer.o: /LinuxPPC/CDK/include/linux/posix_types.h
+timer.o: /LinuxPPC/CDK/include/linux/stddef.h
+timer.o: /LinuxPPC/CDK/include/asm/posix_types.h
+timer.o: /LinuxPPC/CDK/include/linux/string.h
+timer.o: /LinuxPPC/CDK/include/asm/string.h
+timer.o: /home/wd/ppc/ppcboot/include/asm/8xx_immap.h
+timer.o: /home/wd/ppc/ppcboot/include/flash.h
+timer.o: /home/wd/ppc/ppcboot/include/commproc.h
+timer.o: /home/wd/ppc/ppcboot/include/mpc8xx_irq.h
diff --git a/examples/hello_world.c b/examples/hello_world.c
new file mode 100644 (file)
index 0000000..4d423b2
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <ppcboot.h>
+
+#define        MON_PRINT(fmt,args...)  \
+       (*(void (*)(const char *, ...))(bd->bi_serial_io.printf)) (fmt ,##args)
+
+#define MON_GETC               \
+       (*(int (*)(void))(bd->bi_serial_io.getc))
+
+#define MON_TSTC               \
+       (*(int (*)(void))(bd->bi_serial_io.tstc))
+
+int hello_world (bd_t *bd, int argc, char *argv[])
+{
+       int i;
+
+       MON_PRINT ("Hello World\n");
+
+       MON_PRINT ("argc = %d\n", argc);
+
+       for (i=0; i<=argc; ++i) {
+               MON_PRINT ("argv[%d] = \"%s\"\n",
+                       i,
+                       argv[i] ? argv[i] : "<NULL>");
+       }
+
+       MON_PRINT ("Hit any key to exit ... ");
+       while (!MON_TSTC())
+               ;
+       /* consume input */
+       (void) MON_GETC();
+
+       MON_PRINT ("\n\n");
+       return (0);
+}
diff --git a/examples/timer.c b/examples/timer.c
new file mode 100644 (file)
index 0000000..fa15f8b
--- /dev/null
@@ -0,0 +1,355 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <ppcboot.h>
+#include <commproc.h>
+#include <mpc8xx_irq.h>
+
+#undef DEBUG
+
+#define        TIMER_PERIOD    1000000         /* 1 second clock */
+
+static void timer_handler (void *arg);
+
+
+/* Access functions for the Machine State Register */
+static __inline__ unsigned long get_msr(void)
+{
+    unsigned long msr;
+
+    asm volatile("mfmsr %0" : "=r" (msr) :);
+    return msr;
+}
+
+static __inline__ void set_msr(unsigned long msr)
+{
+    asm volatile("mtmsr %0" : : "r" (msr)); 
+}
+
+/*
+ * Definitions to access the CPM Timer registers
+ * See 8xx_immap.h for Internal Memory Map layout,
+ * and commproc.h for CPM Interrupt vectors (aka "IRQ"s)
+ */
+
+typedef struct tid_8xx_cpmtimer_s {
+  bd_t         *bd;            /* Pointer to Board Info data           */
+  int           cpm_vec;       /* CPM Interrupt Vector for this timer  */
+  ushort       *tgcrp;         /* Pointer to Timer Global Config Reg.  */
+  ushort       *tmrp;          /* Pointer to Timer Mode Register       */
+  ushort       *trrp;          /* Pointer to Timer Reference Register  */
+  ushort       *tcrp;          /* Pointer to Timer Capture Register    */
+  ushort       *tcnp;          /* Pointer to Timer Counter Register    */
+  ushort       *terp;          /* Pointer to Timer Event Register      */
+} tid_8xx_cpmtimer_t;
+
+#ifndef CLOCKRATE
+#  define CLOCKRATE 64
+#endif
+
+#define        CPMT_CLOCK_DIV          16
+#define        CPMT_MAX_PRESCALER      256
+#define CPMT_MAX_REFERENCE     65535   /* max. unsigned short */
+
+#define        CPMT_MAX_TICKS          (CPMT_MAX_REFERENCE * CPMT_MAX_PRESCALER)
+#define        CPMT_MAX_TICKS_WITH_DIV (CPMT_MAX_REFERENCE * CPMT_MAX_PRESCALER * CPMT_CLOCK_DIV)
+#define        CPMT_MAX_INTERVAL       (CPMT_MAX_TICKS_WITH_DIV / CLOCKRATE)
+
+/* For now: always use max. prescaler value */
+#define        CPMT_PRESCALER          (CPMT_MAX_PRESCALER)
+
+/* CPM Timer Event Register Bits */
+#define        CPMT_EVENT_CAP          0x0001  /* Capture Event                */
+#define        CPMT_EVENT_REF          0x0002  /* Reference Counter Event      */
+
+/* CPM Timer Global Config Register */
+#define        CPMT_GCR_RST            0x0001  /* Reset  Timer                 */
+#define        CPMT_GCR_STP            0x0002  /* Stop   Timer                 */
+#define        CPMT_GCR_FRZ            0x0004  /* Freeze Timer                 */
+#define        CPMT_GCR_GM_CAS         0x0008  /* Gate Mode / Cascade Timers   */
+#define        CPMT_GCR_MASK           (CPMT_GCR_RST|CPMT_GCR_STP|CPMT_GCR_FRZ|CPMT_GCR_GM_CAS)
+
+/* CPM Timer Mode register */
+#define        CPMT_MR_GE              0x0001  /* Gate Enable                  */
+#define        CPMT_MR_ICLK_CASC       0x0000  /* Clock internally cascaded    */
+#define        CPMT_MR_ICLK_CLK        0x0002  /* Clock = system clock         */
+#define        CPMT_MR_ICLK_CLKDIV     0x0004  /* Clock = system clock / 16    */
+#define        CPMT_MR_ICLK_TIN        0x0006  /* Clock = TINx signal          */
+#define        CPMT_MR_FRR             0x0008  /* Free Run / Restart           */
+#define        CPMT_MR_ORI             0x0010  /* Out. Reference Interrupt En. */
+#define        CPMT_MR_OM              0x0020  /* Output Mode                  */
+#define        CPMT_MR_CE_DIS          0x0000  /* Capture/Interrupt disabled   */
+#define        CPMT_MR_CE_RISE         0x0040  /* Capt./Interr. on rising  TIN */
+#define CPMT_MR_CE_FALL                0x0080  /* Capt./Interr. on falling TIN */
+#define        CPMT_MR_CE_ANY          0x00C0  /* Capt./Interr. on any TIN edge*/
+
+
+
+/*
+ * which CPM timer to use - index starts at 0 (= timer 1)
+ */
+#define        TID_TIMER_ID    0       /* use CPM timer 1              */
+
+
+#define        MON_PRINT(fmt,args...)  \
+       (*(void (*)(const char *, ...))(bd->bi_serial_io.printf)) (fmt ,##args)
+
+#define MON_GETC               \
+       (*(int (*)(void))(bd->bi_serial_io.getc))
+
+#define MON_TSTC               \
+       (*(int (*)(void))(bd->bi_serial_io.tstc))
+
+#define MON_INSTALL_HANDLER    \
+       (*(int (*)(int, void (*)(void *), void *))(bd->bi_interrupt.install_hdlr))
+
+#define MON_FREE_HANDLER       \
+       (*(int (*)(int))(bd->bi_interrupt.free_hdlr))
+
+void setPeriod (bd_t * bd, tid_8xx_cpmtimer_t *hwp, ulong interval);
+
+static char *usage = "\n[q, b, e, ?] ";
+
+int timer (bd_t * bd, int argc, char *argv[])
+{
+       cpmtimer8xx_t *cpmtimerp;       /* Pointer to the CPM Timer structure   */
+       tid_8xx_cpmtimer_t hw;
+       tid_8xx_cpmtimer_t *hwp = &hw;
+       int c;
+
+       /* Pointer to CPM Timer structure */
+       cpmtimerp = &((immap_t *) bd->bi_immr_base)->im_cpmtimer;
+
+       MON_PRINT ("TIMERS=0x%x\n", (unsigned) cpmtimerp);
+
+       hwp->bd = bd;
+
+       /* Initialize pointers depending on which timer we use */
+       switch (TID_TIMER_ID) {
+       case 0:
+               hwp->tmrp = &(cpmtimerp->cpmt_tmr1);
+               hwp->trrp = &(cpmtimerp->cpmt_trr1);
+               hwp->tcrp = &(cpmtimerp->cpmt_tcr1);
+               hwp->tcnp = &(cpmtimerp->cpmt_tcn1);
+               hwp->terp = &(cpmtimerp->cpmt_ter1);
+               hwp->cpm_vec = CPMVEC_TIMER1;
+               break;
+       case 1:
+               hwp->tmrp = &(cpmtimerp->cpmt_tmr2);
+               hwp->trrp = &(cpmtimerp->cpmt_trr2);
+               hwp->tcrp = &(cpmtimerp->cpmt_tcr2);
+               hwp->tcnp = &(cpmtimerp->cpmt_tcn2);
+               hwp->terp = &(cpmtimerp->cpmt_ter2);
+               hwp->cpm_vec = CPMVEC_TIMER2;
+               break;
+       case 2:
+               hwp->tmrp = &(cpmtimerp->cpmt_tmr3);
+               hwp->trrp = &(cpmtimerp->cpmt_trr3);
+               hwp->tcrp = &(cpmtimerp->cpmt_tcr3);
+               hwp->tcnp = &(cpmtimerp->cpmt_tcn3);
+               hwp->terp = &(cpmtimerp->cpmt_ter3);
+               hwp->cpm_vec = CPMVEC_TIMER3;
+               break;
+       case 3:
+               hwp->tmrp = &(cpmtimerp->cpmt_tmr4);
+               hwp->trrp = &(cpmtimerp->cpmt_trr4);
+               hwp->tcrp = &(cpmtimerp->cpmt_tcr4);
+               hwp->tcnp = &(cpmtimerp->cpmt_tcn4);
+               hwp->terp = &(cpmtimerp->cpmt_ter4);
+               hwp->cpm_vec = CPMVEC_TIMER4;
+               break;
+       }
+
+       hwp->tgcrp = &cpmtimerp->cpmt_tgcr;
+
+       MON_PRINT ("Using timer %d\n"
+                       "  tgcr @ 0x%x, tmr @ 0x%x, trr @ 0x%x,"
+                       " tcr @ 0x%x, tcn @ 0x%x, ter @ 0x%x\n",
+                       TID_TIMER_ID + 1,
+                       (unsigned) hwp->tgcrp,
+                       (unsigned) hwp->tmrp,
+                       (unsigned) hwp->trrp,
+                       (unsigned) hwp->tcrp,
+                       (unsigned) hwp->tcnp,
+                       (unsigned) hwp->terp
+                       );
+
+       /* reset timer    */
+       *hwp->tgcrp &= ~(CPMT_GCR_MASK << TID_TIMER_ID);
+
+       /* clear all events */
+       *hwp->terp = (CPMT_EVENT_CAP | CPMT_EVENT_REF);
+
+       MON_PRINT(usage);
+       while ((c = MON_GETC()) != 'q') {
+           if (c == 'b') {
+
+               setPeriod (bd, hwp, TIMER_PERIOD);      /* Set period and start ticking */
+
+               /* Install interrupt handler (enable timer in CIMR) */
+               MON_INSTALL_HANDLER (hwp->cpm_vec, timer_handler, hwp);
+
+               MON_PRINT ("Enabling timer\n");
+
+               /* enable timer */
+               *hwp->tgcrp |= (CPMT_GCR_RST << TID_TIMER_ID);
+
+#ifdef DEBUG
+               MON_PRINT ("  tgcr=0x%x, tmr=0x%x, trr=0x%x,"
+                       " tcr=0x%x, tcn=0x%x, ter=0x%x\n",
+                               *hwp->tgcrp, *hwp->tmrp, *hwp->trrp,
+                               *hwp->tcrp,  *hwp->tcnp, *hwp->terp
+                               );
+#endif
+           } else if (c == 'e') {
+
+               MON_PRINT ("Stopping timer\n");
+
+               *hwp->tgcrp &= ~(CPMT_GCR_MASK << TID_TIMER_ID);
+
+#ifdef DEBUG
+               MON_PRINT ("  tgcr=0x%x, tmr=0x%x, trr=0x%x,"
+                       " tcr=0x%x, tcn=0x%x, ter=0x%x\n",
+                               *hwp->tgcrp, *hwp->tmrp, *hwp->trrp,
+                               *hwp->tcrp,  *hwp->tcnp, *hwp->terp
+                       );
+#endif
+               /* Uninstall interrupt handler */
+               MON_FREE_HANDLER (hwp->cpm_vec);
+
+           } else if (c == '?') {
+#ifdef DEBUG
+               cpic8xx_t *cpm_icp = &((immap_t *) bd->bi_immr_base)->im_cpic;
+               sysconf8xx_t *siup = &((immap_t *) bd->bi_immr_base)->im_siu_conf;
+#endif
+
+               MON_PRINT ("\ntgcr=0x%x, tmr=0x%x, trr=0x%x,"
+                       " tcr=0x%x, tcn=0x%x, ter=0x%x\n",
+                               *hwp->tgcrp, *hwp->tmrp, *hwp->trrp,
+                               *hwp->tcrp,  *hwp->tcnp, *hwp->terp
+                       );
+#ifdef DEBUG
+               MON_PRINT ("SIUMCR=0x%08lx, SYPCR=0x%08lx,"
+                       " SIMASK=0x%08lx, SIPEND=0x%08lx\n",
+                               siup->sc_siumcr,
+                               siup->sc_sypcr,
+                               siup->sc_simask,
+                               siup->sc_sipend
+                       );
+
+               MON_PRINT ("CIMR=0x%08lx, CICR=0x%08lx, CIPR=0x%08lx\n",
+                       cpm_icp->cpic_cimr,
+                       cpm_icp->cpic_cicr,
+                       cpm_icp->cpic_cipr
+                       );
+#endif
+           } else {
+               MON_PRINT ("\nEnter: q - quit, b - start timer, e - stop timer, ? - get status\n");
+           }
+           MON_PRINT(usage);
+       }
+       return (0);
+}
+
+
+/* Set period in microseconds and start.
+ * Truncate to maximum period if more than this is requested - but warn about it.
+ */
+
+void setPeriod (bd_t * bd, tid_8xx_cpmtimer_t *hwp, ulong interval)
+{
+       unsigned short prescaler;
+       unsigned long ticks;
+
+       MON_PRINT ("Set interval %ld us\n", interval);
+
+       /* Warn if requesting longer period than possible */
+       if (interval > CPMT_MAX_INTERVAL) {
+               MON_PRINT ("Truncate interval %ld to maximum (%d)\n",
+                               interval, CPMT_MAX_INTERVAL);
+               interval = CPMT_MAX_INTERVAL;
+       }
+       /*
+        * Check if we want to use clock divider:
+        * Since the reference counter can be incremented only in integer steps,
+        * we try to keep it as big as possible to allow the resulting period to be
+        * as precise as possible.
+        */
+       /* prescaler, enable interrupt, restart after ref count is reached */
+       prescaler = (ushort) ((CPMT_PRESCALER - 1) << 8) |
+                       CPMT_MR_ORI |
+                       CPMT_MR_FRR;
+
+       ticks = ((ulong) CLOCKRATE * interval);
+
+       if (ticks > CPMT_MAX_TICKS) {
+               ticks /= CPMT_CLOCK_DIV;
+               prescaler |= CPMT_MR_ICLK_CLKDIV;       /* use system clock divided by 16 */
+       } else {
+               prescaler |= CPMT_MR_ICLK_CLK;  /* use system clock without divider */
+       }
+
+#ifdef DEBUG
+       MON_PRINT ("clock/%d, prescale factor %d, reference %ld, ticks %ld\n",
+                       (ticks > CPMT_MAX_TICKS) ? CPMT_CLOCK_DIV : 1,
+                       CPMT_PRESCALER,
+                       (ticks / CPMT_PRESCALER),
+                       ticks
+                       );
+#endif
+
+       /* set prescaler register */
+       *hwp->tmrp = prescaler;
+
+       /* clear timer counter */
+       *hwp->tcnp = 0;
+
+       /* set reference register */
+       *hwp->trrp = (unsigned short) (ticks / CPMT_PRESCALER);
+
+#ifdef DEBUG
+       MON_PRINT ("  tgcr=0x%x, tmr=0x%x, trr=0x%x,"
+               " tcr=0x%x, tcn=0x%x, ter=0x%x\n",
+                       *hwp->tgcrp, *hwp->tmrp, *hwp->trrp,
+                       *hwp->tcrp,  *hwp->tcnp, *hwp->terp
+               );
+#endif
+}
+
+/*
+ * Handler for CPMVEC_TIMER1 interrupt
+ */
+static
+void timer_handler (void *arg)
+{
+       tid_8xx_cpmtimer_t *hwp = (tid_8xx_cpmtimer_t *)arg;
+       bd_t *bd = hwp->bd;
+       
+       /* printf ("** TER1=%04x ** ", *hwp->terp); */
+
+       /* just for demonstration */
+       MON_PRINT (".");
+
+       /* clear all possible events: Ref. and Cap. */
+       *hwp->terp = (CPMT_EVENT_CAP | CPMT_EVENT_REF);
+}
diff --git a/include/asm/8xx_immap.h b/include/asm/8xx_immap.h
new file mode 100644 (file)
index 0000000..0223fe2
--- /dev/null
@@ -0,0 +1,455 @@
+
+/*
+ * MPC8xx Internal Memory Map
+ * Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
+ *
+ * The I/O on the MPC860 is comprised of blocks of special registers
+ * and the dual port ram for the Communication Processor Module.
+ * Within this space are functional units such as the SIU, memory
+ * controller, system timers, and other control functions.  It is
+ * a combination that I found difficult to separate into logical
+ * functional files.....but anyone else is welcome to try.  -- Dan
+ */
+#ifndef __IMMAP_8XX__
+#define __IMMAP_8XX__
+
+/* System configuration registers.
+*/
+typedef        struct sys_conf {
+       uint    sc_siumcr;
+       uint    sc_sypcr;
+       uint    sc_swt;
+       char    res1[2];
+       ushort  sc_swsr;
+       uint    sc_sipend;
+       uint    sc_simask;
+       uint    sc_siel;
+       uint    sc_sivec;
+       uint    sc_tesr;
+       char    res2[0xc];
+       uint    sc_sdcr;
+       char    res3[0x4c];
+} sysconf8xx_t;
+
+/* PCMCIA configuration registers.
+*/
+typedef struct pcmcia_conf {
+       uint    pcmc_pbr0;
+       uint    pcmc_por0;
+       uint    pcmc_pbr1;
+       uint    pcmc_por1;
+       uint    pcmc_pbr2;
+       uint    pcmc_por2;
+       uint    pcmc_pbr3;
+       uint    pcmc_por3;
+       uint    pcmc_pbr4;
+       uint    pcmc_por4;
+       uint    pcmc_pbr5;
+       uint    pcmc_por5;
+       uint    pcmc_pbr6;
+       uint    pcmc_por6;
+       uint    pcmc_pbr7;
+       uint    pcmc_por7;
+       char    res1[0x20];
+       uint    pcmc_pgcra;
+       uint    pcmc_pgcrb;
+       uint    pcmc_pscr;
+       char    res2[4];
+       uint    pcmc_pipr;
+       char    res3[4];
+       uint    pcmc_per;
+       char    res4[4];
+} pcmconf8xx_t;
+
+/* Memory controller registers.
+*/
+typedef struct mem_ctlr {
+       uint    memc_br0;
+       uint    memc_or0;
+       uint    memc_br1;
+       uint    memc_or1;
+       uint    memc_br2;
+       uint    memc_or2;
+       uint    memc_br3;
+       uint    memc_or3;
+       uint    memc_br4;
+       uint    memc_or4;
+       uint    memc_br5;
+       uint    memc_or5;
+       uint    memc_br6;
+       uint    memc_or6;
+       uint    memc_br7;
+       uint    memc_or7;
+       char    res1[0x24];
+       uint    memc_mar;
+       uint    memc_mcr;
+       char    res2[4];
+       uint    memc_mamr;
+       uint    memc_mbmr;
+       ushort  memc_mstat;
+       ushort  memc_mptpr;
+       uint    memc_mdr;
+       char    res3[0x80];
+} memctl8xx_t;
+
+/* System Integration Timers.
+*/
+typedef struct sys_int_timers {
+       ushort  sit_tbscr;
+       uint    sit_tbreff0;
+       uint    sit_tbreff1;
+       char    res1[0x14];
+       ushort  sit_rtcsc;
+       uint    sit_rtc;
+       uint    sit_rtsec;
+       uint    sit_rtcal;
+       char    res2[0x10];
+       ushort  sit_piscr;
+       char    res3[2];
+       uint    sit_pitc;
+       uint    sit_pitr;
+       char    res4[0x34];
+} sit8xx_t;
+
+#define TBSCR_TBIRQ_MASK       ((ushort)0xff00)
+#define TBSCR_REFA             ((ushort)0x0080)
+#define TBSCR_REFB             ((ushort)0x0040)
+#define TBSCR_REFAE            ((ushort)0x0008)
+#define TBSCR_REFBE            ((ushort)0x0004)
+#define TBSCR_TBF              ((ushort)0x0002)
+#define TBSCR_TBE              ((ushort)0x0001)
+
+#define RTCSC_RTCIRQ_MASK      ((ushort)0xff00)
+#define RTCSC_SEC              ((ushort)0x0080)
+#define RTCSC_ALR              ((ushort)0x0040)
+#define RTCSC_38K              ((ushort)0x0010)
+#define RTCSC_SIE              ((ushort)0x0008)
+#define RTCSC_ALE              ((ushort)0x0004)
+#define RTCSC_RTF              ((ushort)0x0002)
+#define RTCSC_RTE              ((ushort)0x0001)
+
+#define PISCR_PIRQ_MASK                ((ushort)0xff00)
+#define PISCR_PS               ((ushort)0x0080)
+#define PISCR_PIE              ((ushort)0x0004)
+#define PISCR_PTF              ((ushort)0x0002)
+#define PISCR_PTE              ((ushort)0x0001)
+
+/* Clocks and Reset.
+*/
+typedef struct clk_and_reset {
+       uint    car_sccr;
+       uint    car_plprcr;
+       uint    car_rsr;
+       char    res[0x74];        /* Reserved area                  */
+} car8xx_t;
+
+/* System Integration Timers keys.
+*/
+typedef struct sitk {
+       uint    sitk_tbscrk;
+       uint    sitk_tbreff0k;
+       uint    sitk_tbreff1k;
+       uint    sitk_tbk;
+       char    res1[0x10];
+       uint    sitk_rtcsck;
+       uint    sitk_rtck;
+       uint    sitk_rtseck;
+       uint    sitk_rtcalk;
+       char    res2[0x10];
+       uint    sitk_piscrk;
+       uint    sitk_pitck;
+       char    res3[0x38];
+} sitk8xx_t;
+
+/* Clocks and reset keys.
+*/
+typedef struct cark {
+       uint    cark_sccrk;
+       uint    cark_plprcrk;
+       uint    cark_rsrk;
+       char    res[0x474];
+} cark8xx_t;
+
+/* The key to unlock registers maintained by keep-alive power.
+*/
+#define KAPWR_KEY      ((unsigned int)0x55ccaa33)
+
+/* LCD interface.  MPC821 Only.
+*/
+typedef struct lcd {
+       ushort  lcd_lcolr[16];
+       char    res[0x20];
+       uint    lcd_lccr;
+       uint    lcd_lchcr;
+       uint    lcd_lcvcr;
+       char    res2[4];
+       uint    lcd_lcfaa;
+       uint    lcd_lcfba;
+       char    lcd_lcsr;
+       char    res3[0x7];
+} lcd8xx_t;
+
+/* I2C
+*/
+typedef struct i2c {
+       u_char  i2c_i2mod;
+       char    res1[3];
+       u_char  i2c_i2add;
+       char    res2[3];
+       u_char  i2c_i2brg;
+       char    res3[3];
+       u_char  i2c_i2com;
+       char    res4[3];
+       u_char  i2c_i2cer;
+       char    res5[3];
+       u_char  i2c_i2cmr;
+       char    res6[0x8b];
+} i2c8xx_t;
+
+/* DMA control/status registers.
+*/
+typedef struct sdma_csr {
+       char    res1[4];
+       uint    sdma_sdar;
+       u_char  sdma_sdsr;
+       char    res3[3];
+       u_char  sdma_sdmr;
+       char    res4[3];
+       u_char  sdma_idsr1;
+       char    res5[3];
+       u_char  sdma_idmr1;
+       char    res6[3];
+       u_char  sdma_idsr2;
+       char    res7[3];
+       u_char  sdma_idmr2;
+       char    res8[0x13];
+} sdma8xx_t;
+
+/* Communication Processor Module Interrupt Controller.
+*/
+typedef struct cpm_ic {
+       ushort  cpic_civr;
+       char    res[0xe];
+       uint    cpic_cicr;
+       uint    cpic_cipr;
+       uint    cpic_cimr;
+       uint    cpic_cisr;
+} cpic8xx_t;
+
+/* Input/Output Port control/status registers.
+*/
+typedef struct io_port {
+       ushort  iop_padir;
+       ushort  iop_papar;
+       ushort  iop_paodr;
+       ushort  iop_padat;
+       char    res1[8];
+       ushort  iop_pcdir;
+       ushort  iop_pcpar;
+       ushort  iop_pcso;
+       ushort  iop_pcdat;
+       ushort  iop_pcint;
+       char    res2[6];
+       ushort  iop_pddir;
+       ushort  iop_pdpar;
+       char    res3[2];
+       ushort  iop_pddat;
+       char    res4[8];
+} iop8xx_t;
+
+/* Communication Processor Module Timers
+*/
+typedef struct cpm_timers {
+       ushort  cpmt_tgcr;
+       char    res1[0xe];
+       ushort  cpmt_tmr1;
+       ushort  cpmt_tmr2;
+       ushort  cpmt_trr1;
+       ushort  cpmt_trr2;
+       ushort  cpmt_tcr1;
+       ushort  cpmt_tcr2;
+       ushort  cpmt_tcn1;
+       ushort  cpmt_tcn2;
+       ushort  cpmt_tmr3;
+       ushort  cpmt_tmr4;
+       ushort  cpmt_trr3;
+       ushort  cpmt_trr4;
+       ushort  cpmt_tcr3;
+       ushort  cpmt_tcr4;
+       ushort  cpmt_tcn3;
+       ushort  cpmt_tcn4;
+       ushort  cpmt_ter1;
+       ushort  cpmt_ter2;
+       ushort  cpmt_ter3;
+       ushort  cpmt_ter4;
+       char    res2[8];
+} cpmtimer8xx_t;
+
+/* Finally, the Communication Processor stuff.....
+*/
+typedef struct scc {           /* Serial communication channels */
+       uint    scc_gsmrl;
+       uint    scc_gsmrh;
+       ushort  scc_pmsr;
+       char    res1[2];
+       ushort  scc_todr;
+       ushort  scc_dsr;
+       ushort  scc_scce;
+       char    res2[2];
+       ushort  scc_sccm;
+       char    res3;
+       u_char  scc_sccs;
+       char    res4[8];
+} scc_t;
+
+typedef struct smc {           /* Serial management channels */
+       char    res1[2];
+       ushort  smc_smcmr;
+       char    res2[2];
+       u_char  smc_smce;
+       char    res3[3];
+       u_char  smc_smcm;
+       char    res4[5];
+} smc_t;
+
+/* MPC860T Fast Ethernet Controller.  It isn't part of the CPM, but
+ * it fits within the address space.
+ */
+typedef struct fec {
+       uint    fec_addr_low;           /* LS 32 bits of station address */
+       ushort  fec_addr_high;          /* MS 16 bits of address */
+       ushort  res1;
+       uint    fec_hash_table_high;
+       uint    fec_hash_table_low;
+       uint    fec_r_des_start;
+       uint    fec_x_des_start;
+       uint    fec_r_buff_size;
+       uint    res2[9];
+       uint    fec_ecntrl;
+       uint    fec_ievent;
+       uint    fec_imask;
+       uint    fec_ivec;
+       uint    fec_r_des_active;
+       uint    fec_x_des_active;
+       uint    res3[10];
+       uint    fec_mii_data;
+       uint    fec_mii_speed;
+       uint    res4[17];
+       uint    fec_r_bound;
+       uint    fec_r_fstart;
+       uint    res5[6];
+       uint    fec_x_fstart;
+       uint    res6[17];
+       uint    fec_fun_code;
+       uint    res7[3];
+       uint    fec_r_cntrl;
+       uint    fec_r_hash;
+       uint    res8[14];
+       uint    fec_x_cntrl;
+       uint    res9[0x1e];
+} fec_t;
+
+typedef struct comm_proc {
+       /* General control and status registers.
+       */
+       ushort  cp_cpcr;
+       char    res1[2];
+       ushort  cp_rccr;
+       char    res2[6];
+       ushort  cp_cpmcr1;
+       ushort  cp_cpmcr2;
+       ushort  cp_cpmcr3;
+       ushort  cp_cpmcr4;
+       char    res3[2];
+       ushort  cp_rter;
+       char    res4[2];
+       ushort  cp_rtmr;
+       char    res5[0x14];
+
+       /* Baud rate generators.
+       */
+       uint    cp_brgc1;
+       uint    cp_brgc2;
+       uint    cp_brgc3;
+       uint    cp_brgc4;
+
+       /* Serial Communication Channels.
+       */
+       scc_t   cp_scc[4];
+
+       /* Serial Management Channels.
+       */
+       smc_t   cp_smc[2];
+
+       /* Serial Peripheral Interface.
+       */
+       ushort  cp_spmode;
+       char    res6[4];
+       u_char  cp_spie;
+       char    res7[3];
+       u_char  cp_spim;
+       char    res8[2];
+       u_char  cp_spcom;
+       char    res9[2];
+
+       /* Parallel Interface Port.
+       */
+       char    res10[2];
+       ushort  cp_pipc;
+       char    res11[2];
+       ushort  cp_ptpr;
+       uint    cp_pbdir;
+       uint    cp_pbpar;
+       char    res12[2];
+       ushort  cp_pbodr;
+       uint    cp_pbdat;
+       char    res13[0x18];
+
+       /* Serial Interface and Time Slot Assignment.
+       */
+       uint    cp_simode;
+       u_char  cp_sigmr;
+       char    res14;
+       u_char  cp_sistr;
+       u_char  cp_sicmr;
+       char    res15[4];
+       uint    cp_sicr;
+       uint    cp_sirp;
+       char    res16[0x10c];
+       u_char  cp_siram[0x200];
+
+       /* The fast ethernet controller is not really part of the CPM,
+        * but it resides in the address space.
+        */
+       fec_t   cp_fec;
+       char    res18[0x1000];
+
+       /* Dual Ported RAM follows.
+        * There are many different formats for this memory area
+        * depending upon the devices used and options chosen.
+        */
+       u_char  cp_dpmem[0x1000];       /* BD / Data / ucode */
+       u_char  res19[0xc00];
+       u_char  cp_dparam[0x400];       /* Parameter RAM */
+} cpm8xx_t;
+
+/* Internal memory map.
+*/
+typedef struct immap {
+       sysconf8xx_t    im_siu_conf;    /* SIU Configuration */
+       pcmconf8xx_t    im_pcmcia;      /* PCMCIA Configuration */
+       memctl8xx_t     im_memctl;      /* Memory Controller */
+       sit8xx_t        im_sit;         /* System integration timers */
+       car8xx_t        im_clkrst;      /* Clocks and reset */
+       sitk8xx_t       im_sitk;        /* Sys int timer keys */
+       cark8xx_t       im_clkrstk;     /* Clocks and reset keys */
+       lcd8xx_t        im_lcd;         /* LCD (821 only) */
+       i2c8xx_t        im_i2c;         /* I2C control/status */
+       sdma8xx_t       im_sdma;        /* SDMA control/status */
+       cpic8xx_t       im_cpic;        /* CPM Interrupt Controller */
+       iop8xx_t        im_ioport;      /* IO Port control/status */
+       cpmtimer8xx_t   im_cpmtimer;    /* CPM timers */
+       cpm8xx_t        im_cpm;         /* Communication processor */
+} immap_t;
+
+#endif /* __IMMAP_8XX__ */
diff --git a/include/asm/mmu.h b/include/asm/mmu.h
new file mode 100644 (file)
index 0000000..4a3a42f
--- /dev/null
@@ -0,0 +1,365 @@
+/*
+ * PowerPC memory management structures
+ */
+
+#ifndef _PPC_MMU_H_
+#define _PPC_MMU_H_
+
+#include <linux/config.h>
+
+#ifndef __ASSEMBLY__
+/* Hardware Page Table Entry */
+typedef struct _PTE {
+#ifdef CONFIG_PPC64BRIDGE
+       unsigned long long vsid:52;
+       unsigned long api:5;
+       unsigned long :5;
+       unsigned long h:1;
+       unsigned long v:1;
+       unsigned long long rpn:52;
+#else /* CONFIG_PPC64BRIDGE */
+       unsigned long v:1;      /* Entry is valid */
+       unsigned long vsid:24;  /* Virtual segment identifier */
+       unsigned long h:1;      /* Hash algorithm indicator */
+       unsigned long api:6;    /* Abbreviated page index */
+       unsigned long rpn:20;   /* Real (physical) page number */
+#endif /* CONFIG_PPC64BRIDGE */
+       unsigned long    :3;    /* Unused */
+       unsigned long r:1;      /* Referenced */
+       unsigned long c:1;      /* Changed */
+       unsigned long w:1;      /* Write-thru cache mode */
+       unsigned long i:1;      /* Cache inhibited */
+       unsigned long m:1;      /* Memory coherence */
+       unsigned long g:1;      /* Guarded */
+       unsigned long  :1;      /* Unused */
+       unsigned long pp:2;     /* Page protection */
+} PTE; 
+
+/* Values for PP (assumes Ks=0, Kp=1) */
+#define PP_RWXX        0       /* Supervisor read/write, User none */
+#define PP_RWRX 1      /* Supervisor read/write, User read */
+#define PP_RWRW 2      /* Supervisor read/write, User read/write */
+#define PP_RXRX 3      /* Supervisor read,       User read */
+
+/* Segment Register */
+typedef struct _SEGREG {
+       unsigned long t:1;      /* Normal or I/O  type */
+       unsigned long ks:1;     /* Supervisor 'key' (normally 0) */
+       unsigned long kp:1;     /* User 'key' (normally 1) */
+       unsigned long n:1;      /* No-execute */
+       unsigned long :4;       /* Unused */
+       unsigned long vsid:24;  /* Virtual Segment Identifier */
+} SEGREG;
+
+/* Block Address Translation (BAT) Registers */
+typedef struct _P601_BATU {    /* Upper part of BAT for 601 processor */
+       unsigned long bepi:15;  /* Effective page index (virtual address) */
+       unsigned long :8;       /* unused */
+       unsigned long w:1;
+       unsigned long i:1;      /* Cache inhibit */
+       unsigned long m:1;      /* Memory coherence */
+       unsigned long ks:1;     /* Supervisor key (normally 0) */
+       unsigned long kp:1;     /* User key (normally 1) */
+       unsigned long pp:2;     /* Page access protections */
+} P601_BATU;
+
+typedef struct _BATU {         /* Upper part of BAT (all except 601) */
+#ifdef CONFIG_PPC64BRIDGE
+       unsigned long long bepi:47;
+#else /* CONFIG_PPC64BRIDGE */
+       unsigned long bepi:15;  /* Effective page index (virtual address) */
+#endif /* CONFIG_PPC64BRIDGE */
+       unsigned long :4;       /* Unused */
+       unsigned long bl:11;    /* Block size mask */
+       unsigned long vs:1;     /* Supervisor valid */
+       unsigned long vp:1;     /* User valid */
+} BATU;   
+
+typedef struct _P601_BATL {    /* Lower part of BAT for 601 processor */
+       unsigned long brpn:15;  /* Real page index (physical address) */
+       unsigned long :10;      /* Unused */
+       unsigned long v:1;      /* Valid bit */
+       unsigned long bl:6;     /* Block size mask */
+} P601_BATL;
+
+typedef struct _BATL {         /* Lower part of BAT (all except 601) */
+#ifdef CONFIG_PPC64BRIDGE
+       unsigned long long brpn:47;
+#else /* CONFIG_PPC64BRIDGE */
+       unsigned long brpn:15;  /* Real page index (physical address) */
+#endif /* CONFIG_PPC64BRIDGE */
+       unsigned long :10;      /* Unused */
+       unsigned long w:1;      /* Write-thru cache */
+       unsigned long i:1;      /* Cache inhibit */
+       unsigned long m:1;      /* Memory coherence */
+       unsigned long g:1;      /* Guarded (MBZ in IBAT) */
+       unsigned long :1;       /* Unused */
+       unsigned long pp:2;     /* Page access protections */
+} BATL;
+
+typedef struct _BAT {
+       BATU batu;              /* Upper register */
+       BATL batl;              /* Lower register */
+} BAT;
+
+typedef struct _P601_BAT {
+       P601_BATU batu;         /* Upper register */
+       P601_BATL batl;         /* Lower register */
+} P601_BAT;
+
+/*
+ * Simulated two-level MMU.  This structure is used by the kernel
+ * to keep track of MMU mappings and is used to update/maintain
+ * the hardware HASH table which is really a cache of mappings.
+ *
+ * The simulated structures mimic the hardware available on other
+ * platforms, notably the 80x86 and 680x0.
+ */
+
+typedef struct _pte {
+       unsigned long page_num:20;
+       unsigned long flags:12;         /* Page flags (some unused bits) */
+} pte;
+
+#define PD_SHIFT (10+12)               /* Page directory */
+#define PD_MASK  0x02FF
+#define PT_SHIFT (12)                  /* Page Table */
+#define PT_MASK  0x02FF
+#define PG_SHIFT (12)                  /* Page Entry */
+
+/* MMU context */
+
+typedef struct _MMU_context {
+       SEGREG  segs[16];       /* Segment registers */
+       pte     **pmap;         /* Two-level page-map structure */
+} MMU_context;
+
+extern void _tlbie(unsigned long va);  /* invalidate a TLB entry */
+extern void _tlbia(void);              /* invalidate all TLB entries */
+
+#endif /* __ASSEMBLY__ */
+
+/* Block size masks */
+#define BL_128K        0x000
+#define BL_256K 0x001
+#define BL_512K 0x003
+#define BL_1M   0x007
+#define BL_2M   0x00F
+#define BL_4M   0x01F
+#define BL_8M   0x03F
+#define BL_16M  0x07F
+#define BL_32M  0x0FF
+#define BL_64M  0x1FF
+#define BL_128M 0x3FF
+#define BL_256M 0x7FF
+
+/* BAT Access Protection */
+#define BPP_XX 0x00            /* No access */
+#define BPP_RX 0x01            /* Read only */
+#define BPP_RW 0x02            /* Read/write */
+
+/* Used to set up SDR1 register */
+#define HASH_TABLE_SIZE_64K    0x00010000
+#define HASH_TABLE_SIZE_128K   0x00020000
+#define HASH_TABLE_SIZE_256K   0x00040000
+#define HASH_TABLE_SIZE_512K   0x00080000
+#define HASH_TABLE_SIZE_1M     0x00100000
+#define HASH_TABLE_SIZE_2M     0x00200000
+#define HASH_TABLE_SIZE_4M     0x00400000
+#define HASH_TABLE_MASK_64K    0x000   
+#define HASH_TABLE_MASK_128K   0x001   
+#define HASH_TABLE_MASK_256K   0x003   
+#define HASH_TABLE_MASK_512K   0x007
+#define HASH_TABLE_MASK_1M     0x00F   
+#define HASH_TABLE_MASK_2M     0x01F   
+#define HASH_TABLE_MASK_4M     0x03F   
+
+/* Control/status registers for the MPC8xx.
+ * A write operation to these registers causes serialized access.
+ * During software tablewalk, the registers used perform mask/shift-add
+ * operations when written/read.  A TLB entry is created when the Mx_RPN
+ * is written, and the contents of several registers are used to
+ * create the entry.
+ */
+#define MI_CTR         784     /* Instruction TLB control register */
+#define MI_GPM         0x80000000      /* Set domain manager mode */
+#define MI_PPM         0x40000000      /* Set subpage protection */
+#define MI_CIDEF       0x20000000      /* Set cache inhibit when MMU dis */
+#define MI_RSV4I       0x08000000      /* Reserve 4 TLB entries */
+#define MI_PPCS                0x02000000      /* Use MI_RPN prob/priv state */
+#define MI_IDXMASK     0x00001f00      /* TLB index to be loaded */
+#define MI_RESETVAL    0x00000000      /* Value of register at reset */
+
+/* These are the Ks and Kp from the PowerPC books.  For proper operation,
+ * Ks = 0, Kp = 1.
+ */
+#define MI_AP          786
+#define MI_Ks          0x80000000      /* Should not be set */
+#define MI_Kp          0x40000000      /* Should always be set */
+
+/* The effective page number register.  When read, contains the information
+ * about the last instruction TLB miss.  When MI_RPN is written, bits in
+ * this register are used to create the TLB entry.
+ */
+#define MI_EPN         787
+#define MI_EPNMASK     0xfffff000      /* Effective page number for entry */
+#define MI_EVALID      0x00000200      /* Entry is valid */
+#define MI_ASIDMASK    0x0000000f      /* ASID match value */
+                                       /* Reset value is undefined */
+
+/* A "level 1" or "segment" or whatever you want to call it register.
+ * For the instruction TLB, it contains bits that get loaded into the
+ * TLB entry when the MI_RPN is written.
+ */
+#define MI_TWC         789
+#define MI_APG         0x000001e0      /* Access protection group (0) */
+#define MI_GUARDED     0x00000010      /* Guarded storage */
+#define MI_PSMASK      0x0000000c      /* Mask of page size bits */
+#define MI_PS8MEG      0x0000000c      /* 8M page size */
+#define MI_PS512K      0x00000004      /* 512K page size */
+#define MI_PS4K_16K    0x00000000      /* 4K or 16K page size */
+#define MI_SVALID      0x00000001      /* Segment entry is valid */
+                                       /* Reset value is undefined */
+
+/* Real page number.  Defined by the pte.  Writing this register
+ * causes a TLB entry to be created for the instruction TLB, using
+ * additional information from the MI_EPN, and MI_TWC registers.
+ */
+#define MI_RPN         790
+
+/* Define an RPN value for mapping kernel memory to large virtual
+ * pages for boot initialization.  This has real page number of 0,
+ * large page size, shared page, cache enabled, and valid.
+ * Also mark all subpages valid and write access.
+ */
+#define MI_BOOTINIT    0x000001fd
+
+#define MD_CTR         792     /* Data TLB control register */
+#define MD_GPM         0x80000000      /* Set domain manager mode */
+#define MD_PPM         0x40000000      /* Set subpage protection */
+#define MD_CIDEF       0x20000000      /* Set cache inhibit when MMU dis */
+#define MD_WTDEF       0x10000000      /* Set writethrough when MMU dis */
+#define MD_RSV4I       0x08000000      /* Reserve 4 TLB entries */
+#define MD_TWAM                0x04000000      /* Use 4K page hardware assist */
+#define MD_PPCS                0x02000000      /* Use MI_RPN prob/priv state */
+#define MD_IDXMASK     0x00001f00      /* TLB index to be loaded */
+#define MD_RESETVAL    0x04000000      /* Value of register at reset */
+
+#define M_CASID                793     /* Address space ID (context) to match */
+#define MC_ASIDMASK    0x0000000f      /* Bits used for ASID value */
+
+
+/* These are the Ks and Kp from the PowerPC books.  For proper operation,
+ * Ks = 0, Kp = 1.
+ */
+#define MD_AP          794
+#define MD_Ks          0x80000000      /* Should not be set */
+#define MD_Kp          0x40000000      /* Should always be set */
+
+/* The effective page number register.  When read, contains the information
+ * about the last instruction TLB miss.  When MD_RPN is written, bits in
+ * this register are used to create the TLB entry.
+ */
+#define MD_EPN         795
+#define MD_EPNMASK     0xfffff000      /* Effective page number for entry */
+#define MD_EVALID      0x00000200      /* Entry is valid */
+#define MD_ASIDMASK    0x0000000f      /* ASID match value */
+                                       /* Reset value is undefined */
+
+/* The pointer to the base address of the first level page table.
+ * During a software tablewalk, reading this register provides the address
+ * of the entry associated with MD_EPN.
+ */
+#define M_TWB          796
+#define        M_L1TB          0xfffff000      /* Level 1 table base address */
+#define M_L1INDX       0x00000ffc      /* Level 1 index, when read */
+                                       /* Reset value is undefined */
+
+/* A "level 1" or "segment" or whatever you want to call it register.
+ * For the data TLB, it contains bits that get loaded into the TLB entry
+ * when the MD_RPN is written.  It is also provides the hardware assist
+ * for finding the PTE address during software tablewalk.
+ */
+#define MD_TWC         797
+#define MD_L2TB                0xfffff000      /* Level 2 table base address */
+#define MD_L2INDX      0xfffffe00      /* Level 2 index (*pte), when read */
+#define MD_APG         0x000001e0      /* Access protection group (0) */
+#define MD_GUARDED     0x00000010      /* Guarded storage */
+#define MD_PSMASK      0x0000000c      /* Mask of page size bits */
+#define MD_PS8MEG      0x0000000c      /* 8M page size */
+#define MD_PS512K      0x00000004      /* 512K page size */
+#define MD_PS4K_16K    0x00000000      /* 4K or 16K page size */
+#define MD_WT          0x00000002      /* Use writethrough page attribute */
+#define MD_SVALID      0x00000001      /* Segment entry is valid */
+                                       /* Reset value is undefined */
+
+
+/* Real page number.  Defined by the pte.  Writing this register
+ * causes a TLB entry to be created for the data TLB, using
+ * additional information from the MD_EPN, and MD_TWC registers.
+ */
+#define MD_RPN         798
+
+/* This is a temporary storage register that could be used to save
+ * a processor working register during a tablewalk.
+ */
+#define M_TW           799
+
+/*
+ * At present, all PowerPC 400-class processors share a similar TLB
+ * architecture. The instruction and data sides share a unified,
+ * 64-entry, fully-associative TLB which is maintained totally under
+ * software control. In addition, the instruction side has a
+ * hardware-managed, 4-entry, fully- associative TLB which serves as a
+ * first level to the shared TLB. These two TLBs are known as the UTLB
+ * and ITLB, respectively.
+ */
+
+#define        PPC4XX_TLB_SIZE 64
+
+/*
+ * TLB entries are defined by a "high" tag portion and a "low" data
+ * portion.  On all architectures, the data portion is 32-bits.
+ *
+ * TLB entries are managed entirely under software control by reading,
+ * writing, and searchoing using the 4xx-specific tlbre, tlbwr, and tlbsx
+ * instructions.
+ */
+
+#define        TLB_LO          1
+#define        TLB_HI          0
+       
+#define        TLB_DATA        TLB_LO
+#define        TLB_TAG         TLB_HI
+
+/* Tag portion */
+
+#define TLB_EPN_MASK    0xFFFFFC00      /* Effective Page Number */
+#define TLB_PAGESZ_MASK 0x00000380
+#define TLB_PAGESZ(x)   (((x) & 0x7) << 7)
+#define   PAGESZ_1K            0
+#define   PAGESZ_4K             1
+#define   PAGESZ_16K            2
+#define   PAGESZ_64K            3
+#define   PAGESZ_256K           4
+#define   PAGESZ_1M             5
+#define   PAGESZ_4M             6
+#define   PAGESZ_16M            7
+#define TLB_VALID       0x00000040      /* Entry is valid */
+
+/* Data portion */
+                 
+#define TLB_RPN_MASK    0xFFFFFC00      /* Real Page Number */
+#define TLB_PERM_MASK   0x00000300
+#define TLB_EX          0x00000200      /* Instruction execution allowed */
+#define TLB_WR          0x00000100      /* Writes permitted */
+#define TLB_ZSEL_MASK   0x000000F0
+#define TLB_ZSEL(x)     (((x) & 0xF) << 4)
+#define TLB_ATTR_MASK   0x0000000F
+#define TLB_W           0x00000008      /* Caching is write-through */
+#define TLB_I           0x00000004      /* Caching is inhibited */
+#define TLB_M           0x00000002      /* Memory is coherent */
+#define TLB_G           0x00000001      /* Memory is guarded from prefetch */
+
+#endif /* _PPC_MMU_H_ */
diff --git a/include/cmd_boot.h b/include/cmd_boot.h
new file mode 100644 (file)
index 0000000..5fd8e1a
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * Boot support
+ */
+#ifndef        _CMD_BOOT_H
+#define        _CMD_BOOT_H
+
+#define        CMD_TBL_BDINFO  {                                                       \
+       "bdinfo",       2,      1,      do_bdinfo,                              \
+       "bdinfo  - print Board Info structure\n",                               \
+       NULL,                                                                   \
+}
+
+void do_bdinfo (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[]);
+
+#define CMD_TBL_GO     {                                                       \
+       "go",           2,      CFG_MAXARGS,    do_go,                          \
+       "go      - start application at address 'addr'\n",                      \
+       "addr [arg ...]\n    - start application at address 'addr'\n"           \
+       "      passing 'arg' as arguments\n",                                   \
+}
+
+void do_go (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[]);
+
+#define        CMD_TBL_LOADS   {                                                       \
+       "loads",        5,      2,      do_load_serial,                         \
+       "loads   - load S-Record file over serial line\n",                      \
+       "[ off ]\n"                                                             \
+       "    - load S-Record file over serial line with offset 'off'\n",        \
+}
+
+void do_load_serial (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[]);
+
+#define CMD_TBL_RESET  {                                                       \
+       "reset",        5,      1,      do_reset,                               \
+       "reset   - Perform RESET of the CPU\n",                         \
+       NULL,                                                                   \
+}
+
+void do_reset (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[]);
+
+#endif /* _CMD_BOOT_H */
diff --git a/include/cmd_bootm.h b/include/cmd_bootm.h
new file mode 100644 (file)
index 0000000..a6127ad
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * Boot support
+ */
+#ifndef        _CMD_BOOTM_H
+#define        _CMD_BOOTM_H
+
+void do_bootm (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[]);
+
+#define        CMD_TBL_BOOTM   {                                                       \
+       "bootm",        3,      CFG_MAXARGS,    do_bootm,                       \
+       "bootm   - boot application image from memory\n",                       \
+       "addr [arg ...]\n    - boot application image stored in memory\n"       \
+       "        passing arguments 'arg ...'; when booting a Linux kernel,\n"   \
+       "        'arg' can be the address of an initrd image\n",                \
+}
+
+void do_iminfo (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[]);
+
+#define        CMD_TBL_IMINFO  {                                                       \
+       "iminfo",       3,      CFG_MAXARGS,    do_iminfo,                      \
+       "iminfo  - print header information for application image\n",           \
+       "addr [addr ...]\n"                                                     \
+       "    - print header information for application image starting at\n"    \
+       "      address 'addr' in memory; this includes verification of the\n"   \
+       "      image contents (magic number, header and payload checksums)\n",  \
+}
+
+#endif /* _CMD_BOOTM_H */
diff --git a/include/cmd_cache.h b/include/cmd_cache.h
new file mode 100644 (file)
index 0000000..e33e7ec
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * Cache support: switch on or off, get status
+ */
+#ifndef        _CMD_CACHE_H
+#define        _CMD_CACHE_H
+
+#define        CMD_TBL_ICACHE  {                                                       \
+       "icache",       2,      2,      do_icache,                              \
+       "icache  - enable or disable instruction cache\n",                      \
+       "[on, off]\n"                                                           \
+       "    - enable or disable instruction cache\n",                          \
+}
+
+#define CMD_TBL_DCACHE {                                                       \
+       "dcache",       2,      2,      do_dcache,                              \
+       "dcache  - enable or disable data cache\n",                             \
+       "[on, off]\n"                                                           \
+       "    - enable or disable data (writethrough) cache\n",                  \
+}
+
+void do_icache (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[]);
+void do_dcache (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[]);
+
+#endif /* _CMD_CACHE_H */
diff --git a/include/cmd_flash.h b/include/cmd_flash.h
new file mode 100644 (file)
index 0000000..8be6c38
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * FLASH support
+ */
+#ifndef        _CMD_FLASH_H
+#define        _CMD_FLASH_H
+
+#define        CMD_TBL_FLINFO  {                                                       \
+       "flinfo",       3,      2,      do_flinfo,                              \
+       "flinfo  - print FLASH memory information\n",                           \
+       "\n    - print information for all FLASH memory banks\n"                \
+       "flinfo N\n    - print information for FLASH memory bank # N\n",        \
+}
+
+#define        CMD_TBL_FLERASE {                                                       \
+       "erase",        3,      3,      do_flerase,                             \
+       "erase   - erase FLASH memory\n",                                       \
+       "start end\n"                                                           \
+       "    - erase FLASH from addr 'start' to addr 'end'\n"                   \
+       "erase bank N\n    - erase FLASH bank # N\n"                            \
+       "erase all\n    - erase all FLASH banks\n",                             \
+}
+
+#define        CMD_TBL_PROTECT {                                                       \
+       "protect",      4,      4,      do_protect,                             \
+       "protect - enable or disable FLASH write protection\n",                 \
+       "on  start end\n"                                                       \
+       "    - protect FLASH from addr 'start' to addr 'end'\n"                 \
+       "protect on  bank N\n    - protect FLASH bank # N\n"                    \
+       "protect on  all\n    - protect all FLASH banks\n"                      \
+       "protect off start end\n"                                               \
+       "    - make FLASH from addr 'start' to addr 'end' writable\n"           \
+       "protect off bank N\n    - make FLASH bank # N writable\n"              \
+       "protect off all\n    - make all FLASH banks writable\n",               \
+}
+
+void do_flinfo (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[]);
+void do_flerase(cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[]);
+void do_protect(cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[]);
+
+#endif /* _CMD_FLASH_H */
+
diff --git a/include/cmd_mem.h b/include/cmd_mem.h
new file mode 100644 (file)
index 0000000..8bf916d
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * Memory Functions
+ */
+#ifndef        _CMD_MEM_H
+#define _CMD_MEM_H
+
+#define CMD_TBL_MD     {                                                       \
+       "md",           2,      3,      do_mem_md,                              \
+       "md      - memory display\n",                                           \
+       "[.b, .w, .l] address [# of objects]\n    - memory display\n",          \
+}
+#define CMD_TBL_MM     {                                                       \
+       "mm",           2,      2,      do_mem_mm,                              \
+       "mm      - memory modify (auto-incrementing)\n",                        \
+       "[.b, .w, .l] address\n"                                                \
+       "    - memory modify, auto increment address\n",                        \
+}
+#define CMD_TBL_NM     {                                                       \
+       "nm",           2,      2,      do_mem_nm,                              \
+       "nm      - memory modify (constant address)\n",                         \
+       "[.b, .w, .l] address\n    - memory modify, read and keep address\n",   \
+}
+#define CMD_TBL_MW     {                                                       \
+       "mw",           2,      4,      do_mem_mw,                              \
+       "mw      - memory write (fill)\n",                                      \
+       "[.b, .w, .l] address value [count]\n    - write memory\n",             \
+}
+#define        CMD_TBL_CP      {                                                       \
+       "cp",           2,      4,      do_mem_cp,                              \
+       "cp      - memory copy\n",                                              \
+       "[.b, .w, .l] source target count\n    - copy memory\n",                \
+}
+#define        CMD_TBL_CRC     {                                                       \
+       "crc32",        3,      4,      do_mem_crc,                             \
+       "crc32   - checksum calculation\n",                                     \
+       "address count\n    - compute CRC32 checksum\n",                        \
+}
+#define CMD_TBL_BASE   {                                                       \
+       "base",         2,      2,      do_mem_base,                            \
+       "base    - print or set address offset\n",                              \
+       "\n    - print address offset fpr memory commands\n"                    \
+       "base off\n    - set address offset for memory commands to 'off'\n",    \
+}
+/*
+ * Require full name for "loop" and "mtest" because these are infinite loops!
+ */
+#define CMD_TBL_LOOP   {                                                       \
+       "loop",         4,      3,      do_mem_loop,                            \
+       "loop    - infinite loop on address range\n",                           \
+       "[.b, .w, .l] address number_of_objects\n"                              \
+       "    - loop on a set of addresses\n",                                   \
+}
+#define CMD_TBL_MTEST  {                                                       \
+       "mtest",        5,      1,      do_mem_mtest,                           \
+       "mtest   - simple RAM test\n",                                          \
+       "\n    - simple SDRAM read/write test\n",                                       \
+}
+
+void do_mem_md    (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[]);
+void do_mem_mm    (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[]);
+void do_mem_nm    (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[]);
+void do_mem_mw    (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[]);
+void do_mem_cp    (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[]);
+void do_mem_crc   (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[]);
+void do_mem_base  (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[]);
+void do_mem_loop  (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[]);
+void do_mem_mtest (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[]);
+
+#endif /* _CMD_MEM_H */
diff --git a/include/cmd_nvedit.h b/include/cmd_nvedit.h
new file mode 100644 (file)
index 0000000..2b37eaa
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * Boot support
+ */
+#ifndef        _CMD_NVEDIT_H
+#define        _CMD_NVEDIT_H
+
+#define        CMD_TBL_PRINTENV        {                                               \
+       "printenv",     8,      CFG_MAXARGS,    do_printenv,                    \
+       "printenv- print environment variables\n",                              \
+       "\n    - print values of all environment variables\n"                   \
+       "printenv name ...\n"                                                   \
+       "    - print value of environment variable 'name'\n",                   \
+}
+
+#define CMD_TBL_SETENV         {                                               \
+       "setenv",       6,      CFG_MAXARGS,    do_setenv,                      \
+       "setenv  - set environment variables\n",                                \
+       "name value ...\n"                                                      \
+       "    - set environment variable 'name' to 'value ...'\n"                \
+       "setenv name\n"                                                         \
+       "    - delete environment variable 'name'\n",                           \
+}
+
+#define        CMD_TBL_SAVEENV         {                                               \
+       "saveenv",      4,      1,              do_saveenv,                     \
+       "saveenv - save environment variables to persistent storage\n",         \
+       NULL,                                                                   \
+}
+
+void do_printenv (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[]);
+void do_setenv   (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[]);
+void do_saveenv  (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[]);
+
+#endif /* _CMD_NVEDIT_H */
diff --git a/include/command.h b/include/command.h
new file mode 100644 (file)
index 0000000..311d9d5
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ *  Definitions for Command Processor
+ */
+#ifndef __COMMAND_H
+#define __COMMAND_H
+
+#ifndef NULL
+#define NULL   0
+#endif
+
+/*
+ * Monitor Command Table
+ */
+
+struct cmd_tbl_s {
+       char            *name;          /* Command Name                 */
+       int             lmin;           /* minimum abbreviated length   */
+       int             maxargs;        /* maximum number of arguments  */
+                                       /* Implementation function      */
+       void            (*cmd)(struct cmd_tbl_s *, bd_t *, int, int, char *[]);
+       char            *usage;         /* Usage message        (short) */
+       char            *help;          /* Help  message        (long)  */
+};
+
+typedef struct cmd_tbl_s       cmd_tbl_t;
+
+extern cmd_tbl_t cmd_tbl[];
+
+/*
+ * Monitor Command
+ *
+ * All commands use a common argument format:
+ *
+ * void function (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[]);
+ */
+
+typedef        void    command_t (cmd_tbl_t *, bd_t *, int, int, char *[]);
+
+/*
+ * Command Flags:
+ */
+#define CMD_FLAG_REPEAT                0x0001  /* repeat same command as before        */
+
+#endif /* __COMMAND_H */
diff --git a/include/commproc.h b/include/commproc.h
new file mode 100644 (file)
index 0000000..7faae4c
--- /dev/null
@@ -0,0 +1,738 @@
+
+/*
+ * MPC8xx Communication Processor Module.
+ * Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
+ *
+ * This file contains structures and information for the communication
+ * processor channels.  Some CPM control and status is available
+ * throught the MPC8xx internal memory map.  See immap.h for details.
+ * This file only contains what I need for the moment, not the total
+ * CPM capabilities.  I (or someone else) will add definitions as they
+ * are needed.  -- Dan
+ *
+ * On the MBX board, EPPC-Bug loads CPM microcode into the first 512
+ * bytes of the DP RAM and relocates the I2C parameter area to the
+ * IDMA1 space.  The remaining DP RAM is available for buffer descriptors
+ * or other use.
+ */
+#ifndef __CPM_8XX__
+#define __CPM_8XX__
+
+#include <linux/config.h>
+#include <asm/8xx_immap.h>
+
+/* CPM Command register.
+*/
+#define CPM_CR_RST     ((ushort)0x8000)
+#define CPM_CR_OPCODE  ((ushort)0x0f00)
+#define CPM_CR_CHAN    ((ushort)0x00f0)
+#define CPM_CR_FLG     ((ushort)0x0001)
+
+/* Some commands (there are more...later)
+*/
+#define CPM_CR_INIT_TRX                ((ushort)0x0000)
+#define CPM_CR_INIT_RX         ((ushort)0x0001)
+#define CPM_CR_INIT_TX         ((ushort)0x0002)
+#define CPM_CR_HUNT_MODE       ((ushort)0x0003)
+#define CPM_CR_STOP_TX         ((ushort)0x0004)
+#define CPM_CR_RESTART_TX      ((ushort)0x0006)
+#define CPM_CR_SET_GADDR       ((ushort)0x0008)
+
+/* Channel numbers.
+*/
+#define CPM_CR_CH_SCC1 ((ushort)0x0000)
+#define CPM_CR_CH_I2C  ((ushort)0x0001)        /* I2C and IDMA1 */
+#define CPM_CR_CH_SCC2 ((ushort)0x0004)
+#define CPM_CR_CH_SPI  ((ushort)0x0005)        /* SPI / IDMA2 / Timers */
+#define CPM_CR_CH_SCC3 ((ushort)0x0008)
+#define CPM_CR_CH_SMC1 ((ushort)0x0009)        /* SMC1 / DSP1 */
+#define CPM_CR_CH_SCC4 ((ushort)0x000c)
+#define CPM_CR_CH_SMC2 ((ushort)0x000d)        /* SMC2 / DSP2 */
+
+#define mk_cr_cmd(CH, CMD)     ((CMD << 8) | (CH << 4))
+
+/* The dual ported RAM is multi-functional.  Some areas can be (and are
+ * being) used for microcode.  There is an area that can only be used
+ * as data ram for buffer descriptors, which is all we use right now.
+ * Currently the first 512 and last 256 bytes are used for microcode.
+ */
+#define CPM_DATAONLY_BASE      ((uint)0x0800)
+#define CPM_DATAONLY_SIZE      ((uint)0x0700)
+#define CPM_DP_NOSPACE         ((uint)0x7fffffff)
+
+/* Export the base address of the communication processor registers
+ * and dual port ram.
+ */
+extern cpm8xx_t        *cpmp;          /* Pointer to comm processor */
+uint           m8xx_cpm_dpalloc(uint size);
+uint           m8xx_cpm_hostalloc(uint size);
+void           m8xx_cpm_setbrg(uint brg, uint rate);
+
+/* Buffer descriptors used by many of the CPM protocols.
+*/
+typedef struct cpm_buf_desc {
+       ushort  cbd_sc;         /* Status and Control */
+       ushort  cbd_datlen;     /* Data length in buffer */
+       uint    cbd_bufaddr;    /* Buffer address in host memory */
+} cbd_t;
+
+#define BD_SC_EMPTY    ((ushort)0x8000)        /* Recieve is empty */
+#define BD_SC_READY    ((ushort)0x8000)        /* Transmit is ready */
+#define BD_SC_WRAP     ((ushort)0x2000)        /* Last buffer descriptor */
+#define BD_SC_INTRPT   ((ushort)0x1000)        /* Interrupt on change */
+#define BD_SC_LAST     ((ushort)0x0800)        /* Last buffer in frame */
+#define BD_SC_CM       ((ushort)0x0200)        /* Continous mode */
+#define BD_SC_ID       ((ushort)0x0100)        /* Rec'd too many idles */
+#define BD_SC_P                ((ushort)0x0100)        /* xmt preamble */
+#define BD_SC_BR       ((ushort)0x0020)        /* Break received */
+#define BD_SC_FR       ((ushort)0x0010)        /* Framing error */
+#define BD_SC_PR       ((ushort)0x0008)        /* Parity error */
+#define BD_SC_OV       ((ushort)0x0002)        /* Overrun */
+#define BD_SC_CD       ((ushort)0x0001)        /* ?? */
+
+/* Parameter RAM offsets.
+*/
+#define PROFF_SCC1     ((uint)0x0000)
+#define PROFF_IIC      ((uint)0x0080)
+#define PROFF_SCC2     ((uint)0x0100)
+#define PROFF_SCC3     ((uint)0x0200)
+#define PROFF_SMC1     ((uint)0x0280)
+#define PROFF_SCC4     ((uint)0x0300)
+#define PROFF_SMC2     ((uint)0x0380)
+
+/* Define enough so I can at least use the serial port as a UART.
+ * The MBX uses SMC1 as the host serial port.
+ */
+typedef struct smc_uart {
+       ushort  smc_rbase;      /* Rx Buffer descriptor base address */
+       ushort  smc_tbase;      /* Tx Buffer descriptor base address */
+       u_char  smc_rfcr;       /* Rx function code */
+       u_char  smc_tfcr;       /* Tx function code */
+       ushort  smc_mrblr;      /* Max receive buffer length */
+       uint    smc_rstate;     /* Internal */
+       uint    smc_idp;        /* Internal */
+       ushort  smc_rbptr;      /* Internal */
+       ushort  smc_ibc;        /* Internal */
+       uint    smc_rxtmp;      /* Internal */
+       uint    smc_tstate;     /* Internal */
+       uint    smc_tdp;        /* Internal */
+       ushort  smc_tbptr;      /* Internal */
+       ushort  smc_tbc;        /* Internal */
+       uint    smc_txtmp;      /* Internal */
+       ushort  smc_maxidl;     /* Maximum idle characters */
+       ushort  smc_tmpidl;     /* Temporary idle counter */
+       ushort  smc_brklen;     /* Last received break length */
+       ushort  smc_brkec;      /* rcv'd break condition counter */
+       ushort  smc_brkcr;      /* xmt break count register */
+       ushort  smc_rmask;      /* Temporary bit mask */
+} smc_uart_t;
+
+/* Function code bits.
+*/
+#define SMC_EB ((u_char)0x10)  /* Set big endian byte order */
+
+/* SMC uart mode register.
+*/
+#define        SMCMR_REN       ((ushort)0x0001)
+#define SMCMR_TEN      ((ushort)0x0002)
+#define SMCMR_DM       ((ushort)0x000c)
+#define SMCMR_SM_GCI   ((ushort)0x0000)
+#define SMCMR_SM_UART  ((ushort)0x0020)
+#define SMCMR_SM_TRANS ((ushort)0x0030)
+#define SMCMR_SM_MASK  ((ushort)0x0030)
+#define SMCMR_PM_EVEN  ((ushort)0x0100)        /* Even parity, else odd */
+#define SMCMR_REVD     SMCMR_PM_EVEN
+#define SMCMR_PEN      ((ushort)0x0200)        /* Parity enable */
+#define SMCMR_BS       SMCMR_PEN
+#define SMCMR_SL       ((ushort)0x0400)        /* Two stops, else one */
+#define SMCR_CLEN_MASK ((ushort)0x7800)        /* Character length */
+#define smcr_mk_clen(C)        (((C) << 11) & SMCR_CLEN_MASK)
+
+/* SMC2 as Centronics parallel printer.  It is half duplex, in that
+ * it can only receive or transmit.  The parameter ram values for
+ * each direction are either unique or properly overlap, so we can
+ * include them in one structure.
+ */
+typedef struct smc_centronics {
+       ushort  scent_rbase;
+       ushort  scent_tbase;
+       u_char  scent_cfcr;
+       u_char  scent_smask;
+       ushort  scent_mrblr;
+       uint    scent_rstate;
+       uint    scent_r_ptr;
+       ushort  scent_rbptr;
+       ushort  scent_r_cnt;
+       uint    scent_rtemp;
+       uint    scent_tstate;
+       uint    scent_t_ptr;
+       ushort  scent_tbptr;
+       ushort  scent_t_cnt;
+       uint    scent_ttemp;
+       ushort  scent_max_sl;
+       ushort  scent_sl_cnt;
+       ushort  scent_character1;
+       ushort  scent_character2;
+       ushort  scent_character3;
+       ushort  scent_character4;
+       ushort  scent_character5;
+       ushort  scent_character6;
+       ushort  scent_character7;
+       ushort  scent_character8;
+       ushort  scent_rccm;
+       ushort  scent_rccr;
+} smc_cent_t;
+
+/* Centronics Status Mask Register.
+*/
+#define SMC_CENT_F     ((u_char)0x08)
+#define SMC_CENT_PE    ((u_char)0x04)
+#define SMC_CENT_S     ((u_char)0x02)
+
+/* SMC Event and Mask register.
+*/
+#define        SMCM_BRKE       ((unsigned char)0x40)   /* When in UART Mode */
+#define        SMCM_BRK        ((unsigned char)0x10)   /* When in UART Mode */
+#define        SMCM_TXE        ((unsigned char)0x10)   /* When in Transparent Mode */
+#define        SMCM_BSY        ((unsigned char)0x04)
+#define        SMCM_TX         ((unsigned char)0x02)
+#define        SMCM_RX         ((unsigned char)0x01)
+
+/* Baud rate generators.
+*/
+#define CPM_BRG_RST            ((uint)0x00020000)
+#define CPM_BRG_EN             ((uint)0x00010000)
+#define CPM_BRG_EXTC_INT       ((uint)0x00000000)
+#define CPM_BRG_EXTC_CLK2      ((uint)0x00004000)
+#define CPM_BRG_EXTC_CLK6      ((uint)0x00008000)
+#define CPM_BRG_ATB            ((uint)0x00002000)
+#define CPM_BRG_CD_MASK                ((uint)0x00001ffe)
+#define CPM_BRG_DIV16          ((uint)0x00000001)
+
+/* SCCs.
+*/
+#define SCC_GSMRH_IRP          ((uint)0x00040000)
+#define SCC_GSMRH_GDE          ((uint)0x00010000)
+#define SCC_GSMRH_TCRC_CCITT   ((uint)0x00008000)
+#define SCC_GSMRH_TCRC_BISYNC  ((uint)0x00004000)
+#define SCC_GSMRH_TCRC_HDLC    ((uint)0x00000000)
+#define SCC_GSMRH_REVD         ((uint)0x00002000)
+#define SCC_GSMRH_TRX          ((uint)0x00001000)
+#define SCC_GSMRH_TTX          ((uint)0x00000800)
+#define SCC_GSMRH_CDP          ((uint)0x00000400)
+#define SCC_GSMRH_CTSP         ((uint)0x00000200)
+#define SCC_GSMRH_CDS          ((uint)0x00000100)
+#define SCC_GSMRH_CTSS         ((uint)0x00000080)
+#define SCC_GSMRH_TFL          ((uint)0x00000040)
+#define SCC_GSMRH_RFW          ((uint)0x00000020)
+#define SCC_GSMRH_TXSY         ((uint)0x00000010)
+#define SCC_GSMRH_SYNL16       ((uint)0x0000000c)
+#define SCC_GSMRH_SYNL8                ((uint)0x00000008)
+#define SCC_GSMRH_SYNL4                ((uint)0x00000004)
+#define SCC_GSMRH_RTSM         ((uint)0x00000002)
+#define SCC_GSMRH_RSYN         ((uint)0x00000001)
+
+#define SCC_GSMRL_SIR          ((uint)0x80000000)      /* SCC2 only */
+#define SCC_GSMRL_EDGE_NONE    ((uint)0x60000000)
+#define SCC_GSMRL_EDGE_NEG     ((uint)0x40000000)
+#define SCC_GSMRL_EDGE_POS     ((uint)0x20000000)
+#define SCC_GSMRL_EDGE_BOTH    ((uint)0x00000000)
+#define SCC_GSMRL_TCI          ((uint)0x10000000)
+#define SCC_GSMRL_TSNC_3       ((uint)0x0c000000)
+#define SCC_GSMRL_TSNC_4       ((uint)0x08000000)
+#define SCC_GSMRL_TSNC_14      ((uint)0x04000000)
+#define SCC_GSMRL_TSNC_INF     ((uint)0x00000000)
+#define SCC_GSMRL_RINV         ((uint)0x02000000)
+#define SCC_GSMRL_TINV         ((uint)0x01000000)
+#define SCC_GSMRL_TPL_128      ((uint)0x00c00000)
+#define SCC_GSMRL_TPL_64       ((uint)0x00a00000)
+#define SCC_GSMRL_TPL_48       ((uint)0x00800000)
+#define SCC_GSMRL_TPL_32       ((uint)0x00600000)
+#define SCC_GSMRL_TPL_16       ((uint)0x00400000)
+#define SCC_GSMRL_TPL_8                ((uint)0x00200000)
+#define SCC_GSMRL_TPL_NONE     ((uint)0x00000000)
+#define SCC_GSMRL_TPP_ALL1     ((uint)0x00180000)
+#define SCC_GSMRL_TPP_01       ((uint)0x00100000)
+#define SCC_GSMRL_TPP_10       ((uint)0x00080000)
+#define SCC_GSMRL_TPP_ZEROS    ((uint)0x00000000)
+#define SCC_GSMRL_TEND         ((uint)0x00040000)
+#define SCC_GSMRL_TDCR_32      ((uint)0x00030000)
+#define SCC_GSMRL_TDCR_16      ((uint)0x00020000)
+#define SCC_GSMRL_TDCR_8       ((uint)0x00010000)
+#define SCC_GSMRL_TDCR_1       ((uint)0x00000000)
+#define SCC_GSMRL_RDCR_32      ((uint)0x0000c000)
+#define SCC_GSMRL_RDCR_16      ((uint)0x00008000)
+#define SCC_GSMRL_RDCR_8       ((uint)0x00004000)
+#define SCC_GSMRL_RDCR_1       ((uint)0x00000000)
+#define SCC_GSMRL_RENC_DFMAN   ((uint)0x00003000)
+#define SCC_GSMRL_RENC_MANCH   ((uint)0x00002000)
+#define SCC_GSMRL_RENC_FM0     ((uint)0x00001000)
+#define SCC_GSMRL_RENC_NRZI    ((uint)0x00000800)
+#define SCC_GSMRL_RENC_NRZ     ((uint)0x00000000)
+#define SCC_GSMRL_TENC_DFMAN   ((uint)0x00000600)
+#define SCC_GSMRL_TENC_MANCH   ((uint)0x00000400)
+#define SCC_GSMRL_TENC_FM0     ((uint)0x00000200)
+#define SCC_GSMRL_TENC_NRZI    ((uint)0x00000100)
+#define SCC_GSMRL_TENC_NRZ     ((uint)0x00000000)
+#define SCC_GSMRL_DIAG_LE      ((uint)0x000000c0)      /* Loop and echo */
+#define SCC_GSMRL_DIAG_ECHO    ((uint)0x00000080)
+#define SCC_GSMRL_DIAG_LOOP    ((uint)0x00000040)
+#define SCC_GSMRL_DIAG_NORM    ((uint)0x00000000)
+#define SCC_GSMRL_ENR          ((uint)0x00000020)
+#define SCC_GSMRL_ENT          ((uint)0x00000010)
+#define SCC_GSMRL_MODE_ENET    ((uint)0x0000000c)
+#define SCC_GSMRL_MODE_DDCMP   ((uint)0x00000009)
+#define SCC_GSMRL_MODE_BISYNC  ((uint)0x00000008)
+#define SCC_GSMRL_MODE_V14     ((uint)0x00000007)
+#define SCC_GSMRL_MODE_AHDLC   ((uint)0x00000006)
+#define SCC_GSMRL_MODE_PROFIBUS        ((uint)0x00000005)
+#define SCC_GSMRL_MODE_UART    ((uint)0x00000004)
+#define SCC_GSMRL_MODE_SS7     ((uint)0x00000003)
+#define SCC_GSMRL_MODE_ATALK   ((uint)0x00000002)
+#define SCC_GSMRL_MODE_HDLC    ((uint)0x00000000)
+
+#define SCC_TODR_TOD           ((ushort)0x8000)
+
+/* SCC Event and Mask register.
+*/
+#define        SCCM_TXE        ((unsigned char)0x10)
+#define        SCCM_BSY        ((unsigned char)0x04)
+#define        SCCM_TX         ((unsigned char)0x02)
+#define        SCCM_RX         ((unsigned char)0x01)
+
+typedef struct scc_param {
+       ushort  scc_rbase;      /* Rx Buffer descriptor base address */
+       ushort  scc_tbase;      /* Tx Buffer descriptor base address */
+       u_char  scc_rfcr;       /* Rx function code */
+       u_char  scc_tfcr;       /* Tx function code */
+       ushort  scc_mrblr;      /* Max receive buffer length */
+       uint    scc_rstate;     /* Internal */
+       uint    scc_idp;        /* Internal */
+       ushort  scc_rbptr;      /* Internal */
+       ushort  scc_ibc;        /* Internal */
+       uint    scc_rxtmp;      /* Internal */
+       uint    scc_tstate;     /* Internal */
+       uint    scc_tdp;        /* Internal */
+       ushort  scc_tbptr;      /* Internal */
+       ushort  scc_tbc;        /* Internal */
+       uint    scc_txtmp;      /* Internal */
+       uint    scc_rcrc;       /* Internal */
+       uint    scc_tcrc;       /* Internal */
+} sccp_t;
+
+/* Function code bits.
+*/
+#define SCC_EB ((u_char)0x10)  /* Set big endian byte order */
+
+/* CPM Ethernet through SCC1.
+ */
+typedef struct scc_enet {
+       sccp_t  sen_genscc;
+       uint    sen_cpres;      /* Preset CRC */
+       uint    sen_cmask;      /* Constant mask for CRC */
+       uint    sen_crcec;      /* CRC Error counter */
+       uint    sen_alec;       /* alignment error counter */
+       uint    sen_disfc;      /* discard frame counter */
+       ushort  sen_pads;       /* Tx short frame pad character */
+       ushort  sen_retlim;     /* Retry limit threshold */
+       ushort  sen_retcnt;     /* Retry limit counter */
+       ushort  sen_maxflr;     /* maximum frame length register */
+       ushort  sen_minflr;     /* minimum frame length register */
+       ushort  sen_maxd1;      /* maximum DMA1 length */
+       ushort  sen_maxd2;      /* maximum DMA2 length */
+       ushort  sen_maxd;       /* Rx max DMA */
+       ushort  sen_dmacnt;     /* Rx DMA counter */
+       ushort  sen_maxb;       /* Max BD byte count */
+       ushort  sen_gaddr1;     /* Group address filter */
+       ushort  sen_gaddr2;
+       ushort  sen_gaddr3;
+       ushort  sen_gaddr4;
+       uint    sen_tbuf0data0; /* Save area 0 - current frame */
+       uint    sen_tbuf0data1; /* Save area 1 - current frame */
+       uint    sen_tbuf0rba;   /* Internal */
+       uint    sen_tbuf0crc;   /* Internal */
+       ushort  sen_tbuf0bcnt;  /* Internal */
+       ushort  sen_paddrh;     /* physical address (MSB) */
+       ushort  sen_paddrm;
+       ushort  sen_paddrl;     /* physical address (LSB) */
+       ushort  sen_pper;       /* persistence */
+       ushort  sen_rfbdptr;    /* Rx first BD pointer */
+       ushort  sen_tfbdptr;    /* Tx first BD pointer */
+       ushort  sen_tlbdptr;    /* Tx last BD pointer */
+       uint    sen_tbuf1data0; /* Save area 0 - current frame */
+       uint    sen_tbuf1data1; /* Save area 1 - current frame */
+       uint    sen_tbuf1rba;   /* Internal */
+       uint    sen_tbuf1crc;   /* Internal */
+       ushort  sen_tbuf1bcnt;  /* Internal */
+       ushort  sen_txlen;      /* Tx Frame length counter */
+       ushort  sen_iaddr1;     /* Individual address filter */
+       ushort  sen_iaddr2;
+       ushort  sen_iaddr3;
+       ushort  sen_iaddr4;
+       ushort  sen_boffcnt;    /* Backoff counter */
+
+       /* NOTE: Some versions of the manual have the following items
+        * incorrectly documented.  Below is the proper order.
+        */
+       ushort  sen_taddrh;     /* temp address (MSB) */
+       ushort  sen_taddrm;
+       ushort  sen_taddrl;     /* temp address (LSB) */
+} scc_enet_t;
+
+#ifdef CONFIG_MBX
+/* Bits in parallel I/O port registers that have to be set/cleared
+ * to configure the pins for SCC1 use.  The TCLK and RCLK seem unique
+ * to the MBX860 board.  Any two of the four available clocks could be
+ * used, and the MPC860 cookbook manual has an example using different
+ * clock pins.
+ */
+#define PA_ENET_RXD    ((ushort)0x0001)
+#define PA_ENET_TXD    ((ushort)0x0002)
+#define PA_ENET_TCLK   ((ushort)0x0200)
+#define PA_ENET_RCLK   ((ushort)0x0800)
+#define PC_ENET_TENA   ((ushort)0x0001)
+#define PC_ENET_CLSN   ((ushort)0x0010)
+#define PC_ENET_RENA   ((ushort)0x0020)
+
+/* Control bits in the SICR to route TCLK (CLK2) and RCLK (CLK4) to
+ * SCC1.  Also, make sure GR1 (bit 24) and SC1 (bit 25) are zero.
+ */
+#define SICR_ENET_MASK ((uint)0x000000ff)
+#define SICR_ENET_CLKRT        ((uint)0x0000003d)
+#endif
+
+#ifdef CONFIG_RPXLITE
+/* This ENET stuff is for the MPC850 with ethernet on SCC2.  Some of
+ * this may be unique to the RPX-Lite configuration.
+ * Note TENA is on Port B.
+ */
+#define PA_ENET_RXD    ((ushort)0x0004)
+#define PA_ENET_TXD    ((ushort)0x0008)
+#define PA_ENET_TCLK   ((ushort)0x0200)
+#define PA_ENET_RCLK   ((ushort)0x0800)
+#define PB_ENET_TENA   ((uint)0x00002000)
+#define PC_ENET_CLSN   ((ushort)0x0040)
+#define PC_ENET_RENA   ((ushort)0x0080)
+
+#define SICR_ENET_MASK ((uint)0x0000ff00)
+#define SICR_ENET_CLKRT        ((uint)0x00003d00)
+#endif
+
+#ifdef CONFIG_BSEIP
+/* This ENET stuff is for the MPC823 with ethernet on SCC2.
+ * This is unique to the BSE ip-Engine board.
+ */
+#define PA_ENET_RXD    ((ushort)0x0004)
+#define PA_ENET_TXD    ((ushort)0x0008)
+#define PA_ENET_TCLK   ((ushort)0x0100)
+#define PA_ENET_RCLK   ((ushort)0x0200)
+#define PB_ENET_TENA   ((uint)0x00002000)
+#define PC_ENET_CLSN   ((ushort)0x0040)
+#define PC_ENET_RENA   ((ushort)0x0080)
+
+/* BSE uses port B and C bits for PHY control also.
+*/
+#define PB_BSE_POWERUP ((uint)0x00000004)
+#define PB_BSE_FDXDIS  ((uint)0x00008000)
+#define PC_BSE_LOOPBACK        ((ushort)0x0800)
+
+#define SICR_ENET_MASK ((uint)0x0000ff00)
+#define SICR_ENET_CLKRT        ((uint)0x00002c00)
+#endif
+
+#ifdef CONFIG_RPXCLASSIC
+/* Bits in parallel I/O port registers that have to be set/cleared
+ * to configure the pins for SCC1 use.
+ */
+#define PA_ENET_RXD    ((ushort)0x0001)
+#define PA_ENET_TXD    ((ushort)0x0002)
+#define PA_ENET_TCLK   ((ushort)0x0200)
+#define PA_ENET_RCLK   ((ushort)0x0800)
+#define PB_ENET_TENA   ((uint)0x00001000)
+#define PC_ENET_CLSN   ((ushort)0x0010)
+#define PC_ENET_RENA   ((ushort)0x0020)
+
+/* Control bits in the SICR to route TCLK (CLK2) and RCLK (CLK4) to
+ * SCC1.  Also, make sure GR1 (bit 24) and SC1 (bit 25) are zero.
+ */
+#define SICR_ENET_MASK ((uint)0x000000ff)
+#define SICR_ENET_CLKRT        ((uint)0x0000003d)
+#endif
+
+#if (defined(CONFIG_TQM860) || defined(CONFIG_TQM860L))
+/*
+ * TQM860 and TQM860L Configuration:
+ *
+ * Signal       PAR     DIR     ODR     DAT     Function
+ * Port A,  5    1       0       -       -       TCLK (CLK3) for Ethernet
+ * Port A,  7    1       0       -       -       RCLK (CLK1) for Ethernet
+ * Port A, 14    1       0       -       -       TXD for Ethernet (SCC1)
+ * Port A, 15    1       0       -       -       RXD for Ethernet (SCC1)
+ * Port C,  7    0       0       0       -       -> ETH-LOOP
+ * Port C, 10    0       0       1       -       CD  for Ethernet (SCC1)
+ * Port C, 11    0       0       1       -       CTS for Ethernet (SCC1)
+ * Port C, 15    *       *       0       -       TENA/RTS for Ethernet
+ */
+
+#define PA_ENET_RXD    ((ushort)0x0001)        /* PA 15 */
+#define PA_ENET_TXD    ((ushort)0x0002)        /* PA 14 */
+#define PA_ENET_TCLK   ((ushort)0x0400)        /* PA  5 */
+#define PA_ENET_RCLK   ((ushort)0x0100)        /* PA  7 */
+
+#define PC_ENET_TENA   ((ushort)0x0001)        /* PC 15 */
+#define PC_ENET_CLSN   ((ushort)0x0010)        /* PC 11 */
+#define PC_ENET_RENA   ((ushort)0x0020)        /* PC 10 */
+
+/* Control bits in the SICR to route TCLK (CLK3) and RCLK (CLK1) to
+ * SCC1.  Also, make sure GR1 (bit 24) and SC1 (bit 25) are zero.
+ */
+#define SICR_ENET_MASK ((uint)0x000000ff)
+#define SICR_ENET_CLKRT        ((uint)0x00000026)
+
+#endif /* CONFIG_TQM860, TQM860L */
+
+#ifdef CONFIG_TQM8xxL
+/*
+ * TQM8xxL Configuration (except TQM860L):
+ *
+ * Signal       PAR     DIR     ODR     DAT     Function
+ * Port A,  5    1       0       -       -       TCLK (CLK3) for Ethernet
+ * Port A,  7    1       0       -       -       RCLK (CLK1) for Ethernet
+ * Port A, 12    1       0       -       -       TXD for Ethernet (SCC2)
+ * Port A, 13    1       0       -       -       RXD for Ethernet (SCC2)
+ * Port B, 18    1       1       -       -       TENA/RTS for Ethernet on STK8xx
+ * Port C,  7    0       0       0       -       -> ETH-LOOP
+ * Port C,  8    0       0       1       -       CD  for Ethernet (SCC2)
+ * Port C,  9    0       0       1       -       CTS for Ethernet (SCC2)
+ * Port C, 14    *       *       0       -       TENA/RTS for Ethernet on FPS850
+ *
+ * Note: Using PC14 as RTS2 (TENA) does not work on the TQM850L when
+ * used with the starter-kit mainboard; we *must* use PB18 instead.
+ * For the FPS850 system, we *must* use PC14 :-(
+ */
+
+#define PA_ENET_RXD    ((ushort)0x0004)        /* PA 13 */
+#define PA_ENET_TXD    ((ushort)0x0008)        /* PA 12 */
+#define PA_ENET_RCLK   ((ushort)0x0100)        /* PA  7 */
+#define PA_ENET_TCLK   ((ushort)0x0400)        /* PA  5 */
+
+#ifndef        CONFIG_FPS850   /* not valid on FPS board */
+#define        PB_ENET_TENA    ((uint)0x00002000)
+#endif /* !CONFIG_FPS850 */
+
+#ifdef CONFIG_FPS850   /* FPS uses default configuration */
+#define PC_ENET_TENA   ((ushort)0x0002)        /* PC 14 */
+#endif /* CONFIG_FPS850 */
+#define PC_ENET_CLSN   ((ushort)0x0040)        /* PC  9 */
+#define PC_ENET_RENA   ((ushort)0x0080)        /* PC  8 */
+
+/* Control bits in the SICR to route TCLK (CLK3) and RCLK (CLK1) to
+ * SCC2.  Also, make sure GR2 (bit 16) and SC2 (bit 17) are zero.
+ */
+#define SICR_ENET_MASK ((uint)0x0000ff00)
+#define SICR_ENET_CLKRT        ((uint)0x00002600)
+
+#endif /* CONFIG_TQM8xxL */
+
+/* SCC Event register as used by Ethernet.
+*/
+#define SCCE_ENET_GRA  ((ushort)0x0080)        /* Graceful stop complete */
+#define SCCE_ENET_TXE  ((ushort)0x0010)        /* Transmit Error */
+#define SCCE_ENET_RXF  ((ushort)0x0008)        /* Full frame received */
+#define SCCE_ENET_BSY  ((ushort)0x0004)        /* All incoming buffers full */
+#define SCCE_ENET_TXB  ((ushort)0x0002)        /* A buffer was transmitted */
+#define SCCE_ENET_RXB  ((ushort)0x0001)        /* A buffer was received */
+
+/* SCC Mode Register (PMSR) as used by Ethernet.
+*/
+#define SCC_PMSR_HBC   ((ushort)0x8000)        /* Enable heartbeat */
+#define SCC_PMSR_FC    ((ushort)0x4000)        /* Force collision */
+#define SCC_PMSR_RSH   ((ushort)0x2000)        /* Receive short frames */
+#define SCC_PMSR_IAM   ((ushort)0x1000)        /* Check individual hash */
+#define SCC_PMSR_ENCRC ((ushort)0x0800)        /* Ethernet CRC mode */
+#define SCC_PMSR_PRO   ((ushort)0x0200)        /* Promiscuous mode */
+#define SCC_PMSR_BRO   ((ushort)0x0100)        /* Catch broadcast pkts */
+#define SCC_PMSR_SBT   ((ushort)0x0080)        /* Special backoff timer */
+#define SCC_PMSR_LPB   ((ushort)0x0040)        /* Set Loopback mode */
+#define SCC_PMSR_SIP   ((ushort)0x0020)        /* Sample Input Pins */
+#define SCC_PMSR_LCW   ((ushort)0x0010)        /* Late collision window */
+#define SCC_PMSR_NIB22 ((ushort)0x000a)        /* Start frame search */
+#define SCC_PMSR_FDE   ((ushort)0x0001)        /* Full duplex enable */
+
+/* Buffer descriptor control/status used by Ethernet receive.
+*/
+#define BD_ENET_RX_EMPTY       ((ushort)0x8000)
+#define BD_ENET_RX_WRAP                ((ushort)0x2000)
+#define BD_ENET_RX_INTR                ((ushort)0x1000)
+#define BD_ENET_RX_LAST                ((ushort)0x0800)
+#define BD_ENET_RX_FIRST       ((ushort)0x0400)
+#define BD_ENET_RX_MISS                ((ushort)0x0100)
+#define BD_ENET_RX_LG          ((ushort)0x0020)
+#define BD_ENET_RX_NO          ((ushort)0x0010)
+#define BD_ENET_RX_SH          ((ushort)0x0008)
+#define BD_ENET_RX_CR          ((ushort)0x0004)
+#define BD_ENET_RX_OV          ((ushort)0x0002)
+#define BD_ENET_RX_CL          ((ushort)0x0001)
+#define BD_ENET_RX_STATS       ((ushort)0x013f)        /* All status bits */
+
+/* Buffer descriptor control/status used by Ethernet transmit.
+*/
+#define BD_ENET_TX_READY       ((ushort)0x8000)
+#define BD_ENET_TX_PAD         ((ushort)0x4000)
+#define BD_ENET_TX_WRAP                ((ushort)0x2000)
+#define BD_ENET_TX_INTR                ((ushort)0x1000)
+#define BD_ENET_TX_LAST                ((ushort)0x0800)
+#define BD_ENET_TX_TC          ((ushort)0x0400)
+#define BD_ENET_TX_DEF         ((ushort)0x0200)
+#define BD_ENET_TX_HB          ((ushort)0x0100)
+#define BD_ENET_TX_LC          ((ushort)0x0080)
+#define BD_ENET_TX_RL          ((ushort)0x0040)
+#define BD_ENET_TX_RCMASK      ((ushort)0x003c)
+#define BD_ENET_TX_UN          ((ushort)0x0002)
+#define BD_ENET_TX_CSL         ((ushort)0x0001)
+#define BD_ENET_TX_STATS       ((ushort)0x03ff)        /* All status bits */
+
+/* SCC as UART
+*/
+typedef struct scc_uart {
+       sccp_t  scc_genscc;
+       uint    scc_res1;       /* Reserved */
+       uint    scc_res2;       /* Reserved */
+       ushort  scc_maxidl;     /* Maximum idle chars */
+       ushort  scc_idlc;       /* temp idle counter */
+       ushort  scc_brkcr;      /* Break count register */
+       ushort  scc_parec;      /* receive parity error counter */
+       ushort  scc_frmec;      /* receive framing error counter */
+       ushort  scc_nosec;      /* receive noise counter */
+       ushort  scc_brkec;      /* receive break condition counter */
+       ushort  scc_brkln;      /* last received break length */
+       ushort  scc_uaddr1;     /* UART address character 1 */
+       ushort  scc_uaddr2;     /* UART address character 2 */
+       ushort  scc_rtemp;      /* Temp storage */
+       ushort  scc_toseq;      /* Transmit out of sequence char */
+       ushort  scc_char1;      /* control character 1 */
+       ushort  scc_char2;      /* control character 2 */
+       ushort  scc_char3;      /* control character 3 */
+       ushort  scc_char4;      /* control character 4 */
+       ushort  scc_char5;      /* control character 5 */
+       ushort  scc_char6;      /* control character 6 */
+       ushort  scc_char7;      /* control character 7 */
+       ushort  scc_char8;      /* control character 8 */
+       ushort  scc_rccm;       /* receive control character mask */
+       ushort  scc_rccr;       /* receive control character register */
+       ushort  scc_rlbc;       /* receive last break character */
+} scc_uart_t;
+
+/* SCC Event and Mask registers when it is used as a UART.
+*/
+#define UART_SCCM_GLR          ((ushort)0x1000)
+#define UART_SCCM_GLT          ((ushort)0x0800)
+#define UART_SCCM_AB           ((ushort)0x0200)
+#define UART_SCCM_IDL          ((ushort)0x0100)
+#define UART_SCCM_GRA          ((ushort)0x0080)
+#define UART_SCCM_BRKE         ((ushort)0x0040)
+#define UART_SCCM_BRKS         ((ushort)0x0020)
+#define UART_SCCM_CCR          ((ushort)0x0008)
+#define UART_SCCM_BSY          ((ushort)0x0004)
+#define UART_SCCM_TX           ((ushort)0x0002)
+#define UART_SCCM_RX           ((ushort)0x0001)
+
+/* The SCC PMSR when used as a UART.
+*/
+#define SCU_PMSR_FLC           ((ushort)0x8000)
+#define SCU_PMSR_SL            ((ushort)0x4000)
+#define SCU_PMSR_CL            ((ushort)0x3000)
+#define SCU_PMSR_UM            ((ushort)0x0c00)
+#define SCU_PMSR_FRZ           ((ushort)0x0200)
+#define SCU_PMSR_RZS           ((ushort)0x0100)
+#define SCU_PMSR_SYN           ((ushort)0x0080)
+#define SCU_PMSR_DRT           ((ushort)0x0040)
+#define SCU_PMSR_PEN           ((ushort)0x0010)
+#define SCU_PMSR_RPM           ((ushort)0x000c)
+#define SCU_PMSR_REVP          ((ushort)0x0008)
+#define SCU_PMSR_TPM           ((ushort)0x0003)
+#define SCU_PMSR_TEVP          ((ushort)0x0003)
+
+/* CPM Transparent mode SCC.
+ */
+typedef struct scc_trans {
+       sccp_t  st_genscc;
+       uint    st_cpres;       /* Preset CRC */
+       uint    st_cmask;       /* Constant mask for CRC */
+} scc_trans_t;
+
+#define BD_SCC_TX_LAST         ((ushort)0x0800)
+
+/* IIC parameter RAM.
+*/
+typedef struct iic {
+       ushort  iic_rbase;      /* Rx Buffer descriptor base address */
+       ushort  iic_tbase;      /* Tx Buffer descriptor base address */
+       u_char  iic_rfcr;       /* Rx function code */
+       u_char  iic_tfcr;       /* Tx function code */
+       ushort  iic_mrblr;      /* Max receive buffer length */
+       uint    iic_rstate;     /* Internal */
+       uint    iic_rdp;        /* Internal */
+       ushort  iic_rbptr;      /* Internal */
+       ushort  iic_rbc;        /* Internal */
+       uint    iic_rxtmp;      /* Internal */
+       uint    iic_tstate;     /* Internal */
+       uint    iic_tdp;        /* Internal */
+       ushort  iic_tbptr;      /* Internal */
+       ushort  iic_tbc;        /* Internal */
+       uint    iic_txtmp;      /* Internal */
+} iic_t;
+
+#define BD_IIC_START           ((ushort)0x0400)
+
+/* CPM interrupts.  There are nearly 32 interrupts generated by CPM
+ * channels or devices.  All of these are presented to the PPC core
+ * as a single interrupt.  The CPM interrupt handler dispatches its
+ * own handlers, in a similar fashion to the PPC core handler.  We
+ * use the table as defined in the manuals (i.e. no special high
+ * priority and SCC1 == SCCa, etc...).
+ */
+#define CPMVEC_NR              32
+#define        CPMVEC_PIO_PC15         ((ushort)0x1f)
+#define        CPMVEC_SCC1             ((ushort)0x1e)
+#define        CPMVEC_SCC2             ((ushort)0x1d)
+#define        CPMVEC_SCC3             ((ushort)0x1c)
+#define        CPMVEC_SCC4             ((ushort)0x1b)
+#define        CPMVEC_PIO_PC14         ((ushort)0x1a)
+#define        CPMVEC_TIMER1           ((ushort)0x19)
+#define        CPMVEC_PIO_PC13         ((ushort)0x18)
+#define        CPMVEC_PIO_PC12         ((ushort)0x17)
+#define        CPMVEC_SDMA_CB_ERR      ((ushort)0x16)
+#define CPMVEC_IDMA1           ((ushort)0x15)
+#define CPMVEC_IDMA2           ((ushort)0x14)
+#define CPMVEC_TIMER2          ((ushort)0x12)
+#define CPMVEC_RISCTIMER       ((ushort)0x11)
+#define CPMVEC_I2C             ((ushort)0x10)
+#define        CPMVEC_PIO_PC11         ((ushort)0x0f)
+#define        CPMVEC_PIO_PC10         ((ushort)0x0e)
+#define CPMVEC_TIMER3          ((ushort)0x0c)
+#define        CPMVEC_PIO_PC9          ((ushort)0x0b)
+#define        CPMVEC_PIO_PC8          ((ushort)0x0a)
+#define        CPMVEC_PIO_PC7          ((ushort)0x09)
+#define CPMVEC_TIMER4          ((ushort)0x07)
+#define        CPMVEC_PIO_PC6          ((ushort)0x06)
+#define        CPMVEC_SPI              ((ushort)0x05)
+#define        CPMVEC_SMC1             ((ushort)0x04)
+#define        CPMVEC_SMC2             ((ushort)0x03)
+#define        CPMVEC_PIO_PC5          ((ushort)0x02)
+#define        CPMVEC_PIO_PC4          ((ushort)0x01)
+#define        CPMVEC_ERROR            ((ushort)0x00)
+
+extern void cpm_install_handler(int vec, void (*handler)(void *), void *dev_id);
+
+/* CPM interrupt configuration vector.
+*/
+#define        CICR_SCD_SCC4           ((uint)0x00c00000)      /* SCC4 @ SCCd */
+#define        CICR_SCC_SCC3           ((uint)0x00200000)      /* SCC3 @ SCCc */
+#define        CICR_SCB_SCC2           ((uint)0x00040000)      /* SCC2 @ SCCb */
+#define        CICR_SCA_SCC1           ((uint)0x00000000)      /* SCC1 @ SCCa */
+#define CICR_IRL_MASK          ((uint)0x0000e000)      /* Core interrrupt */
+#define CICR_HP_MASK           ((uint)0x00001f00)      /* Hi-pri int. */
+#define CICR_IEN               ((uint)0x00000080)      /* Int. enable */
+#define CICR_SPS               ((uint)0x00000001)      /* SCC Spread */
+#endif /* __CPM_8XX__ */
diff --git a/include/config.h b/include/config.h
new file mode 100644 (file)
index 0000000..1fefb30
--- /dev/null
@@ -0,0 +1,253 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * board/config.h - configuration options, board specific
+ */
+
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+/*
+ * High Level Configuration Options
+ * (easy to change)
+ */
+
+#define CONFIG_MPC850          1       /* This is a MPC850 CPU         */
+#define CONFIG_TQM850L         1       /* ...on a TQM8xxL module       */
+
+#define CONFIG_8xx_CPUCLOCK    50
+#define CONFIG_8xx_BUSCLOCK    (CONFIG_8xx_CPUCLOCK)
+
+#define        CONFIG_8xx_CONS_SMC1    1       /* Console is on SMC1           */
+#undef CONFIG_8xx_CONS_SMC2
+#define CONFIG_8xx_BAUDRATE    115200
+#if 0
+#define CONFIG_8xx_BOOTDELAY   -1      /* autoboot disabled            */
+#else
+#define CONFIG_8xx_BOOTDELAY   5       /* autoboot after 5 seconds     */
+#endif
+#define CONFIG_8xx_BOOTCOMMAND "help"  /* autoboot command             */
+
+#define CONFIG_DRAM_SPEED      (CONFIG_8xx_BUSCLOCK)   /* MHz          */
+
+/*
+ * Miscellaneous configurable options
+ */
+#define        CFG_PROMPT      "=> "           /* Monitor Command Prompt       */
+#define        CFG_CBSIZE      256             /* Console I/O Buffer Size      */
+#define        CFG_PBSIZE (CFG_CBSIZE+sizeof(CFG_PROMPT)+16) /* Print Buffer Size */
+#define        CFG_MAXARGS     8               /* max number of command args   */
+#define CFG_BARGSIZE   CFG_CBSIZE      /* Boot Argument Buffer Size    */
+
+#define CFG_MEMTEST_START      0x0400000       /* memtest works on     */
+#define CFG_MEMTEST_END                0x0C00000       /* 4 ... 12 MB in DRAM  */
+/*
+ * Low Level Configuration Settings
+ * (address mappings, register initial values, etc.)
+ * You should know what you are doing if you make changes here.
+ */
+/*-----------------------------------------------------------------------
+ * Internal Memory Mapped Register
+ */
+#define CFG_IMMR               0xFFF00000
+
+/*-----------------------------------------------------------------------
+ * Start addresses for the final memory configuration
+ * (Set up by the startup code)
+ * Please note that CFG_SDRAM_BASE _must_ start at 0
+ */
+#define        CFG_SDRAM_BASE          0x00000000
+#define CFG_FLASH_BASE         0x40000000
+#define        CFG_MONITOR_LEN         (128 << 10)     /* Reserve 128 kB for Monitor   */
+#define CFG_HWINFO_LEN         0x0040          /* Length of HW Info Data       */
+#define CFG_HWINFO_ADDR  (CFG_FLASH_BASE + CFG_MONITOR_LEN - CFG_HWINFO_LEN)
+#define        CFG_MALLOC_LEN          (128 << 10)     /* Reserve 128 kB for malloc()  */
+
+/*
+ * For booting Linux, the board info and command line data
+ * have to be in the first 8 MB of memory, since this is
+ * the maximum mapped by the Linux kernel during initialization.
+ */
+#define        CFG_BOOTMAPSZ           (8 << 20)       /* Initial Memory map for Linux */
+/*-----------------------------------------------------------------------
+ * FLASH organization
+ */
+#define CFG_MAX_FLASH_BANKS    2       /* max number of memory banks           */
+#define CFG_MAX_FLASH_SECT     67      /* max number of sectors on one chip    */
+
+#define CFG_FLASH_ERASE_TOUT   120000  /* Timeout for Flash Erase (in ms)      */
+#define CFG_FLASH_WRITE_TOUT   500     /* Timeout for Flash Write (in ms)      */
+
+/*-----------------------------------------------------------------------
+ * Cache Configuration
+ */
+#define CFG_CACHELINE_SIZE     16      /* For all MPC8xx CPUs                  */
+
+/*-----------------------------------------------------------------------
+ * SYPCR - System Protection Control                           11-9
+ * SYPCR can only be written once after reset!
+ *-----------------------------------------------------------------------
+ * Software & Bus Monitor Timer max, Bus Monitor enable, SW Watchdog freeze
+ */
+#define CFG_SYPCR      (SYPCR_SWTC | SYPCR_BMT | SYPCR_BME | SYPCR_SWF | SYPCR_SWP)
+
+/*-----------------------------------------------------------------------
+ * SUMCR - SIU Module Configuration                            11-6
+ *-----------------------------------------------------------------------
+ * PCMCIA config., multi-function pin tri-state
+ */
+#define CFG_SIUMCR     (SIUMCR_DBGC00 | SIUMCR_DBPC00 | SIUMCR_MLRC01)
+
+/*-----------------------------------------------------------------------
+ * TBSCR - Time Base Status and Control                                11-26
+ *-----------------------------------------------------------------------
+ * Clear Reference Interrupt Status, Timebase freezing enabled
+ */
+#define CFG_TBSCR      (TBSCR_REFA | TBSCR_REFB | TBSCR_TBF)
+
+/*-----------------------------------------------------------------------
+ * PISCR - Periodic Interrupt Status and Control               11-31
+ *-----------------------------------------------------------------------
+ * Clear Periodic Interrupt Status, Interrupt Timer freezing enabled
+ */
+#define CFG_PISCR      (PISCR_PS | PISCR_PITF)
+
+/*-----------------------------------------------------------------------
+ * PLPRCR - PLL, Low-Power, and Reset Control Register         15-30
+ *-----------------------------------------------------------------------
+ * Reset PLL lock status sticky bit, timer expired status bit and timer
+ * interrupt status bit - leave PLL multiplication factor unchanged !
+ */
+#define CFG_PLPRCR     (PLPRCR_SPLSS | PLPRCR_TEXPS | PLPRCR_TMIST)
+
+/*-----------------------------------------------------------------------
+ * SCCR - System Clock and reset Control Register              15-27
+ *-----------------------------------------------------------------------
+ * Set clock output, timebase and RTC source and divider,
+ * power management and some other internal clocks
+ */
+#define SCCR_MASK      SCCR_EBDF11
+#define CFG_SCCR       (SCCR_TBS     | \
+                        SCCR_COM00   | SCCR_DFSYNC00 | SCCR_DFBRG00  | \
+                        SCCR_DFNL000 | SCCR_DFNH000  | SCCR_DFLCD000 | \
+                        SCCR_DFALCD00)
+
+/*-----------------------------------------------------------------------
+ * 
+ *-----------------------------------------------------------------------
+ *
+ */
+/*#define      CFG_DER 0x2002000F*/
+#define CFG_DER        0
+
+#define MPC8XX_FACT    1               /* Multiply by 1                */
+#if 0
+#define MPC8XX_XIN     50000000        /* 50 MHz in    - ??? - XXX     */
+/* #define MPC8XX_BUSDIV 2  */
+#define MPC8XX_HZ ((MPC8XX_XIN) * (MPC8XX_FACT))
+#endif
+
+/*
+ * Init Memory Controller:
+ *
+ * BR0/1 and OR0/1 (FLASH)
+ */
+
+#define FLASH_BASE0_PRELIM     0x40000000      /* FLASH bank #0        */
+#define FLASH_BASE1_PRELIM     0x60000000      /* FLASH bank #0        */
+
+/* used to re-map FLASH both when starting from SRAM or FLASH:
+ * restrict access enough to keep SRAM working (if any)
+ * but not too much to meddle with FLASH accesses
+ */
+#define CFG_REMAP_OR_AM                0x80000000      /* OR addr mask */
+#define CFG_PRELIM_OR_AM       0xE0000000      /* OR addr mask */
+
+/* FLASH timing: ACS = 11, TRLX = 0, CSNT = 1, SCY = 5, EHTR = 1       */
+#define CFG_OR_TIMING_FLASH    (OR_CSNT_SAM  | OR_ACS_DIV2 | OR_BI | \
+                                OR_SCY_5_CLK | OR_EHTR)
+
+#define CFG_OR0_REMAP  (CFG_REMAP_OR_AM  | CFG_OR_TIMING_FLASH)
+#define CFG_OR0_PRELIM (CFG_PRELIM_OR_AM | CFG_OR_TIMING_FLASH)
+#define CFG_BR0_PRELIM ((FLASH_BASE0_PRELIM & BR_BA_MSK) | BR_V )
+
+#define CFG_OR1_REMAP  CFG_OR0_REMAP
+#define CFG_OR1_PRELIM CFG_OR0_PRELIM
+#define CFG_BR1_PRELIM ((FLASH_BASE1_PRELIM & BR_BA_MSK) | BR_V )
+
+/*
+ * BR2/3 and OR2/3 (SDRAM)
+ *
+ */
+#define SDRAM_BASE2_PRELIM     0x00000000      /* SDRAM bank #0        */
+#define SDRAM_BASE3_PRELIM     0x20000000      /* SDRAM bank #1        */
+#define        SDRAM_MAX_SIZE          0x04000000      /* max 64 MB per bank   */
+
+/* SDRAM timing: Multiplexed addresses, GPL5 output to GPL5_A (don't care)     */
+#define CFG_OR_TIMING_SDRAM    0x00000A00
+
+#define CFG_OR2_PRELIM (CFG_PRELIM_OR_AM | CFG_OR_TIMING_SDRAM )
+#define CFG_BR2_PRELIM ((SDRAM_BASE2_PRELIM & BR_BA_MSK) | BR_MS_UPMA | BR_V )
+
+#define        CFG_OR3_PRELIM  CFG_OR2_PRELIM
+#define CFG_BR3_PRELIM ((SDRAM_BASE3_PRELIM & BR_BA_MSK) | BR_MS_UPMA | BR_V )
+
+/*
+ * Memory Periodic Timer Prescaler
+ */
+
+/* periodic timer for refresh */
+#define CFG_MAMR_PTA   97              /* start with divider for 100 MHz       */
+
+/* refresh rate 15.6 us (= 64 ms / 4K = 62.4 / quad bursts) for <= 128 MBit    */
+#define CFG_MPTPR_2BK_4K       MPTPR_PTP_DIV16         /* setting for 2 banks  */
+#define CFG_MPTPR_1BK_4K       MPTPR_PTP_DIV32         /* setting for 1 bank   */
+
+/* refresh rate 7.8 us (= 64 ms / 8K = 31.2 / quad bursts) for 256 MBit                */
+#define CFG_MPTPR_2BK_8K       MPTPR_PTP_DIV8          /* setting for 2 banks  */
+#define CFG_MPTPR_1BK_8K       MPTPR_PTP_DIV16         /* setting for 1 bank   */
+
+/*
+ * MAMR settings for SDRAM
+ */
+
+/* 8 column SDRAM */
+#define CFG_MAMR_8COL  ((CFG_MAMR_PTA << MAMR_PTA_SHIFT)  | MAMR_PTAE      |   \
+                        MAMR_AMA_TYPE_0 | MAMR_DSA_1_CYCL | MAMR_G0CLA_A11 |   \
+                        MAMR_RLFA_1X    | MAMR_WLFA_1X    | MAMR_TLFA_4X)
+/* 9 column SDRAM */
+#define CFG_MAMR_9COL  ((CFG_MAMR_PTA << MAMR_PTA_SHIFT)  | MAMR_PTAE      |   \
+                        MAMR_AMA_TYPE_1 | MAMR_DSA_1_CYCL | MAMR_G0CLA_A10 |   \
+                        MAMR_RLFA_1X    | MAMR_WLFA_1X    | MAMR_TLFA_4X)
+
+
+/*
+ * Internal Definitions
+ *
+ * Boot Flags
+ */
+#define        BOOTFLAG_COLD   0x01            /* Normal Power-On: Boot from FLASH     */
+#define BOOTFLAG_WARM  0x02            /* Software reboot                      */
+
+#endif /* __CONFIG_H */
diff --git a/include/config_TQM850L.h b/include/config_TQM850L.h
new file mode 100644 (file)
index 0000000..1fefb30
--- /dev/null
@@ -0,0 +1,253 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * board/config.h - configuration options, board specific
+ */
+
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+/*
+ * High Level Configuration Options
+ * (easy to change)
+ */
+
+#define CONFIG_MPC850          1       /* This is a MPC850 CPU         */
+#define CONFIG_TQM850L         1       /* ...on a TQM8xxL module       */
+
+#define CONFIG_8xx_CPUCLOCK    50
+#define CONFIG_8xx_BUSCLOCK    (CONFIG_8xx_CPUCLOCK)
+
+#define        CONFIG_8xx_CONS_SMC1    1       /* Console is on SMC1           */
+#undef CONFIG_8xx_CONS_SMC2
+#define CONFIG_8xx_BAUDRATE    115200
+#if 0
+#define CONFIG_8xx_BOOTDELAY   -1      /* autoboot disabled            */
+#else
+#define CONFIG_8xx_BOOTDELAY   5       /* autoboot after 5 seconds     */
+#endif
+#define CONFIG_8xx_BOOTCOMMAND "help"  /* autoboot command             */
+
+#define CONFIG_DRAM_SPEED      (CONFIG_8xx_BUSCLOCK)   /* MHz          */
+
+/*
+ * Miscellaneous configurable options
+ */
+#define        CFG_PROMPT      "=> "           /* Monitor Command Prompt       */
+#define        CFG_CBSIZE      256             /* Console I/O Buffer Size      */
+#define        CFG_PBSIZE (CFG_CBSIZE+sizeof(CFG_PROMPT)+16) /* Print Buffer Size */
+#define        CFG_MAXARGS     8               /* max number of command args   */
+#define CFG_BARGSIZE   CFG_CBSIZE      /* Boot Argument Buffer Size    */
+
+#define CFG_MEMTEST_START      0x0400000       /* memtest works on     */
+#define CFG_MEMTEST_END                0x0C00000       /* 4 ... 12 MB in DRAM  */
+/*
+ * Low Level Configuration Settings
+ * (address mappings, register initial values, etc.)
+ * You should know what you are doing if you make changes here.
+ */
+/*-----------------------------------------------------------------------
+ * Internal Memory Mapped Register
+ */
+#define CFG_IMMR               0xFFF00000
+
+/*-----------------------------------------------------------------------
+ * Start addresses for the final memory configuration
+ * (Set up by the startup code)
+ * Please note that CFG_SDRAM_BASE _must_ start at 0
+ */
+#define        CFG_SDRAM_BASE          0x00000000
+#define CFG_FLASH_BASE         0x40000000
+#define        CFG_MONITOR_LEN         (128 << 10)     /* Reserve 128 kB for Monitor   */
+#define CFG_HWINFO_LEN         0x0040          /* Length of HW Info Data       */
+#define CFG_HWINFO_ADDR  (CFG_FLASH_BASE + CFG_MONITOR_LEN - CFG_HWINFO_LEN)
+#define        CFG_MALLOC_LEN          (128 << 10)     /* Reserve 128 kB for malloc()  */
+
+/*
+ * For booting Linux, the board info and command line data
+ * have to be in the first 8 MB of memory, since this is
+ * the maximum mapped by the Linux kernel during initialization.
+ */
+#define        CFG_BOOTMAPSZ           (8 << 20)       /* Initial Memory map for Linux */
+/*-----------------------------------------------------------------------
+ * FLASH organization
+ */
+#define CFG_MAX_FLASH_BANKS    2       /* max number of memory banks           */
+#define CFG_MAX_FLASH_SECT     67      /* max number of sectors on one chip    */
+
+#define CFG_FLASH_ERASE_TOUT   120000  /* Timeout for Flash Erase (in ms)      */
+#define CFG_FLASH_WRITE_TOUT   500     /* Timeout for Flash Write (in ms)      */
+
+/*-----------------------------------------------------------------------
+ * Cache Configuration
+ */
+#define CFG_CACHELINE_SIZE     16      /* For all MPC8xx CPUs                  */
+
+/*-----------------------------------------------------------------------
+ * SYPCR - System Protection Control                           11-9
+ * SYPCR can only be written once after reset!
+ *-----------------------------------------------------------------------
+ * Software & Bus Monitor Timer max, Bus Monitor enable, SW Watchdog freeze
+ */
+#define CFG_SYPCR      (SYPCR_SWTC | SYPCR_BMT | SYPCR_BME | SYPCR_SWF | SYPCR_SWP)
+
+/*-----------------------------------------------------------------------
+ * SUMCR - SIU Module Configuration                            11-6
+ *-----------------------------------------------------------------------
+ * PCMCIA config., multi-function pin tri-state
+ */
+#define CFG_SIUMCR     (SIUMCR_DBGC00 | SIUMCR_DBPC00 | SIUMCR_MLRC01)
+
+/*-----------------------------------------------------------------------
+ * TBSCR - Time Base Status and Control                                11-26
+ *-----------------------------------------------------------------------
+ * Clear Reference Interrupt Status, Timebase freezing enabled
+ */
+#define CFG_TBSCR      (TBSCR_REFA | TBSCR_REFB | TBSCR_TBF)
+
+/*-----------------------------------------------------------------------
+ * PISCR - Periodic Interrupt Status and Control               11-31
+ *-----------------------------------------------------------------------
+ * Clear Periodic Interrupt Status, Interrupt Timer freezing enabled
+ */
+#define CFG_PISCR      (PISCR_PS | PISCR_PITF)
+
+/*-----------------------------------------------------------------------
+ * PLPRCR - PLL, Low-Power, and Reset Control Register         15-30
+ *-----------------------------------------------------------------------
+ * Reset PLL lock status sticky bit, timer expired status bit and timer
+ * interrupt status bit - leave PLL multiplication factor unchanged !
+ */
+#define CFG_PLPRCR     (PLPRCR_SPLSS | PLPRCR_TEXPS | PLPRCR_TMIST)
+
+/*-----------------------------------------------------------------------
+ * SCCR - System Clock and reset Control Register              15-27
+ *-----------------------------------------------------------------------
+ * Set clock output, timebase and RTC source and divider,
+ * power management and some other internal clocks
+ */
+#define SCCR_MASK      SCCR_EBDF11
+#define CFG_SCCR       (SCCR_TBS     | \
+                        SCCR_COM00   | SCCR_DFSYNC00 | SCCR_DFBRG00  | \
+                        SCCR_DFNL000 | SCCR_DFNH000  | SCCR_DFLCD000 | \
+                        SCCR_DFALCD00)
+
+/*-----------------------------------------------------------------------
+ * 
+ *-----------------------------------------------------------------------
+ *
+ */
+/*#define      CFG_DER 0x2002000F*/
+#define CFG_DER        0
+
+#define MPC8XX_FACT    1               /* Multiply by 1                */
+#if 0
+#define MPC8XX_XIN     50000000        /* 50 MHz in    - ??? - XXX     */
+/* #define MPC8XX_BUSDIV 2  */
+#define MPC8XX_HZ ((MPC8XX_XIN) * (MPC8XX_FACT))
+#endif
+
+/*
+ * Init Memory Controller:
+ *
+ * BR0/1 and OR0/1 (FLASH)
+ */
+
+#define FLASH_BASE0_PRELIM     0x40000000      /* FLASH bank #0        */
+#define FLASH_BASE1_PRELIM     0x60000000      /* FLASH bank #0        */
+
+/* used to re-map FLASH both when starting from SRAM or FLASH:
+ * restrict access enough to keep SRAM working (if any)
+ * but not too much to meddle with FLASH accesses
+ */
+#define CFG_REMAP_OR_AM                0x80000000      /* OR addr mask */
+#define CFG_PRELIM_OR_AM       0xE0000000      /* OR addr mask */
+
+/* FLASH timing: ACS = 11, TRLX = 0, CSNT = 1, SCY = 5, EHTR = 1       */
+#define CFG_OR_TIMING_FLASH    (OR_CSNT_SAM  | OR_ACS_DIV2 | OR_BI | \
+                                OR_SCY_5_CLK | OR_EHTR)
+
+#define CFG_OR0_REMAP  (CFG_REMAP_OR_AM  | CFG_OR_TIMING_FLASH)
+#define CFG_OR0_PRELIM (CFG_PRELIM_OR_AM | CFG_OR_TIMING_FLASH)
+#define CFG_BR0_PRELIM ((FLASH_BASE0_PRELIM & BR_BA_MSK) | BR_V )
+
+#define CFG_OR1_REMAP  CFG_OR0_REMAP
+#define CFG_OR1_PRELIM CFG_OR0_PRELIM
+#define CFG_BR1_PRELIM ((FLASH_BASE1_PRELIM & BR_BA_MSK) | BR_V )
+
+/*
+ * BR2/3 and OR2/3 (SDRAM)
+ *
+ */
+#define SDRAM_BASE2_PRELIM     0x00000000      /* SDRAM bank #0        */
+#define SDRAM_BASE3_PRELIM     0x20000000      /* SDRAM bank #1        */
+#define        SDRAM_MAX_SIZE          0x04000000      /* max 64 MB per bank   */
+
+/* SDRAM timing: Multiplexed addresses, GPL5 output to GPL5_A (don't care)     */
+#define CFG_OR_TIMING_SDRAM    0x00000A00
+
+#define CFG_OR2_PRELIM (CFG_PRELIM_OR_AM | CFG_OR_TIMING_SDRAM )
+#define CFG_BR2_PRELIM ((SDRAM_BASE2_PRELIM & BR_BA_MSK) | BR_MS_UPMA | BR_V )
+
+#define        CFG_OR3_PRELIM  CFG_OR2_PRELIM
+#define CFG_BR3_PRELIM ((SDRAM_BASE3_PRELIM & BR_BA_MSK) | BR_MS_UPMA | BR_V )
+
+/*
+ * Memory Periodic Timer Prescaler
+ */
+
+/* periodic timer for refresh */
+#define CFG_MAMR_PTA   97              /* start with divider for 100 MHz       */
+
+/* refresh rate 15.6 us (= 64 ms / 4K = 62.4 / quad bursts) for <= 128 MBit    */
+#define CFG_MPTPR_2BK_4K       MPTPR_PTP_DIV16         /* setting for 2 banks  */
+#define CFG_MPTPR_1BK_4K       MPTPR_PTP_DIV32         /* setting for 1 bank   */
+
+/* refresh rate 7.8 us (= 64 ms / 8K = 31.2 / quad bursts) for 256 MBit                */
+#define CFG_MPTPR_2BK_8K       MPTPR_PTP_DIV8          /* setting for 2 banks  */
+#define CFG_MPTPR_1BK_8K       MPTPR_PTP_DIV16         /* setting for 1 bank   */
+
+/*
+ * MAMR settings for SDRAM
+ */
+
+/* 8 column SDRAM */
+#define CFG_MAMR_8COL  ((CFG_MAMR_PTA << MAMR_PTA_SHIFT)  | MAMR_PTAE      |   \
+                        MAMR_AMA_TYPE_0 | MAMR_DSA_1_CYCL | MAMR_G0CLA_A11 |   \
+                        MAMR_RLFA_1X    | MAMR_WLFA_1X    | MAMR_TLFA_4X)
+/* 9 column SDRAM */
+#define CFG_MAMR_9COL  ((CFG_MAMR_PTA << MAMR_PTA_SHIFT)  | MAMR_PTAE      |   \
+                        MAMR_AMA_TYPE_1 | MAMR_DSA_1_CYCL | MAMR_G0CLA_A10 |   \
+                        MAMR_RLFA_1X    | MAMR_WLFA_1X    | MAMR_TLFA_4X)
+
+
+/*
+ * Internal Definitions
+ *
+ * Boot Flags
+ */
+#define        BOOTFLAG_COLD   0x01            /* Normal Power-On: Boot from FLASH     */
+#define BOOTFLAG_WARM  0x02            /* Software reboot                      */
+
+#endif /* __CONFIG_H */
diff --git a/include/flash.h b/include/flash.h
new file mode 100644 (file)
index 0000000..3bbc9c1
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+
+/*-----------------------------------------------------------------------
+ * FLASH Info: contains chip specific data, per FLASH bank
+ */
+
+#ifdef __ASSEMBLY__
+
+#define FI_OFF_SIZE     0
+#define FI_OFF_SECT     4
+#define        FI_OFF_ID        6
+#define FI_OFF_FIRST    8
+#define FI_OFF_LAST    10
+#define FI_OFF_START   12
+
+#else  /* ! __ASSEMBLY__ */
+
+typedef struct {
+       ulong   size;                   /* total bank size in bytes             */
+       ushort  sector_count;           /* number of erase units                */
+       ushort  flash_id;               /* combined device & manufacturer code  */
+       ulong   start[CFG_MAX_FLASH_SECT];   /* physical sector start addresses */
+       uchar   protect[CFG_MAX_FLASH_SECT]; /* sector protection status        */
+} flash_info_t;
+
+/* Prototypes */
+
+unsigned long flash_init (void);
+void   flash_print_info (flash_info_t *);
+void   flash_erase      (flash_info_t *, int, int);
+
+#endif /* __ASSEMBLY__ */
+
+/*-----------------------------------------------------------------------
+ * Device IDs for AMD and Fujitsu FLASH
+ */
+
+#define AMD_MANUFACT   0x00010001      /* AMD     manuf. ID in D23..D16, D7..D0 */
+#define FUJ_MANUFACT   0x00040004      /* FUJITSU manuf. ID in D23..D16, D7..D0 */
+
+#define AMD_ID_LV400T  0x22B922B9      /* 29LV400T ID (4 M, top boot sector)   */
+#define AMD_ID_LV400B  0x22BA22BA      /* 29LV400B ID (4 M, bottom boot sect)  */
+
+#define AMD_ID_LV800T  0x22DA22DA      /* 29LV800T ID (8 M, top boot sector)   */
+#define AMD_ID_LV800B  0x225B225B      /* 29LV800B ID (8 M, bottom boot sect)  */
+
+#define AMD_ID_LV160T  0x22C422C4      /* 29LV160T ID (16 M, top boot sector)  */
+#define AMD_ID_LV160B  0x22492249      /* 29LV160B ID (16 M, bottom boot sect) */
+
+/* 29LV320 device IDs are not yet available */
+#define AMD_ID_LV320T  0xDEADBEEF      /* 29LV320T ID (32 M, top boot sector)  */
+#define AMD_ID_LV320B  0xDEADBEEF      /* 29LV320B ID (32 M, bottom boot sect) */
+
+/*-----------------------------------------------------------------------
+ * Internal FLASH identification codes
+ */
+
+#define FLASH_AM400T   0x00            /* AMD AM29LV400                        */
+#define FLASH_AM400B   0x01
+#define FLASH_AM800T   0x02            /* AMD AM29LV800                        */
+#define FLASH_AM800B   0x03
+#define FLASH_AM160T   0x04            /* AMD AM29LV160                        */
+#define FLASH_AM160B   0x05
+#define FLASH_AM320T   0x06            /* AMD AM29LV320                        */
+#define FLASH_AM320B   0x07
+#define FLASH_UNKNOWN  0xFF            /* unknown flash type                   */
+
+#define FLASH_MAN_AMD  0x00            /* manufacturer offsets                 */
+#define FLASH_MAN_FUJ  0x10
+
+#define FLASH_TYPEMASK 0x0F            /* extract FLASH type   information     */
+#define FLASH_VENDMASK 0xF0            /* extract FLASH vendor information     */
+
+#define FLASH_AMD_COMP 0x0F            /* Up to this ID, FLASH is compatible   */
+                                       /* with AMD and Fujitsu                 */
+                                       /* (JEDEC standard commands ?)          */
+
+#define FLASH_BTYPE    0x01            /* mask for bottom boot sector type     */
+
+/*-----------------------------------------------------------------------
+ * Timeout constants:
+ *
+ * We can't find any spcifications for maximum chip erase times,
+ * so these values are guestimates.
+ */
+#define FLASH_ERASE_TIMEOUT    120000  /* timeout for erasing in ms            */
+#define FLASH_WRITE_TIMEOUT    500     /* timeout for writes  in ms            */
+
diff --git a/include/image.h b/include/image.h
new file mode 100644 (file)
index 0000000..7119f0c
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef        __IMAGE_H__
+#define __IMAGE_H__
+
+/*
+ * Operating System Codes
+ */
+#define        IH_OS_INVALID           0       /* Invalid OS   */
+#define        IH_OS_OPENBSD           1       /* OpenBSD      */
+#define        IH_OS_NETBSD            2       /* NetBSD       */
+#define        IH_OS_FREEBSD           3       /* FreeBSD      */
+#define        IH_OS_4_4BSD            4       /* 4.4BSD       */
+#define        IH_OS_LINUX             5       /* Linux        */
+#define        IH_OS_SVR4              6       /* SVR4         */
+#define        IH_OS_ESIX              7       /* Esix         */
+#define        IH_OS_SOLARIS           8       /* Solaris      */
+#define        IH_OS_IRIX              9       /* Irix         */
+#define        IH_OS_SCO               10      /* SCO          */
+#define        IH_OS_DELL              11      /* Dell         */
+#define        IH_OS_NCR               12      /* NCR          */
+#define        IH_OS_LYNXOS            13      /* LynxOS       */
+#define        IH_OS_VXWORKS           14      /* VxWorks      */
+#define        IH_OS_PSOS              15      /* pSOS         */
+#define        IH_OS_QNX               16      /* QNX          */
+
+/*
+ * CPU Architecture Codes (supported by Linux)
+ */
+#define        IH_CPU_INVALID          0       /* Invalid CPU  */
+#define        IH_CPU_ALPHA            1       /* Alpha        */
+#define        IH_CPU_ARM              2       /* ARM          */
+#define        IH_CPU_I386             3       /* Intel x86    */
+#define        IH_CPU_IA64             4       /* IA64         */
+#define        IH_CPU_MIPS             5       /* MIPS         */
+#define        IH_CPU_MIPS64           6       /* MIPS  64 Bit */
+#define        IH_CPU_PPC              7       /* PowerPC      */
+#define        IH_CPU_S390             8       /* IBM S390     */
+#define        IH_CPU_SH               9       /* SuperH       */
+#define        IH_CPU_SPARC            10      /* Sparc        */
+#define        IH_CPU_SPARC64          11      /* Sparc 64 Bit */
+
+/*
+ * Image Types
+ */
+#define        IH_TYPE_INVALID         0       /* Invalid Image                */
+#define IH_TYPE_STANDALONE     1       /* Standalone Program           */
+#define IH_TYPE_KERNEL         2       /* OS Kernel Image              */
+#define IH_TYPE_RAMDISK                3       /* RAMDisk Image                */
+
+/*
+ * Compression Types
+ */
+#define IH_COMP_NONE           0       /*  No   Compression Used       */
+#define IH_COMP_GZIP           1       /* gzip  Compression Used       */
+#define IH_COMP_BZIP2          2       /* bzip2 Compression Used       */
+
+#define        IH_MAGIC        0x27051956      /* Image Magic Number           */
+#define        IH_NMLEN                32      /* Image Name Length            */
+
+/*
+ * all data in network byte order (aka natural aka bigendian)
+ */
+
+typedef struct image_header {
+       uint32_t        ih_magic;       /* Image Header Magic Number    */
+       uint32_t        ih_hcrc;        /* Image Header CRC Checksum    */
+       uint32_t        ih_time;        /* Image Creation Timestamp     */
+       uint32_t        ih_size;        /* Image Data Size              */
+       uint32_t        ih_load;        /* Data  Load  Address          */
+       uint32_t        ih_ep;          /* Entry Point Address          */
+       uint32_t        ih_dcrc;        /* Image Data CRC Checksum      */
+       uint8_t         ih_os;          /* Operating System             */
+       uint8_t         ih_arch;        /* CPU architecture             */
+       uint8_t         ih_type;        /* Image Type                   */
+       uint8_t         ih_comp;        /* Compression Type             */
+       uint8_t         ih_name[IH_NMLEN];      /* Image Name           */
+} image_header_t;
+
+
+#endif /* __IMAGE_H__ */
diff --git a/include/malloc.h b/include/malloc.h
new file mode 100644 (file)
index 0000000..033a77a
--- /dev/null
@@ -0,0 +1,949 @@
+/*
+  A version of malloc/free/realloc written by Doug Lea and released to the
+  public domain.  Send questions/comments/complaints/performance data
+  to dl@cs.oswego.edu
+
+* VERSION 2.6.6  Sun Mar  5 19:10:03 2000  Doug Lea  (dl at gee)
+
+   Note: There may be an updated version of this malloc obtainable at
+           ftp://g.oswego.edu/pub/misc/malloc.c
+         Check before installing!
+
+* Why use this malloc?
+
+  This is not the fastest, most space-conserving, most portable, or
+  most tunable malloc ever written. However it is among the fastest
+  while also being among the most space-conserving, portable and tunable.
+  Consistent balance across these factors results in a good general-purpose
+  allocator. For a high-level description, see
+     http://g.oswego.edu/dl/html/malloc.html
+
+* Synopsis of public routines
+
+  (Much fuller descriptions are contained in the program documentation below.)
+
+  malloc(size_t n);
+     Return a pointer to a newly allocated chunk of at least n bytes, or null
+     if no space is available.
+  free(Void_t* p);
+     Release the chunk of memory pointed to by p, or no effect if p is null.
+  realloc(Void_t* p, size_t n);
+     Return a pointer to a chunk of size n that contains the same data
+     as does chunk p up to the minimum of (n, p's size) bytes, or null
+     if no space is available. The returned pointer may or may not be
+     the same as p. If p is null, equivalent to malloc.  Unless the
+     #define REALLOC_ZERO_BYTES_FREES below is set, realloc with a
+     size argument of zero (re)allocates a minimum-sized chunk.
+  memalign(size_t alignment, size_t n);
+     Return a pointer to a newly allocated chunk of n bytes, aligned
+     in accord with the alignment argument, which must be a power of
+     two.
+  valloc(size_t n);
+     Equivalent to memalign(pagesize, n), where pagesize is the page
+     size of the system (or as near to this as can be figured out from
+     all the includes/defines below.)
+  pvalloc(size_t n);
+     Equivalent to valloc(minimum-page-that-holds(n)), that is,
+     round up n to nearest pagesize.
+  calloc(size_t unit, size_t quantity);
+     Returns a pointer to quantity * unit bytes, with all locations
+     set to zero.
+  cfree(Void_t* p);
+     Equivalent to free(p).
+  malloc_trim(size_t pad);
+     Release all but pad bytes of freed top-most memory back
+     to the system. Return 1 if successful, else 0.
+  malloc_usable_size(Void_t* p);
+     Report the number usable allocated bytes associated with allocated
+     chunk p. This may or may not report more bytes than were requested,
+     due to alignment and minimum size constraints.
+  malloc_stats();
+     Prints brief summary statistics on stderr.
+  mallinfo()
+     Returns (by copy) a struct containing various summary statistics.
+  mallopt(int parameter_number, int parameter_value)
+     Changes one of the tunable parameters described below. Returns
+     1 if successful in changing the parameter, else 0.
+
+* Vital statistics:
+
+  Alignment:                            8-byte
+       8 byte alignment is currently hardwired into the design.  This
+       seems to suffice for all current machines and C compilers.
+
+  Assumed pointer representation:       4 or 8 bytes
+       Code for 8-byte pointers is untested by me but has worked
+       reliably by Wolfram Gloger, who contributed most of the
+       changes supporting this.
+
+  Assumed size_t  representation:       4 or 8 bytes
+       Note that size_t is allowed to be 4 bytes even if pointers are 8.
+
+  Minimum overhead per allocated chunk: 4 or 8 bytes
+       Each malloced chunk has a hidden overhead of 4 bytes holding size
+       and status information.
+
+  Minimum allocated size: 4-byte ptrs:  16 bytes    (including 4 overhead)
+                          8-byte ptrs:  24/32 bytes (including, 4/8 overhead)
+
+       When a chunk is freed, 12 (for 4byte ptrs) or 20 (for 8 byte
+       ptrs but 4 byte size) or 24 (for 8/8) additional bytes are
+       needed; 4 (8) for a trailing size field
+       and 8 (16) bytes for free list pointers. Thus, the minimum
+       allocatable size is 16/24/32 bytes.
+
+       Even a request for zero bytes (i.e., malloc(0)) returns a
+       pointer to something of the minimum allocatable size.
+
+  Maximum allocated size: 4-byte size_t: 2^31 -  8 bytes
+                          8-byte size_t: 2^63 - 16 bytes
+
+       It is assumed that (possibly signed) size_t bit values suffice to
+       represent chunk sizes. `Possibly signed' is due to the fact
+       that `size_t' may be defined on a system as either a signed or
+       an unsigned type. To be conservative, values that would appear
+       as negative numbers are avoided.
+       Requests for sizes with a negative sign bit when the request
+       size is treaded as a long will return null.
+
+  Maximum overhead wastage per allocated chunk: normally 15 bytes
+
+       Alignnment demands, plus the minimum allocatable size restriction
+       make the normal worst-case wastage 15 bytes (i.e., up to 15
+       more bytes will be allocated than were requested in malloc), with
+       two exceptions:
+         1. Because requests for zero bytes allocate non-zero space,
+            the worst case wastage for a request of zero bytes is 24 bytes.
+         2. For requests >= mmap_threshold that are serviced via
+            mmap(), the worst case wastage is 8 bytes plus the remainder
+            from a system page (the minimal mmap unit); typically 4096 bytes.
+
+* Limitations
+
+    Here are some features that are NOT currently supported
+
+    * No user-definable hooks for callbacks and the like.
+    * No automated mechanism for fully checking that all accesses
+      to malloced memory stay within their bounds.
+    * No support for compaction.
+
+* Synopsis of compile-time options:
+
+    People have reported using previous versions of this malloc on all
+    versions of Unix, sometimes by tweaking some of the defines
+    below. It has been tested most extensively on Solaris and
+    Linux. It is also reported to work on WIN32 platforms.
+    People have also reported adapting this malloc for use in
+    stand-alone embedded systems.
+
+    The implementation is in straight, hand-tuned ANSI C.  Among other
+    consequences, it uses a lot of macros.  Because of this, to be at
+    all usable, this code should be compiled using an optimizing compiler
+    (for example gcc -O2) that can simplify expressions and control
+    paths.
+
+  __STD_C                  (default: derived from C compiler defines)
+     Nonzero if using ANSI-standard C compiler, a C++ compiler, or
+     a C compiler sufficiently close to ANSI to get away with it.
+  DEBUG                    (default: NOT defined)
+     Define to enable debugging. Adds fairly extensive assertion-based
+     checking to help track down memory errors, but noticeably slows down
+     execution.
+  REALLOC_ZERO_BYTES_FREES (default: NOT defined)
+     Define this if you think that realloc(p, 0) should be equivalent
+     to free(p). Otherwise, since malloc returns a unique pointer for
+     malloc(0), so does realloc(p, 0).
+  HAVE_MEMCPY               (default: defined)
+     Define if you are not otherwise using ANSI STD C, but still
+     have memcpy and memset in your C library and want to use them.
+     Otherwise, simple internal versions are supplied.
+  USE_MEMCPY               (default: 1 if HAVE_MEMCPY is defined, 0 otherwise)
+     Define as 1 if you want the C library versions of memset and
+     memcpy called in realloc and calloc (otherwise macro versions are used).
+     At least on some platforms, the simple macro versions usually
+     outperform libc versions.
+  HAVE_MMAP                 (default: defined as 1)
+     Define to non-zero to optionally make malloc() use mmap() to
+     allocate very large blocks.
+  HAVE_MREMAP                 (default: defined as 0 unless Linux libc set)
+     Define to non-zero to optionally make realloc() use mremap() to
+     reallocate very large blocks.
+  malloc_getpagesize        (default: derived from system #includes)
+     Either a constant or routine call returning the system page size.
+  HAVE_USR_INCLUDE_MALLOC_H (default: NOT defined)
+     Optionally define if you are on a system with a /usr/include/malloc.h
+     that declares struct mallinfo. It is not at all necessary to
+     define this even if you do, but will ensure consistency.
+  INTERNAL_SIZE_T           (default: size_t)
+     Define to a 32-bit type (probably `unsigned int') if you are on a
+     64-bit machine, yet do not want or need to allow malloc requests of
+     greater than 2^31 to be handled. This saves space, especially for
+     very small chunks.
+  INTERNAL_LINUX_C_LIB      (default: NOT defined)
+     Defined only when compiled as part of Linux libc.
+     Also note that there is some odd internal name-mangling via defines
+     (for example, internally, `malloc' is named `mALLOc') needed
+     when compiling in this case. These look funny but don't otherwise
+     affect anything.
+  WIN32                     (default: undefined)
+     Define this on MS win (95, nt) platforms to compile in sbrk emulation.
+  LACKS_UNISTD_H            (default: undefined if not WIN32)
+     Define this if your system does not have a <unistd.h>.
+  LACKS_SYS_PARAM_H         (default: undefined if not WIN32)
+     Define this if your system does not have a <sys/param.h>.
+  MORECORE                  (default: sbrk)
+     The name of the routine to call to obtain more memory from the system.
+  MORECORE_FAILURE          (default: -1)
+     The value returned upon failure of MORECORE.
+  MORECORE_CLEARS           (default 1)
+     True (1) if the routine mapped to MORECORE zeroes out memory (which
+     holds for sbrk).
+  DEFAULT_TRIM_THRESHOLD
+  DEFAULT_TOP_PAD
+  DEFAULT_MMAP_THRESHOLD
+  DEFAULT_MMAP_MAX
+     Default values of tunable parameters (described in detail below)
+     controlling interaction with host system routines (sbrk, mmap, etc).
+     These values may also be changed dynamically via mallopt(). The
+     preset defaults are those that give best performance for typical
+     programs/systems.
+  USE_DL_PREFIX             (default: undefined)
+     Prefix all public routines with the string 'dl'.  Useful to
+     quickly avoid procedure declaration conflicts and linker symbol
+     conflicts with existing memory allocation routines.
+
+
+*/
+
+\f
+
+
+/* Preliminaries */
+
+#ifndef __STD_C
+#ifdef __STDC__
+#define __STD_C     1
+#else
+#if __cplusplus
+#define __STD_C     1
+#else
+#define __STD_C     0
+#endif /*__cplusplus*/
+#endif /*__STDC__*/
+#endif /*__STD_C*/
+
+#ifndef Void_t
+#if (__STD_C || defined(WIN32))
+#define Void_t      void
+#else
+#define Void_t      char
+#endif
+#endif /*Void_t*/
+
+#if __STD_C
+#include <stddef.h>   /* for size_t */
+#else
+#include <sys/types.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if 0  /* no for PPCBOOT */
+#include <stdio.h>    /* needed for malloc_stats */
+#endif
+
+
+/*
+  Compile-time options
+*/
+
+
+/*
+    Debugging:
+
+    Because freed chunks may be overwritten with link fields, this
+    malloc will often die when freed memory is overwritten by user
+    programs.  This can be very effective (albeit in an annoying way)
+    in helping track down dangling pointers.
+
+    If you compile with -DDEBUG, a number of assertion checks are
+    enabled that will catch more memory errors. You probably won't be
+    able to make much sense of the actual assertion errors, but they
+    should help you locate incorrectly overwritten memory.  The
+    checking is fairly extensive, and will slow down execution
+    noticeably. Calling malloc_stats or mallinfo with DEBUG set will
+    attempt to check every non-mmapped allocated and free chunk in the
+    course of computing the summmaries. (By nature, mmapped regions
+    cannot be checked very much automatically.)
+
+    Setting DEBUG may also be helpful if you are trying to modify
+    this code. The assertions in the check routines spell out in more
+    detail the assumptions and invariants underlying the algorithms.
+
+*/
+
+#if DEBUG
+/* #include <assert.h> */
+#define assert(x) ((void)0)
+#else
+#define assert(x) ((void)0)
+#endif
+
+
+/*
+  INTERNAL_SIZE_T is the word-size used for internal bookkeeping
+  of chunk sizes. On a 64-bit machine, you can reduce malloc
+  overhead by defining INTERNAL_SIZE_T to be a 32 bit `unsigned int'
+  at the expense of not being able to handle requests greater than
+  2^31. This limitation is hardly ever a concern; you are encouraged
+  to set this. However, the default version is the same as size_t.
+*/
+
+#ifndef INTERNAL_SIZE_T
+#define INTERNAL_SIZE_T size_t
+#endif
+
+/*
+  REALLOC_ZERO_BYTES_FREES should be set if a call to
+  realloc with zero bytes should be the same as a call to free.
+  Some people think it should. Otherwise, since this malloc
+  returns a unique pointer for malloc(0), so does realloc(p, 0).
+*/
+
+
+/*   #define REALLOC_ZERO_BYTES_FREES */
+
+
+/*
+  WIN32 causes an emulation of sbrk to be compiled in
+  mmap-based options are not currently supported in WIN32.
+*/
+
+/* #define WIN32 */
+#ifdef WIN32
+#define MORECORE wsbrk
+#define HAVE_MMAP 0
+
+#define LACKS_UNISTD_H
+#define LACKS_SYS_PARAM_H
+
+/*
+  Include 'windows.h' to get the necessary declarations for the
+  Microsoft Visual C++ data structures and routines used in the 'sbrk'
+  emulation.
+
+  Define WIN32_LEAN_AND_MEAN so that only the essential Microsoft
+  Visual C++ header files are included.
+*/
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#endif
+
+
+/*
+  HAVE_MEMCPY should be defined if you are not otherwise using
+  ANSI STD C, but still have memcpy and memset in your C library
+  and want to use them in calloc and realloc. Otherwise simple
+  macro versions are defined here.
+
+  USE_MEMCPY should be defined as 1 if you actually want to
+  have memset and memcpy called. People report that the macro
+  versions are often enough faster than libc versions on many
+  systems that it is better to use them.
+
+*/
+
+#define HAVE_MEMCPY
+
+#ifndef USE_MEMCPY
+#ifdef HAVE_MEMCPY
+#define USE_MEMCPY 1
+#else
+#define USE_MEMCPY 0
+#endif
+#endif
+
+#if (__STD_C || defined(HAVE_MEMCPY))
+
+#if __STD_C
+void* memset(void*, int, size_t);
+void* memcpy(void*, const void*, size_t);
+#else
+#ifdef WIN32
+// On Win32 platforms, 'memset()' and 'memcpy()' are already declared in
+// 'windows.h'
+#else
+Void_t* memset();
+Void_t* memcpy();
+#endif
+#endif
+#endif
+
+#if USE_MEMCPY
+
+/* The following macros are only invoked with (2n+1)-multiples of
+   INTERNAL_SIZE_T units, with a positive integer n. This is exploited
+   for fast inline execution when n is small. */
+
+#define MALLOC_ZERO(charp, nbytes)                                            \
+do {                                                                          \
+  INTERNAL_SIZE_T mzsz = (nbytes);                                            \
+  if(mzsz <= 9*sizeof(mzsz)) {                                                \
+    INTERNAL_SIZE_T* mz = (INTERNAL_SIZE_T*) (charp);                         \
+    if(mzsz >= 5*sizeof(mzsz)) {     *mz++ = 0;                               \
+                                     *mz++ = 0;                               \
+      if(mzsz >= 7*sizeof(mzsz)) {   *mz++ = 0;                               \
+                                     *mz++ = 0;                               \
+        if(mzsz >= 9*sizeof(mzsz)) { *mz++ = 0;                               \
+                                     *mz++ = 0; }}}                           \
+                                     *mz++ = 0;                               \
+                                     *mz++ = 0;                               \
+                                     *mz   = 0;                               \
+  } else memset((charp), 0, mzsz);                                            \
+} while(0)
+
+#define MALLOC_COPY(dest,src,nbytes)                                          \
+do {                                                                          \
+  INTERNAL_SIZE_T mcsz = (nbytes);                                            \
+  if(mcsz <= 9*sizeof(mcsz)) {                                                \
+    INTERNAL_SIZE_T* mcsrc = (INTERNAL_SIZE_T*) (src);                        \
+    INTERNAL_SIZE_T* mcdst = (INTERNAL_SIZE_T*) (dest);                       \
+    if(mcsz >= 5*sizeof(mcsz)) {     *mcdst++ = *mcsrc++;                     \
+                                     *mcdst++ = *mcsrc++;                     \
+      if(mcsz >= 7*sizeof(mcsz)) {   *mcdst++ = *mcsrc++;                     \
+                                     *mcdst++ = *mcsrc++;                     \
+        if(mcsz >= 9*sizeof(mcsz)) { *mcdst++ = *mcsrc++;                     \
+                                     *mcdst++ = *mcsrc++; }}}                 \
+                                     *mcdst++ = *mcsrc++;                     \
+                                     *mcdst++ = *mcsrc++;                     \
+                                     *mcdst   = *mcsrc  ;                     \
+  } else memcpy(dest, src, mcsz);                                             \
+} while(0)
+
+#else /* !USE_MEMCPY */
+
+/* Use Duff's device for good zeroing/copying performance. */
+
+#define MALLOC_ZERO(charp, nbytes)                                            \
+do {                                                                          \
+  INTERNAL_SIZE_T* mzp = (INTERNAL_SIZE_T*)(charp);                           \
+  long mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T), mcn;                         \
+  if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; }             \
+  switch (mctmp) {                                                            \
+    case 0: for(;;) { *mzp++ = 0;                                             \
+    case 7:           *mzp++ = 0;                                             \
+    case 6:           *mzp++ = 0;                                             \
+    case 5:           *mzp++ = 0;                                             \
+    case 4:           *mzp++ = 0;                                             \
+    case 3:           *mzp++ = 0;                                             \
+    case 2:           *mzp++ = 0;                                             \
+    case 1:           *mzp++ = 0; if(mcn <= 0) break; mcn--; }                \
+  }                                                                           \
+} while(0)
+
+#define MALLOC_COPY(dest,src,nbytes)                                          \
+do {                                                                          \
+  INTERNAL_SIZE_T* mcsrc = (INTERNAL_SIZE_T*) src;                            \
+  INTERNAL_SIZE_T* mcdst = (INTERNAL_SIZE_T*) dest;                           \
+  long mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T), mcn;                         \
+  if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; }             \
+  switch (mctmp) {                                                            \
+    case 0: for(;;) { *mcdst++ = *mcsrc++;                                    \
+    case 7:           *mcdst++ = *mcsrc++;                                    \
+    case 6:           *mcdst++ = *mcsrc++;                                    \
+    case 5:           *mcdst++ = *mcsrc++;                                    \
+    case 4:           *mcdst++ = *mcsrc++;                                    \
+    case 3:           *mcdst++ = *mcsrc++;                                    \
+    case 2:           *mcdst++ = *mcsrc++;                                    \
+    case 1:           *mcdst++ = *mcsrc++; if(mcn <= 0) break; mcn--; }       \
+  }                                                                           \
+} while(0)
+
+#endif
+
+
+/*
+  Define HAVE_MMAP to optionally make malloc() use mmap() to
+  allocate very large blocks.  These will be returned to the
+  operating system immediately after a free().
+*/
+
+/***
+#ifndef HAVE_MMAP
+#define HAVE_MMAP 1
+#endif
+***/
+#undef HAVE_MMAP       /* Not available for PPCBOOT */
+
+/*
+  Define HAVE_MREMAP to make realloc() use mremap() to re-allocate
+  large blocks.  This is currently only possible on Linux with
+  kernel versions newer than 1.3.77.
+*/
+
+/***
+#ifndef HAVE_MREMAP
+#ifdef INTERNAL_LINUX_C_LIB
+#define HAVE_MREMAP 1
+#else
+#define HAVE_MREMAP 0
+#endif
+#endif
+***/
+#undef HAVE_MREMAP     /* Not available for PPCBOOT */
+
+#if HAVE_MMAP
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
+#define MAP_ANONYMOUS MAP_ANON
+#endif
+
+#endif /* HAVE_MMAP */
+
+/*
+  Access to system page size. To the extent possible, this malloc
+  manages memory from the system in page-size units.
+
+  The following mechanics for getpagesize were adapted from
+  bsd/gnu getpagesize.h
+*/
+
+#define        LACKS_UNISTD_H  /* Shortcut for PPCBOOT */
+#define        malloc_getpagesize      4096
+
+#ifndef LACKS_UNISTD_H
+#  include <unistd.h>
+#endif
+
+#ifndef malloc_getpagesize
+#  ifdef _SC_PAGESIZE         /* some SVR4 systems omit an underscore */
+#    ifndef _SC_PAGE_SIZE
+#      define _SC_PAGE_SIZE _SC_PAGESIZE
+#    endif
+#  endif
+#  ifdef _SC_PAGE_SIZE
+#    define malloc_getpagesize sysconf(_SC_PAGE_SIZE)
+#  else
+#    if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE)
+       extern size_t getpagesize();
+#      define malloc_getpagesize getpagesize()
+#    else
+#      ifdef WIN32
+#        define malloc_getpagesize (4096) /* TBD: Use 'GetSystemInfo' instead */
+#      else
+#        ifndef LACKS_SYS_PARAM_H
+#          include <sys/param.h>
+#        endif
+#        ifdef EXEC_PAGESIZE
+#          define malloc_getpagesize EXEC_PAGESIZE
+#        else
+#          ifdef NBPG
+#            ifndef CLSIZE
+#              define malloc_getpagesize NBPG
+#            else
+#              define malloc_getpagesize (NBPG * CLSIZE)
+#            endif
+#          else
+#            ifdef NBPC
+#              define malloc_getpagesize NBPC
+#            else
+#              ifdef PAGESIZE
+#                define malloc_getpagesize PAGESIZE
+#              else
+#                define malloc_getpagesize (4096) /* just guess */
+#              endif
+#            endif
+#          endif
+#        endif
+#      endif
+#    endif
+#  endif
+#endif
+
+
+
+/*
+
+  This version of malloc supports the standard SVID/XPG mallinfo
+  routine that returns a struct containing the same kind of
+  information you can get from malloc_stats. It should work on
+  any SVID/XPG compliant system that has a /usr/include/malloc.h
+  defining struct mallinfo. (If you'd like to install such a thing
+  yourself, cut out the preliminary declarations as described above
+  and below and save them in a malloc.h file. But there's no
+  compelling reason to bother to do this.)
+
+  The main declaration needed is the mallinfo struct that is returned
+  (by-copy) by mallinfo().  The SVID/XPG malloinfo struct contains a
+  bunch of fields, most of which are not even meaningful in this
+  version of malloc. Some of these fields are are instead filled by
+  mallinfo() with other numbers that might possibly be of interest.
+
+  HAVE_USR_INCLUDE_MALLOC_H should be set if you have a
+  /usr/include/malloc.h file that includes a declaration of struct
+  mallinfo.  If so, it is included; else an SVID2/XPG2 compliant
+  version is declared below.  These must be precisely the same for
+  mallinfo() to work.
+
+*/
+
+/* #define HAVE_USR_INCLUDE_MALLOC_H */
+
+#if HAVE_USR_INCLUDE_MALLOC_H
+#include "/usr/include/malloc.h"
+#else
+
+/* SVID2/XPG mallinfo structure */
+
+struct mallinfo {
+  int arena;    /* total space allocated from system */
+  int ordblks;  /* number of non-inuse chunks */
+  int smblks;   /* unused -- always zero */
+  int hblks;    /* number of mmapped regions */
+  int hblkhd;   /* total space in mmapped regions */
+  int usmblks;  /* unused -- always zero */
+  int fsmblks;  /* unused -- always zero */
+  int uordblks; /* total allocated space */
+  int fordblks; /* total non-inuse space */
+  int keepcost; /* top-most, releasable (via malloc_trim) space */
+};
+
+/* SVID2/XPG mallopt options */
+
+#define M_MXFAST  1    /* UNUSED in this malloc */
+#define M_NLBLKS  2    /* UNUSED in this malloc */
+#define M_GRAIN   3    /* UNUSED in this malloc */
+#define M_KEEP    4    /* UNUSED in this malloc */
+
+#endif
+
+/* mallopt options that actually do something */
+
+#define M_TRIM_THRESHOLD    -1
+#define M_TOP_PAD           -2
+#define M_MMAP_THRESHOLD    -3
+#define M_MMAP_MAX          -4
+
+
+
+#ifndef DEFAULT_TRIM_THRESHOLD
+#define DEFAULT_TRIM_THRESHOLD (128 * 1024)
+#endif
+
+/*
+    M_TRIM_THRESHOLD is the maximum amount of unused top-most memory
+      to keep before releasing via malloc_trim in free().
+
+      Automatic trimming is mainly useful in long-lived programs.
+      Because trimming via sbrk can be slow on some systems, and can
+      sometimes be wasteful (in cases where programs immediately
+      afterward allocate more large chunks) the value should be high
+      enough so that your overall system performance would improve by
+      releasing.
+
+      The trim threshold and the mmap control parameters (see below)
+      can be traded off with one another. Trimming and mmapping are
+      two different ways of releasing unused memory back to the
+      system. Between these two, it is often possible to keep
+      system-level demands of a long-lived program down to a bare
+      minimum. For example, in one test suite of sessions measuring
+      the XF86 X server on Linux, using a trim threshold of 128K and a
+      mmap threshold of 192K led to near-minimal long term resource
+      consumption.
+
+      If you are using this malloc in a long-lived program, it should
+      pay to experiment with these values.  As a rough guide, you
+      might set to a value close to the average size of a process
+      (program) running on your system.  Releasing this much memory
+      would allow such a process to run in memory.  Generally, it's
+      worth it to tune for trimming rather tham memory mapping when a
+      program undergoes phases where several large chunks are
+      allocated and released in ways that can reuse each other's
+      storage, perhaps mixed with phases where there are no such
+      chunks at all.  And in well-behaved long-lived programs,
+      controlling release of large blocks via trimming versus mapping
+      is usually faster.
+
+      However, in most programs, these parameters serve mainly as
+      protection against the system-level effects of carrying around
+      massive amounts of unneeded memory. Since frequent calls to
+      sbrk, mmap, and munmap otherwise degrade performance, the default
+      parameters are set to relatively high values that serve only as
+      safeguards.
+
+      The default trim value is high enough to cause trimming only in
+      fairly extreme (by current memory consumption standards) cases.
+      It must be greater than page size to have any useful effect.  To
+      disable trimming completely, you can set to (unsigned long)(-1);
+
+
+*/
+
+
+#ifndef DEFAULT_TOP_PAD
+#define DEFAULT_TOP_PAD        (0)
+#endif
+
+/*
+    M_TOP_PAD is the amount of extra `padding' space to allocate or
+      retain whenever sbrk is called. It is used in two ways internally:
+
+      * When sbrk is called to extend the top of the arena to satisfy
+        a new malloc request, this much padding is added to the sbrk
+        request.
+
+      * When malloc_trim is called automatically from free(),
+        it is used as the `pad' argument.
+
+      In both cases, the actual amount of padding is rounded
+      so that the end of the arena is always a system page boundary.
+
+      The main reason for using padding is to avoid calling sbrk so
+      often. Having even a small pad greatly reduces the likelihood
+      that nearly every malloc request during program start-up (or
+      after trimming) will invoke sbrk, which needlessly wastes
+      time.
+
+      Automatic rounding-up to page-size units is normally sufficient
+      to avoid measurable overhead, so the default is 0.  However, in
+      systems where sbrk is relatively slow, it can pay to increase
+      this value, at the expense of carrying around more memory than
+      the program needs.
+
+*/
+
+
+#ifndef DEFAULT_MMAP_THRESHOLD
+#define DEFAULT_MMAP_THRESHOLD (128 * 1024)
+#endif
+
+/*
+
+    M_MMAP_THRESHOLD is the request size threshold for using mmap()
+      to service a request. Requests of at least this size that cannot
+      be allocated using already-existing space will be serviced via mmap.
+      (If enough normal freed space already exists it is used instead.)
+
+      Using mmap segregates relatively large chunks of memory so that
+      they can be individually obtained and released from the host
+      system. A request serviced through mmap is never reused by any
+      other request (at least not directly; the system may just so
+      happen to remap successive requests to the same locations).
+
+      Segregating space in this way has the benefit that mmapped space
+      can ALWAYS be individually released back to the system, which
+      helps keep the system level memory demands of a long-lived
+      program low. Mapped memory can never become `locked' between
+      other chunks, as can happen with normally allocated chunks, which
+      menas that even trimming via malloc_trim would not release them.
+
+      However, it has the disadvantages that:
+
+         1. The space cannot be reclaimed, consolidated, and then
+            used to service later requests, as happens with normal chunks.
+         2. It can lead to more wastage because of mmap page alignment
+            requirements
+         3. It causes malloc performance to be more dependent on host
+            system memory management support routines which may vary in
+            implementation quality and may impose arbitrary
+            limitations. Generally, servicing a request via normal
+            malloc steps is faster than going through a system's mmap.
+
+      All together, these considerations should lead you to use mmap
+      only for relatively large requests.
+
+
+*/
+
+
+
+#ifndef DEFAULT_MMAP_MAX
+#if HAVE_MMAP
+#define DEFAULT_MMAP_MAX       (64)
+#else
+#define DEFAULT_MMAP_MAX       (0)
+#endif
+#endif
+
+/*
+    M_MMAP_MAX is the maximum number of requests to simultaneously
+      service using mmap. This parameter exists because:
+
+         1. Some systems have a limited number of internal tables for
+            use by mmap.
+         2. In most systems, overreliance on mmap can degrade overall
+            performance.
+         3. If a program allocates many large regions, it is probably
+            better off using normal sbrk-based allocation routines that
+            can reclaim and reallocate normal heap memory. Using a
+            small value allows transition into this mode after the
+            first few allocations.
+
+      Setting to 0 disables all use of mmap.  If HAVE_MMAP is not set,
+      the default value is 0, and attempts to set it to non-zero values
+      in mallopt will fail.
+*/
+
+
+
+
+/*
+    USE_DL_PREFIX will prefix all public routines with the string 'dl'.
+      Useful to quickly avoid procedure declaration conflicts and linker
+      symbol conflicts with existing memory allocation routines.
+
+*/
+
+/* #define USE_DL_PREFIX */
+
+
+
+
+/*
+
+  Special defines for linux libc
+
+  Except when compiled using these special defines for Linux libc
+  using weak aliases, this malloc is NOT designed to work in
+  multithreaded applications.  No semaphores or other concurrency
+  control are provided to ensure that multiple malloc or free calls
+  don't run at the same time, which could be disasterous. A single
+  semaphore could be used across malloc, realloc, and free (which is
+  essentially the effect of the linux weak alias approach). It would
+  be hard to obtain finer granularity.
+
+*/
+
+
+#ifdef INTERNAL_LINUX_C_LIB
+
+#if __STD_C
+
+Void_t * __default_morecore_init (ptrdiff_t);
+Void_t *(*__morecore)(ptrdiff_t) = __default_morecore_init;
+
+#else
+
+Void_t * __default_morecore_init ();
+Void_t *(*__morecore)() = __default_morecore_init;
+
+#endif
+
+#define MORECORE (*__morecore)
+#define MORECORE_FAILURE 0
+#define MORECORE_CLEARS 1
+
+#else /* INTERNAL_LINUX_C_LIB */
+
+#if __STD_C
+extern Void_t*     sbrk(ptrdiff_t);
+#else
+extern Void_t*     sbrk();
+#endif
+
+#ifndef MORECORE
+#define MORECORE sbrk
+#endif
+
+#ifndef MORECORE_FAILURE
+#define MORECORE_FAILURE -1
+#endif
+
+#ifndef MORECORE_CLEARS
+#define MORECORE_CLEARS 1
+#endif
+
+#endif /* INTERNAL_LINUX_C_LIB */
+
+#if defined(INTERNAL_LINUX_C_LIB) && defined(__ELF__)
+
+#define cALLOc         __libc_calloc
+#define fREe           __libc_free
+#define mALLOc         __libc_malloc
+#define mEMALIGn       __libc_memalign
+#define rEALLOc                __libc_realloc
+#define vALLOc         __libc_valloc
+#define pvALLOc                __libc_pvalloc
+#define mALLINFo       __libc_mallinfo
+#define mALLOPt                __libc_mallopt
+
+#pragma weak calloc = __libc_calloc
+#pragma weak free = __libc_free
+#pragma weak cfree = __libc_free
+#pragma weak malloc = __libc_malloc
+#pragma weak memalign = __libc_memalign
+#pragma weak realloc = __libc_realloc
+#pragma weak valloc = __libc_valloc
+#pragma weak pvalloc = __libc_pvalloc
+#pragma weak mallinfo = __libc_mallinfo
+#pragma weak mallopt = __libc_mallopt
+
+#else
+
+#ifdef USE_DL_PREFIX
+#define cALLOc         dlcalloc
+#define fREe           dlfree
+#define mALLOc         dlmalloc
+#define mEMALIGn       dlmemalign
+#define rEALLOc                dlrealloc
+#define vALLOc         dlvalloc
+#define pvALLOc                dlpvalloc
+#define mALLINFo       dlmallinfo
+#define mALLOPt                dlmallopt
+#else /* USE_DL_PREFIX */
+#define cALLOc         calloc
+#define fREe           free
+#define mALLOc         malloc
+#define mEMALIGn       memalign
+#define rEALLOc                realloc
+#define vALLOc         valloc
+#define pvALLOc                pvalloc
+#define mALLINFo       mallinfo
+#define mALLOPt                mallopt
+#endif /* USE_DL_PREFIX */
+
+#endif
+
+/* Public routines */
+
+#if __STD_C
+
+Void_t* mALLOc(size_t);
+void    fREe(Void_t*);
+Void_t* rEALLOc(Void_t*, size_t);
+Void_t* mEMALIGn(size_t, size_t);
+Void_t* vALLOc(size_t);
+Void_t* pvALLOc(size_t);
+Void_t* cALLOc(size_t, size_t);
+void    cfree(Void_t*);
+int     malloc_trim(size_t);
+size_t  malloc_usable_size(Void_t*);
+void    malloc_stats(void);
+int     mALLOPt(int, int);
+struct mallinfo mALLINFo(void);
+#else
+Void_t* mALLOc();
+void    fREe();
+Void_t* rEALLOc();
+Void_t* mEMALIGn();
+Void_t* vALLOc();
+Void_t* pvALLOc();
+Void_t* cALLOc();
+void    cfree();
+int     malloc_trim();
+size_t  malloc_usable_size();
+void    malloc_stats();
+int     mALLOPt();
+struct mallinfo mALLINFo();
+#endif
+
+
+#ifdef __cplusplus
+};  /* end of extern "C" */
+#endif
diff --git a/include/mpc8xx.h b/include/mpc8xx.h
new file mode 100644 (file)
index 0000000..976deae
--- /dev/null
@@ -0,0 +1,432 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * mpc8xx.h
+ *
+ * MPC8xx specific definitions
+ */
+
+#ifndef __MPCXX_H__
+#define __MPCXX_H__
+
+
+/*-----------------------------------------------------------------------
+ * Exception offsets (PowerPC standard)
+ */
+#define EXC_OFF_SYS_RESET      0x0100  /* System reset                         */
+
+
+/*-----------------------------------------------------------------------
+ * SYPCR - System Protection Control Register                          11-9
+ */
+#define SYPCR_SWTC     0xffff0000      /* Software Watchdog Timer Count        */
+#define SYPCR_BMT      0x0000ff00      /* Bus Monitor Timing                   */
+#define SYPCR_BME      0x00000080      /* Bus Monitor Enable                   */
+#define SYPCR_SWF      0x00000008      /* Software Watchdog Freeze             */
+#define SYPCR_SWE      0x00000004      /* Software Watchdog Enable             */
+#define SYPCR_SWRI     0x00000002      /* Software Watchdog Reset/Int Select   */
+#define SYPCR_SWP      0x00000001      /* Software Watchdog Prescale           */
+
+/*-----------------------------------------------------------------------
+ * SIUMCR - SIU Module Configuration Register                          11-6
+ */
+#define SIUMCR_EARB    0x80000000      /* External Arbitation                  */
+#define SIUMCR_EARP111 0x70000000      /* Extern Arbi. Request prior.          */
+#define SIUMCR_DSHW    0x00800000      /* Data Showcycles                      */
+#define SIUMCR_DBGC00  0x00000000      /* Debug pins configuration             */
+#define SIUMCR_DBGC01  0x00200000      /* - " -                                */
+#define SIUMCR_DBGC10  0x00400000      /* - " -                                */
+#define SIUMCR_DBGC11  0x00600000      /* - " -                                */
+#define SIUMCR_DBPC00  0x00000000      /* Debug Port pins Config.              */
+#define SIUMCR_DBPC01  0x00080000      /* - " -                                */
+#define SIUMCR_DBPC10  0x00100000      /* - " -                                */
+#define SIUMCR_DBPC11  0x00180000      /* - " -                                */
+#define SIUMCR_FRC     0x00020000      /* FRZ pin Configuration                */
+#define SIUMCR_DLK     0x00010000      /* Debug Register Lock                  */
+#define SIUMCR_PNCS    0x00008000      /* Parity Non-mem Crtl reg              */
+#define SIUMCR_OPAR    0x00004000      /* Odd Parity                           */
+#define SIUMCR_DPC     0x00002000      /* Data Parity pins Config.             */
+#define SIUMCR_MPRE    0x00001000      /* Multi CPU Reserva. Enable            */
+#define SIUMCR_MLRC00  0x00000000      /* Multi Level Reserva. Ctrl            */
+#define SIUMCR_MLRC01  0x00000400      /* - " -                                */
+#define SIUMCR_MLRC10  0x00000800      /* - " -                                */
+#define SIUMCR_MLRC11  0x00000c00      /* - " -                                */
+#define SIUMCR_AEME    0x00000200      /* Asynchro External Master             */
+#define SIUMCR_SEME    0x00000100      /* Synchro External Master              */
+#define SIUMCR_BSC     0x00000080      /* Byte Select Configuration            */
+#define SIUMCR_GB5E    0x00000040      /* GPL_B(5) Enable                      */
+#define SIUMCR_B2DD    0x00000020      /* Bank 2 Double Drive                  */
+#define SIUMCR_B3DD    0x00000010      /* Bank 3 Double Drive                  */
+
+/*-----------------------------------------------------------------------
+ * TBSCR - Time Base Status and Control Register                       11-26
+ */
+#define TBSCR_TBIRQ7   0x8000          /* Time Base Interrupt Request 7        */
+#define TBSCR_TBIRQ6   0x4000          /* Time Base Interrupt Request 6        */
+#define TBSCR_TBIRQ5   0x2000          /* Time Base Interrupt Request 5        */
+#define TBSCR_TBIRQ4   0x1000          /* Time Base Interrupt Request 4        */
+#define TBSCR_TBIRQ3   0x0800          /* Time Base Interrupt Request 3        */
+#define TBSCR_TBIRQ2   0x0400          /* Time Base Interrupt Request 2        */
+#define TBSCR_TBIRQ1   0x0200          /* Time Base Interrupt Request 1        */
+#define TBSCR_TBIRQ0   0x0100          /* Time Base Interrupt Request 0        */
+#if 0  /* already in asm/8xx_immap.h */
+#define TBSCR_REFA     0x0080          /* Reference Interrupt Status A         */
+#define TBSCR_REFB     0x0040          /* Reference Interrupt Status B         */
+#define TBSCR_REFAE    0x0008          /* Second Interrupt Enable A            */
+#define TBSCR_REFBE    0x0004          /* Second Interrupt Enable B            */
+#define TBSCR_TBF      0x0002          /* Time Base Freeze                     */
+#define TBSCR_TBE      0x0001          /* Time Base Enable                     */
+#endif
+
+/*-----------------------------------------------------------------------
+ * PISCR - Periodic Interrupt Status and Control Register              11-31
+ */
+#undef PISCR_PIRQ                      /* TBD                                  */
+#define PISCR_PITF     0x0002          /* Periodic Interrupt Timer Freeze      */
+#if 0  /* already in asm/8xx_immap.h */
+#define PISCR_PS       0x0080          /* Periodic interrupt Status            */
+#define PISCR_PIE      0x0004          /* Periodic Interrupt Enable            */
+#define PISCR_PTE      0x0001          /* Periodic Timer Enable                */
+#endif
+
+/*-----------------------------------------------------------------------
+ * PLPRCR - PLL, Low-Power, and Reset Control Register                 15-30
+ */
+#define PLPRCR_MF_MSK  0xfff00000      /* Multiplication factor bits           */
+#define PLPRCR_MF_SHIFT 0x00000014     /* Multiplication factor shift value    */
+#define PLPRCR_SPLSS   0x00008000      /* SPLL Lock Status Sticky bit          */
+#define PLPRCR_TEXPS   0x00004000      /* TEXP Status                          */
+#define PLPRCR_TMIST   0x00001000      /* Timers Interrupt Status              */
+#define PLPRCR_CSRC    0x00000400      /* Clock Source                         */
+#define PLPRCR_LPM_MSK 0x00000300      /* Low Power Mode mask                  */
+#define PLPRCR_LPM_NORMAL 0x00000000   /* normal power management mode         */
+#define PLPRCR_LPM_DOZE          0x00000100    /* doze power management mode           */
+#define PLPRCR_LPM_SLEEP  0x00000200   /* sleep power management mode          */
+#define PLPRCR_LPM_DEEP_SLEEP 0x00000300 /* deep sleep power mgt mode          */
+#define PLPRCR_LPM_DOWN          0x00000300    /* down power management mode           */
+#define PLPRCR_CSR     0x00000080      /* CheskStop Reset value                */
+#define PLPRCR_LOLRE   0x00000040      /* Loss Of Lock Reset Enable            */
+#define PLPRCR_FIOPD   0x00000020      /* Force I/O Pull Down                  */
+
+/*-----------------------------------------------------------------------
+ * SCCR - System Clock and reset Control Register                      15-27
+ */
+#define SCCR_COM00     0x00000000      /* full strength CLKOUT output buffer   */
+#define SCCR_COM01     0x20000000      /* half strength CLKOUT output buffer   */
+#define SCCR_COM10     0x40000000      /* reserved                             */
+#define SCCR_COM11     0x60000000      /* CLKOUT output buffer disabled        */
+#define SCCR_TBS       0x02000000      /* Time Base Source                     */
+#define SCCR_RTDIV     0x01000000      /* RTC Clock Dive                       */
+#define SCCR_RTSEL     0x00800000      /* RTC circuit input source select      */
+#define SCCR_CRQEN     0x00400000      /* CPM Request Enable                   */
+#define SCCR_PRQEN     0x00200000      /* Power Management Request Enable      */
+#define SCCR_EBDF00    0x00000000      /* CLKOUT is GCLK2 / 1 (normal op.)     */
+#define SCCR_EBDF01    0x00020000      /* CLKOUT is GCLK2 / 2                  */
+#define SCCR_EBDF10    0x00040000      /* reserved                             */
+#define SCCR_EBDF11    0x00060000      /* reserved                             */
+#define SCCR_DFSYNC00  0x00000000      /* SyncCLK division by 1 (normal op.)   */
+#define SCCR_DFSYNC01  0x00002000      /* SyncCLK division by 4                */
+#define SCCR_DFSYNC10  0x00004000      /* SyncCLK division by 16               */
+#define SCCR_DFSYNC11  0x00006000      /* SyncCLK division by 64               */
+#define SCCR_DFBRG00   0x00000000      /* BRGCLK division by 1 (normal op.)    */
+#define SCCR_DFBRG01   0x00000800      /* BRGCLK division by 4                 */
+#define SCCR_DFBRG10   0x00001000      /* BRGCLK division by 16                */
+#define SCCR_DFBRG11   0x00001800      /* BRGCLK division by 64                */
+#define SCCR_DFNL000   0x00000000      /* Division by 2 (default = minimum)    */
+#define SCCR_DFNL111   0x00000700      /* Division by 256 (maximum)            */
+#define SCCR_DFNH000   0x00000000      /* Division by 1 (default = minimum)    */
+#define SCCR_DFNH110   0x000000D0      /* Division by 64 (maximum)             */
+#define SCCR_DFNH111   0x000000E0      /* reserved                             */
+#define SCCR_DFLCD000  0x00000000      /* Division by 1 (default = minimum)    */
+#define SCCR_DFLCD110  0x00000180      /* Division by 64 (maximum)             */
+#define SCCR_DFLCD111  0x000001C0      /* reserved                             */
+#define SCCR_DFALCD00  0x00000000      /* Division by 1 (default = minimum)    */
+#define SCCR_DFALCD01  0x00000001      /* Division by 3                        */
+#define SCCR_DFALCD10  0x00000002      /* Division by 5                        */
+#define SCCR_DFALCD11  0x00000003      /* Division by 7 (maximum)              */
+
+
+/*-----------------------------------------------------------------------
+ * BR - Memory Controler: Base Register                                        16-9
+ */
+#define BR_BA_MSK      0xffff8000      /* Base Address Mask                    */
+#define BR_AT_MSK      0x00007000      /* Address Type Mask                    */
+#define BR_PS_MSK      0x00000c00      /* Port Size Mask                       */
+#define BR_PARE                0x00000200      /* Parity Enable                        */
+#define BR_WP          0x00000100      /* Write Protect                        */
+#define BR_MS_MSK      0x000000c0      /* Machine Select Mask                  */
+#define BR_MS_GPCM     0x00000000      /* G.P.C.M. Machine Select              */
+#define BR_MS_UPMA     0x00000080      /* U.P.M.A Machine Select               */
+#define BR_MS_UPMB     0x000000c0      /* U.P.M.B Machine Select               */
+#define BR_V           0x00000001      /* Bank Valid                           */
+#define BR_PS_8                0x00000400      /*  8 bit port size                     */
+#define BR_PS_16       0x00000800      /* 16 bit port size                     */
+#define BR_PS_32       0x00000000      /* 32 bit port size                     */
+
+/*-----------------------------------------------------------------------
+ * OR - Memory Controler: Option Register                              16-11
+ */
+#define OR_AM_MSK      0xffff8000      /* Address Mask Mask                    */
+#define OR_ATM_MSK     0x00007000      /* Address Type Mask Mask               */
+#define OR_CSNT_SAM    0x00000800      /* Chip Select Negation Time/ Start     */
+                                       /* Address Multiplex                    */
+#define OR_ACS_MSK     0x00000600      /* Address to Chip Select Setup mask    */
+#define OR_ACS_DIV1    0x00000000      /* CS is output at the same time        */
+#define OR_ACS_DIV4    0x00000400      /* CS is output 1/4 a clock later       */
+#define OR_ACS_DIV2    0x00000600      /* CS is output 1/2 a clock later       */
+#define OR_BI          0x00000100      /* Burst inhibit                        */
+#define OR_SCY_MSK     0x000000f0      /* Cycle Lenght in Clocks               */
+#define OR_SCY_0_CLK   0x00000000      /* 0 clock cycles wait states           */
+#define OR_SCY_1_CLK   0x00000010      /* 1 clock cycles wait states           */
+#define OR_SCY_2_CLK   0x00000020      /* 2 clock cycles wait states           */
+#define OR_SCY_3_CLK   0x00000030      /* 3 clock cycles wait states           */
+#define OR_SCY_4_CLK   0x00000040      /* 4 clock cycles wait states           */
+#define OR_SCY_5_CLK   0x00000050      /* 5 clock cycles wait states           */
+#define OR_SCY_6_CLK   0x00000060      /* 6 clock cycles wait states           */
+#define OR_SCY_7_CLK   0x00000070      /* 7 clock cycles wait states           */
+#define OR_SCY_8_CLK   0x00000080      /* 8 clock cycles wait states           */
+#define OR_SCY_9_CLK   0x00000090      /* 9 clock cycles wait states           */
+#define OR_SCY_10_CLK  0x000000a0      /* 10 clock cycles wait states          */
+#define OR_SCY_11_CLK  0x000000b0      /* 11 clock cycles wait states          */
+#define OR_SCY_12_CLK  0x000000c0      /* 12 clock cycles wait states          */
+#define OR_SCY_13_CLK  0x000000d0      /* 13 clock cycles wait states          */
+#define OR_SCY_14_CLK  0x000000e0      /* 14 clock cycles wait states          */
+#define OR_SCY_15_CLK  0x000000f0      /* 15 clock cycles wait states          */
+#define OR_SETA                0x00000008      /* External Transfer Acknowledge        */
+#define OR_TRLX                0x00000004      /* Timing Relaxed                       */
+#define OR_EHTR                0x00000002      /* Extended Hold Time on Read           */
+
+
+/*-----------------------------------------------------------------------
+ * MPTPR - Memory Periodic Timer Prescaler Register                    16-17
+ */
+#define MPTPR_PTP_MSK  0xff00          /* Periodic Timers Prescaler Mask       */
+#define MPTPR_PTP_DIV2 0x2000          /* BRGCLK divided by 2                  */
+#define MPTPR_PTP_DIV4 0x1000          /* BRGCLK divided by 4                  */
+#define MPTPR_PTP_DIV8 0x0800          /* BRGCLK divided by 8                  */
+#define MPTPR_PTP_DIV16 0x0400         /* BRGCLK divided by 16                 */
+#define MPTPR_PTP_DIV32 0x0200         /* BRGCLK divided by 32                 */
+#define MPTPR_PTP_DIV64 0x0100         /* BRGCLK divided by 64                 */
+
+
+/*-----------------------------------------------------------------------
+ * Machine A Mode Register                                             16-13
+ */
+#define MAMR_PTA_MSK   0xff000000      /* Periodic Timer A period mask         */
+#define MAMR_PTA_SHIFT 0x00000018      /* Periodic Timer A period shift        */
+#define MAMR_PTAE      0x00800000      /* Periodic Timer A Enable              */
+#define MAMR_AMA_MSK   0x00700000      /* Addess Multiplexing size A           */
+#define MAMR_AMA_TYPE_0 0x00000000     /* Addess Multiplexing Type 0           */
+#define MAMR_AMA_TYPE_1 0x00100000     /* Addess Multiplexing Type 1           */
+#define MAMR_AMA_TYPE_2 0x00200000     /* Addess Multiplexing Type 2           */
+#define MAMR_AMA_TYPE_3 0x00300000     /* Addess Multiplexing Type 3           */
+#define MAMR_AMA_TYPE_4 0x00400000     /* Addess Multiplexing Type 4           */
+#define MAMR_AMA_TYPE_5 0x00500000     /* Addess Multiplexing Type 5           */
+#define MAMR_DSA_MSK   0x00060000      /* Disable Timer period mask            */
+#define MAMR_DSA_1_CYCL 0x00000000     /* 1 cycle Disable Period               */
+#define MAMR_DSA_2_CYCL 0x00020000     /* 2 cycle Disable Period               */
+#define MAMR_DSA_3_CYCL 0x00040000     /* 3 cycle Disable Period               */
+#define MAMR_DSA_4_CYCL 0x00060000     /* 4 cycle Disable Period               */
+#define MAMR_G0CLA_MSK 0x0000e000      /* General Line 0 Control A             */
+#define MAMR_G0CLA_A12 0x00000000      /* General Line 0 : A12                 */
+#define MAMR_G0CLA_A11 0x00002000      /* General Line 0 : A11                 */
+#define MAMR_G0CLA_A10 0x00004000      /* General Line 0 : A10                 */
+#define MAMR_G0CLA_A9  0x00006000      /* General Line 0 : A9                  */
+#define MAMR_G0CLA_A8  0x00008000      /* General Line 0 : A8                  */
+#define MAMR_G0CLA_A7  0x0000a000      /* General Line 0 : A7                  */
+#define MAMR_G0CLA_A6  0x0000b000      /* General Line 0 : A6                  */
+#define MAMR_G0CLA_A5  0x0000e000      /* General Line 0 : A5                  */
+#define MAMR_GPL_A4DIS 0x00001000      /* GPL_A4 ouput line Disable            */
+#define MAMR_RLFA_MSK  0x00000f00      /* Read Loop Field A mask               */
+#define MAMR_RLFA_1X   0x00000100      /* The Read Loop is executed 1 time     */
+#define MAMR_RLFA_2X   0x00000200      /* The Read Loop is executed 2 times    */
+#define MAMR_RLFA_3X   0x00000300      /* The Read Loop is executed 3 times    */
+#define MAMR_RLFA_4X   0x00000400      /* The Read Loop is executed 4 times    */
+#define MAMR_RLFA_5X   0x00000500      /* The Read Loop is executed 5 times    */
+#define MAMR_RLFA_6X   0x00000600      /* The Read Loop is executed 6 times    */
+#define MAMR_RLFA_7X   0x00000700      /* The Read Loop is executed 7 times    */
+#define MAMR_RLFA_8X   0x00000800      /* The Read Loop is executed 8 times    */
+#define MAMR_RLFA_9X   0x00000900      /* The Read Loop is executed 9 times    */
+#define MAMR_RLFA_10X  0x00000a00      /* The Read Loop is executed 10 times   */
+#define MAMR_RLFA_11X  0x00000b00      /* The Read Loop is executed 11 times   */
+#define MAMR_RLFA_12X  0x00000c00      /* The Read Loop is executed 12 times   */
+#define MAMR_RLFA_13X  0x00000d00      /* The Read Loop is executed 13 times   */
+#define MAMR_RLFA_14X  0x00000e00      /* The Read Loop is executed 14 times   */
+#define MAMR_RLFA_15X  0x00000f00      /* The Read Loop is executed 15 times   */
+#define MAMR_RLFA_16X  0x00000000      /* The Read Loop is executed 16 times   */
+#define MAMR_WLFA_MSK  0x000000f0      /* Write Loop Field A mask              */
+#define MAMR_WLFA_1X   0x00000010      /* The Write Loop is executed 1 time    */
+#define MAMR_WLFA_2X   0x00000020      /* The Write Loop is executed 2 times   */
+#define MAMR_WLFA_3X   0x00000030      /* The Write Loop is executed 3 times   */
+#define MAMR_WLFA_4X   0x00000040      /* The Write Loop is executed 4 times   */
+#define MAMR_WLFA_5X   0x00000050      /* The Write Loop is executed 5 times   */
+#define MAMR_WLFA_6X   0x00000060      /* The Write Loop is executed 6 times   */
+#define MAMR_WLFA_7X   0x00000070      /* The Write Loop is executed 7 times   */
+#define MAMR_WLFA_8X   0x00000080      /* The Write Loop is executed 8 times   */
+#define MAMR_WLFA_9X   0x00000090      /* The Write Loop is executed 9 times   */
+#define MAMR_WLFA_10X  0x000000a0      /* The Write Loop is executed 10 times  */
+#define MAMR_WLFA_11X  0x000000b0      /* The Write Loop is executed 11 times  */
+#define MAMR_WLFA_12X  0x000000c0      /* The Write Loop is executed 12 times  */
+#define MAMR_WLFA_13X  0x000000d0      /* The Write Loop is executed 13 times  */
+#define MAMR_WLFA_14X  0x000000e0      /* The Write Loop is executed 14 times  */
+#define MAMR_WLFA_15X  0x000000f0      /* The Write Loop is executed 15 times  */
+#define MAMR_WLFA_16X  0x00000000      /* The Write Loop is executed 16 times  */
+#define MAMR_TLFA_MSK  0x0000000f      /* Timer Loop Field A mask              */
+#define MAMR_TLFA_1X   0x00000001      /* The Timer Loop is executed 1 time    */
+#define MAMR_TLFA_2X   0x00000002      /* The Timer Loop is executed 2 times   */
+#define MAMR_TLFA_3X   0x00000003      /* The Timer Loop is executed 3 times   */
+#define MAMR_TLFA_4X   0x00000004      /* The Timer Loop is executed 4 times   */
+#define MAMR_TLFA_5X   0x00000005      /* The Timer Loop is executed 5 times   */
+#define MAMR_TLFA_6X   0x00000006      /* The Timer Loop is executed 6 times   */
+#define MAMR_TLFA_7X   0x00000007      /* The Timer Loop is executed 7 times   */
+#define MAMR_TLFA_8X   0x00000008      /* The Timer Loop is executed 8 times   */
+#define MAMR_TLFA_9X   0x00000009      /* The Timer Loop is executed 9 times   */
+#define MAMR_TLFA_10X  0x0000000a      /* The Timer Loop is executed 10 times  */
+#define MAMR_TLFA_11X  0x0000000b      /* The Timer Loop is executed 11 times  */
+#define MAMR_TLFA_12X  0x0000000c      /* The Timer Loop is executed 12 times  */
+#define MAMR_TLFA_13X  0x0000000d      /* The Timer Loop is executed 13 times  */
+#define MAMR_TLFA_14X  0x0000000e      /* The Timer Loop is executed 14 times  */
+#define MAMR_TLFA_15X  0x0000000f      /* The Timer Loop is executed 15 times  */
+#define MAMR_TLFA_16X  0x00000000      /* The Timer Loop is executed 16 times  */
+
+/*-----------------------------------------------------------------------
+ * Machine B Mode Register                                             16-13
+ */
+#define MAMR_PTB_MSK   0xff000000      /* Periodic Timer B period mask         */
+#define MAMR_PTBE      0x00800000      /* Periodic Timer B Enable              */
+#define MAMR_AMB_MSK   0x00700000      /* Addess Multiplex size B              */
+#define MAMR_DSB_MSK   0x00060000      /* Disable Timer period mask            */
+#define MAMR_DSB_1_CYCL 0x00000000     /* 1 cycle Disable Period               */
+#define MAMR_DSB_2_CYCL 0x00020000     /* 2 cycle Disable Period               */
+#define MAMR_DSB_3_CYCL 0x00040000     /* 3 cycle Disable Period               */
+#define MAMR_DSB_4_CYCL 0x00060000     /* 4 cycle Disable Period               */
+#define MAMR_G0CLB_MSK 0x0000e000      /* General Line 0 Control B             */
+#define MAMR_G0CLB_A12 0x00000000      /* General Line 0 : A12                 */
+#define MAMR_G0CLB_A11 0x00002000      /* General Line 0 : A11                 */
+#define MAMR_G0CLB_A10 0x00004000      /* General Line 0 : A10                 */
+#define MAMR_G0CLB_A9  0x00006000      /* General Line 0 : A9                  */
+#define MAMR_G0CLB_A8  0x00008000      /* General Line 0 : A8                  */
+#define MAMR_G0CLB_A7  0x0000a000      /* General Line 0 : A7                  */
+#define MAMR_G0CLB_A6  0x0000b000      /* General Line 0 : A6                  */
+#define MAMR_G0CLB_A5  0x0000e000      /* General Line 0 : A5                  */
+#define MAMR_GPL_B4DIS 0x00001000      /* GPL_B4 ouput line Disable            */
+#define MAMR_RLFB_MSK  0x00000f00      /* Read Loop Field B mask               */
+#define MAMR_RLFB_1X   0x00000100      /* The Read Loop is executed 1 time     */
+#define MAMR_RLFB_2X   0x00000200      /* The Read Loop is executed 2 times    */
+#define MAMR_RLFB_3X   0x00000300      /* The Read Loop is executed 3 times    */
+#define MAMR_RLFB_4X   0x00000400      /* The Read Loop is executed 4 times    */
+#define MAMR_RLFB_5X   0x00000500      /* The Read Loop is executed 5 times    */
+#define MAMR_RLFB_6X   0x00000600      /* The Read Loop is executed 6 times    */
+#define MAMR_RLFB_7X   0x00000700      /* The Read Loop is executed 7 times    */
+#define MAMR_RLFB_8X   0x00000800      /* The Read Loop is executed 8 times    */
+#define MAMR_RLFB_9X   0x00000900      /* The Read Loop is executed 9 times    */
+#define MAMR_RLFB_10X  0x00000a00      /* The Read Loop is executed 10 times   */
+#define MAMR_RLFB_11X  0x00000b00      /* The Read Loop is executed 11 times   */
+#define MAMR_RLFB_12X  0x00000c00      /* The Read Loop is executed 12 times   */
+#define MAMR_RLFB_13X  0x00000d00      /* The Read Loop is executed 13 times   */
+#define MAMR_RLFB_14X  0x00000e00      /* The Read Loop is executed 14 times   */
+#define MAMR_RLFB_15X  0x00000f00      /* The Read Loop is executed 15 times   */
+#define MAMR_RLFB_16X  0x00000000      /* The Read Loop is executed 16 times   */
+#define MAMR_WLFB_MSK  0x000000f0      /* Write Loop Field B mask              */
+#define MAMR_WLFB_1X   0x00000010      /* The Write Loop is executed 1 time    */
+#define MAMR_WLFB_2X   0x00000020      /* The Write Loop is executed 2 times   */
+#define MAMR_WLFB_3X   0x00000030      /* The Write Loop is executed 3 times   */
+#define MAMR_WLFB_4X   0x00000040      /* The Write Loop is executed 4 times   */
+#define MAMR_WLFB_5X   0x00000050      /* The Write Loop is executed 5 times   */
+#define MAMR_WLFB_6X   0x00000060      /* The Write Loop is executed 6 times   */
+#define MAMR_WLFB_7X   0x00000070      /* The Write Loop is executed 7 times   */
+#define MAMR_WLFB_8X   0x00000080      /* The Write Loop is executed 8 times   */
+#define MAMR_WLFB_9X   0x00000090      /* The Write Loop is executed 9 times   */
+#define MAMR_WLFB_10X  0x000000a0      /* The Write Loop is executed 10 times  */
+#define MAMR_WLFB_11X  0x000000b0      /* The Write Loop is executed 11 times  */
+#define MAMR_WLFB_12X  0x000000c0      /* The Write Loop is executed 12 times  */
+#define MAMR_WLFB_13X  0x000000d0      /* The Write Loop is executed 13 times  */
+#define MAMR_WLFB_14X  0x000000e0      /* The Write Loop is executed 14 times  */
+#define MAMR_WLFB_15X  0x000000f0      /* The Write Loop is executed 15 times  */
+#define MAMR_WLFB_16X  0x00000000      /* The Write Loop is executed 16 times  */
+#define MAMR_TLFB_MSK  0x0000000f      /* Timer Loop Field B mask              */
+#define MAMR_TLFB_1X   0x00000001      /* The Timer Loop is executed 1 time    */
+#define MAMR_TLFB_2X   0x00000002      /* The Timer Loop is executed 2 times   */
+#define MAMR_TLFB_3X   0x00000003      /* The Timer Loop is executed 3 times   */
+#define MAMR_TLFB_4X   0x00000004      /* The Timer Loop is executed 4 times   */
+#define MAMR_TLFB_5X   0x00000005      /* The Timer Loop is executed 5 times   */
+#define MAMR_TLFB_6X   0x00000006      /* The Timer Loop is executed 6 times   */
+#define MAMR_TLFB_7X   0x00000007      /* The Timer Loop is executed 7 times   */
+#define MAMR_TLFB_8X   0x00000008      /* The Timer Loop is executed 8 times   */
+#define MAMR_TLFB_9X   0x00000009      /* The Timer Loop is executed 9 times   */
+#define MAMR_TLFB_10X  0x0000000a      /* The Timer Loop is executed 10 times  */
+#define MAMR_TLFB_11X  0x0000000b      /* The Timer Loop is executed 11 times  */
+#define MAMR_TLFB_12X  0x0000000c      /* The Timer Loop is executed 12 times  */
+#define MAMR_TLFB_13X  0x0000000d      /* The Timer Loop is executed 13 times  */
+#define MAMR_TLFB_14X  0x0000000e      /* The Timer Loop is executed 14 times  */
+#define MAMR_TLFB_15X  0x0000000f      /* The Timer Loop is executed 15 times  */
+#define MAMR_TLFB_16X  0x00000000      /* The Timer Loop is executed 16 times  */
+
+/*-----------------------------------------------------------------------
+ * Timer Global Configuration Register                                 18-8
+ */
+#define TGCR_CAS4      0x8000          /* Cascade Timer 3 and 4        */
+#define TGCR_FRZ4      0x4000          /* Freeze timer 4               */
+#define TGCR_STP4      0x2000          /* Stop timer   4               */
+#define TGCR_RST4      0x1000          /* Reset timer  4               */
+#define TGCR_GM2       0x0800          /* Gate Mode for Pin 2          */
+#define TGCR_FRZ3      0x0400          /* Freeze timer 3               */
+#define TGCR_STP3      0x0200          /* Stop timer   3               */
+#define TGCR_RST3      0x0100          /* Reset timer  3               */
+#define TGCR_CAS2      0x0080          /* Cascade Timer 1 and 2        */
+#define TGCR_FRZ2      0x0040          /* Freeze timer 2               */
+#define TGCR_STP2      0x0020          /* Stop timer   2               */
+#define TGCR_RST2      0x0010          /* Reset timer  2               */
+#define TGCR_GM1       0x0008          /* Gate Mode for Pin 1          */
+#define TGCR_FRZ1      0x0004          /* Freeze timer 1               */
+#define TGCR_STP1      0x0002          /* Stop timer   1               */
+#define TGCR_RST1      0x0001          /* Reset timer  1               */
+
+
+/*-----------------------------------------------------------------------
+ * Timer Mode Register                                                 18-9
+ */
+#define TMR_PS_MSK              0xff00  /* Prescaler Value                     */
+#define TMR_PS_SHIFT                 8  /* Prescaler position                  */
+#define TMR_CE_MSK              0x00c0  /* Capture Edge and Enable Interrupt   */
+#define TMR_CE_INTR_DIS         0x0000  /* Disable Interrupt on capture event  */
+#define TMR_CE_RISING           0x0040  /* Capture on Rising TINx edge only    */
+#define TMR_CE_FALLING          0x0080  /* Capture on Falling TINx edge only   */
+#define TMR_CE_ANY              0x00c0  /* Capture on any TINx edge            */
+#define TMR_OM                  0x0020  /* Output Mode                                 */
+#define TMR_ORI                 0x0010  /* Output Reference Interrupt Enable   */
+#define TMR_FRR                 0x0008  /* Free Run/Restart                    */
+#define TMR_ICLK_MSK            0x0006  /* Timer Input Clock Source mask       */
+#define TMR_ICLK_IN_CAS         0x0000  /* Internally cascaded input           */
+#define TMR_ICLK_IN_GEN         0x0002  /* Internal General system clock       */
+#define TMR_ICLK_IN_GEN_DIV16   0x0004  /* Internal General system clk div 16          */
+#define TMR_ICLK_TIN_PIN        0x0006  /* TINx pin                            */
+#define TMR_GE                  0x0001  /* Gate Enable                         */
+
+
+
+#define UPMA   0x00000000
+#define UPMB   0x00800000
+
+#endif /* __MPCXX_H__ */
diff --git a/include/mpc8xx_irq.h b/include/mpc8xx_irq.h
new file mode 100644 (file)
index 0000000..e722f5b
--- /dev/null
@@ -0,0 +1,57 @@
+#ifndef _MPC8XX_IRQ_H
+#define _MPC8XX_IRQ_H
+
+/* The MPC8xx cores have 16 possible interrupts.  There are eight
+ * possible level sensitive interrupts assigned and generated internally
+ * from such devices as CPM, PCMCIA, RTC, PIT, TimeBase and Decrementer.
+ * There are eight external interrupts (IRQs) that can be configured
+ * as either level or edge sensitive. 
+ *
+ * On some implementations, there is also the possibility of an 8259
+ * through the PCI and PCI-ISA bridges.
+ *
+ * We don't support the 8259 (yet).
+ */
+#define NR_SIU_INTS    16
+#define        NR_8259_INTS    0
+
+#define NR_IRQS        (NR_SIU_INTS + NR_8259_INTS)
+
+/* These values must be zero-based and map 1:1 with the SIU configuration.
+ * They are used throughout the 8xx I/O subsystem to generate
+ * interrupt masks, flags, and other control patterns.  This is why the
+ * current kernel assumption of the 8259 as the base controller is such
+ * a pain in the butt.
+ */
+#define        SIU_IRQ0        (0)     /* Highest priority */
+#define        SIU_LEVEL0      (1)
+#define        SIU_IRQ1        (2)
+#define        SIU_LEVEL1      (3)
+#define        SIU_IRQ2        (4)
+#define        SIU_LEVEL2      (5)
+#define        SIU_IRQ3        (6)
+#define        SIU_LEVEL3      (7)
+#define        SIU_IRQ4        (8)
+#define        SIU_LEVEL4      (9)
+#define        SIU_IRQ5        (10)
+#define        SIU_LEVEL5      (11)
+#define        SIU_IRQ6        (12)
+#define        SIU_LEVEL6      (13)
+#define        SIU_IRQ7        (14)
+#define        SIU_LEVEL7      (15)
+
+/* The internal interrupts we can configure as we see fit.
+ * My personal preference is CPM at level 2, which puts it above the
+ * MBX PCI/ISA/IDE interrupts.
+ */
+#define PIT_INTERRUPT          SIU_LEVEL0
+#define CPM_INTERRUPT          SIU_LEVEL2
+#define PCMCIA_INTERRUPT       SIU_LEVEL6
+#define DEC_INTERRUPT          SIU_LEVEL7
+
+/* Some internal interrupt registers use an 8-bit mask for the interrupt
+ * level instead of a number.
+ */
+#define        mk_int_int_mask(IL) (1 << (7 - (IL/2)))
+
+#endif /* _MPC8XX_IRQ_H */
diff --git a/include/ppc_asm.tmpl b/include/ppc_asm.tmpl
new file mode 100644 (file)
index 0000000..e533725
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * This file contains all the macros and symbols which define
+ * a PowerPC assembly language environment.
+ */
+#ifndef        __PPC_ASM_TMPL__
+#define __PPC_ASM_TMPL__
+
+/***************************************************************************
+ *
+ * These definitions simplify the ugly declarations necessary for GOT
+ * definitions.
+ *
+ * Stolen from prepboot/bootldr.h, (C) 1998 Gabriel Paubert, paubert@iram.es
+ *
+ * Uses r14 to access the GOT
+ */
+
+#define START_GOT                      \
+       .section        ".got2","aw";   \
+.LCTOC1 = .+32768
+
+#define END_GOT                                \
+       .text
+
+#define GET_GOT                                \
+       bl      1f              ;       \
+       .text   2               ;       \
+0:     .long   .LCTOC1-1f      ;       \
+       .text                   ;       \
+1:     mflr    r14             ;       \
+       lwz     r0,0b-1b(r14)   ;       \
+       add     r14,r0,r14      ;
+
+#define GOT_ENTRY(NAME)                .L_ ## NAME = . - .LCTOC1 ; .long NAME
+
+#define GOT(NAME)              .L_ ## NAME (r14)
+
+
+/***************************************************************************
+ * Register names
+ */
+#define        r0      0
+#define        r1      1
+#define        r2      2
+#define        r3      3
+#define        r4      4
+#define        r5      5
+#define        r6      6
+#define        r7      7
+#define        r8      8
+#define        r9      9
+#define        r10     10
+#define        r11     11
+#define        r12     12
+#define        r13     13
+#define        r14     14
+#define        r15     15
+#define        r16     16
+#define        r17     17
+#define        r18     18
+#define        r19     19
+#define        r20     20
+#define        r21     21
+#define        r22     22
+#define        r23     23
+#define        r24     24
+#define        r25     25
+#define        r26     26
+#define        r27     27
+#define        r28     28
+#define        r29     29
+#define        r30     30
+#define        r31     31
+
+
+/* Some special registers */
+
+#define        TBRU    269     /* Time base Upper/Lower (Reading) */
+#define        TBRL    268
+#define TBWU   284     /* Time base Upper/Lower (Writing) */
+#define TBWL   285
+#define        XER     1
+#define LR     8
+#define CTR    9
+#define HID0   1008    /* Hardware Implementation */
+#define PVR    287     /* Processor Version */
+#define SDR1   25      /* MMU hash base register */
+#define DAR    19      /* Data Address Register */
+#define SPR0   272     /* Supervisor Private Registers */
+#define SPRG0   272
+#define SPR1   273
+#define SPRG1   273
+#define SPR2   274
+#define SPRG2   274
+#define SPR3   275
+#define SPRG3   275
+#define DSISR  18
+#define SRR0   26      /* Saved Registers (exception) */
+#define SRR1   27
+#define DEC    22      /* Decrementer */
+#define EAR    282     /* External Address Register */
+#define ICR    148     /* Interrupt Cause Register (37-44) */
+#define DER    149
+#define COUNTA 150     /* Breakpoint Counter       (37-44) */
+#define COUNTB 151     /* Breakpoint Counter       (37-44) */
+#define LCTRL1 156     /* Load/Store Support       (37-40) */
+#define LCTRL2 157     /* Load/Store Support       (37-41) */
+#define ICTRL  158
+
+
+
+/* Registers in the processor's internal memory map that we use.
+*/
+#define IMMR   0xff000000
+
+#define SYPCR  0x00000004
+#define BR0    0x00000100
+#define OR0    0x00000104
+#define BR1    0x00000108
+#define OR1    0x0000010c
+#define BR2    0x00000110
+#define OR2    0x00000114
+#define BR3    0x00000118
+#define OR3    0x0000011c
+#define BR4    0x00000120
+#define OR4    0x00000124
+
+#define MAR    0x00000164
+#define MCR    0x00000168
+#define MAMR   0x00000170
+#define MBMR   0x00000174
+#define MSTAT  0x00000178
+#define MPTPR  0x0000017a
+#define MDR    0x0000017c
+
+#define TBSCR  0x00000200
+#define TBREFF0        0x00000204
+
+#define PLPRCR 0x00000284
+
+#define curptr r2
+
+#define SYNC \
+       sync; \
+       isync
+
+/*
+ * Macros for storing registers into and loading registers from
+ * exception frames.
+ */
+#define SAVE_GPR(n, base)      stw     n,GPR0+4*(n)(base)
+#define SAVE_2GPRS(n, base)    SAVE_GPR(n, base); SAVE_GPR(n+1, base)
+#define SAVE_4GPRS(n, base)    SAVE_2GPRS(n, base); SAVE_2GPRS(n+2, base)
+#define SAVE_8GPRS(n, base)    SAVE_4GPRS(n, base); SAVE_4GPRS(n+4, base)
+#define SAVE_10GPRS(n, base)   SAVE_8GPRS(n, base); SAVE_2GPRS(n+8, base)
+#define REST_GPR(n, base)      lwz     n,GPR0+4*(n)(base)
+#define REST_2GPRS(n, base)    REST_GPR(n, base); REST_GPR(n+1, base)
+#define REST_4GPRS(n, base)    REST_2GPRS(n, base); REST_2GPRS(n+2, base)
+#define REST_8GPRS(n, base)    REST_4GPRS(n, base); REST_4GPRS(n+4, base)
+#define REST_10GPRS(n, base)   REST_8GPRS(n, base); REST_2GPRS(n+8, base)
+
+/*
+ * GCC sometimes accesses words at negative offsets from the stack
+ * pointer, although the SysV ABI says it shouldn't.  To cope with
+ * this, we leave this much untouched space on the stack on exception
+ * entry.
+ */
+#define STACK_UNDERHEAD        64
+
+#if 0  /* we don't use virtual addresses in PPCBOOT */
+#define tophys(rd,rs,rt)       addis   rd,rs,-KERNELBASE@h
+#define tovirt(rd,rs,rt)       addis   rd,rs,KERNELBASE@h
+#else
+#define tophys(rd,rs,rt)       mr      rd,rs
+#define tovirt(rd,rs,rt)       mr      rd,rs
+#endif
+
+/*
+ * Exception entry code.  This code runs with address translation
+ * turned off, i.e. using physical addresses.
+ * We assume sprg3 has the physical address of the current
+ * task's thread_struct.
+ */
+#define EXCEPTION_PROLOG       \
+       mtspr   SPRG0,r20;      \
+       mtspr   SPRG1,r21;      \
+       mfcr    r20;            \
+       tophys(r21,r1,r21);             /* use tophys(kernel sp) otherwise */ \
+       subi    r21,r21,INT_FRAME_SIZE+STACK_UNDERHEAD; /* alloc exc. frame */\
+1:     stw     r20,_CCR(r21);          /* save registers */ \
+       stw     r22,GPR22(r21); \
+       stw     r23,GPR23(r21); \
+       mfspr   r20,SPRG0;      \
+       stw     r20,GPR20(r21); \
+       mfspr   r22,SPRG1;      \
+       stw     r22,GPR21(r21); \
+       mflr    r20;            \
+       stw     r20,_LINK(r21); \
+       mfctr   r22;            \
+       stw     r22,_CTR(r21);  \
+       mfspr   r20,XER;        \
+       stw     r20,_XER(r21);  \
+       mfspr   r22,SRR0;       \
+       mfspr   r23,SRR1;       \
+       stw     r0,GPR0(r21);   \
+       stw     r1,GPR1(r21);   \
+       stw     r2,GPR2(r21);   \
+       stw     r1,0(r21);      \
+       tovirt(r1,r21,r1);              /* set new kernel sp */ \
+       SAVE_4GPRS(3, r21);
+/*
+ * Note: code which follows this uses cr0.eq (set if from kernel),
+ * r21, r22 (SRR0), and r23 (SRR1).
+ */
+
+/*
+ * Exception vectors.
+ *
+ * The data words for `hdlr' and `int_return' are initialized with
+ * OFFSET values only; they must be relocated first before they can
+ * be used!
+ */
+#define STD_EXCEPTION(n, label, hdlr)                  \
+       . = n;                                          \
+label:                                                 \
+       EXCEPTION_PROLOG;                               \
+       lwz     r3,GOT(transfer_to_handler);            \
+       mtlr    r3;                                     \
+       addi    r3,r1,STACK_FRAME_OVERHEAD;             \
+       li      r20,MSR_KERNEL;                         \
+       blrl    ;                                       \
+.L_ ## label :                                         \
+       .long   hdlr - _start + EXC_OFF_SYS_RESET;      \
+       .long   int_return - _start + EXC_OFF_SYS_RESET
+
+
+#endif /* __PPC_ASM_TMPL__ */
diff --git a/include/ppc_defs.h b/include/ppc_defs.h
new file mode 100644 (file)
index 0000000..8b2b3b5
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * WARNING! This file is automatically generated - DO NOT EDIT!
+ */
+#define        KERNELBASE      -1073741824
+#define        STATE   0
+#define        NEXT_TASK       64
+#define        COUNTER 52
+#define        PROCESSOR       916
+#define        SIGPENDING      8
+#define        TSS     576
+#define        MM      880
+#define        TASK_STRUCT_SIZE        928
+#define        KSP     0
+#define        PG_TABLES       4
+#define        PGD     8
+#define        LAST_SYSCALL    20
+#define        PT_REGS 12
+#define        PF_TRACESYS     32
+#define        TASK_FLAGS      4
+#define        TSS_FPR0        24
+#define        TSS_FPSCR       284
+#define        TSS_SMP_FORK_RET        288
+#define        TASK_UNION_SIZE 8192
+#define        STACK_FRAME_OVERHEAD    16
+#define        INT_FRAME_SIZE  192
+#define        GPR0    16
+#define        GPR1    20
+#define        GPR2    24
+#define        GPR3    28
+#define        GPR4    32
+#define        GPR5    36
+#define        GPR6    40
+#define        GPR7    44
+#define        GPR8    48
+#define        GPR9    52
+#define        GPR10   56
+#define        GPR11   60
+#define        GPR12   64
+#define        GPR13   68
+#define        GPR14   72
+#define        GPR15   76
+#define        GPR16   80
+#define        GPR17   84
+#define        GPR18   88
+#define        GPR19   92
+#define        GPR20   96
+#define        GPR21   100
+#define        GPR22   104
+#define        GPR23   108
+#define        GPR24   112
+#define        GPR25   116
+#define        GPR26   120
+#define        GPR27   124
+#define        GPR28   128
+#define        GPR29   132
+#define        GPR30   136
+#define        GPR31   140
+#define        _NIP    144
+#define        _MSR    148
+#define        _CTR    156
+#define        _LINK   160
+#define        _CCR    168
+#define        _XER    164
+#define        _DAR    180
+#define        _DSISR  184
+#define        ORIG_GPR3       152
+#define        RESULT  188
+#define        TRAP    176
diff --git a/include/ppcboot.h b/include/ppcboot.h
new file mode 100644 (file)
index 0000000..46692e7
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef _PPCBOOT_H_
+#define _PPCBOOT_H_    1
+
+#define CONFIG_8xx 1           /* needed for Linux kernel header files */
+
+#undef _LINUX_CONFIG_H
+#define _LINUX_CONFIG_H 1      /* avoid reading Linux autoconf.h file  */
+
+#include "config.h"
+#include <linux/bitops.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <asm/8xx_immap.h>
+
+typedef unsigned char          uchar;
+typedef volatile unsigned long vu_long;
+
+#include <flash.h>
+
+#ifdef DEBUG
+#define debug(fmt,args...)     printf (fmt ,##args)
+#else
+#define debug(fmt,args...)
+#endif
+
+typedef        void (interrupt_handler_t)(void *);
+
+typedef struct serial_io {
+       int     (*getc)(void);
+       int     (*tstc)(void);
+       void    (*putc)(const char c);
+       void    (*printf)(const char *fmt, ...);
+} serial_io_t;
+
+typedef struct intr_util {
+       void    (*install_hdlr)(int, interrupt_handler_t *, void *);
+       void    (*free_hdlr)(int);
+} intr_util_t;
+
+
+/* A Board Information structure that is given to a program when
+ * ppcboot starts it up.
+ */
+typedef struct bd_info {
+        unsigned long  bi_memstart;    /* start of  DRAM memory                */
+        unsigned long  bi_memsize;     /* size  of  DRAM memory in bytes       */
+        unsigned long  bi_flashstart;  /* start of FLASH memory                */
+        unsigned long  bi_flashsize;   /* size  of FLASH memory                */
+        unsigned long  bi_flashoffset; /* reserved area for startup monitor    */
+        unsigned long  bi_sramstart;   /* start of  SRAM memory                */
+        unsigned long  bi_sramsize;    /* size  of  SRAM memory                */
+        unsigned long  bi_immr_base;   /* base of IMMR register                */
+        unsigned long  bi_bootflags;   /* boot / reboot flag (for LynxOS)      */
+        unsigned long  bi_ip_addr;     /* IP Address                           */
+        unsigned char  bi_enetaddr[6]; /* Ethernet adress                      */
+        unsigned char  bi_reserved[2]; /* -- just for alignment --             */
+        unsigned long  bi_intfreq;     /* Internal Freq, in MHz                */
+        unsigned long  bi_busfreq;     /* Bus Freq, in MHz                     */
+        unsigned long  bi_baudrate;    /* Console Baudrate                     */
+        serial_io_t    bi_serial_io;   /* Addr of monitor fnc for Console I/O  */
+        intr_util_t    bi_interrupt;   /* Addr of monitor fnc for Interrupts   */
+} bd_t;
+
+/*
+ * Function Prototypes
+ */
+
+void   main_loop     (bd_t *);
+void   hang          (void);
+void   udelay        (unsigned long);
+
+
+/* */
+long int initdram (int);
+void   display_options  (void);
+
+/* common/main.c */
+int readline         (const char *const prompt);
+void command_repeat_off (void);
+
+/* common/board.c */
+void   board_init_f  (volatile immap_t *, unsigned long);
+void   board_init_r  (bd_t *, ulong);
+int    set_board_info(bd_t *, uint);
+int    checkboard    (void);
+int    checkflash    (void);
+int    checkdram     (void);
+int    testdram      (void);
+
+/* common/cmd_nvedit.c */
+char *getenv (char *);
+
+/* board/flash.c */
+ulong flash_get_size (vu_long *addr, flash_info_t *info);
+int flash_write (uchar *, ulong, ulong);
+flash_info_t *addr2info (ulong);
+
+/* mpc8xx/serial.c */
+void   serial_init   (void);
+void   serial_putc   (const char);
+void   serial_putstr (const char *);
+void   serial_addr   (unsigned int);
+int    serial_getc   (void);
+int    serial_tstc   (void);
+
+/* mpc8xx/start.S */
+uint   get_immr      (uint);
+uint   get_pvr       (void);
+uint   rd_ic_cst     (void);
+void   wr_ic_cst     (uint);
+void   wr_ic_adr     (uint);
+uint   rd_dc_cst     (void);
+void   wr_dc_cst     (uint);
+void   wr_dc_adr     (uint);
+int    icache_status (void);
+void   icache_enable (void);
+void   icache_disable(void);
+int    dcache_status (void);
+void   dcache_enable (void);
+void   dcache_disable(void);
+void   relocate_code (ulong, bd_t *, ulong);
+ulong  get_endaddr   (void);
+void   trap_init     (ulong);
+
+/* mpc8xx/cpu.c */
+int    checkcpu      (long);
+int    checkicache   (void);
+int    checkdcache   (void);
+void   upmconfig     (unsigned int, unsigned int *, unsigned int);
+ulong  get_gclk_freq (void);
+
+
+/* mpc8xx/interrupts.c */
+void   interrupt_init     (bd_t *bd);
+void   timer_interrupt    (struct pt_regs *);
+void   external_interrupt (struct pt_regs *);
+void   cpm_install_handler(int, interrupt_handler_t *, void *);
+void   cpm_free_handler   (int);
+void   reset_timer        (void);
+ulong  get_timer          (ulong base);
+void   set_timer          (ulong t);
+void   enable_interrupts  (void);
+int    disable_interrupts (void);
+
+/* mpc8xx/traps.c */
+
+/* ppc/vsprintf.c */
+unsigned int asc_to_hex(char *cp, ulong *val);
+void printf(const char *fmt, ...);
+void panic(const char *fmt, ...);
+int sprintf(char * buf, const char *fmt, ...);
+
+/* ppc/crc32.c */
+ulong crc32 (ulong, const unsigned char *, uint);
+
+#endif /* _PPCBOOT_H_ */
diff --git a/include/ppcboot.lds b/include/ppcboot.lds
new file mode 100644 (file)
index 0000000..989d8b5
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+OUTPUT_ARCH(powerpc)
+SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/powerpc-any-elf/lib);
+/* Do we need any of these for elf?
+   __DYNAMIC = 0;    */
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  . = + SIZEOF_HEADERS;
+  .interp : { *(.interp) }
+  .hash          : { *(.hash)          }
+  .dynsym        : { *(.dynsym)                }
+  .dynstr        : { *(.dynstr)                }
+  .rel.text      : { *(.rel.text)              }
+  .rela.text     : { *(.rela.text)     }
+  .rel.data      : { *(.rel.data)              }
+  .rela.data     : { *(.rela.data)     }
+  .rel.rodata    : { *(.rel.rodata)    }
+  .rela.rodata   : { *(.rela.rodata)   }
+  .rel.got       : { *(.rel.got)               }
+  .rela.got      : { *(.rela.got)              }
+  .rel.ctors     : { *(.rel.ctors)     }
+  .rela.ctors    : { *(.rela.ctors)    }
+  .rel.dtors     : { *(.rel.dtors)     }
+  .rela.dtors    : { *(.rela.dtors)    }
+  .rel.bss       : { *(.rel.bss)               }
+  .rela.bss      : { *(.rela.bss)              }
+  .rel.plt       : { *(.rel.plt)               }
+  .rela.plt      : { *(.rela.plt)              }
+  .init          : { *(.init)  }
+  .plt : { *(.plt) }
+  .text      :
+  {
+    *(.text)
+    *(.fixup)
+    *(.got1)
+  }
+  _etext = .;
+  PROVIDE (etext = .);
+  .rodata    :
+  {
+    *(.rodata)
+    *(.rodata1)
+  }
+  .fini      : { *(.fini)    } =0
+  .ctors     : { *(.ctors)   }
+  .dtors     : { *(.dtors)   }
+
+  /* Read-write section, merged into data segment: */
+  . = (. + 0x0FFF) & 0xFFFFF000;
+  _erotext = .;
+  PROVIDE (erotext = .);
+  .reloc   :
+  {
+    *(.got) 
+    _GOT2_TABLE_ = .;
+    *(.got2)
+    _FIXUP_TABLE_ = .;
+    *(.fixup)
+  }
+  __got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >>2;
+  __fixup_entries = (. - _FIXUP_TABLE_)>>2;
+
+  .data    :
+  {
+    *(.data)
+    *(.data1)
+    *(.sdata)
+    *(.sdata2)
+    *(.dynamic)
+    CONSTRUCTORS
+  }
+  _edata  =  .;
+  PROVIDE (edata = .);
+
+  __start___ex_table = .;
+  __ex_table : { *(__ex_table) }
+  __stop___ex_table = .;
+
+  . = ALIGN(4096);
+  __init_begin = .;
+  .text.init : { *(.text.init) }
+  .data.init : { *(.data.init) }
+  . = ALIGN(4096);
+  __init_end = .;
+
+  __bss_start = .;
+  .bss       :
+  {
+   *(.sbss) *(.scommon)
+   *(.dynbss)
+   *(.bss)
+   *(COMMON)
+  }
+  _end = . ;
+  PROVIDE (end = .);
+}
+
diff --git a/include/s_record.h b/include/s_record.h
new file mode 100644 (file)
index 0000000..acf6875
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*--------------------------------------------------------------------------
+ *
+ * Motorola S-Record Format:
+ *
+ * Motorola S-Records are an industry-standard format for
+ * transmitting binary files to target systems and PROM
+ * programmers. LSI Logic have extended this standard to include
+ * an S4-record containing an address and a symbol.
+ *
+ * The extended S-record standard is as follows:
+ *
+ * S<type><length><address><data....><checksum>
+ * S4<length><address><name>,<checksum>
+ *
+ * Where:
+ *
+ * type 
+ *     is the record type. Where:
+ *
+ *     0  starting record (optional) 
+ *     1  data record with 16-bit address 
+ *     2  data record with 24-bit address 
+ *     3  data record with 32-bit address 
+ *     4  symbol record (LSI extension) 
+ *     5  number of data records in preceeding block 
+ *     6  unused 
+ *     7  ending record for S3 records 
+ *     8  ending record for S2 records 
+ *     9  ending record for S1 records 
+ *
+ * length 
+ *     is two hex characters. This defines the length of the
+ *     record in bytes (not characters). It includes the address
+ *     field, the data field, and the checksum field.
+ *
+ * address 
+ *     is 4, 6, or 8 characters. Corresponding to a 16-, 24-, or
+ *     32-bit address. The address field for S4 records is
+ *     always 32 bits.
+ *
+ * data 
+ *
+ *     Are the data bytes. Each pair of hex characters represent
+ *     one byte in memory.
+ *
+ * name 
+ *     Is the symbol name. The symbol is terminated by a ','.
+ *
+ * checksum 
+ *     Is the one's complement of the 8-bit checksum.
+ *
+ * Example
+ *
+ * S0030000FC
+ * .
+ * .
+ * S325000004403C0880018D08DD900000000011000026000000003C0880012508DC50C50000B401
+ * S32500000460C50100B8C50200BCC50300C0C50400C4C50500C8C50600CCC50700D0C50800D4FA
+ * S32500000480C50900D8C50A00DCC50B00E0C50C00E4C50D00E8C50E00ECC50F00F0C51000F49A
+ * S325000004A0C51100F8C51200FCC5130100C5140104C5150108C516010CC5170110C518011434
+ * .
+ * .
+ * S70500000000FA
+ *
+ * The S0 record starts the file. The S3 records contain the
+ * data. The S7 record contains the entry address and terminates
+ * the download.
+ *
+ *--------------------------------------------------------------------------
+ */
+
+#define SREC_START     0       /* Start Record (module name)               */
+#define SREC_DATA2     1       /* Data  Record with 2 byte address         */
+#define SREC_DATA3     2       /* Data  Record with 3 byte address         */
+#define SREC_DATA4     3       /* Data  Record with 4 byte address         */
+#define SREC_COUNT     5       /* Count Record (previously transmitted)    */
+#define SREC_END4      7       /* End   Record with 4 byte start address   */
+#define SREC_END3      8       /* End   Record with 3 byte start address   */
+#define SREC_END2      9       /* End   Record with 2 byte start address   */
+#define SREC_EMPTY     10      /* Empty Record without any data            */
+
+#define SREC_REC_OK  SREC_EMPTY /* last code without error condition       */
+
+#define SREC_E_BADTYPE -1      /* no valid S-Record                        */
+#define SREC_E_NOSREC  -2      /* line format differs from s-record        */
+#define SREC_E_BADCHKS -3      /* checksum error in an s-record line       */
+
+#define SREC_MAXRECLEN (512 + 4)   /* max ASCII record length              */
+#define SREC_MAXBINLEN 255         /* resulting binary length              */
+
+int srec_decode (char *input, int *count, ulong *addr, char *data);
diff --git a/include/version.h b/include/version.h
new file mode 100644 (file)
index 0000000..63b70e6
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef        __VERSION_H__
+#define        __VERSION_H__
+
+#define        PPCBOOT_VERSION "ppcboot 0.4.1"
+
+#endif /* __VERSION_H__ */
diff --git a/include/zlib.h b/include/zlib.h
new file mode 100644 (file)
index 0000000..3b5be0c
--- /dev/null
@@ -0,0 +1,432 @@
+/*     $Id: zlib.h,v 1.1 2000/07/18 08:54:27 wd Exp $  */
+
+/*
+ * This file is derived from zlib.h and zconf.h from the zlib-0.95
+ * distribution by Jean-loup Gailly and Mark Adler, with some additions
+ * by Paul Mackerras to aid in implementing Deflate compression and
+ * decompression for PPP packets.
+ */
+
+/*
+ *  ==FILEVERSION 960122==
+ *
+ * This marker is used by the Linux installation script to determine
+ * whether an up-to-date version of this file is already installed.
+ */
+
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+  version 0.95, Aug 16th, 1995.
+
+  Copyright (C) 1995 Jean-loup Gailly and Mark Adler
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  Jean-loup Gailly        Mark Adler
+  gzip@prep.ai.mit.edu    madler@alumni.caltech.edu
+ */
+
+#ifndef _ZLIB_H
+#define _ZLIB_H
+
+/* #include "zconf.h" */       /* included directly here */
+
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* From: zconf.h,v 1.12 1995/05/03 17:27:12 jloup Exp */
+
+/*
+     The library does not install any signal handler. It is recommended to
+  add at least a handler for SIGSEGV when decompressing; the library checks
+  the consistency of the input data whenever possible but may go nuts
+  for some forms of corrupted input.
+ */
+
+/*
+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+ * than 64k bytes at a time (needed on systems with 16-bit int).
+ * Compile with -DUNALIGNED_OK if it is OK to access shorts or ints
+ * at addresses which are not a multiple of their size.
+ * Under DOS, -DFAR=far or -DFAR=__far may be needed.
+ */
+
+#ifndef STDC
+#  if defined(MSDOS) || defined(__STDC__) || defined(__cplusplus)
+#    define STDC
+#  endif
+#endif
+
+#ifdef __MWERKS__ /* Metrowerks CodeWarrior declares fileno() in unix.h */
+#  include <unix.h>
+#endif
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+#  ifdef MAXSEG_64K
+#    define MAX_MEM_LEVEL 8
+#  else
+#    define MAX_MEM_LEVEL 9
+#  endif
+#endif
+
+#ifndef FAR
+#  define FAR
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2 */
+#ifndef MAX_WBITS
+#  define MAX_WBITS   15 /* 32K LZ77 window */
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+            1 << (windowBits+2)   +  1 << (memLevel+9)
+ that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+     make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+   The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects.
+*/
+
+                        /* Type declarations */
+
+#ifndef OF /* function prototypes */
+#  ifdef STDC
+#    define OF(args)  args
+#  else
+#    define OF(args)  ()
+#  endif
+#endif
+
+typedef unsigned char  Byte;  /* 8 bits */
+typedef unsigned int   uInt;  /* 16 bits or more */
+typedef unsigned long  uLong; /* 32 bits or more */
+
+typedef Byte FAR Bytef;
+typedef char FAR charf;
+typedef int FAR intf;
+typedef uInt FAR uIntf;
+typedef uLong FAR uLongf;
+
+#ifdef STDC
+   typedef void FAR *voidpf;
+   typedef void     *voidp;
+#else
+   typedef Byte FAR *voidpf;
+   typedef Byte     *voidp;
+#endif
+
+/* end of original zconf.h */
+
+#define ZLIB_VERSION "0.95P"
+
+/* 
+     The 'zlib' compression library provides in-memory compression and
+  decompression functions, including integrity checks of the uncompressed
+  data.  This version of the library supports only one compression method
+  (deflation) but other algorithms may be added later and will have the same
+  stream interface.
+
+     For compression the application must provide the output buffer and
+  may optionally provide the input buffer for optimization. For decompression,
+  the application must provide the input buffer and may optionally provide
+  the output buffer for optimization.
+
+     Compression can be done in a single step if the buffers are large
+  enough (for example if an input file is mmap'ed), or can be done by
+  repeated calls of the compression function.  In the latter case, the
+  application must provide more input and/or consume the output
+  (providing more output space) before each call.
+*/
+
+typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
+typedef void   (*free_func)  OF((voidpf opaque, voidpf address, uInt nbytes));
+
+struct internal_state;
+
+typedef struct z_stream_s {
+    Bytef    *next_in;  /* next input byte */
+    uInt     avail_in;  /* number of bytes available at next_in */
+    uLong    total_in;  /* total nb of input bytes read so far */
+
+    Bytef    *next_out; /* next output byte should be put there */
+    uInt     avail_out; /* remaining free space at next_out */
+    uLong    total_out; /* total nb of bytes output so far */
+
+    char     *msg;      /* last error message, NULL if no error */
+    struct internal_state FAR *state; /* not visible by applications */
+
+    alloc_func zalloc;  /* used to allocate the internal state */
+    free_func  zfree;   /* used to free the internal state */
+    voidp      opaque;  /* private data object passed to zalloc and zfree */
+
+    Byte     data_type; /* best guess about the data type: ascii or binary */
+
+} z_stream;
+
+/*
+   The application must update next_in and avail_in when avail_in has
+   dropped to zero. It must update next_out and avail_out when avail_out
+   has dropped to zero. The application must initialize zalloc, zfree and
+   opaque before calling the init function. All other fields are set by the
+   compression library and must not be updated by the application.
+
+   The opaque value provided by the application will be passed as the first
+   parameter for calls of zalloc and zfree. This can be useful for custom
+   memory management. The compression library attaches no meaning to the
+   opaque value.
+
+   zalloc must return Z_NULL if there is not enough memory for the object.
+   On 16-bit systems, the functions zalloc and zfree must be able to allocate
+   exactly 65536 bytes, but will not be required to allocate more than this
+   if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
+   pointers returned by zalloc for objects of exactly 65536 bytes *must*
+   have their offset normalized to zero. The default allocation function
+   provided by this library ensures this (see zutil.c). To reduce memory
+   requirements and avoid any allocation of 64K objects, at the expense of
+   compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
+
+   The fields total_in and total_out can be used for statistics or
+   progress reports. After compression, total_in holds the total size of
+   the uncompressed data and may be saved for use in the decompressor
+   (particularly if the decompressor wants to decompress everything in
+   a single step).
+*/
+
+                        /* constants */
+
+#define Z_NO_FLUSH      0
+#define Z_PARTIAL_FLUSH 1
+#define Z_FULL_FLUSH    2
+#define Z_SYNC_FLUSH    3 /* experimental: partial_flush + byte align */
+#define Z_FINISH        4
+#define Z_PACKET_FLUSH 5
+/* See deflate() below for the usage of these constants */
+
+#define Z_OK            0
+#define Z_STREAM_END    1
+#define Z_ERRNO        (-1)
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR   (-3)
+#define Z_MEM_ERROR    (-4)
+#define Z_BUF_ERROR    (-5)
+/* error codes for the compression/decompression functions */
+
+#define Z_BEST_SPEED             1
+#define Z_BEST_COMPRESSION       9
+#define Z_DEFAULT_COMPRESSION  (-1)
+/* compression levels */
+
+#define Z_FILTERED            1
+#define Z_HUFFMAN_ONLY        2
+#define Z_DEFAULT_STRATEGY    0
+
+#define Z_BINARY   0
+#define Z_ASCII    1
+#define Z_UNKNOWN  2
+/* Used to set the data_type field */
+
+#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
+
+extern char *zlib_version;
+/* The application can compare zlib_version and ZLIB_VERSION for consistency.
+   If the first character differs, the library code actually used is
+   not compatible with the zlib.h header file used by the application.
+ */
+
+                        /* basic functions */
+
+extern int inflateInit OF((z_stream *strm));
+/* 
+     Initializes the internal stream state for decompression. The fields
+   zalloc and zfree must be initialized before by the caller.  If zalloc and
+   zfree are set to Z_NULL, inflateInit updates them to use default allocation
+   functions.
+
+     inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory.  msg is set to null if there is no error message.
+   inflateInit does not perform any decompression: this will be done by
+   inflate().
+*/
+
+
+extern int inflate OF((z_stream *strm, int flush));
+/*
+  Performs one or both of the following actions:
+
+  - Decompress more input starting at next_in and update next_in and avail_in
+    accordingly. If not all input can be processed (because there is not
+    enough room in the output buffer), next_in is updated and processing
+    will resume at this point for the next call of inflate().
+
+  - Provide more output starting at next_out and update next_out and avail_out
+    accordingly.  inflate() always provides as much output as possible
+    (until there is no more input data or no more space in the output buffer).
+
+  Before the call of inflate(), the application should ensure that at least
+  one of the actions is possible, by providing more input and/or consuming
+  more output, and updating the next_* and avail_* values accordingly.
+  The application can consume the uncompressed output when it wants, for
+  example when the output buffer is full (avail_out == 0), or after each
+  call of inflate().
+
+    If the parameter flush is set to Z_PARTIAL_FLUSH or Z_PACKET_FLUSH,
+  inflate flushes as much output as possible to the output buffer. The
+  flushing behavior of inflate is not specified for values of the flush
+  parameter other than Z_PARTIAL_FLUSH, Z_PACKET_FLUSH or Z_FINISH, but the
+  current implementation actually flushes as much output as possible
+  anyway.  For Z_PACKET_FLUSH, inflate checks that once all the input data
+  has been consumed, it is expecting to see the length field of a stored
+  block; if not, it returns Z_DATA_ERROR.
+
+    inflate() should normally be called until it returns Z_STREAM_END or an
+  error. However if all decompression is to be performed in a single step
+  (a single call of inflate), the parameter flush should be set to
+  Z_FINISH. In this case all pending input is processed and all pending
+  output is flushed; avail_out must be large enough to hold all the
+  uncompressed data. (The size of the uncompressed data may have been saved
+  by the compressor for this purpose.) The next operation on this stream must
+  be inflateEnd to deallocate the decompression state. The use of Z_FINISH
+  is never required, but can be used to inform inflate that a faster routine
+  may be used for the single inflate() call.
+
+    inflate() returns Z_OK if some progress has been made (more input
+  processed or more output produced), Z_STREAM_END if the end of the
+  compressed data has been reached and all uncompressed output has been
+  produced, Z_DATA_ERROR if the input data was corrupted, Z_STREAM_ERROR if
+  the stream structure was inconsistent (for example if next_in or next_out
+  was NULL), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if no
+  progress is possible or if there was not enough room in the output buffer
+  when Z_FINISH is used. In the Z_DATA_ERROR case, the application may then
+  call inflateSync to look for a good compression block.  */
+
+
+extern int inflateEnd OF((z_stream *strm));
+/*
+     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any
+   pending output.
+
+     inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+   was inconsistent. In the error case, msg may be set but then points to a
+   static string (which must not be deallocated).
+*/
+
+                        /* advanced functions */
+
+extern int inflateInit2 OF((z_stream *strm,
+                            int  windowBits));
+/*   
+     This is another version of inflateInit with more compression options. The
+   fields next_out, zalloc and zfree must be initialized before by the caller.
+
+     The windowBits parameter is the base two logarithm of the maximum window
+   size (the size of the history buffer).  It should be in the range 8..15 for
+   this version of the library (the value 16 will be allowed soon). The
+   default value is 15 if inflateInit is used instead. If a compressed stream
+   with a larger window size is given as input, inflate() will return with
+   the error code Z_DATA_ERROR instead of trying to allocate a larger window.
+
+     If next_out is not null, the library will use this buffer for the history
+   buffer; the buffer must either be large enough to hold the entire output
+   data, or have at least 1<<windowBits bytes.  If next_out is null, the
+   library will allocate its own buffer (and leave next_out null). next_in
+   need not be provided here but must be provided by the application for the
+   next call of inflate().
+
+     If the history buffer is provided by the application, next_out must
+   never be changed by the application since the decompressor maintains
+   history information inside this buffer from call to call; the application
+   can only reset next_out to the beginning of the history buffer when
+   avail_out is zero and all output has been consumed.
+
+      inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was
+   not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as
+   windowBits < 8). msg is set to null if there is no error message.
+   inflateInit2 does not perform any decompression: this will be done by
+   inflate().
+*/
+
+extern int inflateSync OF((z_stream *strm));
+/* 
+    Skips invalid compressed data until the special marker (see deflate()
+  above) can be found, or until all available input is skipped. No output
+  is provided.
+
+    inflateSync returns Z_OK if the special marker has been found, Z_BUF_ERROR
+  if no more input was provided, Z_DATA_ERROR if no marker has been found,
+  or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
+  case, the application may save the current current value of total_in which
+  indicates where valid compressed data was found. In the error case, the
+  application may repeatedly call inflateSync, providing more input each time,
+  until success or end of the input data.
+*/
+
+extern int inflateReset OF((z_stream *strm));
+/*
+     This function is equivalent to inflateEnd followed by inflateInit,
+   but does not free and reallocate all the internal decompression state.
+   The stream will keep attributes that may have been set by inflateInit2.
+
+      inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+extern int inflateIncomp OF((z_stream *strm));
+/*
+     This function adds the data at next_in (avail_in bytes) to the output
+   history without performing any output.  There must be no pending output,
+   and the decompressor must be expecting to see the start of a block.
+   Calling this function is equivalent to decompressing a stored block
+   containing the data at next_in (except that the data is not output).
+*/
+
+                        /* checksum functions */
+
+/*
+     This function is not related to compression but is exported
+   anyway because it might be useful in applications using the
+   compression library.
+*/
+
+extern uLong adler32 OF((uLong adler, Bytef *buf, uInt len));
+
+/*
+     Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+   return the updated checksum. If buf is NULL, this function returns
+   the required initial value for the checksum.
+   An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+   much faster. Usage example:
+
+     uLong adler = adler32(0L, Z_NULL, 0);
+
+     while (read_buffer(buffer, length) != EOF) {
+       adler = adler32(adler, buffer, length);
+     }
+     if (adler != original_adler) error();
+*/
+
+#ifndef _Z_UTIL_H
+    struct internal_state {int dummy;}; /* hack for buggy compilers */
+#endif
+
+#endif /* _ZLIB_H */
diff --git a/mpc8xx/Makefile b/mpc8xx/Makefile
new file mode 100644 (file)
index 0000000..a318523
--- /dev/null
@@ -0,0 +1,188 @@
+#
+# (C) Copyright 2000
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+DIR    := $(shell if [ "$$PWD" != "" ]; then echo $$PWD; else pwd; fi)
+NAME   = $(shell basename $(DIR))
+LIB    = lib$(NAME).a
+
+START  = start.o
+OBJS   = traps.o serial.o cpu.o speed.o interrupts.o
+
+all:   $(START) $(LIB)
+
+$(LIB):        $(OBJS)
+       $(AR) crv $@ $(OBJS)
+
+clean:
+       rm -f $(START) $(OBJS)
+
+distclean:     clean
+       rm -f $(LIB) core *.bak
+
+#########################################################################
+
+depend dep:
+       $(MAKEDEPEND) -- $(CFLAGS) -- $(START:.o=.S) $(OBJS:.o=.c)
+
+#########################################################################
+
+# DO NOT DELETE
+
+start.o: /home/wd/ppc/ppcboot/include/config.h
+start.o: /home/wd/ppc/ppcboot/include/mpc8xx.h
+start.o: /home/wd/ppc/ppcboot/include/version.h
+start.o: /home/wd/ppc/ppcboot/include/ppc_asm.tmpl
+start.o: /home/wd/ppc/ppcboot/include/ppc_defs.h
+start.o: /LinuxPPC/CDK/include/asm/cache.h
+start.o: /LinuxPPC/CDK/include/linux/config.h
+start.o: /LinuxPPC/CDK/include/asm/processor.h
+start.o: /LinuxPPC/CDK/include/asm/ptrace.h
+start.o: /LinuxPPC/CDK/include/asm/residual.h /LinuxPPC/CDK/include/asm/pnp.h
+start.o: /home/wd/ppc/ppcboot/include/asm/mmu.h
+traps.o: /home/wd/ppc/ppcboot/include/ppcboot.h
+traps.o: /home/wd/ppc/ppcboot/include/config.h
+traps.o: /LinuxPPC/CDK/include/linux/bitops.h
+traps.o: /LinuxPPC/CDK/include/asm/bitops.h
+traps.o: /LinuxPPC/CDK/include/asm/system.h
+traps.o: /LinuxPPC/CDK/include/linux/kdev_t.h
+traps.o: /LinuxPPC/CDK/include/asm/processor.h
+traps.o: /LinuxPPC/CDK/include/linux/config.h
+traps.o: /LinuxPPC/CDK/include/asm/ptrace.h
+traps.o: /LinuxPPC/CDK/include/asm/residual.h /LinuxPPC/CDK/include/asm/pnp.h
+traps.o: /LinuxPPC/CDK/include/asm/atomic.h
+traps.o: /LinuxPPC/CDK/include/asm/byteorder.h
+traps.o: /LinuxPPC/CDK/include/asm/types.h
+traps.o: /LinuxPPC/CDK/include/linux/byteorder/big_endian.h
+traps.o: /LinuxPPC/CDK/include/linux/byteorder/swab.h
+traps.o: /LinuxPPC/CDK/include/linux/byteorder/generic.h
+traps.o: /LinuxPPC/CDK/include/linux/types.h
+traps.o: /LinuxPPC/CDK/include/linux/posix_types.h
+traps.o: /LinuxPPC/CDK/include/linux/stddef.h
+traps.o: /LinuxPPC/CDK/include/asm/posix_types.h
+traps.o: /LinuxPPC/CDK/include/linux/string.h
+traps.o: /LinuxPPC/CDK/include/asm/string.h
+traps.o: /home/wd/ppc/ppcboot/include/asm/8xx_immap.h
+traps.o: /home/wd/ppc/ppcboot/include/flash.h
+serial.o: /home/wd/ppc/ppcboot/include/ppcboot.h
+serial.o: /home/wd/ppc/ppcboot/include/config.h
+serial.o: /LinuxPPC/CDK/include/linux/bitops.h
+serial.o: /LinuxPPC/CDK/include/asm/bitops.h
+serial.o: /LinuxPPC/CDK/include/asm/system.h
+serial.o: /LinuxPPC/CDK/include/linux/kdev_t.h
+serial.o: /LinuxPPC/CDK/include/asm/processor.h
+serial.o: /LinuxPPC/CDK/include/linux/config.h
+serial.o: /LinuxPPC/CDK/include/asm/ptrace.h
+serial.o: /LinuxPPC/CDK/include/asm/residual.h
+serial.o: /LinuxPPC/CDK/include/asm/pnp.h /LinuxPPC/CDK/include/asm/atomic.h
+serial.o: /LinuxPPC/CDK/include/asm/byteorder.h
+serial.o: /LinuxPPC/CDK/include/asm/types.h
+serial.o: /LinuxPPC/CDK/include/linux/byteorder/big_endian.h
+serial.o: /LinuxPPC/CDK/include/linux/byteorder/swab.h
+serial.o: /LinuxPPC/CDK/include/linux/byteorder/generic.h
+serial.o: /LinuxPPC/CDK/include/linux/types.h
+serial.o: /LinuxPPC/CDK/include/linux/posix_types.h
+serial.o: /LinuxPPC/CDK/include/linux/stddef.h
+serial.o: /LinuxPPC/CDK/include/asm/posix_types.h
+serial.o: /LinuxPPC/CDK/include/linux/string.h
+serial.o: /LinuxPPC/CDK/include/asm/string.h
+serial.o: /home/wd/ppc/ppcboot/include/asm/8xx_immap.h
+serial.o: /home/wd/ppc/ppcboot/include/flash.h
+serial.o: /home/wd/ppc/ppcboot/include/commproc.h
+cpu.o: /home/wd/ppc/ppcboot/include/ppcboot.h
+cpu.o: /home/wd/ppc/ppcboot/include/config.h
+cpu.o: /LinuxPPC/CDK/include/linux/bitops.h
+cpu.o: /LinuxPPC/CDK/include/asm/bitops.h /LinuxPPC/CDK/include/asm/system.h
+cpu.o: /LinuxPPC/CDK/include/linux/kdev_t.h
+cpu.o: /LinuxPPC/CDK/include/asm/processor.h
+cpu.o: /LinuxPPC/CDK/include/linux/config.h
+cpu.o: /LinuxPPC/CDK/include/asm/ptrace.h
+cpu.o: /LinuxPPC/CDK/include/asm/residual.h /LinuxPPC/CDK/include/asm/pnp.h
+cpu.o: /LinuxPPC/CDK/include/asm/atomic.h
+cpu.o: /LinuxPPC/CDK/include/asm/byteorder.h
+cpu.o: /LinuxPPC/CDK/include/asm/types.h
+cpu.o: /LinuxPPC/CDK/include/linux/byteorder/big_endian.h
+cpu.o: /LinuxPPC/CDK/include/linux/byteorder/swab.h
+cpu.o: /LinuxPPC/CDK/include/linux/byteorder/generic.h
+cpu.o: /LinuxPPC/CDK/include/linux/types.h
+cpu.o: /LinuxPPC/CDK/include/linux/posix_types.h
+cpu.o: /LinuxPPC/CDK/include/linux/stddef.h
+cpu.o: /LinuxPPC/CDK/include/asm/posix_types.h
+cpu.o: /LinuxPPC/CDK/include/linux/string.h
+cpu.o: /LinuxPPC/CDK/include/asm/string.h
+cpu.o: /home/wd/ppc/ppcboot/include/asm/8xx_immap.h
+cpu.o: /home/wd/ppc/ppcboot/include/flash.h /LinuxPPC/CDK/include/asm/cache.h
+speed.o: /home/wd/ppc/ppcboot/include/ppcboot.h
+speed.o: /home/wd/ppc/ppcboot/include/config.h
+speed.o: /LinuxPPC/CDK/include/linux/bitops.h
+speed.o: /LinuxPPC/CDK/include/asm/bitops.h
+speed.o: /LinuxPPC/CDK/include/asm/system.h
+speed.o: /LinuxPPC/CDK/include/linux/kdev_t.h
+speed.o: /LinuxPPC/CDK/include/asm/processor.h
+speed.o: /LinuxPPC/CDK/include/linux/config.h
+speed.o: /LinuxPPC/CDK/include/asm/ptrace.h
+speed.o: /LinuxPPC/CDK/include/asm/residual.h /LinuxPPC/CDK/include/asm/pnp.h
+speed.o: /LinuxPPC/CDK/include/asm/atomic.h
+speed.o: /LinuxPPC/CDK/include/asm/byteorder.h
+speed.o: /LinuxPPC/CDK/include/asm/types.h
+speed.o: /LinuxPPC/CDK/include/linux/byteorder/big_endian.h
+speed.o: /LinuxPPC/CDK/include/linux/byteorder/swab.h
+speed.o: /LinuxPPC/CDK/include/linux/byteorder/generic.h
+speed.o: /LinuxPPC/CDK/include/linux/types.h
+speed.o: /LinuxPPC/CDK/include/linux/posix_types.h
+speed.o: /LinuxPPC/CDK/include/linux/stddef.h
+speed.o: /LinuxPPC/CDK/include/asm/posix_types.h
+speed.o: /LinuxPPC/CDK/include/linux/string.h
+speed.o: /LinuxPPC/CDK/include/asm/string.h
+speed.o: /home/wd/ppc/ppcboot/include/asm/8xx_immap.h
+speed.o: /home/wd/ppc/ppcboot/include/flash.h
+speed.o: /home/wd/ppc/ppcboot/include/mpc8xx.h speed.h
+interrupts.o: /home/wd/ppc/ppcboot/include/ppcboot.h
+interrupts.o: /home/wd/ppc/ppcboot/include/config.h
+interrupts.o: /LinuxPPC/CDK/include/linux/bitops.h
+interrupts.o: /LinuxPPC/CDK/include/asm/bitops.h
+interrupts.o: /LinuxPPC/CDK/include/asm/system.h
+interrupts.o: /LinuxPPC/CDK/include/linux/kdev_t.h
+interrupts.o: /LinuxPPC/CDK/include/asm/processor.h
+interrupts.o: /LinuxPPC/CDK/include/linux/config.h
+interrupts.o: /LinuxPPC/CDK/include/asm/ptrace.h
+interrupts.o: /LinuxPPC/CDK/include/asm/residual.h
+interrupts.o: /LinuxPPC/CDK/include/asm/pnp.h
+interrupts.o: /LinuxPPC/CDK/include/asm/atomic.h
+interrupts.o: /LinuxPPC/CDK/include/asm/byteorder.h
+interrupts.o: /LinuxPPC/CDK/include/asm/types.h
+interrupts.o: /LinuxPPC/CDK/include/linux/byteorder/big_endian.h
+interrupts.o: /LinuxPPC/CDK/include/linux/byteorder/swab.h
+interrupts.o: /LinuxPPC/CDK/include/linux/byteorder/generic.h
+interrupts.o: /LinuxPPC/CDK/include/linux/types.h
+interrupts.o: /LinuxPPC/CDK/include/linux/posix_types.h
+interrupts.o: /LinuxPPC/CDK/include/linux/stddef.h
+interrupts.o: /LinuxPPC/CDK/include/asm/posix_types.h
+interrupts.o: /LinuxPPC/CDK/include/linux/string.h
+interrupts.o: /LinuxPPC/CDK/include/asm/string.h
+interrupts.o: /home/wd/ppc/ppcboot/include/asm/8xx_immap.h
+interrupts.o: /home/wd/ppc/ppcboot/include/flash.h
+interrupts.o: /home/wd/ppc/ppcboot/include/mpc8xx.h
+interrupts.o: /home/wd/ppc/ppcboot/include/mpc8xx_irq.h
+interrupts.o: /home/wd/ppc/ppcboot/include/commproc.h
diff --git a/mpc8xx/config.mk b/mpc8xx/config.mk
new file mode 100644 (file)
index 0000000..78a95e4
--- /dev/null
@@ -0,0 +1,23 @@
+#
+# (C) Copyright 2000
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
diff --git a/mpc8xx/cpu.c b/mpc8xx/cpu.c
new file mode 100644 (file)
index 0000000..bdbad05
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * m8xx.c
+ *
+ * CPU specific code
+ *
+ * written or collected and sometimes rewritten by
+ * Magnus Damm <damm@bitsmart.com>
+ *
+ * minor modifications by
+ * Wolfgang Denk <wd@denx.de>
+ */
+
+#include <ppcboot.h>
+#include <asm/cache.h>
+
+#ifdef CONFIG_MPC860
+static int check_CPU(long clock, uint pvr, uint immr)
+{
+  volatile immap_t *immap = (immap_t *)(immr & 0xFFFF0000);
+  uint k, m;
+
+  /* the highest 16 bits should be 0x0050 for a 860 */
+
+  if((pvr >> 16) != 0x0050)
+    return -1;
+
+  k = (immr << 16) | *((ushort *) &immap->im_cpm.cp_dparam[0xB0]);
+  m = 0;
+
+  switch(k) {
+  case 0x00020001 : printf("pPC860xxZPnn");    break;
+  case 0x00030001 : printf("XPC860xxZPnn");    break;
+
+  case 0x00120003 : printf("XPC860xxZPnnA");   break;
+  case 0x00130003 : printf("XPC860xxZPnnA3");  break;
+
+  case 0x00200004 : printf("XPC860xxZPnnB");   break;
+
+  case 0x00300004 : printf("XPC860xxZPnnC");   break;
+  case 0x00310004 : printf("XPC860xxZPnnC1");  m = 1; break;
+
+
+  case 0x00200064 : printf("XPC860SRZPnnB");   break;
+  case 0x00300065 : printf("XPC860SRZPnnC");   break;
+  case 0x00310065 : printf("XPC860SRZPnnC1");  m = 1; break;
+  case 0x05010000 : printf("XPC860xxZPnnD3");  m = 1; break;
+
+    /* this value is not documented anywhere */
+
+  case 0x40000000 : printf("PPC860PZPnnD");    m = 1; break;
+
+  default: printf("unknown MPC860 (0x%08x)", k);
+  }
+
+  printf(" at %u MHz:", clock);
+
+  printf(" %u kB I-Cache", checkicache() >> 10);
+  printf(" %u kB D-Cache", checkdcache() >> 10);
+
+  /* lets check and see if we're running on a 860T (or P?) */
+
+  immap->im_cpm.cp_fec.fec_addr_low = 0x12345678;
+  if(immap->im_cpm.cp_fec.fec_addr_low == 0x12345678) {
+    printf(" FEC present");
+  }
+
+  if(!m) {
+    printf("\n         *** Warning: CPU Core has Silicon Bugs -- Check the Errata ***");
+  }
+
+  printf("\n");
+
+  return 0;
+}
+
+#elif CONFIG_MPC823
+
+static int check_CPU(long clock, uint pvr, uint immr)
+{
+  volatile immap_t *immap = (immap_t *)(immr & 0xFFFF0000);
+  uint k, m;
+
+  /* the highest 16 bits should be 0x0050 for a 8xx */
+
+  if((pvr >> 16) != 0x0050)
+    return -1;
+
+  k = (immr << 16) | *((ushort *) &immap->im_cpm.cp_dparam[0xB0]);
+  m = 0;
+
+  switch(k) {
+  /* MPC823 */
+  case 0x20000000 : printf("PPC823ZTnn0");     break;
+  case 0x20010000 : printf("PPC823ZTnn0.1");   break;
+  case 0x20020000 : printf("PPC823ZTnnZ2/3");  break;
+  case 0x20020001 : printf("PPC823ZTnnZ3");    break;
+  case 0x21000000 : printf("PPC823ZTnnA");     break;
+  case 0x21010000 : printf("PPC823ZTnnB");     m=1; break;
+  /* MPC823E */
+  case 0x24010000 : printf("PPC823EZTnnB2");   m=1; break;
+
+  default: printf("unknown MPC823 (0x%08x)", k);
+  }
+  printf(" at %u MHz:", clock);
+
+  printf(" %u kB I-Cache", checkicache() >> 10);
+  printf(" %u kB D-Cache", checkdcache() >> 10);
+
+  /* lets check and see if we're running on a 860T (or P?) */
+
+  immap->im_cpm.cp_fec.fec_addr_low = 0x12345678;
+  if(immap->im_cpm.cp_fec.fec_addr_low == 0x12345678) {
+    printf(" FEC present");
+  }
+
+  if(!m) {
+    printf("\n         *** Warning: CPU Core has Silicon Bugs -- Check the Errata ***");
+  }
+
+  printf("\n");
+
+  return 0;
+}
+
+#elif CONFIG_MPC850
+
+static int check_CPU(long clock, uint pvr, uint immr)
+{
+  volatile immap_t *immap = (immap_t *)(immr & 0xFFFF0000);
+  uint k, m;
+
+  /* the highest 16 bits should be 0x0050 for a 8xx */
+
+  if((pvr >> 16) != 0x0050)
+    return -1;
+
+  k = (immr << 16) | *((ushort *) &immap->im_cpm.cp_dparam[0xB0]);
+  m = 0;
+
+  switch(k)
+  {
+  case 0x20020001 : printf("XPC850xxZT");      break;
+  case 0x21000065 : printf("XPC850xxZTA");     break;
+  case 0x21010067 : printf("XPC850xxZTB");     m=1; break;
+  default: printf("unknown MPC850 (0x%08x)", k);
+  }
+  printf(" at %lu MHz:", clock);
+
+  printf(" %u kB I-Cache", checkicache() >> 10);
+  printf(" %u kB D-Cache", checkdcache() >> 10);
+
+  /* lets check and see if we're running on a 860T (or P?) */
+
+  immap->im_cpm.cp_fec.fec_addr_low = 0x12345678;
+  if(immap->im_cpm.cp_fec.fec_addr_low == 0x12345678) {
+    printf(" FEC present");
+  }
+
+  if(!m) {
+    printf("\n         * CPU Core has Silicon Bugs - Check the Errata !");
+  }
+
+  printf("\n");
+
+  return 0;
+}
+#else
+#error CPU undefined
+#endif
+/* ------------------------------------------------------------------------- */
+
+int checkcpu(long clock)
+{
+  uint immr = get_immr(0);     /* Return full IMMR contents */
+  uint pvr = get_pvr();
+
+  /* 850 has PARTNUM 20 */
+  /* 801 has PARTNUM 10 */
+  return check_CPU(clock, pvr, immr);
+}
+
+/* ------------------------------------------------------------------------- */
+/* L1 i-cache                                                                */
+/* the standard 860 has 128 sets of 16 bytes in 2 ways (= 4 kB)              */
+/* the 860 P (plus) has 256 sets of 16 bytes in 4 ways (= 16 kB)             */
+
+int checkicache(void)
+{
+  volatile immap_t     *immap = (immap_t *)CFG_IMMR;
+  volatile memctl8xx_t *memctl = &immap->im_memctl;
+  u32 cacheon = rd_ic_cst() & IDC_ENABLED;
+  u32 k = memctl->memc_br0 & ~0x00007fff;  /* probe in flash memoryarea */
+  u32 m;
+  u32 lines = -1;
+
+  wr_ic_cst(IDC_UNALL);
+  wr_ic_cst(IDC_INVALL);
+  wr_ic_cst(IDC_DISABLE);
+  __asm__ volatile("isync");
+
+  while(!((m = rd_ic_cst()) & IDC_CERR2))
+  {
+    wr_ic_adr(k);
+    wr_ic_cst(IDC_LDLCK);
+    __asm__ volatile("isync");
+    lines++;
+    k += 0x10; /* the number of bytes in a cacheline */
+  }
+
+  wr_ic_cst(IDC_UNALL);
+  wr_ic_cst(IDC_INVALL);
+
+  if(cacheon)
+    wr_ic_cst(IDC_ENABLE);
+  else
+    wr_ic_cst(IDC_DISABLE);
+
+  __asm__ volatile("isync");
+
+  return lines << 4;
+};
+/* ------------------------------------------------------------------------- */
+/* L1 d-cache                                                                */
+/* the standard 860 has 128 sets of 16 bytes in 2 ways (= 4 kB)              */
+/* the 860 P (plus) has 256 sets of 16 bytes in 2 ways (= 8 kB)              */
+/* call with cache disabled                                                  */
+
+int checkdcache(void)
+{
+  volatile immap_t     *immap = (immap_t *)CFG_IMMR;
+  volatile memctl8xx_t *memctl = &immap->im_memctl;
+  u32 cacheon = rd_dc_cst() & IDC_ENABLED;
+  u32 k = memctl->memc_br0 & ~0x00007fff;  /* probe in flash memoryarea */
+  u32 m;
+  u32 lines = -1;
+
+  wr_dc_cst(IDC_UNALL);
+  wr_dc_cst(IDC_INVALL);
+  wr_dc_cst(IDC_DISABLE);
+
+  while(!((m = rd_dc_cst()) & IDC_CERR2))
+  {
+    wr_dc_adr(k);
+    wr_dc_cst(IDC_LDLCK);
+    lines++;
+    k += 0x10; /* the number of bytes in a cacheline */
+  }
+
+  wr_dc_cst(IDC_UNALL);
+  wr_dc_cst(IDC_INVALL);
+
+  if(cacheon)
+    wr_dc_cst(IDC_ENABLE);
+  else
+    wr_dc_cst(IDC_DISABLE);
+
+  return lines << 4;
+};
+
+/* ------------------------------------------------------------------------- */
+
+void upmconfig(uint upm, uint *table, uint size)
+{
+  uint i;
+  uint addr = 0;
+  volatile immap_t     *immap = (immap_t *)CFG_IMMR;
+  volatile memctl8xx_t *memctl = &immap->im_memctl;
+
+  for (i = 0; i < size; i++)
+  {
+    memctl->memc_mdr = table[i];    /* (16-15) */
+    memctl->memc_mcr = addr | upm;  /* (16-16) */
+    addr++;
+  }
+}
+
+/* ------------------------------------------------------------------------- */
diff --git a/mpc8xx/interrupts.c b/mpc8xx/interrupts.c
new file mode 100644 (file)
index 0000000..c1b9ae9
--- /dev/null
@@ -0,0 +1,320 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <ppcboot.h>
+#include <mpc8xx.h>
+#include <mpc8xx_irq.h>
+#include <commproc.h>
+
+/****************************************************************************/
+
+#define        DECREMENTER_TICK        1000    /* 1 ms tick */
+unsigned decrementer_count;            /* count value for 1e6/HZ microseconds */
+
+/****************************************************************************/
+
+/*
+ * CPM interrupt vector functions.
+ */
+struct cpm_action {
+        interrupt_handler_t *handler;
+        void *arg;
+};
+
+static struct cpm_action cpm_vecs[CPMVEC_NR];
+
+static void cpm_interrupt_init (void);
+static void cpm_interrupt(int irq, struct pt_regs * regs);
+
+/****************************************************************************/
+
+static __inline__ unsigned long get_msr(void)
+{
+    unsigned long msr;
+
+    asm volatile("mfmsr %0" : "=r" (msr) :);
+    return msr;
+}
+
+static __inline__ void set_msr(unsigned long msr)
+{
+    asm volatile("mtmsr %0" : : "r" (msr)); 
+}
+
+static __inline__ unsigned long get_dec(void)
+{
+    unsigned long val;
+
+    asm volatile("mfdec %0" : "=r" (val) :);
+    return val;
+}
+
+
+static __inline__ void set_dec(unsigned long val)
+{
+    asm volatile("mtdec %0" : : "r" (val)); 
+}
+
+
+void enable_interrupts (void)
+{
+       set_msr (get_msr() | MSR_EE);
+}
+
+/* returns flag if MSR_EE was set before */
+int disable_interrupts (void)
+{
+       ulong msr = get_msr();
+       set_msr (msr & ~MSR_EE);
+       return ((msr & MSR_EE) != 0);
+}
+
+/****************************************************************************/
+
+void
+interrupt_init (bd_t *bd)
+{
+       int freq;
+
+       freq = (bd->bi_intfreq * 1000000);
+       if (((volatile immap_t *)CFG_IMMR)->im_clkrst.car_sccr & SCCR_TBS) {
+               freq /= 16;     /* use divide by 16 processor clock */
+       }
+       decrementer_count = freq / DECREMENTER_TICK;
+
+       cpm_interrupt_init();
+
+       ((immap_t *)CFG_IMMR)->im_siu_conf.sc_simask |=
+               (1 << (31-CPM_INTERRUPT));
+
+       set_dec (decrementer_count);
+
+       set_msr (get_msr() | MSR_EE);
+}
+
+/****************************************************************************/
+
+/*
+ * Handle external interrupts
+ */
+void external_interrupt(struct pt_regs *regs)
+{
+       immap_t *immr = (immap_t *)CFG_IMMR;
+       int     irq;
+       ulong   bits;
+       ulong   simask, newmask;
+       ulong   vec;
+
+       /*
+        * read the SIVEC register and shift the bits down
+        * to get the irq number
+        */
+       bits = immr->im_siu_conf.sc_sivec;
+       irq = bits >> 26;
+
+       bits = 1UL << irq;
+
+       /*
+        * Read Interrupt Mask Register and Mask Interrupts
+        */
+       simask = immr->im_siu_conf.sc_simask;
+       newmask = simask & (~(0xFFFF0000 >> irq));
+       immr->im_siu_conf.sc_simask = newmask;
+
+       if (!(irq & 0x1)) {                     /* External Interrupt ?         */
+               ulong siel, v_bit;
+               /*
+                * Read Interrupt Edge/Level Register
+                */
+               siel = immr->im_siu_conf.sc_siel;
+               v_bit = 0x80000000 >> irq;
+
+               if (siel & v_bit) {             /* edge triggered interrupt ?   */
+                       /*
+                        * Rewrite SIPEND Register to clear interrupt
+                        */
+                       immr->im_siu_conf.sc_sipend = v_bit;
+               }
+       }
+
+       switch (irq) {
+       case CPM_INTERRUPT:
+               cpm_interrupt (irq, regs);
+               break;
+       default:
+               printf ("\nBogus External Interrupt IRQ %d Vector %ld\n",
+                       irq, vec);
+               break;
+       }
+
+       /*
+        * Re-Enable old Interrupt Mask
+        */
+       immr->im_siu_conf.sc_simask = simask;
+}
+
+/****************************************************************************/
+
+/*
+ * CPM interrupt handler
+ */
+static void
+cpm_interrupt(int irq, struct pt_regs * regs)
+{
+       immap_t *immr = (immap_t *)CFG_IMMR;
+       uint    vec;
+
+       /*
+        * Get the vector by setting the ACK bit
+        * and then reading the register.
+        */
+       immr->im_cpic.cpic_civr = 1;
+       vec = immr->im_cpic.cpic_civr;
+       vec >>= 11;
+
+       if (cpm_vecs[vec].handler != NULL) {
+               (*cpm_vecs[vec].handler)(cpm_vecs[vec].arg);
+       } else {
+               immr->im_cpic.cpic_cimr &= ~(1 << vec);
+               printf ("Masking bogus CPM interrupt vector 0x%x\n", vec);
+       }
+       /*
+        * After servicing the interrupt, we have to remove the status indicator.
+        */
+       immr->im_cpic.cpic_cisr |= (1 << vec);
+}
+
+/*
+ * The CPM can generate the error interrupt when there is a race
+ * condition between generating and masking interrupts. All we have
+ * to do is ACK it and return. This is a no-op function so we don't
+ * need any special tests in the interrupt handler.
+ */
+static void
+cpm_error_interrupt (void *dummy)
+{
+}
+
+/****************************************************************************/
+
+/*
+ * Install and free a CPM interrupt handler.
+ */
+
+void
+cpm_install_handler(int vec, interrupt_handler_t *handler, void *arg)
+{
+       if (cpm_vecs[vec].handler != NULL) {
+               printf ("CPM interrupt 0x%x replacing 0x%x\n",
+                       (uint)handler, (uint)cpm_vecs[vec].handler);
+       }
+       cpm_vecs[vec].handler = handler;
+       cpm_vecs[vec].arg     = arg;
+       ((immap_t *)CFG_IMMR)->im_cpic.cpic_cimr |= (1 << vec);
+#if 0
+       printf ("Install CPM interrupt for vector %d ==> %p\n", vec, handler);
+#endif
+}
+
+void
+cpm_free_handler(int vec)
+{
+#if 0
+       printf ("Free CPM interrupt for vector %d ==> %p\n",
+               vec, cpm_vecs[vec].handler);
+#endif
+       ((immap_t *)CFG_IMMR)->im_cpic.cpic_cimr &= ~(1 << vec);
+       cpm_vecs[vec].handler = NULL;
+       cpm_vecs[vec].arg     = NULL;
+}
+
+/****************************************************************************/
+
+static void
+cpm_interrupt_init (void)
+{
+       immap_t *immr = (immap_t *)CFG_IMMR;
+
+       /*
+        * Initialize the CPM interrupt controller.
+        */
+       
+       immr->im_cpic.cpic_cicr =
+               ( CICR_SCD_SCC4 |
+                 CICR_SCC_SCC3 |
+                 CICR_SCB_SCC2 |
+                 CICR_SCA_SCC1 ) | ((CPM_INTERRUPT/2) << 13) | CICR_HP_MASK;
+       
+       immr->im_cpic.cpic_cimr = 0;
+
+       /*
+        * Install the error handler.
+        */
+       cpm_install_handler(CPMVEC_ERROR, cpm_error_interrupt, NULL);
+
+       immr->im_cpic.cpic_cicr |= CICR_IEN;
+}
+
+/****************************************************************************/
+
+
+volatile ulong timestamp = 0;
+
+/*
+ * timer_interrupt - gets called when the decrementer overflows,
+ * with interrupts disabled.
+ * Trivial implementation - no need to be really accurate.
+ */
+void timer_interrupt(struct pt_regs *regs)
+{
+       immap_t *immr = (immap_t *)CFG_IMMR;
+#if 0
+       printf ("*** Timer Interrupt *** ");
+#endif
+       /* Reset Timer Expired and Timers Interrupt Status */
+       immr->im_clkrst.car_plprcr = PLPRCR_TEXPS | PLPRCR_TMIST;
+       /* Restore Decrementer Count */
+       set_dec (decrementer_count);
+
+       timestamp++;
+}
+
+/****************************************************************************/
+
+void reset_timer (void)
+{
+       timestamp = 0;
+}
+
+ulong get_timer (ulong base)
+{
+       return (timestamp - base);
+}
+
+void set_timer (ulong t)
+{
+       timestamp = t;
+}
+
+/****************************************************************************/
+
diff --git a/mpc8xx/serial.c b/mpc8xx/serial.c
new file mode 100644 (file)
index 0000000..ad8ff29
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <ppcboot.h>
+#include <commproc.h>
+
+#if defined(CONFIG_8xx_CONS_SMC1)      /* Console on SMC1 */
+
+#define        SMC_INDEX       0
+#define PROFF_SMC      PROFF_SMC1
+#define CPM_CR_CH_SMC  CPM_CR_CH_SMC1
+#define FADS_BCSR1     0x01000000
+
+#elif defined(CONFIG_8xx_CONS_SMC2)    /* Console on SMC2 */
+
+#define SMC_INDEX      1
+#define PROFF_SMC      PROFF_SMC2
+#define CPM_CR_CH_SMC  CPM_CR_CH_SMC2
+#define FADS_BCSR1     0x00040000
+
+#else /* CONFIG_8xx_CONS_SMC? */
+#error "console not correctly defined"
+#endif
+
+/*
+ * Minimal serial functions needed to use one of the SMC ports
+ * as serial console interface.
+ */
+
+void
+serial_init()
+{
+        volatile immap_t *im = (immap_t *)CFG_IMMR;
+       volatile smc_t *sp;
+       volatile smc_uart_t *up;
+       volatile cbd_t *tbdf, *rbdf;
+       volatile cpm8xx_t *cp = &(im->im_cpm);
+       volatile iop8xx_t *ip = (iop8xx_t *)&(im->im_ioport);
+       uint    dpaddr;
+
+       /* initialize pointers to SMC */
+
+       sp = (smc_t *) &(cp->cp_smc[SMC_INDEX]);
+       up = (smc_uart_t *) &cp->cp_dparam[PROFF_SMC];
+
+       /* Disable transmitter/receiver.
+       */
+       sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
+
+       /* Enable SDMA.
+       */
+       im->im_siu_conf.sc_sdcr = 1;
+
+#if defined(CONFIG_8xx_CONS_SMC1)
+       /* Use Port B for SMC1 instead of other functions.
+       */
+       cp->cp_pbpar |=  0x000000c0;
+       cp->cp_pbdir &= ~0x000000c0;
+       cp->cp_pbodr &= ~0x000000c0;
+#else  /* CONFIG_8xx_CONS_SMC2 */
+# if defined(CONFIG_MPC823) || defined(CONFIG_MPC850)
+       /* Use Port A for SMC2 instead of other functions.
+       */
+       ip->iop_papar |=  0x00c0;
+       ip->iop_padir &= ~0x00c0;
+       ip->iop_paodr &= ~0x00c0;
+# else /* must be a 860 then */
+       /* Use Port B for SMC2 instead of other functions.
+       */
+       cp->cp_pbpar |=  0x00000c00;
+       cp->cp_pbdir &= ~0x00000c00;
+       cp->cp_pbodr &= ~0x00000c00;
+# endif        
+#endif
+
+       /* Allocate space for two buffer descriptors in the DP ram.
+        * For now, this address seems OK, but it may have to
+        * change with newer versions of the firmware.
+        * damm: allocating space after the two buffers for rx/tx data
+        */
+
+       dpaddr = 0x800;
+
+       /* Set the physical address of the host memory buffers in
+        * the buffer descriptors.
+        */
+
+       rbdf = (cbd_t *)&cp->cp_dpmem[dpaddr];
+       rbdf->cbd_bufaddr = (uint) (rbdf+2);
+       rbdf->cbd_sc = 0;
+       tbdf = rbdf + 1;
+       tbdf->cbd_bufaddr = ((uint) (rbdf+2)) + 1;
+       tbdf->cbd_sc = 0;
+
+       /* Set up the uart parameters in the parameter ram.
+       */
+       up->smc_rbase = dpaddr;
+       up->smc_tbase = dpaddr+sizeof(cbd_t);
+       up->smc_rfcr = SMC_EB;
+       up->smc_tfcr = SMC_EB;
+
+       /* Set UART mode, 8 bit, no parity, one stop.
+        * Enable receive and transmit.
+        */
+       sp->smc_smcmr = smcr_mk_clen(9) |  SMCMR_SM_UART;
+
+       /* Mask all interrupts and remove anything pending.
+       */
+       sp->smc_smcm = 0;
+       sp->smc_smce = 0xff;
+
+
+       /* Set up the baud rate generator.
+        * See 8xx_io/commproc.c for details.
+        *
+        * Wire BRG1 to SMC1 and BRG2 to SMC2.
+        */
+
+       cp->cp_simode = 0x10000000;
+
+/* XXX FIXME - fix later:
+ * XXX Instead of using a hard-coded value CONFIG_8xx_CPUCLOCK
+ * XXX we might make this automatic?
+ */
+#if defined(CONFIG_8xx_CONS_SMC1)
+       cp->cp_brgc1 =                  /* Console on SMC1 */
+#else
+       cp->cp_brgc2 =                  /* Console on SMC2 */
+#endif
+               (((((CONFIG_8xx_CPUCLOCK * 1000000)/16) / CONFIG_8xx_BAUDRATE)-1) << 1)
+               | CPM_BRG_EN;
+
+       /* Make the first buffer the only buffer.
+       */
+       tbdf->cbd_sc |= BD_SC_WRAP;
+       rbdf->cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP;
+
+       /* Single character receive.
+       */
+       up->smc_mrblr = 1;
+       up->smc_maxidl = 0;
+
+       /* Initialize Tx/Rx parameters.
+       */
+
+       while (cp->cp_cpcr & CPM_CR_FLG)  /* wait if cp is busy */
+         ;
+
+       cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+
+       while (cp->cp_cpcr & CPM_CR_FLG)  /* wait if cp is busy */
+         ;
+
+       /* Enable transmitter/receiver.
+       */
+       sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN;
+}
+
+void
+serial_putc(const char c)
+{
+       volatile cbd_t          *tbdf;
+       volatile char           *buf;
+       volatile smc_uart_t     *up;
+        volatile immap_t       *im = (immap_t *)CFG_IMMR;
+       volatile cpm8xx_t       *cpmp = &(im->im_cpm);
+
+       if (c == '\n')
+               serial_putc ('\r');
+
+       up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC];
+
+       tbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_tbase];
+
+       /* Wait for last character to go.
+       */
+
+       buf = (char *)tbdf->cbd_bufaddr;
+#if 0
+       __asm__("eieio");
+       while (tbdf->cbd_sc & BD_SC_READY)
+               __asm__("eieio");
+#endif
+
+       *buf = c;
+       tbdf->cbd_datlen = 1;
+       tbdf->cbd_sc |= BD_SC_READY;
+       __asm__("eieio");
+#if 1
+       while (tbdf->cbd_sc & BD_SC_READY)
+               __asm__("eieio");
+#endif
+}
+
+void
+serial_putstr (const char *s)
+{
+       while (*s) {
+               serial_putc (*s++);
+       }
+}
+
+int
+serial_getc(void)
+{
+       volatile cbd_t          *rbdf;
+       volatile unsigned char  *buf;
+       volatile smc_uart_t     *up;
+        volatile immap_t       *im = (immap_t *)CFG_IMMR;
+       volatile cpm8xx_t       *cpmp = &(im->im_cpm);
+       unsigned char           c;
+
+       up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC];
+
+       rbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_rbase];
+
+       /* Wait for character to show up.
+       */
+       buf = (unsigned char *)rbdf->cbd_bufaddr;
+       while (rbdf->cbd_sc & BD_SC_EMPTY)
+               ;
+       c = *buf;
+       rbdf->cbd_sc |= BD_SC_EMPTY;
+
+       return(c);
+}
+
+int
+serial_tstc()
+{
+       volatile cbd_t          *rbdf;
+       volatile smc_uart_t     *up;
+        volatile immap_t       *im = (immap_t *)CFG_IMMR;
+       volatile cpm8xx_t       *cpmp = &(im->im_cpm);
+
+       up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC];
+
+       rbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_rbase];
+
+       return(!(rbdf->cbd_sc & BD_SC_EMPTY));
+}
diff --git a/mpc8xx/speed.c b/mpc8xx/speed.c
new file mode 100644 (file)
index 0000000..fcc0ae1
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <ppcboot.h>
+#include <mpc8xx.h>
+#include "speed.h"
+
+/* Access functions for the Machine State Register */
+static __inline__ unsigned long get_msr(void)
+{
+    unsigned long msr;
+
+    asm volatile("mfmsr %0" : "=r" (msr) :);
+    return msr;
+}
+
+static __inline__ void set_msr(unsigned long msr)
+{
+    asm volatile("mtmsr %0" : : "r" (msr)); 
+}
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * Measure CPU clock speed (core clock GCLK1, GCLK2)
+ * (Approx. GCLK frequency in Hz)
+ *
+ * Initializes timer 2 and PIT, but disables them before return.
+ * [Use timer 2, because MPC823 CPUs mask 0.x do not have timers 3 and 4]
+ */
+
+ulong get_gclk_freq (void)
+{
+  volatile immap_t        *immap = (immap_t *)CFG_IMMR;
+  volatile cpmtimer8xx_t *timerp = &immap->im_cpmtimer;
+  ulong timer2_val;
+  ulong msr_val;
+
+  /* Reset + Stop Timer 2, no cascading
+   */
+  timerp->cpmt_tgcr &= ~(TGCR_CAS2 | TGCR_RST2);
+
+  /* Keep stopped, halt in debug mode
+   */
+  timerp->cpmt_tgcr |=  (TGCR_FRZ2 | TGCR_STP2);
+
+  /* Timer 2 setup:
+   * Output ref. interrupt disable, int. clock / 16
+   */
+  timerp->cpmt_tmr2 = (SPEED_TMR2_PS << TMR_PS_SHIFT) | TMR_ICLK_IN_GEN_DIV16;
+
+  timerp->cpmt_tcn2 = 0;                       /* reset state          */
+  timerp->cpmt_tgcr |= TGCR_RST2;              /* enable timer 2       */
+
+  immap->im_sitk.sitk_pitck  = KAPWR_KEY;      /* PIT initialization   */
+  immap->im_sit.sit_pitc    = SPEED_PITC;
+
+  immap->im_sitk.sitk_piscrk = KAPWR_KEY;
+  immap->im_sit.sit_piscr    = CFG_PISCR;
+
+  /*
+   * Start measurement - disable interrupts, just in case
+   */
+  msr_val = get_msr();
+  set_msr (msr_val & ~MSR_EE);
+
+  immap->im_sit.sit_piscr |= PISCR_PTE;
+  timerp->cpmt_tgcr &= ~TGCR_STP2;             /* Start Timer 2        */
+  while ((immap->im_sit.sit_piscr & PISCR_PS) == 0)
+       ;
+  timerp->cpmt_tgcr |=  TGCR_STP2;             /* Stop  Timer 2        */
+
+  /* re-enable external interrupts if they were on */
+  set_msr (msr_val);
+
+  /* Disable timer and PIT
+   */
+  timer2_val = timerp->cpmt_tcn2;              /* save before restting */
+
+  timerp->cpmt_tgcr &= ~(TGCR_RST2 | TGCR_FRZ2 | TGCR_STP2);
+  immap->im_sit.sit_piscr &= ~PISCR_PTE;
+
+  return (timer2_val * 400000L);               /* convert to Hz        */
+}
+
+/* ------------------------------------------------------------------------- */
diff --git a/mpc8xx/speed.h b/mpc8xx/speed.h
new file mode 100644 (file)
index 0000000..204f7ec
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*-----------------------------------------------------------------------
+ * Timer value for timer 2, ICLK = 10
+ * 
+ * SPEED_FCOUNT2 =  GCLK / (16 * (TIMER_TMR_PS + 1))
+ * SPEED_TMR3_PS = (GCLK / (16 * SPEED_FCOUNT3)) - 1 
+ *
+ * SPEED_FCOUNT2       timer 2 counting frequency
+ * GCLK                        CPU clock
+ * SPEED_TMR2_PS       prescaler
+ */
+#define SPEED_TMR2_PS          (250 - 1)       /* divide by 250        */
+
+/*-----------------------------------------------------------------------
+ * Timer value for PIT
+ * 
+ * PIT_TIME = SPEED_PITC / PITRTCLK
+ * PITRTCLK = 8192 
+ */
+#define SPEED_PITC     (82 << 16)      /* start counting from 82       */
+
+/*
+ * The new value for PTA is calculated from
+ *
+ *     PTA = (gclk * Trefresh) / (2 ^ (2 * DFBRG) * PTP * NCS)
+ * 
+ * gclk                CPU clock (not bus clock !) 
+ * Trefresh    Refresh cycle * 4 (four word bursts used)
+ * DFBRG       For normal mode (no clock reduction) always 0
+ * PTP         Prescaler (already adjusted for no. of banks and 4K / 8K refresh)
+ * NCS         Number of SDRAM banks (chip selects) on this UPM.
+ */
diff --git a/mpc8xx/start.S b/mpc8xx/start.S
new file mode 100644 (file)
index 0000000..343dede
--- /dev/null
@@ -0,0 +1,730 @@
+/*
+ *  Copyright (C) 1998 Dan Malek <dmalek@jlc.net>
+ *  Copyright (C) 1999 Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se>
+ *  Copyright (C) 2000 Wolfgang Denk <wd@denx.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*  ppcboot - Startup Code for PowerPC based Embedded Boards
+ *
+ *
+ *  The processor starts at 0x00000100 and the code is executed
+ *  from flash. The code is organized to be at an other address
+ *  in memory, but as long we don't jump around before relocating.
+ *  board_init lies at a quite high address and when the cpu has
+ *  jumped there, everything is ok.
+ *  This works because the cpu gives the FLASH (CS0) the whole
+ *  address space at startup, and board_init lies as a echo of
+ *  the flash somewhere up there in the memorymap.
+ *
+ *  board_init will change CS0 to be positioned at the correct
+ *  address and (s)dram will be positioned at address 0
+ */
+#include <config.h>
+#include <mpc8xx.h>
+#include "version.h"
+
+#define CONFIG_8xx 1           /* needed for Linux kernel header files */
+#define _LINUX_CONFIG_H 1      /* avoid reading Linux autoconf.h file  */
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+
+#include <asm/cache.h>
+#include <asm/mmu.h>
+
+/* We don't want the  MMU yet.
+*/
+#undef MSR_KERNEL
+#define MSR_KERNEL ( MSR_ME | MSR_RI ) /* Machine Check and Recoverable Interr. */
+
+/*
+ * Set up GOT: Global Offset Table
+ *
+ * Use r14 to access the GOT
+ */
+       START_GOT
+       GOT_ENTRY(_GOT2_TABLE_)
+       GOT_ENTRY(_FIXUP_TABLE_)
+
+       GOT_ENTRY(_start)
+       GOT_ENTRY(_start_of_vectors)
+       GOT_ENTRY(_end_of_vectors)
+       GOT_ENTRY(transfer_to_handler)
+
+       GOT_ENTRY(_end)
+       GOT_ENTRY(.bss)
+       END_GOT
+
+/*
+ * r3 - 1st arg to board_init(): IMMP pointer
+ * r4 - 2nd arg to board_init(): boot flag
+ */
+       .text
+       .long   0x27051956              /* PPCBOOT Magic Number                 */
+       .globl  version_string
+version_string:
+       .ascii PPCBOOT_VERSION, " (", __DATE__, " - ", __TIME__, ")\0"
+
+       . = EXC_OFF_SYS_RESET
+       .globl  _start
+_start:
+       li      r4, BOOTFLAG_COLD       /* Normal Power-On: Boot from FLASH     */
+       b       boot_cold
+
+       . = EXC_OFF_SYS_RESET + 0x10
+
+       .globl  _start_warm
+_start_warm:
+       li      r4, BOOTFLAG_WARM       /* Software reboot                      */
+       b       boot_warm
+
+boot_cold:
+boot_warm:
+
+       /* Initialize machine status; enable machine check interrupt            */
+       /*----------------------------------------------------------------------*/
+       li      r3, MSR_KERNEL          /* Set ME, RI flags */
+       mtmsr   r3
+       mtspr   SRR1, r3                /* Make SRR1 match MSR */
+
+       mfspr   r3, ICR                 /* clear Interrupt Cause Register */
+
+       /* Initialize debug port registers                                      */
+       /*----------------------------------------------------------------------*/
+       xor     r0, r0, r0              /* Clear R0 */
+       mtspr   LCTRL1, r0              /* Initialize debug port regs */
+       mtspr   LCTRL2, r0
+       mtspr   COUNTA, r0
+       mtspr   COUNTB, r0
+
+       /* Reset the caches                                                     */
+       /*----------------------------------------------------------------------*/
+
+       mfspr   r3, IC_CST              /* Clear error bits */
+       mfspr   r3, DC_CST
+
+       lis     r3, IDC_UNALL@h         /* Unlock all */
+       mtspr   IC_CST, r3
+       mtspr   DC_CST, r3
+
+       lis     r3, IDC_INVALL@h        /* Invalidate all */
+       mtspr   IC_CST, r3
+       mtspr   DC_CST, r3
+
+       lis     r3, IDC_DISABLE@h       /* Disable data cache */
+       mtspr   DC_CST, r3
+
+       lis     r3, IDC_ENABLE@h        /* Enable instruction cache */
+       mtspr   IC_CST, r3
+
+       /* invalidate all tlb's                                                 */
+       /*----------------------------------------------------------------------*/
+
+       tlbia
+       isync
+
+       /*
+        * Calculate absolute address in FLASH and jump there
+        *----------------------------------------------------------------------*/
+
+       lis     r3, CFG_FLASH_BASE@h
+       ori     r3, r3, CFG_FLASH_BASE@l
+       addi    r3, r3, in_flash - _start + EXC_OFF_SYS_RESET
+       mtlr    r3
+       blr
+
+in_flash:
+
+       /* initialize some SPRs that are hard to access from C                  */
+       /*----------------------------------------------------------------------*/
+
+       lis     r3, CFG_IMMR@h          /* position IMMR and */
+       mtspr   638, r3                 /* pass r3 as arg1 to C routine */
+
+       ori     r1, r3, 0x3000          /* set up the stack in internal DPRAM */
+
+
+       /*
+        * Disable serialized ifetch and show cycles
+        * (i.e. set processor to normal mode).
+        * This is also a silicon bug workaround, see errata
+        */
+
+       li      r2, 0x0007
+       mtspr   ICTRL, r2
+
+       /* Set up debug mode entry */
+
+       li      r2, CFG_DER@h
+       ori     r2, r2, CFG_DER@l
+       mtspr   DER, r2
+
+       /* let the C-code set up the rest                                       */
+       /*                                                                      */
+       /* Be careful to keep code relocatable !                                */
+       /*----------------------------------------------------------------------*/
+
+       GET_GOT                 /* initialize GOT access                        */
+
+       bl      board_init_f    /* run first part of init code (from Flash)     */
+
+
+
+       .globl  _start_of_vectors
+_start_of_vectors:
+
+/* Machine check */
+       STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)
+
+/* Data Storage exception.  "Never" generated on the 860. */
+       STD_EXCEPTION(0x300, DataStorage, UnknownException)
+
+/* Instruction Storage exception.  "Never" generated on the 860. */
+       STD_EXCEPTION(0x400, InstStorage, UnknownException)
+
+/* External Interrupt exception. */
+       STD_EXCEPTION(0x500, ExtInterrupt, external_interrupt)
+
+/* Alignment exception. */
+       . = 0x600
+Alignment:
+       EXCEPTION_PROLOG
+       mfspr   r4,DAR
+       stw     r4,_DAR(r21)
+       mfspr   r5,DSISR
+       stw     r5,_DSISR(r21)
+       addi    r3,r1,STACK_FRAME_OVERHEAD
+       li      r20,MSR_KERNEL
+       rlwimi  r20,r23,0,16,16         /* copy EE bit from saved MSR */
+       lwz     r6,GOT(transfer_to_handler)
+       mtlr    r6
+       blrl
+.L_Alignment:
+       .long   AlignmentException - _start + EXC_OFF_SYS_RESET
+       .long   int_return - _start + EXC_OFF_SYS_RESET
+
+/* Program check exception */
+       . = 0x700
+ProgramCheck:
+       EXCEPTION_PROLOG
+       addi    r3,r1,STACK_FRAME_OVERHEAD
+       li      r20,MSR_KERNEL
+       rlwimi  r20,r23,0,16,16         /* copy EE bit from saved MSR */
+       lwz     r6,GOT(transfer_to_handler)
+       mtlr    r6
+       blrl
+.L_ProgramCheck:
+       .long   ProgramCheckException - _start + EXC_OFF_SYS_RESET
+       .long   int_return - _start + EXC_OFF_SYS_RESET
+
+       /* No FPU on MPC8xx.  This exception is not supposed to happen.
+       */
+       STD_EXCEPTION(0x800, FPUnavailable, UnknownException)
+
+       /* I guess we could implement decrementer, and may have
+        * to someday for timekeeping.
+        */
+       STD_EXCEPTION(0x900, Decrementer, timer_interrupt)
+       STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
+       STD_EXCEPTION(0xb00, Trap_0b, UnknownException)
+
+       STD_EXCEPTION(0xc00, SystemCall, UnknownException)
+       STD_EXCEPTION(0xd00, SingleStep, UnknownException)
+
+       STD_EXCEPTION(0xe00, Trap_0e, UnknownException)
+       STD_EXCEPTION(0xf00, Trap_0f, UnknownException)
+
+       /* On the MPC8xx, this is a software emulation interrupt.  It occurs
+        * for all unimplemented and illegal instructions.
+        */
+       STD_EXCEPTION(0x1000, SoftEmu, SoftEmuException)
+
+       STD_EXCEPTION(0x1100, InstructionTLBMiss, UnknownException)
+       STD_EXCEPTION(0x1200, DataTLBMiss, UnknownException)
+       STD_EXCEPTION(0x1300, InstructionTLBError, UnknownException)
+       STD_EXCEPTION(0x1400, DataTLBError, UnknownException)
+
+       STD_EXCEPTION(0x1500, Reserved5, UnknownException)
+       STD_EXCEPTION(0x1600, Reserved6, UnknownException)
+       STD_EXCEPTION(0x1700, Reserved7, UnknownException)
+       STD_EXCEPTION(0x1800, Reserved8, UnknownException)
+       STD_EXCEPTION(0x1900, Reserved9, UnknownException)
+       STD_EXCEPTION(0x1a00, ReservedA, UnknownException)
+       STD_EXCEPTION(0x1b00, ReservedB, UnknownException)
+
+       STD_EXCEPTION(0x1c00, DataBreakpoint, UnknownException)
+       STD_EXCEPTION(0x1d00, InstructionBreakpoint, UnknownException)
+       STD_EXCEPTION(0x1e00, PeripheralBreakpoint, UnknownException)
+       STD_EXCEPTION(0x1f00, DevPortBreakpoint, UnknownException)
+
+
+       .globl  _end_of_vectors
+_end_of_vectors:
+
+
+       . = 0x2000
+
+/*
+ * This code finishes saving the registers to the exception frame
+ * and jumps to the appropriate handler for the exception.
+ * Register r21 is pointer into trap frame, r1 has new stack pointer.
+ */
+       .globl  transfer_to_handler
+transfer_to_handler:
+       stw     r22,_NIP(r21)
+       lis     r22,MSR_POW@h
+       andc    r23,r23,r22
+       stw     r23,_MSR(r21)
+       SAVE_GPR(7, r21)
+       SAVE_4GPRS(8, r21)
+       SAVE_8GPRS(12, r21)
+       SAVE_8GPRS(24, r21)
+#if 0
+       andi.   r23,r23,MSR_PR
+       mfspr   r23,SPRG3               /* if from user, fix up tss.regs */
+       beq     2f
+       addi    r24,r1,STACK_FRAME_OVERHEAD
+       stw     r24,PT_REGS(r23)
+2:     addi    r2,r23,-TSS             /* set r2 to current */
+       tovirt(r2,r2,r23)
+#endif
+       mflr    r23
+       andi.   r24,r23,0x3f00          /* get vector offset */
+       stw     r24,TRAP(r21)
+       li      r22,0
+       stw     r22,RESULT(r21)
+       mtspr   SPRG2,r22               /* r1 is now kernel sp */
+#if 0
+       addi    r24,r2,TASK_STRUCT_SIZE /* check for kernel stack overflow */
+       cmplw   0,r1,r2
+       cmplw   1,r1,r24
+       crand   1,1,4
+       bgt     stack_ovf               /* if r2 < r1 < r2+TASK_STRUCT_SIZE */
+#endif
+       lwz     r24,0(r23)              /* virtual address of handler */
+       lwz     r23,4(r23)              /* where to go when done */
+       mtspr   SRR0,r24
+       mtspr   SRR1,r20
+       mtlr    r23
+       SYNC
+       rfi                             /* jump to handler, enable MMU */
+
+int_return:
+       mfmsr   r29             /* Disable interrupts */
+       li      r4,0
+       ori     r4,r4,MSR_EE
+       andc    r29,r29,r4
+       SYNC                    /* Some chip revs need this... */
+       mtmsr   r29
+       SYNC
+       lwz     r2,_CTR(r1)
+       lwz     r0,_LINK(r1)
+       mtctr   r2
+       mtlr    r0
+       lwz     r2,_XER(r1)
+       lwz     r0,_CCR(r1)
+       mtspr   XER,r2
+       mtcrf   0xFF,r0
+       REST_10GPRS(3, r1)
+       REST_10GPRS(13, r1)
+       REST_8GPRS(23, r1)
+       REST_GPR(31, r1)
+       lwz     r2,_NIP(r1)     /* Restore environment */
+       lwz     r0,_MSR(r1)
+       mtspr   SRR0,r2
+       mtspr   SRR1,r0
+       lwz     r0,GPR0(r1)
+       lwz     r2,GPR2(r1)
+       lwz     r1,GPR1(r1)
+       SYNC
+       rfi
+
+/* Cache functions.
+*/
+       .globl  icache_enable
+icache_enable:
+       SYNC
+       lis     r3, IDC_INVALL@h
+       mtspr   IC_CST, r3
+       lis     r3, IDC_ENABLE@h
+       mtspr   IC_CST, r3
+       blr
+
+       .globl  icache_disable
+icache_disable:
+       SYNC
+       lis     r3, IDC_DISABLE@h
+       mtspr   IC_CST, r3
+       blr
+
+       .globl  icache_status
+icache_status:
+       mfspr   r3, IC_CST
+       srwi    r3, r3, 31      /* >>31 => select bit 0 */
+       blr
+
+       .globl  dcache_enable
+dcache_enable:
+#if 0
+       SYNC
+#endif
+#if 1
+       lis     r3, 0x0400              /* Set cache mode with MMU off */
+       mtspr   MD_CTR, r3
+#endif
+
+       lis     r3, IDC_INVALL@h
+       mtspr   DC_CST, r3
+#if 0
+       lis     r3, DC_SFWT@h
+       mtspr   DC_CST, r3
+#endif
+       lis     r3, IDC_ENABLE@h
+       mtspr   DC_CST, r3
+       blr
+
+       .globl  dcache_disable
+dcache_disable:
+       SYNC
+       lis     r3, IDC_DISABLE@h
+       mtspr   DC_CST, r3
+       lis     r3, IDC_INVALL@h
+       mtspr   DC_CST, r3
+       blr
+
+       .globl  dcache_status
+dcache_status:
+       mfspr   r3, DC_CST
+       srwi    r3, r3, 31      /* >>31 => select bit 0 */
+       blr
+
+       .globl  dc_read
+dc_read:
+       mtspr   DC_ADR, r3
+       mfspr   r3, DC_DAT
+       blr
+
+/*
+ * Delay for a number of microseconds
+ * -- Use the BUS timer (assumes 50 MHz) -- FIXME --
+ */
+       .globl  udelay
+udelay:
+       mulli   r4,r3,10000     /* 50 MHz / 16 = 3125000 */
+       li      r5,3125
+       divw    r4,r4,r5        /* BUS ticks */
+1:     mftbu   r5
+       mftb    r6
+       mftbu   r7
+       cmp     0,r5,r7
+       bne     1b              /* Get [synced] base time */
+       addc    r9,r6,r4        /* Compute end time */
+       addze   r8,r5
+2:     mftbu   r5
+       cmp     0,r5,r8
+       blt     2b
+       bgt     3f
+       mftb    r6
+       cmp     0,r6,r9
+       blt     2b
+3:     blr
+
+
+/*
+ * unsigned int get_immr (unsigned int mask)
+ *
+ * return (mask ? (IMMR & mask) : IMMR);
+ */
+       .globl  get_immr
+get_immr:
+       mr      r4,r3           /* save mask */
+       mfspr   r3, 638         /* IMMR */
+       cmpwi   0,r4,0          /* mask != 0 ? */
+       beq     4f
+       and     r3,r3,r4        /* IMMR & mask */
+4:
+       blr
+
+       .globl get_pvr
+get_pvr:
+       mfspr   r3, PVR
+       blr
+
+
+       .globl wr_ic_cst
+wr_ic_cst:
+       mtspr   IC_CST, r3
+       blr
+
+       .globl rd_ic_cst
+rd_ic_cst:
+       mfspr   r3, IC_CST
+       blr
+
+       .globl wr_ic_adr
+wr_ic_adr:
+       mtspr   IC_ADR, r3
+       blr
+
+
+       .globl wr_dc_cst
+wr_dc_cst:
+       mtspr   DC_CST, r3
+       blr
+
+       .globl rd_dc_cst
+rd_dc_cst:
+       mfspr   r3, DC_CST
+       blr
+
+       .globl wr_dc_adr
+wr_dc_adr:
+       mtspr   DC_ADR, r3
+       blr
+
+/*------------------------------------------------------------------------------*/
+
+/*
+ * void relocate_code (addr_sp, bd, addr_moni)
+ *
+ * This "function" does not return, instead it continues in RAM
+ * after relocating the monitor code.
+ *
+ * r3 = dest
+ * r4 = src
+ * r5 = length in bytes
+ * r6 = cachelinesize
+ */
+       .globl  relocate_code
+relocate_code:
+       mr      r1,  r3         /* Set new stack pointer                */
+       mr      r9,  r4         /* Save copy of Board Info pointer      */
+       mr      r10, r5         /* Save copy of Destination Address     */
+
+       mr      r3,  r5                         /* Destination Address  */
+       lis     r4, CFG_FLASH_BASE@h            /* Source      Address  */
+       ori     r4, r4, CFG_FLASH_BASE@l
+       lis     r5, CFG_MONITOR_LEN@h           /* Length in Bytes      */
+       ori     r5, r5, CFG_MONITOR_LEN@l
+       li      r6, CFG_CACHELINE_SIZE          /* Cache Line Size      */
+
+       /*
+        * Fix GOT pointer:
+        *
+        * New GOT-PTR = (old GOT-PTR - CFG_FLASH_BASE) + Destination Address
+        *
+        * Offset:
+        */
+       sub     r15, r10, r4
+
+       /* First our own GOT */
+       add     r14, r14, r15
+       /* the the one used by the C code */
+       add     r30, r30, r15
+
+       /*
+        * Now relocate code
+        */
+       
+       cmplw   cr1,r3,r4
+       addi    r0,r5,3
+       srwi.   r0,r0,2
+       beq     cr1,4f          /* In place copy is not necessary       */
+       beq     7f              /* Protect against 0 count              */
+       mtctr   r0
+       bge     cr1,2f
+
+       la      r8,-4(r4)
+       la      r7,-4(r3)
+1:     lwzu    r0,4(r8)
+       stwu    r0,4(r7)
+       bdnz    1b
+       b       4f
+
+2:     slwi    r0,r0,2
+       add     r8,r4,r0
+       add     r7,r3,r0
+3:     lwzu    r0,-4(r8)
+       stwu    r0,-4(r7)
+       bdnz    3b
+
+/*
+ * Now flush the cache: note that we must start from a cache aligned
+ * address. Otherwise we might miss one cache line.
+ */
+4:     cmpwi   r6,0
+       add     r5,r3,r5
+       beq     7f              /* Always flush prefetch queue in any case */
+       subi    r0,r6,1
+       andc    r3,r3,r0
+       mr      r4,r3
+5:     cmplw   r4,r5
+       dcbst   0,r4
+       add     r4,r4,r6
+       blt     5b
+       sync                    /* Wait for all dcbst to complete on bus */
+       mr      r4,r3
+6:     cmplw   r4,r5
+       icbi    0,r4
+       add     r4,r4,r6
+       blt     6b
+7:     sync                    /* Wait for all icbi to complete on bus */
+       isync
+
+/*
+ * We are done. Do not return, instead branch to second part of board
+ * initialization, now running from RAM.
+ */
+
+       addi    r0, r10, in_ram - _start + EXC_OFF_SYS_RESET
+       mtlr    r0
+       blr
+
+in_ram:
+
+       /*
+        * Relocation Function, r14 point to got2+0x8000
+        *
+         * Adjust got2 pointers, no need to check for 0, this code
+         * already puts a few entries in the table.
+        */
+       li      r0,__got2_entries@sectoff@l
+       la      r3,GOT(_GOT2_TABLE_)
+       lwz     r11,GOT(_GOT2_TABLE_)
+       mtctr   r0
+       sub     r11,r3,r11
+       addi    r3,r3,-4
+1:     lwzu    r0,4(r3)
+       add     r0,r0,r11
+       stw     r0,0(r3)
+       bdnz    1b
+       
+       /*
+         * Now adjust the fixups and the pointers to the fixups
+        * in case we need to move ourselves again.
+        */     
+2:     li      r0,__fixup_entries@sectoff@l
+       lwz     r3,GOT(_FIXUP_TABLE_)
+       cmpwi   r0,0
+       mtctr   r0
+       addi    r3,r3,-4
+       beq     4f
+3:     lwzu    r4,4(r3)
+       lwzux   r0,r4,r11
+       add     r0,r0,r11
+       stw     r10,0(r3)
+       stw     r0,0(r4)
+       bdnz    3b
+4:
+clear_bss:
+       /*
+        * Now clear BSS segment
+        */
+       lwz     r3,GOT(.bss)
+       lwz     r4,GOT(_end)
+
+       cmplw   0, r3, r4
+       beq     6f
+
+       li      r0, 0
+5:
+       stw     r0, 0(r3)
+       addi    r3, r3, 4
+       cmplw   0, r3, r4
+       bne     5b
+6:
+
+       mr      r3, r9          /* Board Info pointer           */
+       mr      r4, r10         /* Destination Address          */
+       bl      board_init_r
+
+       /* Problems accessing "end" in C, so do it here */
+       .globl  get_endaddr
+get_endaddr:
+       lwz     r3,GOT(_end)
+       blr
+
+       /*
+        * Copy exception vector code to low memory
+        *
+        * r3: dest_addr
+        * r7: source address, r8: end address, r9: target address
+        */
+       .globl  trap_init
+trap_init:
+       lwz     r7, GOT(_start)
+       lwz     r8, GOT(_end_of_vectors)
+
+       rlwinm  r9, r7, 0, 18, 31       /* _start & 0x3FFF      */
+
+       cmplw   0, r7, r8
+       bgelr                           /* return if r7>=r8 - just in case */
+
+       mflr    r4                      /* save link register           */
+1:
+       lwz     r0, 0(r7)
+       stw     r0, 0(r9)
+       addi    r7, r7, 4
+       addi    r9, r9, 4
+       cmplw   0, r7, r8
+       bne     1b
+
+       /*
+        * relocate `hdlr' and `int_return' entries
+        */
+       li      r7, .L_MachineCheck - _start + EXC_OFF_SYS_RESET
+       li      r8, Alignment - _start + EXC_OFF_SYS_RESET
+2:
+       bl      trap_reloc
+       addi    r7, r7, 0x100           /* next exception vector        */
+       cmplw   0, r7, r8
+       blt     2b
+
+       li      r7, .L_Alignment - _start + EXC_OFF_SYS_RESET
+       bl      trap_reloc
+
+       li      r7, .L_ProgramCheck - _start + EXC_OFF_SYS_RESET
+       bl      trap_reloc
+
+       li      r7, .L_FPUnavailable - _start + EXC_OFF_SYS_RESET
+       li      r8, _end_of_vectors - _start + EXC_OFF_SYS_RESET
+3:
+       bl      trap_reloc
+       addi    r7, r7, 0x100           /* next exception vector        */
+       cmplw   0, r7, r8
+       blt     3b
+
+       mtlr    r4                      /* restore link register        */
+       blr
+
+       /*
+        * Function: relocate entries for one exception vector
+        */
+trap_reloc:
+       lwz     r0, 0(r7)               /* hdlr ...                     */
+       add     r0, r0, r3              /*  ... += dest_addr            */
+       stw     r0, 0(r7)
+
+       lwz     r0, 4(r7)               /* int_return ...               */
+       add     r0, r0, r3              /*  ... += dest_addr            */
+       stw     r0, 4(r7)
+
+       blr
diff --git a/mpc8xx/traps.c b/mpc8xx/traps.c
new file mode 100644 (file)
index 0000000..92893fa
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+ * linux/arch/ppc/kernel/traps.c
+ *
+ * Copyright (C) 1995-1996  Gary Thomas (gdt@linuxppc.org)
+ *
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * This file handles the architecture-dependent parts of hardware exceptions
+ */
+
+#include <ppcboot.h>
+
+/* Returns 0 if exception not found and fixup otherwise.  */
+extern unsigned long search_exception_table(unsigned long);
+
+/* THIS NEEDS CHANGING to use the board info structure.
+*/
+#define END_OF_MEM     0x00400000
+
+/*
+ * Trap & Exception support
+ */
+
+void
+print_backtrace(unsigned long *sp)
+{
+       int cnt = 0;
+       unsigned long i;
+
+       printf("Call backtrace: ");
+       while (sp) {
+               if ((uint)sp > END_OF_MEM)
+                       break;
+
+               i = sp[1];
+               if (cnt++ % 7 == 0)
+                       printf("\n");
+               printf("%08lX ", i);
+               if (cnt > 32) break;
+               sp = (unsigned long *)*sp;
+       }
+       printf("\n");
+}
+
+void show_regs(struct pt_regs * regs)
+{
+       int i;
+
+       printf("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx DAR: %08lX\n",
+              regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar);
+       printf("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
+              regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
+              regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
+              regs->msr&MSR_IR ? 1 : 0,
+              regs->msr&MSR_DR ? 1 : 0);
+
+       printf("\n");
+       for (i = 0;  i < 32;  i++) {
+               if ((i % 8) == 0)
+               {
+                       printf("GPR%02d: ", i);
+               }
+
+               printf("%08lX ", regs->gpr[i]);
+               if ((i % 8) == 7)
+               {
+                       printf("\n");
+               }
+       }
+}
+
+
+void
+_exception(int signr, struct pt_regs *regs)
+{
+       show_regs(regs);
+       print_backtrace((unsigned long *)regs->gpr[1]);
+       panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
+}
+
+void
+MachineCheckException(struct pt_regs *regs)
+{
+       unsigned long fixup;
+
+       /* Probing PCI using config cycles cause this exception
+        * when a device is not present.  Catch it and return to
+        * the PCI exception handler.
+        */
+       if ((fixup = search_exception_table(regs->nip)) != 0) {
+               regs->nip = fixup;
+               return;
+       }
+
+       printf("Machine check in kernel mode.\n");
+       printf("Caused by (from msr): ");
+       printf("regs %p ",regs);
+       switch( regs->msr & 0x0000F000)
+       {
+       case (1<<12) :
+               printf("Machine check signal - probably due to mm fault\n"
+                       "with mmu off\n");
+               break;
+       case (1<<13) :
+               printf("Transfer error ack signal\n");
+               break;
+       case (1<<14) :
+               printf("Data parity signal\n");
+               break;
+       case (1<<15) :
+               printf("Address parity signal\n");
+               break;
+       default:
+               printf("Unknown values in msr\n");
+       }
+       show_regs(regs);
+       print_backtrace((unsigned long *)regs->gpr[1]);
+       panic("machine check");
+}
+
+void
+AlignmentException(struct pt_regs *regs)
+{
+       show_regs(regs);
+       print_backtrace((unsigned long *)regs->gpr[1]);
+       panic("Alignment Exception");
+}
+
+void
+ProgramCheckException(struct pt_regs *regs)
+{
+       show_regs(regs);
+       print_backtrace((unsigned long *)regs->gpr[1]);
+       panic("Program Check Exception");
+}
+
+void
+SoftEmuException(struct pt_regs *regs)
+{
+       show_regs(regs);
+       print_backtrace((unsigned long *)regs->gpr[1]);
+       panic("Software Emulation Exception");
+}
+
+
+void
+UnknownException(struct pt_regs *regs)
+{
+       printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
+              regs->nip, regs->msr, regs->trap);
+       _exception(0, regs);
+}
+
+/* Probe an address by reading.  If not present, return -1, otherwise
+ * return 0.
+ */
+int
+addr_probe(uint *addr)
+{
+#if 0
+       int     retval;
+
+       __asm__ __volatile__(                   \
+               "1:     lwz %0,0(%1)\n"         \
+               "       eieio\n"                \
+               "       li %0,0\n"              \
+               "2:\n"                          \
+               ".section .fixup,\"ax\"\n"      \
+               "3:     li %0,-1\n"             \
+               "       b 2b\n"                 \
+               ".section __ex_table,\"a\"\n"   \
+               "       .align 2\n"             \
+               "       .long 1b,3b\n"          \
+               ".text"                         \
+               : "=r" (retval) : "r"(addr));
+
+       return (retval);
+#endif
+       return 0;
+}
diff --git a/ppc/Makefile b/ppc/Makefile
new file mode 100644 (file)
index 0000000..42c45bb
--- /dev/null
@@ -0,0 +1,146 @@
+#
+# (C) Copyright 2000
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+DIR    := $(shell if [ "$$PWD" != "" ]; then echo $$PWD; else pwd; fi)
+NAME   = $(shell basename $(DIR))
+LIB    = lib$(NAME).a
+
+AOBJS  = ppcstring.o
+COBJS  = ctype.o vsprintf.o extable.o string.o \
+         display_options.o zlib.o crc32.o
+OBJS   = $(AOBJS) $(COBJS)
+
+$(LIB):        $(OBJS)
+       $(AR) crv $@ $(OBJS)
+
+clean:
+       rm -f $(OBJS)
+
+distclean:     clean
+       rm -f $(LIB) core *.bak
+
+#########################################################################
+
+depend dep:
+       $(MAKEDEPEND) -- $(CFLAGS) -- $(AOBJS:.o=.S) $(COBJS:.o=.c)
+
+#########################################################################
+
+# DO NOT DELETE
+
+ppcstring.o: /home/wd/ppc/ppcboot/include/ppc_asm.tmpl
+ppcstring.o: /LinuxPPC/CDK/include/asm/errno.h
+ctype.o: /LinuxPPC/CDK/include/linux/ctype.h
+vsprintf.o: /LinuxPPC/CDK/lib/gcc-lib/powerpc-linux/2.95.2/include/stdarg.h
+vsprintf.o: /LinuxPPC/CDK/include/linux/types.h
+vsprintf.o: /LinuxPPC/CDK/include/linux/posix_types.h
+vsprintf.o: /LinuxPPC/CDK/include/linux/stddef.h
+vsprintf.o: /LinuxPPC/CDK/include/asm/posix_types.h
+vsprintf.o: /LinuxPPC/CDK/include/asm/types.h
+vsprintf.o: /LinuxPPC/CDK/include/linux/string.h
+vsprintf.o: /LinuxPPC/CDK/include/asm/string.h
+vsprintf.o: /LinuxPPC/CDK/include/linux/ctype.h
+vsprintf.o: /home/wd/ppc/ppcboot/include/ppcboot.h
+vsprintf.o: /home/wd/ppc/ppcboot/include/config.h
+vsprintf.o: /LinuxPPC/CDK/include/linux/bitops.h
+vsprintf.o: /LinuxPPC/CDK/include/asm/bitops.h
+vsprintf.o: /LinuxPPC/CDK/include/asm/system.h
+vsprintf.o: /LinuxPPC/CDK/include/linux/kdev_t.h
+vsprintf.o: /LinuxPPC/CDK/include/asm/processor.h
+vsprintf.o: /LinuxPPC/CDK/include/linux/config.h
+vsprintf.o: /LinuxPPC/CDK/include/asm/ptrace.h
+vsprintf.o: /LinuxPPC/CDK/include/asm/residual.h
+vsprintf.o: /LinuxPPC/CDK/include/asm/pnp.h
+vsprintf.o: /LinuxPPC/CDK/include/asm/atomic.h
+vsprintf.o: /LinuxPPC/CDK/include/asm/byteorder.h
+vsprintf.o: /LinuxPPC/CDK/include/linux/byteorder/big_endian.h
+vsprintf.o: /LinuxPPC/CDK/include/linux/byteorder/swab.h
+vsprintf.o: /LinuxPPC/CDK/include/linux/byteorder/generic.h
+vsprintf.o: /home/wd/ppc/ppcboot/include/asm/8xx_immap.h
+vsprintf.o: /home/wd/ppc/ppcboot/include/flash.h
+extable.o: /home/wd/ppc/ppcboot/include/ppcboot.h
+extable.o: /home/wd/ppc/ppcboot/include/config.h
+extable.o: /LinuxPPC/CDK/include/linux/bitops.h
+extable.o: /LinuxPPC/CDK/include/asm/bitops.h
+extable.o: /LinuxPPC/CDK/include/asm/system.h
+extable.o: /LinuxPPC/CDK/include/linux/kdev_t.h
+extable.o: /LinuxPPC/CDK/include/asm/processor.h
+extable.o: /LinuxPPC/CDK/include/linux/config.h
+extable.o: /LinuxPPC/CDK/include/asm/ptrace.h
+extable.o: /LinuxPPC/CDK/include/asm/residual.h
+extable.o: /LinuxPPC/CDK/include/asm/pnp.h /LinuxPPC/CDK/include/asm/atomic.h
+extable.o: /LinuxPPC/CDK/include/asm/byteorder.h
+extable.o: /LinuxPPC/CDK/include/asm/types.h
+extable.o: /LinuxPPC/CDK/include/linux/byteorder/big_endian.h
+extable.o: /LinuxPPC/CDK/include/linux/byteorder/swab.h
+extable.o: /LinuxPPC/CDK/include/linux/byteorder/generic.h
+extable.o: /LinuxPPC/CDK/include/linux/types.h
+extable.o: /LinuxPPC/CDK/include/linux/posix_types.h
+extable.o: /LinuxPPC/CDK/include/linux/stddef.h
+extable.o: /LinuxPPC/CDK/include/asm/posix_types.h
+extable.o: /LinuxPPC/CDK/include/linux/string.h
+extable.o: /LinuxPPC/CDK/include/asm/string.h
+extable.o: /home/wd/ppc/ppcboot/include/asm/8xx_immap.h
+extable.o: /home/wd/ppc/ppcboot/include/flash.h
+string.o: /LinuxPPC/CDK/include/linux/types.h
+string.o: /LinuxPPC/CDK/include/linux/posix_types.h
+string.o: /LinuxPPC/CDK/include/linux/stddef.h
+string.o: /LinuxPPC/CDK/include/asm/posix_types.h
+string.o: /LinuxPPC/CDK/include/asm/types.h
+string.o: /LinuxPPC/CDK/include/linux/string.h
+string.o: /LinuxPPC/CDK/include/asm/string.h
+display_options.o: /home/wd/ppc/ppcboot/include/ppcboot.h
+display_options.o: /home/wd/ppc/ppcboot/include/config.h
+display_options.o: /LinuxPPC/CDK/include/linux/bitops.h
+display_options.o: /LinuxPPC/CDK/include/asm/bitops.h
+display_options.o: /LinuxPPC/CDK/include/asm/system.h
+display_options.o: /LinuxPPC/CDK/include/linux/kdev_t.h
+display_options.o: /LinuxPPC/CDK/include/asm/processor.h
+display_options.o: /LinuxPPC/CDK/include/linux/config.h
+display_options.o: /LinuxPPC/CDK/include/asm/ptrace.h
+display_options.o: /LinuxPPC/CDK/include/asm/residual.h
+display_options.o: /LinuxPPC/CDK/include/asm/pnp.h
+display_options.o: /LinuxPPC/CDK/include/asm/atomic.h
+display_options.o: /LinuxPPC/CDK/include/asm/byteorder.h
+display_options.o: /LinuxPPC/CDK/include/asm/types.h
+display_options.o: /LinuxPPC/CDK/include/linux/byteorder/big_endian.h
+display_options.o: /LinuxPPC/CDK/include/linux/byteorder/swab.h
+display_options.o: /LinuxPPC/CDK/include/linux/byteorder/generic.h
+display_options.o: /LinuxPPC/CDK/include/linux/types.h
+display_options.o: /LinuxPPC/CDK/include/linux/posix_types.h
+display_options.o: /LinuxPPC/CDK/include/linux/stddef.h
+display_options.o: /LinuxPPC/CDK/include/asm/posix_types.h
+display_options.o: /LinuxPPC/CDK/include/linux/string.h
+display_options.o: /LinuxPPC/CDK/include/asm/string.h
+display_options.o: /home/wd/ppc/ppcboot/include/asm/8xx_immap.h
+display_options.o: /home/wd/ppc/ppcboot/include/flash.h
+zlib.o: /home/wd/ppc/ppcboot/include/zlib.h
+zlib.o: /LinuxPPC/CDK/include/linux/string.h
+zlib.o: /LinuxPPC/CDK/include/linux/types.h
+zlib.o: /LinuxPPC/CDK/include/linux/posix_types.h
+zlib.o: /LinuxPPC/CDK/include/linux/stddef.h
+zlib.o: /LinuxPPC/CDK/include/asm/posix_types.h
+zlib.o: /LinuxPPC/CDK/include/asm/types.h /LinuxPPC/CDK/include/asm/string.h
+crc32.o: /home/wd/ppc/ppcboot/include/zlib.h
diff --git a/ppc/config.mk b/ppc/config.mk
new file mode 100644 (file)
index 0000000..19d37c9
--- /dev/null
@@ -0,0 +1,24 @@
+#
+# (C) Copyright 2000
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+
diff --git a/ppc/crc32.c b/ppc/crc32.c
new file mode 100644 (file)
index 0000000..5298463
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * This file is derived from crc32.c from the zlib-1.1.3 distribution
+ * by Jean-loup Gailly and Mark Adler.
+ */
+
+/* crc32.c -- compute the CRC-32 of a data stream
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* @(#) $Id: crc32.c,v 1.1 2000/07/18 08:54:27 wd Exp $ */
+
+#include "zlib.h"
+
+#define local static
+#define ZEXPORT        /* empty */
+unsigned long crc32 (unsigned long, const unsigned char *, unsigned int);
+
+#ifdef DYNAMIC_CRC_TABLE
+
+local int crc_table_empty = 1;
+local uLongf crc_table[256];
+local void make_crc_table OF((void));
+
+/*
+  Generate a table for a byte-wise 32-bit CRC calculation on the polynomial:
+  x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.
+
+  Polynomials over GF(2) are represented in binary, one bit per coefficient,
+  with the lowest powers in the most significant bit.  Then adding polynomials
+  is just exclusive-or, and multiplying a polynomial by x is a right shift by
+  one.  If we call the above polynomial p, and represent a byte as the
+  polynomial q, also with the lowest power in the most significant bit (so the
+  byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,
+  where a mod b means the remainder after dividing a by b.
+
+  This calculation is done using the shift-register method of multiplying and
+  taking the remainder.  The register is initialized to zero, and for each
+  incoming bit, x^32 is added mod p to the register if the bit is a one (where
+  x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by
+  x (which is shifting right by one and adding x^32 mod p if the bit shifted
+  out is a one).  We start with the highest power (least significant bit) of
+  q and repeat for all eight bits of q.
+
+  The table is simply the CRC of all possible eight bit values.  This is all
+  the information needed to generate CRC's on data a byte at a time for all
+  combinations of CRC register values and incoming bytes.
+*/
+local void make_crc_table()
+{
+  uLong c;
+  int n, k;
+  uLong poly;            /* polynomial exclusive-or pattern */
+  /* terms of polynomial defining this crc (except x^32): */
+  static const Byte p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
+
+  /* make exclusive-or pattern from polynomial (0xedb88320L) */
+  poly = 0L;
+  for (n = 0; n < sizeof(p)/sizeof(Byte); n++)
+    poly |= 1L << (31 - p[n]);
+  for (n = 0; n < 256; n++)
+  {
+    c = (uLong)n;
+    for (k = 0; k < 8; k++)
+      c = c & 1 ? poly ^ (c >> 1) : c >> 1;
+    crc_table[n] = c;
+  }
+  crc_table_empty = 0;
+}
+#else
+/* ========================================================================
+ * Table of CRC-32's of all single-byte values (made by make_crc_table)
+ */
+local const uLongf crc_table[256] = {
+  0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+  0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+  0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+  0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+  0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+  0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+  0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+  0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+  0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+  0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+  0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+  0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+  0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+  0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+  0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+  0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+  0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+  0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+  0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+  0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+  0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+  0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+  0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+  0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+  0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+  0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+  0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+  0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+  0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+  0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+  0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+  0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+  0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+  0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+  0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+  0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+  0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+  0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+  0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+  0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+  0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+  0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+  0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+  0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+  0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+  0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+  0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+  0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+  0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+  0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+  0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+  0x2d02ef8dL
+};
+#endif
+
+#if 0
+/* =========================================================================
+ * This function can be used by asm versions of crc32()
+ */
+const uLongf * ZEXPORT get_crc_table()
+{
+#ifdef DYNAMIC_CRC_TABLE
+  if (crc_table_empty) make_crc_table();
+#endif
+  return (const uLongf *)crc_table;
+}
+#endif
+
+/* ========================================================================= */
+#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8);
+#define DO2(buf)  DO1(buf); DO1(buf);
+#define DO4(buf)  DO2(buf); DO2(buf);
+#define DO8(buf)  DO4(buf); DO4(buf);
+
+/* ========================================================================= */
+uLong ZEXPORT crc32(crc, buf, len)
+    uLong crc;
+    const Bytef *buf;
+    uInt len;
+{
+    if (buf == Z_NULL) return 0L;
+#ifdef DYNAMIC_CRC_TABLE
+    if (crc_table_empty)
+      make_crc_table();
+#endif
+    crc = crc ^ 0xffffffffL;
+    while (len >= 8)
+    {
+      DO8(buf);
+      len -= 8;
+    }
+    if (len) do {
+      DO1(buf);
+    } while (--len);
+    return crc ^ 0xffffffffL;
+}
diff --git a/ppc/ctype.c b/ppc/ctype.c
new file mode 100644 (file)
index 0000000..6ed0468
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ *  linux/lib/ctype.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+#include <linux/ctype.h>
+
+unsigned char _ctype[] = {
+_C,_C,_C,_C,_C,_C,_C,_C,                       /* 0-7 */
+_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C,                /* 8-15 */
+_C,_C,_C,_C,_C,_C,_C,_C,                       /* 16-23 */
+_C,_C,_C,_C,_C,_C,_C,_C,                       /* 24-31 */
+_S|_SP,_P,_P,_P,_P,_P,_P,_P,                   /* 32-39 */
+_P,_P,_P,_P,_P,_P,_P,_P,                       /* 40-47 */
+_D,_D,_D,_D,_D,_D,_D,_D,                       /* 48-55 */
+_D,_D,_P,_P,_P,_P,_P,_P,                       /* 56-63 */
+_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U,     /* 64-71 */
+_U,_U,_U,_U,_U,_U,_U,_U,                       /* 72-79 */
+_U,_U,_U,_U,_U,_U,_U,_U,                       /* 80-87 */
+_U,_U,_U,_P,_P,_P,_P,_P,                       /* 88-95 */
+_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L,     /* 96-103 */
+_L,_L,_L,_L,_L,_L,_L,_L,                       /* 104-111 */
+_L,_L,_L,_L,_L,_L,_L,_L,                       /* 112-119 */
+_L,_L,_L,_P,_P,_P,_P,_C,                       /* 120-127 */
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,               /* 128-143 */
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,               /* 144-159 */
+_S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,   /* 160-175 */
+_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,       /* 176-191 */
+_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,       /* 192-207 */
+_U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L,       /* 208-223 */
+_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,       /* 224-239 */
+_L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L};      /* 240-255 */
diff --git a/ppc/display_options.c b/ppc/display_options.c
new file mode 100644 (file)
index 0000000..d7ed220
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <ppcboot.h>
+
+void display_options (void)
+{
+       extern char version_string[];
+
+       printf ("\n\n%s\n\n", version_string);
+#if 0  /* XXX - disabled for now - FIXME! */
+       printf ("Compiletime Options: \n");
+
+       printf ("  Board: ");
+
+#if defined(CONFIG_FADS)
+       printf ("FADS");
+#elif defined(CONFIG_ADS)
+       printf ("ADS");
+#elif defined(CONFIG_RPXLITE)
+       printf ("RPXLITE");
+#elif defined(CONFIG_RPXCLASSIC)
+       printf ("RPXCLASSIC");
+#elif defined(CONFIG_BSEIP)
+       printf ("BSEIP");
+#elif defined(CONFIG_MBX)
+       printf ("MBX");
+#elif defined(CONFIG_TQM823L)
+       printf ("TQM823L");
+#elif defined(CONFIG_TQM850L)
+       printf ("TQM850L");
+#elif defined(CONFIG_TQM855L)
+       printf ("TQM855L");
+#elif defined(CONFIG_TQM860L)
+       printf ("TQM860L");
+#elif defined(CONFIG_FPS850L)
+       printf ("FPS850L");
+#elif defined(CONFIG_TQM860)
+       printf ("TQM860");
+#elif defined(CONFIG_WINCEPT)
+       printf ("WINCEPT");
+#else
+#error Board undefined
+#endif
+
+#if defined(CONFIG_DRAM_SPEED)
+       printf (", DRAM %dMHZ ", CONFIG_DRAM_SPEED);
+#else
+#error DRAM speed undefined
+#endif
+       printf ("\n");
+#endif /* XXX */
+}
diff --git a/ppc/extable.c b/ppc/extable.c
new file mode 100644 (file)
index 0000000..91a0e9b
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 1999  Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se>
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#include <ppcboot.h>
+
+/*
+ * The exception table consists of pairs of addresses: the first is the
+ * address of an instruction that is allowed to fault, and the second is
+ * the address at which the program should continue.  No registers are
+ * modified, so it is entirely up to the continuation code to figure out
+ * what to do.
+ *
+ * All the routines below use bits of fixup code that are out of line
+ * with the main instruction path.  This means when everything is well,
+ * we don't even have to jump over them.  Further, they do not intrude
+ * on our cache or tlb entries.
+ */
+
+struct exception_table_entry
+{
+       unsigned long insn, fixup;
+};
+
+extern const struct exception_table_entry __start___ex_table[];
+extern const struct exception_table_entry __stop___ex_table[];
+
+static inline unsigned long
+search_one_table(const struct exception_table_entry *first,
+                const struct exception_table_entry *last,
+                unsigned long value)
+{
+        while (first <= last) {
+               const struct exception_table_entry *mid;
+               long diff;
+
+               mid = (last - first) / 2 + first;
+               diff = mid->insn - value;
+                if (diff == 0)
+                        return mid->fixup;
+                else if (diff < 0)
+                        first = mid+1;
+                else
+                        last = mid-1;
+        }
+        return 0;
+}
+
+int    ex_tab_message;
+
+unsigned long
+search_exception_table(unsigned long addr)
+{
+       unsigned long ret;
+
+       /* There is only the kernel to search.  */
+       ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr);
+       if (ex_tab_message)
+               printf("Bus Fault @ 0x%08lx, fixup 0x%08lx\n", addr, ret);
+       if (ret) return ret;
+
+       return 0;
+}
+
+// vim: ts=4 noexpandtab cino=>4 cindent
diff --git a/ppc/ppcstring.S b/ppc/ppcstring.S
new file mode 100644 (file)
index 0000000..97023a0
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ * String handling functions for PowerPC.
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ *
+ * 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 <ppc_asm.tmpl>
+#include <asm/errno.h>
+
+       .globl  strcpy
+strcpy:
+       addi    r5,r3,-1
+       addi    r4,r4,-1
+1:     lbzu    r0,1(r4)
+       cmpwi   0,r0,0
+       stbu    r0,1(r5)
+       bne     1b
+       blr
+
+       .globl  strncpy
+strncpy:
+       cmpwi   0,r5,0
+       beqlr
+       mtctr   r5
+       addi    r6,r3,-1
+       addi    r4,r4,-1
+1:     lbzu    r0,1(r4)
+       cmpwi   0,r0,0
+       stbu    r0,1(r6)
+       bdnzf   2,1b            /* dec ctr, branch if ctr != 0 && !cr0.eq */
+       blr
+
+       .globl  strcat
+strcat:
+       addi    r5,r3,-1
+       addi    r4,r4,-1
+1:     lbzu    r0,1(r5)
+       cmpwi   0,r0,0
+       bne     1b
+       addi    r5,r5,-1
+1:     lbzu    r0,1(r4)
+       cmpwi   0,r0,0
+       stbu    r0,1(r5)
+       bne     1b
+       blr
+
+       .globl  strcmp
+strcmp:
+       addi    r5,r3,-1
+       addi    r4,r4,-1
+1:     lbzu    r3,1(r5)
+       cmpwi   1,r3,0
+       lbzu    r0,1(r4)
+       subf.   r3,r0,r3
+       beqlr   1
+       beq     1b
+       blr
+
+       .globl  strlen
+strlen:
+       addi    r4,r3,-1
+1:     lbzu    r0,1(r4)
+       cmpwi   0,r0,0
+       bne     1b
+       subf    r3,r3,r4
+       blr
+
+       .globl  memset
+memset:
+       rlwimi  r4,r4,8,16,23
+       rlwimi  r4,r4,16,0,15
+       addi    r6,r3,-4
+       cmplwi  0,r5,4
+       blt     7f
+       stwu    r4,4(r6)
+       beqlr
+       andi.   r0,r6,3
+       add     r5,r0,r5
+       subf    r6,r0,r6
+       rlwinm  r0,r5,32-2,2,31
+       mtctr   r0
+       bdz     6f
+1:     stwu    r4,4(r6)
+       bdnz    1b
+6:     andi.   r5,r5,3
+7:     cmpwi   0,r5,0
+       beqlr
+       mtctr   r5
+       addi    r6,r6,3
+8:     stbu    r4,1(r6)
+       bdnz    8b
+       blr
+
+       .globl  bcopy
+bcopy:
+       mr      r6,r3
+       mr      r3,r4
+       mr      r4,r6
+       b       memcpy
+
+       .globl  memmove
+memmove:
+       cmplw   0,r3,r4
+       bgt     backwards_memcpy
+       /* fall through */
+
+       .globl  memcpy
+memcpy:
+       rlwinm. r7,r5,32-3,3,31         /* r0 = r5 >> 3 */
+       addi    r6,r3,-4
+       addi    r4,r4,-4
+       beq     2f                      /* if less than 8 bytes to do */
+       andi.   r0,r6,3                 /* get dest word aligned */
+       mtctr   r7
+       bne     5f
+1:     lwz     r7,4(r4)
+       lwzu    r8,8(r4)
+       stw     r7,4(r6)
+       stwu    r8,8(r6)
+       bdnz    1b
+       andi.   r5,r5,7
+2:     cmplwi  0,r5,4
+       blt     3f
+       lwzu    r0,4(r4)
+       addi    r5,r5,-4
+       stwu    r0,4(r6)
+3:     cmpwi   0,r5,0
+       beqlr
+       mtctr   r5
+       addi    r4,r4,3
+       addi    r6,r6,3
+4:     lbzu    r0,1(r4)
+       stbu    r0,1(r6)
+       bdnz    4b
+       blr
+5:     subfic  r0,r0,4
+       mtctr   r0
+6:     lbz     r7,4(r4)
+       addi    r4,r4,1
+       stb     r7,4(r6)
+       addi    r6,r6,1
+       bdnz    6b
+       subf    r5,r0,r5
+       rlwinm. r7,r5,32-3,3,31
+       beq     2b
+       mtctr   r7
+       b       1b
+
+       .globl  backwards_memcpy
+backwards_memcpy:
+       rlwinm. r7,r5,32-3,3,31         /* r0 = r5 >> 3 */
+       add     r6,r3,r5
+       add     r4,r4,r5
+       beq     2f
+       andi.   r0,r6,3
+       mtctr   r7
+       bne     5f
+1:     lwz     r7,-4(r4)
+       lwzu    r8,-8(r4)
+       stw     r7,-4(r6)
+       stwu    r8,-8(r6)
+       bdnz    1b
+       andi.   r5,r5,7
+2:     cmplwi  0,r5,4
+       blt     3f
+       lwzu    r0,-4(r4)
+       subi    r5,r5,4
+       stwu    r0,-4(r6)
+3:     cmpwi   0,r5,0
+       beqlr
+       mtctr   r5
+4:     lbzu    r0,-1(r4)
+       stbu    r0,-1(r6)
+       bdnz    4b
+       blr
+5:     mtctr   r0
+6:     lbzu    r7,-1(r4)
+       stbu    r7,-1(r6)
+       bdnz    6b
+       subf    r5,r0,r5
+       rlwinm. r7,r5,32-3,3,31
+       beq     2b
+       mtctr   r7
+       b       1b
+
+       .globl  memcmp
+memcmp:
+       cmpwi   0,r5,0
+       ble-    2f
+       mtctr   r5
+       addi    r6,r3,-1
+       addi    r4,r4,-1
+1:     lbzu    r3,1(r6)
+       lbzu    r0,1(r4)
+       subf.   r3,r0,r3
+       bdnzt   2,1b
+       blr
+2:     li      r3,0
+       blr
+
+       .global memchr
+memchr:
+       cmpwi   0,r5,0
+       ble-    2f
+       mtctr   r5
+       addi    r3,r3,-1
+1:     lbzu    r0,1(r3)
+       cmpw    0,r0,r4
+       bdnzf   2,1b
+       beqlr
+2:     li      r3,0
+       blr
diff --git a/ppc/string.c b/ppc/string.c
new file mode 100644 (file)
index 0000000..2d1b2e6
--- /dev/null
@@ -0,0 +1,324 @@
+/*
+ *  linux/lib/string.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+/*
+ * stupid library routines.. The optimized versions should generally be found
+ * as inline code in <asm-xx/string.h>
+ *
+ * These are buggy as well..
+ */
+
+#include <linux/types.h>
+#include <linux/string.h>
+
+#define __HAVE_ARCH_BCOPY
+#define __HAVE_ARCH_MEMCMP
+#define __HAVE_ARCH_MEMCPY
+#define __HAVE_ARCH_MEMMOVE
+#define __HAVE_ARCH_MEMSET
+#define __HAVE_ARCH_STRCAT
+#define __HAVE_ARCH_STRCMP
+#define __HAVE_ARCH_STRCPY
+#define __HAVE_ARCH_STRLEN
+#define __HAVE_ARCH_STRNCPY
+
+char * ___strtok = NULL;
+
+#ifndef __HAVE_ARCH_STRCPY
+char * strcpy(char * dest,const char *src)
+{
+       char *tmp = dest;
+
+       while ((*dest++ = *src++) != '\0')
+               /* nothing */;
+       return tmp;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRNCPY
+char * strncpy(char * dest,const char *src,size_t count)
+{
+       char *tmp = dest;
+
+       while (count-- && (*dest++ = *src++) != '\0')
+               /* nothing */;
+
+       return tmp;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRCAT
+char * strcat(char * dest, const char * src)
+{
+       char *tmp = dest;
+
+       while (*dest)
+               dest++;
+       while ((*dest++ = *src++) != '\0')
+               ;
+
+       return tmp;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRNCAT
+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;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRCMP
+int strcmp(const char * cs,const char * ct)
+{
+       register signed char __res;
+
+       while (1) {
+               if ((__res = *cs - *ct++) != 0 || !*cs++)
+                       break;
+       }
+
+       return __res;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRNCMP
+int strncmp(const char * cs,const char * ct,size_t count)
+{
+       register signed char __res = 0;
+
+       while (count) {
+               if ((__res = *cs - *ct++) != 0 || !*cs++)
+                       break;
+               count--;
+       }
+
+       return __res;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRCHR
+char * strchr(const char * s, int c)
+{
+       for(; *s != (char) c; ++s)
+               if (*s == '\0')
+                       return NULL;
+       return (char *) s;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRRCHR
+char * strrchr(const char * s, int c)
+{
+       const char *p = s + strlen(s);
+       do {
+           if (*p == (char)c)
+               return (char *)p;
+       } while (--p >= s);
+       return NULL;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRLEN
+size_t strlen(const char * s)
+{
+       const char *sc;
+
+       for (sc = s; *sc != '\0'; ++sc)
+               /* nothing */;
+       return sc - s;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRNLEN
+size_t strnlen(const char * s, size_t count)
+{
+       const char *sc;
+
+       for (sc = s; count-- && *sc != '\0'; ++sc)
+               /* nothing */;
+       return sc - s;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRSPN
+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;
+               ++count;
+       }
+
+       return count;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRPBRK
+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;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRTOK
+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);
+}
+#endif
+
+#ifndef __HAVE_ARCH_MEMSET
+void * memset(void * s,char c,size_t count)
+{
+       char *xs = (char *) s;
+
+       while (count--)
+               *xs++ = c;
+
+       return s;
+}
+#endif
+
+#ifndef __HAVE_ARCH_BCOPY
+char * bcopy(const char * src, char * dest, int count)
+{
+       char *tmp = dest;
+
+       while (count--)
+               *tmp++ = *src++;
+
+       return dest;
+}
+#endif
+
+#ifndef __HAVE_ARCH_MEMCPY
+void * memcpy(void * dest,const void *src,size_t count)
+{
+       char *tmp = (char *) dest, *s = (char *) src;
+
+       while (count--)
+               *tmp++ = *s++;
+
+       return dest;
+}
+#endif
+
+#ifndef __HAVE_ARCH_MEMMOVE
+void * memmove(void * dest,const void *src,size_t count)
+{
+       char *tmp, *s;
+
+       if (dest <= src) {
+               tmp = (char *) dest;
+               s = (char *) src;
+               while (count--)
+                       *tmp++ = *s++;
+               }
+       else {
+               tmp = (char *) dest + count;
+               s = (char *) src + count;
+               while (count--)
+                       *--tmp = *--s;
+               }
+
+       return dest;
+}
+#endif
+
+#ifndef __HAVE_ARCH_MEMCMP
+int memcmp(const void * cs,const void * ct,size_t count)
+{
+       const unsigned char *su1, *su2;
+       signed char res = 0;
+
+       for( su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
+               if ((res = *su1 - *su2) != 0)
+                       break;
+       return res;
+}
+#endif
+
+/*
+ * find the first occurrence of byte 'c', or 1 past the area if none
+ */
+#ifndef __HAVE_ARCH_MEMSCAN
+void * memscan(void * addr, int c, size_t size)
+{
+       unsigned char * p = (unsigned char *) addr;
+
+       while (size) {
+               if (*p == c)
+                       return (void *) p;
+               p++;
+               size--;
+       }
+       return (void *) p;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRSTR
+char * strstr(const char * s1,const char * s2)
+{
+       int l1, l2;
+
+       l2 = strlen(s2);
+       if (!l2)
+               return (char *) s1;
+       l1 = strlen(s1);
+       while (l1 >= l2) {
+               l1--;
+               if (!memcmp(s1,s2,l2))
+                       return (char *) s1;
+               s1++;
+       }
+       return NULL;
+}
+#endif
diff --git a/ppc/vsprintf.c b/ppc/vsprintf.c
new file mode 100644 (file)
index 0000000..ce5d34b
--- /dev/null
@@ -0,0 +1,399 @@
+/*
+ *  linux/lib/vsprintf.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
+/*
+ * Wirzenius wrote this portably, Torvalds fucked it up :-)
+ */
+
+#include <stdarg.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+
+#include <ppcboot.h>
+
+unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
+{
+       unsigned long result = 0,value;
+
+       if (!base) {
+               base = 10;
+               if (*cp == '0') {
+                       base = 8;
+                       cp++;
+                       if ((*cp == 'x') && isxdigit(cp[1])) {
+                               cp++;
+                               base = 16;
+                       }
+               }
+       }
+       while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
+           ? toupper(*cp) : *cp)-'A'+10) < base) {
+               result = result*base + value;
+               cp++;
+       }
+       if (endp)
+               *endp = (char *)cp;
+       return result;
+}
+
+long simple_strtol(const char *cp,char **endp,unsigned int base)
+{
+       if(*cp=='-')
+               return -simple_strtoul(cp+1,endp,base);
+       return simple_strtoul(cp,endp,base);
+}
+
+/* we use this so that we can do without the ctype library */
+#define is_digit(c)    ((c) >= '0' && (c) <= '9')
+
+static int skip_atoi(const char **s)
+{
+       int i=0;
+
+       while (is_digit(**s))
+               i = i*10 + *((*s)++) - '0';
+       return i;
+}
+
+#define ZEROPAD        1               /* pad with zero */
+#define SIGN   2               /* unsigned/signed long */
+#define PLUS   4               /* show plus */
+#define SPACE  8               /* space if plus */
+#define LEFT   16              /* left justified */
+#define SPECIAL        32              /* 0x */
+#define LARGE  64              /* use 'ABCDEF' instead of 'abcdef' */
+
+#define do_div(n,base) ({ \
+int __res; \
+__res = ((unsigned long) n) % (unsigned) base; \
+n = ((unsigned long) n) / (unsigned) base; \
+__res; })
+
+static char * number(char * str, long num, int base, int size, int precision
+       ,int type)
+{
+       char c,sign,tmp[66];
+       const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
+       int i;
+
+       if (type & LARGE)
+               digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+       if (type & LEFT)
+               type &= ~ZEROPAD;
+       if (base < 2 || base > 36)
+               return 0;
+       c = (type & ZEROPAD) ? '0' : ' ';
+       sign = 0;
+       if (type & SIGN) {
+               if (num < 0) {
+                       sign = '-';
+                       num = -num;
+                       size--;
+               } else if (type & PLUS) {
+                       sign = '+';
+                       size--;
+               } else if (type & SPACE) {
+                       sign = ' ';
+                       size--;
+               }
+       }
+       if (type & SPECIAL) {
+               if (base == 16)
+                       size -= 2;
+               else if (base == 8)
+                       size--;
+       }
+       i = 0;
+       if (num == 0)
+               tmp[i++]='0';
+       else while (num != 0)
+               tmp[i++] = digits[do_div(num,base)];
+       if (i > precision)
+               precision = i;
+       size -= precision;
+       if (!(type&(ZEROPAD+LEFT)))
+               while(size-->0)
+                       *str++ = ' ';
+       if (sign)
+               *str++ = sign;
+       if (type & SPECIAL) {
+               if (base==8)
+                       *str++ = '0';
+               else if (base==16) {
+                       *str++ = '0';
+                       *str++ = digits[33];
+               }
+       }
+       if (!(type & LEFT))
+               while (size-- > 0)
+                       *str++ = c;
+       while (i < precision--)
+               *str++ = '0';
+       while (i-- > 0)
+               *str++ = tmp[i];
+       while (size-- > 0)
+               *str++ = ' ';
+       return str;
+}
+
+/* Forward decl. needed for IP address printing stuff... */
+int sprintf(char * buf, const char *fmt, ...);
+
+int vsprintf(char *buf, const char *fmt, va_list args)
+{
+       int len;
+       unsigned long num;
+       int i, base;
+       char * str;
+       const char *s;
+
+       int flags;              /* flags to number() */
+
+       int field_width;        /* width of output field */
+       int precision;          /* min. # of digits for integers; max
+                                  number of chars for from string */
+       int qualifier;          /* 'h', 'l', or 'L' for integer fields */
+
+       for (str=buf ; *fmt ; ++fmt) {
+               if (*fmt != '%') {
+                       *str++ = *fmt;
+                       continue;
+               }
+
+               /* process flags */
+               flags = 0;
+               repeat:
+                       ++fmt;          /* this also skips first '%' */
+                       switch (*fmt) {
+                               case '-': flags |= LEFT; goto repeat;
+                               case '+': flags |= PLUS; goto repeat;
+                               case ' ': flags |= SPACE; goto repeat;
+                               case '#': flags |= SPECIAL; goto repeat;
+                               case '0': flags |= ZEROPAD; goto repeat;
+                               }
+
+               /* get field width */
+               field_width = -1;
+               if (is_digit(*fmt))
+                       field_width = skip_atoi(&fmt);
+               else if (*fmt == '*') {
+                       ++fmt;
+                       /* it's the next argument */
+                       field_width = va_arg(args, int);
+                       if (field_width < 0) {
+                               field_width = -field_width;
+                               flags |= LEFT;
+                       }
+               }
+
+               /* get the precision */
+               precision = -1;
+               if (*fmt == '.') {
+                       ++fmt;
+                       if (is_digit(*fmt))
+                               precision = skip_atoi(&fmt);
+                       else if (*fmt == '*') {
+                               ++fmt;
+                               /* it's the next argument */
+                               precision = va_arg(args, int);
+                       }
+                       if (precision < 0)
+                               precision = 0;
+               }
+
+               /* get the conversion qualifier */
+               qualifier = -1;
+               if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
+                       qualifier = *fmt;
+                       ++fmt;
+               }
+
+               /* default base */
+               base = 10;
+
+               switch (*fmt) {
+               case 'c':
+                       if (!(flags & LEFT))
+                               while (--field_width > 0)
+                                       *str++ = ' ';
+                       *str++ = (unsigned char) va_arg(args, int);
+                       while (--field_width > 0)
+                               *str++ = ' ';
+                       continue;
+
+               case 's':
+                       s = va_arg(args, char *);
+                       if (!s)
+                               s = "<NULL>";
+
+                       len = strnlen(s, precision);
+
+                       if (!(flags & LEFT))
+                               while (len < field_width--)
+                                       *str++ = ' ';
+                       for (i = 0; i < len; ++i)
+                               *str++ = *s++;
+                       while (len < field_width--)
+                               *str++ = ' ';
+                       continue;
+
+               case 'p':
+                       if (field_width == -1) {
+                               field_width = 2*sizeof(void *);
+                               flags |= ZEROPAD;
+                       }
+                       str = number(str,
+                               (unsigned long) va_arg(args, void *), 16,
+                               field_width, precision, flags);
+                       continue;
+
+
+               case 'n':
+                       if (qualifier == 'l') {
+                               long * ip = va_arg(args, long *);
+                               *ip = (str - buf);
+                       } else {
+                               int * ip = va_arg(args, int *);
+                               *ip = (str - buf);
+                       }
+                       continue;
+
+               case '%':
+                       *str++ = '%';
+                       continue;
+
+               /* integer number formats - set up the flags and "break" */
+               case 'o':
+                       base = 8;
+                       break;
+
+               case 'X':
+                       flags |= LARGE;
+               case 'x':
+                       base = 16;
+                       break;
+
+               case 'd':
+               case 'i':
+                       flags |= SIGN;
+               case 'u':
+                       break;
+
+               default:
+                       *str++ = '%';
+                       if (*fmt)
+                               *str++ = *fmt;
+                       else
+                               --fmt;
+                       continue;
+               }
+               if (qualifier == 'l')
+                       num = va_arg(args, unsigned long);
+               else if (qualifier == 'h') {
+                       num = (unsigned short) va_arg(args, int);
+                       if (flags & SIGN)
+                               num = (short) num;
+               } else if (flags & SIGN)
+                       num = va_arg(args, int);
+               else
+                       num = va_arg(args, unsigned int);
+               str = number(str, num, base, field_width, precision, flags);
+       }
+       *str = '\0';
+       return str-buf;
+}
+
+int sprintf(char * buf, const char *fmt, ...)
+{
+       va_list args;
+       int i;
+
+       va_start(args, fmt);
+       i=vsprintf(buf,fmt,args);
+       va_end(args);
+       return i;
+}
+
+// static      char    printbuffer[256];
+
+/* damm:
+ * i've put the printbuffer on the stack - good for printouts without dram */
+
+void printf(const char *fmt, ...)
+{
+       va_list args;
+       uint    i;
+       char    printbuffer[CFG_PBSIZE]; // damm, wd
+       char    *cp;
+       extern  void serial_putc (const char);
+
+       va_start(args, fmt);
+
+       /* For this to work, printbuffer must be larger than
+        * anything we ever want to print.
+        */
+       i = vsprintf(printbuffer, fmt, args);
+       va_end(args);
+
+       cp = printbuffer;
+       while (i-- > 0) {
+               serial_putc(*cp);
+               cp++;
+       }
+}
+
+/* Convert an ascii string to a hex number.
+*/
+static char    *hexdigits = "0123456789abcdefABCDEF";
+
+uint
+asc_to_hex(char *cp, ulong *val)
+{
+       char    *lp;
+       uint    loc, hexval, cnvbytes;
+
+       /* If the first two characters are "0x", skip them.
+       */
+       if ((*cp == '0') && (*(cp + 1) == 'x'))
+               cp += 2;
+
+       hexval = cnvbytes = 0;
+       while (*cp != 0) {
+               lp = strchr(hexdigits, *cp);
+               if (lp != NULL) {
+                       /* Found a character we can convert.
+                       */
+                       hexval *= 16;
+                       loc = lp - hexdigits;
+                       if (loc > 15)           /* Accomodate upper case */
+                               loc -= 6;
+                       hexval += loc;
+               }
+               else {
+                       /* Found something we can't convert.  We are done.
+                       */
+                       *val = hexval;
+                       return cnvbytes;
+               }
+               cnvbytes++;
+               cp++;
+       }
+       *val = hexval;
+       return cnvbytes;
+}
+
+void panic(const char *fmt, ...)
+{
+       va_list args;
+       va_start(args, fmt);
+       printf(fmt);
+       va_end(args);
+
+       /* Hang */
+       for(;;);
+}
diff --git a/ppc/zlib.c b/ppc/zlib.c
new file mode 100644 (file)
index 0000000..fedd9dc
--- /dev/null
@@ -0,0 +1,2150 @@
+/*
+ * This file is derived from various .h and .c files from the zlib-0.95
+ * distribution by Jean-loup Gailly and Mark Adler, with some additions
+ * by Paul Mackerras to aid in implementing Deflate compression and
+ * decompression for PPP packets.  See zlib.h for conditions of
+ * distribution and use.
+ *
+ * Changes that have been made include:
+ * - changed functions not used outside this file to "local"
+ * - added minCompression parameter to deflateInit2
+ * - added Z_PACKET_FLUSH (see zlib.h for details)
+ * - added inflateIncomp
+ *
+ * $Id: zlib.c,v 1.1 2000/07/18 08:54:27 wd Exp $
+ */
+
+/*+++++*/
+/* zutil.h -- internal interface and configuration of the compression library
+ * Copyright (C) 1995 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* From: zutil.h,v 1.9 1995/05/03 17:27:12 jloup Exp */
+
+#define _Z_UTIL_H
+
+#include "zlib.h"
+
+#ifndef local
+#  define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+#define FAR
+
+typedef unsigned char  uch;
+typedef uch FAR uchf;
+typedef unsigned short ush;
+typedef ush FAR ushf;
+typedef unsigned long  ulg;
+
+extern char *z_errmsg[]; /* indexed by 1-zlib_error */
+
+#define ERR_RETURN(strm,err) return (strm->msg=z_errmsg[1-err], err)
+/* To be used only when the state is known to be valid */
+
+#ifndef NULL
+#define NULL   ((void *) 0)
+#endif
+
+        /* common constants */
+
+#define DEFLATED   8
+
+#ifndef DEF_WBITS
+#  define DEF_WBITS MAX_WBITS
+#endif
+/* default windowBits for decompression. MAX_WBITS is for compression only */
+
+#if MAX_MEM_LEVEL >= 8
+#  define DEF_MEM_LEVEL 8
+#else
+#  define DEF_MEM_LEVEL  MAX_MEM_LEVEL
+#endif
+/* default memLevel */
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES    2
+/* The three kinds of block type */
+
+#define MIN_MATCH  3
+#define MAX_MATCH  258
+/* The minimum and maximum match lengths */
+
+         /* functions */
+
+#include <linux/string.h>
+#define zmemcpy memcpy
+#define zmemzero(dest, len)    memset(dest, 0, len)
+
+/* Diagnostic functions */
+#ifdef DEBUG_ZLIB
+#  include <stdio.h>
+#  ifndef verbose
+#    define verbose 0
+#  endif
+#  define Assert(cond,msg) {if(!(cond)) z_error(msg);}
+#  define Trace(x) fprintf x
+#  define Tracev(x) {if (verbose) fprintf x ;}
+#  define Tracevv(x) {if (verbose>1) fprintf x ;}
+#  define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
+#  define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
+#else
+#  define Assert(cond,msg)
+#  define Trace(x)
+#  define Tracev(x)
+#  define Tracevv(x)
+#  define Tracec(c,x)
+#  define Tracecv(c,x)
+#endif
+
+
+typedef uLong (*check_func) OF((uLong check, Bytef *buf, uInt len));
+
+/* voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); */
+/* void   zcfree  OF((voidpf opaque, voidpf ptr)); */
+
+#define ZALLOC(strm, items, size) \
+           (*((strm)->zalloc))((strm)->opaque, (items), (size))
+#define ZFREE(strm, addr, size)        \
+          (*((strm)->zfree))((strm)->opaque, (voidpf)(addr), (size))
+#define TRY_FREE(s, p, n) {if (p) ZFREE(s, p, n);}
+
+/* deflate.h -- internal compression state
+ * Copyright (C) 1995 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/*+++++*/
+/* infblock.h -- header to use infblock.c
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+struct inflate_blocks_state;
+typedef struct inflate_blocks_state FAR inflate_blocks_statef;
+
+local inflate_blocks_statef * inflate_blocks_new OF((
+    z_stream *z,
+    check_func c,               /* check function */
+    uInt w));                   /* window size */
+
+local int inflate_blocks OF((
+    inflate_blocks_statef *,
+    z_stream *,
+    int));                      /* initial return code */
+
+local void inflate_blocks_reset OF((
+    inflate_blocks_statef *,
+    z_stream *,
+    uLongf *));                  /* check value on output */
+
+local int inflate_blocks_free OF((
+    inflate_blocks_statef *,
+    z_stream *,
+    uLongf *));                  /* check value on output */
+
+local int inflate_addhistory OF((
+    inflate_blocks_statef *,
+    z_stream *));
+
+local int inflate_packet_flush OF((
+    inflate_blocks_statef *));
+
+/*+++++*/
+/* inftrees.h -- header to use inftrees.c
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* Huffman code lookup table entry--this entry is four bytes for machines
+   that have 16-bit pointers (e.g. PC's in the small or medium model). */
+
+typedef struct inflate_huft_s FAR inflate_huft;
+
+struct inflate_huft_s {
+  union {
+    struct {
+      Byte Exop;        /* number of extra bits or operation */
+      Byte Bits;        /* number of bits in this code or subcode */
+    } what;
+    uInt Nalloc;       /* number of these allocated here */
+    Bytef *pad;         /* pad structure to a power of 2 (4 bytes for */
+  } word;               /*  16-bit, 8 bytes for 32-bit machines) */
+  union {
+    uInt Base;          /* literal, length base, or distance base */
+    inflate_huft *Next; /* pointer to next level of table */
+  } more;
+};
+
+#ifdef DEBUG_ZLIB
+  local uInt inflate_hufts;
+#endif
+
+local int inflate_trees_bits OF((
+    uIntf *,                    /* 19 code lengths */
+    uIntf *,                    /* bits tree desired/actual depth */
+    inflate_huft * FAR *,       /* bits tree result */
+    z_stream *));               /* for zalloc, zfree functions */
+
+local int inflate_trees_dynamic OF((
+    uInt,                       /* number of literal/length codes */
+    uInt,                       /* number of distance codes */
+    uIntf *,                    /* that many (total) code lengths */
+    uIntf *,                    /* literal desired/actual bit depth */
+    uIntf *,                    /* distance desired/actual bit depth */
+    inflate_huft * FAR *,       /* literal/length tree result */
+    inflate_huft * FAR *,       /* distance tree result */
+    z_stream *));               /* for zalloc, zfree functions */
+
+local int inflate_trees_fixed OF((
+    uIntf *,                    /* literal desired/actual bit depth */
+    uIntf *,                    /* distance desired/actual bit depth */
+    inflate_huft * FAR *,       /* literal/length tree result */
+    inflate_huft * FAR *));     /* distance tree result */
+
+local int inflate_trees_free OF((
+    inflate_huft *,             /* tables to free */
+    z_stream *));               /* for zfree function */
+
+
+/*+++++*/
+/* infcodes.h -- header to use infcodes.c
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+struct inflate_codes_state;
+typedef struct inflate_codes_state FAR inflate_codes_statef;
+
+local inflate_codes_statef *inflate_codes_new OF((
+    uInt, uInt,
+    inflate_huft *, inflate_huft *,
+    z_stream *));
+
+local int inflate_codes OF((
+    inflate_blocks_statef *,
+    z_stream *,
+    int));
+
+local void inflate_codes_free OF((
+    inflate_codes_statef *,
+    z_stream *));
+
+
+/*+++++*/
+/* inflate.c -- zlib interface to inflate modules
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* inflate private state */
+struct internal_state {
+
+  /* mode */
+  enum {
+      METHOD,   /* waiting for method byte */
+      FLAG,     /* waiting for flag byte */
+      BLOCKS,   /* decompressing blocks */
+      CHECK4,   /* four check bytes to go */
+      CHECK3,   /* three check bytes to go */
+      CHECK2,   /* two check bytes to go */
+      CHECK1,   /* one check byte to go */
+      DONE,     /* finished check, done */
+      BAD}      /* got an error--stay here */
+    mode;               /* current inflate mode */
+
+  /* mode dependent information */
+  union {
+    uInt method;        /* if FLAGS, method byte */
+    struct {
+      uLong was;                /* computed check value */
+      uLong need;               /* stream check value */
+    } check;            /* if CHECK, check values to compare */
+    uInt marker;        /* if BAD, inflateSync's marker bytes count */
+  } sub;        /* submode */
+
+  /* mode independent information */
+  int  nowrap;          /* flag for no wrapper */
+  uInt wbits;           /* log2(window size)  (8..15, defaults to 15) */
+  inflate_blocks_statef 
+    *blocks;            /* current inflate_blocks state */
+
+};
+
+
+int inflateReset(z)
+z_stream *z;
+{
+  uLong c;
+
+  if (z == Z_NULL || z->state == Z_NULL)
+    return Z_STREAM_ERROR;
+  z->total_in = z->total_out = 0;
+  z->msg = Z_NULL;
+  z->state->mode = z->state->nowrap ? BLOCKS : METHOD;
+  inflate_blocks_reset(z->state->blocks, z, &c);
+  Trace((stderr, "inflate: reset\n"));
+  return Z_OK;
+}
+
+
+int inflateEnd(z)
+z_stream *z;
+{
+  uLong c;
+
+  if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL)
+    return Z_STREAM_ERROR;
+  if (z->state->blocks != Z_NULL)
+    inflate_blocks_free(z->state->blocks, z, &c);
+  ZFREE(z, z->state, sizeof(struct internal_state));
+  z->state = Z_NULL;
+  Trace((stderr, "inflate: end\n"));
+  return Z_OK;
+}
+
+
+int inflateInit2(z, w)
+z_stream *z;
+int w;
+{
+  /* initialize state */
+  if (z == Z_NULL)
+    return Z_STREAM_ERROR;
+/*  if (z->zalloc == Z_NULL) z->zalloc = zcalloc; */
+/*  if (z->zfree == Z_NULL) z->zfree = zcfree; */
+  if ((z->state = (struct internal_state FAR *)
+       ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL)
+    return Z_MEM_ERROR;
+  z->state->blocks = Z_NULL;
+
+  /* handle undocumented nowrap option (no zlib header or check) */
+  z->state->nowrap = 0;
+  if (w < 0)
+  {
+    w = - w;
+    z->state->nowrap = 1;
+  }
+
+  /* set window size */
+  if (w < 8 || w > 15)
+  {
+    inflateEnd(z);
+    return Z_STREAM_ERROR;
+  }
+  z->state->wbits = (uInt)w;
+
+  /* create inflate_blocks state */
+  if ((z->state->blocks =
+       inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, 1 << w))
+      == Z_NULL)
+  {
+    inflateEnd(z);
+    return Z_MEM_ERROR;
+  }
+  Trace((stderr, "inflate: allocated\n"));
+
+  /* reset state */
+  inflateReset(z);
+  return Z_OK;
+}
+
+
+int inflateInit(z)
+z_stream *z;
+{
+  return inflateInit2(z, DEF_WBITS);
+}
+
+
+#define NEEDBYTE {if(z->avail_in==0)goto empty;r=Z_OK;}
+#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++)
+
+int inflate(z, f)
+z_stream *z;
+int f;
+{
+  int r;
+  uInt b;
+
+  if (z == Z_NULL || z->next_in == Z_NULL)
+    return Z_STREAM_ERROR;
+  r = Z_BUF_ERROR;
+  while (1) switch (z->state->mode)
+  {
+    case METHOD:
+      NEEDBYTE
+      if (((z->state->sub.method = NEXTBYTE) & 0xf) != DEFLATED)
+      {
+        z->state->mode = BAD;
+        z->msg = "unknown compression method";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      if ((z->state->sub.method >> 4) + 8 > z->state->wbits)
+      {
+        z->state->mode = BAD;
+        z->msg = "invalid window size";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      z->state->mode = FLAG;
+    case FLAG:
+      NEEDBYTE
+      if ((b = NEXTBYTE) & 0x20)
+      {
+        z->state->mode = BAD;
+        z->msg = "invalid reserved bit";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      if (((z->state->sub.method << 8) + b) % 31)
+      {
+        z->state->mode = BAD;
+        z->msg = "incorrect header check";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      Trace((stderr, "inflate: zlib header ok\n"));
+      z->state->mode = BLOCKS;
+    case BLOCKS:
+      r = inflate_blocks(z->state->blocks, z, r);
+      if (f == Z_PACKET_FLUSH && z->avail_in == 0 && z->avail_out != 0)
+         r = inflate_packet_flush(z->state->blocks);
+      if (r == Z_DATA_ERROR)
+      {
+        z->state->mode = BAD;
+        z->state->sub.marker = 0;       /* can try inflateSync */
+        break;
+      }
+      if (r != Z_STREAM_END)
+        return r;
+      r = Z_OK;
+      inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was);
+      if (z->state->nowrap)
+      {
+        z->state->mode = DONE;
+        break;
+      }
+      z->state->mode = CHECK4;
+    case CHECK4:
+      NEEDBYTE
+      z->state->sub.check.need = (uLong)NEXTBYTE << 24;
+      z->state->mode = CHECK3;
+    case CHECK3:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE << 16;
+      z->state->mode = CHECK2;
+    case CHECK2:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE << 8;
+      z->state->mode = CHECK1;
+    case CHECK1:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE;
+
+      if (z->state->sub.check.was != z->state->sub.check.need)
+      {
+        z->state->mode = BAD;
+        z->msg = "incorrect data check";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      Trace((stderr, "inflate: zlib check ok\n"));
+      z->state->mode = DONE;
+    case DONE:
+      return Z_STREAM_END;
+    case BAD:
+      return Z_DATA_ERROR;
+    default:
+      return Z_STREAM_ERROR;
+  }
+
+ empty:
+  if (f != Z_PACKET_FLUSH)
+    return r;
+  z->state->mode = BAD;
+  z->state->sub.marker = 0;       /* can try inflateSync */
+  return Z_DATA_ERROR;
+}
+
+/*
+ * This subroutine adds the data at next_in/avail_in to the output history
+ * without performing any output.  The output buffer must be "caught up";
+ * i.e. no pending output (hence s->read equals s->write), and the state must
+ * be BLOCKS (i.e. we should be willing to see the start of a series of
+ * BLOCKS).  On exit, the output will also be caught up, and the checksum
+ * will have been updated if need be.
+ */
+
+int inflateIncomp(z)
+z_stream *z;
+{
+    if (z->state->mode != BLOCKS)
+       return Z_DATA_ERROR;
+    return inflate_addhistory(z->state->blocks, z);
+}
+
+
+int inflateSync(z)
+z_stream *z;
+{
+  uInt n;       /* number of bytes to look at */
+  Bytef *p;     /* pointer to bytes */
+  uInt m;       /* number of marker bytes found in a row */
+  uLong r, w;   /* temporaries to save total_in and total_out */
+
+  /* set up */
+  if (z == Z_NULL || z->state == Z_NULL)
+    return Z_STREAM_ERROR;
+  if (z->state->mode != BAD)
+  {
+    z->state->mode = BAD;
+    z->state->sub.marker = 0;
+  }
+  if ((n = z->avail_in) == 0)
+    return Z_BUF_ERROR;
+  p = z->next_in;
+  m = z->state->sub.marker;
+
+  /* search */
+  while (n && m < 4)
+  {
+    if (*p == (Byte)(m < 2 ? 0 : 0xff))
+      m++;
+    else if (*p)
+      m = 0;
+    else
+      m = 4 - m;
+    p++, n--;
+  }
+
+  /* restore */
+  z->total_in += p - z->next_in;
+  z->next_in = p;
+  z->avail_in = n;
+  z->state->sub.marker = m;
+
+  /* return no joy or set up to restart on a new block */
+  if (m != 4)
+    return Z_DATA_ERROR;
+  r = z->total_in;  w = z->total_out;
+  inflateReset(z);
+  z->total_in = r;  z->total_out = w;
+  z->state->mode = BLOCKS;
+  return Z_OK;
+}
+
+#undef NEEDBYTE
+#undef NEXTBYTE
+
+/*+++++*/
+/* infutil.h -- types and macros common to blocks and codes
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* inflate blocks semi-private state */
+struct inflate_blocks_state {
+
+  /* mode */
+  enum {
+      TYPE,     /* get type bits (3, including end bit) */
+      LENS,     /* get lengths for stored */
+      STORED,   /* processing stored block */
+      TABLE,    /* get table lengths */
+      BTREE,    /* get bit lengths tree for a dynamic block */
+      DTREE,    /* get length, distance trees for a dynamic block */
+      CODES,    /* processing fixed or dynamic block */
+      DRY,      /* output remaining window bytes */
+      DONEB,     /* finished last block, done */
+      BADB}      /* got a data error--stuck here */
+    mode;               /* current inflate_block mode */
+
+  /* mode dependent information */
+  union {
+    uInt left;          /* if STORED, bytes left to copy */
+    struct {
+      uInt table;               /* table lengths (14 bits) */
+      uInt index;               /* index into blens (or border) */
+      uIntf *blens;             /* bit lengths of codes */
+      uInt bb;                  /* bit length tree depth */
+      inflate_huft *tb;         /* bit length decoding tree */
+      int nblens;              /* # elements allocated at blens */
+    } trees;            /* if DTREE, decoding info for trees */
+    struct {
+      inflate_huft *tl, *td;    /* trees to free */
+      inflate_codes_statef 
+         *codes;
+    } decode;           /* if CODES, current state */
+  } sub;                /* submode */
+  uInt last;            /* true if this block is the last block */
+
+  /* mode independent information */
+  uInt bitk;            /* bits in bit buffer */
+  uLong bitb;           /* bit buffer */
+  Bytef *window;        /* sliding window */
+  Bytef *end;           /* one byte after sliding window */
+  Bytef *read;          /* window read pointer */
+  Bytef *write;         /* window write pointer */
+  check_func checkfn;   /* check function */
+  uLong check;          /* check on output */
+
+};
+
+
+/* defines for inflate input/output */
+/*   update pointers and return */
+#define UPDBITS {s->bitb=b;s->bitk=k;}
+#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;}
+#define UPDOUT {s->write=q;}
+#define UPDATE {UPDBITS UPDIN UPDOUT}
+#define LEAVE {UPDATE return inflate_flush(s,z,r);}
+/*   get bytes and bits */
+#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;}
+#define NEEDBYTE {if(n)r=Z_OK;else LEAVE}
+#define NEXTBYTE (n--,*p++)
+#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<<k;k+=8;}}
+#define DUMPBITS(j) {b>>=(j);k-=(j);}
+/*   output bytes */
+#define WAVAIL (q<s->read?s->read-q-1:s->end-q)
+#define LOADOUT {q=s->write;m=WAVAIL;}
+#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=WAVAIL;}}
+#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT}
+#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;}
+#define OUTBYTE(a) {*q++=(Byte)(a);m--;}
+/*   load local pointers */
+#define LOAD {LOADIN LOADOUT}
+
+/*
+ * The IBM 150 firmware munges the data right after _etext[].  This
+ * protects it. -- Cort
+ */
+#if 0
+local uInt protect_mask[] = {0, 0, 0, 0, 0, 0, 0, 0, 0 ,0 ,0 ,0};
+#endif
+/* And'ing with mask[n] masks the lower n bits */
+local uInt inflate_mask[] = {
+    0x0000,
+    0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
+    0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
+};
+
+/* copy as much as possible from the sliding window to the output area */
+local int inflate_flush OF((
+    inflate_blocks_statef *,
+    z_stream *,
+    int));
+
+/*+++++*/
+/* inffast.h -- header to use inffast.c
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+local int inflate_fast OF((
+    uInt,
+    uInt,
+    inflate_huft *,
+    inflate_huft *,
+    inflate_blocks_statef *,
+    z_stream *));
+
+
+/*+++++*/
+/* infblock.c -- interpret and process block types to last block
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* Table for deflate from PKZIP's appnote.txt. */
+local uInt border[] = { /* Order of the bit length code lengths */
+        16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+/*
+   Notes beyond the 1.93a appnote.txt:
+
+   1. Distance pointers never point before the beginning of the output
+      stream.
+   2. Distance pointers can point back across blocks, up to 32k away.
+   3. There is an implied maximum of 7 bits for the bit length table and
+      15 bits for the actual data.
+   4. If only one code exists, then it is encoded using one bit.  (Zero
+      would be more efficient, but perhaps a little confusing.)  If two
+      codes exist, they are coded using one bit each (0 and 1).
+   5. There is no way of sending zero distance codes--a dummy must be
+      sent if there are none.  (History: a pre 2.0 version of PKZIP would
+      store blocks with no distance codes, but this was discovered to be
+      too harsh a criterion.)  Valid only for 1.93a.  2.04c does allow
+      zero distance codes, which is sent as one code of zero bits in
+      length.
+   6. There are up to 286 literal/length codes.  Code 256 represents the
+      end-of-block.  Note however that the static length tree defines
+      288 codes just to fill out the Huffman codes.  Codes 286 and 287
+      cannot be used though, since there is no length base or extra bits
+      defined for them.  Similarily, there are up to 30 distance codes.
+      However, static trees define 32 codes (all 5 bits) to fill out the
+      Huffman codes, but the last two had better not show up in the data.
+   7. Unzip can check dynamic Huffman blocks for complete code sets.
+      The exception is that a single code would not be complete (see #4).
+   8. The five bits following the block type is really the number of
+      literal codes sent minus 257.
+   9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
+      (1+6+6).  Therefore, to output three times the length, you output
+      three codes (1+1+1), whereas to output four times the same length,
+      you only need two codes (1+3).  Hmm.
+  10. In the tree reconstruction algorithm, Code = Code + Increment
+      only if BitLength(i) is not zero.  (Pretty obvious.)
+  11. Correction: 4 Bits: # of Bit Length codes - 4     (4 - 19)
+  12. Note: length code 284 can represent 227-258, but length code 285
+      really is 258.  The last length deserves its own, short code
+      since it gets used a lot in very redundant files.  The length
+      258 is special since 258 - 3 (the min match length) is 255.
+  13. The literal/length and distance code bit lengths are read as a
+      single stream of lengths.  It is possible (and advantageous) for
+      a repeat code (16, 17, or 18) to go across the boundary between
+      the two sets of lengths.
+ */
+
+
+local void inflate_blocks_reset(s, z, c)
+inflate_blocks_statef *s;
+z_stream *z;
+uLongf *c;
+{
+  if (s->checkfn != Z_NULL)
+    *c = s->check;
+  if (s->mode == BTREE || s->mode == DTREE)
+    ZFREE(z, s->sub.trees.blens, s->sub.trees.nblens * sizeof(uInt));
+  if (s->mode == CODES)
+  {
+    inflate_codes_free(s->sub.decode.codes, z);
+    inflate_trees_free(s->sub.decode.td, z);
+    inflate_trees_free(s->sub.decode.tl, z);
+  }
+  s->mode = TYPE;
+  s->bitk = 0;
+  s->bitb = 0;
+  s->read = s->write = s->window;
+  if (s->checkfn != Z_NULL)
+    s->check = (*s->checkfn)(0L, Z_NULL, 0);
+  Trace((stderr, "inflate:   blocks reset\n"));
+}
+
+
+local inflate_blocks_statef *inflate_blocks_new(z, c, w)
+z_stream *z;
+check_func c;
+uInt w;
+{
+  inflate_blocks_statef *s;
+
+  if ((s = (inflate_blocks_statef *)ZALLOC
+       (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL)
+    return s;
+  if ((s->window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL)
+  {
+    ZFREE(z, s, sizeof(struct inflate_blocks_state));
+    return Z_NULL;
+  }
+  s->end = s->window + w;
+  s->checkfn = c;
+  s->mode = TYPE;
+  Trace((stderr, "inflate:   blocks allocated\n"));
+  inflate_blocks_reset(s, z, &s->check);
+  return s;
+}
+
+
+local int inflate_blocks(s, z, r)
+inflate_blocks_statef *s;
+z_stream *z;
+int r;
+{
+  uInt t;               /* temporary storage */
+  uLong b;              /* bit buffer */
+  uInt k;               /* bits in bit buffer */
+  Bytef *p;             /* input data pointer */
+  uInt n;               /* bytes available there */
+  Bytef *q;             /* output window write pointer */
+  uInt m;               /* bytes to end of window or read pointer */
+
+  /* copy input/output information to locals (UPDATE macro restores) */
+  LOAD
+
+  /* process input based on current state */
+  while (1) switch (s->mode)
+  {
+    case TYPE:
+      NEEDBITS(3)
+      t = (uInt)b & 7;
+      s->last = t & 1;
+      switch (t >> 1)
+      {
+        case 0:                         /* stored */
+          Trace((stderr, "inflate:     stored block%s\n",
+                 s->last ? " (last)" : ""));
+          DUMPBITS(3)
+          t = k & 7;                    /* go to byte boundary */
+          DUMPBITS(t)
+          s->mode = LENS;               /* get length of stored block */
+          break;
+        case 1:                         /* fixed */
+          Trace((stderr, "inflate:     fixed codes block%s\n",
+                 s->last ? " (last)" : ""));
+          {
+            uInt bl, bd;
+            inflate_huft *tl, *td;
+
+            inflate_trees_fixed(&bl, &bd, &tl, &td);
+            s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z);
+            if (s->sub.decode.codes == Z_NULL)
+            {
+              r = Z_MEM_ERROR;
+              LEAVE
+            }
+            s->sub.decode.tl = Z_NULL;  /* don't try to free these */
+            s->sub.decode.td = Z_NULL;
+          }
+          DUMPBITS(3)
+          s->mode = CODES;
+          break;
+        case 2:                         /* dynamic */
+          Trace((stderr, "inflate:     dynamic codes block%s\n",
+                 s->last ? " (last)" : ""));
+          DUMPBITS(3)
+          s->mode = TABLE;
+          break;
+        case 3:                         /* illegal */
+          DUMPBITS(3)
+          s->mode = BADB;
+          z->msg = "invalid block type";
+          r = Z_DATA_ERROR;
+          LEAVE
+      }
+      break;
+    case LENS:
+      NEEDBITS(32)
+      if (((~b) >> 16) != (b & 0xffff))
+      {
+        s->mode = BADB;
+        z->msg = "invalid stored block lengths";
+        r = Z_DATA_ERROR;
+        LEAVE
+      }
+      s->sub.left = (uInt)b & 0xffff;
+      b = k = 0;                      /* dump bits */
+      Tracev((stderr, "inflate:       stored length %u\n", s->sub.left));
+      s->mode = s->sub.left ? STORED : TYPE;
+      break;
+    case STORED:
+      if (n == 0)
+        LEAVE
+      NEEDOUT
+      t = s->sub.left;
+      if (t > n) t = n;
+      if (t > m) t = m;
+      zmemcpy(q, p, t);
+      p += t;  n -= t;
+      q += t;  m -= t;
+      if ((s->sub.left -= t) != 0)
+        break;
+      Tracev((stderr, "inflate:       stored end, %lu total out\n",
+              z->total_out + (q >= s->read ? q - s->read :
+              (s->end - s->read) + (q - s->window))));
+      s->mode = s->last ? DRY : TYPE;
+      break;
+    case TABLE:
+      NEEDBITS(14)
+      s->sub.trees.table = t = (uInt)b & 0x3fff;
+#ifndef PKZIP_BUG_WORKAROUND
+      if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29)
+      {
+        s->mode = BADB;
+        z->msg = "too many length or distance symbols";
+        r = Z_DATA_ERROR;
+        LEAVE
+      }
+#endif
+      t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f);
+      if (t < 19)
+        t = 19;
+      if ((s->sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL)
+      {
+        r = Z_MEM_ERROR;
+        LEAVE
+      }
+      s->sub.trees.nblens = t;
+      DUMPBITS(14)
+      s->sub.trees.index = 0;
+      Tracev((stderr, "inflate:       table sizes ok\n"));
+      s->mode = BTREE;
+    case BTREE:
+      while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10))
+      {
+        NEEDBITS(3)
+        s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7;
+        DUMPBITS(3)
+      }
+      while (s->sub.trees.index < 19)
+        s->sub.trees.blens[border[s->sub.trees.index++]] = 0;
+      s->sub.trees.bb = 7;
+      t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb,
+                             &s->sub.trees.tb, z);
+      if (t != Z_OK)
+      {
+        r = t;
+        if (r == Z_DATA_ERROR)
+          s->mode = BADB;
+        LEAVE
+      }
+      s->sub.trees.index = 0;
+      Tracev((stderr, "inflate:       bits tree ok\n"));
+      s->mode = DTREE;
+    case DTREE:
+      while (t = s->sub.trees.table,
+             s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))
+      {
+        inflate_huft *h;
+        uInt i, j, c;
+
+        t = s->sub.trees.bb;
+        NEEDBITS(t)
+        h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]);
+        t = h->word.what.Bits;
+        c = h->more.Base;
+        if (c < 16)
+        {
+          DUMPBITS(t)
+          s->sub.trees.blens[s->sub.trees.index++] = c;
+        }
+        else /* c == 16..18 */
+        {
+          i = c == 18 ? 7 : c - 14;
+          j = c == 18 ? 11 : 3;
+          NEEDBITS(t + i)
+          DUMPBITS(t)
+          j += (uInt)b & inflate_mask[i];
+          DUMPBITS(i)
+          i = s->sub.trees.index;
+          t = s->sub.trees.table;
+          if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) ||
+              (c == 16 && i < 1))
+          {
+            s->mode = BADB;
+            z->msg = "invalid bit length repeat";
+            r = Z_DATA_ERROR;
+            LEAVE
+          }
+          c = c == 16 ? s->sub.trees.blens[i - 1] : 0;
+          do {
+            s->sub.trees.blens[i++] = c;
+          } while (--j);
+          s->sub.trees.index = i;
+        }
+      }
+      inflate_trees_free(s->sub.trees.tb, z);
+      s->sub.trees.tb = Z_NULL;
+      {
+        uInt bl, bd;
+        inflate_huft *tl, *td;
+        inflate_codes_statef *c;
+
+        bl = 9;         /* must be <= 9 for lookahead assumptions */
+        bd = 6;         /* must be <= 9 for lookahead assumptions */
+        t = s->sub.trees.table;
+        t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f),
+                                  s->sub.trees.blens, &bl, &bd, &tl, &td, z);
+        if (t != Z_OK)
+        {
+          if (t == (uInt)Z_DATA_ERROR)
+            s->mode = BADB;
+          r = t;
+          LEAVE
+        }
+        Tracev((stderr, "inflate:       trees ok\n"));
+        if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL)
+        {
+          inflate_trees_free(td, z);
+          inflate_trees_free(tl, z);
+          r = Z_MEM_ERROR;
+          LEAVE
+        }
+        ZFREE(z, s->sub.trees.blens, s->sub.trees.nblens * sizeof(uInt));
+        s->sub.decode.codes = c;
+        s->sub.decode.tl = tl;
+        s->sub.decode.td = td;
+      }
+      s->mode = CODES;
+    case CODES:
+      UPDATE
+      if ((r = inflate_codes(s, z, r)) != Z_STREAM_END)
+        return inflate_flush(s, z, r);
+      r = Z_OK;
+      inflate_codes_free(s->sub.decode.codes, z);
+      inflate_trees_free(s->sub.decode.td, z);
+      inflate_trees_free(s->sub.decode.tl, z);
+      LOAD
+      Tracev((stderr, "inflate:       codes end, %lu total out\n",
+              z->total_out + (q >= s->read ? q - s->read :
+              (s->end - s->read) + (q - s->window))));
+      if (!s->last)
+      {
+        s->mode = TYPE;
+        break;
+      }
+      if (k > 7)              /* return unused byte, if any */
+      {
+        Assert(k < 16, "inflate_codes grabbed too many bytes")
+        k -= 8;
+        n++;
+        p--;                    /* can always return one */
+      }
+      s->mode = DRY;
+    case DRY:
+      FLUSH
+      if (s->read != s->write)
+        LEAVE
+      s->mode = DONEB;
+    case DONEB:
+      r = Z_STREAM_END;
+      LEAVE
+    case BADB:
+      r = Z_DATA_ERROR;
+      LEAVE
+    default:
+      r = Z_STREAM_ERROR;
+      LEAVE
+  }
+}
+
+
+local int inflate_blocks_free(s, z, c)
+inflate_blocks_statef *s;
+z_stream *z;
+uLongf *c;
+{
+  inflate_blocks_reset(s, z, c);
+  ZFREE(z, s->window, s->end - s->window);
+  ZFREE(z, s, sizeof(struct inflate_blocks_state));
+  Trace((stderr, "inflate:   blocks freed\n"));
+  return Z_OK;
+}
+
+/*
+ * This subroutine adds the data at next_in/avail_in to the output history
+ * without performing any output.  The output buffer must be "caught up";
+ * i.e. no pending output (hence s->read equals s->write), and the state must
+ * be BLOCKS (i.e. we should be willing to see the start of a series of
+ * BLOCKS).  On exit, the output will also be caught up, and the checksum
+ * will have been updated if need be.
+ */
+local int inflate_addhistory(s, z)
+inflate_blocks_statef *s;
+z_stream *z;
+{
+    uLong b;              /* bit buffer */  /* NOT USED HERE */
+    uInt k;               /* bits in bit buffer */ /* NOT USED HERE */
+    uInt t;               /* temporary storage */
+    Bytef *p;             /* input data pointer */
+    uInt n;               /* bytes available there */
+    Bytef *q;             /* output window write pointer */
+    uInt m;               /* bytes to end of window or read pointer */
+
+    if (s->read != s->write)
+       return Z_STREAM_ERROR;
+    if (s->mode != TYPE)
+       return Z_DATA_ERROR;
+
+    /* we're ready to rock */
+    LOAD
+    /* while there is input ready, copy to output buffer, moving
+     * pointers as needed.
+     */
+    while (n) {
+       t = n;  /* how many to do */
+       /* is there room until end of buffer? */
+       if (t > m) t = m;
+       /* update check information */
+       if (s->checkfn != Z_NULL)
+           s->check = (*s->checkfn)(s->check, q, t);
+       zmemcpy(q, p, t);
+       q += t;
+       p += t;
+       n -= t;
+       z->total_out += t;
+       s->read = q;    /* drag read pointer forward */
+/*      WRAP  */       /* expand WRAP macro by hand to handle s->read */
+       if (q == s->end) {
+           s->read = q = s->window;
+           m = WAVAIL;
+       }
+    }
+    UPDATE
+    return Z_OK;
+}
+
+
+/*
+ * At the end of a Deflate-compressed PPP packet, we expect to have seen
+ * a `stored' block type value but not the (zero) length bytes.
+ */
+local int inflate_packet_flush(s)
+    inflate_blocks_statef *s;
+{
+    if (s->mode != LENS)
+       return Z_DATA_ERROR;
+    s->mode = TYPE;
+    return Z_OK;
+}
+
+
+/*+++++*/
+/* inftrees.c -- generate Huffman trees for efficient decoding
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* simplify the use of the inflate_huft type with some defines */
+#define base more.Base
+#define next more.Next
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+
+local int huft_build OF((
+    uIntf *,            /* code lengths in bits */
+    uInt,               /* number of codes */
+    uInt,               /* number of "simple" codes */
+    uIntf *,            /* list of base values for non-simple codes */
+    uIntf *,            /* list of extra bits for non-simple codes */
+    inflate_huft * FAR*,/* result: starting table */
+    uIntf *,            /* maximum lookup bits (returns actual) */
+    z_stream *));       /* for zalloc function */
+
+local voidpf falloc OF((
+    voidpf,             /* opaque pointer (not used) */
+    uInt,               /* number of items */
+    uInt));             /* size of item */
+
+local void ffree OF((
+    voidpf q,           /* opaque pointer (not used) */
+    voidpf p,           /* what to free (not used) */
+    uInt n));          /* number of bytes (not used) */
+
+/* Tables for deflate from PKZIP's appnote.txt. */
+local uInt cplens[] = { /* Copy lengths for literal codes 257..285 */
+        3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+        35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+        /* actually lengths - 2; also see note #13 above about 258 */
+local uInt cplext[] = { /* Extra bits for literal codes 257..285 */
+        0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+        3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 192, 192}; /* 192==invalid */
+local uInt cpdist[] = { /* Copy offsets for distance codes 0..29 */
+        1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+        257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+        8193, 12289, 16385, 24577};
+local uInt cpdext[] = { /* Extra bits for distance codes */
+        0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+        7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+        12, 12, 13, 13};
+
+/*
+   Huffman code decoding is performed using a multi-level table lookup.
+   The fastest way to decode is to simply build a lookup table whose
+   size is determined by the longest code.  However, the time it takes
+   to build this table can also be a factor if the data being decoded
+   is not very long.  The most common codes are necessarily the
+   shortest codes, so those codes dominate the decoding time, and hence
+   the speed.  The idea is you can have a shorter table that decodes the
+   shorter, more probable codes, and then point to subsidiary tables for
+   the longer codes.  The time it costs to decode the longer codes is
+   then traded against the time it takes to make longer tables.
+
+   This results of this trade are in the variables lbits and dbits
+   below.  lbits is the number of bits the first level table for literal/
+   length codes can decode in one step, and dbits is the same thing for
+   the distance codes.  Subsequent tables are also less than or equal to
+   those sizes.  These values may be adjusted either when all of the
+   codes are shorter than that, in which case the longest code length in
+   bits is used, or when the shortest code is *longer* than the requested
+   table size, in which case the length of the shortest code in bits is
+   used.
+
+   There are two different values for the two tables, since they code a
+   different number of possibilities each.  The literal/length table
+   codes 286 possible values, or in a flat code, a little over eight
+   bits.  The distance table codes 30 possible values, or a little less
+   than five bits, flat.  The optimum values for speed end up being
+   about one bit more than those, so lbits is 8+1 and dbits is 5+1.
+   The optimum values may differ though from machine to machine, and
+   possibly even between compilers.  Your mileage may vary.
+ */
+
+
+/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */
+#define BMAX 15         /* maximum bit length of any code */
+#define N_MAX 288       /* maximum number of codes in any set */
+
+#ifdef DEBUG_ZLIB
+  uInt inflate_hufts;
+#endif
+
+local int huft_build(b, n, s, d, e, t, m, zs)
+uIntf *b;               /* code lengths in bits (all assumed <= BMAX) */
+uInt n;                 /* number of codes (assumed <= N_MAX) */
+uInt s;                 /* number of simple-valued codes (0..s-1) */
+uIntf *d;               /* list of base values for non-simple codes */
+uIntf *e;               /* list of extra bits for non-simple codes */  
+inflate_huft * FAR *t;  /* result: starting table */
+uIntf *m;               /* maximum lookup bits, returns actual */
+z_stream *zs;           /* for zalloc function */
+/* Given a list of code lengths and a maximum table size, make a set of
+   tables to decode that set of codes.  Return Z_OK on success, Z_BUF_ERROR
+   if the given code set is incomplete (the tables are still built in this
+   case), Z_DATA_ERROR if the input is invalid (all zero length codes or an
+   over-subscribed set of lengths), or Z_MEM_ERROR if not enough memory. */
+{
+
+  uInt a;                       /* counter for codes of length k */
+  uInt c[BMAX+1];               /* bit length count table */
+  uInt f;                       /* i repeats in table every f entries */
+  int g;                        /* maximum code length */
+  int h;                        /* table level */
+  register uInt i;              /* counter, current code */
+  register uInt j;              /* counter */
+  register int k;               /* number of bits in current code */
+  int l;                        /* bits per table (returned in m) */
+  register uIntf *p;            /* pointer into c[], b[], or v[] */
+  inflate_huft *q;              /* points to current table */
+  struct inflate_huft_s r;      /* table entry for structure assignment */
+  inflate_huft *u[BMAX];        /* table stack */
+  uInt v[N_MAX];                /* values in order of bit length */
+  register int w;               /* bits before this table == (l * h) */
+  uInt x[BMAX+1];               /* bit offsets, then code stack */
+  uIntf *xp;                    /* pointer into x */
+  int y;                        /* number of dummy codes added */
+  uInt z;                       /* number of entries in current table */
+
+
+  /* Generate counts for each bit length */
+  p = c;
+#define C0 *p++ = 0;
+#define C2 C0 C0 C0 C0
+#define C4 C2 C2 C2 C2
+  C4                            /* clear c[]--assume BMAX+1 is 16 */
+  p = b;  i = n;
+  do {
+    c[*p++]++;                  /* assume all entries <= BMAX */
+  } while (--i);
+  if (c[0] == n)                /* null input--all zero length codes */
+  {
+    *t = (inflate_huft *)Z_NULL;
+    *m = 0;
+    return Z_OK;
+  }
+
+
+  /* Find minimum and maximum length, bound *m by those */
+  l = *m;
+  for (j = 1; j <= BMAX; j++)
+    if (c[j])
+      break;
+  k = j;                        /* minimum code length */
+  if ((uInt)l < j)
+    l = j;
+  for (i = BMAX; i; i--)
+    if (c[i])
+      break;
+  g = i;                        /* maximum code length */
+  if ((uInt)l > i)
+    l = i;
+  *m = l;
+
+
+  /* Adjust last length count to fill out codes, if needed */
+  for (y = 1 << j; j < i; j++, y <<= 1)
+    if ((y -= c[j]) < 0)
+      return Z_DATA_ERROR;
+  if ((y -= c[i]) < 0)
+    return Z_DATA_ERROR;
+  c[i] += y;
+
+
+  /* Generate starting offsets into the value table for each length */
+  x[1] = j = 0;
+  p = c + 1;  xp = x + 2;
+  while (--i) {                 /* note that i == g from above */
+    *xp++ = (j += *p++);
+  }
+
+
+  /* Make a table of values in order of bit lengths */
+  p = b;  i = 0;
+  do {
+    if ((j = *p++) != 0)
+      v[x[j]++] = i;
+  } while (++i < n);
+
+
+  /* Generate the Huffman codes and for each, make the table entries */
+  x[0] = i = 0;                 /* first Huffman code is zero */
+  p = v;                        /* grab values in bit order */
+  h = -1;                       /* no tables yet--level -1 */
+  w = -l;                       /* bits decoded == (l * h) */
+  u[0] = (inflate_huft *)Z_NULL;        /* just to keep compilers happy */
+  q = (inflate_huft *)Z_NULL;   /* ditto */
+  z = 0;                        /* ditto */
+
+  /* go through the bit lengths (k already is bits in shortest code) */
+  for (; k <= g; k++)
+  {
+    a = c[k];
+    while (a--)
+    {
+      /* here i is the Huffman code of length k bits for value *p */
+      /* make tables up to required level */
+      while (k > w + l)
+      {
+        h++;
+        w += l;                 /* previous table always l bits */
+
+        /* compute minimum size table less than or equal to l bits */
+        z = (z = g - w) > (uInt)l ? l : z;      /* table size upper limit */
+        if ((f = 1 << (j = k - w)) > a + 1)     /* try a k-w bit table */
+        {                       /* too few codes for k-w bit table */
+          f -= a + 1;           /* deduct codes from patterns left */
+          xp = c + k;
+          if (j < z)
+            while (++j < z)     /* try smaller tables up to z bits */
+            {
+              if ((f <<= 1) <= *++xp)
+                break;          /* enough codes to use up j bits */
+              f -= *xp;         /* else deduct codes from patterns */
+            }
+        }
+        z = 1 << j;             /* table entries for j-bit table */
+
+        /* allocate and link in new table */
+        if ((q = (inflate_huft *)ZALLOC
+             (zs,z + 1,sizeof(inflate_huft))) == Z_NULL)
+        {
+          if (h)
+            inflate_trees_free(u[0], zs);
+          return Z_MEM_ERROR;   /* not enough memory */
+        }
+       q->word.Nalloc = z + 1;
+#ifdef DEBUG_ZLIB
+        inflate_hufts += z + 1;
+#endif
+        *t = q + 1;             /* link to list for huft_free() */
+        *(t = &(q->next)) = Z_NULL;
+        u[h] = ++q;             /* table starts after link */
+
+        /* connect to last table, if there is one */
+        if (h)
+        {
+          x[h] = i;             /* save pattern for backing up */
+          r.bits = (Byte)l;     /* bits to dump before this table */
+          r.exop = (Byte)j;     /* bits in this table */
+          r.next = q;           /* pointer to this table */
+          j = i >> (w - l);     /* (get around Turbo C bug) */
+          u[h-1][j] = r;        /* connect to last table */
+        }
+      }
+
+      /* set up table entry in r */
+      r.bits = (Byte)(k - w);
+      if (p >= v + n)
+        r.exop = 128 + 64;      /* out of values--invalid code */
+      else if (*p < s)
+      {
+        r.exop = (Byte)(*p < 256 ? 0 : 32 + 64);     /* 256 is end-of-block */
+        r.base = *p++;          /* simple code is just the value */
+      }
+      else
+      {
+        r.exop = (Byte)e[*p - s] + 16 + 64; /* non-simple--look up in lists */
+        r.base = d[*p++ - s];
+      }
+
+      /* fill code-like entries with r */
+      f = 1 << (k - w);
+      for (j = i >> w; j < z; j += f)
+        q[j] = r;
+
+      /* backwards increment the k-bit code i */
+      for (j = 1 << (k - 1); i & j; j >>= 1)
+        i ^= j;
+      i ^= j;
+
+      /* backup over finished tables */
+      while ((i & ((1 << w) - 1)) != x[h])
+      {
+        h--;                    /* don't need to update q */
+        w -= l;
+      }
+    }
+  }
+
+
+  /* Return Z_BUF_ERROR if we were given an incomplete table */
+  return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK;
+}
+
+
+local int inflate_trees_bits(c, bb, tb, z)
+uIntf *c;               /* 19 code lengths */
+uIntf *bb;              /* bits tree desired/actual depth */
+inflate_huft * FAR *tb; /* bits tree result */
+z_stream *z;            /* for zfree function */
+{
+  int r;
+
+  r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL, tb, bb, z);
+  if (r == Z_DATA_ERROR)
+    z->msg = "oversubscribed dynamic bit lengths tree";
+  else if (r == Z_BUF_ERROR)
+  {
+    inflate_trees_free(*tb, z);
+    z->msg = "incomplete dynamic bit lengths tree";
+    r = Z_DATA_ERROR;
+  }
+  return r;
+}
+
+
+local int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, z)
+uInt nl;                /* number of literal/length codes */
+uInt nd;                /* number of distance codes */
+uIntf *c;               /* that many (total) code lengths */
+uIntf *bl;              /* literal desired/actual bit depth */
+uIntf *bd;              /* distance desired/actual bit depth */
+inflate_huft * FAR *tl; /* literal/length tree result */
+inflate_huft * FAR *td; /* distance tree result */
+z_stream *z;            /* for zfree function */
+{
+  int r;
+
+  /* build literal/length tree */
+  if ((r = huft_build(c, nl, 257, cplens, cplext, tl, bl, z)) != Z_OK)
+  {
+    if (r == Z_DATA_ERROR)
+      z->msg = "oversubscribed literal/length tree";
+    else if (r == Z_BUF_ERROR)
+    {
+      inflate_trees_free(*tl, z);
+      z->msg = "incomplete literal/length tree";
+      r = Z_DATA_ERROR;
+    }
+    return r;
+  }
+
+  /* build distance tree */
+  if ((r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, z)) != Z_OK)
+  {
+    if (r == Z_DATA_ERROR)
+      z->msg = "oversubscribed literal/length tree";
+    else if (r == Z_BUF_ERROR) {
+#ifdef PKZIP_BUG_WORKAROUND
+      r = Z_OK;
+    }
+#else
+      inflate_trees_free(*td, z);
+      z->msg = "incomplete literal/length tree";
+      r = Z_DATA_ERROR;
+    }
+    inflate_trees_free(*tl, z);
+    return r;
+#endif
+  }
+
+  /* done */
+  return Z_OK;
+}
+
+
+/* build fixed tables only once--keep them here */
+local int fixed_lock = 0;
+local int fixed_built = 0;
+#define FIXEDH 530      /* number of hufts used by fixed tables */
+local uInt fixed_left = FIXEDH;
+local inflate_huft fixed_mem[FIXEDH];
+local uInt fixed_bl;
+local uInt fixed_bd;
+local inflate_huft *fixed_tl;
+local inflate_huft *fixed_td;
+
+
+local voidpf falloc(q, n, s)
+voidpf q;        /* opaque pointer (not used) */
+uInt n;         /* number of items */
+uInt s;         /* size of item */
+{
+  Assert(s == sizeof(inflate_huft) && n <= fixed_left,
+         "inflate_trees falloc overflow");
+  if (q) s++; /* to make some compilers happy */
+  fixed_left -= n;
+  return (voidpf)(fixed_mem + fixed_left);
+}
+
+
+local void ffree(q, p, n)
+voidpf q;
+voidpf p;
+uInt n;
+{
+  Assert(0, "inflate_trees ffree called!");
+  if (q) q = p; /* to make some compilers happy */
+}
+
+
+local int inflate_trees_fixed(bl, bd, tl, td)
+uIntf *bl;               /* literal desired/actual bit depth */
+uIntf *bd;               /* distance desired/actual bit depth */
+inflate_huft * FAR *tl;  /* literal/length tree result */
+inflate_huft * FAR *td;  /* distance tree result */
+{
+  /* build fixed tables if not built already--lock out other instances */
+  while (++fixed_lock > 1)
+    fixed_lock--;
+  if (!fixed_built)
+  {
+    int k;              /* temporary variable */
+    unsigned c[288];    /* length list for huft_build */
+    z_stream z;         /* for falloc function */
+
+    /* set up fake z_stream for memory routines */
+    z.zalloc = falloc;
+    z.zfree = ffree;
+    z.opaque = Z_NULL;
+
+    /* literal table */
+    for (k = 0; k < 144; k++)
+      c[k] = 8;
+    for (; k < 256; k++)
+      c[k] = 9;
+    for (; k < 280; k++)
+      c[k] = 7;
+    for (; k < 288; k++)
+      c[k] = 8;
+    fixed_bl = 7;
+    huft_build(c, 288, 257, cplens, cplext, &fixed_tl, &fixed_bl, &z);
+
+    /* distance table */
+    for (k = 0; k < 30; k++)
+      c[k] = 5;
+    fixed_bd = 5;
+    huft_build(c, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd, &z);
+
+    /* done */
+    fixed_built = 1;
+  }
+  fixed_lock--;
+  *bl = fixed_bl;
+  *bd = fixed_bd;
+  *tl = fixed_tl;
+  *td = fixed_td;
+  return Z_OK;
+}
+
+
+local int inflate_trees_free(t, z)
+inflate_huft *t;        /* table to free */
+z_stream *z;            /* for zfree function */
+/* Free the malloc'ed tables built by huft_build(), which makes a linked
+   list of the tables it made, with the links in a dummy first entry of
+   each table. */
+{
+  register inflate_huft *p, *q;
+
+  /* Go through linked list, freeing from the malloced (t[-1]) address. */
+  p = t;
+  while (p != Z_NULL)
+  {
+    q = (--p)->next;
+    ZFREE(z, p, p->word.Nalloc * sizeof(inflate_huft));
+    p = q;
+  } 
+  return Z_OK;
+}
+
+/*+++++*/
+/* infcodes.c -- process literals and length/distance pairs
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* simplify the use of the inflate_huft type with some defines */
+#define base more.Base
+#define next more.Next
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+/* inflate codes private state */
+struct inflate_codes_state {
+
+  /* mode */
+  enum {        /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
+      START,    /* x: set up for LEN */
+      LEN,      /* i: get length/literal/eob next */
+      LENEXT,   /* i: getting length extra (have base) */
+      DIST,     /* i: get distance next */
+      DISTEXT,  /* i: getting distance extra */
+      COPY,     /* o: copying bytes in window, waiting for space */
+      LIT,      /* o: got literal, waiting for output space */
+      WASH,     /* o: got eob, possibly still output waiting */
+      END,      /* x: got eob and all data flushed */
+      BADCODE}  /* x: got error */
+    mode;               /* current inflate_codes mode */
+
+  /* mode dependent information */
+  uInt len;
+  union {
+    struct {
+      inflate_huft *tree;       /* pointer into tree */
+      uInt need;                /* bits needed */
+    } code;             /* if LEN or DIST, where in tree */
+    uInt lit;           /* if LIT, literal */
+    struct {
+      uInt get;                 /* bits to get for extra */
+      uInt dist;                /* distance back to copy from */
+    } copy;             /* if EXT or COPY, where and how much */
+  } sub;                /* submode */
+
+  /* mode independent information */
+  Byte lbits;           /* ltree bits decoded per branch */
+  Byte dbits;           /* dtree bits decoder per branch */
+  inflate_huft *ltree;          /* literal/length/eob tree */
+  inflate_huft *dtree;          /* distance tree */
+
+};
+
+
+local inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z)
+uInt bl, bd;
+inflate_huft *tl, *td;
+z_stream *z;
+{
+  inflate_codes_statef *c;
+
+  if ((c = (inflate_codes_statef *)
+       ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL)
+  {
+    c->mode = START;
+    c->lbits = (Byte)bl;
+    c->dbits = (Byte)bd;
+    c->ltree = tl;
+    c->dtree = td;
+    Tracev((stderr, "inflate:       codes new\n"));
+  }
+  return c;
+}
+
+
+local int inflate_codes(s, z, r)
+inflate_blocks_statef *s;
+z_stream *z;
+int r;
+{
+  uInt j;               /* temporary storage */
+  inflate_huft *t;      /* temporary pointer */
+  uInt e;               /* extra bits or operation */
+  uLong b;              /* bit buffer */
+  uInt k;               /* bits in bit buffer */
+  Bytef *p;             /* input data pointer */
+  uInt n;               /* bytes available there */
+  Bytef *q;             /* output window write pointer */
+  uInt m;               /* bytes to end of window or read pointer */
+  Bytef *f;             /* pointer to copy strings from */
+  inflate_codes_statef *c = s->sub.decode.codes;  /* codes state */
+
+  /* copy input/output information to locals (UPDATE macro restores) */
+  LOAD
+
+  /* process input and output based on current state */
+  while (1) switch (c->mode)
+  {             /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
+    case START:         /* x: set up for LEN */
+#ifndef SLOW
+      if (m >= 258 && n >= 10)
+      {
+        UPDATE
+        r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z);
+        LOAD
+        if (r != Z_OK)
+        {
+          c->mode = r == Z_STREAM_END ? WASH : BADCODE;
+          break;
+        }
+      }
+#endif /* !SLOW */
+      c->sub.code.need = c->lbits;
+      c->sub.code.tree = c->ltree;
+      c->mode = LEN;
+    case LEN:           /* i: get length/literal/eob next */
+      j = c->sub.code.need;
+      NEEDBITS(j)
+      t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
+      DUMPBITS(t->bits)
+      e = (uInt)(t->exop);
+      if (e == 0)               /* literal */
+      {
+        c->sub.lit = t->base;
+        Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+                 "inflate:         literal '%c'\n" :
+                 "inflate:         literal 0x%02x\n", t->base));
+        c->mode = LIT;
+        break;
+      }
+      if (e & 16)               /* length */
+      {
+        c->sub.copy.get = e & 15;
+        c->len = t->base;
+        c->mode = LENEXT;
+        break;
+      }
+      if ((e & 64) == 0)        /* next table */
+      {
+        c->sub.code.need = e;
+        c->sub.code.tree = t->next;
+        break;
+      }
+      if (e & 32)               /* end of block */
+      {
+        Tracevv((stderr, "inflate:         end of block\n"));
+        c->mode = WASH;
+        break;
+      }
+      c->mode = BADCODE;        /* invalid code */
+      z->msg = "invalid literal/length code";
+      r = Z_DATA_ERROR;
+      LEAVE
+    case LENEXT:        /* i: getting length extra (have base) */
+      j = c->sub.copy.get;
+      NEEDBITS(j)
+      c->len += (uInt)b & inflate_mask[j];
+      DUMPBITS(j)
+      c->sub.code.need = c->dbits;
+      c->sub.code.tree = c->dtree;
+      Tracevv((stderr, "inflate:         length %u\n", c->len));
+      c->mode = DIST;
+    case DIST:          /* i: get distance next */
+      j = c->sub.code.need;
+      NEEDBITS(j)
+      t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
+      DUMPBITS(t->bits)
+      e = (uInt)(t->exop);
+      if (e & 16)               /* distance */
+      {
+        c->sub.copy.get = e & 15;
+        c->sub.copy.dist = t->base;
+        c->mode = DISTEXT;
+        break;
+      }
+      if ((e & 64) == 0)        /* next table */
+      {
+        c->sub.code.need = e;
+        c->sub.code.tree = t->next;
+        break;
+      }
+      c->mode = BADCODE;        /* invalid code */
+      z->msg = "invalid distance code";
+      r = Z_DATA_ERROR;
+      LEAVE
+    case DISTEXT:       /* i: getting distance extra */
+      j = c->sub.copy.get;
+      NEEDBITS(j)
+      c->sub.copy.dist += (uInt)b & inflate_mask[j];
+      DUMPBITS(j)
+      Tracevv((stderr, "inflate:         distance %u\n", c->sub.copy.dist));
+      c->mode = COPY;
+    case COPY:          /* o: copying bytes in window, waiting for space */
+#ifndef __TURBOC__ /* Turbo C bug for following expression */
+      f = (uInt)(q - s->window) < c->sub.copy.dist ?
+          s->end - (c->sub.copy.dist - (q - s->window)) :
+          q - c->sub.copy.dist;
+#else
+      f = q - c->sub.copy.dist;
+      if ((uInt)(q - s->window) < c->sub.copy.dist)
+        f = s->end - (c->sub.copy.dist - (q - s->window));
+#endif
+      while (c->len)
+      {
+        NEEDOUT
+        OUTBYTE(*f++)
+        if (f == s->end)
+          f = s->window;
+        c->len--;
+      }
+      c->mode = START;
+      break;
+    case LIT:           /* o: got literal, waiting for output space */
+      NEEDOUT
+      OUTBYTE(c->sub.lit)
+      c->mode = START;
+      break;
+    case WASH:          /* o: got eob, possibly more output */
+      FLUSH
+      if (s->read != s->write)
+        LEAVE
+      c->mode = END;
+    case END:
+      r = Z_STREAM_END;
+      LEAVE
+    case BADCODE:       /* x: got error */
+      r = Z_DATA_ERROR;
+      LEAVE
+    default:
+      r = Z_STREAM_ERROR;
+      LEAVE
+  }
+}
+
+
+local void inflate_codes_free(c, z)
+inflate_codes_statef *c;
+z_stream *z;
+{
+  ZFREE(z, c, sizeof(struct inflate_codes_state));
+  Tracev((stderr, "inflate:       codes free\n"));
+}
+
+/*+++++*/
+/* inflate_util.c -- data and routines common to blocks and codes
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* copy as much as possible from the sliding window to the output area */
+local int inflate_flush(s, z, r)
+inflate_blocks_statef *s;
+z_stream *z;
+int r;
+{
+  uInt n;
+  Bytef *p, *q;
+
+  /* local copies of source and destination pointers */
+  p = z->next_out;
+  q = s->read;
+
+  /* compute number of bytes to copy as far as end of window */
+  n = (uInt)((q <= s->write ? s->write : s->end) - q);
+  if (n > z->avail_out) n = z->avail_out;
+  if (n && r == Z_BUF_ERROR) r = Z_OK;
+
+  /* update counters */
+  z->avail_out -= n;
+  z->total_out += n;
+
+  /* update check information */
+  if (s->checkfn != Z_NULL)
+    s->check = (*s->checkfn)(s->check, q, n);
+
+  /* copy as far as end of window */
+  zmemcpy(p, q, n);
+  p += n;
+  q += n;
+
+  /* see if more to copy at beginning of window */
+  if (q == s->end)
+  {
+    /* wrap pointers */
+    q = s->window;
+    if (s->write == s->end)
+      s->write = s->window;
+
+    /* compute bytes to copy */
+    n = (uInt)(s->write - q);
+    if (n > z->avail_out) n = z->avail_out;
+    if (n && r == Z_BUF_ERROR) r = Z_OK;
+
+    /* update counters */
+    z->avail_out -= n;
+    z->total_out += n;
+
+    /* update check information */
+    if (s->checkfn != Z_NULL)
+      s->check = (*s->checkfn)(s->check, q, n);
+
+    /* copy */
+    zmemcpy(p, q, n);
+    p += n;
+    q += n;
+  }
+
+  /* update pointers */
+  z->next_out = p;
+  s->read = q;
+
+  /* done */
+  return r;
+}
+
+
+/*+++++*/
+/* inffast.c -- process literals and length/distance pairs fast
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* simplify the use of the inflate_huft type with some defines */
+#define base more.Base
+#define next more.Next
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+/* macros for bit input with no checking and for returning unused bytes */
+#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<<k;k+=8;}}
+#define UNGRAB {n+=(c=k>>3);p-=c;k&=7;}
+
+/* Called with number of bytes left to write in window at least 258
+   (the maximum string length) and number of input bytes available
+   at least ten.  The ten bytes are six bytes for the longest length/
+   distance pair plus four bytes for overloading the bit buffer. */
+
+local int inflate_fast(bl, bd, tl, td, s, z)
+uInt bl, bd;
+inflate_huft *tl, *td;
+inflate_blocks_statef *s;
+z_stream *z;
+{
+  inflate_huft *t;      /* temporary pointer */
+  uInt e;               /* extra bits or operation */
+  uLong b;              /* bit buffer */
+  uInt k;               /* bits in bit buffer */
+  Bytef *p;             /* input data pointer */
+  uInt n;               /* bytes available there */
+  Bytef *q;             /* output window write pointer */
+  uInt m;               /* bytes to end of window or read pointer */
+  uInt ml;              /* mask for literal/length tree */
+  uInt md;              /* mask for distance tree */
+  uInt c;               /* bytes to copy */
+  uInt d;               /* distance back to copy from */
+  Bytef *r;             /* copy source pointer */
+
+  /* load input, output, bit values */
+  LOAD
+
+  /* initialize masks */
+  ml = inflate_mask[bl];
+  md = inflate_mask[bd];
+
+  /* do until not enough input or output space for fast loop */
+  do {                          /* assume called with m >= 258 && n >= 10 */
+    /* get literal/length code */
+    GRABBITS(20)                /* max bits for literal/length code */
+    if ((e = (t = tl + ((uInt)b & ml))->exop) == 0)
+    {
+      DUMPBITS(t->bits)
+      Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+                "inflate:         * literal '%c'\n" :
+                "inflate:         * literal 0x%02x\n", t->base));
+      *q++ = (Byte)t->base;
+      m--;
+      continue;
+    }
+    do {
+      DUMPBITS(t->bits)
+      if (e & 16)
+      {
+        /* get extra bits for length */
+        e &= 15;
+        c = t->base + ((uInt)b & inflate_mask[e]);
+        DUMPBITS(e)
+        Tracevv((stderr, "inflate:         * length %u\n", c));
+
+        /* decode distance base of block to copy */
+        GRABBITS(15);           /* max bits for distance code */
+        e = (t = td + ((uInt)b & md))->exop;
+        do {
+          DUMPBITS(t->bits)
+          if (e & 16)
+          {
+            /* get extra bits to add to distance base */
+            e &= 15;
+            GRABBITS(e)         /* get extra bits (up to 13) */
+            d = t->base + ((uInt)b & inflate_mask[e]);
+            DUMPBITS(e)
+            Tracevv((stderr, "inflate:         * distance %u\n", d));
+
+            /* do the copy */
+            m -= c;
+            if ((uInt)(q - s->window) >= d)     /* offset before dest */
+            {                                   /*  just copy */
+              r = q - d;
+              *q++ = *r++;  c--;        /* minimum count is three, */
+              *q++ = *r++;  c--;        /*  so unroll loop a little */
+            }
+            else                        /* else offset after destination */
+            {
+              e = d - (q - s->window);  /* bytes from offset to end */
+              r = s->end - e;           /* pointer to offset */
+              if (c > e)                /* if source crosses, */
+              {
+                c -= e;                 /* copy to end of window */
+                do {
+                  *q++ = *r++;
+                } while (--e);
+                r = s->window;          /* copy rest from start of window */
+              }
+            }
+            do {                        /* copy all or what's left */
+              *q++ = *r++;
+            } while (--c);
+            break;
+          }
+          else if ((e & 64) == 0)
+            e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop;
+          else
+          {
+            z->msg = "invalid distance code";
+            UNGRAB
+            UPDATE
+            return Z_DATA_ERROR;
+          }
+        } while (1);
+        break;
+      }
+      if ((e & 64) == 0)
+      {
+        if ((e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop) == 0)
+        {
+          DUMPBITS(t->bits)
+          Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+                    "inflate:         * literal '%c'\n" :
+                    "inflate:         * literal 0x%02x\n", t->base));
+          *q++ = (Byte)t->base;
+          m--;
+          break;
+        }
+      }
+      else if (e & 32)
+      {
+        Tracevv((stderr, "inflate:         * end of block\n"));
+        UNGRAB
+        UPDATE
+        return Z_STREAM_END;
+      }
+      else
+      {
+        z->msg = "invalid literal/length code";
+        UNGRAB
+        UPDATE
+        return Z_DATA_ERROR;
+      }
+    } while (1);
+  } while (m >= 258 && n >= 10);
+
+  /* not enough input or output--restore pointers and return */
+  UNGRAB
+  UPDATE
+  return Z_OK;
+}
+
+
+/*+++++*/
+/* zutil.c -- target dependent utility functions for the compression library
+ * Copyright (C) 1995 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* From: zutil.c,v 1.8 1995/05/03 17:27:12 jloup Exp */
+
+char *zlib_version = ZLIB_VERSION;
+
+char *z_errmsg[] = {
+"stream end",          /* Z_STREAM_END    1 */
+"",                    /* Z_OK            0 */
+"file error",          /* Z_ERRNO        (-1) */
+"stream error",        /* Z_STREAM_ERROR (-2) */
+"data error",          /* Z_DATA_ERROR   (-3) */
+"insufficient memory", /* Z_MEM_ERROR    (-4) */
+"buffer error",        /* Z_BUF_ERROR    (-5) */
+""};
+
+
+/*+++++*/
+/* adler32.c -- compute the Adler-32 checksum of a data stream
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* From: adler32.c,v 1.6 1995/05/03 17:27:08 jloup Exp */
+
+#define BASE 65521L /* largest prime smaller than 65536 */
+#define NMAX 5552
+/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+
+#define DO1(buf)  {s1 += *buf++; s2 += s1;}
+#define DO2(buf)  DO1(buf); DO1(buf);
+#define DO4(buf)  DO2(buf); DO2(buf);
+#define DO8(buf)  DO4(buf); DO4(buf);
+#define DO16(buf) DO8(buf); DO8(buf);
+
+/* ========================================================================= */
+uLong adler32(adler, buf, len)
+    uLong adler;
+    Bytef *buf;
+    uInt len;
+{
+    unsigned long s1 = adler & 0xffff;
+    unsigned long s2 = (adler >> 16) & 0xffff;
+    int k;
+
+    if (buf == Z_NULL) return 1L;
+
+    while (len > 0) {
+        k = len < NMAX ? len : NMAX;
+        len -= k;
+        while (k >= 16) {
+            DO16(buf);
+            k -= 16;
+        }
+        if (k != 0) do {
+            DO1(buf);
+        } while (--k);
+        s1 %= BASE;
+        s2 %= BASE;
+    }
+    return (s2 << 16) | s1;
+}
diff --git a/tools/Makefile b/tools/Makefile
new file mode 100644 (file)
index 0000000..e94e01b
--- /dev/null
@@ -0,0 +1,79 @@
+#
+# (C) Copyright 2000
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+BINS   = img2srec mkimage
+
+OBJS   = img2srec.o mkimage.o crc32.o
+
+#
+# Use native tools and options
+#
+CPPFLAGS   = -Wall -pedantic -O
+CFLAGS     = $(CPPFLAGS)
+CC        = $(HOSTCC)
+MAKEDEPEND = makedepend
+
+all:   $(BINS)
+
+img2srec:      img2srec.o
+               $(CC) $(CFLAGS) -s -o $@ $^
+
+mkimage:       mkimage.o crc32.o
+               $(CC) -g $(CFLAGS) -I../include -o $@ $^
+       
+crc32.o:       crc32.c
+               $(CC) -g $(CFLAGS) -I../include -c $^
+       
+mkimage.o:     mkimage.c
+               $(CC) -g $(CFLAGS) -I../include -c $^
+
+clean:
+       rm -f $(OBJS)
+
+distclean:     clean
+       rm -f $(BINS) core *.bak
+
+#########################################################################
+
+depend dep:
+       $(MAKEDEPEND) -- $(CPPFLAGS) -- $(OBJS:.o=.c)
+
+#########################################################################
+
+# DO NOT DELETE
+
+img2srec.o: /usr/lib/gcc-lib/i386-redhat-linux/egcs-2.91.66/include/stddef.h
+img2srec.o: /usr/include/stdio.h /usr/include/features.h
+img2srec.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h
+img2srec.o: /usr/lib/gcc-lib/i386-redhat-linux/egcs-2.91.66/include/stdarg.h
+img2srec.o: /usr/include/bits/types.h /usr/include/libio.h
+img2srec.o: /usr/include/_G_config.h /usr/include/bits/stdio_lim.h
+img2srec.o: /usr/include/stdlib.h /usr/include/sys/types.h
+img2srec.o: /usr/include/time.h /usr/include/endian.h
+img2srec.o: /usr/include/bits/endian.h /usr/include/sys/select.h
+img2srec.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+img2srec.o: /usr/include/sys/sysmacros.h /usr/include/alloca.h
+img2srec.o: /usr/include/ctype.h /usr/include/string.h /usr/include/elf.h
+img2srec.o: /usr/include/stdint.h
diff --git a/tools/crc32.c b/tools/crc32.c
new file mode 100644 (file)
index 0000000..5298463
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * This file is derived from crc32.c from the zlib-1.1.3 distribution
+ * by Jean-loup Gailly and Mark Adler.
+ */
+
+/* crc32.c -- compute the CRC-32 of a data stream
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* @(#) $Id: crc32.c,v 1.1 2000/07/18 08:54:27 wd Exp $ */
+
+#include "zlib.h"
+
+#define local static
+#define ZEXPORT        /* empty */
+unsigned long crc32 (unsigned long, const unsigned char *, unsigned int);
+
+#ifdef DYNAMIC_CRC_TABLE
+
+local int crc_table_empty = 1;
+local uLongf crc_table[256];
+local void make_crc_table OF((void));
+
+/*
+  Generate a table for a byte-wise 32-bit CRC calculation on the polynomial:
+  x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.
+
+  Polynomials over GF(2) are represented in binary, one bit per coefficient,
+  with the lowest powers in the most significant bit.  Then adding polynomials
+  is just exclusive-or, and multiplying a polynomial by x is a right shift by
+  one.  If we call the above polynomial p, and represent a byte as the
+  polynomial q, also with the lowest power in the most significant bit (so the
+  byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,
+  where a mod b means the remainder after dividing a by b.
+
+  This calculation is done using the shift-register method of multiplying and
+  taking the remainder.  The register is initialized to zero, and for each
+  incoming bit, x^32 is added mod p to the register if the bit is a one (where
+  x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by
+  x (which is shifting right by one and adding x^32 mod p if the bit shifted
+  out is a one).  We start with the highest power (least significant bit) of
+  q and repeat for all eight bits of q.
+
+  The table is simply the CRC of all possible eight bit values.  This is all
+  the information needed to generate CRC's on data a byte at a time for all
+  combinations of CRC register values and incoming bytes.
+*/
+local void make_crc_table()
+{
+  uLong c;
+  int n, k;
+  uLong poly;            /* polynomial exclusive-or pattern */
+  /* terms of polynomial defining this crc (except x^32): */
+  static const Byte p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
+
+  /* make exclusive-or pattern from polynomial (0xedb88320L) */
+  poly = 0L;
+  for (n = 0; n < sizeof(p)/sizeof(Byte); n++)
+    poly |= 1L << (31 - p[n]);
+  for (n = 0; n < 256; n++)
+  {
+    c = (uLong)n;
+    for (k = 0; k < 8; k++)
+      c = c & 1 ? poly ^ (c >> 1) : c >> 1;
+    crc_table[n] = c;
+  }
+  crc_table_empty = 0;
+}
+#else
+/* ========================================================================
+ * Table of CRC-32's of all single-byte values (made by make_crc_table)
+ */
+local const uLongf crc_table[256] = {
+  0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+  0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+  0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+  0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+  0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+  0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+  0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+  0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+  0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+  0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+  0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+  0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+  0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+  0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+  0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+  0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+  0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+  0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+  0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+  0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+  0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+  0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+  0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+  0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+  0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+  0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+  0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+  0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+  0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+  0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+  0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+  0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+  0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+  0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+  0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+  0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+  0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+  0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+  0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+  0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+  0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+  0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+  0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+  0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+  0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+  0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+  0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+  0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+  0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+  0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+  0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+  0x2d02ef8dL
+};
+#endif
+
+#if 0
+/* =========================================================================
+ * This function can be used by asm versions of crc32()
+ */
+const uLongf * ZEXPORT get_crc_table()
+{
+#ifdef DYNAMIC_CRC_TABLE
+  if (crc_table_empty) make_crc_table();
+#endif
+  return (const uLongf *)crc_table;
+}
+#endif
+
+/* ========================================================================= */
+#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8);
+#define DO2(buf)  DO1(buf); DO1(buf);
+#define DO4(buf)  DO2(buf); DO2(buf);
+#define DO8(buf)  DO4(buf); DO4(buf);
+
+/* ========================================================================= */
+uLong ZEXPORT crc32(crc, buf, len)
+    uLong crc;
+    const Bytef *buf;
+    uInt len;
+{
+    if (buf == Z_NULL) return 0L;
+#ifdef DYNAMIC_CRC_TABLE
+    if (crc_table_empty)
+      make_crc_table();
+#endif
+    crc = crc ^ 0xffffffffL;
+    while (len >= 8)
+    {
+      DO8(buf);
+      len -= 8;
+    }
+    if (len) do {
+      DO1(buf);
+    } while (--len);
+    return crc ^ 0xffffffffL;
+}
diff --git a/tools/img2srec.c b/tools/img2srec.c
new file mode 100644 (file)
index 0000000..028c04b
--- /dev/null
@@ -0,0 +1,411 @@
+/*************************************************************************
+|  COPYRIGHT (c) 2000 BY ABATRON AG
+|*************************************************************************
+|
+|  PROJECT NAME: Linux Image to S-record Conversion Utility
+|  FILENAME    : img2srec.c
+|
+|  COMPILER    : GCC
+|
+|  TARGET OS   : LINUX / UNIX
+|  TARGET HW   : -
+|
+|  PROGRAMMER  : Abatron / RD
+|  CREATION    : 07.07.00
+|
+|*************************************************************************
+|
+|  DESCRIPTION :
+|
+|  Utility to convert a Linux Boot Image to S-record:
+|  ==================================================
+|
+|  This command line utility can be used to convert a Linux boot image
+|  (zimage.initrd) to S-Record format used for flash programming.
+|  This conversion takes care of the special sections "IMAGE" and INITRD".
+|
+|  img2srec [-o offset] image > image.srec
+|
+|
+|  Build the utility:
+|  ==================
+|
+|  To build the utility use GCC as follows:
+|
+|  gcc img2srec.c -o img2srec
+|
+|
+|*************************************************************************
+|
+|
+|  UPDATES     :
+|
+|  DATE      NAME  CHANGES
+|  -----------------------------------------------------------
+|  Latest update
+|
+|  07.07.00  aba   Initial release
+|
+|*************************************************************************/
+
+/*************************************************************************
+|  INCLUDES
+|*************************************************************************/
+
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <elf.h>
+
+extern int errno;
+
+/*************************************************************************
+|  DEFINES
+|*************************************************************************/
+
+#define FALSE           0
+#define TRUE            1
+
+/*************************************************************************
+|  MACROS
+|*************************************************************************/
+
+/*************************************************************************
+|  TYPEDEFS
+|*************************************************************************/
+
+typedef uint8_t   CHAR;
+typedef uint8_t   BYTE;
+typedef uint16_t  WORD;
+typedef uint32_t  DWORD;
+typedef int       BOOL;
+
+/*************************************************************************
+|  LOCALS
+|*************************************************************************/
+
+/*************************************************************************
+|  PROTOTYPES
+|*************************************************************************/
+
+static char *ExtractHex(DWORD *value, char *getPtr);
+static char *ExtractDecimal(DWORD *value, char *getPtr);
+static void ExtractNumber(DWORD *value, char *getPtr);
+static BYTE *ExtractWord(WORD *value, BYTE *buffer);
+static BYTE *ExtractLong(DWORD *value, BYTE *buffer);
+static BYTE *ExtractBlock(WORD count, BYTE *data, BYTE *buffer);
+static char *WriteHex(char *pa, BYTE value, WORD *pCheckSum);
+static char *BuildSRecord(char *pa, WORD sType, DWORD addr,
+                         const BYTE *data, int nCount);
+static void ConvertELF(char *fileName, DWORD loadOffset);
+int main(int argc, char *argv[]);
+
+/*************************************************************************
+|  FUNCTIONS
+|*************************************************************************/
+
+static char* ExtractHex (DWORD* value,  char* getPtr)
+{
+  DWORD num;
+  DWORD digit;
+  BYTE  c;
+
+  while (*getPtr == ' ') getPtr++;
+  num = 0;
+  for (;;) {
+    c = *getPtr;
+    if      ((c >= '0') && (c <= '9')) digit = (DWORD)(c - '0');
+    else if ((c >= 'A') && (c <= 'F')) digit = (DWORD)(c - 'A' + 10);
+    else if ((c >= 'a') && (c <= 'f')) digit = (DWORD)(c - 'a' + 10);
+    else break;
+    num <<= 4;
+    num += digit;
+    getPtr++;
+  } /* for */
+  *value = num;
+  return getPtr;
+} /* ExtractHex */
+
+static char* ExtractDecimal (DWORD* value,  char* getPtr)
+{
+  DWORD num;
+  DWORD digit;
+  BYTE  c;
+
+  while (*getPtr == ' ') getPtr++;
+  num = 0;
+  for (;;) {
+    c = *getPtr;
+    if      ((c >= '0') && (c <= '9')) digit = (DWORD)(c - '0');
+    else break;
+    num *= 10;
+    num += digit;
+    getPtr++;
+  } /* for */
+  *value = num;
+  return getPtr;
+} /* ExtractDecimal */
+
+
+static void ExtractNumber (DWORD* value,  char* getPtr)
+{
+  BOOL  neg = FALSE;;
+
+  while (*getPtr == ' ') getPtr++;
+  if (*getPtr == '-') {
+    neg = TRUE;
+    getPtr++;
+  } /* if */
+  if ((*getPtr == '0') && ((*(getPtr+1) == 'x') || (*(getPtr+1) == 'X'))) {
+    getPtr +=2;
+    (void)ExtractHex(value, getPtr);
+  } /* if */
+  else {
+    (void)ExtractDecimal(value, getPtr);
+  } /* else */
+  if (neg) *value = -(*value);
+} /* ExtractNumber */
+
+
+static BYTE* ExtractWord(WORD* value, BYTE* buffer)
+{
+  WORD x;
+  x = (WORD)*buffer++;
+  x = (x<<8) + (WORD)*buffer++;
+  *value = x;
+  return buffer;
+} /* ExtractWord */
+
+
+static BYTE* ExtractLong(DWORD* value, BYTE* buffer)
+{
+  DWORD x;
+  x = (DWORD)*buffer++;
+  x = (x<<8) + (DWORD)*buffer++;
+  x = (x<<8) + (DWORD)*buffer++;
+  x = (x<<8) + (DWORD)*buffer++;
+  *value = x;
+  return buffer;
+} /* ExtractLong */
+
+
+static BYTE* ExtractBlock(WORD count, BYTE* data, BYTE* buffer)
+{
+  while (count--) *data++ = *buffer++;
+  return buffer;
+} /* ExtractBlock */
+
+
+static char* WriteHex(char* pa, BYTE value, WORD* pCheckSum)
+{
+  WORD  temp;
+
+  static  char ByteToHex[] = "0123456789ABCDEF";
+
+  *pCheckSum += value;
+  temp  = value / 16;
+  *pa++ = ByteToHex[temp];
+  temp  = value % 16;
+  *pa++ = ByteToHex[temp];
+  return pa;
+}
+
+
+static char* BuildSRecord(char* pa, WORD sType, DWORD addr,
+                         const BYTE* data, int nCount)
+{
+  WORD  addrLen;
+  WORD  sRLen;
+  WORD  checkSum;
+  WORD  i;
+
+  switch (sType) {
+  case 0:
+  case 1:
+  case 9:
+    addrLen = 2;
+    break;
+  case 2:
+  case 8:
+    addrLen = 3;
+    break;
+  case 3:
+  case 7:
+    addrLen = 4;
+    break;
+  default:
+    return pa;
+  } /* switch */
+
+  *pa++ = 'S';
+  *pa++ = (char)(sType + '0');
+  sRLen = addrLen + nCount + 1;
+  checkSum = 0;
+  pa = WriteHex(pa, (BYTE)sRLen, &checkSum);
+
+  /* Write address field */
+  for (i = 1; i <= addrLen; i++) {
+    pa = WriteHex(pa, (BYTE)(addr >> (8 * (addrLen - i))), &checkSum);
+  } /* for */
+
+  /* Write code/data fields */
+  for (i = 0; i < nCount; i++) {
+    pa = WriteHex(pa, *data++, &checkSum);
+  } /* for */
+
+  /* Write checksum field */
+  checkSum = ~checkSum;
+  pa = WriteHex(pa, (BYTE)checkSum, &checkSum);
+  *pa++ = '\0';
+  return pa;
+}
+
+
+static void ConvertELF(char* fileName, DWORD loadOffset)
+{
+  FILE*         file;
+  int           i;
+  int           rxCount;
+  BYTE          rxBlock[1024];
+  DWORD         loadSize;
+  DWORD         firstAddr;
+  DWORD         loadAddr;
+  DWORD         loadDiff = 0;
+  Elf32_Ehdr    elfHeader;
+  Elf32_Shdr    sectHeader[32];
+  BYTE*         getPtr;
+  char          srecLine[128];
+  char         *hdr_name;
+
+
+  /* open file */
+  if ((file = fopen(fileName,"rb")) == NULL) {
+    fprintf (stderr, "Can't open %s: %s\n", fileName, strerror(errno));
+    return;
+  } /* if */
+
+  /* read ELF header */
+  rxCount = fread(rxBlock, 1, sizeof elfHeader, file);
+  getPtr = ExtractBlock(sizeof elfHeader.e_ident, elfHeader.e_ident, rxBlock);
+  getPtr = ExtractWord(&elfHeader.e_type, getPtr);
+  getPtr = ExtractWord(&elfHeader.e_machine, getPtr);
+  getPtr = ExtractLong(&elfHeader.e_version, getPtr);
+  getPtr = ExtractLong(&elfHeader.e_entry, getPtr);
+  getPtr = ExtractLong(&elfHeader.e_phoff, getPtr);
+  getPtr = ExtractLong(&elfHeader.e_shoff, getPtr);
+  getPtr = ExtractLong(&elfHeader.e_flags, getPtr);
+  getPtr = ExtractWord(&elfHeader.e_ehsize, getPtr);
+  getPtr = ExtractWord(&elfHeader.e_phentsize, getPtr);
+  getPtr = ExtractWord(&elfHeader.e_phnum, getPtr);
+  getPtr = ExtractWord(&elfHeader.e_shentsize, getPtr);
+  getPtr = ExtractWord(&elfHeader.e_shnum, getPtr);
+  getPtr = ExtractWord(&elfHeader.e_shstrndx, getPtr);
+  if (    (rxCount              != sizeof elfHeader)
+       || (elfHeader.e_ident[0] != ELFMAG0)
+       || (elfHeader.e_ident[1] != ELFMAG1)
+       || (elfHeader.e_ident[2] != ELFMAG2)
+       || (elfHeader.e_ident[3] != ELFMAG3)
+       || (elfHeader.e_type     != ET_EXEC)
+     ) {
+    fclose(file);
+    fprintf (stderr, "*** illegal file format\n");
+    return;
+  } /* if */
+
+  /* read all section headers */
+  fseek(file, elfHeader.e_shoff, SEEK_SET);
+  for (i = 0; i < elfHeader.e_shnum; i++) {
+    rxCount = fread(rxBlock, 1, sizeof sectHeader[0], file);
+    getPtr = ExtractLong(&sectHeader[i].sh_name, rxBlock);
+    getPtr = ExtractLong(&sectHeader[i].sh_type, getPtr);
+    getPtr = ExtractLong(&sectHeader[i].sh_flags, getPtr);
+    getPtr = ExtractLong(&sectHeader[i].sh_addr, getPtr);
+    getPtr = ExtractLong(&sectHeader[i].sh_offset, getPtr);
+    getPtr = ExtractLong(&sectHeader[i].sh_size, getPtr);
+    getPtr = ExtractLong(&sectHeader[i].sh_link, getPtr);
+    getPtr = ExtractLong(&sectHeader[i].sh_info, getPtr);
+    getPtr = ExtractLong(&sectHeader[i].sh_addralign, getPtr);
+    getPtr = ExtractLong(&sectHeader[i].sh_entsize, getPtr);
+    if (rxCount != sizeof sectHeader[0]) {
+      fclose(file);
+      fprintf (stderr, "*** illegal file format\n");
+      return;
+    } /* if */
+  } /* for */
+
+  if ((hdr_name = strrchr(fileName, '/')) == NULL) {
+    hdr_name = fileName;
+  } else {
+    ++hdr_name;
+  }
+  /* write start record */
+  (void)BuildSRecord(srecLine, 0, 0, (BYTE *)hdr_name, strlen(hdr_name));
+  printf("%s\r\n",srecLine);
+
+  /* write data records */
+  firstAddr = ~0;
+  loadAddr  =  0;
+  for (i = 0; i < elfHeader.e_shnum; i++) {
+    if (    (sectHeader[i].sh_type == SHT_PROGBITS)
+         && (sectHeader[i].sh_size != 0)
+         ) {
+      loadSize = sectHeader[i].sh_size;
+      if (sectHeader[i].sh_flags != 0) {
+        loadAddr = sectHeader[i].sh_addr;
+        loadDiff = loadAddr - sectHeader[i].sh_offset;
+      } /* if */
+      else {
+        loadAddr = sectHeader[i].sh_offset + loadDiff;
+      } /* else */
+
+      if (loadAddr < firstAddr)
+        firstAddr = loadAddr;
+
+      /* build s-records */
+      loadSize = sectHeader[i].sh_size;
+      fseek(file, sectHeader[i].sh_offset, SEEK_SET);
+      while (loadSize) {
+        rxCount = fread(rxBlock, 1, (loadSize > 32) ? 32 : loadSize, file);
+        if (rxCount < 0) {
+          fclose(file);
+          fprintf (stderr, "*** illegal file format\n");
+        return;
+        } /* if */
+        (void)BuildSRecord(srecLine, 3, loadAddr + loadOffset, rxBlock, rxCount);
+        loadSize -= rxCount;
+        loadAddr += rxCount;
+        printf("%s\r\n",srecLine);
+      } /* while */
+    } /* if */
+  } /* for */
+
+  /* add end record */
+  (void)BuildSRecord(srecLine, 7, firstAddr + loadOffset, 0, 0);
+  printf("%s\r\n",srecLine);
+  fclose(file);
+} /* ConvertELF */
+
+
+/*************************************************************************
+|  MAIN
+|*************************************************************************/
+
+int main( int argc, char *argv[ ])
+{
+  DWORD offset;
+
+  if (argc == 2) {
+    ConvertELF(argv[1], 0);
+  } /* if */
+  else if ((argc == 4) && (strcmp(argv[1], "-o") == 0)) {
+    ExtractNumber(&offset, argv[2]);
+    ConvertELF(argv[3], offset);
+  } /* if */
+  else {
+    fprintf (stderr, "Usage: img2srec [-o offset] <image>\n");
+  } /* if */
+
+  return 0;
+} /* main */
diff --git a/tools/mkimage.c b/tools/mkimage.c
new file mode 100644 (file)
index 0000000..39d0bf4
--- /dev/null
@@ -0,0 +1,470 @@
+/*
+ * (C) Copyright 2000
+ * DENX Software Engineering
+ * Wolfgang Denk, wd@denx.de
+ * All rights reserved.
+ *     
+ * $Date: 2000/07/18 08:54:27 $
+ * $Revision: 1.1 $
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netinet/in.h>                /* for host / network byte order conversions    */
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <image.h>
+
+extern int errno;
+
+char *cmdname;
+
+extern unsigned long crc32 (unsigned long crc, const char *buf, unsigned int len);
+
+typedef struct table_entry {
+       int     val;            /* as defined in image.h        */
+       char    *sname;         /* short (input) name           */
+       char    *lname;         /* long (output) name           */
+} table_entry_t;
+
+table_entry_t arch_name[] = {
+    {  IH_CPU_INVALID, "",             "Invalid CPU",          },
+    {  IH_CPU_ALPHA,   "alpha",        "Alpha",                },
+    {  IH_CPU_ARM,     "arm",          "ARM",                  },
+    {  IH_CPU_I386,    "x86",          "Intel x86",            },
+    {  IH_CPU_IA64,    "ia64",         "IA64",                 },
+    {  IH_CPU_MIPS,    "mips",         "MIPS",                 },
+    {  IH_CPU_MIPS64,  "mips64",       "MIPS 64 Bit",          },
+    {  IH_CPU_PPC,     "ppc",          "PowerPC",              },
+    {  IH_CPU_S390,    "s390",         "IBM S390",             },
+    {  IH_CPU_SH,      "sh",           "SuperH",               },
+    {  IH_CPU_SPARC,   "sparc",        "SPARC",                },
+    {  IH_CPU_SPARC64, "sparc64",      "SPARC 64 Bit",         },
+    {  -1,             "",             "",                     },
+};
+
+table_entry_t os_name[] = {
+    {  IH_OS_INVALID,  "",             "Invalid OS",           },
+    {  IH_OS_OPENBSD,  "openbsd",      "OpenBSD",              },
+    {  IH_OS_NETBSD,   "netbsd",       "NetBSD",               },
+    {  IH_OS_FREEBSD,  "freebsd",      "FreeBSD",              },
+    {  IH_OS_4_4BSD,   "4_4bsd",       "4_4BSD",               },
+    {  IH_OS_LINUX,    "linux",        "Linux",                },
+    {  IH_OS_SVR4,     "svr4",         "SVR4",                 },
+    {  IH_OS_ESIX,     "esix",         "Esix",                 },
+    {  IH_OS_SOLARIS,  "solaris",      "Solaris",              },
+    {  IH_OS_IRIX,     "irix",         "Irix",                 },
+    {  IH_OS_SCO,      "sco",          "SCO",                  },
+    {  IH_OS_DELL,     "dell",         "Dell",                 },
+    {  IH_OS_NCR,      "ncr",          "NCR",                  },
+    {  IH_OS_LYNXOS,   "lynxos",       "LynxOS",               },
+    {  IH_OS_VXWORKS,  "vxworks",      "VxWorks",              },
+    {  IH_OS_PSOS,     "psos",         "pSOS",                 },
+    {  IH_OS_QNX,      "qnx",          "QNX",                  },
+    {  -1,             "",             "",                     },
+};
+
+table_entry_t type_name[] = {
+    {  IH_TYPE_INVALID,    "",           "Invalid Image",      },
+    {  IH_TYPE_STANDALONE, "standalone", "Standalone Program", },
+    {  IH_TYPE_KERNEL,     "kernel",     "Kernel Image",       },
+    {  IH_TYPE_RAMDISK,    "ramdisk",    "RAMDisk Image",      },
+    {  -1,                 "",           "",                   },
+};
+
+table_entry_t comp_name[] = {
+    {  IH_COMP_NONE,   "none",         "uncompressed",         },
+    {  IH_COMP_GZIP,   "gzip",         "gzip compressed",      },
+    {  IH_COMP_BZIP2,  "bzip2",        "bzip2 compressed",     },
+    {  -1,             "",             "",                     },
+};
+
+static void    usage   (void);
+static void    print_header (image_header_t *);
+static void    print_type (image_header_t *);
+static char    *put_table_entry (table_entry_t *, char *, int);
+static char    *put_arch (int);
+static char    *put_type (int);
+static char    *put_os   (int);
+static char    *put_comp (int);
+static int     get_table_entry (table_entry_t *, char *, char *);
+static int     get_arch(char *);
+static int     get_comp(char *);
+static int     get_os  (char *);
+static int     get_type(char *);
+
+
+char   *datafile;
+char   *imagefile;
+
+int dflag    = 0;
+int eflag    = 0;
+int lflag    = 0;
+int opt_os   = IH_OS_LINUX;
+int opt_arch = IH_CPU_PPC;
+int opt_type = IH_TYPE_KERNEL;
+int opt_comp = IH_COMP_GZIP;
+
+image_header_t header;
+image_header_t *hdr = &header;
+
+int
+main (int argc, char **argv)
+{
+       int ifd, dfd;
+       uint32_t checksum;
+       uint32_t addr;
+       uint32_t ep;
+       struct stat sbuf;
+       unsigned char *ptr;
+       char *name = "";
+
+       cmdname = *argv;
+
+       addr = ep = 0;
+
+       while (--argc > 0 && **++argv == '-') {
+               while (*++*argv) {
+                       switch (**argv) {
+                       case 'l':
+                               lflag = 1;
+                               break;
+                       case 'A':
+                               if ((argc-- <= 0) ||
+                                   (opt_arch = get_arch(*++argv)) < 0)
+                                       usage ();
+                               goto NXTARG;
+                       case 'C':
+                               if ((argc-- <= 0) ||
+                                   (opt_comp = get_comp(*++argv)) < 0)
+                                       usage ();
+                               goto NXTARG;
+                       case 'O':
+                               if ((argc-- <= 0) ||
+                                   (opt_os = get_os(*++argv)) < 0)
+                                       usage ();
+                               goto NXTARG;
+                       case 'T':
+                               if ((argc-- <= 0) ||
+                                   (opt_type = get_type(*++argv)) < 0)
+                                       usage ();
+                               goto NXTARG;
+
+                       case 'a':
+                               if (argc-- <= 0)
+                                       usage ();
+                               addr = strtol (*++argv, (char **)&ptr, 16);
+                               if (*ptr) {
+                                       fprintf (stderr,
+                                               "%s: invalid load address %s\n",
+                                               cmdname, *argv);
+                                       exit (EXIT_FAILURE);
+                               }
+                               goto NXTARG;
+                       case 'd':
+                               if (argc-- <= 0)
+                                       usage ();
+                               datafile = *++argv;
+                               dflag = 1;
+                               goto NXTARG;
+                       case 'e':
+                               if (argc-- <= 0)
+                                       usage ();
+                               ep = strtol (*++argv, (char **)&ptr, 16);
+                               if (*ptr) {
+                                       fprintf (stderr,
+                                               "%s: invalid entry point %s\n",
+                                               cmdname, *argv);
+                                       exit (EXIT_FAILURE);
+                               }
+                               eflag = 1;
+                               goto NXTARG;
+                       case 'n':
+                               if (argc-- <= 0)
+                                       usage ();
+                               name = *++argv;
+                               goto NXTARG;
+                       default:
+                               usage ();
+                       }
+               }
+NXTARG:                ;
+       }
+
+       if ((argc != 1) || ((lflag ^ dflag) == 0))
+               usage();
+
+       if (!eflag)
+               ep = addr;
+
+       imagefile = *argv;
+
+       if ((ifd = open(imagefile, lflag ? O_RDONLY : O_WRONLY | O_CREAT)) < 0) {
+               fprintf (stderr, "%s: Can't open %s: %s\n",
+                       cmdname, imagefile, strerror(errno));
+               exit (EXIT_FAILURE);
+       }
+
+       if (lflag) {
+               int len;
+               char *data;
+               /*
+                * list header information of existing image
+                */
+               if (fstat(ifd, &sbuf) < 0) {
+                       fprintf (stderr, "%s: Can't stat %s: %s\n",
+                               cmdname, imagefile, strerror(errno));
+                       exit (EXIT_FAILURE);
+               }
+
+               if (sbuf.st_size < sizeof(image_header_t)) {
+                       fprintf (stderr,
+                               "%s: Bad size: \"%s\" is no valid image\n",
+                               cmdname, imagefile);
+                       exit (EXIT_FAILURE);
+               }
+
+               ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, ifd, 0);
+               if ((caddr_t)ptr == (caddr_t)-1) {
+                       fprintf (stderr, "%s: Can't read %s: %s\n",
+                               cmdname, imagefile, strerror(errno));
+                       exit (EXIT_FAILURE);
+               }
+
+                /*
+                 * create copy of header so that we can blank out the
+                 * checksum field for checking - this can't be done
+                 * on the PROT_READ mapped data.
+                */
+               memcpy (hdr, ptr, sizeof(image_header_t));
+
+               if (ntohl(hdr->ih_magic) != IH_MAGIC) {
+                       fprintf (stderr,
+                               "%s: Bad Magic Number: \"%s\" is no valid image\n",
+                               cmdname, imagefile);
+                       exit (EXIT_FAILURE);
+               }
+
+               data = (char *)hdr;
+               len  = sizeof(image_header_t);
+
+               checksum = ntohl(hdr->ih_hcrc);
+               hdr->ih_hcrc = htonl(0);        /* clear for re-calculation */
+
+               if (crc32 (0, data, len) != checksum) {
+                       fprintf (stderr,
+                               "*** Warning: \"%s\" has bad header checksum!\n",
+                               imagefile);
+               }
+
+               data = (char *)(ptr + sizeof(image_header_t));
+               len  = sbuf.st_size - sizeof(image_header_t) ;
+
+               if (crc32 (0, data, len) != ntohl(hdr->ih_dcrc)) {
+                       fprintf (stderr,
+                               "*** Warning: \"%s\" has corrupted data!\n",
+                               imagefile);
+               }
+
+               print_header (hdr);
+
+               (void) munmap(ptr, sbuf.st_size);
+               (void) close (ifd);
+
+               exit (EXIT_SUCCESS);
+       }
+
+       /*
+        * Must be -w then:
+        *
+        * Create new image file
+        */
+
+       if ((dfd = open(datafile, O_RDONLY)) < 0) {
+               fprintf (stderr, "%s: Can't open %s: %s\n",
+                       cmdname, datafile, strerror(errno));
+               exit (EXIT_FAILURE);
+       }
+
+       if (fstat(dfd, &sbuf) < 0) {
+               fprintf (stderr, "%s: Can't stat %s: %s\n",
+                       cmdname, datafile, strerror(errno));
+               exit (EXIT_FAILURE);
+       }
+
+       ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, dfd, 0);
+       if ((caddr_t)ptr == (caddr_t)-1) {
+               fprintf (stderr, "%s: Can't read %s: %s\n",
+                       cmdname, datafile, strerror(errno));
+               exit (EXIT_FAILURE);
+       }
+
+       checksum = crc32 (0, (const char *)ptr, sbuf.st_size);
+       
+       /* Build new header */
+       memset (hdr, 0, sizeof(image_header_t));
+       hdr->ih_magic = htonl(IH_MAGIC);
+       hdr->ih_time  = htonl(sbuf.st_mtime);
+       hdr->ih_size  = htonl(sbuf.st_size);
+       hdr->ih_load  = htonl(addr);
+       hdr->ih_ep    = htonl(ep);
+       hdr->ih_dcrc  = htonl(checksum);
+       hdr->ih_os    = opt_os;
+       hdr->ih_arch  = opt_arch;
+       hdr->ih_type  = opt_type;
+       hdr->ih_comp  = opt_comp;
+
+       strncpy(hdr->ih_name, name, IH_NMLEN);
+
+       checksum = crc32(0,(const char *)hdr,sizeof(image_header_t));
+
+       hdr->ih_hcrc = htonl(checksum);
+
+       if ((ifd = open(imagefile, O_WRONLY | O_CREAT)) < 0) {
+               fprintf (stderr, "%s: Can't open %s: %s\n",
+                       cmdname, imagefile, strerror(errno));
+               exit (EXIT_FAILURE);
+       }
+
+       if ((write(ifd, hdr, sizeof(image_header_t)) != sizeof(image_header_t)) ||
+           (write(ifd, ptr, sbuf.st_size) != sbuf.st_size) ) {
+               fprintf (stderr, "%s: Write error on %s: %s\n",
+                       cmdname, imagefile, strerror(errno));
+               exit (EXIT_FAILURE);
+       }
+
+       (void) munmap(ptr, sbuf.st_size);
+       (void) close (dfd);
+       if (close(ifd)) {
+               fprintf (stderr, "%s: Write error on %s: %s\n",
+                       cmdname, imagefile, strerror(errno));
+               exit (EXIT_FAILURE);
+       }
+
+       print_header (hdr);
+
+       exit (EXIT_SUCCESS);
+}
+
+void
+usage ()
+{
+       fprintf (stderr, "Usage: %s -l image\n"
+                        "          -l ==> list image header information\n"
+                        "       %s -A arch -O os -T type -C comp "
+                        "-a addr -e ep -n name -d data_file image\n"
+                        "          -A ==> set architecture to 'arch'\n"
+                        "          -O ==> set operating system to 'os'\n"
+                        "          -T ==> set image type to 'type'\n"
+                        "          -C ==> set compression type 'comp'\n"
+                        "          -a ==> set load address to 'addr' (hex)\n"
+                        "          -e ==> set entry point to 'ep' (hex)\n"
+                        "          -n ==> set image name to 'name'\n"
+                        "          -d ==> use image data from 'datafile'\n",
+               cmdname, cmdname);
+       exit (EXIT_FAILURE);
+}
+
+static void
+print_header (image_header_t *hdr)
+{
+       time_t timestamp;
+       uint32_t size;
+
+       timestamp = (time_t)ntohl(hdr->ih_time);
+       size = ntohl(hdr->ih_size);
+
+       printf ("Image Name:   %.*s\n", IH_NMLEN, hdr->ih_name);
+       printf ("Created:      %s", ctime(&timestamp));
+       printf ("Image Type:   "); print_type(hdr);
+       printf ("Data Size:    %d Bytes = %.2f kB = %.2f MB\n",
+               size, (double)size / 1.024e3, (double)size / 1.048576e6 );
+       printf ("Load Address: 0x%08x\n", ntohl(hdr->ih_load));
+       printf ("Entry Point:  0x%08x\n", ntohl(hdr->ih_ep));
+}
+
+
+static void
+print_type (image_header_t *hdr)
+{
+       printf ("%s %s %s (%s)\n",
+               put_arch (hdr->ih_arch),
+               put_os   (hdr->ih_os  ),
+               put_type (hdr->ih_type),
+               put_comp (hdr->ih_comp)
+       );
+}
+
+static char *put_arch (int arch)
+{
+       return (put_table_entry(arch_name, "Unknown Architecture", arch));
+}
+
+static char *put_os (int os)
+{
+       return (put_table_entry(os_name, "Unknown OS", os));
+}
+
+static char *put_type (int type)
+{
+       return (put_table_entry(type_name, "Unknown Image", type));
+}
+
+static char *put_comp (int comp)
+{
+       return (put_table_entry(comp_name, "Unknown Compression", comp));
+}
+
+static char *put_table_entry (table_entry_t *table, char *msg, int type)
+{
+       for (; table->val>=0; ++table) {
+               if (table->val == type)
+                       return (table->lname);
+       }
+       return (msg);
+}
+
+static int get_arch(char *name)
+{
+       return (get_table_entry(arch_name, "CPU", name));
+}
+
+
+static int get_comp(char *name)
+{
+       return (get_table_entry(comp_name, "Compression", name));
+}
+
+
+static int get_os (char *name)
+{
+       return (get_table_entry(os_name, "OS", name));
+}
+
+
+static int get_type(char *name)
+{
+       return (get_table_entry(type_name, "Image", name));
+}
+
+static int get_table_entry (table_entry_t *table, char *msg, char *name)
+{
+       table_entry_t *t;
+
+       for (t=table; t->val>=0; ++t) {
+               if (strcasecmp(t->sname, name) == 0)
+                       return (t->val);
+       }
+       fprintf (stderr, "\nInvalid %s Type - valid names are", msg);
+       for (t=table; t->val>=0; ++t) {
+               fprintf (stderr, "%c %s", (t == table) ? ':' : ',', t->sname);
+       }
+       fprintf (stderr, "\n");
+       return (-1);
+}
diff --git a/tqm8xx/Makefile b/tqm8xx/Makefile
new file mode 100644 (file)
index 0000000..af19d47
--- /dev/null
@@ -0,0 +1,97 @@
+#
+# (C) Copyright 2000
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB    = lib$(BOARD).a
+
+OBJS   = $(BOARD).o flash.o
+
+$(LIB):        $(OBJS)
+       $(AR) crv $@ $^
+
+clean:
+       rm -f $(SOBJS) $(OBJS)
+
+distclean:     clean
+       rm -f $(LIB) core *.bak
+
+#########################################################################
+
+depend dep:
+       $(MAKEDEPEND) -- $(CFLAGS) -- $(SOBJS:.o=.S) $(OBJS:.o=.c)
+
+#########################################################################
+
+# DO NOT DELETE
+
+tqm8xx.o: /home/wd/ppc/ppcboot/include/ppcboot.h
+tqm8xx.o: /home/wd/ppc/ppcboot/include/config.h
+tqm8xx.o: /LinuxPPC/CDK/include/linux/bitops.h
+tqm8xx.o: /LinuxPPC/CDK/include/asm/bitops.h
+tqm8xx.o: /LinuxPPC/CDK/include/asm/system.h
+tqm8xx.o: /LinuxPPC/CDK/include/linux/kdev_t.h
+tqm8xx.o: /LinuxPPC/CDK/include/asm/processor.h
+tqm8xx.o: /LinuxPPC/CDK/include/linux/config.h
+tqm8xx.o: /LinuxPPC/CDK/include/asm/ptrace.h
+tqm8xx.o: /LinuxPPC/CDK/include/asm/residual.h
+tqm8xx.o: /LinuxPPC/CDK/include/asm/pnp.h /LinuxPPC/CDK/include/asm/atomic.h
+tqm8xx.o: /LinuxPPC/CDK/include/asm/byteorder.h
+tqm8xx.o: /LinuxPPC/CDK/include/asm/types.h
+tqm8xx.o: /LinuxPPC/CDK/include/linux/byteorder/big_endian.h
+tqm8xx.o: /LinuxPPC/CDK/include/linux/byteorder/swab.h
+tqm8xx.o: /LinuxPPC/CDK/include/linux/byteorder/generic.h
+tqm8xx.o: /LinuxPPC/CDK/include/linux/types.h
+tqm8xx.o: /LinuxPPC/CDK/include/linux/posix_types.h
+tqm8xx.o: /LinuxPPC/CDK/include/linux/stddef.h
+tqm8xx.o: /LinuxPPC/CDK/include/asm/posix_types.h
+tqm8xx.o: /LinuxPPC/CDK/include/linux/string.h
+tqm8xx.o: /LinuxPPC/CDK/include/asm/string.h
+tqm8xx.o: /home/wd/ppc/ppcboot/include/asm/8xx_immap.h
+tqm8xx.o: /home/wd/ppc/ppcboot/include/flash.h
+tqm8xx.o: /home/wd/ppc/ppcboot/include/mpc8xx.h tqm8xx.h
+flash.o: /home/wd/ppc/ppcboot/include/ppcboot.h
+flash.o: /home/wd/ppc/ppcboot/include/config.h
+flash.o: /LinuxPPC/CDK/include/linux/bitops.h
+flash.o: /LinuxPPC/CDK/include/asm/bitops.h
+flash.o: /LinuxPPC/CDK/include/asm/system.h
+flash.o: /LinuxPPC/CDK/include/linux/kdev_t.h
+flash.o: /LinuxPPC/CDK/include/asm/processor.h
+flash.o: /LinuxPPC/CDK/include/linux/config.h
+flash.o: /LinuxPPC/CDK/include/asm/ptrace.h
+flash.o: /LinuxPPC/CDK/include/asm/residual.h /LinuxPPC/CDK/include/asm/pnp.h
+flash.o: /LinuxPPC/CDK/include/asm/atomic.h
+flash.o: /LinuxPPC/CDK/include/asm/byteorder.h
+flash.o: /LinuxPPC/CDK/include/asm/types.h
+flash.o: /LinuxPPC/CDK/include/linux/byteorder/big_endian.h
+flash.o: /LinuxPPC/CDK/include/linux/byteorder/swab.h
+flash.o: /LinuxPPC/CDK/include/linux/byteorder/generic.h
+flash.o: /LinuxPPC/CDK/include/linux/types.h
+flash.o: /LinuxPPC/CDK/include/linux/posix_types.h
+flash.o: /LinuxPPC/CDK/include/linux/stddef.h
+flash.o: /LinuxPPC/CDK/include/asm/posix_types.h
+flash.o: /LinuxPPC/CDK/include/linux/string.h
+flash.o: /LinuxPPC/CDK/include/asm/string.h
+flash.o: /home/wd/ppc/ppcboot/include/asm/8xx_immap.h
+flash.o: /home/wd/ppc/ppcboot/include/flash.h
+flash.o: /home/wd/ppc/ppcboot/include/mpc8xx.h
diff --git a/tqm8xx/config.mk b/tqm8xx/config.mk
new file mode 100644 (file)
index 0000000..9d6080b
--- /dev/null
@@ -0,0 +1,28 @@
+#
+# (C) Copyright 2000
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+#
+# TQM8xxL boards
+#
+
+TEXT_BASE = 0x40000000
diff --git a/tqm8xx/flash.c b/tqm8xx/flash.c
new file mode 100644 (file)
index 0000000..757900b
--- /dev/null
@@ -0,0 +1,693 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <ppcboot.h>
+#include <mpc8xx.h>
+
+flash_info_t   flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips        */
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+ulong flash_get_size (vu_long *addr, flash_info_t *info);
+
+int flash_write (uchar *, ulong, ulong);
+flash_info_t *addr2info (ulong);
+
+static int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt);
+static int write_word (flash_info_t *info, ulong dest, ulong data);
+static void flash_get_offsets (ulong base, flash_info_t *info);
+static int  flash_protect (int flag, ulong from, ulong to, flash_info_t *info);
+
+/*-----------------------------------------------------------------------
+ * Protection Flags:
+ */
+#define FLAG_PROTECT_SET       0x01
+#define FLAG_PROTECT_CLEAR     0x02
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+       volatile immap_t     *immap  = (immap_t *)CFG_IMMR;
+       volatile memctl8xx_t *memctl = &immap->im_memctl;
+       unsigned long size_b0, size_b1;
+       int i;
+
+       /* Init: no FLASHes known */
+       for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+               flash_info[i].flash_id = FLASH_UNKNOWN;
+       }
+
+       /* Static FLASH Bank configuration here - FIXME XXX */
+
+       size_b0 = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &flash_info[0]);
+
+       if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+               printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+                       size_b0, size_b0<<20);
+       }
+
+       size_b1 = flash_get_size((vu_long *)FLASH_BASE1_PRELIM, &flash_info[1]);
+
+       if (size_b1 > size_b0) {
+               printf ("## ERROR: "
+                       "Bank 1 (0x%08lx = %ld MB) > Bank 0 (0x%08lx = %ld MB)\n",
+                       size_b1, size_b1<<20,
+                       size_b0, size_b0<<20
+               );
+               flash_info[0].flash_id  = FLASH_UNKNOWN;
+               flash_info[1].flash_id  = FLASH_UNKNOWN;
+               flash_info[0].sector_count      = -1;
+               flash_info[1].sector_count      = -1;
+               flash_info[0].size              = 0;
+               flash_info[1].size              = 0;
+               return (0);
+       }
+
+       /* Remap FLASH according to real size */
+       memctl->memc_or0 = CFG_OR_TIMING_FLASH | (-size_b0 & 0xFFFF8000);
+       memctl->memc_br0 = (CFG_FLASH_BASE & BR_BA_MSK) | BR_MS_GPCM | BR_V;
+
+       /* Re-do sizing to get full correct info */
+       size_b0 = flash_get_size((vu_long *)CFG_FLASH_BASE, &flash_info[0]);
+
+       flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
+
+       /* monitor protection ON by default */
+       (void)flash_protect(FLAG_PROTECT_SET,
+                           CFG_FLASH_BASE,
+                           CFG_FLASH_BASE+CFG_MONITOR_LEN-1,
+                           &flash_info[0]);
+
+       if (size_b1) {
+               memctl->memc_or1 = CFG_OR_TIMING_FLASH | (-size_b1 & 0xFFFF8000);
+               memctl->memc_br1 = ((CFG_FLASH_BASE + size_b0) & BR_BA_MSK) |
+                                   BR_MS_GPCM | BR_V;
+
+               /* Re-do sizing to get full correct info */
+               size_b1 = flash_get_size((vu_long *)(CFG_FLASH_BASE + size_b0),
+                                         &flash_info[1]);
+
+               flash_get_offsets (CFG_FLASH_BASE + size_b0, &flash_info[1]);
+
+               /* monitor protection ON by default */
+               (void)flash_protect(FLAG_PROTECT_SET,
+                                   CFG_FLASH_BASE,
+                                   CFG_FLASH_BASE+CFG_MONITOR_LEN-1,
+                                   &flash_info[1]);
+       } else {
+               memctl->memc_br1 = 0;           /* invalidate bank */
+
+               flash_info[1].flash_id = FLASH_UNKNOWN;
+               flash_info[1].sector_count = -1;
+       }
+
+       flash_info[0].size = size_b0;
+       flash_info[1].size = size_b1;
+
+       return (size_b0 + size_b1);
+}
+
+/*-----------------------------------------------------------------------
+ * Check or set protection status for monitor sectors
+ *
+ * The monitor always occupies the _first_ part of the _first_ Flash bank.
+ */
+static int  flash_protect (int flag, ulong from, ulong to, flash_info_t *info)
+{
+       ulong b_end = info->start[0] + info->size - 1;  /* bank end address */
+       int rc    =  0;
+       int first = -1;
+       int last  = -1;
+       int i;
+
+       if (to < info->start[0]) {
+               return (0);
+       }
+
+       for (i=0; i<info->sector_count; ++i) {
+               ulong end;              /* last address in current sect */
+               short s_end;
+
+               s_end = info->sector_count - 1;
+
+               end = (i == s_end) ? b_end : info->start[i + 1] - 1;
+
+               if (from > end) {
+                       continue;
+               }
+               if (to < info->start[i]) {
+                       continue;
+               }
+
+               if (from == info->start[i]) {
+                       first = i;
+                       if (last < 0) {
+                               last = s_end;
+                       }
+               }
+               if (to  == end) {
+                       last  = i;
+                       if (first < 0) {
+                               first = 0;
+                       }
+               }
+       }
+
+       for (i=first; i<=last; ++i) {
+               if (flag & FLAG_PROTECT_CLEAR) {
+                       info->protect[i] = 0;
+               } else if (flag & FLAG_PROTECT_SET) {
+                       info->protect[i] = 1;
+               }
+               if (info->protect[i]) {
+                       rc = 1;
+               }
+       }
+       return (rc);
+}
+
+
+/*-----------------------------------------------------------------------
+ */
+static void flash_get_offsets (ulong base, flash_info_t *info)
+{
+       int i;
+
+       /* set up sector start adress table */
+       if (info->flash_id & FLASH_BTYPE) {
+               /* set sector offsets for bottom boot block type        */
+               info->start[0] = base + 0x00000000;
+               info->start[1] = base + 0x00008000;
+               info->start[2] = base + 0x0000C000;
+               info->start[3] = base + 0x00010000;
+               for (i = 4; i < info->sector_count; i++) {
+                       info->start[i] = base + (i * 0x00020000) - 0x00060000;
+               }
+       } else {
+               /* set sector offsets for top boot block type           */
+               i = info->sector_count - 1;
+               info->start[i--] = base + info->size - 0x00008000;
+               info->start[i--] = base + info->size - 0x0000C000;
+               info->start[i--] = base + info->size - 0x00010000;
+               for (; i >= 0; i--) {
+                       info->start[i] = base + i * 0x00020000;
+               }
+       }
+
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info  (flash_info_t *info)
+{
+       int i;
+
+       if (info->flash_id == FLASH_UNKNOWN) {
+               printf ("missing or unknown FLASH type\n");
+               return;
+       }
+
+       switch (info->flash_id & FLASH_VENDMASK) {
+       case FLASH_MAN_AMD:     printf ("AMD ");                break;
+       case FLASH_MAN_FUJ:     printf ("FUJITSU ");            break;
+       default:                printf ("Unknown Vendor ");     break;
+       }
+
+       switch (info->flash_id & FLASH_TYPEMASK) {
+       case FLASH_AM400B:      printf ("AM29LV400B (4 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AM400T:      printf ("AM29LV400T (4 Mbit, top boot sector)\n");
+                               break;
+       case FLASH_AM800B:      printf ("AM29LV800B (8 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AM800T:      printf ("AM29LV800T (8 Mbit, top boot sector)\n");
+                               break;
+       case FLASH_AM160B:      printf ("AM29LV160B (16 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AM160T:      printf ("AM29LV160T (16 Mbit, top boot sector)\n");
+                               break;
+       case FLASH_AM320B:      printf ("AM29LV320B (32 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AM320T:      printf ("AM29LV320T (32 Mbit, top boot sector)\n");
+                               break;
+       default:                printf ("Unknown Chip Type\n");
+                               break;
+       }
+
+       printf ("  Size: %ld MB in %d Sectors\n",
+               info->size >> 20, info->sector_count);
+
+       printf ("  Sector Start Addresses:");
+       for (i=0; i<info->sector_count; ++i) {
+               if ((i % 5) == 0)
+                       printf ("\n   ");
+               printf (" %08lX%s",
+                       info->start[i],
+                       info->protect[i] ? " (RO)" : "     "
+               );
+       }
+       printf ("\n");
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+
+ulong flash_get_size (vu_long *addr, flash_info_t *info)
+{
+       short i;
+       ulong value;
+       ulong base = (ulong)addr;
+
+
+       /* Write auto select command: read Manufacturer ID */
+       addr[0x0555] = 0x00AA00AA;
+       addr[0x02AA] = 0x00550055;
+       addr[0x0555] = 0x00900090;
+
+       value = addr[0];
+
+       switch (value) {
+       case AMD_MANUFACT:
+               info->flash_id = FLASH_MAN_AMD;
+               break;
+       case FUJ_MANUFACT:
+               info->flash_id = FLASH_MAN_FUJ;
+               break;
+       default:
+               info->flash_id = FLASH_UNKNOWN;
+               info->sector_count = 0;
+               info->size = 0;
+               return (0);                     /* no or unknown flash  */
+       }
+
+       value = addr[1];                        /* device ID            */
+
+       switch (value) {
+       case AMD_ID_LV400T:
+               info->flash_id += FLASH_AM400T;
+               info->sector_count = 11;
+               info->size = 0x00100000;
+               break;                          /* => 1 MB              */
+
+       case AMD_ID_LV400B:
+               info->flash_id += FLASH_AM400B;
+               info->sector_count = 11;
+               info->size = 0x00100000;
+               break;                          /* => 1 MB              */
+
+       case AMD_ID_LV800T:
+               info->flash_id += FLASH_AM800T;
+               info->sector_count = 19;
+               info->size = 0x00200000;
+               break;                          /* => 2 MB              */
+
+       case AMD_ID_LV800B:
+               info->flash_id += FLASH_AM800B;
+               info->sector_count = 19;
+               info->size = 0x00200000;
+               break;                          /* => 2 MB              */
+
+       case AMD_ID_LV160T:
+               info->flash_id += FLASH_AM160T;
+               info->sector_count = 35;
+               info->size = 0x00400000;
+               break;                          /* => 4 MB              */
+
+       case AMD_ID_LV160B:
+               info->flash_id += FLASH_AM160B;
+               info->sector_count = 35;
+               info->size = 0x00400000;
+               break;                          /* => 4 MB              */
+#if 0  /* enable when device IDs are available */
+       case AMD_ID_LV320T:
+               info->flash_id += FLASH_AM320T;
+               info->sector_count = 67;
+               info->size = 0x00800000;
+               break;                          /* => 8 MB              */
+
+       case AMD_ID_LV320B:
+               info->flash_id += FLASH_AM320B;
+               info->sector_count = 67;
+               info->size = 0x00800000;
+               break;                          /* => 8 MB              */
+#endif
+       default:
+               info->flash_id = FLASH_UNKNOWN;
+               return (0);                     /* => no or unknown flash */
+
+       }
+
+       /* set up sector start adress table */
+       if (info->flash_id & FLASH_BTYPE) {
+               /* set sector offsets for bottom boot block type        */
+               info->start[0] = base + 0x00000000;
+               info->start[1] = base + 0x00008000;
+               info->start[2] = base + 0x0000C000;
+               info->start[3] = base + 0x00010000;
+               for (i = 4; i < info->sector_count; i++) {
+                       info->start[i] = base + (i * 0x00020000) - 0x00060000;
+               }
+       } else {
+               /* set sector offsets for top boot block type           */
+               i = info->sector_count - 1;
+               info->start[i--] = base + info->size - 0x00008000;
+               info->start[i--] = base + info->size - 0x0000C000;
+               info->start[i--] = base + info->size - 0x00010000;
+               for (; i >= 0; i--) {
+                       info->start[i] = base + i * 0x00020000;
+               }
+       }
+
+       /* check for protected sectors */
+       for (i = 0; i < info->sector_count; i++) {
+               /* read sector protection at sector address, (A7 .. A0) = 0x02 */
+               /* D0 = 1 if protected */
+               addr = (volatile unsigned long *)(info->start[i]);
+               info->protect[i] = addr[2] & 1;
+       }
+
+       /*
+        * Prevent writes to uninitialized FLASH.
+        */
+       if (info->flash_id != FLASH_UNKNOWN) {
+               addr = (volatile unsigned long *)info->start[0];
+
+               *addr = 0x00F000F0;     /* reset bank */
+       }
+
+       return (info->size);
+}
+
+
+/*-----------------------------------------------------------------------
+ */
+
+void   flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+       vu_long *addr = (vu_long*)(info->start[0]);
+       int flag, prot, sect, l_sect;
+       ulong start, now, last;
+
+       if ((s_first < 0) || (s_first > s_last)) {
+               if (info->flash_id == FLASH_UNKNOWN) {
+                       printf ("- missing\n");
+               } else {
+                       printf ("- no sectors to erase\n");
+               }
+               return;
+       }
+
+       if ((info->flash_id == FLASH_UNKNOWN) ||
+           (info->flash_id > FLASH_AMD_COMP)) {
+               printf ("Can't erase unknown flash type - aborted\n");
+               return;
+       }
+
+       prot = 0;
+       for (sect=s_first; sect<=s_last; ++sect) {
+               if (info->protect[sect]) {
+                       prot++;
+               }
+       }
+
+       if (prot) {
+               printf ("- Warning: %d protected sectors will not be erased!\n",
+                       prot);
+       } else {
+               printf ("\n");
+       }
+
+       l_sect = -1;
+
+       /* Disable interrupts which might cause a timeout here */
+       flag = disable_interrupts();
+
+       addr[0x0555] = 0x00AA00AA;
+       addr[0x02AA] = 0x00550055;
+       addr[0x0555] = 0x00800080;
+       addr[0x0555] = 0x00AA00AA;
+       addr[0x02AA] = 0x00550055;
+
+       /* Start erase on unprotected sectors */
+       for (sect = s_first; sect<s_last; sect++) {
+               if (info->protect[sect] == 0) { /* not protected */
+                       addr = (vu_long*)(info->start[sect]);
+                       addr[0] = 0x00300030;
+                       l_sect = sect;
+               }
+       }
+
+       /* re-enable interrupts if necessary */
+       if (flag)
+               enable_interrupts();
+
+       /* wait at least 80us - let's wait 1 ms */
+       udelay (1000);
+
+       /*
+        * We wait for the last triggered sector
+        */
+       if (l_sect < 0)
+               goto DONE;
+
+       start = get_timer (0);
+       last  = start;
+       addr = (vu_long*)(info->start[l_sect]);
+       while ((addr[0] & 0x00800080) != 0x00800080) {
+               if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+                       printf ("Timeout\n");
+                       return;
+               }
+               /* show that we're waiting */
+               if ((now - last) > 1000) {      /* every second */
+                       serial_putc ('.');
+                       last = now;
+               }
+       }
+
+DONE:
+       /* reset to read mode */
+       addr = (volatile unsigned long *)info->start[0];
+       addr[0] = 0x00F000F0;   /* reset bank */
+
+       printf (" done\n");
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+flash_info_t *addr2info (ulong addr)
+{
+       flash_info_t *info;
+       int i;
+
+       for (i=0, info=&flash_info[0]; i<CFG_MAX_FLASH_BANKS; ++i, ++info) {
+               if ((addr >= info->start[0]) &&
+                   (addr < (info->start[0] + info->size)) ) {
+                       return (info);
+               }
+       }
+
+       return (NULL);
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash.
+ * Make sure all target addresses are within Flash bounds,
+ * and no protected sectors are hit.
+ * Returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ * 4 - target range includes protected sectors
+ * 8 - target address not in Flash memory
+ */
+int flash_write (uchar *src, ulong addr, ulong cnt)
+{
+       int i;
+       ulong         end        = addr + cnt;
+       flash_info_t *info_first = addr2info (addr);
+       flash_info_t *info_last  = addr2info (end );
+       flash_info_t *info;
+
+       if (cnt == 0) {
+               return (0);
+       }
+
+       if (!info_first || !info_last) {
+               return (8);
+       }
+
+       for (info = info_first; info <= info_last; ++info) {
+               ulong b_end = info->start[0] + info->size;      /* bank end addr */
+               short s_end = info->sector_count - 1;
+               for (i=0; i<info->sector_count; ++i) {
+                       ulong e_addr = (i == s_end) ? b_end : info->start[i + 1];
+
+                       if ((end >= info->start[i]) && (addr < e_addr) &&
+                           (info->protect[i] != 0) ) {
+                               return (4);
+                       }
+               }
+       }
+
+       /* finally write data to flash */
+       for (info = info_first; info <= info_last && cnt>0; ++info) {
+               ulong len;
+               
+               len = info->start[0] + info->size - addr;
+               if (len > cnt)
+                       len = cnt;
+               if ((i = write_buff(info, src, addr, len)) != 0) {
+                       return (i);
+               }
+               cnt  -= len;
+               addr += len;
+               src  += len;
+       }
+       return (0);
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+
+static int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+       ulong cp, wp, data;
+       int i, l, rc;
+
+       wp = (addr & ~3);       /* get lower word aligned address */
+
+       /*
+        * handle unaligned start bytes
+        */
+       if ((l = addr - wp) != 0) {
+               data = 0;
+               for (i=0, cp=wp; i<l; ++i, ++cp) {
+                       data = (data << 8) | (*(uchar *)cp);
+               }
+               for (; i<4 && cnt>0; ++i) {
+                       data = (data << 8) | *src++;
+                       --cnt;
+                       ++cp;
+               }
+               for (; cnt==0 && i<4; ++i, ++cp) {
+                       data = (data << 8) | (*(uchar *)cp);
+               }
+
+               if ((rc = write_word(info, wp, data)) != 0) {
+                       return (rc);
+               }
+               wp += 4;
+       }
+
+       /*
+        * handle word aligned part
+        */
+       while (cnt >= 4) {
+               data = 0;
+               for (i=0; i<4; ++i) {
+                       data = (data << 8) | *src++;
+               }
+               if ((rc = write_word(info, wp, data)) != 0) {
+                       return (rc);
+               }
+               wp  += 4;
+               cnt -= 4;
+       }
+
+       if (cnt == 0) {
+               return (0);
+       }
+
+       /*
+        * handle unaligned tail bytes
+        */
+       data = 0;
+       for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
+               data = (data << 8) | *src++;
+               --cnt;
+       }
+       for (; i<4; ++i, ++cp) {
+               data = (data << 8) | (*(uchar *)cp);
+       }
+       
+       return (write_word(info, wp, data));
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_word (flash_info_t *info, ulong dest, ulong data)
+{
+       vu_long *addr = (vu_long*)(info->start[0]);
+       ulong start;
+       int flag;
+
+       /* Check if Flash is (sufficiently) erased */
+       if ((*((vu_long *)dest) & data) != data) {
+               return (2);
+       }
+       /* Disable interrupts which might cause a timeout here */
+       flag = disable_interrupts();
+
+       addr[0x0555] = 0x00AA00AA;
+       addr[0x02AA] = 0x00550055;
+       addr[0x0555] = 0x00A000A0;
+
+       *((vu_long *)dest) = data;
+
+       /* re-enable interrupts if necessary */
+       if (flag)
+               enable_interrupts();
+
+       /* data polling for D7 */
+       start = get_timer (0);
+       while ((*((vu_long *)dest) & 0x00800080) != (data & 0x00800080)) {
+               if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+                       return (1);
+               }
+       }
+       return (0);
+}
+
+/*-----------------------------------------------------------------------
+ */
diff --git a/tqm8xx/tqm8xx.c b/tqm8xx/tqm8xx.c
new file mode 100644 (file)
index 0000000..c526a06
--- /dev/null
@@ -0,0 +1,346 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <ppcboot.h>
+#include "mpc8xx.h"
+#include "tqm8xx.h"
+
+/* ------------------------------------------------------------------------- */
+
+static long int dram_size (long int, long int *, long int);
+
+/* ------------------------------------------------------------------------- */
+
+#define        _NOT_USED_      0xFFFFFFFF
+
+const uint sdram_table[] =
+{
+       /*
+        * Single Read. (Offset 0 in UPMA RAM)
+        */
+       0x1F0DFC04, 0xEEAFBC04, 0x11AF7C04, 0xEFBAFC00,
+       0x1FF5FC47, /* last */
+       /*
+        * SDRAM Initialization (offset 5 in UPMA RAM)
+        *
+         * This is no UPM entry point. The following definition uses
+         * the remaining space to establish an initialization
+         * sequence, which is executed by a RUN command.
+        *
+        */
+                   0x1FF5FC34, 0xEFEABC34, 0x1FB57C35, /* last */
+       /*
+        * Burst Read. (Offset 8 in UPMA RAM)
+        */
+       0x1F0DFC04, 0xEEAFBC04, 0x10AF7C04, 0xF0AFFC00,
+       0xF0AFFC00, 0xF1AFFC00, 0xEFBAFC00, 0x1FF5FC47, /* last */
+       _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_,
+       _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_,
+       /*
+        * Single Write. (Offset 18 in UPMA RAM)
+        */
+       0x1F0DFC04, 0xEEABBC00, 0x01B27C04, 0x1FF5FC47, /* last */
+       _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_,
+       /*
+        * Burst Write. (Offset 20 in UPMA RAM)
+        */
+       0x1F0DFC04, 0xEEABBC00, 0x10A77C00, 0xF0AFFC00,
+       0xF0AFFC00, 0xE1BAFC04, 0x1FF5FC47, /* last */
+                                           _NOT_USED_,
+       _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_,
+       _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_,
+       /*
+        * Refresh  (Offset 30 in UPMA RAM)
+        */
+       0x1FFD7C84, 0xFFFFFC04, 0xFFFFFC04, 0xFFFFFC04,
+       0xFFFFFC84, 0xFFFFFC07, /* last */
+                               _NOT_USED_, _NOT_USED_,
+       _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_,
+       /*
+        * Exception. (Offset 3c in UPMA RAM)
+        */
+       0x7FFFFC07, /* last */
+                   _NOT_USED_, _NOT_USED_, _NOT_USED_,
+};
+
+/* ------------------------------------------------------------------------- */
+
+
+/*
+ * Check Board Identity:
+ *
+ * Test TQ ID string (TQM8xx...)
+ * If present, check for "L" type (no second DRAM bank),
+ * otherwise "L" type is assumed as default.
+ * 
+ * Return 1 for "L" type, 0 else.
+ */
+
+int checkboard (void)
+{
+    unsigned char *s = (unsigned char *)CFG_HWINFO_ADDR;
+    unsigned char *e;
+    int l_type;
+
+    if (strncmp(s, "TQM8", 4)) {
+       printf ("### No HW ID - assuming TQM8xxL\n");
+       return (1);
+    }
+
+    l_type = (*(s+6) == 'L');
+
+    for (e=s; (e-s)<CFG_HWINFO_LEN; ++e) {
+       if ((*e == ' ') || *e == '\0')
+           break;
+    }
+
+    for ( ; s<e; ++s) {
+       serial_putc (*s);
+    }
+    serial_putc ('\n');
+
+    return (l_type);
+}
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * Check Size of FLASH memory
+ */
+int checkflash (void)
+{
+    /* TODO: XXX XXX XXX */
+    printf ("8 MB ## Test not implemented yet ##\n");
+
+    return (0);
+}
+
+/* ------------------------------------------------------------------------- */
+
+long int initdram (int board_type)
+{
+    volatile immap_t     *immap  = (immap_t *)CFG_IMMR;
+    volatile memctl8xx_t *memctl = &immap->im_memctl;
+    long int size_b0, size_b1, size8, size9;
+
+    /*
+     * Preliminary prescaler for refresh (depends on number of
+     * banks): This value is selected for four cycles every 62.4 us
+     * with two SDRAM banks or four cycles every 31.2 us with one
+     * bank. It will be adjusted after memory sizing.
+     */
+    memctl->memc_mptpr = CFG_MPTPR_2BK_8K;
+
+    memctl->memc_mamr = CFG_MAMR_8COL;
+
+    upmconfig(UPMA, (uint *)sdram_table, sizeof(sdram_table)/sizeof(uint));
+
+    /*
+     * Map controller banks 2 and 3 to the SDRAM banks 2 and 3 at
+     * preliminary addresses - these have to be modified after the
+     * SDRAM size has been determined.
+     */
+    memctl->memc_or2 = CFG_OR2_PRELIM;
+    memctl->memc_br2 = CFG_BR2_PRELIM;
+
+    if (board_type == 0) {     /* "L" type boards have only one bank SDRAM */
+       memctl->memc_or3 = CFG_OR3_PRELIM;
+       memctl->memc_br3 = CFG_BR3_PRELIM;
+    }
+
+    /* perform SDRAM initializsation sequence */
+    memctl->memc_mar  = 0x00000088;
+
+    memctl->memc_mcr  = 0x80004105;    /* SDRAM bank 0 */
+
+    
+    if (board_type == 0) {     /* "L" type boards have only one bank SDRAM */
+       memctl->memc_mcr  = 0x80006105; /* SDRAM bank 1 */
+    }
+
+    memctl->memc_mcr  = 0x80004230;    /* SDRAM bank 0 - execute twice */
+
+    if (board_type == 0) {     /* "L" type boards have only one bank SDRAM */
+       memctl->memc_mcr  = 0x80006230; /* SDRAM bank 1 - execute twice */
+    }
+
+    /*
+     * Check Bank 0 Memory Size for re-configuration
+     *
+     * try 8 column mode
+     */
+    size8 = dram_size (CFG_MAMR_8COL, (ulong *)SDRAM_BASE2_PRELIM, SDRAM_MAX_SIZE);
+
+    /*
+     * try 9 column mode
+     */
+    size9 = dram_size (CFG_MAMR_9COL, (ulong *)SDRAM_BASE2_PRELIM, SDRAM_MAX_SIZE);
+
+    if (size8 < size9) {               /* leave configuration at 9 columns     */
+       size_b0 = size9;
+/*     debug ("SDRAM Bank 0 in 9 column mode: %ld MB\n", size >> 20);  */
+    } else {                           /* back to 8 columns                    */
+       size_b0 = size8;
+       memctl->memc_mamr = CFG_MAMR_8COL;
+/*     debug ("SDRAM Bank 0 in 8 column mode: %ld MB\n", size >> 20);  */
+    }
+
+    if (board_type == 0) {     /* "L" type boards have only one bank SDRAM     */
+       /*
+        * Check Bank 1 Memory Size
+        * use current column settings
+        * [9 column SDRAM may also be used in 8 column mode,
+        *  but then only half the real size will be used.]
+        */
+       size_b1 = dram_size (memctl->memc_mamr, (ulong *)SDRAM_BASE3_PRELIM,
+                               SDRAM_MAX_SIZE);
+/*     debug ("SDRAM Bank 1: %ld MB\n", size8 >> 20);  */
+    } else {
+       size_b1 = 0;
+    }
+
+    /*
+     * Adjust refresh rate depending on SDRAM type, both banks
+     * For types > 128 MBit leave it at the current (fast) rate
+     */
+    if ((size_b0 < 0x02000000) && (size_b1 < 0x02000000)) {
+       /* reduce to 15.6 us (62.4 us / quad) */
+       memctl->memc_mptpr = CFG_MPTPR_2BK_4K;
+    }
+
+    /*
+     * Final mapping: map bigger bank first
+     */
+    if (size_b1 > size_b0) {   /* SDRAM Bank 1 is bigger - map first   */
+
+       memctl->memc_or3 = ((-size_b1) & 0xFFFF0000) | CFG_OR_TIMING_SDRAM;
+       memctl->memc_br3 = (CFG_SDRAM_BASE & BR_BA_MSK) | BR_MS_UPMA | BR_V;
+
+       if (size_b0 > 0) {
+           /*
+            * Position Bank 0 immediately above Bank 1
+            */
+           memctl->memc_or2 = ((-size_b0) & 0xFFFF0000) | CFG_OR_TIMING_SDRAM;
+           memctl->memc_br2 = ((CFG_SDRAM_BASE & BR_BA_MSK) | BR_MS_UPMA | BR_V)
+                              + size_b1;
+       } else {
+           unsigned long reg;
+           /*
+            * No bank 0
+            *
+            * invalidate bank
+            */
+           memctl->memc_br2 = 0;
+
+           /* adjust refresh rate depending on SDRAM type, one bank */
+           reg = memctl->memc_mptpr;
+           reg >>= 1;  /* reduce to CFG_MPTPR_1BK_8K / _4K */
+           memctl->memc_mptpr = reg;
+       }
+
+    } else {                   /* SDRAM Bank 0 is bigger - map first   */
+
+       memctl->memc_or2 = ((-size_b0) & 0xFFFF0000) | CFG_OR_TIMING_SDRAM;
+       memctl->memc_br2 = (CFG_SDRAM_BASE & BR_BA_MSK) | BR_MS_UPMA | BR_V;
+       
+       if (size_b1 > 0) {
+           /*
+            * Position Bank 1 immediately above Bank 0
+            */
+           memctl->memc_or3 = ((-size_b1) & 0xFFFF0000) | CFG_OR_TIMING_SDRAM;
+           memctl->memc_br3 = ((CFG_SDRAM_BASE & BR_BA_MSK) | BR_MS_UPMA | BR_V)
+                              + size_b0;
+       } else {
+           unsigned long reg;
+           /*
+            * No bank 1
+            *
+            * invalidate bank 
+            */
+            memctl->memc_br3 = 0;
+
+            /* adjust refresh rate depending on SDRAM type, one bank */
+            reg = memctl->memc_mptpr;
+            reg >>= 1; /* reduce to CFG_MPTPR_1BK_8K / _4K */
+            memctl->memc_mptpr = reg;
+       }
+    }
+
+    return (size_b0 + size_b1);
+}
+
+/* ------------------------------------------------------------------------- */
+
+int testdram (void)
+{
+    /* TODO: XXX XXX XXX */
+    printf ("test: 16 MB - ok\n");
+
+    return (0);
+}
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * Check memory range for valid RAM. A simple memory test determines
+ * the actually available RAM size between addresses `base' and
+ * `base + maxsize'. Some (not all) hardware errors are detected:
+ * - short between address lines
+ * - short between data lines
+ */
+
+static long int dram_size (long int mamr_value, long int *base, long int maxsize)
+{
+    volatile immap_t     *immap  = (immap_t *)CFG_IMMR;
+    volatile memctl8xx_t *memctl = &immap->im_memctl;
+    volatile long int   *addr;
+    long int             cnt, val;
+
+    memctl->memc_mamr = mamr_value;
+
+    for (cnt = maxsize/sizeof(long); cnt > 0; cnt >>= 1) {
+       addr = base + cnt;      /* pointer arith! */
+
+       *addr = ~cnt;
+    }
+
+    /* write 0 to base address */
+    addr = base;
+    *addr = 0;
+
+    /* check at base address */
+    if ((val = *addr) != 0) {
+       return (0);
+    }
+
+    for (cnt = 1; ; cnt <<= 1) {
+       addr = base + cnt;      /* pointer arith! */
+
+       val = *addr;
+
+       if (val != (~cnt)) {
+           return (cnt * sizeof(long));
+       }
+    }
+    /* NOTREACHED */
+}
diff --git a/tqm8xx/tqm8xx.h b/tqm8xx/tqm8xx.h
new file mode 100644 (file)
index 0000000..b9c1a87
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/****************************************************************************
+ * FLASH Memory Map as used by TQ Monitor:
+ *
+ *                          Start Address    Length
+ * +-----------------------+ 0x4000_0000     Start of Flash -----------------
+ * | MON8xx code           | 0x4000_0100     Reset Vector
+ * +-----------------------+ 0x400?_????
+ * | (unused)              |
+ * +-----------------------+ 0x4001_FF00
+ * | Ethernet Addresses    |                 0x78
+ * +-----------------------+ 0x4001_FF78
+ * | (Reserved for MON8xx) |                 0x44
+ * +-----------------------+ 0x4001_FFBC
+ * | Lock Address          |                 0x04
+ * +-----------------------+ 0x4001_FFC0                     ^
+ * | Hardware Information  |                 0x40            | MON8xx
+ * +=======================+ 0x4002_0000 (sector border)    -----------------
+ * | Autostart Header      |                                 | Applications
+ * | ...                   |                                 v
+ *
+ *****************************************************************************/
+
+/* ------------------------------------------------------------------------- */
+/* SDRAM Table according to TQM8xxL Initialization Code                      */
+
+#define SDRAM_MPTPRVALUE 0x1000
+
+#define SDRAM_MARVALUE   0x00000088     /* MAR = Memory Address Register        */
+
+/* ???????? */
+#define SDRAM_MBMRVALUE0 0xc3802114  /* (16-14) 50 MHz */
+#define SDRAM_MBMRVALUE1 SDRAM_MBMRVALUE0
+
+#define SDRAM_OR2VALUE   0xffc00a00
+#define SDRAM_BR2VALUE   0x000000c1   /* base address will be or:ed on */
+
+#define SDRAM_MCRVALUE0  0x80808111   /* run pattern 0x11 */ 
+#define SDRAM_MCRVALUE1  SDRAM_MCRVALUE0
+/* ???????? */
+