This commit is contained in:
Ville Linde 2006-07-12 13:53:14 +00:00
parent 9788eb4750
commit a1c9f6cf92
215 changed files with 74022 additions and 0 deletions

184
config.c Normal file
View file

@ -0,0 +1,184 @@
#include "model3.h"
#include "expat.h"
enum
{
ELEMENT_NONE = 1,
ELEMENT_CONFIG,
ELEMENT_ROMPATH,
ELEMENT_GAMELIST,
ELEMENT_BACKUPPATH,
ELEMENT_WIDTH,
ELEMENT_HEIGHT,
ELEMENT_FULLSCREEN,
ELEMENT_FPSLIMIT,
ELEMENT_STRETCH,
};
static STRING_ID element_id[] =
{
{ "config", ELEMENT_CONFIG },
{ "rom_path", ELEMENT_ROMPATH },
{ "gamelist", ELEMENT_GAMELIST },
{ "backup_path", ELEMENT_BACKUPPATH },
{ "width", ELEMENT_WIDTH },
{ "height", ELEMENT_HEIGHT },
{ "fullscreen", ELEMENT_FULLSCREEN },
{ "fps_limit", ELEMENT_FPSLIMIT },
{ "stretch", ELEMENT_STRETCH },
{ "", 0 },
};
static STRING_ID boolean_id[] =
{
{ "yes", TRUE },
{ "no", FALSE },
{ "", 0 },
};
static UINT8 *config_file;
static int current_element;
static void XMLCALL element_start(void *data, const char *el, const char **attr)
{
int element = get_string_id(el, element_id);
if (element < 0)
{
message(0, "Unknown element %s while parsing XML file\n", el);
}
else
{
current_element = element;
}
}
static void XMLCALL element_end(void *data, const char *el)
{
int element = get_string_id(el, element_id);
if (element < 0)
{
message(0, "Unknown element %s while parsing XML\n", el);
}
else
{
switch (element)
{
case ELEMENT_CONFIG:
case ELEMENT_ROMPATH:
case ELEMENT_GAMELIST:
case ELEMENT_BACKUPPATH:
case ELEMENT_WIDTH:
case ELEMENT_HEIGHT:
case ELEMENT_FULLSCREEN:
case ELEMENT_FPSLIMIT:
case ELEMENT_STRETCH:
{
current_element = ELEMENT_NONE;
break;
}
}
}
}
static void XMLCALL character_data(void *data, const char *s, int len)
{
char temp[2000];
memcpy(temp, s, len);
temp[len] = 0;
switch (current_element)
{
case ELEMENT_ROMPATH:
{
strcpy(m3_config.rom_path, temp);
break;
}
case ELEMENT_GAMELIST:
{
strcpy(m3_config.rom_list, temp);
break;
}
case ELEMENT_BACKUPPATH:
{
strcpy(m3_config.backup_path, temp);
break;
}
case ELEMENT_WIDTH:
{
int width;
sscanf(temp, "%d", &width);
m3_config.width = width;
break;
}
case ELEMENT_HEIGHT:
{
int height;
sscanf(temp, "%d", &height);
m3_config.height = height;
break;
}
case ELEMENT_FULLSCREEN:
{
BOOL fullscreen = get_string_id(temp, boolean_id);
m3_config.fullscreen = fullscreen;
break;
}
case ELEMENT_FPSLIMIT:
{
BOOL fpslimit = get_string_id(temp, boolean_id);
m3_config.fps_limit = fpslimit;
break;
}
case ELEMENT_STRETCH:
{
BOOL stretch = get_string_id(temp, boolean_id);
m3_config.stretch = stretch;
break;
}
}
}
BOOL parse_config(const char *config_name)
{
XML_Parser parser;
int length;
FILE *file;
file = open_file(FILE_READ|FILE_BINARY, "%s", config_name);
if (file == NULL)
{
message(0, "Couldn't open %s", config_name);
return FALSE;
}
length = (int)get_open_file_size(file);
config_file = (UINT8*)malloc(length);
if (!read_from_file(file, config_file, length))
{
message(0, "I/O error while reading %s", config_name);
return FALSE;
}
close_file(file);
// parse the XML file
parser = XML_ParserCreate(NULL);
XML_SetElementHandler(parser, element_start, element_end);
XML_SetCharacterDataHandler(parser, character_data);
if (XML_Parse(parser, config_file, length, 1) != XML_STATUS_OK)
{
message(0, "Error while parsing the XML file %s", config_name);
return FALSE;
}
XML_ParserFree(parser);
return TRUE;
}

22
config.xml Normal file
View file

@ -0,0 +1,22 @@
<?xml version="1.0"?>
<!DOCTYPE config [
<!ELEMENT config (rom_path?, gamelist?, backup_path?, width?, height?, fullscreen?, fps_limit?)>
<!ELEMENT rom_path (#PCDATA)>
<!ELEMENT gamelist (#PCDATA)>
<!ELEMENT backup_path (#PCDATA)>
<!ELEMENT width (#PCDATA)>
<!ELEMENT height (#PCDATA)>
<!ELEMENT fullscreen (#PCDATA)>
<!ELEMENT fps_limit (#PCDATA)>
]>
<config>
<rom_path>c:\devmame\roms</rom_path>
<gamelist>games.xml</gamelist>
<backup_path>c:\code\supermodel2\backup</backup_path>
<width>1280</width>
<height>1024</height>
<fullscreen>yes</fullscreen>
<fps_limit>no</fps_limit>
<stretch>yes</stretch>
</config>

492
core/bridge.c Normal file
View file

@ -0,0 +1,492 @@
/*
* Sega Model 3 Emulator
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* 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 (license.txt); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* bridge.c
*
* MPC105 and MPC106 PCI bridge/memory controller emulation.
*
* Warning: Portability hazard. Code assumes it is running on a little endian
* machine.
*
* NOTE: Data written to the bridge controller is byte-reversed by the PPC.
* This is to make it little endian.
*/
#include "model3.h"
/******************************************************************/
/* Internal Bridge State */
/******************************************************************/
/*
* Macros for Register Access
*
* Assuming a little endian system (portability hazard!)
*/
#define DWORD(addr) *((UINT32 *) &regs[addr])
#define WORD(addr) *((UINT16 *) &regs[addr])
#define BYTE(addr) regs[addr]
/*
* Bridge State
*
* This code is intended for use on little-endian systems. Data from the
* registers should be returned as if a big endian read was performed (thus
* returning the little endian word 0x1057 as 0x5710.)
*
* The DWORD() and WORD() macros only work on little endian systems and are
* intended to set up the bridge state. Reads and writes using the handlers
* are done in big endian fashion by manually breaking down the data into
* bytes.
*
* To make this code fully portable, it would probably be enough to remove
* the DWORD() and WORD() macros.
*/
static UINT8 regs[0x100];
static UINT8 config_data[4]; // data for last CONFIG_ADDR command
static UINT32 reg_ptr; // current register address
/******************************************************************/
/* Interface */
/******************************************************************/
/*
* Callback for Bus Commands
*
* Note that there are no callbacks for reads/writes to CONFIG_DATA yet as
* the need for them has not yet appeared.
*/
static UINT32 (*config_addr_callback)(UINT32);
/*
* UINT8 bridge_read_8(UINT32 addr);
*
* Reads directly from a register. The lower 8 bits of the address are the
* register to read from. This is intended for the MPC105 which can map its
* internal registers to 0xF8FFF0xx.
*
* Parameters:
* addr = Address (only lower 8 bits matter.)
*
* Returns:
* Data read.
*/
UINT8 bridge_read_8(UINT32 addr)
{
LOG("model3.log", "RB REG%02X\n", addr & 0xff);
return BYTE(addr & 0xff);
}
/*
* UINT16 bridge_read_16(UINT32 addr);
*
* Reads directly from a register. The lower 8 bits of the address are the
* register to read from. This is intended for the MPC105 which can map its
* internal registers to 0xF8FFF0xx.
*
* Bit 0 is masked off to ensure 16-bit alignment (I'm not sure how a real
* PCIBMC would handle this.)
*
* Parameters:
* addr = Address (only lower 8 bits matter.)
*
* Returns:
* Data read.
*/
UINT16 bridge_read_16(UINT32 addr)
{
LOG("model3.log", "RH REG%02X\n", addr & 0xff);
addr &= 0xfe;
return (BYTE(addr + 0) << 8) | BYTE(addr + 1);
}
/*
* UINT32 bridge_read_32(UINT32 addr);
*
* Reads directly from a register. The lower 8 bits of the address are the
* register to read from. This is intended for the MPC105 which can map its
* internal registers to 0xF8FFF0xx.
*
* The lower 2 bits are masked off to ensure 32-bit alignment.
*
* Parameters:
* addr = Address (only lower 8 bits matter.)
*
* Returns:
* Data read.
*/
UINT32 bridge_read_32(UINT32 addr)
{
LOG("model3.log", "RW REG%02X\n", addr & 0xff);
addr &= 0xfc;
return (BYTE(addr + 0) << 24) | (BYTE(addr + 1) << 16) |
(BYTE(addr + 2) << 8) | BYTE(addr + 3);
}
/*
* void bridge_write_8(UINT32 addr, UINT8 data);
*
* Writes directly to a register. Only the lower 8 bits matter. This is
* intended for the MPC105.
*
* Arguments:
* addr = Address (only lower 8 bits matter.)
* data = Data to write.
*/
void bridge_write_8(UINT32 addr, UINT8 data)
{
LOG("model3.log", "REG%02X=%02X\n", addr & 0xff, data);
BYTE(addr & 0xff) = data;
}
/*
* void bridge_write_16(UINT32 addr, UINT16 data);
*
* Writes directly to a register. Only the lower 8 bits matter. This is
* intended for the MPC105.
*
* Bit 0 is masked off to ensure 16-bit alignment.
*
* Arguments:
* addr = Address (only lower 8 bits matter.)
* data = Data to write.
*/
void bridge_write_16(UINT32 addr, UINT16 data)
{
LOG("model3.log", "REG%02X=%02X%02X\n", addr & 0xff, data & 0xff, (data >> 8) & 0xff);
addr &= 0xfe;
BYTE(addr + 0) = data >> 8;
BYTE(addr + 1) = (UINT8) data;
}
/*
* void bridge_write_32(UINT32 addr, UINT32 data);
*
* Writes directly to a register. Only the lower 8 bits matter. This is
* intended for the MPC105.
*
* The lower 2 bits are masked off to ensure 32-bit alignment.
*
* Arguments:
* addr = Address (only lower 8 bits matter.)
* data = Data to write.
*/
void bridge_write_32(UINT32 addr, UINT32 data)
{
LOG("model3.log", "REG%02X=%02X%02X%02X%02X\n", addr & 0xff, data & 0xff, (data >> 8) & 0xff, (data >> 16) & 0xff, (data >> 24) & 0xff);
addr &= 0xfc;
BYTE(addr + 0) = data >> 24;
BYTE(addr + 1) = data >> 16;
BYTE(addr + 2) = data >> 8;
BYTE(addr + 3) = data;
}
/*
* UINT8 bridge_read_config_data_8(UINT32 addr);
*
* Reads from CONFIG_DATA offset 0 to 3. Only the lower 2 bits of the address
* are checked to determine which byte to read. I'm not sure whether this is
* correct behavior (perhaps all byte offsets return the same data.)
*
* Parameters:
* addr = Address to read from (only lower 2 bits matter.)
*
* Returns:
* Data read.
*/
UINT8 bridge_read_config_data_8(UINT32 addr)
{
return config_data[addr & 3];
// return BYTE(reg_ptr + (addr & 3));
}
/*
* UINT16 bridge_read_config_data_16(UINT32 addr);
*
* Reads from CONFIG_DATA offset 0 or 2. Only bit 1 of the address is checked
* to determine which word to read. I'm not sure whether this is correct
* behavior for word reads (both words might return the same data, for
* example.)
*
* Parameters:
* addr = Address to read from (only bit 1 matters.)
*
* Returns:
* Data read.
*/
UINT16 bridge_read_config_data_16(UINT32 addr)
{
return (config_data[(addr & 2) + 0] << 8) | config_data[(addr & 2) + 1];
// return (BYTE(reg_ptr + (addr & 2) + 0) << 8) |
// BYTE(reg_ptr + (addr & 2) + 1);
}
/*
* UINT32 bridge_read_config_data_32(UINT32 addr);
*
* Reads from CONFIG_DATA. The address argument is ignored because it is
* assumed that this function is only called for valid CONFIG_DATA addresses.
*
* Parameters:
* addr = Ignored.
*
* Returns:
* Data read.
*/
UINT32 bridge_read_config_data_32(UINT32 addr)
{
LOG("model3.log", "%08X: READ CONFIG DATA\n", ppc_get_pc());
return (config_data[0] << 24) | (config_data[1] << 16) |
(config_data[2] << 8) | config_data[3];
// return (BYTE(reg_ptr + 0) << 24) | (BYTE(reg_ptr + 1) << 16) |
// (BYTE(reg_ptr + 2) << 8) | BYTE(reg_ptr + 3);
}
/*
* void bridge_write_config_addr_32(UINT32 addr, UINT32 data);
*
* Writes to CONFIG_ADDR. The address argument is ignored because it is
* assumed that this function is only called for valid CONFIG_ADDR addresses.
*
* Parameters:
* addr = Ignored.
* data = Data to write.
*/
void bridge_write_config_addr_32(UINT32 addr, UINT32 data)
{
UINT32 callback_data;
/*
* I'm not sure how the bridge controller distinguishes between indirect
* register accesses and accesses which must be passed to some device on
* the PCI bus.
*
* Currently, I test to see if the command is of the format 0x800000XX,
* and if so, I return put register data in the return buffer
* (config_data), otherwise I invoke the callback.
*/
// LOG("model3.log", "CONFIG_ADDR=%02X%02X%02X%02X @ %08X", data & 0xff, (data >> 8) & 0xff, (data >> 16) & 0xff, (data >> 24) & 0xff, PowerPC_ReadIntegerRegister(POWERPC_IREG_PC));
// reg_ptr = data >> 24; // remember, data comes in little endian form
// // see page 3-15 of MPC106UM/D REV.1
if ((data & 0x00ffffff) == 0x00000080) // indirect register access (little endian data, see page 3-15 of MPC106UM/D REV.1)
{
reg_ptr = data >> 24;
config_data[0] = BYTE(reg_ptr + 0);
config_data[1] = BYTE(reg_ptr + 1);
config_data[2] = BYTE(reg_ptr + 2);
config_data[3] = BYTE(reg_ptr + 3);
}
else // pass it to the callback
{
if (config_addr_callback != NULL)
{
callback_data = config_addr_callback(BSWAP32(data));
callback_data = BSWAP32(callback_data); // so we can return as little endian
}
else
callback_data = 0xFFFFFFFF;
config_data[0] = callback_data >> 24;
config_data[1] = callback_data >> 16;
config_data[2] = callback_data >> 8;
config_data[3] = callback_data;
}
}
/*
* void bridge_write_config_data_8(UINT32 addr, UINT8 data);
*
* Writes to CONFIG_DATA. The lower 2 bits determine which byte offset to
* write to.
*
* Parameters:
* addr = Address to write to (only lower 2 bits matter.)
* data = Data to write.
*/
void bridge_write_config_data_8(UINT32 addr, UINT8 data)
{
// LOG("model3.log", "CONFIG_DATA=%02X @ %08X", data, PowerPC_ReadIntegerRegister(POWERPC_IREG_PC));
BYTE(reg_ptr + (addr & 3)) = data;
config_data[addr & 3] = data;
}
/*
* void bridge_write_config_data_16(UINT32 addr, UINT16 data);
*
* Writes to CONFIG_DATA. Only bit 1 of the address is checked to determine
* which word to write to.
*
* Parameters:
* addr = Address to write to (only bit 1 matters.)
* data = Data to write.
*/
void bridge_write_config_data_16(UINT32 addr, UINT16 data)
{
BYTE(reg_ptr + (addr & 2) + 0) = data >> 8;
BYTE(reg_ptr + (addr & 2) + 1) = (UINT8) data;
config_data[(addr & 2) + 0] = data >> 8;
config_data[(addr & 2) + 1] = (UINT8) data;
// LOG("model3.log", "CONFIG_DATA=%04X @ %08X", WORD(reg_ptr), PowerPC_ReadIntegerRegister(POWERPC_IREG_PC));
}
/*
* void bridge_write_config_data_32(UINT32 addr, UINT32 data);
*
* Writes to CONFIG_DATA. The address argument is ignored because it is
* assumed that this function is only called for valid CONFIG_DATA addresses.
*
* Parameters:
* addr = Ignored.
* data = Data to write.
*/
void bridge_write_config_data_32(UINT32 addr, UINT32 data)
{
BYTE(reg_ptr + 0) = data >> 24;
BYTE(reg_ptr + 1) = data >> 16;
BYTE(reg_ptr + 2) = data >> 8;
BYTE(reg_ptr + 3) = data;
config_data[0] = data >> 24;
config_data[1] = data >> 16;
config_data[2] = data >> 8;
config_data[3] = data;
// LOG("model3.log", "CONFIG_DATA=%08X @ %08X", DWORD(reg_ptr), PowerPC_ReadIntegerRegister(POWERPC_IREG_PC));
}
/*
* void bridge_save_state(FILE *fp);
*
* Saves the bridge controller state by writing it out to a file.
*
* Parameters:
* fp = File to write to.
*/
void bridge_save_state(FILE *fp)
{
fwrite(regs, sizeof(UINT8), 0x100, fp);
fwrite(config_data, sizeof(UINT8), 4, fp);
fwrite(&reg_ptr, sizeof(UINT32), 1, fp);
}
/*
* void bridge_load_state(FILE *fp);
*
* Loads the bridge controller state by reading it in from a file.
*
* Parameters:
* fp = File to read from.
*/
void bridge_load_state(FILE *fp)
{
fread(regs, sizeof(UINT8), 0x100, fp);
fread(config_data, sizeof(UINT8), 4, fp);
fread(&reg_ptr, sizeof(UINT32), 1, fp);
}
/*
* void bridge_reset(INT device);
*
* Initializes the bridge controller's internal state.
*
* Memory control configuration 1 is to be set to 0xFFn20000, where n is data
* sampled from signals sent by hardware to the MPC105 (see the MPC105
* manual.) For Model 3, I'm guessing that n == 0.
*
* Parameters:
* device = Device ID of the bridge to emulate (1 = MPC105, 2 = MPC106.)
* If it is not one of these values, behavior is undefined.
*/
void bridge_reset(INT device)
{
if (device == 1)
LOG("model3.log", "Using MPC105\n");
else if (device == 2)
LOG("model3.log", "Using MPC106\n");
else
LOG("model3.log", "ERROR: Unknown bridge controller device ID (%d)\n", device);
memset(regs, 0, sizeof(UINT8) * 0x100);
memset(config_data, 0, sizeof(UINT8) * 4);
reg_ptr = 0;
/*
* Set up common fields
*/
WORD(0x00) = 0x1057; // vendor ID (Motorola)
WORD(0x02) = device; // device ID
WORD(0x04) = 0x0006; // PCI command
WORD(0x06) = 0x0080; // PCI status
BYTE(0x08) = 0x00; // revision ID (?)
BYTE(0x0b) = 0x06; // class code
DWORD(0xa8) = 0xff000010; // processor interface configuration 1
DWORD(0xac) = 0x000c060c; // processor interface configuration 2
BYTE(0xba) = 0x04; // alternate OS-visible parameters 1
BYTE(0xc0) = 0x01; // error enabling 1
DWORD(0xf0) = 0xff020000; // memory control configuration 1
DWORD(0xf4) = 0x00000003; // memory control configuration 2
DWORD(0xfc) = 0x00100000; // memory control configuration 4
/*
* Additional settings for MPC106
*/
if (device == 2) // MPC106
{
BYTE(0x0c) = 0x08; // cache line size
BYTE(0x73) = 0xcd; // output driver control
DWORD(0xe0) = 0x0fff0042; // emulation support configuration 1
DWORD(0xe8) = 0x00000020; // emulation support configuration 2
}
}
/*
* void bridge_init(UINT32 (*config_addr_callback_ptr)(UINT32));
*
* Initializes the bridge controller by setting up the CONFIG_ADDR callback.
* bridge_reset() must still be used to put the controller in a usable (reset)
* state.
*/
void bridge_init(UINT32 (*config_addr_callback_ptr)(UINT32))
{
config_addr_callback = config_addr_callback_ptr;
}

50
core/bridge.h Normal file
View file

@ -0,0 +1,50 @@
/*
* Sega Model 3 Emulator
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* 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 (license.txt); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* bridge.h
*
* MPC105 and MPC106 PCI bridge/memory controller header.
*/
#ifndef INCLUDED_BRIDGE_H
#define INCLUDED_BRIDGE_H
extern UINT8 bridge_read_8(UINT32);
extern UINT16 bridge_read_16(UINT32);
extern UINT32 bridge_read_32(UINT32);
extern void bridge_write_8(UINT32, UINT8);
extern void bridge_write_16(UINT32, UINT16);
extern void bridge_write_32(UINT32, UINT32);
extern UINT8 bridge_read_config_data_8(UINT32);
extern UINT16 bridge_read_config_data_16(UINT32);
extern UINT32 bridge_read_config_data_32(UINT32);
extern void bridge_write_config_addr_32(UINT32, UINT32);
extern void bridge_write_config_data_8(UINT32, UINT8);
extern void bridge_write_config_data_16(UINT32, UINT16);
extern void bridge_write_config_data_32(UINT32, UINT32);
extern void bridge_save_state(FILE *);
extern void bridge_load_state(FILE *);
extern void bridge_reset(INT);
extern void bridge_init(UINT32 (*)(UINT32));
#endif // INCLUDED_BRIDGE_H

292
core/controls.c Normal file
View file

@ -0,0 +1,292 @@
/*
* Sega Model 3 Emulator
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* 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 (license.txt); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
//TODO: In controls_write(): Is EEPROM only written when bank_select = 1?
// This makes little sense because banking affects reg 4 only, right?
// Also, should EEPROM reads only be performed when bank_select=1?
/*
* controls.c
*
* Control emulation.
*/
/*
* Lost World Gun Notes:
* ---------------------
*
* MCU Command Reg = 0x24 (byte)
* MCU Arg Reg = 0x28 (byte)
*
* Procedure for issuing commands:
* 1. Arg written first, then command.
* 2. Waits on reg 0x34 (see Stefano's post to model3 group for details.)
* 3. Reads a byte from 0x2C, then a byte from 0x30.
*
* Command 0x00: Set address (in arg reg.)
* Command 0x87: Read gun data.
*
* Virtual On 2 Notes:
* -------------------
*
* Control Area Offset 0x08: Lever 1, LRUD??TS (T = Turbo, S = Shot Trigger)
* 0x0C: Lever 2
* 0x18: Dipswitch, bits 7-0 = DS1-8
*
* Dipswitch bit 0x20 (DS3) should be cleared otherwise some test is performed
* by Virtual On 2 at boot-up.
*/
#include "model3.h"
/******************************************************************/
/* Privates */
/******************************************************************/
/*
* Register Set
*/
static UINT8 controls_reg[0x40];
static UINT8 controls_reg_bank[2];
static BOOL controls_bank_select;
/*
* Gun Data
*
* Gun data is read by communicating with the MCU. An address is passed and
* some data is read back. The total number of data bytes that the MCU stores
* and can address is unknown, but I assume 16 (Stefano: Is this correct?)
*
* Here is how gun data is stored:
*
* Offset 0: player 1 gun X position, lower 8 bits
* 1: player 1 gun X position, upper 3 bits
* 2: player 1 gun Y position, lower 8 bits
* 3: player 1 gun Y position, upper 3 bits
* 4: player 2 gun X position, lower 8 bits
* 5: player 2 gun X position, upper 3 bits
* 6: player 2 gun Y position, lower 8 bits
* 7: player 2 gun Y position, upper 3 bits
* 8: bit 0 = player 1 gun position status (0=aquired 1=lost)
* bit 1 = player 2 gun position status (0=aquired 1=lost)
*
* I think Stefano also said that the X and Y may be reversed and that the gun
* coordinates are only 10 bits, not 11.
*/
static UINT8 gun_data[16];
static int gun_data_ptr; // which address within gun_data[]
static UINT8 analog_axis[8];
static int analog_control = 0; // Currently used register
/******************************************************************/
/* Interface */
/******************************************************************/
void controls_shutdown(void)
{
}
void controls_init(void)
{
}
void controls_reset(UINT32 flags)
{
memset(controls_reg_bank, 0xFF, 2);
memset(controls_reg, 0xFF, 0x40);
memset(controls_reg, 0x00, 8);
// controls_reg[0x18] = 0xDF; // clear bit 0x20 for Virtual On 2
controls_reg[0x18] = 0xff;
}
void controls_update(void)
{
int i;
OSD_CONTROLS *c;
UINT gun_x, gun_y;
c = osd_input_update_controls();
controls_reg_bank[0] = c->system_controls[0];
controls_reg_bank[1] = c->system_controls[1];
controls_reg[0x08] = c->game_controls[0];
controls_reg[0x0C] = c->game_controls[1];
/*
* TEMP: This should be changed so that only games with guns have this
* updated
*/
/*
* Gun Coordinates:
*
* Coordinates returned by the MCU are sight position coordinates. The OSD
* input code returns coordinates in the range of (0,0)-(485,383).
*
* X adjustment: 400 must be added to the sight position in order to
* locate the gun at screen X = 0.
*
* Y adjustment: Sight coordinate 0 maps to screen coordinate 272. Sight
* coordinate 272 maps to screen coordinate 0. Sight coordinate 383 maps
* to -111.
*/
gun_y = c->gun_y[0];
// if (gun_y <= 272)
// gun_y = 272 - gun_y;
// else
gun_x = c->gun_x[0];// + 400;
gun_data[0] = gun_y & 0xFF;
gun_data[1] = (gun_y >> 8) & 7;
gun_data[2] = gun_x & 0xFF;
gun_data[3] = (gun_x >> 8) & 7;
gun_y = c->gun_y[1];
gun_x = c->gun_x[1] + 400;
gun_data[4] = gun_y & 0xFF;
gun_data[5] = (gun_y >> 8) & 7;
gun_data[6] = gun_x & 0xFF;
gun_data[7] = (gun_x >> 8) & 7;
gun_data[8] = (!!c->gun_acquired[0]) | ((!!c->gun_acquired[1]) << 1);
// Steering Wheel controls
// Register 0: Steering wheel, 0x80 is center
// Register 1: Acceleration, 0x00 - 0xFF
// Register 2: Brake, 0x00 - 0xFF
// Registers 3 - 7 are either unused or unknown
for (i=0; i < 8; i++)
{
analog_axis[i] = c->analog_axis[i] & 0xff;
}
}
/*
* void controls_save_state(FILE *fp);
*
* Saves the state of the controls to a file.
*
* Parameters:
* fp = File to save to.
*/
void controls_save_state(FILE *fp)
{
fwrite(controls_reg, sizeof(UINT8), 0x40, fp);
fwrite(controls_reg_bank, sizeof(UINT8), 2, fp);
fwrite(&controls_bank_select, sizeof(BOOL), 1, fp);
}
/*
* void controls_load_state(FILE *fp);
*
* Loads the state of the controls from a file.
*
* Parameters:
* fp = File to load from.
*/
void controls_load_state(FILE *fp)
{
fread(controls_reg, sizeof(UINT8), 0x40, fp);
fread(controls_reg_bank, sizeof(UINT8), 2, fp);
fread(&controls_bank_select, sizeof(BOOL), 1, fp);
}
/******************************************************************/
/* Access */
/******************************************************************/
/* these are only 8-bit wide, byte-aligned */
/* additional data/address adjustement must be performed by the main handler */
UINT8 controls_read(UINT32 a)
{
a &= 0x3F;
switch (a)
{
case 0x4:
{
// should this only be done when bank_select = 1?
controls_reg_bank[1] &= ~0x20; // clear data bit before ORing it in
controls_reg_bank[1] |= (eeprom_read_bit() & 1) << 5;
return controls_reg_bank[controls_bank_select];
}
case 0x3C:
{
// I don't know if the register to be read can be selected.
UINT8 analog_data = analog_axis[analog_control & 0x7];
analog_control++;
return analog_data;
}
}
// LOG("model3.log", "CTRL %02X READ\n", a);
return controls_reg[a];
}
void controls_write(UINT32 a, UINT8 d)
{
a &= 0x3F;
controls_reg[a] = d;
switch(a)
{
case 0x0:
{
controls_bank_select = d & 1;
// if(controls_bank_select == 1)
{
eeprom_set_clk((d & 0x80) ? 1 : 0);
eeprom_set_ce((d & 0x40) ? 1 : 0);
eeprom_set_data((d & 0x20) ? 1 : 0);
}
break;
}
case 0x24: // MCU command
{
switch (d)
{
case 0x00: // set address for gun data (it's already in the arg reg)
gun_data_ptr = controls_reg[0x28] & 0xF;
break;
case 0x87: // read data back from gun
controls_reg[0x2c] = 0; // unused?
controls_reg[0x30] = gun_data[gun_data_ptr];
break;
}
break;
}
}
// LOG("model3.log", "CTRL%02X = %02X\n", a, d);
}

41
core/controls.h Normal file
View file

@ -0,0 +1,41 @@
/*
* Sega Model 3 Emulator
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* 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 (license.txt); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* controls.h
*
* Controls header.
*/
#ifndef INCLUDED_CONTROLS_H
#define INCLUDED_CONTROLS_H
extern void controls_init(void);
extern void controls_shutdown(void);
extern void controls_reset(UINT32 flags);
extern void controls_update(void);
extern void controls_save_state(FILE *);
extern void controls_load_state(FILE *);
extern UINT8 controls_read(UINT32 a);
extern void controls_write(UINT32 a, UINT8 d);
#endif // INCLUDED_CONTROLS_H

371
core/dma.c Normal file
View file

@ -0,0 +1,371 @@
/*
* Sega Model 3 Emulator
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* 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 (license.txt); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* dma.c
*
* Step 2.0+ DMA device emulation. We're unsure whether or not this is a SCSI
* controller; it appears to only be used for its DMA capabilities and is
* thought to be a Sega custom part.
*/
/*
* 0xC2000000 32-bit -W DMA Source
* 0xC2000004 32-bit -W DMA Destination
* 0xC2000008 32-bit -W DMA Length (in words)
* 0xC200000C 8-bit RW DMA Status? AxxxxxxB (A and B must be cleared)
* 0xC200000D 8-bit -W DMA Control? xxxxxxx? (bit0 clears C200000C bit0)
* 0xC200000E 8-bit -W DMA Config?
* 0xC2000010 32-bit -W DMA Command? (Written, result appears at 0x14)
* 0xC2000014 32-bit R- DMA Command Result
*/
#include "model3.h"
/******************************************************************/
/* Private Variables */
/******************************************************************/
/*
* Registers
*/
static UINT8 dma_regs[0x20];
/*
* Read/Write Handlers
*
* These are used as an interface to the rest of the system.
*/
static UINT32 (*read_32)(UINT32);
static void (*write_32)(UINT32, UINT32);
/******************************************************************/
/* DMA Transfer */
/******************************************************************/
/*
* do_dma():
*
* Performs a DMA transfer. The paramaters are expected to be in the
* appropriate registers.
*/
#ifdef _PROFILE_
extern UINT is_dma;
#endif
static void do_dma(void)
{
UINT32 src, dest, len;
PROFILE_SECT_ENTRY("dma");
#ifdef _PROFILE_
is_dma = 1;
#endif
src = *(UINT32 *) &dma_regs[0x00];
dest = *(UINT32 *) &dma_regs[0x04];
len = (*(UINT32 *) &dma_regs[0x08]) * 4;
LOG("model3.log", "DMA %08X -> %08X, %X\n", src, dest, len);
if ((dma_regs[0x0E] & 0x80)) // swap words
{
/*while (len)
{
write_32(dest, BSWAP32(read_32(src)));
src += 4;
dest += 4;
len -= 4;
}*/
model3_dma_transfer(src, dest, len, TRUE);
}
else
{
/*while (len)
{
write_32(dest, read_32(src));
src += 4;
dest += 4;
len -= 4;
}*/
model3_dma_transfer(src, dest, len, FALSE);
}
#ifdef _PROFILE_
is_dma = 0;
#endif
*(UINT32 *) &dma_regs[0x08] = 0; // not sure if this is necessary
/*
* An IRQ may be generated by the DMA device after a copy is performed (or
* at some other time.)
*
* Evidence for this is in Harley Davidson's ISR. The subroutine at 0x8ABE8
* appears to check the status register bit 0 and performs a copy if it is
* set (after first clearing it.)
*
* Here, bit 0 is set, an IRQ is triggered, and the code will clear bit 0 by
* writing a 1 to bit 0 of DMA reg 0xD.
*/
dma_regs[0x0C] |= 1; // this bit may indicate IRQ raised
ppc_set_irq_line(1);
PROFILE_SECT_EXIT("dma");
}
/******************************************************************/
/* Interface */
/******************************************************************/
/*
* void dma_shutdown(void);
*
* Shuts down the DMA device emulation.
*/
void dma_shutdown(void)
{
}
/*
* void dma_init(UINT32 (*read32)(UINT32), void (*write32)(UINT32, UINT32));
*
* Initializes the DMA device emulation by setting the memory access handlers.
*
* Parameters:
* read32 = Handler to use for 32-bit reads.
* write32 = Handler to use for 32-bit writes.
*/
void dma_init(UINT32 (*read32)(UINT32), void (*write32)(UINT32, UINT32))
{
read_32 = read32;
write_32 = write32;
}
/*
* void dma_reset(void);
*
* Resets the DMA device.
*/
void dma_reset(void)
{
memset(dma_regs, 0, 0x20);
}
/*
* void dma_save_state(FILE *fp);
*
* Saves the state of the DMA device (for Step 2.0 or higher games only) to a
* file.
*
* Parameters:
* fp = File to save to.
*/
void dma_save_state(FILE *fp)
{
if (m3_config.step < 0x20)
return;
fwrite(dma_regs, sizeof(UINT8), 0x20, fp);
}
/*
* void dma_load_state(FILE *fp);
*
* Loads the state of the DMA device (for Step 2.0 or higher games only) from
* a file.
*
* Parameters:
* fp = File to load from.
*/
void dma_load_state(FILE *fp)
{
if (m3_config.step < 0x20)
return;
fread(dma_regs, sizeof(UINT8), 0x20, fp);
}
/******************************************************************/
/* Access */
/******************************************************************/
/*
* UINT8 dma_read_8(UINT32 a);
*
* Reads a byte from the DMA device.
*
* Parameters:
* a = Address.
*
* Returns:
* Data read.
*/
UINT8 dma_read_8(UINT32 a)
{
// message(0, "%08X: Unknown DMA read8, %08X", PPC_PC, a);
return dma_regs[a & 0x1F];
}
/*
* UINT32 dma_read_32(UINT32 a);
*
* Reads a word from the DMA device.
*
* Parameters:
* a = Address.
*
* Returns:
* Data read.
*/
UINT32 dma_read_32(UINT32 a)
{
// message(0, "%08X: Unknown DMA read32, %08X", PPC_PC, a);
return BSWAP32(*(UINT32 *) &dma_regs[a & 0x1F]);
}
/*
* void dma_write_8(UINT32 a, UINT8 d);
*
* Writes a byte to the DMA device.
*
* Parameters:
* a = Address.
* d = Data to write.
*/
void dma_write_8(UINT32 a, UINT8 d)
{
dma_regs[a & 0x1F] = d;
switch (a & 0x1F)
{
case 0xD:
if ((d & 1)) // clear status bit 0
dma_regs[0xC] &= ~1;
break;
default:
LOG("model3.log", "%08X: Unknown DMA write8, %08X = %02X\n", ppc_get_pc(), a, d);
break;
}
}
/*
* void dma_write_16(UINT32 a, UINT16 d);
*
* Writes a half-word to the DMA device.
*
* Parameters:
* a = Address.
* d = Data to write.
*/
void dma_write_16(UINT32 a, UINT16 d)
{
switch (a & 0x1F)
{
case 0x14:
message(0, "%08X = %04X", a, d);
LOG("model3.log", "DMA %08X = %04X\n", a, d);
break;
default:
error("unknown DMA write: %08X = %04X", a, d);
break;
}
}
/*
* void dma_write_32(UINT32 a, UINT32 d);
*
* Writes a word to the DMA device.
*
* Parameters:
* a = Address.
* d = Data to write.
*/
void dma_write_32(UINT32 a, UINT32 d)
{
d = BSWAP32(d); // this is a little endian device, only bswap here once
*(UINT32 *) &dma_regs[a & 0x1F] = d;
switch (a & 0x1F)
{
case 0x00: // DMA Source
// message(0, "DMA SRC = %08X", d);
return;
case 0x04: // DMA Destination
// message(0, "DMA DST = %08X", d);
return;
case 0x08: // DMA Length
// message(0, "DMA LEN = %X", d * 4);
do_dma();
return;
case 0x10: // DMA Command
/*
* Virtual On 2 has been observed to write commands to reg 0x10 and
* then expects particular values back from 0x14.
*
* Command 0x80000000 is a little strange. It is issued and twice and
* each time, a bit of the result is expected to be different. This
* is crudely simulated by flipping a bit.
*
* Virtua Striker 2 '99 does something similar, except that it writes
* commands 0x80000000, 0x80000004, ... 0x80000020.
*/
if (d & 0x20000000)
*(UINT32 *) &dma_regs[0x14] = 0x178611db; //0x16C311DB; // PCI Vendor and Device ID
else if ((d & 0x80000000))
*(UINT32 *) &dma_regs[0x14] = r3d_read_32((d & 0xFF) | 0x84000000);
#if 0
else if (d == 0x80000000)
{
static UINT32 result = 0x02000000;
result ^= 0x02000000;
*(UINT32 *) &dma_regs[0x14] = result;
}
#endif
else
message(0, "%08X: Unknown DMA command, %08X", ppc_get_pc(), d);
return;
case 0x14:
*(UINT32 *) &dma_regs[0x14] = 0xffffffff;
return;
}
message(0, "%08X: Unknown DMA write32, %08X = %08X", ppc_get_pc(), a, d);
}

42
core/dma.h Normal file
View file

@ -0,0 +1,42 @@
/*
* Sega Model 3 Emulator
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* 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 (license.txt); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* dma.h
*
* Step 2.0+ DMA device header.
*/
#ifndef INCLUDED_DMA_H
#define INCLUDED_DMA_H
extern void dma_init(UINT32 (*)(UINT32), void (*)(UINT32, UINT32));
extern void dma_shutdown(void);
extern void dma_reset(void);
extern void dma_save_state(FILE *);
extern void dma_load_state(FILE *);
extern UINT8 dma_read_8(UINT32 a);
extern UINT32 dma_read_32(UINT32 a);
extern void dma_write_8(UINT32 a, UINT8 d);
extern void dma_write_16(UINT32 a, UINT16 d);
extern void dma_write_32(UINT32 a, UINT32 d);
#endif // INCLUDED_DMA_H

71
core/dsb1.c Normal file
View file

@ -0,0 +1,71 @@
/*
* Sega Model 3 Emulator
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* 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 (license.txt); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* dsb1.c
*
* DSB1 Digital Sound Board emulation.
*/
#include "model3.h"
void dsb1_init(void)
{
}
void dsb1_reset(void)
{
}
void dsb1_shutdown(void)
{
}
/*
* void dsb1_save_state(FILE *fp);
*
* Saves the state of the DSB1 (for games which have it) to a file.
*
* Parameters:
* fp = File to save to.
*/
void dsb1_save_state(FILE *fp)
{
if (!(m3_config.flags & GAME_OWN_DSB1))
return;
}
/*
* void dsb1_load_state(FILE *fp);
*
* Loads the state of the DSB1 (for games which have it) from a file.
*
* Parameters:
* fp = File to load from.
*/
void dsb1_load_state(FILE *fp)
{
if (!(m3_config.flags & GAME_OWN_DSB1))
return;
}

36
core/dsb1.h Normal file
View file

@ -0,0 +1,36 @@
/*
* Sega Model 3 Emulator
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* 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 (license.txt); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* dsb1.h
*
* DSB1 Digital Sound Board header.
*/
#ifndef _DSB1_H_
#define _DSB1_H_
extern void dsb1_init(void);
extern void dsb1_shutdown(void);
extern void dsb1_reset(void);
extern void dsb1_save_state(FILE *);
extern void dsb1_load_state(FILE *);
#endif /* _DSB1_H_ */

391
core/eeprom.c Normal file
View file

@ -0,0 +1,391 @@
/*
* Sega Model 3 Emulator
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* 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 (license.txt); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* eeprom.c
*
* 93C46 EEPROM emulation courtesy of R. Belmont.
*
* NOTE: Save state code assumes enums will be the same across all compilers
* and systems. The eeprom_store[] array is endian-dependent.
*/
/***************************************************************************
eeprom.cpp - handles a serial eeprom with 64 16-bit addresses and 4-bit commands
as seen in st-v, system 32, many konami boards, etc.
originally written: May 20, 2000 by R. Belmont for "sim"
update: Jan 27, 2001 (RB): implemented "erase" opcode,
made opcode fetch check for start bit
like the real chip.
Mar 26, 2001 (FF): added get_image to access the eeprom
Jan 28, 2004 (Bart): Interface changes to work with Supermodel.
Crudely simulated busy status by setting olatch to 0 in
ES_DESELECT.
***************************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "model3.h"
#define LOG_EEPROM 0 // log channel for EEPROM
static INT32 eeprom_state;
static UINT16 eeprom_store[64]; // 6 address bits times 16 bits per location
static UINT8 opcode; // current opcode
static UINT8 adr; // current address in eeprom_store
static UINT8 curbit; // current bit # in read/write/addr fetch operation
static UINT8 lastclk; // last clock
static UINT8 dlatch; // input data latch
static UINT8 olatch; // output data latch
static UINT16 curio;
// states for the eeprom state machine
enum
{
ES_DESELECT = 0,// chip select not asserted
ES_ASSERT, // chip select asserted, waiting for opcode
ES_OPCODE0, // got opcode bit 0
ES_OPCODE1, // got opcode bit 1
ES_OPCODE2, // got opcode bit 2
ES_ADRFETCH, // fetching address
ES_READBITS, // reading bits, 1 out every time clock goes high
ES_WRITEBITS, // writing bits, 1 in every time clock goes high
ES_WAITING // done with read/write, waiting for deselect to finalize
};
/*
* UINT8 eeprom_read_bit(void);
*
* Reads a data bit from the EEPROM.
*
* Returns:
* Latched data bit.
*/
UINT8 eeprom_read_bit(void)
{
return olatch;
}
/*
* void eeprom_set_ce(UINT8 ce);
*
* Passes the status of the chip enable.
*
* Parameters:
* ce = Chip enable bit (must be 0 or 1.)
*/
void eeprom_set_ce(UINT8 ce)
{
// chip enable
if (ce)
{
// asserting CE - if deselected,
// select. if selected already,
// ignore
if (eeprom_state == ES_DESELECT)
{
// printf("EEPROM: asserting chip enable\n");
eeprom_state = ES_ASSERT;
opcode = 0;
}
}
else
{
// deasserting CE
// printf("EEPROM: deasserting chip enable\n");
eeprom_state = ES_DESELECT;
}
}
/*
* void eeprom_set_data(UINT8 data);
*
* Sets the data bit latch.
*
* Parameters:
* data = Data bit (must be 0 or 1.)
*/
void eeprom_set_data(UINT8 data)
{
dlatch = (data&0x01); // latch the data
}
/*
* void eeprom_set_clk(UINT8 clk);
*
* Sets the clock pin.
*
* Parameters:
* clk = Clock (zero or non-zero.)
*/
void eeprom_set_clk(UINT8 clk)
{
// things only happen on the rising edge of the clock
if ((!lastclk) && (clk))
{
switch (eeprom_state)
{
case ES_DESELECT:
olatch = 0;
break;
case ES_ASSERT:
case ES_OPCODE0:
case ES_OPCODE1:
case ES_OPCODE2:
// first command bit must be a "1" in the real device
if ((eeprom_state == ES_OPCODE0) && (dlatch == 0))
{
#if LOG_EEPROM
LOG("model3.log", "EEPROM: waiting for start bit\n");
#endif
olatch = 1; // assert READY
}
else
{
opcode <<= 1;
opcode |= dlatch;
#if LOG_EEPROM
LOG("model3.log", "EEPROM: opcode fetch state, currently %x\n", opcode);
#endif
eeprom_state++;
}
curbit = 0;
adr = 0;
break;
case ES_ADRFETCH: // fetch address
adr <<= 1;
adr |= dlatch;
#if LOG_EEPROM
LOG("model3.log", "EEPROM: address fetch state, cur addr = %x\n", adr);
#endif
curbit++;
if (curbit == 6)
{
switch (opcode)
{
case 4: // write enable - go back to accept a new opcode immediately
opcode = 0;
eeprom_state = ES_ASSERT;
//printf("EEPROM: write enable\n");
break;
case 5: // write
eeprom_state = ES_WRITEBITS;
olatch = 0; // indicate not ready yet
curbit = 0;
curio = 0;
break;
case 6: // read
eeprom_state = ES_READBITS;
curbit = 0;
curio = eeprom_store[adr];
//printf("EEPROM: read %04x from address %d\n", curio, adr);
break;
case 7: // erase location to ffff and assert READY
eeprom_store[adr] = 0xffff;
olatch = 1;
eeprom_state = ES_WAITING;
//printf("EEPROM: erase at address %d\n", adr);
break;
default:
#if LOG_EEPROM
LOG("model3.log", "Unknown EEPROM opcode %d!\n", opcode);
#endif
eeprom_state = ES_WAITING;
olatch = 1; // assert READY anyway
break;
}
}
break;
case ES_READBITS:
olatch = ((curio & 0x8000)>>15);
curio <<= 1;
curbit++;
if (curbit == 16)
{
eeprom_state = ES_WAITING;
}
break;
case ES_WRITEBITS:
curio <<= 1;
curio |= dlatch;
curbit++;
if (curbit == 16)
{
olatch = 1; // indicate success
eeprom_store[adr] = curio;
#if LOG_EEPROM
LOG("model3.log", "EEPROM: Wrote %04x to address %d\n", curio, adr);
#endif
eeprom_state = ES_WAITING;
}
break;
case ES_WAITING:
break;
}
}
lastclk = clk;
}
/*
* void eeprom_save_state(FILE *fp);
*
* Save the EEPROM state.
*
* Parameters:
* fp = File to save to.
*/
void eeprom_save_state(FILE *fp)
{
if (fp != NULL)
{
fwrite(&eeprom_state, sizeof(INT32), 1, fp);
fwrite(eeprom_store, sizeof(UINT16), 64, fp);
fwrite(&opcode, sizeof(UINT8), 1, fp);
fwrite(&adr, sizeof(UINT8), 1, fp);
fwrite(&curbit, sizeof(UINT8), 1, fp);
fwrite(&lastclk, sizeof(UINT8), 1, fp);
fwrite(&dlatch, sizeof(UINT8), 1, fp);
fwrite(&olatch, sizeof(UINT8), 1, fp);
fwrite(&curio, sizeof(UINT16), 1, fp);
}
}
/*
* void eeprom_load_state(FILE *fp);
*
* Load the EEPROM state.
*
* Parameters:
* fp = File to load from.
*/
void eeprom_load_state(FILE *fp)
{
if (fp != NULL)
{
fread(&eeprom_state, sizeof(INT32), 1, fp);
fread(eeprom_store, sizeof(UINT16), 64, fp);
fread(&opcode, sizeof(UINT8), 1, fp);
fread(&adr, sizeof(UINT8), 1, fp);
fread(&curbit, sizeof(UINT8), 1, fp);
fread(&lastclk, sizeof(UINT8), 1, fp);
fread(&dlatch, sizeof(UINT8), 1, fp);
fread(&olatch, sizeof(UINT8), 1, fp);
fread(&curio, sizeof(UINT16), 1, fp);
}
}
/*
* INT eeprom_load(CHAR *fname);
*
* Loads data from the file specified. If the file does not exist, the EEPROM
* data is initialized with all 1's.
*
* Parameters:
* fname = File name.
*
* Returns:
* MODEL3_OKAY = Success.
* MODEL3_ERROR = Error reading from the file.
*/
INT eeprom_load(CHAR *fname)
{
FILE *fp;
INT error_code = MODEL3_ERROR;
message(0, "loading EEPROM from %s", fname);
if ((fp = fopen(fname, "rb")) != NULL)
{
error_code = fread(eeprom_store, sizeof(UINT16), 64, fp);
fclose(fp);
if (error_code == 64)
return MODEL3_OKAY;
}
memset(eeprom_store, 0xFF, sizeof(UINT16) * 64);
return error_code;
}
/*
* INT eeprom_save(CHAR *fname);
*
* Writes out the EEPROM data to the specified file.
*
* Parameters:
* fname = File name to write.
*
* Returns:
* MODEL3_OKAY = Success.
* MODEL3_ERROR = Unable to open or write file.
*/
INT eeprom_save(CHAR *fname)
{
FILE *fp;
INT i = MODEL3_ERROR;
message(0, "saving EEPROM to %s", fname);
if ((fp = fopen(fname, "wb")) != NULL)
{
i = fwrite(eeprom_store, sizeof(UINT16), 64, fp);
fclose(fp);
if (i == 64)
return MODEL3_OKAY;
}
return i;
}
/*
* void eeprom_reset(void);
*
* Resets the EEPROM emulation.
*/
void eeprom_reset(void)
{
eeprom_state = ES_DESELECT;
lastclk = 0;
}

41
core/eeprom.h Normal file
View file

@ -0,0 +1,41 @@
/*
* Sega Model 3 Emulator
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* 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 (license.txt); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* eeprom.h
*
* 93C46 EEPROM emulation header.
*/
#ifndef INCLUDED_EEPROM_H
#define INCLUDED_EEPROM_H
extern UINT8 eeprom_read_bit(void);
extern void eeprom_set_clk(UINT8 clk);
extern void eeprom_set_ce(UINT8 ce);
extern void eeprom_set_data(UINT8 data);
extern void eeprom_save_state(FILE *);
extern void eeprom_load_state(FILE *);
extern INT eeprom_load(CHAR *);
extern INT eeprom_save(CHAR *);
extern void eeprom_reset(void);
#endif // INCLUDED_EEPROM_H

2391
core/model3.c Normal file

File diff suppressed because it is too large Load diff

417
core/model3.h Normal file
View file

@ -0,0 +1,417 @@
/*
* Sega Model 3 Emulator
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* 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 (license.txt); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* model3.h
*
* Model 3 header. This serves as the primary header file for all modules to
* include.
*/
#ifndef INCLUDED_MODEL3_H
#define INCLUDED_MODEL3_H
/******************************************************************/
/* Program Information */
/******************************************************************/
#define VERSION "0.01" // program version
#define VERSION_MAJOR 0x00 // major version number (BCD)
#define VERSION_MINOR 0x01 // minor version number (BCD)
/******************************************************************/
/* Includes */
/******************************************************************/
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
//#include "zlib.h"
#include "osd.h" // provided by the port to define data types, etc.
#include "ppc_itp/ppc.h"
//#include "m68k/m68k.h"
#include "controls.h"
#include "dma.h"
#include "dsb1.h"
#include "eeprom.h"
#include "bridge.h"
#include "r3d.h"
#include "render.h"
#include "rtc.h"
#include "scsi.h"
#include "scsp.h"
#include "tilegen.h"
#include "file.h"
#include "osd_common.h" // defines OSD interface (must be included last)
/******************************************************************/
/* Helpful Macros */
/******************************************************************/
#define MODEL3_OKAY 0 /* Everything went okay */
#define MODEL3_ERROR -1 /* Some error happened */
#define MODEL3_SCREEN_WIDTH 496
#define MODEL3_SCREEN_HEIGHT 384
#define SAFE_FREE(p) { if(p != NULL) free(p); p = NULL; }
#define PPC_PC ppc_get_reg(PPC_REG_PC)
#define PPC_LR ppc_get_reg(PPC_REG_LR)
#ifdef _MSC_VER
#define BSWAP16(x) _byteswap_ushort(x)
#define BSWAP32(x) _byteswap_ulong(x)
#else
static UINT16 BSWAP16(UINT16 d)
{
return(((d >> 8) & 0x00FF) |
((d << 8) & 0xFF00));
}
static UINT32 BSWAP32(UINT32 d)
{
return(((d >> 24) & 0x000000FF) |
((d >> 8) & 0x0000FF00) |
((d << 8) & 0x00FF0000) |
((d << 24) & 0xFF000000));
}
#endif
/******************************************************************/
/* Configuration Structure */
/******************************************************************/
/*
* Game Flags
*
* Identify various properties that the games can have.
*/
#define GAME_OWN_STEERING_WHEEL (1 << 0) // analog steering wheel
#define GAME_OWN_GUN (1 << 1) // light gun
#define GAME_OWN_DSB1 (1 << 2) // DSB1 sound board
typedef enum
{
P1_BUTTON_1,
P1_BUTTON_2,
P1_BUTTON_3,
P1_BUTTON_4,
P1_BUTTON_5,
P1_BUTTON_6,
P1_BUTTON_7,
P1_BUTTON_8,
P2_BUTTON_1,
P2_BUTTON_2,
P2_BUTTON_3,
P2_BUTTON_4,
P2_BUTTON_5,
P2_BUTTON_6,
P2_BUTTON_7,
P2_BUTTON_8,
P1_JOYSTICK_UP,
P1_JOYSTICK_DOWN,
P1_JOYSTICK_LEFT,
P1_JOYSTICK_RIGHT,
P2_JOYSTICK_UP,
P2_JOYSTICK_DOWN,
P2_JOYSTICK_LEFT,
P2_JOYSTICK_RIGHT,
} GAME_BUTTON;
typedef enum
{
ANALOG_AXIS_1,
ANALOG_AXIS_2,
ANALOG_AXIS_3,
ANALOG_AXIS_4,
ANALOG_AXIS_5,
ANALOG_AXIS_6,
ANALOG_AXIS_7,
ANALOG_AXIS_8,
} GAME_ANALOG;
typedef struct
{
struct
{
UINT8 control_set;
UINT8 control_bit;
GAME_BUTTON mapping;
int enabled;
} button[16];
struct
{
GAME_ANALOG mapping;
int enabled;
UINT8 center;
} analog_axis[8];
} GAME_CONTROLS;
/*
* CONFIG Structure
*
* Emulator configuration and game information.
*/
typedef struct
{
/*
* Emulator Configuration
*
* Determines the behavior of the emulator itself. These fields can be
* loaded, saved, and modified. The user has control over these options.
*/
BOOL log_enabled; // whether to log (no effect if _LOG_ not defined)
BOOL fullscreen;
BOOL triple_buffer;
INT width;
INT height;
BOOL stretch;
FLAGS layer_enable;
CHAR rom_path[512];
CHAR rom_list[512];
CHAR backup_path[512];
BOOL fps_limit;
BOOL show_fps;
/*
* Game Configuration
*
* Information on the game currently being emulated. The user has no
* control over this stuff -- it's internal to the emulator only.
*/
CHAR game_id[8+1]; // game ID string (max 8 chars + null terminator)
CHAR game_name[128];
INT step; // hardware step (0x15 = Step 1.5, etc.)
INT bridge; // type of PCIBMC (1=MPC105, 2=MPC106)
FLAGS flags; // game info flags
BOOL has_lightgun;
// Game controls
GAME_CONTROLS controls;
} CONFIG;
enum
{
ROMTYPE_NONE = 0,
ROMTYPE_PROG0 = 1,
ROMTYPE_PROG1,
ROMTYPE_PROG2,
ROMTYPE_PROG3,
ROMTYPE_CROM00,
ROMTYPE_CROM01,
ROMTYPE_CROM02,
ROMTYPE_CROM03,
ROMTYPE_CROM10,
ROMTYPE_CROM11,
ROMTYPE_CROM12,
ROMTYPE_CROM13,
ROMTYPE_CROM20,
ROMTYPE_CROM21,
ROMTYPE_CROM22,
ROMTYPE_CROM23,
ROMTYPE_CROM30,
ROMTYPE_CROM31,
ROMTYPE_CROM32,
ROMTYPE_CROM33,
ROMTYPE_VROM00,
ROMTYPE_VROM01,
ROMTYPE_VROM02,
ROMTYPE_VROM03,
ROMTYPE_VROM04,
ROMTYPE_VROM05,
ROMTYPE_VROM06,
ROMTYPE_VROM07,
ROMTYPE_VROM10,
ROMTYPE_VROM11,
ROMTYPE_VROM12,
ROMTYPE_VROM13,
ROMTYPE_VROM14,
ROMTYPE_VROM15,
ROMTYPE_VROM16,
ROMTYPE_VROM17,
ROMTYPE_SPROG,
ROMTYPE_SROM0,
ROMTYPE_SROM1,
ROMTYPE_SROM2,
ROMTYPE_SROM3,
ROMTYPE_DSBPROG,
ROMTYPE_DSBROM0,
ROMTYPE_DSBROM1,
ROMTYPE_DSBROM2,
ROMTYPE_DSBROM3,
};
typedef struct
{
int type;
char name[20];
int size;
UINT32 crc32;
int load;
} ROMFILE;
typedef struct {
UINT32 address;
UINT32 data;
INT size; // 8, 16, or 32
} PATCH;
typedef struct
{
char game[20];
char parent[20];
char title[256];
char manufacturer[32];
int year;
int step;
int bridge;
int cromsize;
FLAGS flags;
int num_patches;
PATCH patch[64];
ROMFILE rom[64];
GAME_CONTROLS controls;
} ROMSET;
typedef struct
{
char id[60];
UINT32 int_id;
} STRING_ID;
static int get_string_id(const char *string, STRING_ID *idtable)
{
int i=0;
while (strlen(idtable[i].id) > 0)
{
if (_stricmp(string, idtable[i].id) == 0)
{
return idtable[i].int_id;
}
i++;
}
return -1;
}
/*
* m3_config
*
* A global variable accessible by all parts of the emulator after emulation
* begins successfully.
*/
extern CONFIG m3_config;
extern void message(int, char * fmt, ...);
extern void error(char * fmt, ...);
extern BOOL parse_config(const char *config_name);
extern int parse_romlist(char *romlist_name, ROMSET *_romset);
/*
* Profile
*/
extern void profile_section_entry(CHAR * name);
extern void profile_section_exit(CHAR * name);
extern UINT64 profile_get_stat(CHAR * name);
extern void profile_reset_sect(CHAR * name);
extern void profile_cleanup(void);
extern void profile_print(CHAR * string);
#ifdef _PROFILE_
#define PROFILE_SECT_ENTRY(n) profile_section_entry(n);
#define PROFILE_SECT_EXIT(n) profile_section_exit(n);
#define PROFILE_SECT_RESET(n) profile_reset_sect(n);
#else // !_PROFILE_
#define PROFILE_SECT_ENTRY(n)
#define PROFILE_SECT_EXIT(n)
#define PROFILE_SECT_RESET(n)
#endif // _PROFILE_
/******************************************************************/
/* Functions */
/******************************************************************/
#ifdef _LOG_
#define LOG_INIT _log_init
#define LOG _log
#else // !_LOG_
#define LOG_INIT
#define LOG
#endif // _LOG
extern void _log(char * path, char * fmt, ...);
extern void _log_init(char * path);
extern BOOL model3_init(void);
extern void model3_shutdown(void);
extern BOOL model3_load(void);
extern void model3_reset(void);
extern void model3_run_frame(void);
extern void model3_add_irq(UINT8);
extern void model3_remove_irq(UINT8);
extern BOOL model3_save_state(CHAR *);
extern BOOL model3_load_state(CHAR *);
extern void model3_load_eeprom(void);
extern void model3_save_eeprom(void);
extern void model3_load_bram(void);
extern void model3_save_bram(void);
extern UINT8 m3_ppc_read_8(UINT32 a);
extern UINT16 m3_ppc_read_16(UINT32 a);
extern UINT32 m3_ppc_read_32(UINT32 a);
extern UINT64 m3_ppc_read_64(UINT32 a);
extern void m3_ppc_write_8(UINT32 a, UINT8 d);
extern void m3_ppc_write_16(UINT32 a, UINT16 d);
extern void m3_ppc_write_32(UINT32 a, UINT32 d);
extern void m3_ppc_write_64(UINT32 a, UINT64 d);
extern void model3_dma_transfer(UINT32 src, UINT32 dst, int length, BOOL swap_words);
/******************************************************************/
#endif // INCLUDED_MODEL3_H

937
core/r3d.c Normal file
View file

@ -0,0 +1,937 @@
/*
* Sega Model 3 Emulator
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* 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 (license.txt); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* r3d.c
*
* Real3D Model 3 graphics system emulation. The 3D hardware in Model 3 is
* supposedly based on the Pro-1000.
*
* To-Do List:
* -----------
* - In VS2_98, in the attract mode, when the camera zooms in on the score
* board for South Africa vs. Nigeria, the "Nigeria" text texture is
* garbage.
* - RAM texture uploading is too weird to be true.
*/
/*
* RAM Size:
* ---------
*
* It appears that there is 2MB total of "culling RAM." 1MB appears at
* 0x8C000000 and the other at 0x8E000000. Step 1.0 and 1.5 appear to have
* 1MB of polygon RAM, but Step 2.0 (and probably 2.1) clearly uses 2MB.
*/
#include "model3.h"
extern UINT8 *ram;
/******************************************************************/
/* Privates */
/******************************************************************/
static UINT8 *culling_ram_8e; // culling RAM at 0x8E000000
static UINT8 *culling_ram_8c; // culling RAM at 0x8C000000
static UINT8 *polygon_ram; // polygon RAM at 0x98000000
static UINT8 *texture_ram; // texture RAM
static UINT8 *vrom;
static UINT8 texture_buffer_ram[1*1024*1024];
static UINT32 vrom_texture_address;
static UINT32 vrom_texture_header;
static UINT32 texture_last_addr = 0;
static UINT32 texture_header = 0;
/******************************************************************/
/* Interface */
/******************************************************************/
/*
* void r3d_init(UINT8 *culling_ram_8e_ptr, UINT8 *culling_ram_8c_ptr,
* UINT8 *polygon_ram_ptr, UINT8 *texture_ram, UINT8 *vrom_ptr);
*
* Initializes the Real3D graphics emulation.
*
* Parameters:
* culling_ram_8e_ptr = Pointer to 0x8E000000 culling RAM.
* culling_ram_8c_ptr = Pointer to 0x8C000000 culling RAM.
* polygon_ram_ptr = Pointer to polygon RAM.
* texture_ram = Pointer to texture RAM.
* vrom_ptr = Pointer to VROM.
*/
void r3d_init(UINT8 *culling_ram_8e_ptr, UINT8 *culling_ram_8c_ptr,
UINT8 *polygon_ram_ptr, UINT8 *texture_ram_ptr, UINT8 *vrom_ptr)
{
culling_ram_8e = culling_ram_8e_ptr;
culling_ram_8c = culling_ram_8c_ptr;
polygon_ram = polygon_ram_ptr;
texture_ram = texture_ram_ptr;
vrom = vrom_ptr;
LOG_INIT("texture.log");
}
/*
* void r3d_shutdown(void);
*
* Shuts down the Real3D emulation.
*/
void r3d_shutdown(void)
{
}
/*
* void r3d_reset(void);
*
* Resets the Real3D graphics hardware. RAM is cleared in order to prevent
* the renderer from drawing garbage and possibly locking up as a result.
*/
void r3d_reset(void)
{
memset(culling_ram_8e, 0, 1*1024*1024);
memset(culling_ram_8c, 0, 4*1024*1024);
memset(polygon_ram, 0, 2*1024*1024);
memset(texture_ram, 0, 2048*2048*2);
tap_reset();
}
/*
* void r3d_save_state(FILE *fp);
*
* Saves the state of the Real3D graphics hardware to a file.
*
* Parameters:
* fp = File to save to.
*/
void r3d_save_state(FILE *fp)
{
fwrite(culling_ram_8e, sizeof(UINT8), 1*1024*1024, fp);
fwrite(culling_ram_8c, sizeof(UINT8), 4*1024*1024, fp);
fwrite(polygon_ram, sizeof(UINT8), 2*1024*1024, fp);
fwrite(texture_ram, sizeof(UINT8), 2048*2048*2, fp);
}
/*
* void r3d_load_state(FILE *fp);
*
* Loads the state of the Real3D graphics hardware from a file.
*
* Parameters:
* fp = File to load from.
*/
void r3d_load_state(FILE *fp)
{
fread(culling_ram_8e, sizeof(UINT8), 1*1024*1024, fp);
fread(culling_ram_8c, sizeof(UINT8), 4*1024*1024, fp);
fread(polygon_ram, sizeof(UINT8), 2*1024*1024, fp);
fread(texture_ram, sizeof(UINT8), 2048*2048*2, fp);
osd_renderer_invalidate_textures(0, 0, 2048, 2048, texture_ram);
}
/******************************************************************/
/* Texture Memory Management */
/******************************************************************/
static const INT decode[64] =
{
0, 1, 4, 5, 8, 9,12,13,
2, 3, 6, 7,10,11,14,15,
16,17,20,21,24,25,28,29,
18,19,22,23,26,27,30,31,
32,33,36,37,40,41,44,45,
34,35,38,39,42,43,46,47,
48,49,52,53,56,57,60,61,
50,51,54,55,58,59,62,63
};
/*
* store_texture_tile():
*
* Writes a single 8x8 texture tile into the appropriate part of the texture
* sheet.
*/
static void store_texture_tile(UINT x, UINT y, UINT8 *src, UINT bpp, BOOL little_endian)
{
UINT xi, yi, pixel_offs;
UINT16 rgb16;
UINT8 gray8;
for (yi = 0; yi < 8; yi++)
{
for (xi = 0; xi < 8; xi++)
{
/*
* Grab the pixel offset from the decode[] array and fetch the
* pixel word
*/
if (little_endian)
{
if (bpp == 2)
{
/*
* XOR with 1 in little endian mode -- every word contains
* 2 16-bit pixels, thus they are swapped
*/
pixel_offs = decode[(yi * 8 + xi) ^ 1] * 2;
rgb16 = *(UINT16 *) &src[pixel_offs];
}
else
{
pixel_offs = decode[((yi ^ 1) * 8 + (xi ^ 1))];
gray8 = src[pixel_offs];
}
}
else
{
if (bpp == 2)
{
pixel_offs = decode[yi * 8 + xi] * 2;
rgb16 = (src[pixel_offs + 0] << 8) | src[pixel_offs + 1];
}
else
{
pixel_offs = decode[yi * 8 + xi];
gray8 = src[pixel_offs + 0];
}
}
/*
* Store within the texture sheet
*/
if (bpp == 2)
*(UINT16 *) &texture_ram[((y + yi) * 2048 + (x + xi)) * 2] = rgb16;
else
texture_ram[(((y + yi) * 2048 + x) * 2) + xi] = gray8;
}
}
}
/*
* store_texture():
*
* Writes a texture into the texture sheet. The pixel words are not decoded,
* but the 16-bit pixels are converted into a common endianness (little.)
* 8-bit pixels are not expanded into 16-bits.
*
* bpp (bytes per pixel) must be 1 or 2.
*/
static void store_texture(UINT x, UINT y, UINT w, UINT h, UINT8 *src, UINT bpp, BOOL little_endian)
{
UINT xi, yi;
UINT bw;
if(bpp == 2)
bw = 1;
else
bw = 2;
for (yi = 0; yi < h; yi += 8)
{
for (xi = 0; xi < w; xi += 8)
{
store_texture_tile(x + (xi / bw), y + yi, src, bpp, little_endian);
src += 8 * 8 * bpp; // each texture tile is 8x8 and 16-bit color
}
}
}
/*
* upload_texture():
*
* Uploads a texture to texture memory.
*/
// Mipmap starting positions for each level
static const int mipmap_xpos[11] =
{ 1024, 1536, 1792, 1920, 1984, 2016, 2032, 2040, 2044, 2046, 2047 };
static const int mipmap_ypos[11] =
{ 512, 768, 896, 960, 992, 1008, 1016, 1020, 1022, 1023, 0 };
// Mipmap size dividers
static const int mipmap_size[9] =
{ 2, 4, 8, 16, 32, 64, 128, 256, 512 };
static void upload_texture(UINT32 header, UINT8 *src, BOOL little_endian)
{
UINT size_x, size_y, xpos, ypos, bit_depth, mip_ypos, page;
int mipmap_num = 0;
int mxpos, mypos, msize_x, msize_y;
PROFILE_SECT_ENTRY("real3d");
/*
* Model 3 texture RAM appears as 2 2048x1024 textures. When textures are
* uploaded, their size and position within a sheet is given. I treat the
* texture sheet selection bit as an additional bit to the Y coordinate.
*/
size_x = (header >> 14) & 7;
size_y = (header >> 17) & 7;
size_x = (32 << size_x); // width in pixels
size_y = (32 << size_y); // height
ypos = (((header >> 7) & 0x1F) | ((header >> 15) & 0x20)) * 32;
xpos = ((header >> 0) & 0x3F) * 32;
mip_ypos = ((header >> 7) & 0x1F) * 32;
page = (header >> 15 & 0x20) ? 1 : 0;
if( header & 0x00800000 )
bit_depth = 2; // 16-bit texture
else
bit_depth = 1; // 8-bit texture
LOG("texture.log", "%08X %d,%d\t%dx%d\n", header, xpos, ypos, size_x, size_y);
/*
* Render the texture into the texture buffer
*/
switch( (header >> 24) & 0xF )
{
case 0: // Texture with mipmaps
store_texture(xpos, ypos, size_x, size_y, src, bit_depth, little_endian);
osd_renderer_invalidate_textures(xpos, ypos, xpos, ypos, size_x, size_y, texture_ram, 0);
msize_x = size_x;
msize_y = size_y;
// Store mipmaps
while( msize_y > 8 && msize_x > 8 ) {
src += (msize_x * msize_y * bit_depth);
msize_x /= 2;
msize_y /= 2;
mxpos = mipmap_xpos[mipmap_num] + (xpos / mipmap_size[mipmap_num]);
mypos = mipmap_ypos[mipmap_num] + (mip_ypos / mipmap_size[mipmap_num]);
if(page)
mypos += 1024;
mipmap_num++;
store_texture(mxpos, mypos, msize_x, msize_y, src, bit_depth, little_endian);
//osd_renderer_invalidate_textures(mxpos, mypos, xpos, ypos, size_x, size_y, texture_ram, mipmap_num);
}
break;
case 1: // Texture without mipmaps
store_texture(xpos, ypos, size_x, size_y, src, bit_depth, little_endian);
osd_renderer_invalidate_textures(xpos, ypos, xpos, ypos, size_x, size_y, texture_ram, 0);
break;
case 2: // Only mipmaps
msize_x = size_x;
msize_y = size_y;
while( msize_y > 8 && msize_x > 8 ) {
msize_x /= 2;
msize_y /= 2;
mxpos = mipmap_xpos[mipmap_num] + (xpos / mipmap_size[mipmap_num]);
mypos = mipmap_ypos[mipmap_num] + (mip_ypos / mipmap_size[mipmap_num]);
if(page)
mypos += 1024;
mipmap_num++;
store_texture(mxpos, mypos, msize_x, msize_y, src, bit_depth, little_endian);
//osd_renderer_invalidate_textures(mxpos, mypos, xpos, ypos, size_x, size_y, texture_ram, mipmap_num);
src += (msize_x * msize_y * bit_depth);
}
break;
}
/*
* Remove any existing textures that may have been overwritten
*/
//osd_renderer_invalidate_textures(xpos, ypos, size_x, size_y);
PROFILE_SECT_EXIT("real3d");
}
/******************************************************************/
/* Access */
/******************************************************************/
static BOOL trigger = 0;
static UINT64 trigger_time;
/*
* UINT32 r3d_read_32(UINT32 a);
*
* Reads a 32-bit word from the Real3D regions.
*
* Parameters:
* a = Address.
*
* Returns:
* Data read.
*/
UINT32 r3d_read_32(UINT32 a)
{
static UINT32 _84000000 = 0;
// message(0, "%08X (%08X): Real3D read32 to %08X", PPC_PC, PPC_LR, a);
switch (a)
{
/*
* In Lost World, routine at 0x1174E0 reads all the 0x840000XX status
* registers and at 0x117A30, bit 0x02000000 is checked for.
*/
case 0x84000000:
return (_84000000 ^= 0xFFFFFFFF);
case 0x84000004: // unknown
case 0x84000008:
case 0x8400000C:
case 0x84000010:
case 0x84000014:
case 0x84000018:
case 0x8400001C:
case 0x84000020:
return 0xFFFFFFFF;
}
error("Unknown R3D read: %08X: %08X\n", ppc_get_pc(), a);
return(0);
}
/*
* void r3d_write_32(UINT32 a, UINT32 d);
*
* Writes a 32-bit word to the Real3D regions.
*
* Parameters:
* a = Address.
* d = Data to write.
*/
UINT32 _9C000000, _9C000004, _9C000008;
static int texture_start_pos = 8;
static int texture_ram_ptr = 0;
void r3d_write_32(UINT32 a, UINT32 d)
{
static UINT32 last_addr;
if (a >= 0x8E000000 && a <= 0x8E0FFFFF) // culling RAM
{
*(UINT32 *) &culling_ram_8e[a & 0xFFFFF] = BSWAP32(d);
return;
}
else if (a >= 0x8C000000 && a <= 0x8C3FFFFF) // culling RAM
{
*(UINT32 *) &culling_ram_8c[a & 0x3FFFFF] = BSWAP32(d);
return;
}
else if (a >= 0x98000000 && a <= 0x981FFFFF) // polygon RAM
{
// if(a >= 0x98001000 && a < 0x98002000)
// message(1, "color table: %08X = %08X", a, BSWAP32(d));
*(UINT32 *) &polygon_ram[a & 0x1FFFFF] = BSWAP32(d);
return;
}
else if (a >= 0x94000000 && a <= 0x940FFFFF) // texture buffer
{
d = BSWAP32(d);
*(UINT32 *)&texture_buffer_ram[texture_ram_ptr] = d;
texture_ram_ptr += 4;
return;
}
switch (a)
{
case 0x88000000: // trigger?
//message(0, "%08X (%08X): 88000000 = %08X", PPC_PC, PPC_LR, BSWAP32(d));
if( texture_ram_ptr > 0 ) {
int i=0;
while( i < texture_ram_ptr ) {
UINT32 length = (*(UINT32*)&texture_buffer_ram[i+0] / 2) + 2;
UINT32 header = *(UINT32*)&texture_buffer_ram[i+4];
upload_texture( header, &texture_buffer_ram[i+8], 1 );
i += length;
};
}
texture_ram_ptr = 0;
return;
case 0x90000000: // VROM texture address
vrom_texture_address = BSWAP32(d);
LOG("model3.log", "VROM1 ADDR = %08X\n", BSWAP32(d));
//message(0, "VROM texture address = %08X @ %08X (%08X)", BSWAP32(d), PPC_PC, PPC_LR);
return;
case 0x90000004:
vrom_texture_header = BSWAP32(d);
LOG("model3.log", "VROM1 HEAD = %08X\n", BSWAP32(d));
//message(0, "VROM texture header = %08X @ %08X (%08X)", BSWAP32(d), PPC_PC, PPC_LR);
return;
case 0x90000008:
upload_texture(vrom_texture_header, &vrom[(vrom_texture_address & 0xFFFFFF) * 4], 1);
LOG("model3.log", "VROM1 SIZE = %08X\n", BSWAP32(d));
//message(0, "VROM texture length = %08X @ %08X (%08X)", BSWAP32(d), PPC_PC, PPC_LR);
return;
case 0x9000000C: // ? Virtual On 2: These are almost certainly for VROM textures as well (I was too lazy to check :P)
vrom_texture_address = BSWAP32(d);
LOG("model3.log", "VROM2 ADDR = %08X\n", BSWAP32(d));
//message(0, "90000000C = %08X", BSWAP32(d));
return;
case 0x90000010: // ?
vrom_texture_header = BSWAP32(d);
LOG("model3.log", "VROM2 HEAD = %08X\n", BSWAP32(d));
//message(0, "900000010 = %08X", BSWAP32(d));
return;
case 0x90000014: // ?
upload_texture(vrom_texture_header, &vrom[(vrom_texture_address & 0xFFFFFF) * 4], 1);
LOG("model3.log", "VROM2 SIZE = %08X\n", BSWAP32(d));
//message(0, "900000014 = %08X", BSWAP32(d));
return;
case 0x9C000000: // ?
//message(0, "9C000000 = %08X", BSWAP32(d));
LOG("model3.log", "%08X = %08X\n", a, d);
_9C000000 = BSWAP32(d);
return;
case 0x9C000004: // ?
//message(0, "9C000004 = %08X", BSWAP32(d));
LOG("model3.log", "%08X = %08X\n", a, d);
_9C000004 = BSWAP32(d);
return;
case 0x9C000008: // ?
//message(0, "9C000008 = %08X", BSWAP32(d));
LOG("model3.log", "%08X = %08X\n", a, d);
_9C000008 = BSWAP32(d);
return;
}
error("Unknown R3D write: %08X: %08X = %08X\n", ppc_get_pc(), a, d);
}
void r3d_dma_culling_ram_8c(UINT32 *src, UINT32 dst, int length, BOOL swap_words)
{
int i;
dst &= 0xffffff;
if (swap_words)
{
for (i=0; i < length; i+=4)
{
UINT32 d = BSWAP32(*src++);
*(UINT32 *)&culling_ram_8c[dst] = d;
dst += 4;
}
}
else
{
for (i=0; i < length; i+=4)
{
UINT32 d = (*src++);
*(UINT32 *)&culling_ram_8c[dst] = d;
dst += 4;
}
}
}
void r3d_dma_culling_ram_8e(UINT32 *src, UINT32 dst, int length, BOOL swap_words)
{
int i;
dst &= 0xffffff;
if (swap_words)
{
for (i=0; i < length; i+=4)
{
UINT32 d = BSWAP32(*src++);
*(UINT32 *)&culling_ram_8e[dst] = d;
dst += 4;
}
}
else
{
for (i=0; i < length; i+=4)
{
UINT32 d = (*src++);
*(UINT32 *)&culling_ram_8e[dst] = d;
dst += 4;
}
}
}
void r3d_dma_polygon_ram(UINT32 *src, UINT32 dst, int length, BOOL swap_words)
{
int i;
dst &= 0xffffff;
if (swap_words)
{
for (i=0; i < length; i+=4)
{
UINT32 d = BSWAP32(*src++);
*(UINT32 *) &polygon_ram[dst] = d;
dst += 4;
}
}
else
{
for (i=0; i < length; i+=4)
{
UINT32 d = (*src++);
*(UINT32 *) &polygon_ram[dst] = d;
dst += 4;
}
}
}
void r3d_dma_texture_ram(UINT32 *src, UINT32 dst, int length, BOOL swap_words)
{
int i;
dst &= 0xffffff;
if (swap_words)
{
for (i=0; i < length; i+=4)
{
UINT32 d = BSWAP32(*src++);
*(UINT32 *)&texture_buffer_ram[texture_ram_ptr] = d;
texture_ram_ptr += 4;
}
}
else
{
for (i=0; i < length; i+=4)
{
UINT32 d = (*src++);
*(UINT32 *)&texture_buffer_ram[texture_ram_ptr] = d;
texture_ram_ptr += 4;
}
}
}
/******************************************************************/
/* Real3D TAP Port */
/******************************************************************/
/*
* State (corresponding to fsm[][] Y) and Instruction Names
*/
static char *state_name[] = { "Test-Logic/Reset", "Run-Test/Idle", "Select-DR-Scan",
"Capture-DR", "Shift-DR", "Exit1-DR", "Pause-DR",
"Exit2-DR", "Update-DR", "Select-IR-Scan",
"Capture-IR", "Shift-IR", "Exit1-IR", "Pause-IR",
"Exit2-IR", "Update-IR"
};
/*
* TAP Finite State Machine
*
* Y are states and X are outgoing paths. Constructed from information on page
* 167 of the 3D-RAM manual.
*/
#define NEXT(new_state) fsm[state][new_state]
static INT state; // current state
static INT fsm[][2] = {
{ 1, 0 }, // 0 Test-Logic/Reset
{ 1, 2 }, // 1 Run-Test/Idle
{ 3, 9 }, // 2 Select-DR-Scan
{ 4, 5 }, // 3 Capture-DR
{ 4, 5 }, // 4 Shift-DR
{ 6, 8 }, // 5 Exit1-DR
{ 6, 7 }, // 6 Pause-DR
{ 4, 8 }, // 7 Exit2-DR
{ 1, 2 }, // 8 Update-DR
{ 10, 0 }, // 9 Select-IR-Scan
{ 11, 12 }, // 10 Capture-IR
{ 11, 12 }, // 11 Shift-IR
{ 13, 15 }, // 12 Exit1-IR
{ 13, 14 }, // 13 Pause-IR
{ 11, 15 }, // 14 Exit2-IR
{ 1, 2 } // 15 Update-IR
};
/*
* TAP Registers
*/
static UINT64 current_instruction; // latched IR (not always equal to IR)
static UINT64 ir; // instruction register (46 bits)
static UINT8 id_data[32]; // ASIC ID code data buffer
static INT id_size; // size of ID data in bits
static INT ptr; // current bit ptr for data
static BOOL tdo; // bit shifted out to TDO
/*
* insert_bit():
*
* Inserts a bit into an arbitrarily long bit field. Bit 0 is assumed to be
* the MSB of the first byte in the buffer.
*/
static void insert_bit(UINT8 *buf, INT bit_num, INT bit)
{
INT bit_in_byte;
bit_in_byte = 7 - (bit_num & 7);
buf[bit_num / 8] &= ~(1 << bit_in_byte);
buf[bit_num / 8] |= (bit << bit_in_byte);
}
/*
* insert_id():
*
* Inserts a 32-bit ID code into the ID bit field.
*/
static void insert_id(UINT32 id, INT start_bit)
{
INT i;
for (i = 31; i >= 0; i--)
insert_bit(id_data, start_bit++, (id >> i) & 1);
}
/*
* shift():
*
* Shifts the data buffer right (towards LSB at byte 0) by 1 bit. The size of
* the number of bits must be specified. The bit shifted out of the LSB is
* returned.
*/
static BOOL shift(UINT8 *data, INT num_bits)
{
INT i;
BOOL shift_out, shift_in;
/*
* This loop takes care of all the fully-filled bytes
*/
shift_in = 0;
for (i = 0; i < num_bits / 8; i++)
{
shift_out = data[i] & 1;
data[i] >>= 1;
data[i] |= (shift_in << 7);
shift_in = shift_out; // carry over to next element's MSB
}
/*
* Take care of the last partial byte (if there is one)
*/
if ((num_bits & 7) != 0)
{
shift_out = (data[i] >> (8 - (num_bits & 7))) & 1;
data[i] >>= 1;
data[i] |= (shift_in << 7);
}
return shift_out;
}
/*
* BOOL tap_read(void);
*
* Reads TDO.
*
* Returns:
* TDO.
*/
BOOL tap_read(void)
{
return tdo;
}
/*
* void tap_write(BOOL tck, BOOL tms, BOOL tdi, BOOL trst);
*
* Writes to the TAP. State changes only occur on the rising edge of the clock
* (tck = 1.)
*
* Parameters:
* tck = Clock.
* tms = Test mode select.
* tdi = Serial data input. Must be 0 or 1 only!
* trst = Reset.
*/
void tap_write(BOOL tck, BOOL tms, BOOL tdi, BOOL trst)
{
if (!tck)
return;
state = NEXT(tms);
switch (state)
{
case 3: // Capture-DR
/*
* Read ASIC IDs.
*
* The ID Sequence is:
* - Jupiter
* - Mercury
* - Venus
* - Earth
* - Mars
* - Mars (again)
*
* Note that different Model 3 steps have different chip
* revisions, hence the different IDs returned below.
*
* On Step 1.5 and 1.0, instruction 0x0C631F8C7FFE is used to retrieve
* the ID codes but Step 2.0 is a little weirder. It seems to use this
* and either the state of the TAP after reset or other instructions
* to read the IDs as well. This can be emulated in one of 2 ways:
* Ignore the instruction and always load up the data or load the
* data on TAP reset and when the instruction is issued.
*/
if (m3_config.step == 0x10)
{
insert_id(0x116C7057, 1 + 0 * 32);
insert_id(0x216C3057, 1 + 1 * 32);
insert_id(0x116C4057, 1 + 2 * 32);
insert_id(0x216C5057, 1 + 3 * 32);
insert_id(0x116C6057, 1 + 4 * 32 + 1);
insert_id(0x116C6057, 1 + 5 * 32 + 1);
}
else if (m3_config.step == 0x15)
{
insert_id(0x316C7057, 1 + 0 * 32);
insert_id(0x316C3057, 1 + 1 * 32);
insert_id(0x216C4057, 1 + 2 * 32); // Lost World may to use 0x016C4057
insert_id(0x316C5057, 1 + 3 * 32);
insert_id(0x216C6057, 1 + 4 * 32 + 1);
insert_id(0x216C6057, 1 + 5 * 32 + 1);
}
else if (m3_config.step >= 0x20)
{
insert_id(0x416C7057, 1 + 0 * 32);
insert_id(0x416C3057, 1 + 1 * 32);
insert_id(0x316C4057, 1 + 2 * 32);
insert_id(0x416C5057, 1 + 3 * 32);
insert_id(0x316C6057, 1 + 4 * 32 + 1);
insert_id(0x316C6057, 1 + 5 * 32 + 1);
}
break;
case 4: // Shift-DR
tdo = shift(id_data, id_size);
break;
case 10: // Capture-IR
/*
* Load lower 2 bits with 01 as per IEEE 1149.1-1990
*/
ir = 1;
break;
case 11: // Shift-IR
/*
* Shift IR towards output and load in new data from TDI
*/
tdo = ir & 1; // shift LSB to output
ir >>= 1;
ir |= ((UINT64) tdi << 45);
break;
case 15: // Update-IR
/*
* Latch IR (technically, this should occur on the falling edge of
* TCK)
*/
ir &= 0x3fffffffffff;
current_instruction = ir;
#if 0
{
UINT8 *i = (UINT8 *) &ir;
LOG("tap.log", "current instruction set: %02X%02X%02X%02X%02X%02X\n", i[5], i[4], i[3], i[2], i[1], i[0]);
}
#endif
break;
default:
break;
}
#if 0
if (state == 4)
LOG("tap.log", "state: Shift-DR %d\n", tdi);
else if (state == 11)
LOG("tap.log", "state: Shift-IR %d\n", tdi);
else
LOG("tap.log", "state: %s\n", state_name[state]);
#endif
}
/*
* void tap_reset(void);
*
* Resets the TAP (simulating a power up or SCAN_RST signal.)
*/
void tap_reset(void)
{
id_size = 197; // 197 bits
state = 0; // test-logic/reset
}

49
core/r3d.h Normal file
View file

@ -0,0 +1,49 @@
/*
* Sega Model 3 Emulator
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* 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 (license.txt); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* r3d.h
*
* Real3D Model 3 graphics system header.
*/
#ifndef INCLUDED_R3D_H
#define INCLUDED_R3D_H
extern void r3d_init(UINT8 *, UINT8 *, UINT8 *, UINT8 *, UINT8 *);
extern void r3d_shutdown(void);
extern void r3d_reset(void);
extern void r3d_save_state(FILE *);
extern void r3d_load_state(FILE *);
extern UINT32 r3d_read_32(UINT32 a);
extern void r3d_write_32(UINT32 a, UINT32 d);
extern void r3d_dma_culling_ram_8c(UINT32 *src, UINT32 dst, int length, BOOL swap_words);
extern void r3d_dma_culling_ram_8e(UINT32 *src, UINT32 dst, int length, BOOL swap_words);
extern void r3d_dma_polygon_ram(UINT32 *src, UINT32 dst, int length, BOOL swap_words);
extern void r3d_dma_texture_ram(UINT32 *src, UINT32 dst, int length, BOOL swap_words);
extern void tap_reset(void);
extern BOOL tap_read(void);
extern void tap_write(BOOL tck, BOOL tms, BOOL tdi, BOOL trst);
#endif // INCLUDED_R3D_H

823
core/render.c Normal file
View file

@ -0,0 +1,823 @@
/*
* Sega Model 3 Emulator
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* 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 (license.txt); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* render.c
*
* Rendering engine. Responsible for both Real3D graphics emulation and
* for drawing the tile layers with correct priorities.
*
* NOTES:
* ------
*
* - The "hardware coordinate system" is the default Model 3 coordinate system
* before any matrices are applied. In it, +X is to the right, +Y is down,
* and +Z is further into the screen.
*/
#include "model3.h"
extern BOOL render_scene(void);
#define LOG_MODEL_ADDR 0 // logs model addresses to models.log
/******************************************************************/
/* Useful Macros */
/******************************************************************/
/*
* Single-Precision Floating Point
*/
#define GET_FLOAT(ptr) (*((float *) ptr))
/*
* Trigonometry
*/
#define PI 3.14159265358979323846264338327
#define CONVERT_TO_DEGREES(a) (((a) * 180.0) / PI)
/******************************************************************/
/* Private Data */
/******************************************************************/
/*
* Memory Regions
*
* These will be passed to us before rendering begins.
*/
static UINT8 *culling_ram_8e; // pointer to Real3D culling RAM
static UINT8 *culling_ram_8c; // pointer to Real3D culling RAM
static UINT8 *polygon_ram; // pointer to Real3D polygon RAM
static UINT8 *texture_ram; // pointer to Real3D texture RAM
static UINT8 *vrom; // pointer to VROM
/*
* Matrix Base
*/
static float *matrix_base; // current scene's matrix table
static float *lod_base; // current scene's LOD table
/*
* Matrix Conversion Tables
*
* These tables map Model 3 matrix indices to column-major form.
*/
static INT normal_matrix[4*4] = // normal matrices
{
3*4+0, 3*4+1, 3*4+2,
0*4+0, 1*4+0, 2*4+0,
0*4+1, 1*4+1, 2*4+1,
0*4+2, 1*4+2, 2*4+2
};
static INT coord_matrix[4*4] = // coordinate system matrix
{
3*4+2, 3*4+0, 3*4+1,
0*4+2, 1*4+2, 2*4+2,
0*4+0, 1*4+0, 2*4+0,
0*4+1, 1*4+1, 2*4+1
};
/******************************************************************/
/* Function Prototypes */
/******************************************************************/
static void draw_block(UINT32 *);
/******************************************************************/
/* TEMPORARY Model Tracking Code */
/* */
/* This code builds a list of VROM model addresses as they are */
/* referenced. */
/******************************************************************/
#if LOG_MODEL_ADDR
static struct model_addr
{
UINT32 addr; // model address in VROM
INT num_polys; // number of polygons in model
struct model_addr *next; // next in list
} *model_addr_list = NULL;
static INT count_polys(UINT32 *mdl)
{
UINT32 link_data, mask;
INT num_polys = 0, num_verts, i, stop;
do
{
stop = BSWAP32(mdl[1]) & 4; // get stop bit
link_data = BSWAP32(mdl[0]); // link data
/*
* Count how many vertices the polygon has by subtracting the number
* of vertices used from the previous polygon from 4 (quad) or 3 (tri)
*/
num_verts = (link_data & 0x40) ? 4 : 3;
mask = 8;
for (i = 0; i < 4 && num_verts; i++)
{
if ((link_data & mask))
--num_verts;
mask >>= 1;
}
/*
* Advance to next polygon
*/
mdl += 7 + num_verts * 4;
++num_polys; // increment count
} while (!stop);
return num_polys;
}
static void record_model(UINT32 addr)
{
struct model_addr *l;
/*
* Search for this entry -- if already in the list, exit
for (l = model_addr_list; l != NULL; l = l->next)
{
if (addr == l->addr)
return;
}
/*
* Add new entry
*/
l = malloc(sizeof(struct model_addr));
if (l == NULL)
error("out of memory in record_model()");
l->addr = addr;
l->num_polys = count_polys((UINT32 *) &vrom[addr * 4]);
l->next = model_addr_list;
model_addr_list = l;
}
#endif
/******************************************************************/
/* Real3D Address Translation */
/******************************************************************/
/*
* translate_scene_graph_address():
*
* Returns a pointer to scene graph (culling RAM) memory given a scene graph
* address (only lower 24 bits are relevant.)
*/
static UINT32 *translate_scene_graph_address(UINT32 addr)
{
addr &= 0x00FFFFFF; // only lower 24 bits matter
if ((addr & 0x00800000)) // 8E culling RAM
{
if (addr >= 0x00840000)
error("translate_scene_graph_address(): addr = %08X", addr);
return (UINT32 *) &culling_ram_8e[(addr & 0x0003FFFF) * 4];
}
else // 8C culling RAM
{
if (addr >= 0x00100000)
error("translate_scene_graph_address(): addr = %08X", addr);
return (UINT32 *) &culling_ram_8c[(addr & 0x000FFFFF) * 4];
}
}
/*
* draw_model():
*
* Translates the model address and draws the model (accounting for
* endianness.)
*/
static void draw_model(UINT32 addr)
{
addr &= 0x00FFFFFF; // only lower 24 bits matter
if (addr > 0x00100000) // VROM
{
#if LOG_MODEL_ADDR
record_model(addr); // TEMP: this tracks model addresses in VROM
#endif
osd_renderer_draw_model((UINT32 *) &vrom[(addr & 0x00FFFFFF) * 4], addr, 0);
}
else // polygon RAM (may actually be 4MB)
{
osd_renderer_draw_model((UINT32 *) &polygon_ram[(addr & 0x000FFFFF) * 4], addr, 1);
}
}
/******************************************************************/
/* Matrices */
/* */
/* Model 3 matrices are 4x3 in size (they lack the translational */
/* component.) They are layed out like this: */
/* */
/* 03 04 05 00 */
/* 06 07 08 01 */
/* 09 10 11 02 */
/* */
/* Matrix #0 is for coordinate system selection, it is layed out */
/* as: */
/* */
/* 06 07 08 01 */
/* 09 10 11 02 */
/* 03 04 05 00 */
/* */
/* By default, the Model 3 appears to have a form of left-handed */
/* coordinate system where positive Z means further away from the */
/* camera and the positive Y axis points downward along the */
/* screen. */
/******************************************************************/
/*
* get_matrix():
*
* Reads a Model 3 matrix and converts it to column-major 4x4 form using the
* supplied conversion table.
*/
static void get_matrix(MATRIX dest, INT convert[3*4], UINT num)
{
INT m = num * 12, i;
for (i = 0; i < 3*4; i++) // fetch Model 3 4x3 matrix
dest[convert[i]] = matrix_base[m + i];
dest[0*4+3] = 0.0; // fill in translation component to make 4x4
dest[1*4+3] = 0.0;
dest[2*4+3] = 0.0;
dest[3*4+3] = 1.0;
}
/******************************************************************/
/* Scene Graph Traversal */
/******************************************************************/
int list_depth = 0;
/*
* draw_list():
*
* Processes a list backwards. Each list element references a block.
*/
static void draw_list(UINT32 *list)
{
UINT32 *list_ptr;
UINT32 addr;
list_ptr = list;
if (list_depth > 2)
return;
list_depth++;
/*
* Go to end of list
*/
while (1)
{
addr = *list_ptr;
if ((addr & 0x02000000)) // last pointer in list
{
//--list_ptr;
break;
}
if (addr == 0 || addr == 0x800800) // safeguard in case memory hasn't been set up
{
--list_ptr;
break;
}
++list_ptr;
}
while (list_ptr >= list)
{
addr = *list_ptr;
if ((addr & 0x00FFFFFF) != 0x00FFFFFF)
draw_block(translate_scene_graph_address(addr));
--list_ptr; // next element
}
list_depth--;
}
/*
* draw_pointer_list():
*
* Draws a 4-element pointer list for model LOD selection.
*/
static void draw_pointer_list(UINT lod_num, UINT32* list)
{
float *lod_control = (float *)((UINT32)lod_base + lod_num * 8);
/*
* Perform the actual LOD calculation, select the LOD model
* to draw -- and perform additional LOD blending.
*/
#if 0
printf( "LOD control = %f, %f\n"
" %f, %f\n"
" %f, %f\n"
" %f, %f\n",
lod_control[0], lod_control[1],
lod_control[2], lod_control[3],
lod_control[4], lod_control[5],
lod_control[6], lod_control[7]
);
#endif
if(1)
draw_model( list[0] );
else if(0)
draw_model( list[1] );
else if(0)
draw_model( list[2] );
else
draw_model( list[3] );
}
/*
* draw_block():
*
* Traverses a 10- (or 8-) word block (culling node.) The blocks have this
* format:
*
* 0: ID code (upper 22 bits) and control bits
* 1: Scaling? Not present in Step 1.0
* 2: Flags? Not present in Step 1.0
* 3: Lower 12 bits are matrix select. Upper bits contain flags.
* 4: X translation (floating point)
* 5: Y translation
* 6: Z translation
* 7: Pointer to model data, list, or pointer list
* 8: Pointer to next block
* 9: Pair of 16-bit values, related to rendering order
*
* Lower 16 bits of word 2 control "texture offset": -P-X XXXX X--Y YYYY, same
* as in polygon headers. The purpose of this is unknown.
*/
static void draw_block(UINT32 *block)
{
MATRIX m;
UINT32 addr;
INT offset;
INT txoffs_x, txoffs_y, txoffs_page;
if (m3_config.step == 0x10) // Step 1.0 blocks are only 8 words
offset = 2;
else
offset = 0;
addr = block[7 - offset];
txoffs_x = ((block[2] >> 7) & 0x3F) * 32;
txoffs_y = (block[2] & 0x1F) * 32;
txoffs_page = !!(block[2] & 0x4000);
/*
* Apply matrix and translation
*/
get_matrix(m, normal_matrix, block[3 - offset] & 0xFFF);
osd_renderer_push_matrix();
if ((block[0] & 0x10)) // this bit appears to control translation
{
osd_renderer_translate_matrix(GET_FLOAT(&block[4 - offset]), GET_FLOAT(&block[5 - offset]), GET_FLOAT(&block[6 - offset]));
}
else
{
if ((block[3 - offset] & 0xFFF) != 0)
osd_renderer_multiply_matrix(m);
}
/*
* Bit 0x08 of word 0 indicates a pointer list
*/
if ((block[0] & 0x08))
draw_pointer_list((block[3 - offset] >> 12) & 127, translate_scene_graph_address(addr));
else
{
if (addr != 0x0FFFFFFF && addr != 0x01000000 && addr != 0x00800800 && addr != 0) // valid?
{
switch ((addr >> 24) & 0xFF) // decide what address points to
{
case 0x00: // block
draw_block(translate_scene_graph_address(addr));
break;
case 0x01: // model
case 0x03: // model (Scud Race, model in VROM)
draw_model(addr);
break;
case 0x04: // list
draw_list(translate_scene_graph_address(addr));
break;
default:
break;
}
}
}
osd_renderer_pop_matrix();
/*
* NOTE: This second pointer needs to be investigated further.
*/
addr = block[8 - offset];
if (addr != 0x01000000 && addr != 0x00800800 && addr != 0) // valid?
draw_block(translate_scene_graph_address(addr));
}
/*
* get_viewport_data():
*
* Sets up a VIEWPORT structure. Is passed a pointer to the main node.
*/
static void get_viewport_data(VIEWPORT *vp, UINT32 *node)
{
vp->x = (node[0x1A] & 0xFFFF) >> 4; // position is in 12.4 format
vp->y = (node[0x1A] >> 16) >> 4;
vp->width = (node[0x14] & 0xFFFF) >> 2; // size is in 14.2 format
vp->height = (node[0x14] >> 16) >> 2;
vp->left = asin(GET_FLOAT(&node[0x0C]));
vp->right = asin(GET_FLOAT(&node[0x10]));
vp->up = asin(GET_FLOAT(&node[0x0E]));
vp->down = asin(GET_FLOAT(&node[0x12]));
vp->left = CONVERT_TO_DEGREES(vp->left);
vp->right = CONVERT_TO_DEGREES(vp->right);
vp->up = CONVERT_TO_DEGREES(vp->up);
vp->down = CONVERT_TO_DEGREES(vp->down);
}
/*
* get_light_data():
*
* Sets up a LIGHT structure based on ambient sun light. The sun vector
* indicates the direction of the parallel sun light. It is specified in the
* hardware coordinate system and must be applied before any matrices.
*/
static void get_light_data(LIGHT* l, UINT32* node)
{
memset( l, 0, sizeof(LIGHT) );
l->u = GET_FLOAT(&node[5]); // it seems X needs to be inverted
l->v = GET_FLOAT(&node[6]);
l->w = GET_FLOAT(&node[4]);
l->diffuse_intensity = GET_FLOAT(&node[7]);
l->ambient_intensity = (UINT8)((node[0x24] >> 8) & 0xFF) / 256.0f;
LOG("model3.log", "sun light = (%f,%f,%f),%f,(%02X=%f)\n", l->u, l->v, l->w, l->diffuse_intensity, ((node[0x24] >> 8) & 0xFF), l->ambient_intensity);
l->color = 0xFFFFFFFF;
}
/*
* draw_viewport():
*
* Traverses the main (scene descriptor) nodes and draws the ones with the
* given viewport priority.
*/
static void draw_viewport(UINT pri, UINT32 addr)
{
MATRIX m;
VIEWPORT vp;
LIGHT sun;
UINT32 *node;
UINT32 next_addr, ptr;
node = translate_scene_graph_address(addr);
/*
* Recurse until the last node has been reached
*/
next_addr = node[1];
if (next_addr == 0) // culling RAM probably hasn't been set up yet...
return;
if (next_addr != 0x01000000)
draw_viewport(pri, next_addr);
/*
* Draw this node if the priority matches
*/
if (pri == ((node[0] >> 3) & 3))
{
/*
* Set up viewport and matrix table base
*/
get_viewport_data(&vp, node);
osd_renderer_set_viewport(&vp);
matrix_base = (float *) translate_scene_graph_address(node[0x16]);
lod_base = (float *) translate_scene_graph_address(node[0x17]);
/*
* Lighting -- seems to work nice if applied before coordinate system
* selection but I haven't done a thorough check.
*/
get_light_data(&sun, node);
sun.type = LIGHT_PARALLEL;
osd_renderer_set_light( 0, &sun );
/*
* Set coordinate system (matrix 0)
*/
get_matrix(m, coord_matrix, 0);
osd_renderer_set_coordinate_system(m);
/*
* Process a block or list. So far, no other possibilities have been
* seen here...
*/
ptr = node[2];
switch ((ptr >> 24) & 0xFF)
{
case 0x00: // block
draw_block(translate_scene_graph_address(node[2]));
break;
//case 0x04: // list
// draw_list(translate_scene_graph_address(node[2]));
// break;
default: // unknown
break;
}
}
}
/******************************************************************/
/* Frame Update */
/******************************************************************/
/*
* do_3d():
*
* Draw the complete Real3D frame.
*/
static void do_3d(void)
{
INT i;
for (i = 0; i < 4; i++)
{
osd_renderer_clear(0, 1); // clear Z-buffer
osd_renderer_begin_3d_scene();
draw_viewport(i, 0x00800000);
osd_renderer_end_3d_scene();
LOG("model3.log", "GOT HERE\n");
}
}
/*
* void set_color_offset(UINT32 reg);
*
* Sets color offset to the value specified by reg, and updates the
* renderer status.
*/
static void set_color_offset(UINT32 reg)
{
FLOAT32 r, g, b;
/*
* Color offset is specified as a triplet of signed 8-bit values, one
* for each color component. 0 is the default value, it doesn't modify
* the output color. It's equal to disabling the color offset (though
* some bit in the tilegen ports could be used for this).
* 0x80 (-128) is the minimum value, and corresponds to complete black.
* 0x7F (+127) is the maximum value, and corresponds to complete white.
*/
r = (FLOAT32)((INT32)((INT8)(((INT32)reg >> 8) & 0xFF))) / 128.0f;
g = (FLOAT32)((INT32)((INT8)(((INT32)reg >> 16) & 0xFF))) / 128.0f;
b = (FLOAT32)((INT32)((INT8)(((INT32)reg >> 24) & 0xFF))) / 128.0f;
// osd_renderer_set_color_offset(r != 0.0f && g != 0.0f && b != 0.0f, r, g, b);
}
/*
* void render_frame(void);
*
* Draws the entire frame (all 3D and 2D graphics) and blits it.
*/
void render_frame(void)
{
int i, j;
UINT32 color_offset;
LONGLONG counter_start, counter_end, counter_frequency;
LOG("model3.log", "RENDER START\n");
QueryPerformanceFrequency((LARGE_INTEGER*)&counter_frequency);
tilegen_update();
{
UINT32 *priority = tilegen_get_priority_buffer();
for (i=0; i < 4; i++)
{
int pitch;
UINT8 *buffer;
osd_renderer_get_priority_buffer(i, &buffer, &pitch);
for (j=0; j < 512; j++)
{
if (tilegen_is_priority_enabled())
{
buffer[j*pitch] = (priority[j] >> ((3-i) * 8)) & 0xff;
}
else
{
if (i < 2) buffer[j*pitch] = 0xff;
else buffer[j*pitch] = 0x00;
}
}
osd_renderer_free_priority_buffer(i);
}
}
osd_renderer_clear(1, 1); // clear both the frame and Z-buffer
// set_color_offset(tilegen_read_32(0x44));
/*if (tilegen_is_layer_enabled(3))
{
UINT32 scroll = tilegen_get_layer_scroll_pos(3);
color_offset = tilegen_get_layer_color_offset(3);
osd_renderer_draw_layer(3, color_offset, scroll & 0xffff, scroll >> 16);
}
if (tilegen_is_layer_enabled(2))
{
UINT32 scroll = tilegen_get_layer_scroll_pos(2);
color_offset = tilegen_get_layer_color_offset(2);
osd_renderer_draw_layer(2, color_offset, scroll & 0xffff, scroll >> 16);
}*/
for (i=3; i >= 0; i--)
{
if (tilegen_is_layer_enabled(i))
{
UINT32 scroll = tilegen_get_layer_scroll_pos(i);
color_offset = tilegen_get_layer_color_offset(i);
osd_renderer_draw_layer(i, color_offset, scroll & 0xffff, scroll >> 16, FALSE);
}
}
QueryPerformanceCounter((LARGE_INTEGER*)&counter_start);
do_3d();
QueryPerformanceCounter((LARGE_INTEGER*)&counter_end);
for (i=3; i >= 0; i--)
{
if (tilegen_is_layer_enabled(i))
{
UINT32 scroll = tilegen_get_layer_scroll_pos(i);
color_offset = tilegen_get_layer_color_offset(i);
osd_renderer_draw_layer(i, color_offset, scroll & 0xffff, scroll >> 16, TRUE);
}
}
/*{
double time = (double)(counter_end - counter_start) / (double)counter_frequency;
printf("Rendering time: %f ms\n", time*1000.0);
}*/
// set_color_offset(tilegen_read_32(0x40));
// osd_renderer_draw_layer(1);
/*if (tilegen_is_layer_enabled(1))
{
UINT32 scroll = tilegen_get_layer_scroll_pos(1);
color_offset = tilegen_get_layer_color_offset(1);
osd_renderer_draw_layer(1, color_offset, scroll & 0xffff, scroll >> 16);
}
if (tilegen_is_layer_enabled(0))
{
UINT32 scroll = tilegen_get_layer_scroll_pos(0);
color_offset = tilegen_get_layer_color_offset(0);
osd_renderer_draw_layer(0, color_offset, scroll & 0xffff, scroll >> 16);
}*/
LOG("model3.log", "RENDER END\n");
}
/******************************************************************/
/* Initialization and Shutdown */
/******************************************************************/
/*
* void render_init(UINT8 *culling_ram_8e_ptr, UINT8 *culling_ram_8c_ptr,
* UINT8 *polygon_ram_ptr, UINT8 *texture_ram_ptr,
* UINT8 *vrom_ptr);
*
* Initializes the renderer by receiving the Real3D memory regions. Passes
* the memory to the OSD renderer.
*
* Parameters:
* culling_ram_8e_ptr = Pointer to Real3D culling RAM at 0x8E000000.
* culling_ram_8c_ptr = Pointer to Real3D culling RAM at 0x8C000000.
* polygon_ram_ptr = Pointer to Real3D polygon RAM.
* texture_ram_ptr = Pointer to Real3D texture RAM.
* vrom_ptr = Pointer to VROM.
*/
void render_init(UINT8 *culling_ram_8e_ptr, UINT8 *culling_ram_8c_ptr,
UINT8 *polygon_ram_ptr, UINT8 *texture_ram_ptr,
UINT8 *vrom_ptr)
{
culling_ram_8e = culling_ram_8e_ptr;
culling_ram_8c = culling_ram_8c_ptr;
polygon_ram = polygon_ram_ptr;
texture_ram = texture_ram_ptr;
vrom = vrom_ptr;
}
/*
* void render_shutdown(void);
*
* Shuts down the rendering engine.
*/
void render_shutdown(void)
{
#if LOG_MODEL_ADDR
// TEMP code to print out model list
FILE *fp;
struct model_addr *l, *next;
fp = fopen("models.log", "w");
if (fp == NULL)
{
printf("failed to write models.log\n");
return;
}
l = model_addr_list;
while (l != NULL)
{
fprintf(fp, "addr = %08X\tnum_polys = %d\n", l->addr, l->num_polys);
next = l->next;
free(l);
l = next;
}
fclose(fp);
#endif
}

86
core/render.h Normal file
View file

@ -0,0 +1,86 @@
/*
* Sega Model 3 Emulator
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* 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 (license.txt); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* render.h
*
* Rendering engine header. OSD renderers will want to include this because
* some important data structures are defined here.
*/
#ifndef INCLUDED_RENDER_H
#define INCLUDED_RENDER_H
/******************************************************************/
/* Data Structures */
/******************************************************************/
/*
* MATRIX
*
* A 4x4 matrix stored in column-major (OpenGL) format.
*/
typedef float MATRIX [4*4];
/*
* VIEWPORT
*
* Viewport and projection data. The field-of-view angles are in degrees. The
* coordinates and size of the viewport are truncated from Model 3's fixed-
* point formats to integers.
*
* The viewport coordinate system maps directly to the Model 3's physical
* resolution and its origin is at the bottom-left corner of the screen.
*/
typedef struct
{
UINT x, y, width, height; // viewport position and size.
double up, down, left, right; // FOV angles from center
} VIEWPORT;
/*
* LIGHT
*/
enum {
LIGHT_PARALLEL,
LIGHT_POSITIONAL,
LIGHT_SPOT
};
typedef struct
{
UINT type;
float u,v,w; // Direction vector
float x,y,z; // Position for point light
float diffuse_intensity;
float ambient_intensity;
UINT32 color;
} LIGHT;
/******************************************************************/
/* Functions */
/******************************************************************/
extern void render_frame(void);
extern void render_init(UINT8 *, UINT8 *, UINT8 *, UINT8 *, UINT8 *);
extern void render_shutdown(void);
#endif // INCLUDED_RENDER_H

604
core/romparse.c Normal file
View file

@ -0,0 +1,604 @@
#include "model3.h"
#include "expat.h"
enum
{
ELEMENT_NONE = 1,
ELEMENT_GAMELIST,
ELEMENT_GAME,
ELEMENT_DESCRIPTION,
ELEMENT_YEAR,
ELEMENT_MANUFACTURER,
ELEMENT_STEP,
ELEMENT_CROMSIZE,
ELEMENT_ROM,
ELEMENT_PATCH,
ELEMENT_BRIDGE,
ELEMENT_INPUT,
};
enum
{
ATTR_ROM_TYPE = 1,
ATTR_ROM_NAME,
ATTR_ROM_SIZE,
ATTR_ROM_CRC,
ATTR_ROM_SHA1,
ATTR_GAME_NAME,
ATTR_GAME_PARENT,
ATTR_PATCH_SIZE,
ATTR_PATCH_ADDRESS,
ATTR_PATCH_DATA,
ATTR_INPUT_TYPE,
ATTR_INPUT_CENTER,
ATTR_INPUT_MAPPING,
};
static STRING_ID element_id[] =
{
{ "gamelist", ELEMENT_GAMELIST },
{ "game", ELEMENT_GAME },
{ "description", ELEMENT_DESCRIPTION },
{ "year", ELEMENT_YEAR },
{ "manufacturer", ELEMENT_MANUFACTURER },
{ "step", ELEMENT_STEP },
{ "cromsize", ELEMENT_CROMSIZE },
{ "rom", ELEMENT_ROM },
{ "patch", ELEMENT_PATCH },
{ "bridge", ELEMENT_BRIDGE },
{ "input", ELEMENT_INPUT },
{ "", 0 },
};
static STRING_ID rom_attr_id[] =
{
{ "type", ATTR_ROM_TYPE },
{ "name", ATTR_ROM_NAME },
{ "size", ATTR_ROM_SIZE },
{ "crc", ATTR_ROM_CRC },
{ "sha1", ATTR_ROM_SHA1 },
{ "", 0 },
};
static STRING_ID game_attr_id[] =
{
{ "name", ATTR_GAME_NAME },
{ "parent", ATTR_GAME_PARENT },
{ "", 0 },
};
static STRING_ID patch_attr_id[] =
{
{ "size", ATTR_PATCH_SIZE },
{ "address", ATTR_PATCH_ADDRESS },
{ "data", ATTR_PATCH_DATA },
{ "", 0 },
};
static STRING_ID input_attr_id[] =
{
{ "type", ATTR_INPUT_TYPE },
{ "center", ATTR_INPUT_CENTER },
{ "mapping", ATTR_INPUT_MAPPING },
{ "", 0 },
};
static STRING_ID step_id[] =
{
{ "1.0", 0x10 },
{ "1.5", 0x15 },
{ "2.0", 0x20 },
{ "2.1", 0x21 },
{ "", 0 },
};
static STRING_ID rom_id[] =
{
{ "prog0", ROMTYPE_PROG0 },
{ "prog1", ROMTYPE_PROG1 },
{ "prog2", ROMTYPE_PROG2 },
{ "prog3", ROMTYPE_PROG3 },
{ "crom00", ROMTYPE_CROM00 },
{ "crom01", ROMTYPE_CROM01 },
{ "crom02", ROMTYPE_CROM02 },
{ "crom03", ROMTYPE_CROM03 },
{ "crom10", ROMTYPE_CROM10 },
{ "crom11", ROMTYPE_CROM11 },
{ "crom12", ROMTYPE_CROM12 },
{ "crom13", ROMTYPE_CROM13 },
{ "crom20", ROMTYPE_CROM20 },
{ "crom21", ROMTYPE_CROM21 },
{ "crom22", ROMTYPE_CROM22 },
{ "crom23", ROMTYPE_CROM23 },
{ "crom30", ROMTYPE_CROM30 },
{ "crom31", ROMTYPE_CROM31 },
{ "crom32", ROMTYPE_CROM32 },
{ "crom33", ROMTYPE_CROM33 },
{ "vrom00", ROMTYPE_VROM00 },
{ "vrom01", ROMTYPE_VROM01 },
{ "vrom02", ROMTYPE_VROM02 },
{ "vrom03", ROMTYPE_VROM03 },
{ "vrom04", ROMTYPE_VROM04 },
{ "vrom05", ROMTYPE_VROM05 },
{ "vrom06", ROMTYPE_VROM06 },
{ "vrom07", ROMTYPE_VROM07 },
{ "vrom10", ROMTYPE_VROM10 },
{ "vrom11", ROMTYPE_VROM11 },
{ "vrom12", ROMTYPE_VROM12 },
{ "vrom13", ROMTYPE_VROM13 },
{ "vrom14", ROMTYPE_VROM14 },
{ "vrom15", ROMTYPE_VROM15 },
{ "vrom16", ROMTYPE_VROM16 },
{ "vrom17", ROMTYPE_VROM17 },
{ "sprog", ROMTYPE_SPROG },
{ "srom0", ROMTYPE_SROM0 },
{ "srom1", ROMTYPE_SROM1 },
{ "srom2", ROMTYPE_SROM2 },
{ "srom3", ROMTYPE_SROM3 },
{ "dsbprog", ROMTYPE_DSBPROG },
{ "dsbrom0", ROMTYPE_DSBROM0 },
{ "dsbrom1", ROMTYPE_DSBROM1 },
{ "dsbrom2", ROMTYPE_DSBROM2 },
{ "dsbrom3", ROMTYPE_DSBROM3 },
{ "", 0 },
};
#define INPUT_TYPE_BUTTON 0x10000
#define INPUT_TYPE_ANALOG 0x20000
static STRING_ID input_id[] =
{
{ "button01", INPUT_TYPE_BUTTON | 0 },
{ "button02", INPUT_TYPE_BUTTON | 1 },
{ "button03", INPUT_TYPE_BUTTON | 2 },
{ "button04", INPUT_TYPE_BUTTON | 3 },
{ "button05", INPUT_TYPE_BUTTON | 4 },
{ "button06", INPUT_TYPE_BUTTON | 5 },
{ "button07", INPUT_TYPE_BUTTON | 6 },
{ "button08", INPUT_TYPE_BUTTON | 7 },
{ "button11", INPUT_TYPE_BUTTON | 8 },
{ "button12", INPUT_TYPE_BUTTON | 9 },
{ "button13", INPUT_TYPE_BUTTON | 10 },
{ "button14", INPUT_TYPE_BUTTON | 11 },
{ "button15", INPUT_TYPE_BUTTON | 12 },
{ "button16", INPUT_TYPE_BUTTON | 13 },
{ "button17", INPUT_TYPE_BUTTON | 14 },
{ "button18", INPUT_TYPE_BUTTON | 15 },
{ "analog1", INPUT_TYPE_ANALOG | 0 },
{ "analog2", INPUT_TYPE_ANALOG | 1 },
{ "analog3", INPUT_TYPE_ANALOG | 2 },
{ "analog4", INPUT_TYPE_ANALOG | 3 },
{ "analog5", INPUT_TYPE_ANALOG | 4 },
{ "analog6", INPUT_TYPE_ANALOG | 5 },
{ "analog7", INPUT_TYPE_ANALOG | 6 },
{ "analog8", INPUT_TYPE_ANALOG | 7 },
{ "", 0 },
};
static STRING_ID input_mapping_id[] =
{
{ "p1_button_1", P1_BUTTON_1 },
{ "p1_button_2", P1_BUTTON_2 },
{ "p1_button_3", P1_BUTTON_3 },
{ "p1_button_4", P1_BUTTON_4 },
{ "p1_button_5", P1_BUTTON_5 },
{ "p1_button_6", P1_BUTTON_6 },
{ "p1_button_7", P1_BUTTON_7 },
{ "p1_button_8", P1_BUTTON_8 },
{ "p2_button_1", P2_BUTTON_1 },
{ "p2_button_2", P2_BUTTON_2 },
{ "p2_button_3", P2_BUTTON_3 },
{ "p2_button_4", P2_BUTTON_4 },
{ "p2_button_5", P2_BUTTON_5 },
{ "p2_button_6", P2_BUTTON_6 },
{ "p2_button_7", P2_BUTTON_7 },
{ "p2_button_8", P2_BUTTON_8 },
{ "analog_axis_1", ANALOG_AXIS_1 },
{ "analog_axis_2", ANALOG_AXIS_2 },
{ "analog_axis_3", ANALOG_AXIS_3 },
{ "analog_axis_4", ANALOG_AXIS_4 },
{ "analog_axis_5", ANALOG_AXIS_5 },
{ "analog_axis_6", ANALOG_AXIS_6 },
{ "analog_axis_7", ANALOG_AXIS_7 },
{ "analog_axis_8", ANALOG_AXIS_8 },
{ "p1_joystick_up", P1_JOYSTICK_UP },
{ "p1_joystick_down", P1_JOYSTICK_DOWN },
{ "p1_joystick_left", P1_JOYSTICK_LEFT },
{ "p1_joystick_right", P1_JOYSTICK_RIGHT },
{ "p2_joystick_up", P2_JOYSTICK_UP },
{ "p2_joystick_down", P2_JOYSTICK_DOWN },
{ "p2_joystick_left", P2_JOYSTICK_LEFT },
{ "p2_joystick_right", P2_JOYSTICK_RIGHT },
{ "", 0 },
};
static UINT8 *romlist;
static ROMSET *romset;
static int current_attr;
static int current_element;
static int current_rom;
static int current_romset;
static int current_patch;
static int current_input;
static void XMLCALL element_start(void *data, const char *el, const char **attr)
{
int element = get_string_id(el, element_id);
if (element < 0)
{
message(0, "Unknown element %s while parsing XML file\n", el);
}
else
{
current_element = element;
switch (element)
{
case ELEMENT_ROM:
{
int i=0;
// handle ROM types
while (attr[i] != NULL)
{
int id = get_string_id(attr[i], rom_attr_id);
if (id >= 0)
{
current_attr = id;
}
else
{
// not a type
switch (current_attr)
{
case ATTR_ROM_TYPE:
{
int romtype = get_string_id(attr[i], rom_id);
romset[current_romset].rom[current_rom].type = romtype;
break;
}
case ATTR_ROM_NAME:
{
strcpy(romset[current_romset].rom[current_rom].name, attr[i]);
break;
}
case ATTR_ROM_SIZE:
{
int romsize;
sscanf(attr[i], "%d", &romsize);
romset[current_romset].rom[current_rom].size = romsize;
break;
}
case ATTR_ROM_CRC:
{
UINT32 romcrc;
sscanf(attr[i], "%X", &romcrc);
romset[current_romset].rom[current_rom].crc32 = romcrc;
break;
}
case ATTR_ROM_SHA1:
{
// not handled
break;
}
}
}
i++;
};
break;
}
case ELEMENT_GAME:
{
int i=0;
while (attr[i] != NULL)
{
int id = get_string_id(attr[i], game_attr_id);
if (id >= 0)
{
current_attr = id;
}
else
{
switch (current_attr)
{
case ATTR_GAME_NAME:
{
strcpy(romset[current_romset].game, attr[i]);
break;
}
case ATTR_GAME_PARENT:
{
strcpy(romset[current_romset].parent, attr[i]);
break;
}
}
}
i++;
};
break;
}
case ELEMENT_PATCH:
{
int i=0;
while (attr[i] != NULL)
{
int id = get_string_id(attr[i], patch_attr_id);
if (id >= 0)
{
current_attr = id;
}
else
{
switch (current_attr)
{
case ATTR_PATCH_SIZE:
{
int patch_size;
sscanf(attr[i], "%d", &patch_size);
romset[current_romset].patch[current_patch].size = patch_size;
break;
}
case ATTR_PATCH_ADDRESS:
{
UINT32 address;
sscanf(attr[i], "%X", &address);
romset[current_romset].patch[current_patch].address = address;
break;
}
case ATTR_PATCH_DATA:
{
UINT32 data;
sscanf(attr[i], "%X", &data);
romset[current_romset].patch[current_patch].data = data;
break;
}
}
}
i++;
};
break;
}
case ELEMENT_INPUT:
{
int i=0;
while (attr[i] != NULL)
{
int id = get_string_id(attr[i], input_attr_id);
if (id >= 0)
{
current_attr = id;
}
else
{
switch (current_attr)
{
case ATTR_INPUT_TYPE:
{
current_input = get_string_id(attr[i], input_id);
if (current_input & INPUT_TYPE_BUTTON)
{
int button = current_input & 0xffff;
int set = (button / 8) & 1;
int bit = 1 << (button % 8);
romset[current_romset].controls.button[button].enabled = 1;
romset[current_romset].controls.button[button].control_set = set;
romset[current_romset].controls.button[button].control_bit = bit;
}
else if (current_input & INPUT_TYPE_ANALOG)
{
int axis = current_input & 0xffff;
romset[current_romset].controls.analog_axis[axis].enabled = 1;
}
break;
}
case ATTR_INPUT_CENTER:
{
if (current_input & INPUT_TYPE_ANALOG)
{
int axis = current_input & 0xffff;
int center;
sscanf(attr[i], "%d", &center);
romset[current_romset].controls.analog_axis[axis].center = center;
}
break;
}
case ATTR_INPUT_MAPPING:
{
int mapping = get_string_id(attr[i], input_mapping_id);
if (current_input & INPUT_TYPE_BUTTON)
{
int button = current_input & 0xffff;
romset[current_romset].controls.button[button].mapping = mapping;
}
else if (current_input & INPUT_TYPE_ANALOG)
{
int axis = current_input & 0xffff;
romset[current_romset].controls.analog_axis[axis].mapping = mapping;
}
break;
}
}
}
i++;
};
break;
}
}
}
}
static void XMLCALL element_end(void *data, const char *el)
{
int element = get_string_id(el, element_id);
if (element < 0)
{
message(0, "Unknown element %s while parsing XML\n", el);
}
else
{
switch (element)
{
case ELEMENT_ROM:
{
current_rom++;
current_element = ELEMENT_GAMELIST;
break;
}
case ELEMENT_GAME:
{
romset[current_romset].num_patches = current_patch;
current_romset++;
current_rom = 0;
current_patch = 0;
current_element = ELEMENT_GAMELIST;
break;
}
case ELEMENT_DESCRIPTION:
case ELEMENT_YEAR:
case ELEMENT_MANUFACTURER:
case ELEMENT_STEP:
case ELEMENT_BRIDGE:
case ELEMENT_CROMSIZE:
{
current_element = ELEMENT_GAMELIST;
break;
}
case ELEMENT_PATCH:
{
current_patch++;
current_element = ELEMENT_GAMELIST;
break;
}
}
}
}
static void XMLCALL character_data(void *data, const char *s, int len)
{
char temp[2000];
memcpy(temp, s, len);
temp[len] = 0;
switch (current_element)
{
case ELEMENT_DESCRIPTION:
{
strcpy(romset[current_romset].title, temp);
break;
}
case ELEMENT_YEAR:
{
int year;
sscanf(temp, "%d", &year);
romset[current_romset].year = year;
break;
}
case ELEMENT_MANUFACTURER:
{
strcpy(romset[current_romset].manufacturer, temp);
break;
}
case ELEMENT_STEP:
{
int step = get_string_id(temp, step_id);
if (step >= 0)
{
romset[current_romset].step = step;
}
else
{
message(0, "Invalid step %s while parsing XML file\n", temp);
}
break;
}
case ELEMENT_BRIDGE:
{
if (_stricmp(temp, "mpc106") == 0)
{
romset[current_romset].bridge = 2;
}
else
{
message(0, "Unknown bridge %s while parsing XML file\n", temp);
}
break;
}
case ELEMENT_CROMSIZE:
{
if (_stricmp(temp, "64M") == 0)
{
romset[current_romset].cromsize = 1;
}
else
{
message(0, "Unknown cromsize %s while parsing XML file\n", temp);
}
break;
}
}
}
int parse_romlist(char *romlist_name, ROMSET *_romset)
{
XML_Parser parser;
int length;
FILE *file;
file = open_file(FILE_READ|FILE_BINARY, "%s", romlist_name);
if (file == NULL)
{
message(0, "Couldn't open %s", romlist_name);
return 0;
}
length = (int)get_open_file_size(file);
romlist = (UINT8*)malloc(length);
if (!read_from_file(file, romlist, length))
{
message(0, "I/O error while reading %s", romlist_name);
return 0;
}
close_file(file);
romset = _romset;
// parse the XML file
parser = XML_ParserCreate(NULL);
XML_SetElementHandler(parser, element_start, element_end);
XML_SetCharacterDataHandler(parser, character_data);
if (XML_Parse(parser, romlist, length, 1) != XML_STATUS_OK)
{
message(0, "Error while parsing the XML file %s", romlist_name);
return 0;
}
XML_ParserFree(parser);
return current_romset;
}

179
core/rtc.c Normal file
View file

@ -0,0 +1,179 @@
/*
* Sega Model 3 Emulator
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* 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 (license.txt); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* rtc.c
*
* Real-Time Clock (72421) emulation.
*/
#include "model3.h"
#include <time.h>
static UINT8 rtc_step = 0;
static UINT8 rtc_reg[0x10]; /* 4-bit wide */
/******************************************************************/
/* Interface */
/******************************************************************/
void rtc_init(void)
{
}
void rtc_shutdown(void)
{
}
void rtc_reset(void)
{
rtc_step = 0;
memset(rtc_reg, 0, 0x10);
}
void rtc_step_frame(void)
{
}
/*
* void rtc_save_state(FILE *fp);
*
* Saves the state of the real-time clock to a file.
*
* Parameters:
* fp = File to save to.
*/
void rtc_save_state(FILE *fp)
{
// do nothing yet because this file isn't complete or used, it appears
}
/*
* void rtc_load_state(FILE *fp);
*
* Loads the state of the real-time clock from a file.
*
* Parameters:
* fp = File to load from.
*/
void rtc_load_state(FILE *fp)
{
// do nothing yet because this file isn't complete or used, it appears
}
/******************************************************************/
/* Access */
/******************************************************************/
static UINT8 get_register(int reg)
{
time_t current_time;
struct tm* tms;
time( &current_time );
tms = localtime( &current_time );
switch(reg)
{
case 0: // 1-second digit
return (tms->tm_sec % 10) & 0xF;
break;
case 1: // 10-seconds digit
return (tms->tm_sec / 10) & 0x7;
break;
case 2: // 1-minute digit
return (tms->tm_min % 10) & 0xF;
break;
case 3: // 10-minute digit
return (tms->tm_min / 10) & 0x7;
break;
case 4: // 1-hour digit
return (tms->tm_hour % 10) & 0xF;
break;
case 5: // 10-hours digit
return (tms->tm_hour / 10) & 0x7;
break;
case 6: // 1-day digit (days in month)
return (tms->tm_mday % 10) & 0xF;
break;
case 7: // 10-days digit
return (tms->tm_mday / 10) & 0x3;
break;
case 8: // 1-month digit
return ((tms->tm_mon + 1) % 10) & 0xF;
break;
case 9: // 10-months digit
return ((tms->tm_mon + 1) / 10) & 0x1;
break;
case 10: // 1-year digit
return (tms->tm_year % 10) & 0xF;
break;
case 11: // 10-years digit
return ((tms->tm_year % 100) / 10) & 0xF;
break;
case 12: // day of the week
return tms->tm_wday & 0x7;
break;
case 13:
return 0;
break;
case 14:
return 0;
break;
case 15:
return 0;
break;
default:
error("ERROR: invalid RTC access reg%X\n", reg);
return 0;
}
}
UINT8 rtc_read_8(UINT32 a)
{
int address = (a >> 2) & 0xF;
//message(0, "RTC: read %08X, %08X", address,ppc_get_reg(PPC_REG_PC));
return get_register( address );
}
UINT32 rtc_read_32(UINT32 a)
{
int address = (a >> 2) & 0xF;
//message(0, "RTC: read %08X, %08X", address,ppc_get_reg(PPC_REG_PC));
return get_register( address) << 24 | 0x30000; // Bits 0x30000 set to get battery voltage check to pass
}
void rtc_write(UINT32 a, UINT8 d)
{
a = (a >> 2) & 0xF;
//message(0, "RTC: write %08X = %X", a, d);
a &= 0xF;
rtc_reg[a] = d;
}

41
core/rtc.h Normal file
View file

@ -0,0 +1,41 @@
/*
* Sega Model 3 Emulator
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* 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 (license.txt); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* rtc.h
*
* Real-Time Clock (72421) header.
*/
#ifndef INCLUDED_RTC_H
#define INCLUDED_RTC_H
extern void rtc_init(void);
extern void rtc_shutdown(void);
extern void rtc_reset(void);
extern void rtc_step_frame(void);
extern void rtc_save_state(FILE *);
extern void rtc_load_state(FILE *);
extern UINT8 rtc_read_8(UINT32 a);
extern UINT32 rtc_read_32(UINT32 a);
extern void rtc_write(UINT32 a, UINT8 d);
#endif // INCLUDED_RTC_H

367
core/scsi.c Normal file
View file

@ -0,0 +1,367 @@
/*
* Sega Model 3 Emulator
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* 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 (license.txt); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* scsi.c
*
* NCR 53C810 SCSI controller emulation.
*
* Multi-byte data written is assumed to be little endian and is therefore
* reversed because the PowerPC operates in big endian mode in the Model 3.
*
* NOTE: scsi_run() is often called with an argument of 100. This is
* actually incorrect. It should run until an interrupt condition. A count of
* 100 is used as a runaway counter to prevent lock-ups.
*/
#include "model3.h"
/*
* Read/Write Handlers
*
* These are used as an interface to the rest of the system.
*/
static UINT8 (*read_8)(UINT32);
static UINT16 (*read_16)(UINT32);
static UINT32 (*read_32)(UINT32);
static void (*write_8)(UINT32, UINT8);
static void (*write_16)(UINT32, UINT16);
static void (*write_32)(UINT32, UINT32);
/*
* 53C810 Context
*
* Offsets within the register array correspond to register addresses but the
* endianness in which they are stored is little endian. Macros are provided
* to access them.
*/
#define REG8(r) scsi_regs[r]
#define REG16(r) *((UINT16 *) &scsi_regs[r])
#define REG32(r) *((UINT32 *) &scsi_regs[r])
static UINT8 scsi_regs[0x60];
static BOOL scripts_exec; // true if SCRIPTS code should be executed
/*
* SCRIPTS Emulation
*/
#include "scsiop.h"
/*
* UINT8 scsi_read_8(UINT32 addr);
*
* Reads from the SCSI register space.
*
* Parameters:
* addr = Register address (only lower 8 bits matter.)
*
* Returns:
* Returns data from the register read.
*/
UINT8 scsi_read_8(UINT32 addr)
{
UINT8 reg;
addr &= 0xFF;
//if (addr > 0x5F)
// error("%08X: SCSI invalid read from %02X", ppc_get_reg(PPC_REG_PC), addr);
reg = REG8(addr);
switch (addr)
{
case 0x14:
REG8(addr) &= 0xFE; // clear DIP
break;
default:
break;
}
return reg;
}
/*
* UINT32 scsi_read_32(UINT32 addr);
*
* Reads from the SCSI register space.
*
* Parameters:
* addr = Register address (only lower 8 bits matter.)
*
* Returns:
* Returns data from the register read.
*/
UINT32 scsi_read_32(UINT32 addr)
{
UINT32 reg;
// error("SCSI 32-bit read from %08X", addr);
addr &= 0xFF;
if (addr > 0x5F)
error("%08X: SCSI invalid read from %02X", ppc_get_pc(), addr);
reg = REG32(addr);
switch (addr)
{
case 0x14:
error("%08X: SCSI 32-bit read from reg %02X -- don't know what to do", ppc_get_pc(), addr);
break;
default:
// NOTE: some registers might have to be handled to clear certain
// bits
break;
}
return reg;
}
/*
* void scsi_write_8(UINT32 addr, UINT8 data);
*
* Writes a byte to the SCSI register space.
*
* Parameters:
* addr = Register address (only lower 8 bits matter.)
* data = Data to write.
*/
void scsi_write_8(UINT32 addr, UINT8 data)
{
addr &= 0xFF;
if (addr > 0x5F)
error("%08X: SCSI invalid write8 to %02X", ppc_get_pc(), addr);
//message(0, "%08X: SCSI %02X = %02X", ppc_get_pc(), addr, data);
REG8(addr) = data;
switch (addr)
{
case 0x3B: // DCNTL: DMA Control
/*
* 7 6 5 4 3 2 1 0
* +------+------+------+------+------+------+------+------+
* | CLSE | PFF | PFEN | SSM | IRQM | STD | IRQD | COM |
* +------+------+------+------+------+------+------+------+
*
* CLSE Cache Line Size Enable
*
* PFF Prefetch Flush
*
* PFEN Prefetch Enable
*
* SSM Single Step Mode
*
* Setting this bit causes the SCSI to stop after executing
* each SCRIPTS instruction and generate a single step
* interrupt. To restart the SCSI after the interrupt has
* been generated, read ISTAT and DSTAT to recognize and
* clear the interrupt, then set STD bit in this register
* to resume execution.
*
* IRQM IRQ Mode
*
* STD Start DMA Operation
*
* The SCSI fetches an instruction and executes it when this
* bit is set. It is required when the SCSI is in one of the
* following modes:
*
* - Manual start mode: Bit 0 in the DMODE register is
* set.
* - Single step mode: Bit 4 in the DCNTL register is
* set.
*
* When in manual mode, setting this bit starts instruction
* execution -- it remains set until an interrupt occurs. In
* single step mode, it restarts execution after an
* interrupt.
*
* IRQD IRQ Disable
*
* COM LSI53C700 Family Compatibility
*/
/*
* Single-stepping is checked for in scsi_run() (the number of
* instructions to execute will be reduced to 1 there.)
*/
if ((REG8(0x38) & 0x01) || // MAN=1, start SCRIPTS on STD=1
(REG8(0x3B) & 0x10)) // single step, resume execution
{
scripts_exec = data & 0x04;
scsi_run(500);
}
break;
}
}
/*
* void scsi_write_16(UINT32 addr, UINT16 data);
*
* Writes a word to the SCSI register space.
*
* Parameters:
* addr = Register address (only lower 8 bits matter.)
* data = Data to write.
*/
void scsi_write_16(UINT32 addr, UINT16 data)
{
data = BSWAP16(data);
//message(0, "%08X: SCSI %02X = %04X", ppc_get_pc(), addr, data);
}
/*
* void scsi_write_32(UINT32 addr, UINT32 data);
*
* Writes a byte to the SCSI register space.
*
* Parameters:
* addr = Register address (only lower 8 bits matter.)
* data = Data to write.
*/
void scsi_write_32(UINT32 addr, UINT32 data)
{
if ((addr & 0xff) > 0x5C)
error("%08X: SCSI invalid write32 to %08X", ppc_get_pc(), addr);
addr &= 0xff;
data = BSWAP32(data);
REG32(addr) = data;
// message(0, "%08X: SCSI %02X = %08X", ppc_get_reg(PPC_REG_PC), addr, data);
switch (addr)
{
case 0x2C: // DSP: DMA SCRIPTS Pointer
if ((REG8(0x38) & 0x01) == 0) // MAN=0, start SCRIPTS automatically
scripts_exec = 1;
scsi_run(500);
break;
default:
break;
}
}
/*
* void scsi_save_state(FILE *fp);
*
* Saves the state of the SCSI controller to a file.
*
* Parameters:
* fp = File to save to.
*/
void scsi_save_state(FILE *fp)
{
fwrite(scsi_regs, sizeof(UINT8), 0x60, fp);
fwrite(&scripts_exec, sizeof(BOOL), 1, fp);
}
/*
* void scsi_load_state(FILE *fp);
*
* Loads the state of the SCSI controller from a file.
*
* Parameters:
* fp = File to load from.
*/
void scsi_load_state(FILE *fp)
{
fread(scsi_regs, sizeof(UINT8), 0x60, fp);
fread(&scripts_exec, sizeof(BOOL), 1, fp);
}
/*
* void scsi_reset(void);
*
* Initializes the SCSI controller to its power-on state. All bits which are
* marked as undefined by the manual are simply set to 0 here.
*/
void scsi_reset(void)
{
memset(scsi_regs, 0, sizeof(scsi_regs));
scripts_exec = 0;
REG8(0x00) = 0xc0;
REG8(0x0C) = 0x80;
REG8(0x0F) = 0x02;
REG8(0x18) = 0xff;
REG8(0x19) = 0xf0;
REG8(0x1A) = 0x01;
REG8(0x46) = 0x60;
REG8(0x47) = 0x0f;
REG8(0x4C) = 0x03;
}
/*
* void scsi_init(UINT8 (*read8)(UINT32), UINT16 (*read16)(UINT32),
* UINT32 (*read32)(UINT32), void (*write8)(UINT32, UINT8),
* void (*write16)(UINT32, UINT16),
* void (*write32)(UINT32, UINT32));
*
* Initializes the SCSI controller emulation by building the SCRIPTS opcode
* table and setting the memory access handlers.
*
* Parameters:
* read8 = Handler to use for 8-bit reads.
* read16 = Handler to use for 16-bit reads.
* read32 = Handler to use for 32-bit reads.
* write8 = Handler to use for 8-bit writes.
* write16 = Handler to use for 16-bit writes.
* write32 = Handler to use for 32-bit writes.
*/
void scsi_init(UINT8 (*read8)(UINT32), UINT16 (*read16)(UINT32),
UINT32 (*read32)(UINT32), void (*write8)(UINT32, UINT8),
void (*write16)(UINT32, UINT16),
void (*write32)(UINT32, UINT32))
{
read_8 = read8;
read_16 = read16;
read_32 = read32;
write_8 = write8;
write_16 = write16;
write_32 = write32;
build_opcode_table();
}
/*
* void scsi_shutdown(void);
*
* Shuts down the SCSI emulation (actually does nothing.)
*/
void scsi_shutdown(void)
{
}

51
core/scsi.h Normal file
View file

@ -0,0 +1,51 @@
/*
* Sega Model 3 Emulator
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* 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 (license.txt); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* scsi.h
*
* NCR 53C810 SCSI controller header.
*/
#ifndef INCLUDED_SCSI_H
#define INCLUDED_SCSI_H
/*
* Functions
*/
extern UINT8 scsi_read_8(UINT32);
extern UINT32 scsi_read_32(UINT32);
extern void scsi_write_8(UINT32, UINT8);
extern void scsi_write_16(UINT32, UINT16);
extern void scsi_write_32(UINT32, UINT32);
extern void scsi_save_state(FILE *);
extern void scsi_load_state(FILE *);
extern void scsi_run(INT);
extern void scsi_reset(void);
extern void scsi_init(UINT8 (*)(UINT32), UINT16 (*)(UINT32),
UINT32 (*)(UINT32), void (*)(UINT32, UINT8),
void (*)(UINT32, UINT16),
void (*)(UINT32, UINT32));
extern void scsi_shutdown(void);
#endif // INCLUDED_SCSI_H

221
core/scsiop.h Normal file
View file

@ -0,0 +1,221 @@
/*
* Sega Model 3 Emulator
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* 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 (license.txt); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* scsiop.h
*
* NCR 53C810 SCSI controller SCRIPTS emulation. This file is intended to be
* included by scsi.c only.
*/
#ifndef INCLUDED_SCSIOP_H
#define INCLUDED_SCSIOP_H
/*
* Macros
*/
#define INSTRUCTION(name) static BOOL name()
#define FETCH(dest) do { dest = read_32(REG32(0x2c)); REG32(0x2c) += 4; dest = BSWAP32(dest); } while (0);
#define DBC (REG32(0x24) & 0xffffff)
#define DSPS (REG32(0x30))
#define TEMP (REG32(0x1c))
/*
* Opcode Table
*
* Use the upper 8 bits of a SCRIPTS instruction as an index into this table.
*/
static BOOL (*op_table[256])();
/*
* Move Memory
*/
#ifdef _PROFILE_
extern UINT is_dma;
#endif
INSTRUCTION(move_memory)
{
UINT32 source = DSPS, dest;
INT num_bytes = DBC;
PROFILE_SECT_ENTRY("scsi");
#ifdef _PROFILE_
is_dma = 1;
#endif
FETCH(TEMP);
dest = TEMP;
// message(0, "%08X (%08X): SCSI move memory: %08X->%08X, %X", ppc_get_reg(PPC_REG_PC), ppc_get_reg(PPC_REG_LR), source, dest, num_bytes);
/*
* Perform a 32-bit copy if possible and if necessary, finish off with a
* byte-for-byte copy
*/
/*for (i = 0; i < num_bytes / 4; i++)
{
write_32(dest, read_32(source));
dest += 4;
source += 4;
}*/
model3_dma_transfer(source, dest, num_bytes, FALSE);
if (num_bytes & 3)
{
error("unaligned SCSI op !!!\n");
num_bytes &= 3;
while (num_bytes--)
write_8(dest++, read_8(source++));
}
source += num_bytes;
dest += num_bytes;
#ifdef _PROFILE_
is_dma = 0;
#endif
REG32(0x24) &= 0xff000000; // update DBC (is any of this necessary???)
DSPS = source;
TEMP = dest;
PROFILE_SECT_EXIT("scsi");
return 0;
}
/*
* INT and INTFLY
*/
INSTRUCTION(int_and_intfly)
{
if ((DBC & 0x100000)) // INTFLY -- not yet emulated!
return 1;
if (((REG32(0x24) >> 21) & 1) || ((REG32(0x24) >> 18) & 1) || ((REG32(0x24) >> 17) & 1))
return 1; // conditional tests not yet emulated
REG8(0x14) |= 0x01; // DIP=1
scripts_exec = 0; // halt execution
/*
* NOTE: I haven't seen any games rely on this, so if you observe SCSI
* problems, remove this to see if it helps.
*/
REG8(0x14) |= 0x01; // DIP=1
REG8(0x0c) |= 0x04; // SIR=1
//model3_add_irq(0x60);
ppc_set_irq_line(1);
return 0;
}
/*
* Invalid Instruction
*/
INSTRUCTION(invalid)
{
// message(0, "INVALID SCSI INSTRUCTION @ %08X", REG32(0x2c));
return 1;
}
/*
* void scsi_run(INT num);
*
* Runs SCSI SCRIPTS instructions until the code halts or the requested number
* of instructions is executed.
*
* Parameters:
* num = Number of instructions to execute.
*/
void scsi_run(INT num)
{
LOG("model3.log", "SCSI exec %08X\n", REG32(0x2c));
if (!scripts_exec)
return;
if ((REG8(0x3B) & 0x10)) // single step mode
num = 1;
while (num-- && scripts_exec)
{
UINT32 save_addr = REG32(0x2c); // for debugging
FETCH(REG32(0x24)); // first double word into DCMD and DBC
FETCH(DSPS); // second double word into DSPS
if ((*op_table[REG32(0x24) >> 24])())
error("SCSI: invalid instruction @ %08X", save_addr);
}
scripts_exec = 0;
if ((REG8(0x3B) & 0x10)) // single step mode, trigger interrupt
{
REG8(0x0c) |= 0x08; // SSI=1
REG8(0x14) |= 0x01; // DIP=1
ppc_set_irq_line(1); // what about Model 3 IRQ status?
}
}
/*
* insert():
*
* Inserts an instruction into the appropriate elements of the opcode table
* under the control of a mask.
*/
static void insert(UINT8 match, UINT8 mask, BOOL (*handler)())
{
UINT32 i;
for (i = 0; i < 256; i++)
{
if ((i & mask) == match)
op_table[i] = handler;
}
}
/*
* build_opcode_table():
*
* Installs instruction handlers.
*/
static void build_opcode_table(void)
{
insert(0, 0, &invalid);
insert(0xc0, 0xfe, &move_memory);
insert(0x98, 0xf8, &int_and_intfly);
}
#endif // INCLUDED_SCSIOP_H

2494
core/scsp.c Normal file

File diff suppressed because it is too large Load diff

29
core/scsp.h Normal file
View file

@ -0,0 +1,29 @@
#ifndef _SCSP_H_
#define _SCSP_H_
extern void scsp_shutdown(void);
extern void scsp_init(UINT8 *scsp_ram, void *sint_hand, void *mint_hand);
extern void scsp_reset(void);
extern void scsp_update(INT32 *bufL, INT32 *bufR, UINT32 len);
extern void scsp_update_timer(UINT32 len);
extern UINT32 scsp_read_8(UINT32 a);
extern UINT32 scsp_read_16(UINT32 a);
extern UINT32 scsp_read_32(UINT32 a);
extern void scsp_write_8(UINT32 a, UINT32 d);
extern void scsp_write_16(UINT32 a, UINT32 d);
extern void scsp_write_32(UINT32 a, UINT32 d);
extern void scsp_midi_in_send(UINT8 data);
extern void scsp_midi_out_send(UINT8 data);
extern UINT8 scsp_midi_in_read(void);
extern UINT8 scsp_midi_out_read(void);
extern char * scsp_debug_slist_on(void);
extern char * scsp_debug_ilist(INT s_m, char * out);
#endif /* _SCSP_H_ */

823
core/tilegen.c Normal file
View file

@ -0,0 +1,823 @@
/*
* Sega Model 3 Emulator
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* 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 (license.txt); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* tilegen.c
*
* Tilemap generator.
*
* Palette Notes:
* - Each palette entry occupies 32 bits. Only the second 16 bits are
* actually used.
* - The format of a 16-bit palette entry is: AGGGGGBBBBBRRRRR
*
* Register Notes:
*
* 0x20 -- Layer Colors:
*
* 31 23 20 0
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* |-|-|-|-|-|-|-|-|D|C|B|A|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
* D = Layer 0xFE000 color control (0 = 8-bit, 1 = 4-bit)
* C = Layer 0xFC000 color control (0 = 8-bit, 1 = 4-bit)
* B = Layer 0xFA000 color control (0 = 8-bit, 1 = 4-bit)
* A = Layer 0xF8000 color control (0 = 8-bit, 1 = 4-bit)
*/
#include "model3.h"
/******************************************************************/
/* Privates */
/******************************************************************/
/*
* NOTE: It is critical that vram be set to NULL if it has not yet been
* allocated because tilegen_set_layer_format() will try to use it to
* recache the palette.
*/
static UINT8 *vram = NULL; // 2D VRAM (passed to tilegen_init())
static UINT8 reg[0x100]; // tilemap generator registers
/*
* Register Macros
*/
#define REG_LAYER_COLORS 0x20
/*
* Pre-Decoded Palette Data
*
* Depending on the renderer color depth, the data is either 32-bit RGBA8 or
* 16-bit RGB5A1. The actual order of the fields is obtained from the renderer
* but it is guaranteed that for 16-bit modes, the color components will each
* be 5 bits and the alpha will be 1 and for the 32-bit modes, all components
* will be 8 bits.
*
* For alpha channel: All bits set means the color is opaque, all bits clear
* means the color is transparent. No other bit combinations should be used.
*/
static UINT32 *pal;
/*
* Layer Format
*
* Information that is passed by the renderer on the format of layers. Bit
* position 0 is the LSB (none of that backwards IBM junk ;)) RGBA bit
* positions give the position of the LSB of the field.
*/
static UINT pitch; // layer pitch (in pixels)
static UINT rpos, gpos, bpos, apos; // R, G, B, A bit positions
static INT bpp; // 15 or 32 only
static int tilemap_is_dirty[4];
static int tilemap_dirty[4][64*64];
static int tilemap_depth[4][64*64];
static int tilemap_redraw[4];
/******************************************************************/
/* Rendering */
/******************************************************************/
/*
* PUTPIXELx_xx():
*
* A handy macro used within the draw_tile_xbit_xx() macros to plot a pixel
* and advance the buffer pointer.
*/
/*#define PUTPIXEL8_32(bp) \
do { \
pixel = pal[((pattern >> bp) & 0xFF) | pal_bits]; \
*buf++ = pixel; \
} while (0)
#define PUTPIXEL4_32(bp) \
do { \
pixel = pal[((pattern >> bp) & 0xF) | pal_bits]; \
*buf++ = pixel; \
} while (0)
*/
#define PUTPIXEL8(bp) \
do \
{ \
*buf++ = ((pattern >> bp) & 0xff) | pal_bits; \
} while(0)
#define PUTPIXEL4(bp) \
do \
{ \
*buf++ = ((pattern >> bp) & 0xf) | pal_bits; \
} while(0)
/*
* draw_tile_8bit_32():
*
* Draws an 8-bit tile to a 32-bit layer buffer.
*/
static void draw_tile_8bit(UINT tile, UINT16 *buf)
{
UINT tile_offs; // offset of tile within VRAM
UINT pal_bits; // color palette bits obtained from tile
UINT y;
UINT32 pattern; // 4 pattern pixels fetched at once
/*
* Calculate tile offset; each tile occupies 64 bytes when using 8-bit
* pixels
*/
//tile_offs = tile & 0x3fff;
//tile_offs *= 64;
tile_offs = ((tile & 0x3fff) << 1) | ((tile >> 15) & 1);
tile_offs *= 32;
/*
* Obtain upper color bits; the lower 8 bits come from the tile pattern
*/
pal_bits = tile & 0x7F00;
/*
* Draw!
*/
for (y = 0; y < 8; y++)
{
/*
* Fetch first 4 pixels and draw them
*/
pattern = *((UINT32 *) &vram[tile_offs]);
tile_offs += 4;
PUTPIXEL8(24);
PUTPIXEL8(16);
PUTPIXEL8(8);
PUTPIXEL8(0);
/*
* Next 4
*/
pattern = *((UINT32 *) &vram[tile_offs]);
tile_offs += 4;
PUTPIXEL8(24);
PUTPIXEL8(16);
PUTPIXEL8(8);
PUTPIXEL8(0);
/*
* Move to the next line
*/
buf += (pitch - 8); // next line in layer buffer
}
}
/*
* draw_tile_4bit_32():
*
* Draws a 4-bit tile to a 32-bit layer buffer.
*/
static void draw_tile_4bit(UINT tile, UINT16 *buf)
{
UINT tile_offs; // offset of tile within VRAM
UINT pal_bits; // color palette bits obtained from tile
UINT y;
UINT32 pattern; // 8 pattern pixels fetched at once
/*
* Calculate tile offset; each tile occupies 32 bytes when using 4-bit
* pixels
*/
tile_offs = ((tile & 0x3fff) << 1) | ((tile >> 15) & 1);
tile_offs *= 32;
/*
* Obtain upper color bits; the lower 4 bits come from the tile pattern
*/
pal_bits = tile & 0x7FF0;
/*
* Draw!
*/
for (y = 0; y < 8; y++)
{
pattern = *((UINT32 *) &vram[tile_offs]);
/*
* Draw the 8 pixels we've fetched
*/
PUTPIXEL4(28);
PUTPIXEL4(24);
PUTPIXEL4(20);
PUTPIXEL4(16);
PUTPIXEL4(12);
PUTPIXEL4(8);
PUTPIXEL4(4);
PUTPIXEL4(0);
/*
* Move to the next line
*/
tile_offs += 4; // next tile pattern line
buf += (pitch - 8); // next line in layer buffer
}
}
/*
* draw_layer_8bit_32():
*
* Draws an entire layer of 8-bit tiles to a 32-bit layer buffer.
*/
static void draw_layer_8bit(UINT16 *layer, int layer_num)
{
int ty, tx;
int tilenum;
UINT32 tile;
UINT32 addr = 0xf8000 + (layer_num * 0x2000);
if (tilemap_is_dirty[layer_num] == 0)
{
return;
}
tilemap_is_dirty[layer_num] = 0;
tilenum = 0;
for (ty = 0; ty < 64; ty++)
{
for (tx = 0; tx < 64; tx+=2)
{
if (tilemap_redraw[layer_num] || tilemap_dirty[layer_num][tilenum+0])
{
tilemap_depth[layer_num][tilenum+0] = 0;
tilemap_dirty[layer_num][tilenum+0] = 0;
tile = *((UINT32 *) &vram[addr]) >> 16;
draw_tile_8bit(tile & 0xffff, layer);
}
if (tilemap_redraw[layer_num] || tilemap_dirty[layer_num][tilenum+1])
{
tilemap_depth[layer_num][tilenum+1] = 0;
tilemap_dirty[layer_num][tilenum+1] = 0;
tile = *((UINT32 *) &vram[addr]) >> 0;
draw_tile_8bit(tile & 0xffff, layer+8);
}
addr += 4;
layer += 16;
tilenum+=2;
}
//addr += (64 - 62) * 2;
layer += (7 * pitch) + (pitch - 512); // next tile row
}
tilemap_redraw[layer_num] = 0;
}
/*
* draw_layer_4bit_32():
*
* Draws an entire layer of 4-bit tiles to a 32-bit layer buffer.
*/
static void draw_layer_4bit(UINT16 *layer, int layer_num)
{
int ty, tx;
int tilenum;
UINT32 tile;
UINT32 addr = 0xf8000 + (layer_num * 0x2000);
if (tilemap_is_dirty[layer_num] == 0)
{
return;
}
tilemap_is_dirty[layer_num] = 0;
tilenum = 0;
for (ty = 0; ty < 64; ty++)
{
for (tx = 0; tx < 64; tx+=2)
{
if (tilemap_redraw[layer_num] || tilemap_dirty[layer_num][tilenum+0])
{
tilemap_depth[layer_num][tilenum+0] = 1;
tilemap_dirty[layer_num][tilenum+0] = 0;
tile = *((UINT32 *) &vram[addr]) >> 16;
draw_tile_4bit(tile & 0xffff, layer);
}
if (tilemap_redraw[layer_num] || tilemap_dirty[layer_num][tilenum+1])
{
tilemap_depth[layer_num][tilenum+0] = 1;
tilemap_dirty[layer_num][tilenum+1] = 0;
tile = *((UINT32 *) &vram[addr]) >> 0;
draw_tile_4bit(tile & 0xffff, layer+8);
}
addr += 4;
layer += 16;
tilenum+=2;
}
//addr += (64 - 62) * 2;
layer += (7 * pitch) + (pitch - 512); // next tile row
}
tilemap_redraw[layer_num] = 0;
}
/*
* void tilegen_update(void);
*
* Renders up to 4 layers for the current frame.
*/
void tilegen_update(void)
{
UINT8 *layer;
UINT layer_colors, layer_color_mask;
FLAGS layer_enable_mask;
int i, j;
/*
* Render layers
*/
PROFILE_SECT_ENTRY("tilegen");
layer_colors = BSWAP32(*(UINT32 *) &reg[REG_LAYER_COLORS]);
layer_color_mask = 0x00100000; // first layer color bit (moves left)
layer_enable_mask = 1;
// layer_colors = 0; // enable this to force 8-bit mode for VF3
{
UINT32 *palette;
int pwidth;
int ppitch;
int pheight;
int p = 0;
osd_renderer_get_palette_buffer(&palette, &pwidth, &ppitch);
pheight = 0x10000 / pwidth;
for (j=0; j < 128; j++)
{
int pindex = j * ppitch;
p = j * 256;
for (i=0; i < 256; i++)
{
int a,r,g,b;
UINT32 rgba;
UINT16 pix;
pix = pal[p];
a = (pix & 0x8000) ? 0x00 : 0xff;
b = (pix >> 10) & 0x1f;
g = (pix >> 5) & 0x1f;
r = (pix & 0x1f);
b = (b << 3) | (b >> 2);
g = (g << 3) | (g >> 2);
r = (r << 3) | (r >> 2);
rgba = (a << 24) | (r << 16) | (g << 8) | (b << 0);
palette[pindex + i] = rgba;
p++;
// a very hackish way to counter the effect of using colours as texture coords
if (i == 239)
p--;
}
}
osd_renderer_free_palette_buffer();
}
for (i = 0; i < 4; i++)
{
if ((m3_config.layer_enable & layer_enable_mask))
{
osd_renderer_get_layer_buffer(i, &layer, &pitch);
if ((layer_colors & layer_color_mask))
{
draw_layer_4bit((UINT16 *) layer, i);
}
else
{
draw_layer_8bit((UINT16 *) layer, i);
}
osd_renderer_free_layer_buffer(i);
}
layer_color_mask <<= 1;
layer_enable_mask <<= 1;
}
PROFILE_SECT_EXIT("tilegen");
}
/******************************************************************/
/* VRAM Access */
/******************************************************************/
static void mark_tilemap_dirty(int layer)
{
tilemap_is_dirty[layer] = 1;
tilemap_redraw[layer] = 1;
}
/*
* UINT16 tilegen_vram_read_16(UINT32 addr);
*
* Reads a 16-bit word from VRAM.
*
* Parameters:
* addr = Address.
*
* Returns:
* Data read.
*/
UINT16 tilegen_vram_read_16(UINT32 addr)
{
return(BSWAP16(*(UINT16 *)&vram[addr & 0x1FFFFF]));
}
/*
* UINT32 tilegen_vram_read_32(UINT32 addr);
*
* Reads a 32-bit word from VRAM.
*
* Parameters:
* addr = Address.
*
* Returns:
* Data read.
*/
UINT32 tilegen_vram_read_32(UINT32 addr)
{
return(BSWAP32(*(UINT32 *)&vram[addr & 0x1FFFFF]));
}
/*
* void tilegen_vram_write_32(UINT32 addr, UINT32 data);
*
* Writes a 32-bit word to VRAM. Palette decoding is handled here.
*
* Parameters:
* addr = Address.
* data = Data.
*/
void tilegen_vram_write_32(UINT32 addr, UINT32 data)
{
UINT color;
addr &= 0x1FFFFF;
data = BSWAP32(data); // return to its natural order (as on PPC)
if (addr < 0xf8000)
{
*(UINT32 *)&vram[addr] = data;
}
else if (addr >= 0x0f8000 && addr < 0x100000)
{
UINT32 old_data;
int ad, layer, layer_depth, old_depth;
ad = addr - 0xf8000;
layer = ad / 0x2000;
old_data = *(UINT32 *)&vram[addr];
layer_depth = (BSWAP32(*(UINT32 *) &reg[REG_LAYER_COLORS]) >> (20+layer)) & 1;
old_depth = tilemap_depth[layer][((ad & 0x1fff) / 2)];
if (data != old_data || layer_depth != old_depth)
{
*(UINT32 *)&vram[addr] = data;
//ad = addr - 0xf8000;
//layer = ad / 0x2000;
tilemap_dirty[layer][((ad & 0x1fff) / 2) + 0] = 1;
tilemap_dirty[layer][((ad & 0x1fff) / 2) + 1] = 1;
tilemap_is_dirty[layer] = 1;
}
}
else if (addr >= 0x100000 && addr < 0x120000) // palette
{
*(UINT32 *)&vram[addr] = data;
color = (addr - 0x100000) / 4; // color number
pal[color] = data;
}
}
static void recache_palette(void)
{
UINT32 i;
for (i = 0x100000; i < 0x11FFFF; i += 4)
tilegen_vram_write_32(i, BSWAP32(*(UINT32 *) &vram[i]));
}
/******************************************************************/
/* Tilegen I/O Port Access */
/******************************************************************/
/*
* UINT32 tilegen_read_32(UINT32 a);
*
* Reads a 32-bit word from the tilemap generator register area.
*
* Parameters:
* a = Address.
*
* Returns:
* Data read.
*/
UINT32 tilegen_read_32(UINT32 a)
{
// LOG("MODEL3.LOG", "TILEGEN: %08X: read 32 %08X\n", PPC_PC, a);
//message(0, "tilegen: %08X: read 32 %08X", PPC_PC, a);
a &= 0xFF;
switch(a)
{
case 0x00: // Status/Control
// 0x20 (latch) controls layer pairing
return(0 << 24);
}
return(BSWAP32(*(UINT32 *)&reg[a]));
}
/*
* void tilegen_write_32(UINT32 a, UINT32 d);
*
* Writes a 32-bit word to the tilemap generator register area.
*
* Parameters:
* a = Address.
* d = Data.
*/
void tilegen_write_32(UINT32 a, UINT32 d)
{
/* data is written as 32-bit, but only higher byte is used */
// LOG("MODEL3.LOG", "TILEGEN: %08X: write 32 %08X = %08X\n", PPC_PC, a, d);
a &= 0xFF;
//if (a != 0x60 && a != 0x64 && a != 0x68 && a != 0x6c &&
// a != 0x10 && a != 0x0c && a != 0x40 && a != 0x44)
//printf("tilegen: %08X, %08X\n", a, d);
switch(a)
{
case 0x00:
case 0x04:
case 0x08:
case 0x0C:
break;
case 0x10:
model3_remove_irq((UINT8) (d >> 24));
break;
case 0x14:
case 0x18:
case 0x1C:
break;
case 0x20:
{
UINT32 olddata = *(UINT32 *)&reg[a];
UINT32 newdata = BSWAP32(d);
if ((olddata & 0x100000) != (newdata & 0x100000))
mark_tilemap_dirty(0);
if ((olddata & 0x200000) != (newdata & 0x200000))
mark_tilemap_dirty(1);
if ((olddata & 0x400000) != (newdata & 0x400000))
mark_tilemap_dirty(2);
if ((olddata & 0x800000) != (newdata & 0x800000))
mark_tilemap_dirty(3);
/**(UINT32 *)&reg[0x60] &= ~0x80000000;
*(UINT32 *)&reg[0x64] &= ~0x80000000;
*(UINT32 *)&reg[0x68] &= ~0x80000000;
*(UINT32 *)&reg[0x6c] &= ~0x80000000;*/
break;
}
case 0x24:
case 0x40:
case 0x44:
break;
case 0x60:
case 0x64:
case 0x68:
case 0x6C:
break;
}
*(UINT32 *)&reg[a] = BSWAP32(d);
}
/******************************************************************/
/* Set Up, Shut Down, and State Management */
/******************************************************************/
/*
* void tilegen_save_state(FILE *fp);
*
* Saves the state of the tile generator to a file.
*
* Parameters:
* fp = File to save to.
*/
void tilegen_save_state(FILE *fp)
{
fwrite(vram, sizeof(UINT8), 1*1024*1024+2*65536, fp);
fwrite(reg, sizeof(UINT8), 0x100, fp);
}
/*
* void tilegen_load_state(FILE *fp);
*
* Loads the state of the tile generator from a file.
*
* Parameters:
* fp = File to load from.
*/
void tilegen_load_state(FILE *fp)
{
fread(vram, sizeof(UINT8), 1*1024*1024+2*65536, fp);
fread(reg, sizeof(UINT8), 0x100, fp);
recache_palette();
mark_tilemap_dirty(0);
mark_tilemap_dirty(1);
mark_tilemap_dirty(2);
mark_tilemap_dirty(3);
}
/*
* void tilegen_shutdown(void);
*
* Shuts down the tilemap generator.
*/
void tilegen_shutdown(void)
{
vram = NULL;
SAFE_FREE(pal);
}
/*
* void tilegen_init(UINT8 *vramptr);
*
* Initializes the tilemap generator.
*
* Parameters:
* vramptr = Pointer to 2D VRAM.
*/
void tilegen_init(UINT8 *vramptr)
{
vram = vramptr;
mark_tilemap_dirty(0);
mark_tilemap_dirty(1);
mark_tilemap_dirty(2);
mark_tilemap_dirty(3);
pal = malloc(sizeof(UINT32) * 65536);
atexit(tilegen_shutdown);
}
BOOL tilegen_is_layer_enabled(int layer)
{
if (layer == 1 && stricmp(m3_config.game_id, "lostwsga") == 0)
return FALSE;
switch (layer)
{
case 0:
return *(UINT32 *)&reg[0x60] & 0x80000000 ? 1 : 0;
case 1:
return *(UINT32 *)&reg[0x64] & 0x80000000 ? 1 : 0;
case 2:
return *(UINT32 *)&reg[0x68] & 0x80000000 ? 1 : 0;
case 3:
return *(UINT32 *)&reg[0x6c] & 0x80000000 ? 1 : 0;
}
return 0;
}
UINT32 tilegen_get_layer_color_offset(int layer)
{
switch (layer)
{
case 0:
case 1:
{
INT8 r = (*(UINT32 *)&reg[0x40] >> 16) & 0xff;
INT8 g = (*(UINT32 *)&reg[0x40] >> 8) & 0xff;
INT8 b = (*(UINT32 *)&reg[0x40] >> 0) & 0xff;
r += 127;
g += 127;
b += 127;
return (r << 16) | (g << 8) | (b);
}
case 2:
case 3:
{
UINT8 r = (*(UINT32 *)&reg[0x44] >> 16) & 0xff;
UINT8 g = (*(UINT32 *)&reg[0x44] >> 8) & 0xff;
UINT8 b = (*(UINT32 *)&reg[0x44] >> 0) & 0xff;
r ^= 0x80;
g ^= 0x80;
b ^= 0x80;
return (r << 16) | (g << 8) | (b);
}
}
return 0;
}
UINT32 *tilegen_get_priority_buffer(void)
{
return (UINT32 *)&vram[0xf7000];
}
BOOL tilegen_is_priority_enabled(void)
{
UINT32 v = *(UINT32 *)&reg[0x20];
return (v & 0x80) ? TRUE : FALSE;
}
UINT32 tilegen_get_layer_scroll_pos(int layer)
{
UINT32 s = *(UINT32 *)&reg[0x60 + (layer*4)];
return s & 0x7fff7fff;
}
/*
* void tilegen_reset(void);
*
* Resets the tilemap generator. The registers are put into a reset state and
* the palette is zeroed out.
*/
void tilegen_reset(void)
{
memset(reg, 0xFF, 0x100);
memset(pal, 0x00, 65536 * sizeof(UINT32));
}

49
core/tilegen.h Normal file
View file

@ -0,0 +1,49 @@
/*
* Sega Model 3 Emulator
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* 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 (license.txt); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* tilegen.h
*
* Tilemap generator header.
*/
#ifndef INCLUDED_TILEGEN_H
#define INCLUDED_TILEGEN_H
extern void tilegen_update(void);
extern UINT16 tilegen_vram_read_16(UINT32 addr);
extern UINT32 tilegen_vram_read_32(UINT32);
extern void tilegen_vram_write_32(UINT32, UINT32);
extern UINT16 tilegen_read_16(UINT32);
extern UINT32 tilegen_read_32(UINT32);
extern void tilegen_write_32(UINT32, UINT32);
extern BOOL tilegen_is_layer_enabled(int);
extern UINT32 tilegen_get_layer_color_offset(int layer);
extern void tilegen_save_state(FILE *);
extern void tilegen_load_state(FILE *);
extern void tilegen_reset(void);
extern void tilegen_init(UINT8 *);
extern void tilegen_shutdown(void);
#endif // INCLUDED_TILEGEN_H

1013
expat/expat.h Normal file

File diff suppressed because it is too large Load diff

115
expat/expat_external.h Normal file
View file

@ -0,0 +1,115 @@
/* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd
See the file COPYING for copying permission.
*/
#ifndef Expat_External_INCLUDED
#define Expat_External_INCLUDED 1
/* External API definitions */
#if defined(_MSC_EXTENSIONS) && !defined(__BEOS__) && !defined(__CYGWIN__)
#define XML_USE_MSC_EXTENSIONS 1
#endif
/* Expat tries very hard to make the API boundary very specifically
defined. There are two macros defined to control this boundary;
each of these can be defined before including this header to
achieve some different behavior, but doing so it not recommended or
tested frequently.
XMLCALL - The calling convention to use for all calls across the
"library boundary." This will default to cdecl, and
try really hard to tell the compiler that's what we
want.
XMLIMPORT - Whatever magic is needed to note that a function is
to be imported from a dynamically loaded library
(.dll, .so, or .sl, depending on your platform).
The XMLCALL macro was added in Expat 1.95.7. The only one which is
expected to be directly useful in client code is XMLCALL.
Note that on at least some Unix versions, the Expat library must be
compiled with the cdecl calling convention as the default since
system headers may assume the cdecl convention.
*/
#ifndef XMLCALL
#if defined(XML_USE_MSC_EXTENSIONS)
#define XMLCALL __cdecl
#elif defined(__GNUC__) && defined(__i386)
#define XMLCALL __attribute__((cdecl))
#else
/* For any platform which uses this definition and supports more than
one calling convention, we need to extend this definition to
declare the convention used on that platform, if it's possible to
do so.
If this is the case for your platform, please file a bug report
with information on how to identify your platform via the C
pre-processor and how to specify the same calling convention as the
platform's malloc() implementation.
*/
#define XMLCALL
#endif
#endif /* not defined XMLCALL */
#if !defined(XML_STATIC) && !defined(XMLIMPORT)
#ifndef XML_BUILDING_EXPAT
/* using Expat from an application */
#ifdef XML_USE_MSC_EXTENSIONS
#define XMLIMPORT __declspec(dllimport)
#endif
#endif
#endif /* not defined XML_STATIC */
/* If we didn't define it above, define it away: */
#ifndef XMLIMPORT
#define XMLIMPORT
#endif
#define XMLPARSEAPI(type) XMLIMPORT type XMLCALL
#ifdef __cplusplus
extern "C" {
#endif
#ifdef XML_UNICODE_WCHAR_T
#define XML_UNICODE
#endif
#ifdef XML_UNICODE /* Information is UTF-16 encoded. */
#ifdef XML_UNICODE_WCHAR_T
typedef wchar_t XML_Char;
typedef wchar_t XML_LChar;
#else
typedef unsigned short XML_Char;
typedef char XML_LChar;
#endif /* XML_UNICODE_WCHAR_T */
#else /* Information is UTF-8 encoded. */
typedef char XML_Char;
typedef char XML_LChar;
#endif /* XML_UNICODE */
#ifdef XML_LARGE_SIZE /* Use large integers for file/stream positions. */
#if defined(XML_USE_MSC_EXTENSIONS) && _MSC_VER < 1400
typedef __int64 XML_Index;
typedef unsigned __int64 XML_Size;
#else
typedef long long XML_Index;
typedef unsigned long long XML_Size;
#endif
#else
typedef long XML_Index;
typedef unsigned long XML_Size;
#endif /* XML_LARGE_SIZE */
#ifdef __cplusplus
}
#endif
#endif /* not Expat_External_INCLUDED */

BIN
expat/libexpat.lib Normal file

Binary file not shown.

499
file.c Normal file
View file

@ -0,0 +1,499 @@
/*
* Sega Model 3 Emulator
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* 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 (license.txt); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* file.c
*
* File access and ZIP file support
*
*/
#include "model3.h"
#include "file.h"
#include "unzip/unzip.h" /* ZLIB */
static unzFile zip_file;
/* zip_get_file_size
*
* Gets the uncompressed size of a file in the ZIP file
* Returns the file size or 0 if the file is not found (or the file size is 0)
*/
static UINT32 zip_get_file_size(const char* file)
{
unz_file_info file_info;
if( unzLocateFile(zip_file, file, 2) != UNZ_OK )
return 0;
if( unzGetCurrentFileInfo(zip_file, &file_info, NULL, 0, NULL, 0, NULL, 0) != UNZ_OK )
return 0;
return file_info.uncompressed_size;
}
/* zip_read_file
*
* Reads the specified file to a buffer
* Returns TRUE if successful otherwise FALSE
*/
static BOOL zip_read_file(const char* file, UINT8* buffer, UINT32 size)
{
if( unzLocateFile(zip_file, file, 2) != UNZ_OK )
return FALSE;
if( unzOpenCurrentFile(zip_file) != UNZ_OK )
return FALSE;
if( unzReadCurrentFile(zip_file, buffer, size) < 0 ) {
unzCloseCurrentFile(zip_file);
return FALSE;
}
unzCloseCurrentFile(zip_file);
return TRUE;
}
/* zip_find_name_for_crc
*
* Finds a matching file name for a crc
* Returns TRUE if crc was found. The file name is copied to the supplied string pointer.
*
*/
static BOOL zip_find_name_for_crc(UINT32 crc, char* file)
{
unz_file_info file_info;
char filename[4096];
if( unzGoToFirstFile(zip_file) != UNZ_OK )
return FALSE;
do
{
if( unzGetCurrentFileInfo(zip_file, &file_info, filename, sizeof(filename), NULL, 0, NULL, 0) != UNZ_OK )
return FALSE;
if( file_info.crc == crc ) {
strcpy( file, filename );
return TRUE;
}
} while( unzGoToNextFile(zip_file) == UNZ_OK );
return FALSE;
}
/* zip_open
*
* Opens a zip file. Must be called before any of the above functions !
*/
static BOOL zip_open(const char* file)
{
zip_file = unzOpen(file);
if( zip_file == NULL )
return FALSE;
return TRUE;
}
/* zip_close
*
* Closes the zip file
*/
static void zip_close(void)
{
unzClose(zip_file);
}
/* File access functions */
static BOOL zip_directory = FALSE;
static char directory_path[4096];
/* TODO: set_directory and set_directory_zip could be merged together */
/* set_directory
*
* Sets the current directory
*
*/
BOOL set_directory(char* path, ...)
{
char string[4096];
va_list l;
va_start(l, path);
vsprintf(string, path, l);
va_end(l);
zip_directory = FALSE;
strcpy( directory_path, string );
return TRUE;
}
/* set_directory_zip
*
* Sets a zip file as current directory
*
*/
BOOL set_directory_zip(char* file, ...)
{
char string[4096];
va_list l;
va_start(l, file);
vsprintf(string, file, l);
va_end(l);
/* Close the old zip file */
zip_close();
if( !zip_open(string) )
return FALSE;
zip_directory = TRUE;
strcpy( directory_path, string );
return TRUE;
}
/* get_file_size
*
* Returns the file size
*
*/
size_t get_file_size(const char* file)
{
FILE* f;
size_t length = 0;
char path[4096];
if( zip_directory ) {
length = zip_get_file_size(file);
}
else {
sprintf( path, "%s/%s", directory_path, file );
f = fopen( path, "rb" );
if( f == NULL )
return 0;
fseek( f, 0, SEEK_END );
length = ftell(f);
fclose(f);
}
return length;
}
/* read_file
*
* Reads the content of the file to a buffer
*
*/
BOOL read_file(const char* file, UINT8* buffer, UINT32 size)
{
FILE* f;
char path[4096];
if( zip_directory ) {
return zip_read_file( file, buffer, size );
}
else {
/* Build a full path to file */
strcpy( path, directory_path );
strcat( path, "/" );
strcat( path, file );
f = fopen( path, "rb" );
if( f == NULL )
return FALSE;
fseek( f, 0, SEEK_SET );
if( fread(buffer, sizeof(UINT8), size, f) != (size_t)size ) {
fclose(f);
return FALSE;
}
fclose(f);
}
return TRUE;
}
/* write_file
*
* Writes the contents of a buffer to a file
*
*/
BOOL write_file(const char* file, UINT8* buffer, UINT32 size)
{
FILE* f;
char path[4096];
/* Whoops. No saving to a zip file :) */
if( zip_directory )
return FALSE;
/* Build a full path to file */
strcpy( path, directory_path );
strcat( path, "/" );
strcat( path, file );
f = fopen( path, "wb" );
fseek( f, 0, SEEK_SET );
if( fwrite(buffer, sizeof(UINT8), size, f) != (size_t)size ) {
fclose(f);
return FALSE;
}
fclose(f);
return TRUE;
}
/* get_file_size_crc
*
* Returns the file size of a file specified by crc
*
*/
size_t get_file_size_crc(UINT32 crc)
{
char file[4096];
/* only zip files supported */
if( !zip_directory )
return 0;
if( !zip_find_name_for_crc(crc, file) )
return 0;
return zip_get_file_size(file);
}
/* read_file_crc
*
* Reads the contents of a file specified by crc
*
*/
BOOL read_file_crc(UINT32 crc, UINT8* buffer, UINT32 size)
{
char file[4096];
/* only zip files supported */
if( !zip_directory )
return FALSE;
if( !zip_find_name_for_crc(crc, file) )
return FALSE;
return zip_read_file(file, buffer, size);
}
/* open_file
*
* Opens a file
*
*/
FILE* open_file(UINT32 flags, char* file, ...)
{
char string[4096];
char path[4096];
char mode[3];
char* m = mode;
va_list l;
/* zip files are not supported this way */
if( zip_directory )
return 0;
va_start(l, file);
vsprintf(string, file, l);
va_end(l);
/* Build full path */
if (strlen(directory_path) <= 0)
{
sprintf(path, "%s", string);
}
else
{
sprintf(path, "%s/%s", directory_path, string);
}
/* Set file access mode */
if( flags & FILE_READ )
sprintf(&m[0], "r");
else
sprintf(&m[0], "w");
if( flags & FILE_BINARY )
sprintf(&m[1], "b" );
else
sprintf(&m[1], "t" );
m[2] = '\0';
return fopen(path, m);
}
/* close_file
*
* Closes the file
*
*/
void close_file(FILE* file)
{
fclose(file);
}
/* read_from_file
*
* Reads n bytes from file to a buffer
*
*/
BOOL read_from_file(FILE* file, UINT8* buffer, UINT32 size)
{
if( file == NULL )
return FALSE;
if( fread(buffer, sizeof(UINT8), size, file) != (size_t)size )
return FALSE;
return TRUE;
}
/* write_to_file
*
* Writes n bytes to file
*
*/
BOOL write_to_file(FILE* file, UINT8* buffer, UINT32 size)
{
if( file == NULL )
return FALSE;
if( fwrite(buffer, sizeof(UINT8), size, file) != (size_t)size )
return FALSE;
return TRUE;
}
/* get_file_size
*
* Gets the file size
*
*/
size_t get_open_file_size(FILE *file)
{
size_t length;
int current_pos = ftell(file);
fseek(file, 0, SEEK_END);
length = ftell(file);
fseek(file, current_pos, SEEK_SET);
return length;
}
/*
* Load a file to a buffer.
*/
int load_file(char *path, UINT8 * dest, int size)
{
FILE * fp;
int length;
if(path == NULL || dest == NULL)
return(-1);
if((fp = fopen(path, "rb")) == NULL)
return(-1);
fseek(fp, 0, SEEK_END);
length = ftell(fp);
fseek(fp, 0, SEEK_SET);
if (length <= 0)
return -1;
if (fread(dest, 1, size, fp) != (size_t)length) // file size mismatch
return -1;
return length;
}
static void word_swap(UINT8 *src, int size)
{
while (size -= 4)
{
*((UINT32 *) src) = BSWAP32(*((UINT32 *) src));
src += sizeof(UINT32);
}
}
/*
* Save a buffer to a file.
*/
void save_file(char *path, UINT8 *src, int size, BOOL byte_reversed)
{
FILE * fp;
if (byte_reversed)
{
word_swap(src, size);
}
fp = fopen(path, "wb");
if(fp != NULL)
{
fwrite(src, 1, size, fp);
fclose(fp);
message(0, "Wrote %s", path);
}
else
{
message(0, "Failed to write %s", path);
}
if (byte_reversed)
{
word_swap(src, size);
}
}

50
file.h Normal file
View file

@ -0,0 +1,50 @@
/*
* Sega Model 3 Emulator
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* 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 (license.txt); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef INCLUDED_FILE_H
#define INCLUDED_FILE_H
#include "model3.h"
#define FILE_READ 0x1
#define FILE_WRITE 0x2
#define FILE_BINARY 0x4
#define FILE_TEXT 0x8
/* Functions */
FILE* open_file(UINT32, char*, ...);
void close_file(FILE*);
BOOL read_from_file(FILE*, UINT8*, UINT32);
BOOL write_to_file(FILE*, UINT8*, UINT32);
size_t get_open_file_size(FILE *);
size_t get_file_size(const char*);
BOOL read_file(const char*, UINT8*, UINT32);
BOOL write_file(const char*, UINT8*, UINT32);
size_t get_file_size_crc(UINT32);
BOOL read_file_crc(UINT32, UINT8*, UINT32);
BOOL set_directory(char*, ...);
BOOL set_directory_zip(char*, ...);
int load_file(char *path, UINT8 * dest, int size);
void save_file(char *path, UINT8 *src, int size, BOOL byte_reversed);
#endif /* INCLUDED_FILE_H */

1655
games.xml Normal file

File diff suppressed because it is too large Load diff

1256
osd_common/disasm.c Normal file

File diff suppressed because it is too large Load diff

31
osd_common/disasm.h Normal file
View file

@ -0,0 +1,31 @@
/*
* Sega Model 3 Emulator
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* 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 (license.txt); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* osd_common/disasm.h
*
* PowerPC disassembler header.
*/
#ifndef INCLUDED_OSD_COMMON_DISASM_H
#define INCLUDED_OSD_COMMON_DISASM_H
extern BOOL DisassemblePowerPC(UINT32, UINT32, CHAR *, CHAR *, BOOL);
#endif // INCLUDED_OSD_COMMON_DISASM_H

1571
osd_common/glrender.c Normal file

File diff suppressed because it is too large Load diff

125
osd_common/osd_common.h Normal file
View file

@ -0,0 +1,125 @@
/*
* Sega Model 3 Emulator
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* 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 (license.txt); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* osd_common/osd_common.h
*
* Header file which defines the OSD interface. This is included last in
* model3.h because it relies on data structures defined there.
*/
#ifndef INCLUDED_OSD_COMMON_OSD_H
#define INCLUDED_OSD_COMMON_OSD_H
/******************************************************************/
/* OSD Includes */
/******************************************************************/
#include "disasm.h" // didn't know where to put it, so I stuck it here ;)
/******************************************************************/
/* OSD Data Structures */
/******************************************************************/
/*
* OSD_CONTROLS Structure
*
* Holds the current state of the controls. Filled by the input code and used
* by the control emulation code.
*/
typedef struct
{
/*
* Common to all games
*/
UINT8 system_controls[2]; // maps directly to Fx040004 banks 0 and 1
UINT8 game_controls[2]; // map directly to Fx040008 and Fx04000C
/*
* For games with guns
*
* The gun positions are reported in screen coordinates. The emulator will
* make the appropriate adjustments. Gun coordinates should range from
* (0,0), the upper-left corner, to (495,383), the lower-right corner.
*/
UINT gun_x[2], gun_y[2]; // gun positions for players 1 (0) and 2 (1)
BOOL gun_acquired[2]; // gun acquired status for players 1 and 2
// 0 = acquired, 1 = lost
// Analog controls
int analog_axis[8];
} OSD_CONTROLS;
/******************************************************************/
/* Executable memory allocation */
/******************************************************************/
extern void *malloc_exec(int length);
extern void free_exec(void *ptr);
/******************************************************************/
/* OSD GUI */
/******************************************************************/
extern void osd_message();
extern void osd_error();
/******************************************************************/
/* Renderer */
/******************************************************************/
extern void osd_renderer_invalidate_textures(UINT x, UINT y, UINT w, UINT h, UINT8 *texture_sheet);
extern void osd_renderer_draw_model(UINT32 *, UINT32, BOOL);
extern void osd_renderer_multiply_matrix(MATRIX);
extern void osd_renderer_translate_matrix(float, float, float);
extern void osd_renderer_push_matrix(void);
extern void osd_renderer_pop_matrix(void);
extern void osd_renderer_set_light(INT, LIGHT *);
extern void osd_renderer_set_viewport(const VIEWPORT *);
extern void osd_renderer_set_coordinate_system(const MATRIX);
extern void osd_renderer_clear(BOOL, BOOL);
extern void osd_renderer_set_color_offset(BOOL, FLOAT32, FLOAT32, FLOAT32);
extern void osd_renderer_draw_layer(int layer, UINT32 color_offset);
extern void osd_renderer_get_layer_buffer(int layer_num, UINT8 **buffer, int *pitch);
extern void osd_renderer_free_layer_buffer(UINT);
extern void osd_renderer_get_palette_buffer(UINT32 **, int *, int *);
extern void osd_renderer_free_palette_buffer(void);
extern void osd_renderer_blit(void);
extern void osd_renderer_begin_3d_scene(void);
extern void osd_renderer_end_3d_scene(void);
extern void osd_renderer_draw_text(int x, int y, const char* string, DWORD color, BOOL shadow);
/******************************************************************/
/* Sound Output */
/******************************************************************/
/******************************************************************/
/* Input */
/******************************************************************/
extern OSD_CONTROLS * osd_input_update_controls(void);
extern BOOL osd_input_init(void);
extern void osd_input_shutdown(void);
#endif // INCLUDED_OSD_COMMON_OSD_H

39
osd_common/osd_gl.h Normal file
View file

@ -0,0 +1,39 @@
/*
* Sega Model 3 Emulator
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* 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 (license.txt); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* osd_common/osd_gl.h
*
* Header file which exposes the OSD OpenGL interface. These are functions
* which the OSD code must call.
*/
#ifndef INCLUDED_OSD_COMMON_OSD_GL_H
#define INCLUDED_OSD_COMMON_OSD_GL_H
/******************************************************************/
/* OSD OpenGL Functions */
/******************************************************************/
extern BOOL osd_gl_check_extension(CHAR *);
extern void * osd_gl_get_proc_address(const CHAR *);
extern void osd_gl_set_mode(UINT, UINT);
extern void osd_gl_unset_mode(void);
#endif // INCLUDED_OSD_COMMON_OSD_GL_H

1083
ppc_drc/genx86.c Normal file

File diff suppressed because it is too large Load diff

167
ppc_drc/genx86.h Normal file
View file

@ -0,0 +1,167 @@
typedef enum
{
JUMP_TYPE_NONE = 0,
JUMP_TYPE_BACKWARDS = 1,
JUMP_TYPE_FORWARD = 2,
} JUMP_TYPE;
typedef struct
{
void *pointer;
JUMP_TYPE jump_type;
} JUMP_TARGET;
enum
{
REG_EAX = 0,
REG_ECX = 1,
REG_EDX = 2,
REG_EBX = 3,
REG_ESP = 4,
REG_EBP = 5,
REG_ESI = 6,
REG_EDI = 7
} X86_REGS;
enum
{
REG_AL = 0,
REG_CL = 1,
REG_DL = 2,
REG_BL = 3,
REG_AH = 4,
REG_CH = 5,
REG_DH = 6,
REG_BH = 7
} X86_REGS8;
enum
{
REG_AX = 0,
REG_CX = 1,
REG_DX = 2,
REG_BX = 3,
REG_SP = 4,
REG_BP = 5,
REG_SI = 6,
REG_DI = 7
} X86_REGS16;
enum
{
REG_XMM0 = 0,
REG_XMM1 = 1,
REG_XMM2 = 2,
REG_XMM3 = 3,
REG_XMM4 = 4,
REG_XMM5 = 5,
REG_XMM6 = 6,
REG_XMM7 = 7,
} X86_REGS_SSE2;
typedef enum
{
ADD,
ADDI,
ADDIM,
ADDMR,
ADC,
ADCI,
ADCMR,
AND,
ANDI,
ANDIM,
ANDMR,
BSR,
BSWAP,
BTIM,
BTRI,
CALL,
CALLI,
CMOVAMR,
CMOVBMR,
CMOVGMR,
CMOVLMR,
CMOVZMR,
CMP,
CMPI,
CMPIM,
CMPMR,
CVTSD2SS,
CVTSS2SD,
IDIV,
IMUL,
JA,
JAE,
JB,
JG,
JL,
JMP,
JMPI,
JMPM,
JMPR,
JNS,
JNZ,
JZ,
MOV,
MOVI,
MOVIM,
MOVMR,
MOVRM,
MOVR8M8,
MOVM8R8,
MOVS_R8R32,
MOVS_R16R32,
MOVZ_M8R32,
MOVZ_R8R32,
MOVZ_R16R32,
MOVDRX,
MOVDXR,
MOVQMX,
MOVQXM,
MUL,
NEG,
NOT,
OR,
ORI,
ORIM,
ORMR,
POP,
POPAD,
PUSH,
PUSHAD,
PUSHI,
RET,
ROLCL,
ROLI,
SETCR8,
SETNCR8,
SETZR8,
SHLCL,
SHLI,
SHRCL,
SHRI,
SUB,
SUBI,
SUBIM,
SUBMR,
TESTI,
XCHGR8R8,
XOR,
XORI,
XORMR,
} GENX86_OPCODE;
void gen(GENX86_OPCODE opcode, INT32 dst_param, INT32 src_param);
void gen_jmp_target(JUMP_TARGET *target);
void gen_jmp(GENX86_OPCODE opcode, JUMP_TARGET *target);
void gen_jmp_rpr(INT32 reg1, INT32 reg2);
void gen_mov_dpr_to_reg(INT32 dst_reg, INT32 disp, INT32 disp_reg);
void gen_mov_dprs_to_reg(INT32 dst_reg, INT32 disp, INT32 disp_reg, INT32 disp_reg_scale);
void gen_mov_reg_to_dpr(INT32 src_reg, INT32 disp, INT32 disp_reg);
void gen_reset_cache(void);
UINT8 *gen_get_cache_pos(void);
UINT32 gen_get_instruction_amount(void);
void init_jmp_target(JUMP_TARGET *target);
void init_genx86(void);
void shutdown_genx86(void);

1544
ppc_drc/ppc_drc.c Normal file

File diff suppressed because it is too large Load diff

0
ppc_drc/ppc_drc.h Normal file
View file

4123
ppc_drc/ppc_drc_ops.c Normal file

File diff suppressed because it is too large Load diff

808
ppc_itp/ppc.c Normal file
View file

@ -0,0 +1,808 @@
/* IBM/Motorola PowerPC 4xx/6xx Emulator */
#include "model3.h"
#include "ppc.h"
void ppc603_exception(int exception);
void ppc603_check_interrupts(void);
#define RD ((op >> 21) & 0x1F)
#define RT ((op >> 21) & 0x1f)
#define RS ((op >> 21) & 0x1f)
#define RA ((op >> 16) & 0x1f)
#define RB ((op >> 11) & 0x1f)
#define RC ((op >> 6) & 0x1f)
#define MB ((op >> 6) & 0x1f)
#define ME ((op >> 1) & 0x1f)
#define SH ((op >> 11) & 0x1f)
#define BO ((op >> 21) & 0x1f)
#define BI ((op >> 16) & 0x1f)
#define CRFD ((op >> 23) & 0x7)
#define CRFA ((op >> 18) & 0x7)
#define FXM ((op >> 12) & 0xff)
#define SPR (((op >> 16) & 0x1f) | ((op >> 6) & 0x3e0))
#define SIMM16 (INT32)(INT16)(op & 0xffff)
#define UIMM16 (UINT32)(op & 0xffff)
#define RCBIT (op & 0x1)
#define OEBIT (op & 0x400)
#define AABIT (op & 0x2)
#define LKBIT (op & 0x1)
#define REG(x) (ppc.r[x])
#define LR (ppc.lr)
#define CTR (ppc.ctr)
#define XER (ppc.xer)
#define CR(x) (ppc.cr[x])
#define MSR (ppc.msr)
#define SRR0 (ppc.srr0)
#define SRR1 (ppc.srr1)
#define SRR2 (ppc.srr2)
#define SRR3 (ppc.srr3)
#define EVPR (ppc.evpr)
#define EXIER (ppc.exier)
#define EXISR (ppc.exisr)
#define DEC (ppc.dec)
// Stuff added for the 6xx
#define FPR(x) (ppc.fpr[x])
#define FM ((op >> 17) & 0xFF)
#define SPRF (((op >> 6) & 0x3E0) | ((op >> 16) & 0x1F))
#define CHECK_SUPERVISOR() \
if((ppc.msr & 0x4000) != 0){ \
}
#define CHECK_FPU_AVAILABLE() \
if((ppc.msr & 0x2000) == 0){ \
}
static UINT32 ppc_field_xlat[256];
#define FPSCR_FX 0x80000000
#define FPSCR_FEX 0x40000000
#define FPSCR_VX 0x20000000
#define FPSCR_OX 0x10000000
#define FPSCR_UX 0x08000000
#define FPSCR_ZX 0x04000000
#define FPSCR_XX 0x02000000
#define BITMASK_0(n) (UINT32)(((UINT64)1 << n) - 1)
#define CRBIT(x) ((ppc.cr[x / 4] & (1 << (3 - (x % 4)))) ? 1 : 0)
#define _BIT(n) (1 << (n))
#define GET_ROTATE_MASK(mb,me) (ppc_rotate_mask[mb][me])
#define ADD_CA(r,a,b) ((UINT32)r < (UINT32)a)
#define SUB_CA(r,a,b) (!((UINT32)a < (UINT32)b))
#define ADD_OV(r,a,b) ((~((a) ^ (b)) & ((a) ^ (r))) & 0x80000000)
#define SUB_OV(r,a,b) (( ((a) ^ (b)) & ((a) ^ (r))) & 0x80000000)
#define XER_SO 0x80000000
#define XER_OV 0x40000000
#define XER_CA 0x20000000
#define MSR_POW 0x00040000 /* Power Management Enable */
#define MSR_WE 0x00040000
#define MSR_CE 0x00020000
#define MSR_ILE 0x00010000 /* Interrupt Little Endian Mode */
#define MSR_EE 0x00008000 /* External Interrupt Enable */
#define MSR_PR 0x00004000 /* Problem State */
#define MSR_FP 0x00002000 /* Floating Point Available */
#define MSR_ME 0x00001000 /* Machine Check Enable */
#define MSR_FE0 0x00000800
#define MSR_SE 0x00000400 /* Single Step Trace Enable */
#define MSR_BE 0x00000200 /* Branch Trace Enable */
#define MSR_DE 0x00000200
#define MSR_FE1 0x00000100
#define MSR_IP 0x00000040 /* Interrupt Prefix */
#define MSR_IR 0x00000020 /* Instruction Relocate */
#define MSR_DR 0x00000010 /* Data Relocate */
#define MSR_PE 0x00000008
#define MSR_PX 0x00000004
#define MSR_RI 0x00000002 /* Recoverable Interrupt Enable */
#define MSR_LE 0x00000001
#define TSR_ENW 0x80000000
#define TSR_WIS 0x40000000
#define BYTE_REVERSE16(x) ((((x) >> 8) & 0xff) | (((x) << 8) & 0xff00))
#define BYTE_REVERSE32(x) ((((x) >> 24) & 0xff) | (((x) >> 8) & 0xff00) | (((x) << 8) & 0xff0000) | (((x) << 24) & 0xff000000))
typedef union {
UINT64 id;
double fd;
} FPR;
typedef union {
UINT32 i;
float f;
} FPR32;
typedef struct {
UINT32 u;
UINT32 l;
} BATENT;
typedef struct {
UINT32 r[32];
UINT32 pc;
UINT32 npc;
UINT32 *op;
UINT32 lr;
UINT32 ctr;
UINT32 xer;
UINT32 msr;
UINT8 cr[8];
UINT32 pvr;
UINT32 srr0;
UINT32 srr1;
UINT32 srr2;
UINT32 srr3;
UINT32 hid0;
UINT32 hid1;
UINT32 hid2;
UINT32 sdr1;
UINT32 sprg[4];
UINT32 dsisr;
UINT32 dar;
UINT32 ear;
UINT32 dmiss;
UINT32 dcmp;
UINT32 hash1;
UINT32 hash2;
UINT32 imiss;
UINT32 icmp;
UINT32 rpa;
BATENT ibat[4];
BATENT dbat[4];
UINT32 evpr;
UINT32 exier;
UINT32 exisr;
UINT32 bear;
UINT32 besr;
UINT32 iocr;
UINT32 br[8];
UINT32 iabr;
UINT32 esr;
UINT32 iccr;
UINT32 dccr;
UINT32 pit;
UINT32 pit_counter;
UINT32 pit_int_enable;
UINT32 tsr;
UINT32 dbsr;
UINT32 sgr;
UINT32 pid;
int reserved;
UINT32 reserved_address;
int interrupt_pending;
int external_int;
UINT64 tb; /* 56-bit timebase register */
int (*irq_callback)(int irqline);
PPC_FETCH_REGION cur_fetch;
PPC_FETCH_REGION * fetch;
// STUFF added for the 6xx series
UINT32 dec, dec_frac;
UINT32 fpscr;
FPR fpr[32];
UINT32 sr[16];
#if HAS_PPC603
int is603;
#endif
#if HAS_PPC602
int is602;
#endif
} PPC_REGS;
typedef struct {
int code;
int subcode;
void (* handler)(UINT32);
} PPC_OPCODE;
static int ppc_icount;
static int ppc_tb_base_icount;
static int ppc_dec_base_icount;
static int ppc_dec_trigger_cycle;
static int bus_freq_multiplier = 1;
static PPC_REGS ppc;
static UINT32 ppc_rotate_mask[32][32];
static void ppc_change_pc(UINT32 newpc)
{
UINT i;
if (ppc.cur_fetch.start <= newpc && newpc <= ppc.cur_fetch.end)
{
ppc.op = (UINT32 *)((UINT32)ppc.cur_fetch.ptr + (UINT32)(newpc - ppc.cur_fetch.start));
return;
}
for(i = 0; ppc.fetch[i].ptr != NULL; i++)
{
if (ppc.fetch[i].start <= newpc && newpc <= ppc.fetch[i].end)
{
ppc.cur_fetch.start = ppc.fetch[i].start;
ppc.cur_fetch.end = ppc.fetch[i].end;
ppc.cur_fetch.ptr = ppc.fetch[i].ptr;
ppc.op = (UINT32 *)((UINT32)ppc.cur_fetch.ptr + (UINT32)(newpc - ppc.cur_fetch.start));
return;
}
}
error("Invalid PC %08X, previous PC %08X\n", newpc, ppc.pc);
}
INLINE UINT8 READ8(UINT32 address)
{
return m3_ppc_read_8(address);
}
INLINE UINT16 READ16(UINT32 address)
{
return m3_ppc_read_16(address);
}
INLINE UINT32 READ32(UINT32 address)
{
return m3_ppc_read_32(address);
}
INLINE UINT64 READ64(UINT32 address)
{
return m3_ppc_read_64(address);
}
INLINE void WRITE8(UINT32 address, UINT8 data)
{
m3_ppc_write_8(address, data);
}
INLINE void WRITE16(UINT32 address, UINT16 data)
{
m3_ppc_write_16(address, data);
}
INLINE void WRITE32(UINT32 address, UINT32 data)
{
m3_ppc_write_32(address, data);
}
INLINE void WRITE64(UINT32 address, UINT64 data)
{
m3_ppc_write_64(address, data);
}
/*********************************************************************/
INLINE void SET_CR0(INT32 rd)
{
if( rd < 0 ) {
CR(0) = 0x8;
} else if( rd > 0 ) {
CR(0) = 0x4;
} else {
CR(0) = 0x2;
}
if( XER & XER_SO )
CR(0) |= 0x1;
}
INLINE void SET_CR1(void)
{
CR(1) = (ppc.fpscr >> 28) & 0xf;
}
INLINE void SET_ADD_OV(UINT32 rd, UINT32 ra, UINT32 rb)
{
if( ADD_OV(rd, ra, rb) )
XER |= XER_SO | XER_OV;
else
XER &= ~XER_OV;
}
INLINE void SET_SUB_OV(UINT32 rd, UINT32 ra, UINT32 rb)
{
if( SUB_OV(rd, ra, rb) )
XER |= XER_SO | XER_OV;
else
XER &= ~XER_OV;
}
INLINE void SET_ADD_CA(UINT32 rd, UINT32 ra, UINT32 rb)
{
if( ADD_CA(rd, ra, rb) )
XER |= XER_CA;
else
XER &= ~XER_CA;
}
INLINE void SET_SUB_CA(UINT32 rd, UINT32 ra, UINT32 rb)
{
if( SUB_CA(rd, ra, rb) )
XER |= XER_CA;
else
XER &= ~XER_CA;
}
INLINE UINT32 check_condition_code(UINT32 bo, UINT32 bi)
{
UINT32 ctr_ok;
UINT32 condition_ok;
UINT32 bo0 = (bo & 0x10) ? 1 : 0;
UINT32 bo1 = (bo & 0x08) ? 1 : 0;
UINT32 bo2 = (bo & 0x04) ? 1 : 0;
UINT32 bo3 = (bo & 0x02) ? 1 : 0;
if( bo2 == 0 )
--CTR;
ctr_ok = bo2 | ((CTR != 0) ^ bo3);
condition_ok = bo0 | (CRBIT(bi) ^ (~bo1 & 0x1));
return ctr_ok && condition_ok;
}
INLINE UINT64 ppc_read_timebase(void)
{
int cycles = ppc_tb_base_icount - ppc_icount;
// timebase is incremented once every four core clock cycles, so adjust the cycles accordingly
return ppc.tb + (cycles / 4);
}
INLINE void ppc_write_timebase_l(UINT32 tbl)
{
ppc_tb_base_icount = ppc_icount;
ppc.tb &= ~0xffffffff;
ppc.tb |= tbl;
}
INLINE void ppc_write_timebase_h(UINT32 tbh)
{
ppc_tb_base_icount = ppc_icount;
ppc.tb &= 0xffffffff;
ppc.tb |= (UINT64)(tbh) << 32;
}
INLINE UINT32 read_decrementer(void)
{
int cycles = ppc_dec_base_icount - ppc_icount;
// decrementer is decremented once every four bus clock cycles, so adjust the cycles accordingly
return DEC - (cycles / (bus_freq_multiplier * 2));
}
INLINE void write_decrementer(UINT32 value)
{
ppc_dec_base_icount = ppc_icount + (ppc_dec_base_icount - ppc_icount) % (bus_freq_multiplier * 2);
DEC = value;
// check if decrementer exception occurs during execution
if ((UINT32)(DEC - (ppc_icount / (bus_freq_multiplier * 2))) > (UINT32)(DEC))
{
ppc_dec_trigger_cycle = ((ppc_icount / (bus_freq_multiplier * 2)) - DEC) * 4;
}
else
{
ppc_dec_trigger_cycle = 0x7fffffff;
}
printf("DEC = %08X at %08X\n", value, ppc.pc);
}
/*********************************************************************/
INLINE void ppc_set_spr(int spr, UINT32 value)
{
switch (spr)
{
case SPR_LR: LR = value; return;
case SPR_CTR: CTR = value; return;
case SPR_XER: XER = value; return;
case SPR_SRR0: ppc.srr0 = value; return;
case SPR_SRR1: ppc.srr1 = value; return;
case SPR_SPRG0: ppc.sprg[0] = value; return;
case SPR_SPRG1: ppc.sprg[1] = value; return;
case SPR_SPRG2: ppc.sprg[2] = value; return;
case SPR_SPRG3: ppc.sprg[3] = value; return;
case SPR_PVR: return;
case SPR603E_DEC:
if(((value & 0x80000000) && !(DEC & 0x80000000)) || value == 0)
{
/* trigger interrupt */
ppc.interrupt_pending |= 0x2;
ppc603_check_interrupts();
}
write_decrementer(value);
return;
case SPR603E_TBL_W:
case SPR603E_TBL_R: // special 603e case
ppc_write_timebase_l(value);
return;
case SPR603E_TBU_R:
case SPR603E_TBU_W: // special 603e case
ppc_write_timebase_h(value);
return;
case SPR603E_HID0: ppc.hid0 = value; return;
case SPR603E_HID1: ppc.hid1 = value; return;
case SPR603E_HID2: ppc.hid2 = value; return;
case SPR603E_DSISR: ppc.dsisr = value; return;
case SPR603E_DAR: ppc.dar = value; return;
case SPR603E_EAR: ppc.ear = value; return;
case SPR603E_DMISS: ppc.dmiss = value; return;
case SPR603E_DCMP: ppc.dcmp = value; return;
case SPR603E_HASH1: ppc.hash1 = value; return;
case SPR603E_HASH2: ppc.hash2 = value; return;
case SPR603E_IMISS: ppc.imiss = value; return;
case SPR603E_ICMP: ppc.icmp = value; return;
case SPR603E_RPA: ppc.rpa = value; return;
case SPR603E_IBAT0L: ppc.ibat[0].l = value; return;
case SPR603E_IBAT0U: ppc.ibat[0].u = value; return;
case SPR603E_IBAT1L: ppc.ibat[1].l = value; return;
case SPR603E_IBAT1U: ppc.ibat[1].u = value; return;
case SPR603E_IBAT2L: ppc.ibat[2].l = value; return;
case SPR603E_IBAT2U: ppc.ibat[2].u = value; return;
case SPR603E_IBAT3L: ppc.ibat[3].l = value; return;
case SPR603E_IBAT3U: ppc.ibat[3].u = value; return;
case SPR603E_DBAT0L: ppc.dbat[0].l = value; return;
case SPR603E_DBAT0U: ppc.dbat[0].u = value; return;
case SPR603E_DBAT1L: ppc.dbat[1].l = value; return;
case SPR603E_DBAT1U: ppc.dbat[1].u = value; return;
case SPR603E_DBAT2L: ppc.dbat[2].l = value; return;
case SPR603E_DBAT2U: ppc.dbat[2].u = value; return;
case SPR603E_DBAT3L: ppc.dbat[3].l = value; return;
case SPR603E_DBAT3U: ppc.dbat[3].u = value; return;
case SPR603E_SDR1:
ppc.sdr1 = value;
return;
case SPR603E_IABR: ppc.iabr = value; return;
}
error("ppc: set_spr: unknown spr %d (%03X) !", spr, spr);
}
INLINE UINT32 ppc_get_spr(int spr)
{
switch(spr)
{
case SPR_LR: return LR;
case SPR_CTR: return CTR;
case SPR_XER: return XER;
case SPR_SRR0: return ppc.srr0;
case SPR_SRR1: return ppc.srr1;
case SPR_SPRG0: return ppc.sprg[0];
case SPR_SPRG1: return ppc.sprg[1];
case SPR_SPRG2: return ppc.sprg[2];
case SPR_SPRG3: return ppc.sprg[3];
case SPR_PVR: return ppc.pvr;
case SPR603E_TBL_R:
error("ppc: get_spr: TBL_R ");
break;
case SPR603E_TBU_R:
error("ppc: get_spr: TBU_R ");
break;
case SPR603E_TBL_W: return (UINT32)(ppc_read_timebase());
case SPR603E_TBU_W: return (UINT32)(ppc_read_timebase() >> 32);
case SPR603E_HID0: return ppc.hid0;
case SPR603E_HID1: return ppc.hid1;
case SPR603E_HID2: return ppc.hid2;
case SPR603E_DEC: return read_decrementer();
case SPR603E_SDR1: return ppc.sdr1;
case SPR603E_DSISR: return ppc.dsisr;
case SPR603E_DAR: return ppc.dar;
case SPR603E_EAR: return ppc.ear;
case SPR603E_DMISS: return ppc.dmiss;
case SPR603E_DCMP: return ppc.dcmp;
case SPR603E_HASH1: return ppc.hash1;
case SPR603E_HASH2: return ppc.hash2;
case SPR603E_IMISS: return ppc.imiss;
case SPR603E_ICMP: return ppc.icmp;
case SPR603E_RPA: return ppc.rpa;
case SPR603E_IBAT0L: return ppc.ibat[0].l;
case SPR603E_IBAT0U: return ppc.ibat[0].u;
case SPR603E_IBAT1L: return ppc.ibat[1].l;
case SPR603E_IBAT1U: return ppc.ibat[1].u;
case SPR603E_IBAT2L: return ppc.ibat[2].l;
case SPR603E_IBAT2U: return ppc.ibat[2].u;
case SPR603E_IBAT3L: return ppc.ibat[3].l;
case SPR603E_IBAT3U: return ppc.ibat[3].u;
case SPR603E_DBAT0L: return ppc.dbat[0].l;
case SPR603E_DBAT0U: return ppc.dbat[0].u;
case SPR603E_DBAT1L: return ppc.dbat[1].l;
case SPR603E_DBAT1U: return ppc.dbat[1].u;
case SPR603E_DBAT2L: return ppc.dbat[2].l;
case SPR603E_DBAT2U: return ppc.dbat[2].u;
case SPR603E_DBAT3L: return ppc.dbat[3].l;
case SPR603E_DBAT3U: return ppc.dbat[3].u;
}
error("ppc: get_spr: unknown spr %d (%03X) !", spr, spr);
return 0;
}
INLINE void ppc_set_msr(UINT32 value)
{
if( value & (MSR_ILE | MSR_LE) )
error("ppc: set_msr: little_endian mode not supported !");
MSR = value;
ppc603_check_interrupts();
}
INLINE UINT32 ppc_get_msr(void)
{
return MSR;
}
INLINE void ppc_set_cr(UINT32 value)
{
CR(0) = (value >> 28) & 0xf;
CR(1) = (value >> 24) & 0xf;
CR(2) = (value >> 20) & 0xf;
CR(3) = (value >> 16) & 0xf;
CR(4) = (value >> 12) & 0xf;
CR(5) = (value >> 8) & 0xf;
CR(6) = (value >> 4) & 0xf;
CR(7) = (value >> 0) & 0xf;
}
INLINE UINT32 ppc_get_cr(void)
{
return CR(0) << 28 | CR(1) << 24 | CR(2) << 20 | CR(3) << 16 | CR(4) << 12 | CR(5) << 8 | CR(6) << 4 | CR(7);
}
/***********************************************************************/
static void (* optable19[1024])(UINT32);
static void (* optable31[1024])(UINT32);
static void (* optable59[1024])(UINT32);
static void (* optable63[1024])(UINT32);
static void (* optable[64])(UINT32);
#include "ppc603.c"
/********************************************************************/
#include "ppc_ops.c"
#include "ppc_ops.h"
/* Initialization and shutdown */
void ppc_base_init(void)
{
int i,j;
memset(&ppc, 0, sizeof(ppc));
for( i=0; i < 64; i++ ) {
optable[i] = ppc_invalid;
}
for( i=0; i < 1024; i++ ) {
optable19[i] = ppc_invalid;
optable31[i] = ppc_invalid;
optable59[i] = ppc_invalid;
optable63[i] = ppc_invalid;
}
/* Fill the opcode tables */
for( i=0; i < (sizeof(ppc_opcode_common) / sizeof(PPC_OPCODE)); i++ ) {
switch(ppc_opcode_common[i].code)
{
case 19:
optable19[ppc_opcode_common[i].subcode] = ppc_opcode_common[i].handler;
break;
case 31:
optable31[ppc_opcode_common[i].subcode] = ppc_opcode_common[i].handler;
break;
case 59:
case 63:
break;
default:
optable[ppc_opcode_common[i].code] = ppc_opcode_common[i].handler;
}
}
/* Calculate rotate mask table */
for( i=0; i < 32; i++ ) {
for( j=0; j < 32; j++ ) {
UINT32 mask;
int mb = i;
int me = j;
mask = ((UINT32)0xFFFFFFFF >> mb) ^ ((me >= 31) ? 0 : ((UINT32)0xFFFFFFFF >> (me + 1)));
if( mb > me )
mask = ~mask;
ppc_rotate_mask[i][j] = mask;
}
}
}
void ppc_init(const PPC_CONFIG *config)
{
int pll_config = 0;
float multiplier;
int i ;
ppc_base_init() ;
optable[48] = ppc_lfs;
optable[49] = ppc_lfsu;
optable[50] = ppc_lfd;
optable[51] = ppc_lfdu;
optable[52] = ppc_stfs;
optable[53] = ppc_stfsu;
optable[54] = ppc_stfd;
optable[55] = ppc_stfdu;
optable31[631] = ppc_lfdux;
optable31[599] = ppc_lfdx;
optable31[567] = ppc_lfsux;
optable31[535] = ppc_lfsx;
optable31[595] = ppc_mfsr;
optable31[659] = ppc_mfsrin;
optable31[371] = ppc_mftb;
optable31[210] = ppc_mtsr;
optable31[242] = ppc_mtsrin;
optable31[758] = ppc_dcba;
optable31[759] = ppc_stfdux;
optable31[727] = ppc_stfdx;
optable31[983] = ppc_stfiwx;
optable31[695] = ppc_stfsux;
optable31[663] = ppc_stfsx;
optable31[370] = ppc_tlbia;
optable31[306] = ppc_tlbie;
optable31[566] = ppc_tlbsync;
optable31[310] = ppc_eciwx;
optable31[438] = ppc_ecowx;
optable63[264] = ppc_fabsx;
optable63[21] = ppc_faddx;
optable63[32] = ppc_fcmpo;
optable63[0] = ppc_fcmpu;
optable63[14] = ppc_fctiwx;
optable63[15] = ppc_fctiwzx;
optable63[18] = ppc_fdivx;
optable63[72] = ppc_fmrx;
optable63[136] = ppc_fnabsx;
optable63[40] = ppc_fnegx;
optable63[12] = ppc_frspx;
optable63[26] = ppc_frsqrtex;
optable63[22] = ppc_fsqrtx;
optable63[20] = ppc_fsubx;
optable63[583] = ppc_mffsx;
optable63[70] = ppc_mtfsb0x;
optable63[38] = ppc_mtfsb1x;
optable63[711] = ppc_mtfsfx;
optable63[134] = ppc_mtfsfix;
optable63[64] = ppc_mcrfs;
optable59[21] = ppc_faddsx;
optable59[18] = ppc_fdivsx;
optable59[24] = ppc_fresx;
optable59[22] = ppc_fsqrtsx;
optable59[20] = ppc_fsubsx;
for(i = 0; i < 32; i++)
{
optable63[i * 32 | 29] = ppc_fmaddx;
optable63[i * 32 | 28] = ppc_fmsubx;
optable63[i * 32 | 25] = ppc_fmulx;
optable63[i * 32 | 31] = ppc_fnmaddx;
optable63[i * 32 | 30] = ppc_fnmsubx;
optable63[i * 32 | 23] = ppc_fselx;
optable59[i * 32 | 29] = ppc_fmaddsx;
optable59[i * 32 | 28] = ppc_fmsubsx;
optable59[i * 32 | 25] = ppc_fmulsx;
optable59[i * 32 | 31] = ppc_fnmaddsx;
optable59[i * 32 | 30] = ppc_fnmsubsx;
}
for(i = 0; i < 256; i++)
{
ppc_field_xlat[i] =
((i & 0x80) ? 0xF0000000 : 0) |
((i & 0x40) ? 0x0F000000 : 0) |
((i & 0x20) ? 0x00F00000 : 0) |
((i & 0x10) ? 0x000F0000 : 0) |
((i & 0x08) ? 0x0000F000 : 0) |
((i & 0x04) ? 0x00000F00 : 0) |
((i & 0x02) ? 0x000000F0 : 0) |
((i & 0x01) ? 0x0000000F : 0);
}
ppc.pvr = config->pvr;
multiplier = (float)((config->bus_frequency_multiplier >> 4) & 0xf) +
(float)(config->bus_frequency_multiplier & 0xf) / 10.0f;
bus_freq_multiplier = (int)(multiplier * 2);
switch(config->pvr)
{
case PPC_MODEL_603E: pll_config = mpc603e_pll_config[bus_freq_multiplier-1][config->bus_frequency]; break;
case PPC_MODEL_603EV: pll_config = mpc603ev_pll_config[bus_freq_multiplier-1][config->bus_frequency]; break;
case PPC_MODEL_603R: pll_config = mpc603r_pll_config[bus_freq_multiplier-1][config->bus_frequency]; break;
default: break;
}
if (pll_config == -1)
{
error("PPC: Invalid bus/multiplier combination (bus frequency = %d, multiplier = %1.1f)", config->bus_frequency, multiplier);
}
ppc.hid1 = pll_config << 28;
}
void ppc_shutdown(void)
{
}
void ppc_set_irq_line(int irqline)
{
ppc.interrupt_pending |= 0x1;
ppc603_check_interrupts();
}
UINT32 ppc_get_pc(void)
{
return ppc.pc;
}
void ppc_set_fetch(PPC_FETCH_REGION * fetch)
{
ppc.fetch = fetch;
}

314
ppc_itp/ppc.h Normal file
View file

@ -0,0 +1,314 @@
#ifndef _PPC_H
#define _PPC_H
#define SPR_XER 1 /* Fixed Point Exception Register Read / Write */
#define SPR_LR 8 /* Link Register Read / Write */
#define SPR_CTR 9 /* Count Register Read / Write */
#define SPR_SRR0 26 /* Save/Restore Register 0 Read / Write */
#define SPR_SRR1 27 /* Save/Restore Register 1 Read / Write */
#define SPR_SPRG0 272 /* SPR General 0 Read / Write */
#define SPR_SPRG1 273 /* SPR General 1 Read / Write */
#define SPR_SPRG2 274 /* SPR General 2 Read / Write */
#define SPR_SPRG3 275 /* SPR General 3 Read / Write */
#define SPR_PVR 287 /* Processor Version Number Read Only */
#define SPR403_ICDBDR 0x3D3 /* 406GA Instruction Cache Debug Data Register Rad Only */
#define SPR403_ESR 0x3D4 /* 406GA Exception Syndrome Register Read / Write */
#define SPR403_DEAR 0x3D5 /* 406GA Data Exception Address Register Read Only */
#define SPR403_EVPR 0x3D6 /* 406GA Exception Vector Prefix Register Read / Write */
#define SPR403_CDBCR 0x3D7 /* 406GA Cache Debug Control Register Read/Write */
#define SPR403_TSR 0x3D8 /* 406GA Timer Status Register Read / Clear */
#define SPR403_TCR 0x3DA /* 406GA Timer Control Register Read / Write */
#define SPR403_PIT 0x3DB /* 406GA Programmable Interval Timer Read / Write */
#define SPR403_TBHI 988 /* 406GA Time Base High Read / Write */
#define SPR403_TBLO 989 /* 406GA Time Base Low Read / Write */
#define SPR403_SRR2 0x3DE /* 406GA Save/Restore Register 2 Read / Write */
#define SPR403_SRR3 0x3DF /* 406GA Save/Restore Register 3 Read / Write */
#define SPR403_DBSR 0x3F0 /* 406GA Debug Status Register Read / Clear */
#define SPR403_DBCR 0x3F2 /* 406GA Debug Control Register Read / Write */
#define SPR403_IAC1 0x3F4 /* 406GA Instruction Address Compare 1 Read / Write */
#define SPR403_IAC2 0x3F5 /* 406GA Instruction Address Compare 2 Read / Write */
#define SPR403_DAC1 0x3F6 /* 406GA Data Address Compare 1 Read / Write */
#define SPR403_DAC2 0x3F7 /* 406GA Data Address Compare 2 Read / Write */
#define SPR403_DCCR 0x3FA /* 406GA Data Cache Cacheability Register Read / Write */
#define SPR403_ICCR 0x3FB /* 406GA I Cache Cacheability Registe Read / Write */
#define SPR403_PBL1 0x3FC /* 406GA Protection Bound Lower 1 Read / Write */
#define SPR403_PBU1 0x3FD /* 406GA Protection Bound Upper 1 Read / Write */
#define SPR403_PBL2 0x3FE /* 406GA Protection Bound Lower 2 Read / Write */
#define SPR403_PBU2 0x3FF /* 406GA Protection Bound Upper 2 Read / Write */
#define SPR403_SGR 0x3b9 /* 403GCX Storage Guarded Register */
#define SPR403_DCWR 0x3ba /* 403GCX Data Cache Write Through */
#define SPR403_PID 0x3b1 /* 403GCX Process ID */
#define SPR403_TBHU 0x3cc /* 403GCX Time Base High User-mode */
#define SPR403_TBLU 0x3cd /* 403GCX Time Base Low User-mode */
#define SPR603E_DSISR 18 /* 603E */
#define SPR603E_DAR 19 /* 603E */
#define SPR603E_DEC 22 /* 603E */
#define SPR603E_SDR1 25 /* 603E */
#define SPR603E_TBL_R 268 /* 603E Time Base Low (Read-only) */
#define SPR603E_TBU_R 269 /* 603E Time Base High (Read-only) */
#define SPR603E_TBL_W 284 /* 603E Time Base Low (Write-only) */
#define SPR603E_TBU_W 285 /* 603E Time Base Hight (Write-only) */
#define SPR603E_EAR 282 /* 603E */
#define SPR603E_IBAT0U 528 /* 603E */
#define SPR603E_IBAT0L 529 /* 603E */
#define SPR603E_IBAT1U 530 /* 603E */
#define SPR603E_IBAT1L 531 /* 603E */
#define SPR603E_IBAT2U 532 /* 603E */
#define SPR603E_IBAT2L 533 /* 603E */
#define SPR603E_IBAT3U 534 /* 603E */
#define SPR603E_IBAT3L 535 /* 603E */
#define SPR603E_DBAT0U 536 /* 603E */
#define SPR603E_DBAT0L 537 /* 603E */
#define SPR603E_DBAT1U 538 /* 603E */
#define SPR603E_DBAT1L 539 /* 603E */
#define SPR603E_DBAT2U 540 /* 603E */
#define SPR603E_DBAT2L 541 /* 603E */
#define SPR603E_DBAT3U 542 /* 603E */
#define SPR603E_DBAT3L 543 /* 603E */
#define SPR603E_DABR 1013 /* 603E */
#define SPR603E_DMISS 0x3d0 /* 603E */
#define SPR603E_DCMP 0x3d1 /* 603E */
#define SPR603E_HASH1 0x3d2 /* 603E */
#define SPR603E_HASH2 0x3d3 /* 603E */
#define SPR603E_IMISS 0x3d4 /* 603E */
#define SPR603E_ICMP 0x3d5 /* 603E */
#define SPR603E_RPA 0x3d6 /* 603E */
#define SPR603E_HID0 1008 /* 603E */
#define SPR603E_HID1 1009 /* 603E */
#define SPR603E_IABR 1010 /* 603E */
#define SPR603E_HID2 1011 /* 603E */
#define SPR602_TCR 984 /* 602 */
#define SPR602_IBR 986 /* 602 */
#define SPR602_SP 1021 /* 602 */
#define SPR602_LT 1022 /* 602 */
#define DCR_BEAR 0x90 /* bus error address */
#define DCR_BESR 0x91 /* bus error syndrome */
#define DCR_BR0 0x80 /* bank */
#define DCR_BR1 0x81 /* bank */
#define DCR_BR2 0x82 /* bank */
#define DCR_BR3 0x83 /* bank */
#define DCR_BR4 0x84 /* bank */
#define DCR_BR5 0x85 /* bank */
#define DCR_BR6 0x86 /* bank */
#define DCR_BR7 0x87 /* bank */
#define DCR_DMACC0 0xc4 /* dma chained count */
#define DCR_DMACC1 0xcc /* dma chained count */
#define DCR_DMACC2 0xd4 /* dma chained count */
#define DCR_DMACC3 0xdc /* dma chained count */
#define DCR_DMACR0 0xc0 /* dma channel control */
#define DCR_DMACR1 0xc8 /* dma channel control */
#define DCR_DMACR2 0xd0 /* dma channel control */
#define DCR_DMACR3 0xd8 /* dma channel control */
#define DCR_DMACT0 0xc1 /* dma destination address */
#define DCR_DMACT1 0xc9 /* dma destination address */
#define DCR_DMACT2 0xd1 /* dma destination address */
#define DCR_DMACT3 0xd9 /* dma destination address */
#define DCR_DMADA0 0xc2 /* dma destination address */
#define DCR_DMADA1 0xca /* dma destination address */
#define DCR_DMADA2 0xd2 /* dma source address */
#define DCR_DMADA3 0xda /* dma source address */
#define DCR_DMASA0 0xc3 /* dma source address */
#define DCR_DMASA1 0xcb /* dma source address */
#define DCR_DMASA2 0xd3 /* dma source address */
#define DCR_DMASA3 0xdb /* dma source address */
#define DCR_DMASR 0xe0 /* dma status */
#define DCR_EXIER 0x42 /* external interrupt enable */
#define DCR_EXISR 0x40 /* external interrupt status */
#define DCR_IOCR 0xa0 /* io configuration */
enum {
EXCEPTION_IRQ = 1,
EXCEPTION_DECREMENTER = 2,
EXCEPTION_TRAP = 3,
EXCEPTION_SYSTEM_CALL = 4,
EXCEPTION_SMI = 5,
EXCEPTION_DSI = 6,
EXCEPTION_ISI = 7,
EXCEPTION_PROGRAMMABLE_INTERVAL_TIMER = 20,
EXCEPTION_FIXED_INTERVAL_TIMER = 21,
EXCEPTION_WATCHDOG_TIMER = 22,
EXCEPTION_CRITICAL_INTERRUPT = 23,
};
enum {
PPC_INPUT_LINE_SMI = 10,
PPC_INPUT_LINE_TLBISYNC
};
enum {
PPC_PC=1,
PPC_MSR,
PPC_CR,
PPC_LR,
PPC_CTR,
PPC_XER,
PPC_DEC,
PPC_SRR0,
PPC_SRR1,
PPC_R0,
PPC_R1,
PPC_R2,
PPC_R3,
PPC_R4,
PPC_R5,
PPC_R6,
PPC_R7,
PPC_R8,
PPC_R9,
PPC_R10,
PPC_R11,
PPC_R12,
PPC_R13,
PPC_R14,
PPC_R15,
PPC_R16,
PPC_R17,
PPC_R18,
PPC_R19,
PPC_R20,
PPC_R21,
PPC_R22,
PPC_R23,
PPC_R24,
PPC_R25,
PPC_R26,
PPC_R27,
PPC_R28,
PPC_R29,
PPC_R30,
PPC_R31
};
typedef enum {
PPC_MODEL_403GA = 0x00200000,
PPC_MODEL_403GB = 0x00200100,
PPC_MODEL_403GC = 0x00200200,
PPC_MODEL_403GCX = 0x00201400,
PPC_MODEL_405GP = 0x40110000,
PPC_MODEL_601 = 0x00010000,
PPC_MODEL_603 = 0x00030000, /* "Wart" */
PPC_MODEL_604 = 0x00040000, /* "Zephyr" */
PPC_MODEL_602 = 0x00050000, /* "Galahad" */
PPC_MODEL_603E = 0x00060103, /* "Stretch", version 1.3 */
PPC_MODEL_603EV = 0x00070000, /* "Valiant" */
PPC_MODEL_603R = 0x00071202, /* "Goldeneye", version 2.1 */
PPC_MODEL_740 = 0x00080301, /* "Arthur", version 3.1 */
PPC_MODEL_750 = PPC_MODEL_740,
PPC_MODEL_740P = 0x00080202, /* "Conan Doyle", version 1.2 */
PPC_MODEL_750P = PPC_MODEL_740P,
PPC_MODEL_755 = 0x00083203 /* "Goldfinger", version 2.3 */
} PPC_MODEL;
typedef enum {
BUS_FREQUENCY_16MHZ = 0,
BUS_FREQUENCY_20MHZ,
BUS_FREQUENCY_25MHZ,
BUS_FREQUENCY_33MHZ,
BUS_FREQUENCY_40MHZ,
BUS_FREQUENCY_50MHZ,
BUS_FREQUENCY_60MHZ,
BUS_FREQUENCY_66MHZ,
BUS_FREQUENCY_75MHZ,
} PPC_BUS_FREQUENCY;
// PLL Configuration based on the table in MPC603EUM page 7-31
static const int mpc603e_pll_config[12][9] =
{
// 16, 20, 25, 33, 40, 50, 60, 66, 75
{ -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, -1, 0x0, -1 },
{ -1, -1, -1, -1, -1, 0xc, -1, 0xc, -1 },
{ 0x5, 0x5, 0x5, 0x4, 0x4, 0x4, -1, -1, -1 },
{ -1, -1, -1, 0x6, 0x6, -1, -1, -1, -1 },
{ -1, -1, 0x8, 0x8, -1, -1, -1, -1, -1 },
{ -1, 0xe, 0xe, -1, -1, -1, -1, -1, -1 },
{ 0xa, 0xa, 0xa, -1, -1, -1, -1, -1, -1 },
{ -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ -1, -1, -1, -1, -1, -1, -1, -1, -1 },
};
// PLL Configuration based on the table in MPC603E7VEC page 29
static const int mpc603ev_pll_config[12][9] =
{
// 16, 20, 25, 33, 40, 50, 60, 66, 75
{ -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ -1, -1, -1, -1, -1, -1, -1, -1, -1 },
// 2:1
{ -1, -1, -1, -1, -1, -1, -1, 0x4, 0x4 },
// 2.5:1
{ -1, -1, -1, -1, -1, 0x6, 0x6, 0x6, 0x6 },
// 3:1
{ -1, -1, -1, -1, 0x8, 0x8, 0x8, 0x8, 0x8 },
// 3.5:1
{ -1, -1, -1, -1, 0xe, 0xe, 0xe, 0xe, -1 },
// 4:1
{ -1, -1, -1, 0xa, 0xa, 0xa, 0xa, -1, -1 },
// 4.5:1
{ -1, -1, -1, 0x7, 0x7, 0x7, -1, -1, -1 },
// 5:1
{ -1, -1, 0xb, 0xb, 0xb, -1, -1, -1, -1 },
// 5.5:1
{ -1, -1, 0x9, 0x9, 0x9, -1, -1, -1, -1 },
// 6:1
{ -1, -1, 0xd, 0xd, 0xd, -1, -1, -1, -1 }
};
// PLL Configuration based on the table in MPC603E7TEC page 23
static const int mpc603r_pll_config[12][9] =
{
// 16, 20, 25, 33, 40, 50, 60, 66, 75
{ -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ -1, -1, -1, -1, -1, -1, -1, -1, -1 },
// 2:1
{ -1, -1, -1, -1, 0x5, 0x5, 0x5, 0x5, 0x5 },
// 2.5:1
{ -1, -1, -1, -1, -1, -1, 0x6, 0x6, 0x6 },
// 3:1
{ -1, -1, -1, -1, -1, 0x8, 0x8, 0x8, 0x8 },
// 3.5:1
{ -1, -1, -1, -1, -1, 0xe, 0xe, 0xe, 0xe },
// 4:1
{ -1, -1, -1, -1, 0xa, 0xa, 0xa, 0xa, 0xa },
// 4.5:1
{ -1, -1, -1, 0x7, 0x7, 0x7, 0x7, 0x7, -1 },
// 5:1
{ -1, -1, -1, 0xb, 0xb, 0xb, 0xb, -1, -1 },
// 5.5:1
{ -1, -1, -1, 0x9, 0x9, 0x9, -1, -1, -1 },
// 6:1
{ -1, -1, 0xd, 0xd, 0xd, 0xd, -1, -1, -1 },
};
typedef struct {
PPC_MODEL pvr;
int bus_frequency_multiplier;
PPC_BUS_FREQUENCY bus_frequency;
} PPC_CONFIG;
typedef struct
{
UINT32 start;
UINT32 end;
UINT32 * ptr;
} PPC_FETCH_REGION;
UINT32 ppc_get_pc(void);
void ppc_set_irq_line(int irqline);
int ppc_execute(int cycles);
void ppc_reset(void);
void ppc_shutdown(void);
void ppc_init(const PPC_CONFIG *config);
void ppc_set_fetch(PPC_FETCH_REGION * fetch);
#endif /* _PPC_H */

294
ppc_itp/ppc603.c Normal file
View file

@ -0,0 +1,294 @@
void ppc603_exception(int exception)
{
switch( exception )
{
case EXCEPTION_IRQ: /* External Interrupt */
if( ppc_get_msr() & MSR_EE ) {
UINT32 msr = ppc_get_msr();
SRR0 = ppc.npc;
SRR1 = msr & 0xff73;
msr &= ~(MSR_POW | MSR_EE | MSR_PR | MSR_FP | MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI);
if( msr & MSR_ILE )
msr |= MSR_LE;
else
msr &= ~MSR_LE;
ppc_set_msr(msr);
if( msr & MSR_IP )
ppc.npc = 0xfff00000 | 0x0500;
else
ppc.npc = 0x00000000 | 0x0500;
ppc.interrupt_pending &= ~0x1;
ppc_change_pc(ppc.npc);
}
break;
case EXCEPTION_DECREMENTER: /* Decrementer overflow exception */
if( ppc_get_msr() & MSR_EE ) {
UINT32 msr = ppc_get_msr();
SRR0 = ppc.npc;
SRR1 = msr & 0xff73;
msr &= ~(MSR_POW | MSR_EE | MSR_PR | MSR_FP | MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI);
if( msr & MSR_ILE )
msr |= MSR_LE;
else
msr &= ~MSR_LE;
ppc_set_msr(msr);
if( msr & MSR_IP )
ppc.npc = 0xfff00000 | 0x0900;
else
ppc.npc = 0x00000000 | 0x0900;
ppc.interrupt_pending &= ~0x2;
ppc_change_pc(ppc.npc);
}
break;
case EXCEPTION_TRAP: /* Program exception / Trap */
{
UINT32 msr = ppc_get_msr();
SRR0 = ppc.pc;
SRR1 = (msr & 0xff73) | 0x20000; /* 0x20000 = TRAP bit */
msr &= ~(MSR_POW | MSR_EE | MSR_PR | MSR_FP | MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI);
if( msr & MSR_ILE )
msr |= MSR_LE;
else
msr &= ~MSR_LE;
ppc_set_msr(msr);
if( msr & MSR_IP )
ppc.npc = 0xfff00000 | 0x0700;
else
ppc.npc = 0x00000000 | 0x0700;
ppc_change_pc(ppc.npc);
}
break;
case EXCEPTION_SYSTEM_CALL: /* System call */
{
UINT32 msr = ppc_get_msr();
SRR0 = ppc.npc;
SRR1 = (msr & 0xff73);
msr &= ~(MSR_POW | MSR_EE | MSR_PR | MSR_FP | MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI);
if( msr & MSR_ILE )
msr |= MSR_LE;
else
msr &= ~MSR_LE;
ppc_set_msr(msr);
if( msr & MSR_IP )
ppc.npc = 0xfff00000 | 0x0c00;
else
ppc.npc = 0x00000000 | 0x0c00;
ppc_change_pc(ppc.npc);
}
break;
case EXCEPTION_SMI:
if( ppc_get_msr() & MSR_EE ) {
UINT32 msr = ppc_get_msr();
SRR0 = ppc.npc;
SRR1 = msr & 0xff73;
msr &= ~(MSR_POW | MSR_EE | MSR_PR | MSR_FP | MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI);
if( msr & MSR_ILE )
msr |= MSR_LE;
else
msr &= ~MSR_LE;
ppc_set_msr(msr);
if( msr & MSR_IP )
ppc.npc = 0xfff00000 | 0x1400;
else
ppc.npc = 0x00000000 | 0x1400;
ppc.interrupt_pending &= ~0x4;
ppc_change_pc(ppc.npc);
}
break;
case EXCEPTION_DSI:
{
UINT32 msr = ppc_get_msr();
SRR0 = ppc.npc;
SRR1 = msr & 0xff73;
msr &= ~(MSR_POW | MSR_EE | MSR_PR | MSR_FP | MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI);
if( msr & MSR_ILE )
msr |= MSR_LE;
else
msr &= ~MSR_LE;
ppc_set_msr(msr);
if( msr & MSR_IP )
ppc.npc = 0xfff00000 | 0x0300;
else
ppc.npc = 0x00000000 | 0x0300;
ppc.interrupt_pending &= ~0x4;
ppc_change_pc(ppc.npc);
}
break;
case EXCEPTION_ISI:
{
UINT32 msr = ppc_get_msr();
SRR0 = ppc.npc;
SRR1 = msr & 0xff73;
msr &= ~(MSR_POW | MSR_EE | MSR_PR | MSR_FP | MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI);
if( msr & MSR_ILE )
msr |= MSR_LE;
else
msr &= ~MSR_LE;
ppc_set_msr(msr);
if( msr & MSR_IP )
ppc.npc = 0xfff00000 | 0x0400;
else
ppc.npc = 0x00000000 | 0x0400;
ppc.interrupt_pending &= ~0x4;
ppc_change_pc(ppc.npc);
}
break;
default:
error("ppc: Unhandled exception %d", exception);
break;
}
}
static void ppc603_set_smi_line(int state)
{
if( state ) {
ppc.interrupt_pending |= 0x4;
}
}
static void ppc603_check_interrupts(void)
{
if (MSR & MSR_EE)
{
if (ppc.interrupt_pending != 0)
{
if (ppc.interrupt_pending & 0x1)
{
ppc603_exception(EXCEPTION_IRQ);
}
else if (ppc.interrupt_pending & 0x2)
{
ppc603_exception(EXCEPTION_DECREMENTER);
}
else if (ppc.interrupt_pending & 0x4)
{
ppc603_exception(EXCEPTION_SMI);
}
}
}
}
void ppc_reset(void)
{
ppc.pc = ppc.npc = 0xfff00100;
ppc_set_msr(0x40);
ppc_change_pc(ppc.pc);
ppc.hid0 = 1;
ppc.interrupt_pending = 0;
}
int ppc_execute(int cycles)
{
UINT32 opcode;
ppc_icount = cycles;
ppc_tb_base_icount = cycles;
ppc_dec_base_icount = cycles + ppc.dec_frac;
// check if decrementer exception occurs during execution
if ((UINT32)(DEC - (cycles / (bus_freq_multiplier * 2))) > (UINT32)(DEC))
{
ppc_dec_trigger_cycle = ((cycles / (bus_freq_multiplier * 2)) - DEC) * 4;
}
else
{
ppc_dec_trigger_cycle = 0x7fffffff;
}
ppc_change_pc(ppc.npc);
/*{
char string1[200];
char string2[200];
opcode = BSWAP32(*ppc.op);
DisassemblePowerPC(opcode, ppc.npc, string1, string2, TRUE);
printf("%08X: %s %s\n", ppc.npc, string1, string2);
}*/
printf("trigger cycle %d (%08X)\n", ppc_dec_trigger_cycle, ppc_dec_trigger_cycle);
printf("tb = %08X %08X\n", (UINT32)(ppc.tb >> 32), (UINT32)(ppc.tb));
ppc603_check_interrupts();
while( ppc_icount > 0 )
{
ppc.pc = ppc.npc;
opcode = BSWAP32(*ppc.op++);
ppc.npc = ppc.pc + 4;
switch(opcode >> 26)
{
case 19: optable19[(opcode >> 1) & 0x3ff](opcode); break;
case 31: optable31[(opcode >> 1) & 0x3ff](opcode); break;
case 59: optable59[(opcode >> 1) & 0x3ff](opcode); break;
case 63: optable63[(opcode >> 1) & 0x3ff](opcode); break;
default: optable[opcode >> 26](opcode); break;
}
ppc_icount--;
if(ppc_icount == ppc_dec_trigger_cycle)
{
printf("dec int at %d\n", ppc_icount);
ppc.interrupt_pending |= 0x2;
ppc603_check_interrupts();
}
//ppc603_check_interrupts();
}
// update timebase
// timebase is incremented once every four core clock cycles, so adjust the cycles accordingly
ppc.tb += ((ppc_tb_base_icount - ppc_icount) / 4);
// update decrementer
ppc.dec_frac = ((ppc_dec_base_icount - ppc_icount) % (bus_freq_multiplier * 2));
DEC -= ((ppc_dec_base_icount - ppc_icount) / (bus_freq_multiplier * 2));
/*
{
char string1[200];
char string2[200];
opcode = BSWAP32(*ppc.op);
DisassemblePowerPC(opcode, ppc.npc, string1, string2, TRUE);
printf("%08X: %s %s\n", ppc.npc, string1, string2);
}
*/
return cycles - ppc_icount;
}

2711
ppc_itp/ppc_ops.c Normal file

File diff suppressed because it is too large Load diff

143
ppc_itp/ppc_ops.h Normal file
View file

@ -0,0 +1,143 @@
static PPC_OPCODE ppc_opcode_common[] =
{
/*code subcode handler */
{ 31, 266, ppc_addx },
{ 31, 266 | 512, ppc_addx },
{ 31, 10, ppc_addcx },
{ 31, 10 | 512, ppc_addcx },
{ 31, 138, ppc_addex },
{ 31, 138 | 512, ppc_addex },
{ 14, -1, ppc_addi },
{ 12, -1, ppc_addic },
{ 13, -1, ppc_addic_rc },
{ 15, -1, ppc_addis },
{ 31, 234, ppc_addmex },
{ 31, 234 | 512, ppc_addmex },
{ 31, 202, ppc_addzex },
{ 31, 202 | 512, ppc_addzex },
{ 31, 28, ppc_andx },
{ 31, 28 | 512, ppc_andx },
{ 31, 60, ppc_andcx },
{ 28, -1, ppc_andi_rc },
{ 29, -1, ppc_andis_rc },
{ 18, -1, ppc_bx },
{ 16, -1, ppc_bcx },
{ 19, 528, ppc_bcctrx },
{ 19, 16, ppc_bclrx },
{ 31, 0, ppc_cmp },
{ 11, -1, ppc_cmpi },
{ 31, 32, ppc_cmpl },
{ 10, -1, ppc_cmpli },
{ 31, 26, ppc_cntlzw },
{ 19, 257, ppc_crand },
{ 19, 129, ppc_crandc },
{ 19, 289, ppc_creqv },
{ 19, 225, ppc_crnand },
{ 19, 33, ppc_crnor },
{ 19, 449, ppc_cror },
{ 19, 417, ppc_crorc },
{ 19, 193, ppc_crxor },
{ 31, 86, ppc_dcbf },
{ 31, 470, ppc_dcbi },
{ 31, 54, ppc_dcbst },
{ 31, 278, ppc_dcbt },
{ 31, 246, ppc_dcbtst },
{ 31, 1014, ppc_dcbz },
{ 31, 491, ppc_divwx },
{ 31, 491 | 512, ppc_divwx },
{ 31, 459, ppc_divwux },
{ 31, 459 | 512, ppc_divwux },
{ 31, 854, ppc_eieio },
{ 31, 284, ppc_eqvx },
{ 31, 954, ppc_extsbx },
{ 31, 922, ppc_extshx },
{ 31, 982, ppc_icbi },
{ 19, 150, ppc_isync },
{ 34, -1, ppc_lbz },
{ 35, -1, ppc_lbzu },
{ 31, 119, ppc_lbzux },
{ 31, 87, ppc_lbzx },
{ 42, -1, ppc_lha },
{ 43, -1, ppc_lhau },
{ 31, 375, ppc_lhaux },
{ 31, 343, ppc_lhax },
{ 31, 790, ppc_lhbrx },
{ 40, -1, ppc_lhz },
{ 41, -1, ppc_lhzu },
{ 31, 311, ppc_lhzux },
{ 31, 279, ppc_lhzx },
{ 46, -1, ppc_lmw },
{ 31, 597, ppc_lswi },
{ 31, 533, ppc_lswx },
{ 31, 20, ppc_lwarx },
{ 31, 534, ppc_lwbrx },
{ 32, -1, ppc_lwz },
{ 33, -1, ppc_lwzu },
{ 31, 55, ppc_lwzux },
{ 31, 23, ppc_lwzx },
{ 19, 0, ppc_mcrf },
{ 31, 512, ppc_mcrxr },
{ 31, 19, ppc_mfcr },
{ 31, 83, ppc_mfmsr },
{ 31, 339, ppc_mfspr },
{ 31, 144, ppc_mtcrf },
{ 31, 146, ppc_mtmsr },
{ 31, 467, ppc_mtspr },
{ 31, 75, ppc_mulhwx },
{ 31, 11, ppc_mulhwux },
{ 7, -1, ppc_mulli },
{ 31, 235, ppc_mullwx },
{ 31, 235 | 512, ppc_mullwx },
{ 31, 476, ppc_nandx },
{ 31, 104, ppc_negx },
{ 31, 104 | 512, ppc_negx },
{ 31, 124, ppc_norx },
{ 31, 444, ppc_orx },
{ 31, 412, ppc_orcx },
{ 24, -1, ppc_ori },
{ 25, -1, ppc_oris },
{ 19, 50, ppc_rfi },
{ 20, -1, ppc_rlwimix },
{ 21, -1, ppc_rlwinmx },
{ 23, -1, ppc_rlwnmx },
{ 17, -1, ppc_sc },
{ 31, 24, ppc_slwx },
{ 31, 792, ppc_srawx },
{ 31, 824, ppc_srawix },
{ 31, 536, ppc_srwx },
{ 38, -1, ppc_stb },
{ 39, -1, ppc_stbu },
{ 31, 247, ppc_stbux },
{ 31, 215, ppc_stbx },
{ 44, -1, ppc_sth },
{ 31, 918, ppc_sthbrx },
{ 45, -1, ppc_sthu },
{ 31, 439, ppc_sthux },
{ 31, 407, ppc_sthx },
{ 47, -1, ppc_stmw },
{ 31, 725, ppc_stswi },
{ 31, 661, ppc_stswx },
{ 36, -1, ppc_stw },
{ 31, 662, ppc_stwbrx },
{ 31, 150, ppc_stwcx_rc },
{ 37, -1, ppc_stwu },
{ 31, 183, ppc_stwux },
{ 31, 151, ppc_stwx },
{ 31, 40, ppc_subfx },
{ 31, 40 | 512, ppc_subfx },
{ 31, 8, ppc_subfcx },
{ 31, 8 | 512, ppc_subfcx },
{ 31, 136, ppc_subfex },
{ 31, 136 | 512, ppc_subfex },
{ 8, -1, ppc_subfic },
{ 31, 232, ppc_subfmex },
{ 31, 232 | 512, ppc_subfmex },
{ 31, 200, ppc_subfzex },
{ 31, 200 | 512, ppc_subfzex },
{ 31, 598, ppc_sync },
{ 31, 4, ppc_tw },
{ 3, -1, ppc_twi },
{ 31, 316, ppc_xorx },
{ 26, -1, ppc_xori },
{ 27, -1, ppc_xoris }
};

1298
unzip/unzip.c Normal file

File diff suppressed because it is too large Load diff

274
unzip/unzip.h Normal file
View file

@ -0,0 +1,274 @@
/* unzip.h -- IO for uncompress .zip files using zlib
Version 0.15 beta, Mar 19th, 1998,
Copyright (C) 1998 Gilles Vollant
This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g
WinZip, InfoZip tools and compatible.
Encryption and multi volume ZipFile (span) are not supported.
Old compressions used by old PKZip 1.x are not supported
THIS IS AN ALPHA VERSION. AT THIS STAGE OF DEVELOPPEMENT, SOMES API OR STRUCTURE
CAN CHANGE IN FUTURE VERSION !!
I WAIT FEEDBACK at mail info@winimage.com
Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution
Condition of use and distribution are the same than zlib :
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.
*/
/* for more info about .ZIP format, see
ftp://ftp.cdrom.com/pub/infozip/doc/appnote-970311-iz.zip
PkWare has also a specification at :
ftp://ftp.pkware.com/probdesc.zip */
#ifndef _unz_H
#define _unz_H
#ifdef __cplusplus
extern "C" {
#endif
#ifndef _ZLIB_H
#include "zlib.h"
#endif
#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP)
/* like the STRICT of WIN32, we define a pointer that cannot be converted
from (void*) without cast */
typedef struct TagunzFile__ { int unused; } unzFile__;
typedef unzFile__ *unzFile;
#else
typedef voidp unzFile;
#endif
#define UNZ_OK (0)
#define UNZ_END_OF_LIST_OF_FILE (-100)
#define UNZ_ERRNO (Z_ERRNO)
#define UNZ_EOF (0)
#define UNZ_PARAMERROR (-102)
#define UNZ_BADZIPFILE (-103)
#define UNZ_INTERNALERROR (-104)
#define UNZ_CRCERROR (-105)
/* tm_unz contain date/time info */
typedef struct tm_unz_s
{
uInt tm_sec; /* seconds after the minute - [0,59] */
uInt tm_min; /* minutes after the hour - [0,59] */
uInt tm_hour; /* hours since midnight - [0,23] */
uInt tm_mday; /* day of the month - [1,31] */
uInt tm_mon; /* months since January - [0,11] */
uInt tm_year; /* years - [1980..2044] */
} tm_unz;
/* unz_global_info structure contain global data about the ZIPfile
These data comes from the end of central dir */
typedef struct unz_global_info_s
{
uLong number_entry; /* total number of entries in
the central dir on this disk */
uLong size_comment; /* size of the global comment of the zipfile */
} unz_global_info;
/* unz_file_info contain information about a file in the zipfile */
typedef struct unz_file_info_s
{
uLong version; /* version made by 2 bytes */
uLong version_needed; /* version needed to extract 2 bytes */
uLong flag; /* general purpose bit flag 2 bytes */
uLong compression_method; /* compression method 2 bytes */
uLong dosDate; /* last mod file date in Dos fmt 4 bytes */
uLong crc; /* crc-32 4 bytes */
uLong compressed_size; /* compressed size 4 bytes */
uLong uncompressed_size; /* uncompressed size 4 bytes */
uLong size_filename; /* filename length 2 bytes */
uLong size_file_extra; /* extra field length 2 bytes */
uLong size_file_comment; /* file comment length 2 bytes */
uLong disk_num_start; /* disk number start 2 bytes */
uLong internal_fa; /* internal file attributes 2 bytes */
uLong external_fa; /* external file attributes 4 bytes */
tm_unz tmu_date;
} unz_file_info;
extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1,
const char* fileName2,
int iCaseSensitivity));
/*
Compare two filename (fileName1,fileName2).
If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp)
If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi
or strcasecmp)
If iCaseSenisivity = 0, case sensitivity is defaut of your operating system
(like 1 on Unix, 2 on Windows)
*/
extern unzFile ZEXPORT unzOpen OF((const char *path));
/*
Open a Zip file. path contain the full pathname (by example,
on a Windows NT computer "c:\\zlib\\zlib111.zip" or on an Unix computer
"zlib/zlib111.zip".
If the zipfile cannot be opened (file don't exist or in not valid), the
return value is NULL.
Else, the return value is a unzFile Handle, usable with other function
of this unzip package.
*/
extern int ZEXPORT unzClose OF((unzFile file));
/*
Close a ZipFile opened with unzipOpen.
If there is files inside the .Zip opened with unzOpenCurrentFile (see later),
these files MUST be closed with unzipCloseCurrentFile before call unzipClose.
return UNZ_OK if there is no problem. */
extern int ZEXPORT unzGetGlobalInfo OF((unzFile file,
unz_global_info *pglobal_info));
/*
Write info about the ZipFile in the *pglobal_info structure.
No preparation of the structure is needed
return UNZ_OK if there is no problem. */
extern int ZEXPORT unzGetGlobalComment OF((unzFile file,
char *szComment,
uLong uSizeBuf));
/*
Get the global comment string of the ZipFile, in the szComment buffer.
uSizeBuf is the size of the szComment buffer.
return the number of byte copied or an error code <0
*/
/***************************************************************************/
/* Unzip package allow you browse the directory of the zipfile */
extern int ZEXPORT unzGoToFirstFile OF((unzFile file));
/*
Set the current file of the zipfile to the first file.
return UNZ_OK if there is no problem
*/
extern int ZEXPORT unzGoToNextFile OF((unzFile file));
/*
Set the current file of the zipfile to the next file.
return UNZ_OK if there is no problem
return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.
*/
extern int ZEXPORT unzLocateFile OF((unzFile file,
const char *szFileName,
int iCaseSensitivity));
/*
Try locate the file szFileName in the zipfile.
For the iCaseSensitivity signification, see unzStringFileNameCompare
return value :
UNZ_OK if the file is found. It becomes the current file.
UNZ_END_OF_LIST_OF_FILE if the file is not found
*/
extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file,
unz_file_info *pfile_info,
char *szFileName,
uLong fileNameBufferSize,
void *extraField,
uLong extraFieldBufferSize,
char *szComment,
uLong commentBufferSize));
/*
Get Info about the current file
if pfile_info!=NULL, the *pfile_info structure will contain somes info about
the current file
if szFileName!=NULL, the filemane string will be copied in szFileName
(fileNameBufferSize is the size of the buffer)
if extraField!=NULL, the extra field information will be copied in extraField
(extraFieldBufferSize is the size of the buffer).
This is the Central-header version of the extra field
if szComment!=NULL, the comment string of the file will be copied in szComment
(commentBufferSize is the size of the buffer)
*/
/***************************************************************************/
/* for reading the content of the current zipfile, you can open it, read data
from it, and close it (you can close it before reading all the file)
*/
extern int ZEXPORT unzOpenCurrentFile OF((unzFile file));
/*
Open for reading data the current file in the zipfile.
If there is no error, the return value is UNZ_OK.
*/
extern int ZEXPORT unzCloseCurrentFile OF((unzFile file));
/*
Close the file in zip opened with unzOpenCurrentFile
Return UNZ_CRCERROR if all the file was read but the CRC is not good
*/
extern int ZEXPORT unzReadCurrentFile OF((unzFile file,
voidp buf,
unsigned len));
/*
Read bytes from the current file (opened by unzOpenCurrentFile)
buf contain buffer where data must be copied
len the size of buf.
return the number of byte copied if somes bytes are copied
return 0 if the end of file was reached
return <0 with error code if there is an error
(UNZ_ERRNO for IO error, or zLib error for uncompress error)
*/
extern z_off_t ZEXPORT unztell OF((unzFile file));
/*
Give the current position in uncompressed data
*/
extern int ZEXPORT unzeof OF((unzFile file));
/*
return 1 if the end of file was reached, 0 elsewhere
*/
extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file,
voidp buf,
unsigned len));
/*
Read extra field from the current file (opened by unzOpenCurrentFile)
This is the local-header version of the extra field (sometimes, there is
more info in the local-header version than in the central-header)
if buf==NULL, it return the size of the local extra field
if buf!=NULL, len is the size of the buffer, the extra header is copied in
buf.
the return value is the number of bytes copied in buf, or (if <0)
the error code
*/
#ifdef __cplusplus
}
#endif
#endif /* _unz_H */

1712
win32/dx9_renderer.c Normal file

File diff suppressed because it is too large Load diff

38
win32/dx_render.h Normal file
View file

@ -0,0 +1,38 @@
/*
* Sega Model 3 Emulator
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* 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 (license.txt); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* win32/dx_render.h
*
* DirectX9 Renderer interface
*/
#include "d3d9.h"
#include "d3dx9.h"
#define RGB_REG 0xFFFF0000
#define RGB_GREEN 0xFF00FF00
#define RGB_BLUE 0xFF0000FF
#define RGB_YELLOW 0xFFFFFF00
#define RGB_CYAN 0xFF00FFFF
BOOL d3d_init(HWND);
BOOL d3d_pre_init(void);
void d3d_shutdown(void);
D3DXMATRIX d3d_matrix_stack_get_top(void);
void d3d_matrix_stack_init(void);

84
win32/osd.h Normal file
View file

@ -0,0 +1,84 @@
/*
* Sega Model 3 Emulator
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* 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 (license.txt); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* win32/osd.h
*
* Win32 OSD header: Defines everything an OSD header needs to provide and
* includes some Win32-specific files.
*/
#ifndef INCLUDED_WIN32_OSD_H
#define INCLUDED_WIN32_OSD_H
/******************************************************************/
/* Win32-Specific Includes */
/******************************************************************/
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
/******************************************************************/
/* OSD Definitions */
/******************************************************************/
#ifdef _MSC_VER
#define INLINE static _inline
#endif
#ifdef __GCC__
#define INLINE static __inline__
#endif
/******************************************************************/
/* OSD Fundamental Data Types */
/******************************************************************/
typedef unsigned int FLAGS; // for storage of bit flags
#ifdef __GCC__
typedef int BOOL; // 0 (false) or non-zero (true)
typedef signed int INT; // optimal signed integer
typedef unsigned int UINT; // optimal unsigned integer
typedef signed char CHAR; // signed character (for text)
typedef unsigned char UCHAR; // unsigned character
typedef signed char INT8;
typedef unsigned char UINT8;
typedef signed short INT16;
typedef unsigned short UINT16;
typedef signed int INT32;
typedef unsigned int UINT32;
#ifdef _MSC_VER // Microsoft VisualC++ (for versions 6.0 or older, non-C99)
typedef signed __int64 INT64;
typedef unsigned __int64 UINT64;
#else // assume a C99-compliant compiler
typedef signed long long INT64;
typedef unsigned long long UINT64;
#endif
#endif
typedef float FLOAT32; // single precision (32-bit)
typedef double FLOAT64; // double precision (64-bit)
#endif // INCLUDED_WIN32_OSD_H

57
win32/pixel_shader.ps Normal file
View file

@ -0,0 +1,57 @@
ps_3_0
; input declarations
dcl_color0 v0.xyzw
dcl_texcoord0 v1.xyzw
dcl_texcoord1 v2.xyzw
dcl_texcoord2 v3.xyzw
dcl_color1 v4.xyzw
dcl_2d s0
; constants
def c0, 1.0f, 0.0f, 0.0f, 0.5f
def c1, 0.00048828125f, 0.000244140625f, 0.0f, 0.0f
rcp r30, v2.z ; calculate 1/width
rcp r31, v2.w ; calculate 1/height
mov r31.xy, c0.yy ; r31.xy <- 0,0 \ hopefully co-issue...
mov r31.z, r30.z ; /
add r1.xyzw, v1.xyxy, r31.yyzy ; texel[0][0], texel[1][0]
add r2.xyzw, v1.xyxy, r31.ywzw ; texel[0][1], texel[1][1]
frc r1.xyzw, r1.xyzw
frc r2.xyzw, r2.xyzw
mul r3, r1, v2.zwzw ; mul by width, height
mul r4, r2, v2.zwzw ; mul by width, height
add r10, r3, v2.xyxy ; add tex base
add r11, r4, v2.xyxy ; add tex base
mul r10, r10, c1.xyxy ; div by 2048
mul r11, r11, c1.xyxy ; div by 2048
frc r18, r3
texld r5, r10.xy, s0
texld r6, r10.zw, s0
texld r7, r11.xy, s0
texld r8, r11.zw, s0
lrp r12, r18.xxxx, r6, r5
lrp r13, r18.xxxx, r8, r7
lrp r15, r18.yyyy, r13, r12
;if_lt v0.a, c0.x ; if polygon alpha is enabled use that instead of texture alpha
; mov r15.a, v0.a
;endif
if_ne v4.x, c0.y ; if v4.x == 0 -> color, if v4.x != -> texture
mul_sat r15, v0, r15 ; modulate with color
else
mov r15, v0
endif
;mov r15, v0
mov oC0, r15

38
win32/pixel_shader_2d.ps Normal file
View file

@ -0,0 +1,38 @@
ps_3_0
; parameters
; c8 = color offset
; c9 = (X,Y) scroll position, (Z) 0 = rendering background, 1 = rendering foreground
; input declarations
dcl_color v0.xyzw
dcl_texcoord0 v1.xy
dcl_2d s0
dcl_2d s1
dcl_2d s2
def c0, 1.0, 0.0, 1.0f, 1.0f
def c1, 0.5, 0.0, 0.0, 0.0
add r5, v1.xy, c9.xy ; add scroll position
frc r5, r5 ; wrap
texld r0, r5, s0
texld r10, v1, s2 ; load priority value
mov r11.r, c9.z
mov r1.xy, r0.ga
texld r2, r1, s1
add r2.rgb, r2.rgb, c8.yzw
min r2, r2, c0.xxxx ; clamp to 1.0
max r2, r2, c0.yyyy ; clamp to 0.0
if_eq r11.r, c0.y ; invert priority if rendering foreground
sub r10.r, c0.x, r10.r
endif
mul r2.a, r2.a, r10.r ; multiply alpha with priority
mov oC0, r2

106
win32/shaders.h Normal file
View file

@ -0,0 +1,106 @@
unsigned char pixel_shader_source[524] =
{
0x00, 0x03, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x02, 0x0A, 0x00, 0x00, 0x80, 0x00, 0x00, 0x0F, 0x90,
0x1F, 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x80, 0x01, 0x00, 0x0F, 0x90, 0x1F, 0x00, 0x00, 0x02,
0x05, 0x00, 0x01, 0x80, 0x02, 0x00, 0x0F, 0x90, 0x1F, 0x00, 0x00, 0x02, 0x05, 0x00, 0x02, 0x80,
0x03, 0x00, 0x0F, 0x90, 0x1F, 0x00, 0x00, 0x02, 0x0A, 0x00, 0x01, 0x80, 0x04, 0x00, 0x0F, 0x90,
0x1F, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x90, 0x00, 0x08, 0x0F, 0xA0, 0x51, 0x00, 0x00, 0x05,
0x00, 0x00, 0x0F, 0xA0, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x3F, 0x51, 0x00, 0x00, 0x05, 0x01, 0x00, 0x0F, 0xA0, 0x00, 0x00, 0x00, 0x3A,
0x00, 0x00, 0x80, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x02,
0x1E, 0x00, 0x0F, 0x80, 0x02, 0x00, 0xAA, 0x90, 0x06, 0x00, 0x00, 0x02, 0x1F, 0x00, 0x0F, 0x80,
0x02, 0x00, 0xFF, 0x90, 0x01, 0x00, 0x00, 0x02, 0x1F, 0x00, 0x03, 0x80, 0x00, 0x00, 0x55, 0xA0,
0x01, 0x00, 0x00, 0x02, 0x1F, 0x00, 0x04, 0x80, 0x1E, 0x00, 0xAA, 0x80, 0x02, 0x00, 0x00, 0x03,
0x01, 0x00, 0x0F, 0x80, 0x01, 0x00, 0x44, 0x90, 0x1F, 0x00, 0x65, 0x80, 0x02, 0x00, 0x00, 0x03,
0x02, 0x00, 0x0F, 0x80, 0x01, 0x00, 0x44, 0x90, 0x1F, 0x00, 0xED, 0x80, 0x13, 0x00, 0x00, 0x02,
0x01, 0x00, 0x0F, 0x80, 0x01, 0x00, 0xE4, 0x80, 0x13, 0x00, 0x00, 0x02, 0x02, 0x00, 0x0F, 0x80,
0x02, 0x00, 0xE4, 0x80, 0x05, 0x00, 0x00, 0x03, 0x03, 0x00, 0x0F, 0x80, 0x01, 0x00, 0xE4, 0x80,
0x02, 0x00, 0xEE, 0x90, 0x05, 0x00, 0x00, 0x03, 0x04, 0x00, 0x0F, 0x80, 0x02, 0x00, 0xE4, 0x80,
0x02, 0x00, 0xEE, 0x90, 0x02, 0x00, 0x00, 0x03, 0x0A, 0x00, 0x0F, 0x80, 0x03, 0x00, 0xE4, 0x80,
0x02, 0x00, 0x44, 0x90, 0x02, 0x00, 0x00, 0x03, 0x0B, 0x00, 0x0F, 0x80, 0x04, 0x00, 0xE4, 0x80,
0x02, 0x00, 0x44, 0x90, 0x05, 0x00, 0x00, 0x03, 0x0A, 0x00, 0x0F, 0x80, 0x0A, 0x00, 0xE4, 0x80,
0x01, 0x00, 0x44, 0xA0, 0x05, 0x00, 0x00, 0x03, 0x0B, 0x00, 0x0F, 0x80, 0x0B, 0x00, 0xE4, 0x80,
0x01, 0x00, 0x44, 0xA0, 0x13, 0x00, 0x00, 0x02, 0x12, 0x00, 0x0F, 0x80, 0x03, 0x00, 0xE4, 0x80,
0x42, 0x00, 0x00, 0x03, 0x05, 0x00, 0x0F, 0x80, 0x0A, 0x00, 0x54, 0x80, 0x00, 0x08, 0xE4, 0xA0,
0x42, 0x00, 0x00, 0x03, 0x06, 0x00, 0x0F, 0x80, 0x0A, 0x00, 0xFE, 0x80, 0x00, 0x08, 0xE4, 0xA0,
0x42, 0x00, 0x00, 0x03, 0x07, 0x00, 0x0F, 0x80, 0x0B, 0x00, 0x54, 0x80, 0x00, 0x08, 0xE4, 0xA0,
0x42, 0x00, 0x00, 0x03, 0x08, 0x00, 0x0F, 0x80, 0x0B, 0x00, 0xFE, 0x80, 0x00, 0x08, 0xE4, 0xA0,
0x12, 0x00, 0x00, 0x04, 0x0C, 0x00, 0x0F, 0x80, 0x12, 0x00, 0x00, 0x80, 0x06, 0x00, 0xE4, 0x80,
0x05, 0x00, 0xE4, 0x80, 0x12, 0x00, 0x00, 0x04, 0x0D, 0x00, 0x0F, 0x80, 0x12, 0x00, 0x00, 0x80,
0x08, 0x00, 0xE4, 0x80, 0x07, 0x00, 0xE4, 0x80, 0x12, 0x00, 0x00, 0x04, 0x0F, 0x00, 0x0F, 0x80,
0x12, 0x00, 0x55, 0x80, 0x0D, 0x00, 0xE4, 0x80, 0x0C, 0x00, 0xE4, 0x80, 0x29, 0x00, 0x05, 0x02,
0x04, 0x00, 0x00, 0x90, 0x00, 0x00, 0x55, 0xA0, 0x05, 0x00, 0x00, 0x03, 0x0F, 0x00, 0x1F, 0x80,
0x00, 0x00, 0xE4, 0x90, 0x0F, 0x00, 0xE4, 0x80, 0x2A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02,
0x0F, 0x00, 0x0F, 0x80, 0x00, 0x00, 0xE4, 0x90, 0x2B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02,
0x00, 0x08, 0x0F, 0x80, 0x0F, 0x00, 0xE4, 0x80, 0xFF, 0xFF, 0x00, 0x00,
};
unsigned char pixel_shader_2d_source[324] =
{
0x00, 0x03, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x02, 0x0A, 0x00, 0x00, 0x80, 0x00, 0x00, 0x0F, 0x90,
0x1F, 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x80, 0x01, 0x00, 0x03, 0x90, 0x1F, 0x00, 0x00, 0x02,
0x00, 0x00, 0x00, 0x90, 0x00, 0x08, 0x0F, 0xA0, 0x1F, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x90,
0x01, 0x08, 0x0F, 0xA0, 0x1F, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x90, 0x02, 0x08, 0x0F, 0xA0,
0x51, 0x00, 0x00, 0x05, 0x00, 0x00, 0x0F, 0xA0, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0x80, 0x3F, 0x51, 0x00, 0x00, 0x05, 0x01, 0x00, 0x0F, 0xA0,
0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x03, 0x05, 0x00, 0x0F, 0x80, 0x01, 0x00, 0x54, 0x90, 0x09, 0x00, 0x54, 0xA0,
0x13, 0x00, 0x00, 0x02, 0x05, 0x00, 0x0F, 0x80, 0x05, 0x00, 0xE4, 0x80, 0x42, 0x00, 0x00, 0x03,
0x00, 0x00, 0x0F, 0x80, 0x05, 0x00, 0xE4, 0x80, 0x00, 0x08, 0xE4, 0xA0, 0x42, 0x00, 0x00, 0x03,
0x0A, 0x00, 0x0F, 0x80, 0x01, 0x00, 0xE4, 0x90, 0x02, 0x08, 0xE4, 0xA0, 0x01, 0x00, 0x00, 0x02,
0x0B, 0x00, 0x01, 0x80, 0x09, 0x00, 0xAA, 0xA0, 0x01, 0x00, 0x00, 0x02, 0x01, 0x00, 0x03, 0x80,
0x00, 0x00, 0xFD, 0x80, 0x42, 0x00, 0x00, 0x03, 0x02, 0x00, 0x0F, 0x80, 0x01, 0x00, 0xE4, 0x80,
0x01, 0x08, 0xE4, 0xA0, 0x02, 0x00, 0x00, 0x03, 0x02, 0x00, 0x07, 0x80, 0x02, 0x00, 0xA4, 0x80,
0x08, 0x00, 0xF9, 0xA0, 0x0A, 0x00, 0x00, 0x03, 0x02, 0x00, 0x0F, 0x80, 0x02, 0x00, 0xE4, 0x80,
0x00, 0x00, 0x00, 0xA0, 0x0B, 0x00, 0x00, 0x03, 0x02, 0x00, 0x0F, 0x80, 0x02, 0x00, 0xE4, 0x80,
0x00, 0x00, 0x55, 0xA0, 0x29, 0x00, 0x02, 0x02, 0x0B, 0x00, 0x00, 0x80, 0x00, 0x00, 0x55, 0xA0,
0x02, 0x00, 0x00, 0x03, 0x0A, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0xA0, 0x0A, 0x00, 0x00, 0x81,
0x2B, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x03, 0x02, 0x00, 0x08, 0x80, 0x02, 0x00, 0xFF, 0x80,
0x0A, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x02, 0x00, 0x08, 0x0F, 0x80, 0x02, 0x00, 0xE4, 0x80,
0xFF, 0xFF, 0x00, 0x00,
};
unsigned char vertex_shader_source[500] =
{
0x00, 0x03, 0xFE, 0xFF, 0x1F, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x0F, 0x90,
0x1F, 0x00, 0x00, 0x02, 0x0A, 0x00, 0x00, 0x80, 0x01, 0x00, 0x0F, 0x90, 0x1F, 0x00, 0x00, 0x02,
0x05, 0x00, 0x00, 0x80, 0x02, 0x00, 0x0F, 0x90, 0x1F, 0x00, 0x00, 0x02, 0x05, 0x00, 0x01, 0x80,
0x03, 0x00, 0x0F, 0x90, 0x1F, 0x00, 0x00, 0x02, 0x05, 0x00, 0x02, 0x80, 0x04, 0x00, 0x0F, 0x90,
0x1F, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x80, 0x05, 0x00, 0x0F, 0x90, 0x1F, 0x00, 0x00, 0x02,
0x0A, 0x00, 0x01, 0x80, 0x06, 0x00, 0x0F, 0x90, 0x1F, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x80,
0x00, 0x00, 0x0F, 0xE0, 0x1F, 0x00, 0x00, 0x02, 0x0A, 0x00, 0x00, 0x80, 0x01, 0x00, 0x0F, 0xE0,
0x1F, 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x80, 0x02, 0x00, 0x0F, 0xE0, 0x1F, 0x00, 0x00, 0x02,
0x05, 0x00, 0x01, 0x80, 0x03, 0x00, 0x0F, 0xE0, 0x1F, 0x00, 0x00, 0x02, 0x05, 0x00, 0x02, 0x80,
0x04, 0x00, 0x0F, 0xE0, 0x1F, 0x00, 0x00, 0x02, 0x0A, 0x00, 0x01, 0x80, 0x05, 0x00, 0x0F, 0xE0,
0x51, 0x00, 0x00, 0x05, 0x80, 0x00, 0x0F, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3F,
0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x80, 0x3F, 0x09, 0x00, 0x00, 0x03, 0x14, 0x00, 0x01, 0x80,
0x00, 0x00, 0xE4, 0x90, 0x00, 0x00, 0xE4, 0xA0, 0x09, 0x00, 0x00, 0x03, 0x14, 0x00, 0x02, 0x80,
0x00, 0x00, 0xE4, 0x90, 0x01, 0x00, 0xE4, 0xA0, 0x09, 0x00, 0x00, 0x03, 0x14, 0x00, 0x04, 0x80,
0x00, 0x00, 0xE4, 0x90, 0x02, 0x00, 0xE4, 0xA0, 0x09, 0x00, 0x00, 0x03, 0x14, 0x00, 0x08, 0x80,
0x00, 0x00, 0xE4, 0x90, 0x03, 0x00, 0xE4, 0xA0, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x0F, 0xE0,
0x14, 0x00, 0xE4, 0x80, 0x17, 0x00, 0x00, 0x03, 0x04, 0x00, 0x07, 0x80, 0x05, 0x00, 0xE4, 0x90,
0x04, 0x00, 0xE4, 0xA0, 0x01, 0x00, 0x00, 0x02, 0x02, 0x00, 0x0F, 0x80, 0x10, 0x00, 0xE4, 0xA1,
0x08, 0x00, 0x00, 0x03, 0x03, 0x00, 0x0F, 0x80, 0x04, 0x00, 0xE4, 0x80, 0x02, 0x00, 0xE4, 0x80,
0x0B, 0x00, 0x00, 0x03, 0x03, 0x00, 0x0F, 0x80, 0x03, 0x00, 0xE4, 0x80, 0x80, 0x00, 0x00, 0xA0,
0x05, 0x00, 0x00, 0x03, 0x03, 0x00, 0x0F, 0x80, 0x03, 0x00, 0xE4, 0x80, 0x11, 0x00, 0x00, 0xA0,
0x02, 0x00, 0x00, 0x03, 0x03, 0x00, 0x0F, 0x80, 0x03, 0x00, 0xE4, 0x80, 0x11, 0x00, 0x55, 0xA0,
0x0A, 0x00, 0x00, 0x03, 0x03, 0x00, 0x0F, 0x80, 0x03, 0x00, 0xE4, 0x80, 0x80, 0x00, 0x55, 0xA0,
0x29, 0x00, 0x05, 0x02, 0x06, 0x00, 0x00, 0x90, 0x80, 0x00, 0x00, 0xA0, 0x01, 0x00, 0x00, 0x02,
0x03, 0x00, 0x07, 0x80, 0x06, 0x00, 0x00, 0x90, 0x2B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02,
0x03, 0x00, 0x08, 0x80, 0x80, 0x00, 0xFF, 0xA0, 0x05, 0x00, 0x00, 0x03, 0x01, 0x00, 0x0F, 0xE0,
0x01, 0x00, 0xE4, 0x90, 0x03, 0x00, 0xE4, 0x80, 0x01, 0x00, 0x00, 0x02, 0x0A, 0x00, 0x0F, 0x80,
0x02, 0x00, 0xE4, 0x90, 0x01, 0x00, 0x00, 0x02, 0x0A, 0x00, 0x08, 0x80, 0x14, 0x00, 0xFF, 0x80,
0x01, 0x00, 0x00, 0x02, 0x02, 0x00, 0x0F, 0xE0, 0x0A, 0x00, 0xE4, 0x80, 0x01, 0x00, 0x00, 0x02,
0x03, 0x00, 0x0F, 0xE0, 0x03, 0x00, 0xE4, 0x90, 0x01, 0x00, 0x00, 0x02, 0x04, 0x00, 0x0F, 0xE0,
0x04, 0x00, 0xE4, 0x90, 0x01, 0x00, 0x00, 0x02, 0x05, 0x00, 0x01, 0xE0, 0x06, 0x00, 0x55, 0x90,
0xFF, 0xFF, 0x00, 0x00,
};
unsigned char vertex_shader_2d_source[80] =
{
0x00, 0x03, 0xFE, 0xFF, 0x1F, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x0F, 0x90,
0x1F, 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x80, 0x01, 0x00, 0x0F, 0x90, 0x1F, 0x00, 0x00, 0x02,
0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x0F, 0xE0, 0x1F, 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x80,
0x01, 0x00, 0x0F, 0xE0, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x00, 0xE4, 0x90,
0x01, 0x00, 0x00, 0x02, 0x01, 0x00, 0x0F, 0xE0, 0x01, 0x00, 0xE4, 0x90, 0xFF, 0xFF, 0x00, 0x00,
};

71
win32/vertex_shader.vs Normal file
View file

@ -0,0 +1,71 @@
vs_3_0
; parameters
; c0...c3 world-view-projection matrix
; c4...c7 world-view matrix
; c16 sun light vector
; c17 sun ambient, diffuse intensity
; input declarations
dcl_position v0
dcl_color0 v1
dcl_texcoord0 v2
dcl_texcoord1 v3
dcl_texcoord2 v4
dcl_normal v5
dcl_color1 v6
; output declarations
dcl_position o0.xyzw
dcl_color0 o1.xyzw
dcl_texcoord0 o2.xyzw
dcl_texcoord1 o3.xyzw
dcl_texcoord2 o4.xyzw
dcl_color1 o5.xyzw
; constants
def c128, 0.0f, 1.0f, 0.5f, 1.0f
; transform position to projection space
;dp4 o0.x, v0, c0
;dp4 o0.y, v0, c1
;dp4 o0.z, v0, c2
;dp4 o0.w, v0, c3
dp4 r20.x, v0, c0
dp4 r20.y, v0, c1
dp4 r20.z, v0, c2
dp4 r20.w, v0, c3
mov o0, r20
; calculate parallel lighting
m3x3 r4.xyz, v5, c4 ; transform N
mov r2, -c16
dp3 r3, r4, r2 ; N dot L
max r3, r3, c128.xxxx ; clamp negative values to 0
mul r3, r3, c17.xxxx ; scale with diffuse intensity
add r3, r3, c17.yyyy ; add ambient intensity
min r3, r3, c128.yyyy
if_ne v6.xxxx, c128.xxxx ; if v6.x == 0 -> apply lighting, if v6.x != 0 -> self-luminance
mov r3.xyz, v6.xxx ; self-luminance
endif
mov r3.w, c128.w ; multiply alpha with 1
mul o1, v1, r3 ; modulate and write color
;mov o1, r3
; move texture parameters
mov r10,v2
mov r10.w, r20.w
mov o2, r10
;mov o2, v2
mov o3, v3
mov o4, v4
; parameters (X=texture enable)
mov o5.x, v6.g

14
win32/vertex_shader_2d.vs Normal file
View file

@ -0,0 +1,14 @@
vs_3_0
; input declarations
dcl_position v0
dcl_texcoord0 v1
; output declarations
dcl_position o0.xyzw
dcl_texcoord0 o1.xyzw
mov o0, v0
mov o1, v1

181
win32/win_gl.c Normal file
View file

@ -0,0 +1,181 @@
/*
* Sega Model 3 Emulator
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* 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 (license.txt); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* win32/win_gl.c
*
* Win32 OpenGL support. All of this will have to be rewritten to support
* run-time mode changes and fullscreen modes.
*
* The only osd_renderer function implemented here is osd_renderer_blit().
*/
#include "model3.h"
#include "osd_common/osd_gl.h"
#include <gl\gl.h>
#include <gl\glu.h>
#include <gl\glext.h>
/*
* Window Context
*/
static HGLRC hrc = 0; // OpenGL rendering context
static HDC hdc = 0; // GDI device context
static HINSTANCE hinstance; // application instance
extern HWND main_window; // window handle
/*
* void win_gl_init(UINT xres, UINT yres);
*
* Sets the rendering mode and initializes OpenGL.
*
* Parameters:
* xres = Horizontal resolution in pixels.
* yres = Vertical resolution.
*/
void win_gl_init(UINT xres, UINT yres)
{
GLuint pixel_format;
static PIXELFORMATDESCRIPTOR pfd = // must this be static?
{
sizeof(PIXELFORMATDESCRIPTOR), // size of structure
1, // version (must be 1)
PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
PFD_TYPE_RGBA, // RGBA pixels
32, // color depth
0, 0, 0, 0, 0, 0, // color bits ignored
0, // no alpha buffer
0, // ignore shift bit
0, // no accumulation buffer
0, 0, 0, 0, // accumulation bits ignored
24, // 24-bit z-buffer
0, // no stencil buffer
0, // no auxilliary buffer
PFD_MAIN_PLANE, // main drawing layer
0, // reserved
0, 0, 0 // layer masks ignored
};
/*
* Get window instance
*/
hinstance = GetModuleHandle(NULL); // get window instance
/*
* Get device context and find a pixel format
*/
if (!(hdc = GetDC(main_window)))
osd_error("Unable to create an OpenGL device context.");
if (!(pixel_format = ChoosePixelFormat(hdc, &pfd))) // find matching pixel format
osd_error("Unable to find the required pixel format.");
if (!SetPixelFormat(hdc, pixel_format, &pfd))
osd_error("Unable to set the required pixel format.");
/*
* Get the rendering context and perform some GL initialization
*/
if (!(hrc = wglCreateContext(hdc)))
osd_error("Unable to create an OpenGL rendering context.");
if (!wglMakeCurrent(hdc, hrc))
osd_error("Unable to activate the OpenGL rendering context.");
/*
* Check for mirrored texture repeat extension
*/
if (osd_gl_check_extension("GL_ARB_texture_mirrored_repeat"))
osd_error("Your OpenGL implementation does not support mirrored texture repeating!");
if (osd_gl_check_extension("GL_ARB_texture_env_combine"))
osd_error("Your OpenGL implementation does not support texture combiner operations!");
if (osd_gl_check_extension("GL_EXT_texture_lod_bias"))
osd_error("Your OpenGL implementation does not support texture LOD bias selection!");
if (osd_gl_check_extension("GL_ARB_vertex_buffer_object"))
osd_error("Your OpenGL implementation does not support vertex buffer objects!");
/*
* Initialize GL engine
*/
osd_gl_set_mode(xres, yres);
}
/*
* void win_gl_shutdown(void);
*
* Shuts down the rendering mode mode meaning it releases the rendering and
* device contexts.
*/
void win_gl_shutdown(void)
{
osd_gl_unset_mode();
/*
* If there is a rendering context, release it
*/
if (hrc)
{
wglMakeCurrent(NULL, NULL);
wglDeleteContext(hrc);
}
/*
* If there is a device context, release it
*/
if (hdc)
ReleaseDC(main_window, hdc);
}
/*
* void osd_renderer_blit(void);
*
* Swaps the buffers to display what has been rendered in the last frame.
*/
void osd_renderer_blit(void)
{
SwapBuffers(hdc);
}
/*
* void * osd_gl_get_proc_address(const char *);
*
* Calls wglGetProcAddress.
*/
void * osd_gl_get_proc_address(const CHAR * id)
{
void * ptr = wglGetProcAddress(id);
if (ptr == NULL)
error("GL proc %s not found!\n", id);
else
message(0, "found GL proc %s!", id);
return ptr;
}

13
win32/win_gl.h Normal file
View file

@ -0,0 +1,13 @@
/*
* win32/win_gl.h
*
* Windows OpenGL header.
*/
#ifndef INCLUDED_WIN32_WIN_GL_H
#define INCLUDED_WIN32_WIN_GL_H
extern void win_gl_init(UINT, UINT);
extern void win_gl_shutdown(void);
#endif // INCLUDED_WIN32_WIN_GL_H

319
win32/win_input.c Normal file
View file

@ -0,0 +1,319 @@
/*
* Sega Model 3 Emulator
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* 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 (license.txt); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/******************************************************************/
/* DirectX 9 Input */
/******************************************************************/
#include "MODEL3.H"
#include <dinput.h>
static LPDIRECTINPUT8 dinput;
static LPDIRECTINPUTDEVICE8 keyboard;
static LPDIRECTINPUTDEVICE8 mouse;
static CHAR keyboard_buffer[256];
static DIMOUSESTATE mouse_state;
extern HWND main_window;
static OSD_CONTROLS controls;
void osd_input_init(void)
{
HINSTANCE hinstance;
HRESULT hr;
atexit(osd_input_shutdown);
hinstance = GetModuleHandle(NULL);
hr = DirectInput8Create( hinstance, DIRECTINPUT_VERSION, &IID_IDirectInput8,
(void**)&dinput, NULL );
if(FAILED(hr))
error("DirectInput8Create failed.");
// Create keyboard device
hr = IDirectInput8_CreateDevice( dinput, &GUID_SysKeyboard, &keyboard, NULL );
if(FAILED(hr))
error("IDirectInput8_CreateDevice failed.");
hr = IDirectInputDevice8_SetDataFormat( keyboard, &c_dfDIKeyboard );
if(FAILED(hr))
error("IDirectInputDevice8_SetDataFormat failed.");
hr = IDirectInputDevice8_SetCooperativeLevel( keyboard, main_window, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE );
if(FAILED(hr))
error("IDirectInputDevice8_SetCooperativeLevel failed.");
if(keyboard)
IDirectInputDevice8_Acquire( keyboard );
// Create mouse device
hr = IDirectInput8_CreateDevice( dinput, &GUID_SysMouse, &mouse, NULL );
if(FAILED(hr))
error("IDirectInput8_CreateDevice failed.");
hr = IDirectInputDevice8_SetDataFormat( mouse, &c_dfDIMouse );
if(FAILED(hr))
error("IDirectInputDevice8_SetDataFormat failed.");
hr = IDirectInputDevice8_SetCooperativeLevel( mouse, main_window, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE );
if(FAILED(hr))
error("IDirectInputDevice8_SetCooperativeLevel failed.");
}
void osd_input_shutdown(void)
{
if(dinput) {
if(keyboard) {
IDirectInputDevice8_Unacquire( keyboard );
IDirectInputDevice8_Release( keyboard );
keyboard = NULL;
}
if(mouse) {
IDirectInputDevice8_Unacquire( mouse );
IDirectInputDevice8_Release( mouse );
mouse = NULL;
}
IDirectInput8_Release( dinput );
dinput = NULL;
}
}
static void input_update(void)
{
/* updates the input buffer */
if(dinput) {
// Get keyboard state
IDirectInputDevice8_GetDeviceState( keyboard, sizeof(keyboard_buffer), &keyboard_buffer );
// Get mouse state
IDirectInputDevice8_Acquire( mouse );
IDirectInputDevice8_GetDeviceState( mouse, sizeof(mouse_state), &mouse_state );
}
}
static BOOL keyboard_get_key(UINT8 key)
{
if(keyboard_buffer[key] & 0x80)
return TRUE;
else
return FALSE;
}
static BOOL mouse_get_button(UINT8 button)
{
if(mouse_state.rgbButtons[button] & 0x80)
return TRUE;
else
return FALSE;
}
static void mouse_get_position(INT32* xposition, INT32* yposition)
{
POINT mouse_pos;
GetCursorPos( &mouse_pos );
ScreenToClient( main_window, &mouse_pos );
*xposition = mouse_pos.x + (400 - (MODEL3_SCREEN_WIDTH / 2));
*yposition = mouse_pos.y + (272 - (MODEL3_SCREEN_HEIGHT / 2));
}
OSD_CONTROLS* osd_input_update_controls(void)
{
INT32 mouse_x, mouse_y;
input_update();
controls.game_controls[0] = 0xFF;
controls.game_controls[1] = 0xFF;
controls.system_controls[0] = 0xFF;
controls.system_controls[1] = 0xFF;
// Lightgun
if(mouse_get_button(0))
controls.game_controls[0] &= ~0x01;
if(mouse_get_button(1))
controls.gun_acquired[0] = TRUE;
else
controls.gun_acquired[0] = FALSE;
mouse_get_position(&mouse_x, &mouse_y);
controls.gun_x[0] = mouse_x;
controls.gun_y[0] = mouse_y;
// Game controls
if(keyboard_get_key(DIK_A))
controls.game_controls[0] &= ~0x01;
if(keyboard_get_key(DIK_S))
controls.game_controls[0] &= ~0x02;
if(keyboard_get_key(DIK_D))
controls.game_controls[0] &= ~0x04;
if(keyboard_get_key(DIK_F))
controls.game_controls[0] &= ~0x08;
if(keyboard_get_key(DIK_G))
controls.game_controls[0] &= ~0x80;
if(keyboard_get_key(DIK_H))
controls.game_controls[0] &= ~0x40;
if(keyboard_get_key(DIK_Q))
controls.game_controls[0] &= ~0x80;
if(keyboard_get_key(DIK_W))
controls.game_controls[0] &= ~0x40;
if(keyboard_get_key(DIK_E))
controls.game_controls[0] &= ~0x20;
if(keyboard_get_key(DIK_R))
controls.game_controls[0] &= ~0x10;
if(keyboard_get_key(DIK_T))
controls.game_controls[1] &= ~0x80;
if(keyboard_get_key(DIK_Y))
controls.game_controls[1] &= ~0x40;
if(keyboard_get_key(DIK_U))
controls.game_controls[1] &= ~0x20;
if(keyboard_get_key(DIK_I))
controls.game_controls[1] &= ~0x10;
if(keyboard_get_key(DIK_Z)) // VON2, shot trigger 1
controls.game_controls[0] &= ~0x01;
if(keyboard_get_key(DIK_X)) // VON2, shot trigger 2
controls.game_controls[1] &= ~0x01;
if(keyboard_get_key(DIK_C)) // VON2, turbo 1
controls.game_controls[0] &= ~0x02;
if(keyboard_get_key(DIK_V)) // VON2, turbo 2
controls.game_controls[1] &= ~0x02;
/*if(keyboard_get_key(DIK_UP) || keyboard_get_key(DIK_NUMPAD8)) {
controls.game_controls[0] &= ~0x20; // VON2, forward
controls.game_controls[1] &= ~0x20;
}
if(keyboard_get_key(DIK_DOWN) || keyboard_get_key(DIK_NUMPAD2)) {
controls.game_controls[0] &= ~0x10; // VON2, backward
controls.game_controls[1] &= ~0x10;
}
if(keyboard_get_key(DIK_LEFT) || keyboard_get_key(DIK_NUMPAD4)) {
controls.game_controls[0] &= ~0x10; // VON2, turn left
controls.game_controls[1] &= ~0x20;
}
if(keyboard_get_key(DIK_RIGHT) || keyboard_get_key(DIK_NUMPAD6)) {
controls.game_controls[0] &= ~0x20; // VON2, turn right
controls.game_controls[1] &= ~0x10;
}*/
if(keyboard_get_key(DIK_NUMPAD1)) {// VON2, strafe left
controls.game_controls[0] &= ~0x80;
controls.game_controls[1] &= ~0x80;
}
if(keyboard_get_key(DIK_NUMPAD3)) {// VON2, strafe right
controls.game_controls[0] &= ~0x40;
controls.game_controls[1] &= ~0x40;
}
if(keyboard_get_key(DIK_NUMPAD5)) {// VON2, jump
controls.game_controls[0] &= ~0x80;
controls.game_controls[1] &= ~0x40;
}
// System controls
if(keyboard_get_key(DIK_F1)) { // Test button
controls.system_controls[0] &= ~0x04;
controls.system_controls[1] &= ~0x04;
}
if(keyboard_get_key(DIK_F2)) { // Service button
controls.system_controls[0] &= ~0x08;
controls.system_controls[1] &= ~0x80;
}
if(keyboard_get_key(DIK_F3)) { // Start button
controls.system_controls[0] &= ~0x10;
}
if(keyboard_get_key(DIK_F4)) { // Coin #1
controls.system_controls[0] &= ~0x01;
}
// Steering Wheel
#if 0
if(keyboard_get_key(DIK_LEFT))
controls.steering -= 32;
if(keyboard_get_key(DIK_RIGHT))
controls.steering += 32;
if(controls.steering > 0) {
controls.steering -= 16;
if(controls.steering < 0)
controls.steering = 0;
} else {
controls.steering += 16;
if(controls.steering > 0)
controls.steering = 0;
}
if(controls.steering < -128)
controls.steering = -128;
if(controls.steering > 127)
controls.steering = 127;
if(keyboard_get_key(DIK_UP))
controls.acceleration += 32;
else
controls.acceleration -= 16;
if(controls.acceleration < 0)
controls.acceleration = 0;
if(controls.acceleration > 0xFF)
controls.acceleration = 0xFF;
if(keyboard_get_key(DIK_DOWN))
controls.brake += 32;
else
controls.brake -= 16;
if(controls.brake < 0)
controls.brake = 0;
if(controls.brake > 0xFF)
controls.brake = 0xFF;
#else
/* SWT Force Feedback joystick */
if(keyboard_get_key(DIK_UP))
controls.steering -= 16;
if(keyboard_get_key(DIK_DOWN))
controls.steering += 16;
if(controls.steering < -128)
controls.steering = -128;
if(controls.steering > 127)
controls.steering = 127;
if(keyboard_get_key(DIK_RIGHT)) {
controls.acceleration += 16;
controls.brake -= 16;
}
if(keyboard_get_key(DIK_LEFT)) {
controls.brake += 16;
controls.acceleration -= 16;
}
if(controls.acceleration < 0)
controls.acceleration = 0;
if(controls.acceleration > 0xFF)
controls.acceleration = 0xFF;
if(controls.brake < 0)
controls.brake = 0;
if(controls.brake > 0xFF)
controls.brake = 0xFF;
#endif
return &controls;
}

463
win32/win_main.c Normal file
View file

@ -0,0 +1,463 @@
/*
* Sega Model 3 Emulator
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* 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 (license.txt); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/******************************************************************/
/* Windows Main */
/******************************************************************/
#include "model3.h"
#ifdef RENDERER_D3D
#include "dx_render.h"
#else // RENDERER_GL
#include "win_gl.h"
#endif
#define XRES (496)
#define YRES (384)
static CHAR app_title[] = "Supermodel";
static CHAR app_version[] = "1.0";
static CHAR class_name[] = "MODEL3";
static CHAR CONFIG_FILE[] = "config.xml";
HWND main_window;
// Window Procedure prototype
static LRESULT CALLBACK win_window_proc(HWND, UINT, WPARAM, LPARAM);
static BOOL win_register_class(void)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = (WNDPROC)win_window_proc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = GetModuleHandle(NULL);
wcex.hIcon = NULL;
wcex.hIconSm = NULL;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = class_name;
if (FAILED(RegisterClassEx(&wcex))) // MinGW: "comparison is always false due to limited range of data"
return FALSE;
return TRUE;
}
static BOOL win_create_window(UINT xres, UINT yres)
{
DWORD frame_width, frame_height, caption_height;
int width, height, window_width, window_height;
window_width = xres;
window_height = yres;
frame_width = GetSystemMetrics(SM_CXSIZEFRAME);
frame_height = GetSystemMetrics(SM_CYSIZEFRAME);
caption_height = GetSystemMetrics(SM_CYCAPTION);
width = (window_width - 1) + (frame_width * 2);
height = (window_height - 1) + (frame_height * 2) + caption_height;
main_window = CreateWindow(class_name,
app_title,
WS_CLIPSIBLINGS | WS_CLIPCHILDREN | // required for OpenGL
WS_OVERLAPPED | WS_SYSMENU | WS_MINIMIZEBOX,
CW_USEDEFAULT, CW_USEDEFAULT, // Window X & Y coords
width - 1, height - 1, // Width & Height
NULL, NULL, // Parent Window & Menu
GetModuleHandle(NULL), NULL );
if (!main_window)
return FALSE;
return TRUE;
}
/*
* NOTE: This should actually return an error if something goes wrong, but
* it doesn't matter now. This stuff probably needs to be rewritten anyway ;)
*/
static void win_destroy(void)
{
#ifdef RENDERER_D3D
d3d_shutdown();
#else // RENDERER_GL
win_gl_shutdown();
#endif
DestroyWindow(main_window);
UnregisterClass(class_name, GetModuleHandle(NULL));
}
void *malloc_exec(int length)
{
void *ptr;
ptr = VirtualAlloc(NULL, length, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (ptr == NULL)
{
error("malloc_exec %d failed\n", length);
}
return ptr;
}
void free_exec(void *ptr)
{
if (VirtualFree(ptr, 0, MEM_RELEASE) == FALSE)
{
error("free_exec failed\n");
}
}
BOOL check_cpu_features(void)
{
BOOL features_ok = TRUE;
char cpuname[256];
UINT32 cpu_version;
UINT32 cpu_features;
memset(cpuname, 0, sizeof(cpuname));
__asm
{
// get cpu name string
mov eax, 0x80000002
cpuid
mov dword ptr [cpuname+0 ], eax
mov dword ptr [cpuname+4 ], ebx
mov dword ptr [cpuname+8 ], ecx
mov dword ptr [cpuname+12 ], edx
mov eax, 0x80000003
cpuid
mov dword ptr [cpuname+16 ], eax
mov dword ptr [cpuname+20 ], ebx
mov dword ptr [cpuname+24 ], ecx
mov dword ptr [cpuname+28 ], edx
mov eax, 0x80000004
cpuid
mov dword ptr [cpuname+32 ], eax
mov dword ptr [cpuname+36 ], ebx
mov dword ptr [cpuname+40 ], ecx
mov dword ptr [cpuname+44 ], edx
// get cpu version and features
mov eax, 1
cpuid
mov [cpu_version], eax
mov [cpu_features], edx
}
message(0, "CPU: %s", cpuname);
if ((cpu_features & (1 << 15)) == 0)
{
message(0, "CPU doesn't support Conditional Move/Compare instructions");
features_ok = FALSE;
}
if ((cpu_features & (1 << 23)) == 0)
{
message(0, "CPU doesn't support MMX instructions");
features_ok = FALSE;
}
if ((cpu_features & (1 << 25)) == 0)
{
message(0, "CPU doesn't support SSE instructions");
features_ok = FALSE;
}
if ((cpu_features & (1 << 26)) == 0)
{
message(0, "CPU doesn't support SSE2 instructions");
features_ok = FALSE;
}
if (features_ok == FALSE)
{
message(0, "The CPU doesn't meet the requirements, the program will not run further.");
}
return features_ok;
}
int main(int argc, char *argv[])
{
MSG msg;
BOOL quit = FALSE, do_fps;
INT64 freq, time_start, time_end;
char title[256];
double fps = 0.0;
int frame = 0;
if(argc < 2) {
// Show usage
printf("ERROR: not enough arguments.\n\n");
printf("Usage: m3.exe [romset]\n");
return 0;
}
message(0, "%s v%s\n", app_title, app_version);
if (check_cpu_features() == FALSE)
{
exit(1);
}
if (d3d_pre_init() == FALSE)
{
message(0, "The video card doesn't meet the requirements, the program will not run further.");
exit(1);
}
message(0, "");
// Load config
if (parse_config(CONFIG_FILE) == FALSE)
{
exit(1);
}
m3_config.layer_enable = 0xF;
// Parse command-line
strncpy(m3_config.game_id, argv[1], 8);
m3_config.game_id[8] = '\0'; // in case game name was 8 or more chars
if (stricmp(m3_config.game_id, "lostwsga") == 0)
{
m3_config.has_lightgun = TRUE;
}
// Some initialization
if (!win_register_class())
{
message(0, "win_register_class failed.");
exit(1);
}
if (!win_create_window(XRES, YRES))
{
message(0, "win_create_window failed.");
exit(1);
}
if (model3_load() == FALSE)
{
message(0, "ROM loading failed");
exit(1);
}
model3_init();
model3_reset();
if (!d3d_init(main_window))
{
message(0, "d3d_init failed.");
exit(1);
}
if (osd_input_init() == FALSE)
{
exit(1);
}
// Set window title to show the game name
sprintf(title, "%s: %s", app_title, m3_config.game_name);
SetWindowText(main_window, title);
// Now that everything works, we can show the window
ShowWindow(main_window, SW_SHOWNORMAL);
SetForegroundWindow(main_window);
SetFocus(main_window);
UpdateWindow(main_window);
if (m3_config.fullscreen && !m3_config.has_lightgun)
{
ShowCursor(FALSE);
}
if(QueryPerformanceFrequency((LARGE_INTEGER *)&freq))
do_fps = TRUE;
else
do_fps = FALSE;
memset(&msg, 0, sizeof(MSG));
while (quit == FALSE)
{
//QueryPerformanceCounter((LARGE_INTEGER *)&time_start);
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
quit = TRUE;
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
model3_run_frame();
frame++;
// gather profiler stats
//QueryPerformanceCounter((LARGE_INTEGER *)&time_end);
if (frame >= 5)
{
frame = 0;
QueryPerformanceCounter((LARGE_INTEGER *)&time_end);
fps = 5.0 / ((double)(time_end - time_start) / freq);
time_start = time_end;
}
if (m3_config.show_fps)
{
//fps = 1.0 / ((double)(time_end - time_start) / freq);
sprintf(title, "FPS: %.3f", fps);
osd_renderer_draw_text(2, 2, title, 0xffff0000, TRUE);
}
//osd_renderer_draw_text(2, 2, title, 0x00ff0000, TRUE);
osd_renderer_blit();
#ifdef _PROFILE_
profile_print(prof);
printf(prof);
#endif
}
//for (i = 0; i < 32; i += 4)
// printf("R%d=%08X\tR%d=%08X\tR%d=%08X\tR%d=%08X\n",
// i + 0, ppc_get_reg(PPC_REG_R0 + i + 0),
// i + 1, ppc_get_reg(PPC_REG_R0 + i + 1),
// i + 2, ppc_get_reg(PPC_REG_R0 + i + 2),
// i + 3, ppc_get_reg(PPC_REG_R0 + i + 3));
exit(0);
}
void osd_warning()
{
}
void osd_error(CHAR * string)
{
printf("ERROR: %s\n",string);
exit(0);
}
static LRESULT CALLBACK win_window_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
CHAR fname[13];
static UINT xres = 496, yres = 384;
switch(message)
{
case WM_DESTROY:
{
PostQuitMessage(0);
break;
}
case WM_KEYDOWN:
{
switch (wParam)
{
default:
break;
case '7':
m3_config.layer_enable ^= 1;
break;
case '8':
m3_config.layer_enable ^= 2;
break;
case '9':
m3_config.layer_enable ^= 4;
break;
case '0':
m3_config.layer_enable ^= 8;
break;
case 0x36:
m3_config.layer_enable = 0xF;
break;
case VK_ESCAPE:
DestroyWindow(hWnd);
break;
/*case VK_F7:
strncpy(fname, m3_config.game_id, 8);
fname[8] = '\0';
strcat(fname, ".sta");
model3_save_state(fname);
break;
case VK_F8:
strncpy(fname, m3_config.game_id, 8);
fname[8] = '\0';
strcat(fname, ".sta");
model3_load_state(fname);
break;*/
}
break;
}
case WM_KEYUP:
{
switch (wParam)
{
default:
break;
case VK_F11:
{
if (m3_config.fps_limit)
{
m3_config.fps_limit = FALSE;
}
else
{
m3_config.fps_limit = TRUE;
}
break;
}
case VK_F12:
{
if (m3_config.show_fps)
{
m3_config.show_fps = FALSE;
}
else
{
m3_config.show_fps = TRUE;
}
break;
}
break;
}
}
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}

463
win32/win_xinput.c Normal file
View file

@ -0,0 +1,463 @@
/*
* Sega Model 3 Emulator
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* 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 (license.txt); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/******************************************************************/
/* XInput for Xbox360 controller */
/******************************************************************/
#include "MODEL3.H"
#include <dinput.h>
#include <xinput.h>
static LPDIRECTINPUT8 dinput;
static LPDIRECTINPUTDEVICE8 keyboard;
static LPDIRECTINPUTDEVICE8 mouse;
static CHAR keyboard_buffer[256];
static DIMOUSESTATE mouse_state;
extern HWND main_window;
static OSD_CONTROLS controls;
static int xbox_controllers[4];
static int analog_axis[8];
static BOOL button_state[16];
static struct
{
BOOL up, down, left, right;
} joystick[4];
BOOL osd_input_init(void)
{
HINSTANCE hinstance;
HRESULT hr;
DWORD result;
XINPUT_STATE state;
atexit(osd_input_shutdown);
hinstance = GetModuleHandle(NULL);
hr = DirectInput8Create( hinstance, DIRECTINPUT_VERSION, &IID_IDirectInput8,
(void**)&dinput, NULL );
if (FAILED(hr))
{
message(0, "DirectInput8Create failed.");
return FALSE;
}
// Create keyboard device
hr = IDirectInput8_CreateDevice( dinput, &GUID_SysKeyboard, &keyboard, NULL );
if (FAILED(hr))
{
message(0, "IDirectInput8_CreateDevice failed.");
return FALSE;
}
hr = IDirectInputDevice8_SetDataFormat( keyboard, &c_dfDIKeyboard );
if (FAILED(hr))
{
message(0, "IDirectInputDevice8_SetDataFormat failed.");
return FALSE;
}
hr = IDirectInputDevice8_SetCooperativeLevel( keyboard, main_window, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE );
if (FAILED(hr))
{
message(0, "IDirectInputDevice8_SetCooperativeLevel failed.");
return FALSE;
}
if (keyboard)
{
IDirectInputDevice8_Acquire( keyboard );
}
// Create mouse device
hr = IDirectInput8_CreateDevice( dinput, &GUID_SysMouse, &mouse, NULL );
if (FAILED(hr))
{
message(0, "IDirectInput8_CreateDevice failed.");
return FALSE;
}
hr = IDirectInputDevice8_SetDataFormat( mouse, &c_dfDIMouse );
if (FAILED(hr))
{
message(0, "IDirectInputDevice8_SetDataFormat failed.");
return FALSE;
}
hr = IDirectInputDevice8_SetCooperativeLevel( mouse, main_window, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE );
if (FAILED(hr))
{
message(0, "IDirectInputDevice8_SetCooperativeLevel failed.");
return FALSE;
}
// Init Xbox360 controllers
ZeroMemory(&state, sizeof(XINPUT_STATE));
// Simply get the state of the controller from XInput.
result = XInputGetState(0, &state);
if (result == ERROR_SUCCESS)
{
// Controller is connected
xbox_controllers[0] = 1;
message(0, "Xbox360 controller found!");
}
else
{
// Controller is not connected
xbox_controllers[0] = 0;
}
return TRUE;
}
void osd_input_shutdown(void)
{
if(dinput)
{
if(keyboard)
{
IDirectInputDevice8_Unacquire( keyboard );
IDirectInputDevice8_Release( keyboard );
keyboard = NULL;
}
if(mouse)
{
IDirectInputDevice8_Unacquire( mouse );
IDirectInputDevice8_Release( mouse );
mouse = NULL;
}
IDirectInput8_Release( dinput );
dinput = NULL;
}
}
static void input_update(void)
{
/* updates the input buffer */
if(dinput)
{
// Get keyboard state
IDirectInputDevice8_GetDeviceState( keyboard, sizeof(keyboard_buffer), &keyboard_buffer );
// Get mouse state
IDirectInputDevice8_Acquire( mouse );
IDirectInputDevice8_GetDeviceState( mouse, sizeof(mouse_state), &mouse_state );
}
}
static BOOL keyboard_get_key(UINT8 key)
{
if (keyboard_buffer[key] & 0x80)
{
return TRUE;
}
else
{
return FALSE;
}
}
static BOOL mouse_get_button(UINT8 button)
{
if (mouse_state.rgbButtons[button] & 0x80)
{
return TRUE;
}
else
{
return FALSE;
}
}
static void mouse_get_position(INT32* xposition, INT32* yposition)
{
POINT mouse_pos;
GetCursorPos( &mouse_pos );
ScreenToClient( main_window, &mouse_pos );
*xposition = mouse_pos.x;
*yposition = mouse_pos.y;
}
static void update_controls_keyboard(void)
{
memset(button_state, 0, sizeof(button_state));
memset(joystick, 0, sizeof(joystick));
if (keyboard_get_key(DIK_A)) button_state[0] = 1;
if (keyboard_get_key(DIK_S)) button_state[1] = 1;
if (keyboard_get_key(DIK_D)) button_state[2] = 1;
if (keyboard_get_key(DIK_F)) button_state[3] = 1;
if (keyboard_get_key(DIK_Z)) button_state[4] = 1;
if (keyboard_get_key(DIK_X)) button_state[5] = 1;
if (keyboard_get_key(DIK_C)) button_state[6] = 1;
if (keyboard_get_key(DIK_V)) button_state[7] = 1;
if (keyboard_get_key(DIK_LEFT)) joystick[0].left = TRUE;
if (keyboard_get_key(DIK_RIGHT)) joystick[0].right = TRUE;
if (keyboard_get_key(DIK_UP)) joystick[0].up = TRUE;
if (keyboard_get_key(DIK_DOWN)) joystick[0].down = TRUE;
if (keyboard_get_key(DIK_LEFT)) analog_axis[0] -= 16;
if (keyboard_get_key(DIK_RIGHT)) analog_axis[0] += 16;
if (keyboard_get_key(DIK_UP)) analog_axis[1] -= 16;
if (keyboard_get_key(DIK_DOWN)) analog_axis[1] += 16;
if (analog_axis[0] < -128) analog_axis[0] = -128;
if (analog_axis[0] > 127) analog_axis[0] = 127;
if (analog_axis[1] < -128) analog_axis[1] = -128;
if (analog_axis[1] > 127) analog_axis[1] = 127;
}
static void update_controls_xbox(void)
{
XINPUT_STATE state;
DWORD res;
memset(button_state, 0, sizeof(button_state));
memset(analog_axis, 0, sizeof(analog_axis));
memset(joystick, 0, sizeof(joystick));
res = XInputGetState(0, &state);
if (res == ERROR_SUCCESS)
{
// Zero value if thumbsticks are within the dead zone
if ((state.Gamepad.sThumbLX < XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE &&
state.Gamepad.sThumbLX > -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE))
{
state.Gamepad.sThumbLX = 0;
}
if ((state.Gamepad.sThumbLY < XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE &&
state.Gamepad.sThumbLY > -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE))
{
state.Gamepad.sThumbLY = 0;
}
if ((state.Gamepad.sThumbRX < XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE &&
state.Gamepad.sThumbRX > -XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE))
{
state.Gamepad.sThumbRX = 0;
}
if ((state.Gamepad.sThumbRY < XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE &&
state.Gamepad.sThumbRY > -XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE))
{
state.Gamepad.sThumbRY = 0;
}
if (state.Gamepad.wButtons & XINPUT_GAMEPAD_A) button_state[0] = TRUE;
if (state.Gamepad.wButtons & XINPUT_GAMEPAD_B) button_state[1] = TRUE;
if (state.Gamepad.wButtons & XINPUT_GAMEPAD_X) button_state[2] = TRUE;
if (state.Gamepad.wButtons & XINPUT_GAMEPAD_Y) button_state[3] = TRUE;
if (state.Gamepad.sThumbLX < 0) joystick[0].left = TRUE;
if (state.Gamepad.sThumbLX > 0) joystick[0].right = TRUE;
if (state.Gamepad.sThumbLY < 0) joystick[0].up = TRUE;
if (state.Gamepad.sThumbLY > 0) joystick[0].down = TRUE;
analog_axis[0] = state.Gamepad.sThumbLX / 256;
analog_axis[1] = state.Gamepad.sThumbLY / 256;
analog_axis[2] = state.Gamepad.bRightTrigger;
analog_axis[3] = state.Gamepad.bLeftTrigger;
analog_axis[4] = state.Gamepad.sThumbRX;
analog_axis[5] = state.Gamepad.sThumbRY;
}
}
static int get_analog_axis(GAME_ANALOG axis)
{
switch (axis)
{
case ANALOG_AXIS_1: return analog_axis[0];
case ANALOG_AXIS_2: return analog_axis[1];
case ANALOG_AXIS_3: return analog_axis[2];
case ANALOG_AXIS_4: return analog_axis[3];
case ANALOG_AXIS_5: return analog_axis[4];
case ANALOG_AXIS_6: return analog_axis[5];
case ANALOG_AXIS_7: return analog_axis[6];
case ANALOG_AXIS_8: return analog_axis[7];
}
return 0;
}
static BOOL is_button_pressed(GAME_BUTTON button)
{
switch (button)
{
case P1_BUTTON_1: return button_state[0];
case P1_BUTTON_2: return button_state[1];
case P1_BUTTON_3: return button_state[2];
case P1_BUTTON_4: return button_state[3];
case P1_BUTTON_5: return button_state[4];
case P1_BUTTON_6: return button_state[5];
case P1_BUTTON_7: return button_state[6];
case P1_BUTTON_8: return button_state[7];
case P2_BUTTON_1: return button_state[8];
case P2_BUTTON_2: return button_state[9];
case P2_BUTTON_3: return button_state[10];
case P2_BUTTON_4: return button_state[11];
case P2_BUTTON_5: return button_state[12];
case P2_BUTTON_6: return button_state[13];
case P2_BUTTON_7: return button_state[14];
case P2_BUTTON_8: return button_state[15];
case P1_JOYSTICK_UP: return joystick[0].up;
case P1_JOYSTICK_DOWN: return joystick[0].down;
case P1_JOYSTICK_LEFT: return joystick[0].left;
case P1_JOYSTICK_RIGHT: return joystick[0].right;
}
return FALSE;
}
OSD_CONTROLS* osd_input_update_controls(void)
{
int i;
INT32 mouse_x, mouse_y;
input_update();
controls.game_controls[0] = 0xFF;
controls.game_controls[1] = 0xFF;
controls.system_controls[0] = 0xFF;
controls.system_controls[1] = 0xFF;
// Lightgun
if(mouse_get_button(0))
controls.game_controls[0] &= ~0x01;
if(mouse_get_button(1))
controls.gun_acquired[0] = TRUE;
else
controls.gun_acquired[0] = FALSE;
mouse_get_position(&mouse_x, &mouse_y);
if (!m3_config.fullscreen)
{
controls.gun_x[0] = mouse_x + (400 - (MODEL3_SCREEN_WIDTH / 2));
controls.gun_y[0] = mouse_y + (272 - (MODEL3_SCREEN_HEIGHT / 2));
}
else
{
if (m3_config.stretch)
{
mouse_x = (mouse_x * 496) / m3_config.width;
mouse_y = (mouse_y * 384) / m3_config.height;
}
controls.gun_x[0] = mouse_x + (400 - (MODEL3_SCREEN_WIDTH / 2));
controls.gun_y[0] = mouse_y + (272 - (MODEL3_SCREEN_HEIGHT / 2));
}
// Game controls
if (xbox_controllers[0])
{
update_controls_xbox();
}
else
{
update_controls_keyboard();
}
// update button states
for (i=0; i < 16; i++)
{
if (m3_config.controls.button[i].enabled)
{
if (is_button_pressed(m3_config.controls.button[i].mapping))
{
int set = m3_config.controls.button[i].control_set;
controls.game_controls[set] &= ~m3_config.controls.button[i].control_bit;
}
}
}
// update analog controls
for (i=0; i < 8; i++)
{
if (m3_config.controls.analog_axis[i].enabled)
{
int value = get_analog_axis(m3_config.controls.analog_axis[i].mapping);
value += m3_config.controls.analog_axis[i].center;
controls.analog_axis[i] = value;
}
}
// Lightgun hack for Star Wars Trilogy
if (stricmp(m3_config.game_id, "swtrilgy") == 0)
{
mouse_get_position(&mouse_x, &mouse_y);
mouse_x = (mouse_x * 256) / ((m3_config.fullscreen) ? m3_config.width : 496);
mouse_y = (mouse_y * 256) / ((m3_config.fullscreen) ? m3_config.height : 384);
controls.analog_axis[0] = mouse_y;
controls.analog_axis[1] = mouse_x;
if (mouse_get_button(1))
controls.game_controls[0] &= ~0x01;
if (mouse_get_button(0))
controls.game_controls[0] &= ~0x20;
}
// System controls
if (keyboard_get_key(DIK_F1)) // Service button
{
controls.system_controls[0] &= ~0x08;
}
if (keyboard_get_key(DIK_F2)) // Test button
{
controls.system_controls[0] &= ~0x04;
}
if (keyboard_get_key(DIK_F3)) // Service button B
{
controls.system_controls[1] &= ~0x40;
}
if (keyboard_get_key(DIK_F4)) // Test button B
{
controls.system_controls[1] &= ~0x80;
}
if (keyboard_get_key(DIK_1)) // Start button 1
{
controls.system_controls[0] &= ~0x10;
}
if (keyboard_get_key(DIK_2)) // Start button 2
{
controls.system_controls[0] &= ~0x20;
}
if (keyboard_get_key(DIK_5)) // Coin #1
{
controls.system_controls[0] &= ~0x01;
}
if (keyboard_get_key(DIK_6)) // Coin #2
{
controls.system_controls[0] &= ~0x02;
}
return &controls;
}

722
zlib/ChangeLog Normal file
View file

@ -0,0 +1,722 @@
ChangeLog file for zlib
Changes in 1.2.1 (17 November 2003)
- Remove a tab in contrib/gzappend/gzappend.c
- Update some interfaces in contrib for new zlib functions
- Update zlib version number in some contrib entries
- Add Windows CE definition for ptrdiff_t in zutil.h [Mai, Truta]
- Support shared libraries on Hurd and KFreeBSD [Brown]
- Fix error in NO_DIVIDE option of adler32.c
Changes in 1.2.0.8 (4 November 2003)
- Update version in contrib/delphi/ZLib.pas and contrib/pascal/zlibpas.pas
- Add experimental NO_DIVIDE #define in adler32.c
- Possibly faster on some processors (let me know if it is)
- Correct Z_BLOCK to not return on first inflate call if no wrap
- Fix strm->data_type on inflate() return to correctly indicate EOB
- Add deflatePrime() function for appending in the middle of a byte
- Add contrib/gzappend for an example of appending to a stream
- Update win32/DLL_FAQ.txt [Truta]
- Delete Turbo C comment in README [Truta]
- Improve some indentation in zconf.h [Truta]
- Fix infinite loop on bad input in configure script [Church]
- Fix gzeof() for concatenated gzip files [Johnson]
- Add example to contrib/visual-basic.txt [Michael B.]
- Add -p to mkdir's in Makefile.in [vda]
- Fix configure to properly detect presence or lack of printf functions
- Add AS400 support [Monnerat]
- Add a little Cygwin support [Wilson]
Changes in 1.2.0.7 (21 September 2003)
- Correct some debug formats in contrib/infback9
- Cast a type in a debug statement in trees.c
- Change search and replace delimiter in configure from % to # [Beebe]
- Update contrib/untgz to 0.2 with various fixes [Truta]
- Add build support for Amiga [Nikl]
- Remove some directories in old that have been updated to 1.2
- Add dylib building for Mac OS X in configure and Makefile.in
- Remove old distribution stuff from Makefile
- Update README to point to DLL_FAQ.txt, and add comment on Mac OS X
- Update links in README
Changes in 1.2.0.6 (13 September 2003)
- Minor FAQ updates
- Update contrib/minizip to 1.00 [Vollant]
- Remove test of gz functions in example.c when GZ_COMPRESS defined [Truta]
- Update POSTINC comment for 68060 [Nikl]
- Add contrib/infback9 with deflate64 decoding (unsupported)
- For MVS define NO_vsnprintf and undefine FAR [van Burik]
- Add pragma for fdopen on MVS [van Burik]
Changes in 1.2.0.5 (8 September 2003)
- Add OF to inflateBackEnd() declaration in zlib.h
- Remember start when using gzdopen in the middle of a file
- Use internal off_t counters in gz* functions to properly handle seeks
- Perform more rigorous check for distance-too-far in inffast.c
- Add Z_BLOCK flush option to return from inflate at block boundary
- Set strm->data_type on return from inflate
- Indicate bits unused, if at block boundary, and if in last block
- Replace size_t with ptrdiff_t in crc32.c, and check for correct size
- Add condition so old NO_DEFLATE define still works for compatibility
- FAQ update regarding the Windows DLL [Truta]
- INDEX update: add qnx entry, remove aix entry [Truta]
- Install zlib.3 into mandir [Wilson]
- Move contrib/zlib_dll_FAQ.txt to win32/DLL_FAQ.txt; update [Truta]
- Adapt the zlib interface to the new DLL convention guidelines [Truta]
- Introduce ZLIB_WINAPI macro to allow the export of functions using
the WINAPI calling convention, for Visual Basic [Vollant, Truta]
- Update msdos and win32 scripts and makefiles [Truta]
- Export symbols by name, not by ordinal, in win32/zlib.def [Truta]
- Add contrib/ada [Anisimkov]
- Move asm files from contrib/vstudio/vc70_32 to contrib/asm386 [Truta]
- Rename contrib/asm386 to contrib/masmx86 [Truta, Vollant]
- Add contrib/masm686 [Truta]
- Fix offsets in contrib/inflate86 and contrib/masmx86/inffas32.asm
[Truta, Vollant]
- Update contrib/delphi; rename to contrib/pascal; add example [Truta]
- Remove contrib/delphi2; add a new contrib/delphi [Truta]
- Avoid inclusion of the nonstandard <memory.h> in contrib/iostream,
and fix some method prototypes [Truta]
- Fix the ZCR_SEED2 constant to avoid warnings in contrib/minizip
[Truta]
- Avoid the use of backslash (\) in contrib/minizip [Vollant]
- Fix file time handling in contrib/untgz; update makefiles [Truta]
- Update contrib/vstudio/vc70_32 to comply with the new DLL guidelines
[Vollant]
- Remove contrib/vstudio/vc15_16 [Vollant]
- Rename contrib/vstudio/vc70_32 to contrib/vstudio/vc7 [Truta]
- Update README.contrib [Truta]
- Invert the assignment order of match_head and s->prev[...] in
INSERT_STRING [Truta]
- Compare TOO_FAR with 32767 instead of 32768, to avoid 16-bit warnings
[Truta]
- Compare function pointers with 0, not with NULL or Z_NULL [Truta]
- Fix prototype of syncsearch in inflate.c [Truta]
- Introduce ASMINF macro to be enabled when using an ASM implementation
of inflate_fast [Truta]
- Change NO_DEFLATE to NO_GZCOMPRESS [Truta]
- Modify test_gzio in example.c to take a single file name as a
parameter [Truta]
- Exit the example.c program if gzopen fails [Truta]
- Add type casts around strlen in example.c [Truta]
- Remove casting to sizeof in minigzip.c; give a proper type
to the variable compared with SUFFIX_LEN [Truta]
- Update definitions of STDC and STDC99 in zconf.h [Truta]
- Synchronize zconf.h with the new Windows DLL interface [Truta]
- Use SYS16BIT instead of __32BIT__ to distinguish between
16- and 32-bit platforms [Truta]
- Use far memory allocators in small 16-bit memory models for
Turbo C [Truta]
- Add info about the use of ASMV, ASMINF and ZLIB_WINAPI in
zlibCompileFlags [Truta]
- Cygwin has vsnprintf [Wilson]
- In Windows16, OS_CODE is 0, as in MSDOS [Truta]
- In Cygwin, OS_CODE is 3 (Unix), not 11 (Windows32) [Wilson]
Changes in 1.2.0.4 (10 August 2003)
- Minor FAQ updates
- Be more strict when checking inflateInit2's windowBits parameter
- Change NO_GUNZIP compile option to NO_GZIP to cover deflate as well
- Add gzip wrapper option to deflateInit2 using windowBits
- Add updated QNX rule in configure and qnx directory [Bonnefoy]
- Make inflate distance-too-far checks more rigorous
- Clean up FAR usage in inflate
- Add casting to sizeof() in gzio.c and minigzip.c
Changes in 1.2.0.3 (19 July 2003)
- Fix silly error in gzungetc() implementation [Vollant]
- Update contrib/minizip and contrib/vstudio [Vollant]
- Fix printf format in example.c
- Correct cdecl support in zconf.in.h [Anisimkov]
- Minor FAQ updates
Changes in 1.2.0.2 (13 July 2003)
- Add ZLIB_VERNUM in zlib.h for numerical preprocessor comparisons
- Attempt to avoid warnings in crc32.c for pointer-int conversion
- Add AIX to configure, remove aix directory [Bakker]
- Add some casts to minigzip.c
- Improve checking after insecure sprintf() or vsprintf() calls
- Remove #elif's from crc32.c
- Change leave label to inf_leave in inflate.c and infback.c to avoid
library conflicts
- Remove inflate gzip decoding by default--only enable gzip decoding by
special request for stricter backward compatibility
- Add zlibCompileFlags() function to return compilation information
- More typecasting in deflate.c to avoid warnings
- Remove leading underscore from _Capital #defines [Truta]
- Fix configure to link shared library when testing
- Add some Windows CE target adjustments [Mai]
- Remove #define ZLIB_DLL in zconf.h [Vollant]
- Add zlib.3 [Rodgers]
- Update RFC URL in deflate.c and algorithm.txt [Mai]
- Add zlib_dll_FAQ.txt to contrib [Truta]
- Add UL to some constants [Truta]
- Update minizip and vstudio [Vollant]
- Remove vestigial NEED_DUMMY_RETURN from zconf.in.h
- Expand use of NO_DUMMY_DECL to avoid all dummy structures
- Added iostream3 to contrib [Schwardt]
- Replace rewind() with fseek() for WinCE [Truta]
- Improve setting of zlib format compression level flags
- Report 0 for huffman and rle strategies and for level == 0 or 1
- Report 2 only for level == 6
- Only deal with 64K limit when necessary at compile time [Truta]
- Allow TOO_FAR check to be turned off at compile time [Truta]
- Add gzclearerr() function [Souza]
- Add gzungetc() function
Changes in 1.2.0.1 (17 March 2003)
- Add Z_RLE strategy for run-length encoding [Truta]
- When Z_RLE requested, restrict matches to distance one
- Update zlib.h, minigzip.c, gzopen(), gzdopen() for Z_RLE
- Correct FASTEST compilation to allow level == 0
- Clean up what gets compiled for FASTEST
- Incorporate changes to zconf.in.h [Vollant]
- Refine detection of Turbo C need for dummy returns
- Refine ZLIB_DLL compilation
- Include additional header file on VMS for off_t typedef
- Try to use _vsnprintf where it supplants vsprintf [Vollant]
- Add some casts in inffast.c
- Enchance comments in zlib.h on what happens if gzprintf() tries to
write more than 4095 bytes before compression
- Remove unused state from inflateBackEnd()
- Remove exit(0) from minigzip.c, example.c
- Get rid of all those darn tabs
- Add "check" target to Makefile.in that does the same thing as "test"
- Add "mostlyclean" and "maintainer-clean" targets to Makefile.in
- Update contrib/inflate86 [Anderson]
- Update contrib/testzlib, contrib/vstudio, contrib/minizip [Vollant]
- Add msdos and win32 directories with makefiles [Truta]
- More additions and improvements to the FAQ
Changes in 1.2.0 (9 March 2003)
- New and improved inflate code
- About 20% faster
- Does not allocate 32K window unless and until needed
- Automatically detects and decompresses gzip streams
- Raw inflate no longer needs an extra dummy byte at end
- Added inflateBack functions using a callback interface--even faster
than inflate, useful for file utilities (gzip, zip)
- Added inflateCopy() function to record state for random access on
externally generated deflate streams (e.g. in gzip files)
- More readable code (I hope)
- New and improved crc32()
- About 50% faster, thanks to suggestions from Rodney Brown
- Add deflateBound() and compressBound() functions
- Fix memory leak in deflateInit2()
- Permit setting dictionary for raw deflate (for parallel deflate)
- Fix const declaration for gzwrite()
- Check for some malloc() failures in gzio.c
- Fix bug in gzopen() on single-byte file 0x1f
- Fix bug in gzread() on concatenated file with 0x1f at end of buffer
and next buffer doesn't start with 0x8b
- Fix uncompress() to return Z_DATA_ERROR on truncated input
- Free memory at end of example.c
- Remove MAX #define in trees.c (conflicted with some libraries)
- Fix static const's in deflate.c, gzio.c, and zutil.[ch]
- Declare malloc() and free() in gzio.c if STDC not defined
- Use malloc() instead of calloc() in zutil.c if int big enough
- Define STDC for AIX
- Add aix/ with approach for compiling shared library on AIX
- Add HP-UX support for shared libraries in configure
- Add OpenUNIX support for shared libraries in configure
- Use $cc instead of gcc to build shared library
- Make prefix directory if needed when installing
- Correct Macintosh avoidance of typedef Byte in zconf.h
- Correct Turbo C memory allocation when under Linux
- Use libz.a instead of -lz in Makefile (assure use of compiled library)
- Update configure to check for snprintf or vsnprintf functions and their
return value, warn during make if using an insecure function
- Fix configure problem with compile-time knowledge of HAVE_UNISTD_H that
is lost when library is used--resolution is to build new zconf.h
- Documentation improvements (in zlib.h):
- Document raw deflate and inflate
- Update RFCs URL
- Point out that zlib and gzip formats are different
- Note that Z_BUF_ERROR is not fatal
- Document string limit for gzprintf() and possible buffer overflow
- Note requirement on avail_out when flushing
- Note permitted values of flush parameter of inflate()
- Add some FAQs (and even answers) to the FAQ
- Add contrib/inflate86/ for x86 faster inflate
- Add contrib/blast/ for PKWare Data Compression Library decompression
- Add contrib/puff/ simple inflate for deflate format description
Changes in 1.1.4 (11 March 2002)
- ZFREE was repeated on same allocation on some error conditions.
This creates a security problem described in
http://www.zlib.org/advisory-2002-03-11.txt
- Returned incorrect error (Z_MEM_ERROR) on some invalid data
- Avoid accesses before window for invalid distances with inflate window
less than 32K.
- force windowBits > 8 to avoid a bug in the encoder for a window size
of 256 bytes. (A complete fix will be available in 1.1.5).
Changes in 1.1.3 (9 July 1998)
- fix "an inflate input buffer bug that shows up on rare but persistent
occasions" (Mark)
- fix gzread and gztell for concatenated .gz files (Didier Le Botlan)
- fix gzseek(..., SEEK_SET) in write mode
- fix crc check after a gzeek (Frank Faubert)
- fix miniunzip when the last entry in a zip file is itself a zip file
(J Lillge)
- add contrib/asm586 and contrib/asm686 (Brian Raiter)
See http://www.muppetlabs.com/~breadbox/software/assembly.html
- add support for Delphi 3 in contrib/delphi (Bob Dellaca)
- add support for C++Builder 3 and Delphi 3 in contrib/delphi2 (Davide Moretti)
- do not exit prematurely in untgz if 0 at start of block (Magnus Holmgren)
- use macro EXTERN instead of extern to support DLL for BeOS (Sander Stoks)
- added a FAQ file
- Support gzdopen on Mac with Metrowerks (Jason Linhart)
- Do not redefine Byte on Mac (Brad Pettit & Jason Linhart)
- define SEEK_END too if SEEK_SET is not defined (Albert Chin-A-Young)
- avoid some warnings with Borland C (Tom Tanner)
- fix a problem in contrib/minizip/zip.c for 16-bit MSDOS (Gilles Vollant)
- emulate utime() for WIN32 in contrib/untgz (Gilles Vollant)
- allow several arguments to configure (Tim Mooney, Frodo Looijaard)
- use libdir and includedir in Makefile.in (Tim Mooney)
- support shared libraries on OSF1 V4 (Tim Mooney)
- remove so_locations in "make clean" (Tim Mooney)
- fix maketree.c compilation error (Glenn, Mark)
- Python interface to zlib now in Python 1.5 (Jeremy Hylton)
- new Makefile.riscos (Rich Walker)
- initialize static descriptors in trees.c for embedded targets (Nick Smith)
- use "foo-gz" in example.c for RISCOS and VMS (Nick Smith)
- add the OS/2 files in Makefile.in too (Andrew Zabolotny)
- fix fdopen and halloc macros for Microsoft C 6.0 (Tom Lane)
- fix maketree.c to allow clean compilation of inffixed.h (Mark)
- fix parameter check in deflateCopy (Gunther Nikl)
- cleanup trees.c, use compressed_len only in debug mode (Christian Spieler)
- Many portability patches by Christian Spieler:
. zutil.c, zutil.h: added "const" for zmem*
. Make_vms.com: fixed some typos
. Make_vms.com: msdos/Makefile.*: removed zutil.h from some dependency lists
. msdos/Makefile.msc: remove "default rtl link library" info from obj files
. msdos/Makefile.*: use model-dependent name for the built zlib library
. msdos/Makefile.emx, nt/Makefile.emx, nt/Makefile.gcc:
new makefiles, for emx (DOS/OS2), emx&rsxnt and mingw32 (Windows 9x / NT)
- use define instead of typedef for Bytef also for MSC small/medium (Tom Lane)
- replace __far with _far for better portability (Christian Spieler, Tom Lane)
- fix test for errno.h in configure (Tim Newsham)
Changes in 1.1.2 (19 March 98)
- added contrib/minzip, mini zip and unzip based on zlib (Gilles Vollant)
See http://www.winimage.com/zLibDll/unzip.html
- preinitialize the inflate tables for fixed codes, to make the code
completely thread safe (Mark)
- some simplifications and slight speed-up to the inflate code (Mark)
- fix gzeof on non-compressed files (Allan Schrum)
- add -std1 option in configure for OSF1 to fix gzprintf (Martin Mokrejs)
- use default value of 4K for Z_BUFSIZE for 16-bit MSDOS (Tim Wegner + Glenn)
- added os2/Makefile.def and os2/zlib.def (Andrew Zabolotny)
- add shared lib support for UNIX_SV4.2MP (MATSUURA Takanori)
- do not wrap extern "C" around system includes (Tom Lane)
- mention zlib binding for TCL in README (Andreas Kupries)
- added amiga/Makefile.pup for Amiga powerUP SAS/C PPC (Andreas Kleinert)
- allow "make install prefix=..." even after configure (Glenn Randers-Pehrson)
- allow "configure --prefix $HOME" (Tim Mooney)
- remove warnings in example.c and gzio.c (Glenn Randers-Pehrson)
- move Makefile.sas to amiga/Makefile.sas
Changes in 1.1.1 (27 Feb 98)
- fix macros _tr_tally_* in deflate.h for debug mode (Glenn Randers-Pehrson)
- remove block truncation heuristic which had very marginal effect for zlib
(smaller lit_bufsize than in gzip 1.2.4) and degraded a little the
compression ratio on some files. This also allows inlining _tr_tally for
matches in deflate_slow.
- added msdos/Makefile.w32 for WIN32 Microsoft Visual C++ (Bob Frazier)
Changes in 1.1.0 (24 Feb 98)
- do not return STREAM_END prematurely in inflate (John Bowler)
- revert to the zlib 1.0.8 inflate to avoid the gcc 2.8.0 bug (Jeremy Buhler)
- compile with -DFASTEST to get compression code optimized for speed only
- in minigzip, try mmap'ing the input file first (Miguel Albrecht)
- increase size of I/O buffers in minigzip.c and gzio.c (not a big gain
on Sun but significant on HP)
- add a pointer to experimental unzip library in README (Gilles Vollant)
- initialize variable gcc in configure (Chris Herborth)
Changes in 1.0.9 (17 Feb 1998)
- added gzputs and gzgets functions
- do not clear eof flag in gzseek (Mark Diekhans)
- fix gzseek for files in transparent mode (Mark Diekhans)
- do not assume that vsprintf returns the number of bytes written (Jens Krinke)
- replace EXPORT with ZEXPORT to avoid conflict with other programs
- added compress2 in zconf.h, zlib.def, zlib.dnt
- new asm code from Gilles Vollant in contrib/asm386
- simplify the inflate code (Mark):
. Replace ZALLOC's in huft_build() with single ZALLOC in inflate_blocks_new()
. ZALLOC the length list in inflate_trees_fixed() instead of using stack
. ZALLOC the value area for huft_build() instead of using stack
. Simplify Z_FINISH check in inflate()
- Avoid gcc 2.8.0 comparison bug a little differently than zlib 1.0.8
- in inftrees.c, avoid cc -O bug on HP (Farshid Elahi)
- in zconf.h move the ZLIB_DLL stuff earlier to avoid problems with
the declaration of FAR (Gilles VOllant)
- install libz.so* with mode 755 (executable) instead of 644 (Marc Lehmann)
- read_buf buf parameter of type Bytef* instead of charf*
- zmemcpy parameters are of type Bytef*, not charf* (Joseph Strout)
- do not redeclare unlink in minigzip.c for WIN32 (John Bowler)
- fix check for presence of directories in "make install" (Ian Willis)
Changes in 1.0.8 (27 Jan 1998)
- fixed offsets in contrib/asm386/gvmat32.asm (Gilles Vollant)
- fix gzgetc and gzputc for big endian systems (Markus Oberhumer)
- added compress2() to allow setting the compression level
- include sys/types.h to get off_t on some systems (Marc Lehmann & QingLong)
- use constant arrays for the static trees in trees.c instead of computing
them at run time (thanks to Ken Raeburn for this suggestion). To create
trees.h, compile with GEN_TREES_H and run "make test".
- check return code of example in "make test" and display result
- pass minigzip command line options to file_compress
- simplifying code of inflateSync to avoid gcc 2.8 bug
- support CC="gcc -Wall" in configure -s (QingLong)
- avoid a flush caused by ftell in gzopen for write mode (Ken Raeburn)
- fix test for shared library support to avoid compiler warnings
- zlib.lib -> zlib.dll in msdos/zlib.rc (Gilles Vollant)
- check for TARGET_OS_MAC in addition to MACOS (Brad Pettit)
- do not use fdopen for Metrowerks on Mac (Brad Pettit))
- add checks for gzputc and gzputc in example.c
- avoid warnings in gzio.c and deflate.c (Andreas Kleinert)
- use const for the CRC table (Ken Raeburn)
- fixed "make uninstall" for shared libraries
- use Tracev instead of Trace in infblock.c
- in example.c use correct compressed length for test_sync
- suppress +vnocompatwarnings in configure for HPUX (not always supported)
Changes in 1.0.7 (20 Jan 1998)
- fix gzseek which was broken in write mode
- return error for gzseek to negative absolute position
- fix configure for Linux (Chun-Chung Chen)
- increase stack space for MSC (Tim Wegner)
- get_crc_table and inflateSyncPoint are EXPORTed (Gilles Vollant)
- define EXPORTVA for gzprintf (Gilles Vollant)
- added man page zlib.3 (Rick Rodgers)
- for contrib/untgz, fix makedir() and improve Makefile
- check gzseek in write mode in example.c
- allocate extra buffer for seeks only if gzseek is actually called
- avoid signed/unsigned comparisons (Tim Wegner, Gilles Vollant)
- add inflateSyncPoint in zconf.h
- fix list of exported functions in nt/zlib.dnt and mdsos/zlib.def
Changes in 1.0.6 (19 Jan 1998)
- add functions gzprintf, gzputc, gzgetc, gztell, gzeof, gzseek, gzrewind and
gzsetparams (thanks to Roland Giersig and Kevin Ruland for some of this code)
- Fix a deflate bug occuring only with compression level 0 (thanks to
Andy Buckler for finding this one).
- In minigzip, pass transparently also the first byte for .Z files.
- return Z_BUF_ERROR instead of Z_OK if output buffer full in uncompress()
- check Z_FINISH in inflate (thanks to Marc Schluper)
- Implement deflateCopy (thanks to Adam Costello)
- make static libraries by default in configure, add --shared option.
- move MSDOS or Windows specific files to directory msdos
- suppress the notion of partial flush to simplify the interface
(but the symbol Z_PARTIAL_FLUSH is kept for compatibility with 1.0.4)
- suppress history buffer provided by application to simplify the interface
(this feature was not implemented anyway in 1.0.4)
- next_in and avail_in must be initialized before calling inflateInit or
inflateInit2
- add EXPORT in all exported functions (for Windows DLL)
- added Makefile.nt (thanks to Stephen Williams)
- added the unsupported "contrib" directory:
contrib/asm386/ by Gilles Vollant <info@winimage.com>
386 asm code replacing longest_match().
contrib/iostream/ by Kevin Ruland <kevin@rodin.wustl.edu>
A C++ I/O streams interface to the zlib gz* functions
contrib/iostream2/ by Tyge Løvset <Tyge.Lovset@cmr.no>
Another C++ I/O streams interface
contrib/untgz/ by "Pedro A. Aranda Guti\irrez" <paag@tid.es>
A very simple tar.gz file extractor using zlib
contrib/visual-basic.txt by Carlos Rios <c_rios@sonda.cl>
How to use compress(), uncompress() and the gz* functions from VB.
- pass params -f (filtered data), -h (huffman only), -1 to -9 (compression
level) in minigzip (thanks to Tom Lane)
- use const for rommable constants in deflate
- added test for gzseek and gztell in example.c
- add undocumented function inflateSyncPoint() (hack for Paul Mackerras)
- add undocumented function zError to convert error code to string
(for Tim Smithers)
- Allow compilation of gzio with -DNO_DEFLATE to avoid the compression code.
- Use default memcpy for Symantec MSDOS compiler.
- Add EXPORT keyword for check_func (needed for Windows DLL)
- add current directory to LD_LIBRARY_PATH for "make test"
- create also a link for libz.so.1
- added support for FUJITSU UXP/DS (thanks to Toshiaki Nomura)
- use $(SHAREDLIB) instead of libz.so in Makefile.in (for HPUX)
- added -soname for Linux in configure (Chun-Chung Chen,
- assign numbers to the exported functions in zlib.def (for Windows DLL)
- add advice in zlib.h for best usage of deflateSetDictionary
- work around compiler bug on Atari (cast Z_NULL in call of s->checkfn)
- allow compilation with ANSI keywords only enabled for TurboC in large model
- avoid "versionString"[0] (Borland bug)
- add NEED_DUMMY_RETURN for Borland
- use variable z_verbose for tracing in debug mode (L. Peter Deutsch).
- allow compilation with CC
- defined STDC for OS/2 (David Charlap)
- limit external names to 8 chars for MVS (Thomas Lund)
- in minigzip.c, use static buffers only for 16-bit systems
- fix suffix check for "minigzip -d foo.gz"
- do not return an error for the 2nd of two consecutive gzflush() (Felix Lee)
- use _fdopen instead of fdopen for MSC >= 6.0 (Thomas Fanslau)
- added makelcc.bat for lcc-win32 (Tom St Denis)
- in Makefile.dj2, use copy and del instead of install and rm (Frank Donahoe)
- Avoid expanded $Id$. Use "rcs -kb" or "cvs admin -kb" to avoid Id expansion.
- check for unistd.h in configure (for off_t)
- remove useless check parameter in inflate_blocks_free
- avoid useless assignment of s->check to itself in inflate_blocks_new
- do not flush twice in gzclose (thanks to Ken Raeburn)
- rename FOPEN as F_OPEN to avoid clash with /usr/include/sys/file.h
- use NO_ERRNO_H instead of enumeration of operating systems with errno.h
- work around buggy fclose on pipes for HP/UX
- support zlib DLL with BORLAND C++ 5.0 (thanks to Glenn Randers-Pehrson)
- fix configure if CC is already equal to gcc
Changes in 1.0.5 (3 Jan 98)
- Fix inflate to terminate gracefully when fed corrupted or invalid data
- Use const for rommable constants in inflate
- Eliminate memory leaks on error conditions in inflate
- Removed some vestigial code in inflate
- Update web address in README
Changes in 1.0.4 (24 Jul 96)
- In very rare conditions, deflate(s, Z_FINISH) could fail to produce an EOF
bit, so the decompressor could decompress all the correct data but went
on to attempt decompressing extra garbage data. This affected minigzip too.
- zlibVersion and gzerror return const char* (needed for DLL)
- port to RISCOS (no fdopen, no multiple dots, no unlink, no fileno)
- use z_error only for DEBUG (avoid problem with DLLs)
Changes in 1.0.3 (2 Jul 96)
- use z_streamp instead of z_stream *, which is now a far pointer in MSDOS
small and medium models; this makes the library incompatible with previous
versions for these models. (No effect in large model or on other systems.)
- return OK instead of BUF_ERROR if previous deflate call returned with
avail_out as zero but there is nothing to do
- added memcmp for non STDC compilers
- define NO_DUMMY_DECL for more Mac compilers (.h files merged incorrectly)
- define __32BIT__ if __386__ or i386 is defined (pb. with Watcom and SCO)
- better check for 16-bit mode MSC (avoids problem with Symantec)
Changes in 1.0.2 (23 May 96)
- added Windows DLL support
- added a function zlibVersion (for the DLL support)
- fixed declarations using Bytef in infutil.c (pb with MSDOS medium model)
- Bytef is define's instead of typedef'd only for Borland C
- avoid reading uninitialized memory in example.c
- mention in README that the zlib format is now RFC1950
- updated Makefile.dj2
- added algorithm.doc
Changes in 1.0.1 (20 May 96) [1.0 skipped to avoid confusion]
- fix array overlay in deflate.c which sometimes caused bad compressed data
- fix inflate bug with empty stored block
- fix MSDOS medium model which was broken in 0.99
- fix deflateParams() which could generated bad compressed data.
- Bytef is define'd instead of typedef'ed (work around Borland bug)
- added an INDEX file
- new makefiles for DJGPP (Makefile.dj2), 32-bit Borland (Makefile.b32),
Watcom (Makefile.wat), Amiga SAS/C (Makefile.sas)
- speed up adler32 for modern machines without auto-increment
- added -ansi for IRIX in configure
- static_init_done in trees.c is an int
- define unlink as delete for VMS
- fix configure for QNX
- add configure branch for SCO and HPUX
- avoid many warnings (unused variables, dead assignments, etc...)
- no fdopen for BeOS
- fix the Watcom fix for 32 bit mode (define FAR as empty)
- removed redefinition of Byte for MKWERKS
- work around an MWKERKS bug (incorrect merge of all .h files)
Changes in 0.99 (27 Jan 96)
- allow preset dictionary shared between compressor and decompressor
- allow compression level 0 (no compression)
- add deflateParams in zlib.h: allow dynamic change of compression level
and compression strategy.
- test large buffers and deflateParams in example.c
- add optional "configure" to build zlib as a shared library
- suppress Makefile.qnx, use configure instead
- fixed deflate for 64-bit systems (detected on Cray)
- fixed inflate_blocks for 64-bit systems (detected on Alpha)
- declare Z_DEFLATED in zlib.h (possible parameter for deflateInit2)
- always return Z_BUF_ERROR when deflate() has nothing to do
- deflateInit and inflateInit are now macros to allow version checking
- prefix all global functions and types with z_ with -DZ_PREFIX
- make falloc completely reentrant (inftrees.c)
- fixed very unlikely race condition in ct_static_init
- free in reverse order of allocation to help memory manager
- use zlib-1.0/* instead of zlib/* inside the tar.gz
- make zlib warning-free with "gcc -O3 -Wall -Wwrite-strings -Wpointer-arith
-Wconversion -Wstrict-prototypes -Wmissing-prototypes"
- allow gzread on concatenated .gz files
- deflateEnd now returns Z_DATA_ERROR if it was premature
- deflate is finally (?) fully deterministic (no matches beyond end of input)
- Document Z_SYNC_FLUSH
- add uninstall in Makefile
- Check for __cpluplus in zlib.h
- Better test in ct_align for partial flush
- avoid harmless warnings for Borland C++
- initialize hash_head in deflate.c
- avoid warning on fdopen (gzio.c) for HP cc -Aa
- include stdlib.h for STDC compilers
- include errno.h for Cray
- ignore error if ranlib doesn't exist
- call ranlib twice for NeXTSTEP
- use exec_prefix instead of prefix for libz.a
- renamed ct_* as _tr_* to avoid conflict with applications
- clear z->msg in inflateInit2 before any error return
- initialize opaque in example.c, gzio.c, deflate.c and inflate.c
- fixed typo in zconf.h (_GNUC__ => __GNUC__)
- check for WIN32 in zconf.h and zutil.c (avoid farmalloc in 32-bit mode)
- fix typo in Make_vms.com (f$trnlnm -> f$getsyi)
- in fcalloc, normalize pointer if size > 65520 bytes
- don't use special fcalloc for 32 bit Borland C++
- use STDC instead of __GO32__ to avoid redeclaring exit, calloc, etc...
- use Z_BINARY instead of BINARY
- document that gzclose after gzdopen will close the file
- allow "a" as mode in gzopen.
- fix error checking in gzread
- allow skipping .gz extra-field on pipes
- added reference to Perl interface in README
- put the crc table in FAR data (I dislike more and more the medium model :)
- added get_crc_table
- added a dimension to all arrays (Borland C can't count).
- workaround Borland C bug in declaration of inflate_codes_new & inflate_fast
- guard against multiple inclusion of *.h (for precompiled header on Mac)
- Watcom C pretends to be Microsoft C small model even in 32 bit mode.
- don't use unsized arrays to avoid silly warnings by Visual C++:
warning C4746: 'inflate_mask' : unsized array treated as '__far'
(what's wrong with far data in far model?).
- define enum out of inflate_blocks_state to allow compilation with C++
Changes in 0.95 (16 Aug 95)
- fix MSDOS small and medium model (now easier to adapt to any compiler)
- inlined send_bits
- fix the final (:-) bug for deflate with flush (output was correct but
not completely flushed in rare occasions).
- default window size is same for compression and decompression
(it's now sufficient to set MAX_WBITS in zconf.h).
- voidp -> voidpf and voidnp -> voidp (for consistency with other
typedefs and because voidnp was not near in large model).
Changes in 0.94 (13 Aug 95)
- support MSDOS medium model
- fix deflate with flush (could sometimes generate bad output)
- fix deflateReset (zlib header was incorrectly suppressed)
- added support for VMS
- allow a compression level in gzopen()
- gzflush now calls fflush
- For deflate with flush, flush even if no more input is provided.
- rename libgz.a as libz.a
- avoid complex expression in infcodes.c triggering Turbo C bug
- work around a problem with gcc on Alpha (in INSERT_STRING)
- don't use inline functions (problem with some gcc versions)
- allow renaming of Byte, uInt, etc... with #define.
- avoid warning about (unused) pointer before start of array in deflate.c
- avoid various warnings in gzio.c, example.c, infblock.c, adler32.c, zutil.c
- avoid reserved word 'new' in trees.c
Changes in 0.93 (25 June 95)
- temporarily disable inline functions
- make deflate deterministic
- give enough lookahead for PARTIAL_FLUSH
- Set binary mode for stdin/stdout in minigzip.c for OS/2
- don't even use signed char in inflate (not portable enough)
- fix inflate memory leak for segmented architectures
Changes in 0.92 (3 May 95)
- don't assume that char is signed (problem on SGI)
- Clear bit buffer when starting a stored block
- no memcpy on Pyramid
- suppressed inftest.c
- optimized fill_window, put longest_match inline for gcc
- optimized inflate on stored blocks.
- untabify all sources to simplify patches
Changes in 0.91 (2 May 95)
- Default MEM_LEVEL is 8 (not 9 for Unix) as documented in zlib.h
- Document the memory requirements in zconf.h
- added "make install"
- fix sync search logic in inflateSync
- deflate(Z_FULL_FLUSH) now works even if output buffer too short
- after inflateSync, don't scare people with just "lo world"
- added support for DJGPP
Changes in 0.9 (1 May 95)
- don't assume that zalloc clears the allocated memory (the TurboC bug
was Mark's bug after all :)
- let again gzread copy uncompressed data unchanged (was working in 0.71)
- deflate(Z_FULL_FLUSH), inflateReset and inflateSync are now fully implemented
- added a test of inflateSync in example.c
- moved MAX_WBITS to zconf.h because users might want to change that.
- document explicitly that zalloc(64K) on MSDOS must return a normalized
pointer (zero offset)
- added Makefiles for Microsoft C, Turbo C, Borland C++
- faster crc32()
Changes in 0.8 (29 April 95)
- added fast inflate (inffast.c)
- deflate(Z_FINISH) now returns Z_STREAM_END when done. Warning: this
is incompatible with previous versions of zlib which returned Z_OK.
- work around a TurboC compiler bug (bad code for b << 0, see infutil.h)
(actually that was not a compiler bug, see 0.81 above)
- gzread no longer reads one extra byte in certain cases
- In gzio destroy(), don't reference a freed structure
- avoid many warnings for MSDOS
- avoid the ERROR symbol which is used by MS Windows
Changes in 0.71 (14 April 95)
- Fixed more MSDOS compilation problems :( There is still a bug with
TurboC large model.
Changes in 0.7 (14 April 95)
- Added full inflate support.
- Simplified the crc32() interface. The pre- and post-conditioning
(one's complement) is now done inside crc32(). WARNING: this is
incompatible with previous versions; see zlib.h for the new usage.
Changes in 0.61 (12 April 95)
- workaround for a bug in TurboC. example and minigzip now work on MSDOS.
Changes in 0.6 (11 April 95)
- added minigzip.c
- added gzdopen to reopen a file descriptor as gzFile
- added transparent reading of non-gziped files in gzread.
- fixed bug in gzread (don't read crc as data)
- fixed bug in destroy (gzio.c) (don't return Z_STREAM_END for gzclose).
- don't allocate big arrays in the stack (for MSDOS)
- fix some MSDOS compilation problems
Changes in 0.5:
- do real compression in deflate.c. Z_PARTIAL_FLUSH is supported but
not yet Z_FULL_FLUSH.
- support decompression but only in a single step (forced Z_FINISH)
- added opaque object for zalloc and zfree.
- added deflateReset and inflateReset
- added a variable zlib_version for consistency checking.
- renamed the 'filter' parameter of deflateInit2 as 'strategy'.
Added Z_FILTERED and Z_HUFFMAN_ONLY constants.
Changes in 0.4:
- avoid "zip" everywhere, use zlib instead of ziplib.
- suppress Z_BLOCK_FLUSH, interpret Z_PARTIAL_FLUSH as block flush
if compression method == 8.
- added adler32 and crc32
- renamed deflateOptions as deflateInit2, call one or the other but not both
- added the method parameter for deflateInit2.
- added inflateInit2
- simplied considerably deflateInit and inflateInit by not supporting
user-provided history buffer. This is supported only in deflateInit2
and inflateInit2.
Changes in 0.3:
- prefix all macro names with Z_
- use Z_FINISH instead of deflateEnd to finish compression.
- added Z_HUFFMAN_ONLY
- added gzerror()

315
zlib/FAQ Normal file
View file

@ -0,0 +1,315 @@
Frequently Asked Questions about zlib
If your question is not there, please check the zlib home page
http://www.zlib.org which may have more recent information.
The lastest zlib FAQ is at http://www.gzip.org/zlib/zlib_faq.html
1. Is zlib Y2K-compliant?
Yes. zlib doesn't handle dates.
2. Where can I get a Windows DLL version?
The zlib sources can be compiled without change to produce a DLL.
See the file win32/DLL_FAQ.txt in the zlib distribution.
Pointers to the precompiled DLL are found in the zlib web site at
http://www.zlib.org.
3. Where can I get a Visual Basic interface to zlib?
See
* http://www.winimage.com/zLibDll/
* http://www.dogma.net/markn/articles/zlibtool/zlibtool.htm
* contrib/visual-basic.txt in the zlib distribution
4. compress() returns Z_BUF_ERROR
Make sure that before the call of compress, the length of the compressed
buffer is equal to the total size of the compressed buffer and not
zero. For Visual Basic, check that this parameter is passed by reference
("as any"), not by value ("as long").
5. deflate() or inflate() returns Z_BUF_ERROR
Before making the call, make sure that avail_in and avail_out are not
zero. When setting the parameter flush equal to Z_FINISH, also make sure
that avail_out is big enough to allow processing all pending input.
Note that a Z_BUF_ERROR is not fatal--another call to deflate() or
inflate() can be made with more input or output space. A Z_BUF_ERROR
may in fact be unavoidable depending on how the functions are used, since
it is not possible to tell whether or not there is more output pending
when strm.avail_out returns with zero.
6. Where's the zlib documentation (man pages, etc.)?
It's in zlib.h for the moment, and Francis S. Lin has converted it to a
web page zlib.html. Volunteers to transform this to Unix-style man pages,
please contact Jean-loup Gailly (jloup@gzip.org). Examples of zlib usage
are in the files example.c and minigzip.c.
7. Why don't you use GNU autoconf or libtool or ...?
Because we would like to keep zlib as a very small and simple
package. zlib is rather portable and doesn't need much configuration.
8. I found a bug in zlib.
Most of the time, such problems are due to an incorrect usage of
zlib. Please try to reproduce the problem with a small program and send
the corresponding source to us at zlib@gzip.org . Do not send
multi-megabyte data files without prior agreement.
9. Why do I get "undefined reference to gzputc"?
If "make test" produces something like
example.o(.text+0x154): undefined reference to `gzputc'
check that you don't have old files libz.* in /usr/lib, /usr/local/lib or
/usr/X11R6/lib. Remove any old versions, then do "make install".
10. I need a Delphi interface to zlib.
See the contrib/delphi directory in the zlib distribution.
11. Can zlib handle .zip archives?
See the directory contrib/minizip in the zlib distribution.
12. Can zlib handle .Z files?
No, sorry. You have to spawn an uncompress or gunzip subprocess, or adapt
the code of uncompress on your own.
13. How can I make a Unix shared library?
make clean
./configure -s
make
14. How do I install a shared zlib library on Unix?
make install
However, many flavors of Unix come with a shared zlib already installed.
Before going to the trouble of compiling a shared version of zlib and
trying to install it, you may want to check if it's already there! If you
can #include <zlib.h>, it's there. The -lz option will probably link to it.
15. I have a question about OttoPDF
We are not the authors of OttoPDF. The real author is on the OttoPDF web
site Joel Hainley jhainley@myndkryme.com.
16. Why does gzip give an error on a file I make with compress/deflate?
The compress and deflate functions produce data in the zlib format, which
is different and incompatible with the gzip format. The gz* functions in
zlib on the other hand use the gzip format. Both the zlib and gzip
formats use the same compressed data format internally, but have different
headers and trailers around the compressed data.
17. Ok, so why are there two different formats?
The gzip format was designed to retain the directory information about
a single file, such as the name and last modification date. The zlib
format on the other hand was designed for in-memory and communication
channel applications, and has a much more compact header and trailer and
uses a faster integrity check than gzip.
18. Well that's nice, but how do I make a gzip file in memory?
You can request that deflate write the gzip format instead of the zlib
format using deflateInit2(). You can also request that inflate decode
the gzip format using inflateInit2(). Read zlib.h for more details.
Note that you cannot specify special gzip header contents (e.g. a file
name or modification date), nor will inflate tell you what was in the
gzip header. If you need to customize the header or see what's in it,
you can use the raw deflate and inflate operations and the crc32()
function and roll your own gzip encoding and decoding. Read the gzip
RFC 1952 for details of the header and trailer format.
19. Is zlib thread-safe?
Yes. However any library routines that zlib uses and any application-
provided memory allocation routines must also be thread-safe. zlib's gz*
functions use stdio library routines, and most of zlib's functions use the
library memory allocation routines by default. zlib's Init functions allow
for the application to provide custom memory allocation routines.
Of course, you should only operate on any given zlib or gzip stream from a
single thread at a time.
20. Can I use zlib in my commercial application?
Yes. Please read the license in zlib.h.
21. Is zlib under the GNU license?
No. Please read the license in zlib.h.
22. The license says that altered source versions must be "plainly marked". So
what exactly do I need to do to meet that requirement?
You need to change the ZLIB_VERSION and ZLIB_VERNUM #defines in zlib.h. In
particular, the final version number needs to be changed to "f", and an
identification string should be appended to ZLIB_VERSION. Version numbers
x.x.x.f are reserved for modifications to zlib by others than the zlib
maintainers. For example, if the version of the base zlib you are altering
is "1.2.3.4", then in zlib.h you should change ZLIB_VERNUM to 0x123f, and
ZLIB_VERSION to something like "1.2.3.f-zachary-mods-v3". You can also
update the version strings in deflate.c and inftrees.c.
For altered source distributions, you should also note the origin and
nature of the changes in zlib.h, as well as in ChangeLog and README, along
with the dates of the alterations. The origin should include at least your
name (or your company's name), and an email address to contact for help or
issues with the library.
Note that distributing a compiled zlib library along with zlib.h and
zconf.h is also a source distribution, and so you should change
ZLIB_VERSION and ZLIB_VERNUM and note the origin and nature of the changes
in zlib.h as you would for a full source distribution.
23. Will zlib work on a big-endian or little-endian architecture, and can I
exchange compressed data between them?
Yes and yes.
24. Will zlib work on a 64-bit machine?
It should. It has been tested on 64-bit machines, and has no dependence
on any data types being limited to 32-bits in length. If you have any
difficulties, please provide a complete problem report to zlib@gzip.org
25. Will zlib decompress data from the PKWare Data Compression Library?
No. The PKWare DCL uses a completely different compressed data format
than does PKZIP and zlib. However, you can look in zlib's contrib/blast
directory for a possible solution to your problem.
26. Can I access data randomly in a compressed stream?
No, not without some preparation. If when compressing you periodically
use Z_FULL_FLUSH, carefully write all the pending data at those points,
and keep an index of those locations, then you can start decompression
at those points. You have to be careful to not use Z_FULL_FLUSH too
often, since it can significantly degrade compression.
27. Does zlib work on MVS, OS/390, CICS, etc.?
We don't know for sure. We have heard occasional reports of success on
these systems. If you do use it on one of these, please provide us with
a report, instructions, and patches that we can reference when we get
these questions. Thanks.
28. Is there some simpler, easier to read version of inflate I can look at
to understand the deflate format?
First off, you should read RFC 1951. Second, yes. Look in zlib's
contrib/puff directory.
29. Does zlib infringe on any patents?
As far as we know, no. In fact, that was originally the whole point behind
zlib. Look here for some more information:
http://www.gzip.org/#faq11
30. Can zlib work with greater than 4 GB of data?
Yes. inflate() and deflate() will process any amount of data correctly.
Each call of inflate() or deflate() is limited to input and output chunks
of the maximum value that can be stored in the compiler's "unsigned int"
type, but there is no limit to the number of chunks. Note however that the
strm.total_in and strm_total_out counters may be limited to 4 GB. These
counters are provided as a convenience and are not used internally by
inflate() or deflate(). The application can easily set up its own counters
updated after each call of inflate() or deflate() to count beyond 4 GB.
compress() and uncompress() may be limited to 4 GB, since they operate in a
single call. gzseek() and gztell() may be limited to 4 GB depending on how
zlib is compiled. See the zlibCompileFlags() function in zlib.h.
The word "may" appears several times above since there is a 4 GB limit
only if the compiler's "long" type is 32 bits. If the compiler's "long"
type is 64 bits, then the limit is 16 exabytes.
31. Does zlib have any security vulnerabilities?
The only one that we are aware of is potentially in gzprintf(). If zlib
is compiled to use sprintf() or vsprintf(), then there is no protection
against a buffer overflow of a 4K string space, other than the caller of
gzprintf() assuring that the output will not exceed 4K. On the other
hand, if zlib is compiled to use snprintf() or vsnprintf(), which should
normally be the case, then there is no vulnerability. The ./configure
script will display warnings if an insecure variation of sprintf() will
be used by gzprintf(). Also the zlibCompileFlags() function will return
information on what variant of sprintf() is used by gzprintf().
If you don't have snprintf() or vsnprintf() and would like one, you can
find a portable implementation here:
http://www.ijs.si/software/snprintf/
Note that you should be using the most recent version of zlib. Versions
1.1.3 and before were subject to a double-free vulnerability.
32. Is there a Java version of zlib?
Probably what you want is to use zlib in Java. zlib is already included
as part of the Java SDK in the java.util.zip package. If you really want
a version of zlib written in the Java language, look on the zlib home
page for links: http://www.zlib.org/
33. I get this or that compiler or source-code scanner warning when I crank it
up to maximally-pendantic. Can't you guys write proper code?
Many years ago, we gave up attempting to avoid warnings on every compiler
in the universe. It just got to be a waste of time, and some compilers
were downright silly. So now, we simply make sure that the code always
works.
34. Will zlib read the (insert any ancient or arcane format here) compressed
data format?
Probably not. Look in the comp.compression FAQ for pointers to various
formats and associated software.
35. How can I encrypt/decrypt zip files with zlib?
zlib doesn't support encryption. The original PKZIP encryption is very weak
and can be broken with freely available programs. To get strong encryption,
use gpg ( http://www.gnupg.org/ ) which already includes zlib compression.
For PKZIP compatible "encryption", look at http://www.info-zip.org/
36. What's the difference between the "gzip" and "deflate" HTTP 1.1 encodings?
"gzip" is the gzip format, and "deflate" is the zlib format. They should
probably have called the second one "zlib" instead to avoid confusion
with the raw deflate compressed data format. While the HTTP 1.1 RFC 2616
correctly points to the zlib specification in RFC 1950 for the "deflate"
transfer encoding, there have been reports of servers and browsers that
incorrectly produce or expect raw deflate data per the deflate
specficiation in RFC 1951, most notably Microsoft. So even though the
"deflate" transfer encoding using the zlib format would be the more
efficient approach (and in fact exactly what the zlib format was designed
for), using the "gzip" transfer encoding is probably more reliable due to
an unfortunate choice of name on the part of the HTTP 1.1 authors.
Bottom line: use the gzip format for HTTP 1.1 encoding.
37. Does zlib support the new "Deflate64" format introduced by PKWare?
No. PKWare has apparently decided to keep that format proprietary, since
they have not documented it as they have previous compression formats.
In any case, the compression improvements are so modest compared to other
more modern approaches, that it's not worth the effort to implement.
38. Can you please sign these lengthy legal documents and fax them back to us
so that we can use your software in our product?
No. Go away. Shoo.

48
zlib/INDEX Normal file
View file

@ -0,0 +1,48 @@
ChangeLog history of changes
FAQ Frequently Asked Questions about zlib
INDEX this file
Makefile makefile for Unix (generated by configure)
Makefile.in makefile for Unix (template for configure)
README guess what
algorithm.txt description of the (de)compression algorithm
configure configure script for Unix
zconf.in.h template for zconf.h (used by configure)
msdos/ makefiles for MSDOS
old/ makefiles for various architectures and zlib documentation
files that have not yet been updated for zlib 1.2.x
qnx/ makefiles for QNX
win32/ makefiles for Windows
zlib public header files (must be kept):
zconf.h
zlib.h
private source files used to build the zlib library:
adler32.c
compress.c
crc32.c
crc32.h
deflate.c
deflate.h
gzio.c
infback.c
inffast.c
inffast.h
inffixed.h
inflate.c
inflate.h
inftrees.c
inftrees.h
trees.c
trees.h
uncompr.c
zutil.c
zutil.h
source files for sample programs:
example.c
minigzip.c
unsupported contribution by third parties
See contrib/README.contrib

154
zlib/Makefile Normal file
View file

@ -0,0 +1,154 @@
# Makefile for zlib
# Copyright (C) 1995-2003 Jean-loup Gailly.
# For conditions of distribution and use, see copyright notice in zlib.h
# To compile and test, type:
# ./configure; make test
# The call of configure is optional if you don't have special requirements
# If you wish to build zlib as a shared library, use: ./configure -s
# To use the asm code, type:
# cp contrib/asm?86/match.S ./match.S
# make LOC=-DASMV OBJA=match.o
# To install /usr/local/lib/libz.* and /usr/local/include/zlib.h, type:
# make install
# To install in $HOME instead of /usr/local, use:
# make install prefix=$HOME
CC=cc
CFLAGS=-O
#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7
#CFLAGS=-g -DDEBUG
#CFLAGS=-O3 -Wall -Wwrite-strings -Wpointer-arith -Wconversion \
# -Wstrict-prototypes -Wmissing-prototypes
LDFLAGS=libz.a
LDSHARED=$(CC)
CPP=$(CC) -E
LIBS=libz.a
SHAREDLIB=libz.so
SHAREDLIBV=libz.so.1.2.1
SHAREDLIBM=libz.so.1
AR=ar rc
RANLIB=ranlib
TAR=tar
SHELL=/bin/sh
EXE=
prefix = /usr/local
exec_prefix = ${prefix}
libdir = ${exec_prefix}/lib
includedir = ${prefix}/include
mandir = ${prefix}/share/man
man3dir = ${mandir}/man3
OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \
zutil.o inflate.o infback.o inftrees.o inffast.o
OBJA =
# to use the asm code: make OBJA=match.o
TEST_OBJS = example.o minigzip.o
all: example$(EXE) minigzip$(EXE)
check: test
test: all
@LD_LIBRARY_PATH=.:$(LD_LIBRARY_PATH) ; export LD_LIBRARY_PATH; \
echo hello world | ./minigzip | ./minigzip -d || \
echo ' *** minigzip test FAILED ***' ; \
if ./example; then \
echo ' *** zlib test OK ***'; \
else \
echo ' *** zlib test FAILED ***'; \
fi
libz.a: $(OBJS) $(OBJA)
$(AR) $@ $(OBJS) $(OBJA)
-@ ($(RANLIB) $@ || true) >/dev/null 2>&1
match.o: match.S
$(CPP) match.S > _match.s
$(CC) -c _match.s
mv _match.o match.o
rm -f _match.s
$(SHAREDLIBV): $(OBJS)
$(LDSHARED) -o $@ $(OBJS)
rm -f $(SHAREDLIB) $(SHAREDLIBM)
ln -s $@ $(SHAREDLIB)
ln -s $@ $(SHAREDLIBM)
example$(EXE): example.o $(LIBS)
$(CC) $(CFLAGS) -o $@ example.o $(LDFLAGS)
minigzip$(EXE): minigzip.o $(LIBS)
$(CC) $(CFLAGS) -o $@ minigzip.o $(LDFLAGS)
install: $(LIBS)
-@if [ ! -d $(exec_prefix) ]; then mkdir -p $(exec_prefix); fi
-@if [ ! -d $(includedir) ]; then mkdir -p $(includedir); fi
-@if [ ! -d $(libdir) ]; then mkdir -p $(libdir); fi
-@if [ ! -d $(man3dir) ]; then mkdir -p $(man3dir); fi
cp zlib.h zconf.h $(includedir)
chmod 644 $(includedir)/zlib.h $(includedir)/zconf.h
cp $(LIBS) $(libdir)
cd $(libdir); chmod 755 $(LIBS)
-@(cd $(libdir); $(RANLIB) libz.a || true) >/dev/null 2>&1
cd $(libdir); if test -f $(SHAREDLIBV); then \
rm -f $(SHAREDLIB) $(SHAREDLIBM); \
ln -s $(SHAREDLIBV) $(SHAREDLIB); \
ln -s $(SHAREDLIBV) $(SHAREDLIBM); \
(ldconfig || true) >/dev/null 2>&1; \
fi
cp zlib.3 $(man3dir)
chmod 644 $(man3dir)/zlib.3
# The ranlib in install is needed on NeXTSTEP which checks file times
# ldconfig is for Linux
uninstall:
cd $(includedir); \
cd $(libdir); rm -f libz.a; \
if test -f $(SHAREDLIBV); then \
rm -f $(SHAREDLIBV) $(SHAREDLIB) $(SHAREDLIBM); \
fi
cd $(man3dir); rm -f zlib.3
mostlyclean: clean
clean:
rm -f *.o *~ example$(EXE) minigzip$(EXE) \
libz.* foo.gz so_locations \
_match.s maketree contrib/infback9/*.o
maintainer-clean: distclean
distclean: clean
cp -p Makefile.in Makefile
cp -p zconf.in.h zconf.h
rm -f .DS_Store
tags:
etags *.[ch]
depend:
makedepend -- $(CFLAGS) -- *.[ch]
# DO NOT DELETE THIS LINE -- make depend depends on it.
adler32.o: zlib.h zconf.h
compress.o: zlib.h zconf.h
crc32.o: crc32.h zlib.h zconf.h
deflate.o: deflate.h zutil.h zlib.h zconf.h
example.o: zlib.h zconf.h
gzio.o: zutil.h zlib.h zconf.h
inffast.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h
inflate.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h
infback.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h
inftrees.o: zutil.h zlib.h zconf.h inftrees.h
minigzip.o: zlib.h zconf.h
trees.o: deflate.h zutil.h zlib.h zconf.h trees.h
uncompr.o: zlib.h zconf.h
zutil.o: zutil.h zlib.h zconf.h

154
zlib/Makefile.in Normal file
View file

@ -0,0 +1,154 @@
# Makefile for zlib
# Copyright (C) 1995-2003 Jean-loup Gailly.
# For conditions of distribution and use, see copyright notice in zlib.h
# To compile and test, type:
# ./configure; make test
# The call of configure is optional if you don't have special requirements
# If you wish to build zlib as a shared library, use: ./configure -s
# To use the asm code, type:
# cp contrib/asm?86/match.S ./match.S
# make LOC=-DASMV OBJA=match.o
# To install /usr/local/lib/libz.* and /usr/local/include/zlib.h, type:
# make install
# To install in $HOME instead of /usr/local, use:
# make install prefix=$HOME
CC=cc
CFLAGS=-O
#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7
#CFLAGS=-g -DDEBUG
#CFLAGS=-O3 -Wall -Wwrite-strings -Wpointer-arith -Wconversion \
# -Wstrict-prototypes -Wmissing-prototypes
LDFLAGS=libz.a
LDSHARED=$(CC)
CPP=$(CC) -E
LIBS=libz.a
SHAREDLIB=libz.so
SHAREDLIBV=libz.so.1.2.1
SHAREDLIBM=libz.so.1
AR=ar rc
RANLIB=ranlib
TAR=tar
SHELL=/bin/sh
EXE=
prefix = /usr/local
exec_prefix = ${prefix}
libdir = ${exec_prefix}/lib
includedir = ${prefix}/include
mandir = ${prefix}/share/man
man3dir = ${mandir}/man3
OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \
zutil.o inflate.o infback.o inftrees.o inffast.o
OBJA =
# to use the asm code: make OBJA=match.o
TEST_OBJS = example.o minigzip.o
all: example$(EXE) minigzip$(EXE)
check: test
test: all
@LD_LIBRARY_PATH=.:$(LD_LIBRARY_PATH) ; export LD_LIBRARY_PATH; \
echo hello world | ./minigzip | ./minigzip -d || \
echo ' *** minigzip test FAILED ***' ; \
if ./example; then \
echo ' *** zlib test OK ***'; \
else \
echo ' *** zlib test FAILED ***'; \
fi
libz.a: $(OBJS) $(OBJA)
$(AR) $@ $(OBJS) $(OBJA)
-@ ($(RANLIB) $@ || true) >/dev/null 2>&1
match.o: match.S
$(CPP) match.S > _match.s
$(CC) -c _match.s
mv _match.o match.o
rm -f _match.s
$(SHAREDLIBV): $(OBJS)
$(LDSHARED) -o $@ $(OBJS)
rm -f $(SHAREDLIB) $(SHAREDLIBM)
ln -s $@ $(SHAREDLIB)
ln -s $@ $(SHAREDLIBM)
example$(EXE): example.o $(LIBS)
$(CC) $(CFLAGS) -o $@ example.o $(LDFLAGS)
minigzip$(EXE): minigzip.o $(LIBS)
$(CC) $(CFLAGS) -o $@ minigzip.o $(LDFLAGS)
install: $(LIBS)
-@if [ ! -d $(exec_prefix) ]; then mkdir -p $(exec_prefix); fi
-@if [ ! -d $(includedir) ]; then mkdir -p $(includedir); fi
-@if [ ! -d $(libdir) ]; then mkdir -p $(libdir); fi
-@if [ ! -d $(man3dir) ]; then mkdir -p $(man3dir); fi
cp zlib.h zconf.h $(includedir)
chmod 644 $(includedir)/zlib.h $(includedir)/zconf.h
cp $(LIBS) $(libdir)
cd $(libdir); chmod 755 $(LIBS)
-@(cd $(libdir); $(RANLIB) libz.a || true) >/dev/null 2>&1
cd $(libdir); if test -f $(SHAREDLIBV); then \
rm -f $(SHAREDLIB) $(SHAREDLIBM); \
ln -s $(SHAREDLIBV) $(SHAREDLIB); \
ln -s $(SHAREDLIBV) $(SHAREDLIBM); \
(ldconfig || true) >/dev/null 2>&1; \
fi
cp zlib.3 $(man3dir)
chmod 644 $(man3dir)/zlib.3
# The ranlib in install is needed on NeXTSTEP which checks file times
# ldconfig is for Linux
uninstall:
cd $(includedir); \
cd $(libdir); rm -f libz.a; \
if test -f $(SHAREDLIBV); then \
rm -f $(SHAREDLIBV) $(SHAREDLIB) $(SHAREDLIBM); \
fi
cd $(man3dir); rm -f zlib.3
mostlyclean: clean
clean:
rm -f *.o *~ example$(EXE) minigzip$(EXE) \
libz.* foo.gz so_locations \
_match.s maketree contrib/infback9/*.o
maintainer-clean: distclean
distclean: clean
cp -p Makefile.in Makefile
cp -p zconf.in.h zconf.h
rm -f .DS_Store
tags:
etags *.[ch]
depend:
makedepend -- $(CFLAGS) -- *.[ch]
# DO NOT DELETE THIS LINE -- make depend depends on it.
adler32.o: zlib.h zconf.h
compress.o: zlib.h zconf.h
crc32.o: crc32.h zlib.h zconf.h
deflate.o: deflate.h zutil.h zlib.h zconf.h
example.o: zlib.h zconf.h
gzio.o: zutil.h zlib.h zconf.h
inffast.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h
inflate.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h
infback.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h
inftrees.o: zutil.h zlib.h zconf.h inftrees.h
minigzip.o: zlib.h zconf.h
trees.o: deflate.h zutil.h zlib.h zconf.h trees.h
uncompr.o: zlib.h zconf.h
zutil.o: zutil.h zlib.h zconf.h

126
zlib/README Normal file
View file

@ -0,0 +1,126 @@
ZLIB DATA COMPRESSION LIBRARY
zlib 1.2.1 is a general purpose data compression library. All the code is
thread safe. The data format used by the zlib library is described by RFCs
(Request for Comments) 1950 to 1952 in the files
http://www.ietf.org/rfc/rfc1950.txt (zlib format), rfc1951.txt (deflate format)
and rfc1952.txt (gzip format). These documents are also available in other
formats from ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html
All functions of the compression library are documented in the file zlib.h
(volunteer to write man pages welcome, contact zlib@gzip.org). A usage example
of the library is given in the file example.c which also tests that the library
is working correctly. Another example is given in the file minigzip.c. The
compression library itself is composed of all source files except example.c and
minigzip.c.
To compile all files and run the test program, follow the instructions given at
the top of Makefile. In short "make test; make install" should work for most
machines. For Unix: "./configure; make test; make install" For MSDOS, use one
of the special makefiles such as Makefile.msc. For VMS, use Make_vms.com or
descrip.mms.
Questions about zlib should be sent to <zlib@gzip.org>, or to Gilles Vollant
<info@winimage.com> for the Windows DLL version. The zlib home page is
http://www.zlib.org or http://www.gzip.org/zlib/ Before reporting a problem,
please check this site to verify that you have the latest version of zlib;
otherwise get the latest version and check whether the problem still exists or
not.
PLEASE read the zlib FAQ http://www.gzip.org/zlib/zlib_faq.html before asking
for help.
Mark Nelson <markn@ieee.org> wrote an article about zlib for the Jan. 1997
issue of Dr. Dobb's Journal; a copy of the article is available in
http://dogma.net/markn/articles/zlibtool/zlibtool.htm
The changes made in version 1.2.1 are documented in the file ChangeLog.
Unsupported third party contributions are provided in directory "contrib".
A Java implementation of zlib is available in the Java Development Kit
http://java.sun.com/j2se/1.4.2/docs/api/java/util/zip/package-summary.html
See the zlib home page http://www.zlib.org for details.
A Perl interface to zlib written by Paul Marquess <pmqs@cpan.org> is in the
CPAN (Comprehensive Perl Archive Network) sites
http://www.cpan.org/modules/by-module/Compress/
A Python interface to zlib written by A.M. Kuchling <amk@magnet.com> is
available in Python 1.5 and later versions, see
http://www.python.org/doc/lib/module-zlib.html
A zlib binding for TCL written by Andreas Kupries <a.kupries@westend.com> is
availlable at http://www.oche.de/~akupries/soft/trf/trf_zip.html
An experimental package to read and write files in .zip format, written on top
of zlib by Gilles Vollant <info@winimage.com>, is available in the
contrib/minizip directory of zlib.
Notes for some targets:
- For Windows DLL versions, please see win32/DLL_FAQ.txt
- For 64-bit Irix, deflate.c must be compiled without any optimization. With
-O, one libpng test fails. The test works in 32 bit mode (with the -n32
compiler flag). The compiler bug has been reported to SGI.
- zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1 it works
when compiled with cc.
- On Digital Unix 4.0D (formely OSF/1) on AlphaServer, the cc option -std1 is
necessary to get gzprintf working correctly. This is done by configure.
- zlib doesn't work on HP-UX 9.05 with some versions of /bin/cc. It works with
other compilers. Use "make test" to check your compiler.
- gzdopen is not supported on RISCOS, BEOS and by some Mac compilers.
- For PalmOs, see http://palmzlib.sourceforge.net/
- When building a shared, i.e. dynamic library on Mac OS X, the library must be
installed before testing (do "make install" before "make test"), since the
library location is specified in the library.
Acknowledgments:
The deflate format used by zlib was defined by Phil Katz. The deflate
and zlib specifications were written by L. Peter Deutsch. Thanks to all the
people who reported problems and suggested various improvements in zlib;
they are too numerous to cite here.
Copyright notice:
(C) 1995-2003 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
jloup@gzip.org madler@alumni.caltech.edu
If you use the zlib library in a product, we would appreciate *not*
receiving lengthy legal documents to sign. The sources are provided
for free but without warranty of any kind. The library has been
entirely written by Jean-loup Gailly and Mark Adler; it does not
include third-party code.
If you redistribute modified sources, we would appreciate that you include
in the file ChangeLog history information documenting your changes. Please
read the FAQ for more information on the distribution of modified source
versions.

74
zlib/adler32.c Normal file
View file

@ -0,0 +1,74 @@
/* adler32.c -- compute the Adler-32 checksum of a data stream
* Copyright (C) 1995-2003 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
/* @(#) $Id$ */
#define ZLIB_INTERNAL
#include "zlib.h"
#define BASE 65521UL /* 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,i) {s1 += buf[i]; s2 += s1;}
#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
#define DO16(buf) DO8(buf,0); DO8(buf,8);
#ifdef NO_DIVIDE
# define MOD(a) \
do { \
if (a >= (BASE << 16)) a -= (BASE << 16); \
if (a >= (BASE << 15)) a -= (BASE << 15); \
if (a >= (BASE << 14)) a -= (BASE << 14); \
if (a >= (BASE << 13)) a -= (BASE << 13); \
if (a >= (BASE << 12)) a -= (BASE << 12); \
if (a >= (BASE << 11)) a -= (BASE << 11); \
if (a >= (BASE << 10)) a -= (BASE << 10); \
if (a >= (BASE << 9)) a -= (BASE << 9); \
if (a >= (BASE << 8)) a -= (BASE << 8); \
if (a >= (BASE << 7)) a -= (BASE << 7); \
if (a >= (BASE << 6)) a -= (BASE << 6); \
if (a >= (BASE << 5)) a -= (BASE << 5); \
if (a >= (BASE << 4)) a -= (BASE << 4); \
if (a >= (BASE << 3)) a -= (BASE << 3); \
if (a >= (BASE << 2)) a -= (BASE << 2); \
if (a >= (BASE << 1)) a -= (BASE << 1); \
if (a >= BASE) a -= BASE; \
} while (0)
#else
# define MOD(a) a %= BASE
#endif
/* ========================================================================= */
uLong ZEXPORT adler32(adler, buf, len)
uLong adler;
const 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 ? (int)len : NMAX;
len -= k;
while (k >= 16) {
DO16(buf);
buf += 16;
k -= 16;
}
if (k != 0) do {
s1 += *buf++;
s2 += s1;
} while (--k);
MOD(s1);
MOD(s2);
}
return (s2 << 16) | s1;
}

209
zlib/algorithm.txt Normal file
View file

@ -0,0 +1,209 @@
1. Compression algorithm (deflate)
The deflation algorithm used by gzip (also zip and zlib) is a variation of
LZ77 (Lempel-Ziv 1977, see reference below). It finds duplicated strings in
the input data. The second occurrence of a string is replaced by a
pointer to the previous string, in the form of a pair (distance,
length). Distances are limited to 32K bytes, and lengths are limited
to 258 bytes. When a string does not occur anywhere in the previous
32K bytes, it is emitted as a sequence of literal bytes. (In this
description, `string' must be taken as an arbitrary sequence of bytes,
and is not restricted to printable characters.)
Literals or match lengths are compressed with one Huffman tree, and
match distances are compressed with another tree. The trees are stored
in a compact form at the start of each block. The blocks can have any
size (except that the compressed data for one block must fit in
available memory). A block is terminated when deflate() determines that
it would be useful to start another block with fresh trees. (This is
somewhat similar to the behavior of LZW-based _compress_.)
Duplicated strings are found using a hash table. All input strings of
length 3 are inserted in the hash table. A hash index is computed for
the next 3 bytes. If the hash chain for this index is not empty, all
strings in the chain are compared with the current input string, and
the longest match is selected.
The hash chains are searched starting with the most recent strings, to
favor small distances and thus take advantage of the Huffman encoding.
The hash chains are singly linked. There are no deletions from the
hash chains, the algorithm simply discards matches that are too old.
To avoid a worst-case situation, very long hash chains are arbitrarily
truncated at a certain length, determined by a runtime option (level
parameter of deflateInit). So deflate() does not always find the longest
possible match but generally finds a match which is long enough.
deflate() also defers the selection of matches with a lazy evaluation
mechanism. After a match of length N has been found, deflate() searches for
a longer match at the next input byte. If a longer match is found, the
previous match is truncated to a length of one (thus producing a single
literal byte) and the process of lazy evaluation begins again. Otherwise,
the original match is kept, and the next match search is attempted only N
steps later.
The lazy match evaluation is also subject to a runtime parameter. If
the current match is long enough, deflate() reduces the search for a longer
match, thus speeding up the whole process. If compression ratio is more
important than speed, deflate() attempts a complete second search even if
the first match is already long enough.
The lazy match evaluation is not performed for the fastest compression
modes (level parameter 1 to 3). For these fast modes, new strings
are inserted in the hash table only when no match was found, or
when the match is not too long. This degrades the compression ratio
but saves time since there are both fewer insertions and fewer searches.
2. Decompression algorithm (inflate)
2.1 Introduction
The key question is how to represent a Huffman code (or any prefix code) so
that you can decode fast. The most important characteristic is that shorter
codes are much more common than longer codes, so pay attention to decoding the
short codes fast, and let the long codes take longer to decode.
inflate() sets up a first level table that covers some number of bits of
input less than the length of longest code. It gets that many bits from the
stream, and looks it up in the table. The table will tell if the next
code is that many bits or less and how many, and if it is, it will tell
the value, else it will point to the next level table for which inflate()
grabs more bits and tries to decode a longer code.
How many bits to make the first lookup is a tradeoff between the time it
takes to decode and the time it takes to build the table. If building the
table took no time (and if you had infinite memory), then there would only
be a first level table to cover all the way to the longest code. However,
building the table ends up taking a lot longer for more bits since short
codes are replicated many times in such a table. What inflate() does is
simply to make the number of bits in the first table a variable, and then
to set that variable for the maximum speed.
For inflate, which has 286 possible codes for the literal/length tree, the size
of the first table is nine bits. Also the distance trees have 30 possible
values, and the size of the first table is six bits. Note that for each of
those cases, the table ended up one bit longer than the ``average'' code
length, i.e. the code length of an approximately flat code which would be a
little more than eight bits for 286 symbols and a little less than five bits
for 30 symbols.
2.2 More details on the inflate table lookup
Ok, you want to know what this cleverly obfuscated inflate tree actually
looks like. You are correct that it's not a Huffman tree. It is simply a
lookup table for the first, let's say, nine bits of a Huffman symbol. The
symbol could be as short as one bit or as long as 15 bits. If a particular
symbol is shorter than nine bits, then that symbol's translation is duplicated
in all those entries that start with that symbol's bits. For example, if the
symbol is four bits, then it's duplicated 32 times in a nine-bit table. If a
symbol is nine bits long, it appears in the table once.
If the symbol is longer than nine bits, then that entry in the table points
to another similar table for the remaining bits. Again, there are duplicated
entries as needed. The idea is that most of the time the symbol will be short
and there will only be one table look up. (That's whole idea behind data
compression in the first place.) For the less frequent long symbols, there
will be two lookups. If you had a compression method with really long
symbols, you could have as many levels of lookups as is efficient. For
inflate, two is enough.
So a table entry either points to another table (in which case nine bits in
the above example are gobbled), or it contains the translation for the symbol
and the number of bits to gobble. Then you start again with the next
ungobbled bit.
You may wonder: why not just have one lookup table for how ever many bits the
longest symbol is? The reason is that if you do that, you end up spending
more time filling in duplicate symbol entries than you do actually decoding.
At least for deflate's output that generates new trees every several 10's of
kbytes. You can imagine that filling in a 2^15 entry table for a 15-bit code
would take too long if you're only decoding several thousand symbols. At the
other extreme, you could make a new table for every bit in the code. In fact,
that's essentially a Huffman tree. But then you spend two much time
traversing the tree while decoding, even for short symbols.
So the number of bits for the first lookup table is a trade of the time to
fill out the table vs. the time spent looking at the second level and above of
the table.
Here is an example, scaled down:
The code being decoded, with 10 symbols, from 1 to 6 bits long:
A: 0
B: 10
C: 1100
D: 11010
E: 11011
F: 11100
G: 11101
H: 11110
I: 111110
J: 111111
Let's make the first table three bits long (eight entries):
000: A,1
001: A,1
010: A,1
011: A,1
100: B,2
101: B,2
110: -> table X (gobble 3 bits)
111: -> table Y (gobble 3 bits)
Each entry is what the bits decode as and how many bits that is, i.e. how
many bits to gobble. Or the entry points to another table, with the number of
bits to gobble implicit in the size of the table.
Table X is two bits long since the longest code starting with 110 is five bits
long:
00: C,1
01: C,1
10: D,2
11: E,2
Table Y is three bits long since the longest code starting with 111 is six
bits long:
000: F,2
001: F,2
010: G,2
011: G,2
100: H,2
101: H,2
110: I,3
111: J,3
So what we have here are three tables with a total of 20 entries that had to
be constructed. That's compared to 64 entries for a single table. Or
compared to 16 entries for a Huffman tree (six two entry tables and one four
entry table). Assuming that the code ideally represents the probability of
the symbols, it takes on the average 1.25 lookups per symbol. That's compared
to one lookup for the single table, or 1.66 lookups per symbol for the
Huffman tree.
There, I think that gives you a picture of what's going on. For inflate, the
meaning of a particular symbol is often more than just a letter. It can be a
byte (a "literal"), or it can be either a length or a distance which
indicates a base value and a number of bits to fetch after the code that is
added to the base value. Or it might be the special end-of-block code. The
data structures created in inftrees.c try to encode all that information
compactly in the tables.
Jean-loup Gailly Mark Adler
jloup@gzip.org madler@alumni.caltech.edu
References:
[LZ77] Ziv J., Lempel A., ``A Universal Algorithm for Sequential Data
Compression,'' IEEE Transactions on Information Theory, Vol. 23, No. 3,
pp. 337-343.
``DEFLATE Compressed Data Format Specification'' available in
http://www.ietf.org/rfc/rfc1951.txt

66
zlib/amiga/Makefile.pup Normal file
View file

@ -0,0 +1,66 @@
# Amiga powerUP (TM) Makefile
# makefile for libpng and SAS C V6.58/7.00 PPC compiler
# Copyright (C) 1998 by Andreas R. Kleinert
LIBNAME = libzip.a
CC = scppc
CFLAGS = NOSTKCHK NOSINT OPTIMIZE OPTGO OPTPEEP OPTINLOCAL OPTINL \
OPTLOOP OPTRDEP=8 OPTDEP=8 OPTCOMP=8 NOVER
AR = ppc-amigaos-ar cr
RANLIB = ppc-amigaos-ranlib
LD = ppc-amigaos-ld -r
LDFLAGS = -o
LDLIBS = LIB:scppc.a LIB:end.o
RM = delete quiet
OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \
zutil.o inflate.o infback.o inftrees.o inffast.o
TEST_OBJS = example.o minigzip.o
all: example minigzip
check: test
test: all
example
echo hello world | minigzip | minigzip -d
$(LIBNAME): $(OBJS)
$(AR) $@ $(OBJS)
-$(RANLIB) $@
example: example.o $(LIBNAME)
$(LD) $(LDFLAGS) $@ LIB:c_ppc.o $@.o $(LIBNAME) $(LDLIBS)
minigzip: minigzip.o $(LIBNAME)
$(LD) $(LDFLAGS) $@ LIB:c_ppc.o $@.o $(LIBNAME) $(LDLIBS)
mostlyclean: clean
clean:
$(RM) *.o example minigzip $(LIBNAME) foo.gz
zip:
zip -ul9 zlib README ChangeLog Makefile Make????.??? Makefile.?? \
descrip.mms *.[ch]
tgz:
cd ..; tar cfz zlib/zlib.tgz zlib/README zlib/ChangeLog zlib/Makefile \
zlib/Make????.??? zlib/Makefile.?? zlib/descrip.mms zlib/*.[ch]
# DO NOT DELETE THIS LINE -- make depend depends on it.
adler32.o: zlib.h zconf.h
compress.o: zlib.h zconf.h
crc32.o: crc32.h zlib.h zconf.h
deflate.o: deflate.h zutil.h zlib.h zconf.h
example.o: zlib.h zconf.h
gzio.o: zutil.h zlib.h zconf.h
inffast.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h
inflate.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h
infback.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h
inftrees.o: zutil.h zlib.h zconf.h inftrees.h
minigzip.o: zlib.h zconf.h
trees.o: deflate.h zutil.h zlib.h zconf.h trees.h
uncompr.o: zlib.h zconf.h
zutil.o: zutil.h zlib.h zconf.h

65
zlib/amiga/Makefile.sas Normal file
View file

@ -0,0 +1,65 @@
# SMakefile for zlib
# Modified from the standard UNIX Makefile Copyright Jean-loup Gailly
# Osma Ahvenlampi <Osma.Ahvenlampi@hut.fi>
# Amiga, SAS/C 6.56 & Smake
CC=sc
CFLAGS=OPT
#CFLAGS=OPT CPU=68030
#CFLAGS=DEBUG=LINE
LDFLAGS=LIB z.lib
SCOPTIONS=OPTSCHED OPTINLINE OPTALIAS OPTTIME OPTINLOCAL STRMERGE \
NOICONS PARMS=BOTH NOSTACKCHECK UTILLIB NOVERSION ERRORREXX \
DEF=POSTINC
OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \
zutil.o inflate.o infback.o inftrees.o inffast.o
TEST_OBJS = example.o minigzip.o
all: SCOPTIONS example minigzip
check: test
test: all
example
echo hello world | minigzip | minigzip -d
install: z.lib
copy clone zlib.h zconf.h INCLUDE:
copy clone z.lib LIB:
z.lib: $(OBJS)
oml z.lib r $(OBJS)
example: example.o z.lib
$(CC) $(CFLAGS) LINK TO $@ example.o $(LDFLAGS)
minigzip: minigzip.o z.lib
$(CC) $(CFLAGS) LINK TO $@ minigzip.o $(LDFLAGS)
mostlyclean: clean
clean:
-delete force quiet example minigzip *.o z.lib foo.gz *.lnk SCOPTIONS
SCOPTIONS: Makefile.sas
copy to $@ <from <
$(SCOPTIONS)
<
# DO NOT DELETE THIS LINE -- make depend depends on it.
adler32.o: zlib.h zconf.h
compress.o: zlib.h zconf.h
crc32.o: crc32.h zlib.h zconf.h
deflate.o: deflate.h zutil.h zlib.h zconf.h
example.o: zlib.h zconf.h
gzio.o: zutil.h zlib.h zconf.h
inffast.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h
inflate.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h
infback.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h
inftrees.o: zutil.h zlib.h zconf.h inftrees.h
minigzip.o: zlib.h zconf.h
trees.o: deflate.h zutil.h zlib.h zconf.h trees.h
uncompr.o: zlib.h zconf.h
zutil.o: zutil.h zlib.h zconf.h

132
zlib/as400/bndsrc Normal file
View file

@ -0,0 +1,132 @@
STRPGMEXP PGMLVL(*CURRENT) SIGNATURE('ZLIB')
/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
/* Version 1.1.3 entry points. */
/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
/********************************************************************/
/* *MODULE ADLER32 ZLIB 01/02/01 00:15:09 */
/********************************************************************/
EXPORT SYMBOL("adler32")
/********************************************************************/
/* *MODULE COMPRESS ZLIB 01/02/01 00:15:09 */
/********************************************************************/
EXPORT SYMBOL("compress")
EXPORT SYMBOL("compress2")
/********************************************************************/
/* *MODULE CRC32 ZLIB 01/02/01 00:15:09 */
/********************************************************************/
EXPORT SYMBOL("crc32")
EXPORT SYMBOL("get_crc_table")
/********************************************************************/
/* *MODULE DEFLATE ZLIB 01/02/01 00:15:09 */
/********************************************************************/
EXPORT SYMBOL("deflate")
EXPORT SYMBOL("deflateEnd")
EXPORT SYMBOL("deflateSetDictionary")
EXPORT SYMBOL("deflateCopy")
EXPORT SYMBOL("deflateReset")
EXPORT SYMBOL("deflateParams")
EXPORT SYMBOL("deflatePrime")
EXPORT SYMBOL("deflateInit_")
EXPORT SYMBOL("deflateInit2_")
/********************************************************************/
/* *MODULE GZIO ZLIB 01/02/01 00:15:09 */
/********************************************************************/
EXPORT SYMBOL("gzopen")
EXPORT SYMBOL("gzdopen")
EXPORT SYMBOL("gzsetparams")
EXPORT SYMBOL("gzread")
EXPORT SYMBOL("gzwrite")
EXPORT SYMBOL("gzprintf")
EXPORT SYMBOL("gzputs")
EXPORT SYMBOL("gzgets")
EXPORT SYMBOL("gzputc")
EXPORT SYMBOL("gzgetc")
EXPORT SYMBOL("gzflush")
EXPORT SYMBOL("gzseek")
EXPORT SYMBOL("gzrewind")
EXPORT SYMBOL("gztell")
EXPORT SYMBOL("gzeof")
EXPORT SYMBOL("gzclose")
EXPORT SYMBOL("gzerror")
/********************************************************************/
/* *MODULE INFLATE ZLIB 01/02/01 00:15:09 */
/********************************************************************/
EXPORT SYMBOL("inflate")
EXPORT SYMBOL("inflateEnd")
EXPORT SYMBOL("inflateSetDictionary")
EXPORT SYMBOL("inflateSync")
EXPORT SYMBOL("inflateReset")
EXPORT SYMBOL("inflateInit_")
EXPORT SYMBOL("inflateInit2_")
EXPORT SYMBOL("inflateSyncPoint")
/********************************************************************/
/* *MODULE UNCOMPR ZLIB 01/02/01 00:15:09 */
/********************************************************************/
EXPORT SYMBOL("uncompress")
/********************************************************************/
/* *MODULE ZUTIL ZLIB 01/02/01 00:15:09 */
/********************************************************************/
EXPORT SYMBOL("zlibVersion")
EXPORT SYMBOL("zError")
/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
/* Version 1.2.1 additional entry points. */
/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
/********************************************************************/
/* *MODULE COMPRESS ZLIB 01/02/01 00:15:09 */
/********************************************************************/
EXPORT SYMBOL("compressBound")
/********************************************************************/
/* *MODULE DEFLATE ZLIB 01/02/01 00:15:09 */
/********************************************************************/
EXPORT SYMBOL("deflateBound")
/********************************************************************/
/* *MODULE GZIO ZLIB 01/02/01 00:15:09 */
/********************************************************************/
EXPORT SYMBOL("gzungetc")
EXPORT SYMBOL("gzclearerr")
/********************************************************************/
/* *MODULE INFBACK ZLIB 01/02/01 00:15:09 */
/********************************************************************/
EXPORT SYMBOL("inflateBack")
EXPORT SYMBOL("inflateBackEnd")
EXPORT SYMBOL("inflateBackInit_")
/********************************************************************/
/* *MODULE INFLATE ZLIB 01/02/01 00:15:09 */
/********************************************************************/
EXPORT SYMBOL("inflateCopy")
/********************************************************************/
/* *MODULE ZUTIL ZLIB 01/02/01 00:15:09 */
/********************************************************************/
EXPORT SYMBOL("zlibCompileFlags")
ENDPGMEXP

123
zlib/as400/compile.clp Normal file
View file

@ -0,0 +1,123 @@
/******************************************************************************/
/* */
/* ZLIB */
/* */
/* Compile sources into modules and link them into a service program. */
/* */
/******************************************************************************/
PGM
/* Configuration adjustable parameters. */
DCL VAR(&SRCLIB) TYPE(*CHAR) LEN(10) +
VALUE('ZLIB') /* Source library. */
DCL VAR(&SRCFILE) TYPE(*CHAR) LEN(10) +
VALUE('SOURCES') /* Source member file. */
DCL VAR(&CTLFILE) TYPE(*CHAR) LEN(10) +
VALUE('TOOLS') /* Control member file. */
DCL VAR(&MODLIB) TYPE(*CHAR) LEN(10) +
VALUE('ZLIB') /* Module library. */
DCL VAR(&SRVLIB) TYPE(*CHAR) LEN(10) +
VALUE('LGPL') /* Service program library. */
DCL VAR(&CFLAGS) TYPE(*CHAR) +
VALUE('OPTIMIZE(40)') /* Compile options. */
/* Working storage. */
DCL VAR(&CMDLEN) TYPE(*DEC) LEN(15 5) VALUE(300) /* Command length. */
DCL VAR(&CMD) TYPE(*CHAR) LEN(512)
/* Compile sources into modules. */
CHGVAR VAR(&CMD) VALUE('CRTCMOD MODULE(' *TCAT &MODLIB *TCAT +
'/ADLER32) SRCFILE(' *TCAT +
&SRCLIB *TCAT '/' *TCAT &SRCFILE *TCAT +
') SYSIFCOPT(*IFSIO)' *BCAT &CFLAGS)
CALL PGM(QCMDEXC) PARM(&CMD &CMDLEN)
CHGVAR VAR(&CMD) VALUE('CRTCMOD MODULE(' *TCAT &MODLIB *TCAT +
'/COMPRESS) SRCFILE(' *TCAT +
&SRCLIB *TCAT '/' *TCAT &SRCFILE *TCAT +
') SYSIFCOPT(*IFSIO)' *BCAT &CFLAGS)
CALL PGM(QCMDEXC) PARM(&CMD &CMDLEN)
CHGVAR VAR(&CMD) VALUE('CRTCMOD MODULE(' *TCAT &MODLIB *TCAT +
'/CRC32) SRCFILE(' *TCAT +
&SRCLIB *TCAT '/' *TCAT &SRCFILE *TCAT +
') SYSIFCOPT(*IFSIO)' *BCAT &CFLAGS)
CALL PGM(QCMDEXC) PARM(&CMD &CMDLEN)
CHGVAR VAR(&CMD) VALUE('CRTCMOD MODULE(' *TCAT &MODLIB *TCAT +
'/DEFLATE) SRCFILE(' *TCAT +
&SRCLIB *TCAT '/' *TCAT &SRCFILE *TCAT +
') SYSIFCOPT(*IFSIO)' *BCAT &CFLAGS)
CALL PGM(QCMDEXC) PARM(&CMD &CMDLEN)
CHGVAR VAR(&CMD) VALUE('CRTCMOD MODULE(' *TCAT &MODLIB *TCAT +
'/GZIO) SRCFILE(' *TCAT +
&SRCLIB *TCAT '/' *TCAT &SRCFILE *TCAT +
') SYSIFCOPT(*IFSIO)' *BCAT &CFLAGS)
CALL PGM(QCMDEXC) PARM(&CMD &CMDLEN)
CHGVAR VAR(&CMD) VALUE('CRTCMOD MODULE(' *TCAT &MODLIB *TCAT +
'/INFBACK) SRCFILE(' *TCAT +
&SRCLIB *TCAT '/' *TCAT &SRCFILE *TCAT +
') SYSIFCOPT(*IFSIO)' *BCAT &CFLAGS)
CALL PGM(QCMDEXC) PARM(&CMD &CMDLEN)
CHGVAR VAR(&CMD) VALUE('CRTCMOD MODULE(' *TCAT &MODLIB *TCAT +
'/INFFAST) SRCFILE(' *TCAT +
&SRCLIB *TCAT '/' *TCAT &SRCFILE *TCAT +
') SYSIFCOPT(*IFSIO)' *BCAT &CFLAGS)
CALL PGM(QCMDEXC) PARM(&CMD &CMDLEN)
CHGVAR VAR(&CMD) VALUE('CRTCMOD MODULE(' *TCAT &MODLIB *TCAT +
'/INFLATE) SRCFILE(' *TCAT +
&SRCLIB *TCAT '/' *TCAT &SRCFILE *TCAT +
') SYSIFCOPT(*IFSIO)' *BCAT &CFLAGS)
CALL PGM(QCMDEXC) PARM(&CMD &CMDLEN)
CHGVAR VAR(&CMD) VALUE('CRTCMOD MODULE(' *TCAT &MODLIB *TCAT +
'/INFTREES) SRCFILE(' *TCAT +
&SRCLIB *TCAT '/' *TCAT &SRCFILE *TCAT +
') SYSIFCOPT(*IFSIO)' *BCAT &CFLAGS)
CALL PGM(QCMDEXC) PARM(&CMD &CMDLEN)
CHGVAR VAR(&CMD) VALUE('CRTCMOD MODULE(' *TCAT &MODLIB *TCAT +
'/TREES) SRCFILE(' *TCAT +
&SRCLIB *TCAT '/' *TCAT &SRCFILE *TCAT +
') SYSIFCOPT(*IFSIO)' *BCAT &CFLAGS)
CALL PGM(QCMDEXC) PARM(&CMD &CMDLEN)
CHGVAR VAR(&CMD) VALUE('CRTCMOD MODULE(' *TCAT &MODLIB *TCAT +
'/UNCOMPR) SRCFILE(' *TCAT +
&SRCLIB *TCAT '/' *TCAT &SRCFILE *TCAT +
') SYSIFCOPT(*IFSIO)' *BCAT &CFLAGS)
CALL PGM(QCMDEXC) PARM(&CMD &CMDLEN)
CHGVAR VAR(&CMD) VALUE('CRTCMOD MODULE(' *TCAT &MODLIB *TCAT +
'/ZUTIL) SRCFILE(' *TCAT +
&SRCLIB *TCAT '/' *TCAT &SRCFILE *TCAT +
') SYSIFCOPT(*IFSIO)' *BCAT &CFLAGS)
CALL PGM(QCMDEXC) PARM(&CMD &CMDLEN)
/* Link modules into a service program. */
CRTSRVPGM SRVPGM(&SRVLIB/ZLIB) +
MODULE(&MODLIB/ADLER32 &MODLIB/COMPRESS +
&MODLIB/CRC32 &MODLIB/DEFLATE +
&MODLIB/GZIO &MODLIB/INFBACK +
&MODLIB/INFFAST &MODLIB/INFLATE +
&MODLIB/INFTREES &MODLIB/TREES +
&MODLIB/UNCOMPR &MODLIB/ZUTIL) +
SRCFILE(&SRCLIB/&CTLFILE) SRCMBR(BNDSRC) +
TEXT('ZLIB 1.2.1') TGTRLS(V4R4M0)
ENDPGM

111
zlib/as400/readme.txt Normal file
View file

@ -0,0 +1,111 @@
ZLIB version 1.2.1 for AS400 installation instructions
I) From an AS400 *SAVF file:
1) Unpacking archive to an AS400 save file
On the AS400:
_ Create the ZLIB AS400 library:
CRTLIB LIB(ZLIB) TYPE(PROD) TEXT('ZLIB compression API library')
_ Create a work save file, for example:
CRTSAVF FILE(ZLIB/ZLIBSAVF)
On a PC connected to the target AS400:
_ Unpack the save file image to a PC file "ZLIBSAVF"
_ Upload this file into the save file on the AS400, for example
using ftp in BINARY mode.
2) Populating the ZLIB AS400 source library
On the AS400:
_ Extract the saved objects into the ZLIB AS400 library using:
RSTOBJ OBJ(*ALL) SAVLIB(ZLIB) DEV(*SAVF) SAVF(ZLIB/ZLIBSAVF) RSTLIB(ZLIB)
3) Customize installation:
_ Edit CL member ZLIB/TOOLS(COMPILE) and change parameters if needed,
according to the comments.
_ Compile this member with:
CRTCLPGM PGM(ZLIB/COMPILE) SRCFILE(ZLIB/TOOLS) SRCMBR(COMPILE)
4) Compile and generate the service program:
_ This can now be done by executing:
CALL PGM(ZLIB/COMPILE)
II) From the original source distribution:
1) On the AS400, create the source library:
CRTLIB LIB(ZLIB) TYPE(PROD) TEXT('ZLIB compression API library')
2) Create the source files:
CRTSRCPF FILE(ZLIB/SOURCES) RCDLEN(112) TEXT('ZLIB library modules')
CRTSRCPF FILE(ZLIB/H) RCDLEN(112) TEXT('ZLIB library includes')
CRTSRCPF FILE(ZLIB/TOOLS) RCDLEN(112) TEXT('ZLIB library control utilities')
3) From the machine hosting the distribution files, upload them (with
FTP in text mode, for example) according to the following table:
Original AS400 AS400 AS400 AS400
file file member type description
SOURCES Original ZLIB C subprogram sources
adler32.c ADLER32 C ZLIB - Compute the Adler-32 checksum of a dta strm
compress.c COMPRESS C ZLIB - Compress a memory buffer
crc32.c CRC32 C ZLIB - Compute the CRC-32 of a data stream
deflate.c DEFLATE C ZLIB - Compress data using the deflation algorithm
gzio.c GZIO C ZLIB - IO on .gz files
infback.c INFBACK C ZLIB - Inflate using a callback interface
inffast.c INFFAST C ZLIB - Fast proc. literals & length/distance pairs
inflate.c INFLATE C ZLIB - Interface to inflate modules
inftrees.c INFTREES C ZLIB - Generate Huffman trees for efficient decode
trees.c TREES C ZLIB - Output deflated data using Huffman coding
uncompr.c UNCOMPR C ZLIB - Decompress a memory buffer
zutil.c ZUTIL C ZLIB - Target dependent utility functions
H Original ZLIB C and ILE/RPG include files
crc32.h CRC32 C ZLIB - CRC32 tables
deflate.h DEFLATE C ZLIB - Internal compression state
inffast.h INFFAST C ZLIB - Header to use inffast.c
inffixed.h INFFIXED C ZLIB - Table for decoding fixed codes
inflate.h INFLATE C ZLIB - Internal inflate state definitions
inftrees.h INFTREES C ZLIB - Header to use inftrees.c
trees.h TREES C ZLIB - Created automatically with -DGEN_TREES_H
zconf.h ZCONF C ZLIB - Compression library configuration
zlib.h ZLIB C ZLIB - Compression library C user interface
as400/zlib.inc ZLIB.INC RPGLE ZLIB - Compression library ILE RPG user interface
zutil.h ZUTIL C ZLIB - Internal interface and configuration
TOOLS Building source software & AS/400 README
as400/bndsrc BNDSRC Entry point exportation list
as400/compile.clp COMPILE CLP Compile sources & generate service program
as400/readme.txt README TXT Installation instructions
4) Continue as in I)3).
Notes: For AS400 ILE RPG programmers, a /copy member defining the ZLIB
API prototypes for ILE RPG can be found in ZLIB/H(ZLIB.INC).
Please read comments in this member for more information.
Remember that most foreign textual data are ASCII coded: this
implementation does not handle conversion from/to ASCII, so
text data code conversions must be done explicitely.
Always open zipped files in binary mode.

327
zlib/as400/zlib.inc Normal file
View file

@ -0,0 +1,327 @@
* ZLIB.INC - Interface to the general purpose compression library
*
* ILE RPG400 version by Patrick Monnerat, DATASPHERE.
* Version 1.2.1
*
*
* WARNING:
* Procedures inflateInit(), inflateInit2(), deflateInit(),
* deflateInit2() and inflateBackInit() need to be called with
* two additional arguments:
* the package version string and the stream control structure.
* size. This is needed because RPG lacks some macro feature.
* Call these procedures as:
* inflateInit(...: ZLIB_VERSION: %size(z_stream))
*
/if not defined(ZLIB_H_)
/define ZLIB_H_
*
**************************************************************************
* Constants
**************************************************************************
*
D ZLIB_VERSION C '1.2.1' Header's version
D ZLIB_VERNUM C X'1210'
*
D Z_NO_FLUSH C 0
D Z_SYNC_FLUSH C 2
D Z_FULL_FLUSH C 3
D Z_FINISH C 4
D Z_BLOCK C 5
*
D Z_OK C 0
D Z_STREAM_END C 1
D Z_NEED_DICT C 2
D Z_ERRNO C -1
D Z_STREAM_ERROR C -2
D Z_DATA_ERROR C -3
D Z_MEM_ERROR C -4
D Z_BUF_ERROR C -5
DZ_VERSION_ERROR C -6
*
D Z_NO_COMPRESSION...
D C 0
D Z_BEST_SPEED C 1
D Z_BEST_COMPRESSION...
D C 9
D Z_DEFAULT_COMPRESSION...
D C -1
*
D Z_FILTERED C 1
D Z_HUFFMAN_ONLY C 2
D Z_RLE C 3
D Z_DEFAULT_STRATEGY...
D C 0
*
D Z_BINARY C 0
D Z_ASCII C 1
D Z_UNKNOWN C 2
*
D Z_DEFLATED C 8
*
D Z_NULL C 0
*
**************************************************************************
* Types
**************************************************************************
*
D z_streamp S * Stream struct ptr
D gzFile S * File pointer
D z_off_t S 10i 0 Stream offsets
*
**************************************************************************
* Structures
**************************************************************************
*
* The GZIP encode/decode stream support structure.
*
D z_stream DS align based(z_streamp)
D zs_next_in * Next input byte
D zs_avail_in 10U 0 Byte cnt at next_in
D zs_total_in 10U 0 Total bytes read
D zs_next_out * Output buffer ptr
D zs_avail_out 10U 0 Room left @ next_out
D zs_total_out 10U 0 Total bytes written
D zs_msg * Last errmsg or null
D zs_state * Internal state
D zs_zalloc * procptr Int. state allocator
D zs_free * procptr Int. state dealloc.
D zs_opaque * Private alloc. data
D zs_data_type 10i 0 ASC/BIN best guess
D zs_adler 10u 0 Uncompr. adler32 val
D 10U 0 Reserved
D 10U 0 Ptr. alignment
*
**************************************************************************
* Utility function prototypes
**************************************************************************
*
D compress PR 10I 0 extproc('compress')
D dest 32767 options(*varsize) Destination buffer
D destLen 10U 0 Destination length
D source 32767 const options(*varsize) Source buffer
D sourceLen 10u 0 value Source length
*
D compress2 PR 10I 0 extproc('compress2')
D dest 32767 options(*varsize) Destination buffer
D destLen 10U 0 Destination length
D source 32767 const options(*varsize) Source buffer
D sourceLen 10U 0 value Source length
D level 10I 0 value Compression level
*
D compressBound PR 10U 0 extproc('compressBound')
D sourceLen 10U 0 value
*
D uncompress PR 10I 0 extproc('uncompress')
D dest 32767 options(*varsize) Destination buffer
D destLen 10U 0 Destination length
D source 32767 const options(*varsize) Source buffer
D sourceLen 10U 0 value Source length
*
D gzopen PR extproc('gzopen')
D like(gzFile)
D path * value options(*string) File pathname
D mode * value options(*string) Open mode
*
D gzdopen PR extproc('gzdopen')
D like(gzFile)
D fd 10i 0 value File descriptor
D mode * value options(*string) Open mode
*
D gzsetparams PR 10I 0 extproc('gzsetparams')
D file value like(gzFile) File pointer
D level 10I 0 value
D strategy 10i 0 value
*
D gzread PR 10I 0 extproc('gzread')
D file value like(gzFile) File pointer
D buf 32767 options(*varsize) Buffer
D len 10u 0 value Buffer length
*
D gzwrite PR 10I 0 extproc('gzwrite')
D file value like(gzFile) File pointer
D buf 32767 const options(*varsize) Buffer
D len 10u 0 value Buffer length
*
D gzputs PR 10I 0 extproc('gzputs')
D file value like(gzFile) File pointer
D s * value options(*string) String to output
*
D gzgets PR * extproc('gzgets')
D file value like(gzFile) File pointer
D buf 32767 options(*varsize) Read buffer
D len 10i 0 value Buffer length
*
D gzflush PR 10i 0 extproc('gzflush')
D file value like(gzFile) File pointer
D flush 10I 0 value Type of flush
*
D gzseek PR extproc('gzseek')
D like(z_off_t)
D file value like(gzFile) File pointer
D offset value like(z_off_t) Offset
D whence 10i 0 value Origin
*
D gzrewind PR 10i 0 extproc('gzrewind')
D file value like(gzFile) File pointer
*
D gztell PR extproc('gztell')
D like(z_off_t)
D file value like(gzFile) File pointer
*
D gzeof PR 10i 0 extproc('gzeof')
D file value like(gzFile) File pointer
*
D gzclose PR 10i 0 extproc('gzclose')
D file value like(gzFile) File pointer
*
D gzerror PR * extproc('gzerror') Error string
D file value like(gzFile) File pointer
D errnum 10I 0 Error code
*
D gzclearerr PR extproc('gzclearerr')
D file value like(gzFile) File pointer
*
**************************************************************************
* Basic function prototypes
**************************************************************************
*
D zlibVersion PR * extproc('zlibVersion') Version string
*
D deflateInit PR 10I 0 extproc('deflateInit_') Init. compression
D strm like(z_stream) Compression stream
D level 10I 0 value Compression level
D version * value options(*string) Version string
D stream_size 10i 0 value Stream struct. size
*
D deflate PR 10I 0 extproc('deflate') Compress data
D strm like(z_stream) Compression stream
D flush 10I 0 value Flush type required
*
D deflateEnd PR 10I 0 extproc('deflateEnd') Termin. compression
D strm like(z_stream) Compression stream
*
D inflateInit PR 10I 0 extproc('inflateInit_') Init. expansion
D strm like(z_stream) Expansion stream
D version * value options(*string) Version string
D stream_size 10i 0 value Stream struct. size
*
D inflate PR 10I 0 extproc('inflate') Expand data
D strm like(z_stream) Expansion stream
D flush 10I 0 value Flush type required
*
D inflateEnd PR 10I 0 extproc('inflateEnd') Termin. expansion
D strm like(z_stream) Expansion stream
*
**************************************************************************
* Advanced function prototypes
**************************************************************************
*
D deflateInit2 PR 10I 0 extproc('deflateInit2_') Init. compression
D strm like(z_stream) Compression stream
D level 10I 0 value Compression level
D method 10I 0 value Compression method
D windowBits 10I 0 value log2(window size)
D memLevel 10I 0 value Mem/cmpress tradeoff
D strategy 10I 0 value Compression stategy
D version * value options(*string) Version string
D stream_size 10i 0 value Stream struct. size
*
D deflateSetDictionary...
D PR 10I 0 extproc('deflateSetDictionary') Init. dictionary
D strm like(z_stream) Compression stream
D dictionary 32767 const options(*varsize) Dictionary bytes
D dictLength 10U 0 value Dictionary length
*
D deflateCopy PR 10I 0 extproc('deflateCopy') Compress strm 2 strm
D dest like(z_stream) Destination stream
D source like(z_stream) Source stream
*
D deflateReset PR 10I 0 extproc('deflateReset') End and init. stream
D strm like(z_stream) Compression stream
*
D deflateParams PR 10I 0 extproc('deflateParams') Change level & strat
D strm like(z_stream) Compression stream
D level 10I 0 value Compression level
D strategy 10I 0 value Compression stategy
*
D deflateBound PR 10U 0 extproc('deflateBound') Change level & strat
D strm like(z_stream) Compression stream
D sourcelen 10U 0 value Compression level
*
D deflatePrime PR 10I 0 extproc('deflatePrime') Change level & strat
D strm like(z_stream) Compression stream
D bits 10I 0 value Number of bits to insert
D value 10I 0 value Bits to insert
*
D inflateInit2 PR 10I 0 extproc('inflateInit2_') Init. expansion
D strm like(z_stream) Expansion stream
D windowBits 10I 0 value log2(window size)
D version * value options(*string) Version string
D stream_size 10i 0 value Stream struct. size
*
D inflateSetDictionary...
D PR 10I 0 extproc('inflateSetDictionary') Init. dictionary
D strm like(z_stream) Expansion stream
D dictionary 32767 const options(*varsize) Dictionary bytes
D dictLength 10U 0 value Dictionary length
*
D inflateSync PR 10I 0 extproc('inflateSync') Sync. expansion
D strm like(z_stream) Expansion stream
*
D inflateCopy PR 10I 0 extproc('inflateCopy')
D dest like(z_stream) Destination stream
D source like(z_stream) Source stream
*
D inflateReset PR 10I 0 extproc('inflateReset') End and init. stream
D strm like(z_stream) Expansion stream
*
D inflateBackInit...
D PR 10I 0 extproc('inflateBackInit_')
D strm like(z_stream) Expansion stream
D windowBits 10I 0 value Log2(buffer size)
D window 32767 options(*varsize) Buffer
D version * value options(*string) Version string
D stream_size 10i 0 value Stream struct. size
*
D inflateBack PR 10I 0 extproc('inflateBack')
D strm like(z_stream) Expansion stream
D in * value procptr Input function
D in_desc * value Input descriptor
D out * value procptr Output function
D out_desc * value Output descriptor
*
D inflateBackEnd PR 10I 0 extproc('inflateBackEnd')
D strm like(z_stream) Expansion stream
*
D zlibCompileFlags...
D PR 10U 0 extproc('zlibCompileFlags')
*
**************************************************************************
* Checksum function prototypes
**************************************************************************
*
D adler32 PR 10U 0 extproc('adler32') New checksum
D adler 10U 0 value Old checksum
D buf 32767 const options(*varsize) Bytes to accumulate
D len 10U 0 value Buffer length
*
D crc32 PR 10U 0 extproc('crc32') New checksum
D crc 10U 0 value Old checksum
D buf 32767 const options(*varsize) Bytes to accumulate
D len 10U 0 value Buffer length
*
**************************************************************************
* Miscellaneous function prototypes
**************************************************************************
*
D zError PR * extproc('zError') Error string
D err 10I 0 value Error code
*
D inflateSyncPoint...
D PR 10I 0 extproc('inflateSyncPoint')
D strm like(z_stream) Expansion stream
*
D get_crc_table PR * extproc('get_crc_table') Ptr to ulongs
*
/endif

79
zlib/compress.c Normal file
View file

@ -0,0 +1,79 @@
/* compress.c -- compress a memory buffer
* Copyright (C) 1995-2002 Jean-loup Gailly.
* For conditions of distribution and use, see copyright notice in zlib.h
*/
/* @(#) $Id$ */
#define ZLIB_INTERNAL
#include "zlib.h"
/* ===========================================================================
Compresses the source buffer into the destination buffer. The level
parameter has the same meaning as in deflateInit. sourceLen is the byte
length of the source buffer. Upon entry, destLen is the total size of the
destination buffer, which must be at least 0.1% larger than sourceLen plus
12 bytes. Upon exit, destLen is the actual size of the compressed buffer.
compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
memory, Z_BUF_ERROR if there was not enough room in the output buffer,
Z_STREAM_ERROR if the level parameter is invalid.
*/
int ZEXPORT compress2 (dest, destLen, source, sourceLen, level)
Bytef *dest;
uLongf *destLen;
const Bytef *source;
uLong sourceLen;
int level;
{
z_stream stream;
int err;
stream.next_in = (Bytef*)source;
stream.avail_in = (uInt)sourceLen;
#ifdef MAXSEG_64K
/* Check for source > 64K on 16-bit machine: */
if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
#endif
stream.next_out = dest;
stream.avail_out = (uInt)*destLen;
if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
stream.zalloc = (alloc_func)0;
stream.zfree = (free_func)0;
stream.opaque = (voidpf)0;
err = deflateInit(&stream, level);
if (err != Z_OK) return err;
err = deflate(&stream, Z_FINISH);
if (err != Z_STREAM_END) {
deflateEnd(&stream);
return err == Z_OK ? Z_BUF_ERROR : err;
}
*destLen = stream.total_out;
err = deflateEnd(&stream);
return err;
}
/* ===========================================================================
*/
int ZEXPORT compress (dest, destLen, source, sourceLen)
Bytef *dest;
uLongf *destLen;
const Bytef *source;
uLong sourceLen;
{
return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION);
}
/* ===========================================================================
If the default memLevel or windowBits for deflateInit() is changed, then
this function needs to be updated.
*/
uLong ZEXPORT compressBound (sourceLen)
uLong sourceLen;
{
return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + 11;
}

445
zlib/configure vendored Normal file
View file

@ -0,0 +1,445 @@
#!/bin/sh
# configure script for zlib. This script is needed only if
# you wish to build a shared library and your system supports them,
# of if you need special compiler, flags or install directory.
# Otherwise, you can just use directly "make test; make install"
#
# To create a shared library, use "configure --shared"; by default a static
# library is created. If the primitive shared library support provided here
# does not work, use ftp://prep.ai.mit.edu/pub/gnu/libtool-*.tar.gz
#
# To impose specific compiler or flags or install directory, use for example:
# prefix=$HOME CC=cc CFLAGS="-O4" ./configure
# or for csh/tcsh users:
# (setenv prefix $HOME; setenv CC cc; setenv CFLAGS "-O4"; ./configure)
# LDSHARED is the command to be used to create a shared library
# Incorrect settings of CC or CFLAGS may prevent creating a shared library.
# If you have problems, try without defining CC and CFLAGS before reporting
# an error.
LIBS=libz.a
LDFLAGS="-L. ${LIBS}"
VER=`sed -n -e '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h`
VER2=`sed -n -e '/VERSION "/s/.*"\([0-9]*\\.[0-9]*\)\\..*/\1/p' < zlib.h`
VER1=`sed -n -e '/VERSION "/s/.*"\([0-9]*\)\\..*/\1/p' < zlib.h`
AR=${AR-"ar rc"}
RANLIB=${RANLIB-"ranlib"}
prefix=${prefix-/usr/local}
exec_prefix=${exec_prefix-'${prefix}'}
libdir=${libdir-'${exec_prefix}/lib'}
includedir=${includedir-'${prefix}/include'}
mandir=${mandir-'${prefix}/share/man'}
shared_ext='.so'
shared=0
gcc=0
old_cc="$CC"
old_cflags="$CFLAGS"
while test $# -ge 1
do
case "$1" in
-h* | --h*)
echo 'usage:'
echo ' configure [--shared] [--prefix=PREFIX] [--exec_prefix=EXPREFIX]'
echo ' [--libdir=LIBDIR] [--includedir=INCLUDEDIR]'
exit 0;;
-p*=* | --p*=*) prefix=`echo $1 | sed 's/[-a-z_]*=//'`; shift;;
-e*=* | --e*=*) exec_prefix=`echo $1 | sed 's/[-a-z_]*=//'`; shift;;
-l*=* | --libdir=*) libdir=`echo $1 | sed 's/[-a-z_]*=//'`; shift;;
-i*=* | --includedir=*) includedir=`echo $1 | sed 's/[-a-z_]*=//'`;shift;;
-p* | --p*) prefix="$2"; shift; shift;;
-e* | --e*) exec_prefix="$2"; shift; shift;;
-l* | --l*) libdir="$2"; shift; shift;;
-i* | --i*) includedir="$2"; shift; shift;;
-s* | --s*) shared=1; shift;;
*) echo "unknown option: $1"; echo "$0 --help for help"; exit 1;;
esac
done
test=ztest$$
cat > $test.c <<EOF
extern int getchar();
int hello() {return getchar();}
EOF
test -z "$CC" && echo Checking for gcc...
cc=${CC-gcc}
cflags=${CFLAGS-"-O3"}
# to force the asm version use: CFLAGS="-O3 -DASMV" ./configure
case "$cc" in
*gcc*) gcc=1;;
esac
if test "$gcc" -eq 1 && ($cc -c $cflags $test.c) 2>/dev/null; then
CC="$cc"
SFLAGS=${CFLAGS-"-fPIC -O3"}
CFLAGS="$cflags"
case `(uname -s || echo unknown) 2>/dev/null` in
Linux | linux | GNU | GNU/*) LDSHARED=${LDSHARED-"$cc -shared -Wl,-soname,libz.so.1"};;
CYGWIN* | Cygwin* | cygwin* )
EXE='.exe';;
QNX*) # This is for QNX6. I suppose that the QNX rule below is for QNX2,QNX4
# (alain.bonnefoy@icbt.com)
LDSHARED=${LDSHARED-"$cc -shared -Wl,-hlibz.so.1"};;
HP-UX*) LDSHARED=${LDSHARED-"$cc -shared $SFLAGS"}
shared_ext='.sl'
SHAREDLIB='libz.sl';;
Darwin*) shared_ext='.dylib'
SHAREDLIB=libz$shared_ext
SHAREDLIBV=libz.$VER$shared_ext
SHAREDLIBM=libz.$VER1$shared_ext
LDSHARED=${LDSHARED-"$cc -dynamiclib -install_name /usr/lib/$SHAREDLIBV -compatibility_version $VER2 -current_version $VER"}
libdir='/usr/lib'
includedir='/usr/include';;
*) LDSHARED=${LDSHARED-"$cc -shared"};;
esac
else
# find system name and corresponding cc options
CC=${CC-cc}
case `(uname -sr || echo unknown) 2>/dev/null` in
HP-UX*) SFLAGS=${CFLAGS-"-O +z"}
CFLAGS=${CFLAGS-"-O"}
# LDSHARED=${LDSHARED-"ld -b +vnocompatwarnings"}
LDSHARED=${LDSHARED-"ld -b"}
shared_ext='.sl'
SHAREDLIB='libz.sl';;
IRIX*) SFLAGS=${CFLAGS-"-ansi -O2 -rpath ."}
CFLAGS=${CFLAGS-"-ansi -O2"}
LDSHARED=${LDSHARED-"cc -shared"};;
OSF1\ V4*) SFLAGS=${CFLAGS-"-O -std1"}
CFLAGS=${CFLAGS-"-O -std1"}
LDSHARED=${LDSHARED-"cc -shared -Wl,-soname,libz.so -Wl,-msym -Wl,-rpath,$(libdir) -Wl,-set_version,${VER}:1.0"};;
OSF1*) SFLAGS=${CFLAGS-"-O -std1"}
CFLAGS=${CFLAGS-"-O -std1"}
LDSHARED=${LDSHARED-"cc -shared"};;
QNX*) SFLAGS=${CFLAGS-"-4 -O"}
CFLAGS=${CFLAGS-"-4 -O"}
LDSHARED=${LDSHARED-"cc"}
RANLIB=${RANLIB-"true"}
AR="cc -A";;
SCO_SV\ 3.2*) SFLAGS=${CFLAGS-"-O3 -dy -KPIC "}
CFLAGS=${CFLAGS-"-O3"}
LDSHARED=${LDSHARED-"cc -dy -KPIC -G"};;
SunOS\ 5*) SFLAGS=${CFLAGS-"-fast -xcg89 -KPIC -R."}
CFLAGS=${CFLAGS-"-fast -xcg89"}
LDSHARED=${LDSHARED-"cc -G"};;
SunOS\ 4*) SFLAGS=${CFLAGS-"-O2 -PIC"}
CFLAGS=${CFLAGS-"-O2"}
LDSHARED=${LDSHARED-"ld"};;
UNIX_System_V\ 4.2.0)
SFLAGS=${CFLAGS-"-KPIC -O"}
CFLAGS=${CFLAGS-"-O"}
LDSHARED=${LDSHARED-"cc -G"};;
UNIX_SV\ 4.2MP)
SFLAGS=${CFLAGS-"-Kconform_pic -O"}
CFLAGS=${CFLAGS-"-O"}
LDSHARED=${LDSHARED-"cc -G"};;
OpenUNIX\ 5)
SFLAGS=${CFLAGS-"-KPIC -O"}
CFLAGS=${CFLAGS-"-O"}
LDSHARED=${LDSHARED-"cc -G"};;
AIX*) # Courtesy of dbakker@arrayasolutions.com
SFLAGS=${CFLAGS-"-O -qmaxmem=8192"}
CFLAGS=${CFLAGS-"-O -qmaxmem=8192"}
LDSHARED=${LDSHARED-"xlc -G"};;
# send working options for other systems to support@gzip.org
*) SFLAGS=${CFLAGS-"-O"}
CFLAGS=${CFLAGS-"-O"}
LDSHARED=${LDSHARED-"cc -shared"};;
esac
fi
SHAREDLIB=${SHAREDLIB-"libz$shared_ext"}
SHAREDLIBV=${SHAREDLIBV-"libz$shared_ext.$VER"}
SHAREDLIBM=${SHAREDLIBM-"libz$shared_ext.$VER1"}
if test $shared -eq 1; then
echo Checking for shared library support...
# we must test in two steps (cc then ld), required at least on SunOS 4.x
if test "`($CC -c $SFLAGS $test.c) 2>&1`" = "" &&
test "`($LDSHARED -o $test$shared_ext $test.o) 2>&1`" = ""; then
CFLAGS="$SFLAGS"
LIBS="$SHAREDLIBV"
echo Building shared library $SHAREDLIBV with $CC.
elif test -z "$old_cc" -a -z "$old_cflags"; then
echo No shared library support.
shared=0;
else
echo 'No shared library support; try without defining CC and CFLAGS'
shared=0;
fi
fi
if test $shared -eq 0; then
LDSHARED="$CC"
echo Building static library $LIBS version $VER with $CC.
else
LDFLAGS="-L. ${SHAREDLIBV}"
fi
cat > $test.c <<EOF
#include <unistd.h>
int main() { return 0; }
EOF
if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then
sed < zconf.in.h "/HAVE_UNISTD_H/s%0%1%" > zconf.h
echo "Checking for unistd.h... Yes."
else
cp -p zconf.in.h zconf.h
echo "Checking for unistd.h... No."
fi
cat > $test.c <<EOF
#include <stdio.h>
#include <stdarg.h>
#include "zconf.h"
int main()
{
#ifndef STDC
choke me
#endif
return 0;
}
EOF
if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then
echo "Checking whether to use vs[n]printf() or s[n]printf()... using vs[n]printf()"
cat > $test.c <<EOF
#include <stdio.h>
#include <stdarg.h>
int mytest(char *fmt, ...)
{
char buf[20];
va_list ap;
va_start(ap, fmt);
vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
return 0;
}
int main()
{
return (mytest("Hello%d\n", 1));
}
EOF
if test "`($CC $CFLAGS -o $test $test.c) 2>&1`" = ""; then
echo "Checking for vsnprintf() in stdio.h... Yes."
cat >$test.c <<EOF
#include <stdio.h>
#include <stdarg.h>
int mytest(char *fmt, ...)
{
int n;
char buf[20];
va_list ap;
va_start(ap, fmt);
n = vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
return n;
}
int main()
{
return (mytest("Hello%d\n", 1));
}
EOF
if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then
echo "Checking for return value of vsnprintf()... Yes."
else
CFLAGS="$CFLAGS -DHAS_vsnprintf_void"
echo "Checking for return value of vsnprintf()... No."
echo " WARNING: apparently vsnprintf() does not return a value. zlib"
echo " can build but will be open to possible string-format security"
echo " vulnerabilities."
fi
else
CFLAGS="$CFLAGS -DNO_vsnprintf"
echo "Checking for vsnprintf() in stdio.h... No."
echo " WARNING: vsnprintf() not found, falling back to vsprintf(). zlib"
echo " can build but will be open to possible buffer-overflow security"
echo " vulnerabilities."
cat >$test.c <<EOF
#include <stdio.h>
#include <stdarg.h>
int mytest(char *fmt, ...)
{
int n;
char buf[20];
va_list ap;
va_start(ap, fmt);
n = vsprintf(buf, fmt, ap);
va_end(ap);
return n;
}
int main()
{
return (mytest("Hello%d\n", 1));
}
EOF
if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then
echo "Checking for return value of vsprintf()... Yes."
else
CFLAGS="$CFLAGS -DHAS_vsprintf_void"
echo "Checking for return value of vsprintf()... No."
echo " WARNING: apparently vsprintf() does not return a value. zlib"
echo " can build but will be open to possible string-format security"
echo " vulnerabilities."
fi
fi
else
echo "Checking whether to use vs[n]printf() or s[n]printf()... using s[n]printf()"
cat >$test.c <<EOF
#include <stdio.h>
int mytest()
{
char buf[20];
snprintf(buf, sizeof(buf), "%s", "foo");
return 0;
}
int main()
{
return (mytest());
}
EOF
if test "`($CC $CFLAGS -o $test $test.c) 2>&1`" = ""; then
echo "Checking for snprintf() in stdio.h... Yes."
cat >$test.c <<EOF
#include <stdio.h>
int mytest()
{
char buf[20];
return snprintf(buf, sizeof(buf), "%s", "foo");
}
int main()
{
return (mytest());
}
EOF
if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then
echo "Checking for return value of snprintf()... Yes."
else
CFLAGS="$CFLAGS -DHAS_snprintf_void"
echo "Checking for return value of snprintf()... No."
echo " WARNING: apparently snprintf() does not return a value. zlib"
echo " can build but will be open to possible string-format security"
echo " vulnerabilities."
fi
else
CFLAGS="$CFLAGS -DNO_snprintf"
echo "Checking for snprintf() in stdio.h... No."
echo " WARNING: snprintf() not found, falling back to sprintf(). zlib"
echo " can build but will be open to possible buffer-overflow security"
echo " vulnerabilities."
cat >$test.c <<EOF
#include <stdio.h>
int mytest()
{
char buf[20];
return sprintf(buf, "%s", "foo");
}
int main()
{
return (mytest());
}
EOF
if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then
echo "Checking for return value of sprintf()... Yes."
else
CFLAGS="$CFLAGS -DHAS_sprintf_void"
echo "Checking for return value of sprintf()... No."
echo " WARNING: apparently sprintf() does not return a value. zlib"
echo " can build but will be open to possible string-format security"
echo " vulnerabilities."
fi
fi
fi
cat >$test.c <<EOF
#include <errno.h>
int main() { return 0; }
EOF
if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then
echo "Checking for errno.h... Yes."
else
echo "Checking for errno.h... No."
CFLAGS="$CFLAGS -DNO_ERRNO_H"
fi
cat > $test.c <<EOF
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
caddr_t hello() {
return mmap((caddr_t)0, (off_t)0, PROT_READ, MAP_SHARED, 0, (off_t)0);
}
EOF
if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then
CFLAGS="$CFLAGS -DUSE_MMAP"
echo Checking for mmap support... Yes.
else
echo Checking for mmap support... No.
fi
CPP=${CPP-"$CC -E"}
case $CFLAGS in
*ASMV*)
if test "`nm $test.o | grep _hello`" = ""; then
CPP="$CPP -DNO_UNDERLINE"
echo Checking for underline in external names... No.
else
echo Checking for underline in external names... Yes.
fi;;
esac
rm -f $test.[co] $test $test$shared_ext
# udpate Makefile
sed < Makefile.in "
/^CC *=/s#=.*#=$CC#
/^CFLAGS *=/s#=.*#=$CFLAGS#
/^CPP *=/s#=.*#=$CPP#
/^LDSHARED *=/s#=.*#=$LDSHARED#
/^LIBS *=/s#=.*#=$LIBS#
/^SHAREDLIB *=/s#=.*#=$SHAREDLIB#
/^SHAREDLIBV *=/s#=.*#=$SHAREDLIBV#
/^SHAREDLIBM *=/s#=.*#=$SHAREDLIBM#
/^AR *=/s#=.*#=$AR#
/^RANLIB *=/s#=.*#=$RANLIB#
/^EXE *=/s#=.*#=$EXE#
/^prefix *=/s#=.*#=$prefix#
/^exec_prefix *=/s#=.*#=$exec_prefix#
/^libdir *=/s#=.*#=$libdir#
/^includedir *=/s#=.*#=$includedir#
/^mandir *=/s#=.*#=$mandir#
/^LDFLAGS *=/s#=.*#=$LDFLAGS#
" > Makefile

View file

@ -0,0 +1,70 @@
All files under this contrib directory are UNSUPPORTED. There were
provided by users of zlib and were not tested by the authors of zlib.
Use at your own risk. Please contact the authors of the contributions
for help about these, not the zlib authors. Thanks.
ada/ by Dmitriy Anisimkov <anisimkov@yahoo.com>
Support for Ada
See http://zlib-ada.sourceforge.net/
asm586/
asm686/ by Brian Raiter <breadbox@muppetlabs.com>
asm code for Pentium and PPro/PII, using the AT&T (GNU as) syntax
See http://www.muppetlabs.com/~breadbox/software/assembly.html
blast/ by Mark Adler <madler@alumni.caltech.edu>
Decompressor for output of PKWare Data Compression Library (DCL)
delphi/ by Cosmin Truta <cosmint@cs.ubbcluj.ro>
Support for Delphi and C++ Builder
gzappend/ by Mark Adler <madler@alumni.caltech.edu>
append to a gzip file -- illustrates the use of Z_BLOCK
infback9/ by Mark Adler <madler@alumni.caltech.edu>
Unsupported diffs to infback to decode the deflate64 format
inflate86/ by Chris Anderson <christop@charm.net>
Tuned x86 gcc asm code to replace inflate_fast()
iostream/ by Kevin Ruland <kevin@rodin.wustl.edu>
A C++ I/O streams interface to the zlib gz* functions
iostream2/ by Tyge Løvset <Tyge.Lovset@cmr.no>
Another C++ I/O streams interface
iostream3/ by Ludwig Schwardt <schwardt@sun.ac.za>
and Kevin Ruland <kevin@rodin.wustl.edu>
Yet another C++ I/O streams interface
masm686/ by Dan Higdon <hdan@kinesoft.com>
and Chuck Walbourn <chuckw@kinesoft.com>
asm code for Pentium Pro/PII, using the MASM syntax
masmx86/ by Gilles Vollant <info@winimage.com>
x86 asm code to replace longest_match() and inflate_fast(),
for Visual C++ and MASM
minizip/ by Gilles Vollant <info@winimage.com>
Mini zip and unzip based on zlib
See http://www.winimage.com/zLibDll/unzip.html
pascal/ by Bob Dellaca <bobdl@xtra.co.nz> et al.
Support for Pascal
puff/ by Mark Adler <madler@alumni.caltech.edu>
Small, low memory usage inflate. Also serves to provide an
unambiguous description of the deflate format.
testzlib/ by Gilles Vollant <info@winimage.com>
Example of the use of zlib
untgz/ by "Pedro A. Aranda Guti\irrez" <paag@tid.es>
A very simple tar.gz file extractor using zlib
visual-basic.txt by Carlos Rios <c_rios@sonda.cl>
How to use compress(), uncompress() and the gz* functions from VB
vstudio/ by Gilles Vollant <info@winimage.com>
Building zlib with Visual Studio .NET

153
zlib/contrib/ada/mtest.adb Normal file
View file

@ -0,0 +1,153 @@
----------------------------------------------------------------
-- ZLib for Ada thick binding. --
-- --
-- Copyright (C) 2002-2003 Dmitriy Anisimkov --
-- --
-- Open source license information is in the zlib.ads file. --
----------------------------------------------------------------
-- Continuous test for ZLib multithreading. If the test is fail
-- Wou should provide thread safe allocation routines for the Z_Stream.
--
-- $Id: mtest.adb,v 1.2 2003/08/12 12:11:05 vagul Exp $
with ZLib;
with Ada.Streams;
with Ada.Numerics.Discrete_Random;
with Ada.Text_IO;
with Ada.Exceptions;
with Ada.Task_Identification;
procedure MTest is
use Ada.Streams;
use ZLib;
Stop : Boolean := False;
pragma Atomic (Stop);
subtype Visible_Symbols is Stream_Element range 16#20# .. 16#7E#;
package Random_Elements is
new Ada.Numerics.Discrete_Random (Visible_Symbols);
task type Test_Task;
task body Test_Task is
Buffer : Stream_Element_Array (1 .. 100_000);
Gen : Random_Elements.Generator;
Buffer_First : Stream_Element_Offset;
Compare_First : Stream_Element_Offset;
Deflate : Filter_Type;
Inflate : Filter_Type;
procedure Further (Item : in Stream_Element_Array);
procedure Read_Buffer
(Item : out Ada.Streams.Stream_Element_Array;
Last : out Ada.Streams.Stream_Element_Offset);
-------------
-- Further --
-------------
procedure Further (Item : in Stream_Element_Array) is
procedure Compare (Item : in Stream_Element_Array);
-------------
-- Compare --
-------------
procedure Compare (Item : in Stream_Element_Array) is
Next_First : Stream_Element_Offset := Compare_First + Item'Length;
begin
if Buffer (Compare_First .. Next_First - 1) /= Item then
raise Program_Error;
end if;
Compare_First := Next_First;
end Compare;
procedure Compare_Write is new ZLib.Write (Write => Compare);
begin
Compare_Write (Inflate, Item, No_Flush);
end Further;
-----------------
-- Read_Buffer --
-----------------
procedure Read_Buffer
(Item : out Ada.Streams.Stream_Element_Array;
Last : out Ada.Streams.Stream_Element_Offset)
is
Buff_Diff : Stream_Element_Offset := Buffer'Last - Buffer_First;
Next_First : Stream_Element_Offset;
begin
if Item'Length <= Buff_Diff then
Last := Item'Last;
Next_First := Buffer_First + Item'Length;
Item := Buffer (Buffer_First .. Next_First - 1);
Buffer_First := Next_First;
else
Last := Item'First + Buff_Diff;
Item (Item'First .. Last) := Buffer (Buffer_First .. Buffer'Last);
Buffer_First := Buffer'Last + 1;
end if;
end Read_Buffer;
procedure Translate is new Generic_Translate
(Data_In => Read_Buffer,
Data_Out => Further);
begin
Random_Elements.Reset (Gen);
Buffer := (others => 20);
Main : loop
for J in Buffer'Range loop
Buffer (J) := Random_Elements.Random (Gen);
Deflate_Init (Deflate);
Inflate_Init (Inflate);
Buffer_First := Buffer'First;
Compare_First := Buffer'First;
Translate (Deflate);
if Compare_First /= Buffer'Last + 1 then
raise Program_Error;
end if;
Ada.Text_IO.Put_Line
(Ada.Task_Identification.Image
(Ada.Task_Identification.Current_Task)
& Stream_Element_Offset'Image (J)
& ZLib.Count'Image (Total_Out (Deflate)));
Close (Deflate);
Close (Inflate);
exit Main when Stop;
end loop;
end loop Main;
exception
when E : others =>
Ada.Text_IO.Put_Line (Ada.Exceptions.Exception_Information (E));
Stop := True;
end Test_Task;
Test : array (1 .. 4) of Test_Task;
pragma Unreferenced (Test);
begin
null;
end MTest;

151
zlib/contrib/ada/read.adb Normal file
View file

@ -0,0 +1,151 @@
----------------------------------------------------------------
-- ZLib for Ada thick binding. --
-- --
-- Copyright (C) 2002-2003 Dmitriy Anisimkov --
-- --
-- Open source license information is in the zlib.ads file. --
----------------------------------------------------------------
-- $Id: read.adb,v 1.7 2003/08/12 12:12:35 vagul Exp $
-- Test/demo program for the generic read interface.
with Ada.Numerics.Discrete_Random;
with Ada.Streams;
with Ada.Text_IO;
with ZLib;
procedure Read is
use Ada.Streams;
------------------------------------
-- Test configuration parameters --
------------------------------------
File_Size : Stream_Element_Offset := 100_000;
Continuous : constant Boolean := False;
-- If this constant is True, the test would be repeated again and again,
-- with increment File_Size for every iteration.
Header : constant ZLib.Header_Type := ZLib.Default;
-- Do not use Header other than Default in ZLib versions 1.1.4 and older.
Init_Random : constant := 8;
-- We are using the same random sequence, in case of we catch bug,
-- so we would be able to reproduce it.
-- End --
Pack_Size : Stream_Element_Offset;
Offset : Stream_Element_Offset;
Filter : ZLib.Filter_Type;
subtype Visible_Symbols
is Stream_Element range 16#20# .. 16#7E#;
package Random_Elements is new
Ada.Numerics.Discrete_Random (Visible_Symbols);
Gen : Random_Elements.Generator;
Period : constant Stream_Element_Offset := 200;
-- Period constant variable for random generator not to be very random.
-- Bigger period, harder random.
Read_Buffer : Stream_Element_Array (1 .. 2048);
Read_First : Stream_Element_Offset;
Read_Last : Stream_Element_Offset;
procedure Reset;
procedure Read
(Item : out Stream_Element_Array;
Last : out Stream_Element_Offset);
-- this procedure is for generic instantiation of
-- ZLib.Read
-- reading data from the File_In.
procedure Read is new ZLib.Read (Read, Read_Buffer, Read_First, Read_Last);
----------
-- Read --
----------
procedure Read
(Item : out Stream_Element_Array;
Last : out Stream_Element_Offset) is
begin
Last := Stream_Element_Offset'Min
(Item'Last,
Item'First + File_Size - Offset);
for J in Item'First .. Last loop
if J < Item'First + Period then
Item (J) := Random_Elements.Random (Gen);
else
Item (J) := Item (J - Period);
end if;
Offset := Offset + 1;
end loop;
end Read;
-----------
-- Reset --
-----------
procedure Reset is
begin
Random_Elements.Reset (Gen, Init_Random);
Pack_Size := 0;
Offset := 1;
Read_First := Read_Buffer'Last + 1;
end Reset;
begin
Ada.Text_IO.Put_Line ("ZLib " & ZLib.Version);
loop
for Level in ZLib.Compression_Level'Range loop
Ada.Text_IO.Put ("Level ="
& ZLib.Compression_Level'Image (Level));
-- Deflate using generic instantiation.
ZLib.Deflate_Init
(Filter,
Level,
Header => Header);
Reset;
Ada.Text_IO.Put
(Stream_Element_Offset'Image (File_Size) & " ->");
loop
declare
Buffer : Stream_Element_Array (1 .. 1024);
Last : Stream_Element_Offset;
begin
Read (Filter, Buffer, Last);
Pack_Size := Pack_Size + Last - Buffer'First + 1;
exit when Last < Buffer'Last;
end;
end loop;
Ada.Text_IO.Put_Line (Stream_Element_Offset'Image (Pack_Size));
ZLib.Close (Filter);
end loop;
exit when not Continuous;
File_Size := File_Size + 1;
end loop;
end Read;

View file

@ -0,0 +1,52 @@
ZLib for Ada thick binding (ZLib.Ada)
Release 1.2
ZLib.Ada is a thick binding interface to the popular ZLib data
compression library, available at http://www.gzip.org/zlib/.
It provides Ada-style access to the ZLib C library.
Here are the main changes since ZLib.Ada 1.1:
- The default header type has a name "Default" now. Auto is used only for
automatic GZip/ZLib header detection.
- Added test for multitasking mtest.adb.
- Added GNAT project file zlib.gpr.
How to build ZLib.Ada under GNAT
You should have the ZLib library already build on your computer, before
building ZLib.Ada. Make the directory of ZLib.Ada sources current and
issue the command:
gnatmake test -largs -L<directory where libz.a is> -lz
Or use the GNAT project file build for GNAT 3.15 or later:
gnatmake -Pzlib.gpr -L<directory where libz.a is>
How to build ZLib.Ada under Aonix ObjectAda for Win32 7.2.2
1. Make a project with all *.ads and *.adb files from the distribution.
2. Build the libz.a library from the ZLib C sources.
3. Rename libz.a to z.lib.
4. Add the library z.lib to the project.
5. Add the libc.lib library from the ObjectAda distribution to the project.
6. Build the executable using test.adb as a main procedure.
How to use ZLib.Ada
The source files test.adb and read.adb are small demo programs that show
the main functionality of ZLib.Ada.
The routines from the package specifications are commented.
Homepage: http://zlib-ada.sourceforge.net/
Author: Dmitriy Anisimkov <anisimkov@yahoo.com>

463
zlib/contrib/ada/test.adb Normal file
View file

@ -0,0 +1,463 @@
----------------------------------------------------------------
-- ZLib for Ada thick binding. --
-- --
-- Copyright (C) 2002-2003 Dmitriy Anisimkov --
-- --
-- Open source license information is in the zlib.ads file. --
----------------------------------------------------------------
-- $Id: test.adb,v 1.17 2003/08/12 12:13:30 vagul Exp $
-- The program has a few aims.
-- 1. Test ZLib.Ada95 thick binding functionality.
-- 2. Show the example of use main functionality of the ZLib.Ada95 binding.
-- 3. Build this program automatically compile all ZLib.Ada95 packages under
-- GNAT Ada95 compiler.
with ZLib.Streams;
with Ada.Streams.Stream_IO;
with Ada.Numerics.Discrete_Random;
with Ada.Text_IO;
with Ada.Calendar;
procedure Test is
use Ada.Streams;
use Stream_IO;
------------------------------------
-- Test configuration parameters --
------------------------------------
File_Size : Count := 100_000;
Continuous : constant Boolean := False;
Header : constant ZLib.Header_Type := ZLib.Default;
-- ZLib.None;
-- ZLib.Auto;
-- ZLib.GZip;
-- Do not use Header other then Default in ZLib versions 1.1.4
-- and older.
Strategy : constant ZLib.Strategy_Type := ZLib.Default_Strategy;
Init_Random : constant := 10;
-- End --
In_File_Name : constant String := "testzlib.in";
-- Name of the input file
Z_File_Name : constant String := "testzlib.zlb";
-- Name of the compressed file.
Out_File_Name : constant String := "testzlib.out";
-- Name of the decompressed file.
File_In : File_Type;
File_Out : File_Type;
File_Back : File_Type;
File_Z : ZLib.Streams.Stream_Type;
Filter : ZLib.Filter_Type;
Time_Stamp : Ada.Calendar.Time;
procedure Generate_File;
-- Generate file of spetsified size with some random data.
-- The random data is repeatable, for the good compression.
procedure Compare_Streams
(Left, Right : in out Root_Stream_Type'Class);
-- The procedure compearing data in 2 streams.
-- It is for compare data before and after compression/decompression.
procedure Compare_Files (Left, Right : String);
-- Compare files. Based on the Compare_Streams.
procedure Copy_Streams
(Source, Target : in out Root_Stream_Type'Class;
Buffer_Size : in Stream_Element_Offset := 1024);
-- Copying data from one stream to another. It is for test stream
-- interface of the library.
procedure Data_In
(Item : out Stream_Element_Array;
Last : out Stream_Element_Offset);
-- this procedure is for generic instantiation of
-- ZLib.Generic_Translate.
-- reading data from the File_In.
procedure Data_Out (Item : in Stream_Element_Array);
-- this procedure is for generic instantiation of
-- ZLib.Generic_Translate.
-- writing data to the File_Out.
procedure Stamp;
-- Store the timestamp to the local variable.
procedure Print_Statistic (Msg : String; Data_Size : ZLib.Count);
-- Print the time statistic with the message.
procedure Translate is new ZLib.Generic_Translate
(Data_In => Data_In,
Data_Out => Data_Out);
-- This procedure is moving data from File_In to File_Out
-- with compression or decompression, depend on initialization of
-- Filter parameter.
-------------------
-- Compare_Files --
-------------------
procedure Compare_Files (Left, Right : String) is
Left_File, Right_File : File_Type;
begin
Open (Left_File, In_File, Left);
Open (Right_File, In_File, Right);
Compare_Streams (Stream (Left_File).all, Stream (Right_File).all);
Close (Left_File);
Close (Right_File);
end Compare_Files;
---------------------
-- Compare_Streams --
---------------------
procedure Compare_Streams
(Left, Right : in out Ada.Streams.Root_Stream_Type'Class)
is
Left_Buffer, Right_Buffer : Stream_Element_Array (0 .. 16#FFF#);
Left_Last, Right_Last : Stream_Element_Offset;
begin
loop
Read (Left, Left_Buffer, Left_Last);
Read (Right, Right_Buffer, Right_Last);
if Left_Last /= Right_Last then
Ada.Text_IO.Put_Line ("Compare error :"
& Stream_Element_Offset'Image (Left_Last)
& " /= "
& Stream_Element_Offset'Image (Right_Last));
raise Constraint_Error;
elsif Left_Buffer (0 .. Left_Last)
/= Right_Buffer (0 .. Right_Last)
then
Ada.Text_IO.Put_Line ("ERROR: IN and OUT files is not equal.");
raise Constraint_Error;
end if;
exit when Left_Last < Left_Buffer'Last;
end loop;
end Compare_Streams;
------------------
-- Copy_Streams --
------------------
procedure Copy_Streams
(Source, Target : in out Ada.Streams.Root_Stream_Type'Class;
Buffer_Size : in Stream_Element_Offset := 1024)
is
Buffer : Stream_Element_Array (1 .. Buffer_Size);
Last : Stream_Element_Offset;
begin
loop
Read (Source, Buffer, Last);
Write (Target, Buffer (1 .. Last));
exit when Last < Buffer'Last;
end loop;
end Copy_Streams;
-------------
-- Data_In --
-------------
procedure Data_In
(Item : out Stream_Element_Array;
Last : out Stream_Element_Offset) is
begin
Read (File_In, Item, Last);
end Data_In;
--------------
-- Data_Out --
--------------
procedure Data_Out (Item : in Stream_Element_Array) is
begin
Write (File_Out, Item);
end Data_Out;
-------------------
-- Generate_File --
-------------------
procedure Generate_File is
subtype Visible_Symbols is Stream_Element range 16#20# .. 16#7E#;
package Random_Elements is
new Ada.Numerics.Discrete_Random (Visible_Symbols);
Gen : Random_Elements.Generator;
Buffer : Stream_Element_Array := (1 .. 77 => 16#20#) & 10;
Buffer_Count : constant Count := File_Size / Buffer'Length;
-- Number of same buffers in the packet.
Density : constant Count := 30; -- from 0 to Buffer'Length - 2;
procedure Fill_Buffer (J, D : in Count);
-- Change the part of the buffer.
-----------------
-- Fill_Buffer --
-----------------
procedure Fill_Buffer (J, D : in Count) is
begin
for K in 0 .. D loop
Buffer
(Stream_Element_Offset ((J + K) mod (Buffer'Length - 1) + 1))
:= Random_Elements.Random (Gen);
end loop;
end Fill_Buffer;
begin
Random_Elements.Reset (Gen, Init_Random);
Create (File_In, Out_File, In_File_Name);
Fill_Buffer (1, Buffer'Length - 2);
for J in 1 .. Buffer_Count loop
Write (File_In, Buffer);
Fill_Buffer (J, Density);
end loop;
-- fill remain size.
Write
(File_In,
Buffer
(1 .. Stream_Element_Offset
(File_Size - Buffer'Length * Buffer_Count)));
Flush (File_In);
Close (File_In);
end Generate_File;
---------------------
-- Print_Statistic --
---------------------
procedure Print_Statistic (Msg : String; Data_Size : ZLib.Count) is
use Ada.Calendar;
use Ada.Text_IO;
package Count_IO is new Integer_IO (ZLib.Count);
Curr_Dur : Duration := Clock - Time_Stamp;
begin
Put (Msg);
Set_Col (20);
Ada.Text_IO.Put ("size =");
Count_IO.Put
(Data_Size,
Width => Stream_IO.Count'Image (File_Size)'Length);
Put_Line (" duration =" & Duration'Image (Curr_Dur));
end Print_Statistic;
-----------
-- Stamp --
-----------
procedure Stamp is
begin
Time_Stamp := Ada.Calendar.Clock;
end Stamp;
begin
Ada.Text_IO.Put_Line ("ZLib " & ZLib.Version);
loop
Generate_File;
for Level in ZLib.Compression_Level'Range loop
Ada.Text_IO.Put_Line ("Level ="
& ZLib.Compression_Level'Image (Level));
-- Test generic interface.
Open (File_In, In_File, In_File_Name);
Create (File_Out, Out_File, Z_File_Name);
Stamp;
-- Deflate using generic instantiation.
ZLib.Deflate_Init
(Filter => Filter,
Level => Level,
Strategy => Strategy,
Header => Header);
Translate (Filter);
Print_Statistic ("Generic compress", ZLib.Total_Out (Filter));
ZLib.Close (Filter);
Close (File_In);
Close (File_Out);
Open (File_In, In_File, Z_File_Name);
Create (File_Out, Out_File, Out_File_Name);
Stamp;
-- Inflate using generic instantiation.
ZLib.Inflate_Init (Filter, Header => Header);
Translate (Filter);
Print_Statistic ("Generic decompress", ZLib.Total_Out (Filter));
ZLib.Close (Filter);
Close (File_In);
Close (File_Out);
Compare_Files (In_File_Name, Out_File_Name);
-- Test stream interface.
-- Compress to the back stream.
Open (File_In, In_File, In_File_Name);
Create (File_Back, Out_File, Z_File_Name);
Stamp;
ZLib.Streams.Create
(Stream => File_Z,
Mode => ZLib.Streams.Out_Stream,
Back => ZLib.Streams.Stream_Access
(Stream (File_Back)),
Back_Compressed => True,
Level => Level,
Strategy => Strategy,
Header => Header);
Copy_Streams
(Source => Stream (File_In).all,
Target => File_Z);
-- Flushing internal buffers to the back stream.
ZLib.Streams.Flush (File_Z, ZLib.Finish);
Print_Statistic ("Write compress",
ZLib.Streams.Write_Total_Out (File_Z));
ZLib.Streams.Close (File_Z);
Close (File_In);
Close (File_Back);
-- Compare reading from original file and from
-- decompression stream.
Open (File_In, In_File, In_File_Name);
Open (File_Back, In_File, Z_File_Name);
ZLib.Streams.Create
(Stream => File_Z,
Mode => ZLib.Streams.In_Stream,
Back => ZLib.Streams.Stream_Access
(Stream (File_Back)),
Back_Compressed => True,
Header => Header);
Stamp;
Compare_Streams (Stream (File_In).all, File_Z);
Print_Statistic ("Read decompress",
ZLib.Streams.Read_Total_Out (File_Z));
ZLib.Streams.Close (File_Z);
Close (File_In);
Close (File_Back);
-- Compress by reading from compression stream.
Open (File_Back, In_File, In_File_Name);
Create (File_Out, Out_File, Z_File_Name);
ZLib.Streams.Create
(Stream => File_Z,
Mode => ZLib.Streams.In_Stream,
Back => ZLib.Streams.Stream_Access
(Stream (File_Back)),
Back_Compressed => False,
Level => Level,
Strategy => Strategy,
Header => Header);
Stamp;
Copy_Streams
(Source => File_Z,
Target => Stream (File_Out).all);
Print_Statistic ("Read compress",
ZLib.Streams.Read_Total_Out (File_Z));
ZLib.Streams.Close (File_Z);
Close (File_Out);
Close (File_Back);
-- Decompress to decompression stream.
Open (File_In, In_File, Z_File_Name);
Create (File_Back, Out_File, Out_File_Name);
ZLib.Streams.Create
(Stream => File_Z,
Mode => ZLib.Streams.Out_Stream,
Back => ZLib.Streams.Stream_Access
(Stream (File_Back)),
Back_Compressed => False,
Header => Header);
Stamp;
Copy_Streams
(Source => Stream (File_In).all,
Target => File_Z);
Print_Statistic ("Write decompress",
ZLib.Streams.Write_Total_Out (File_Z));
ZLib.Streams.Close (File_Z);
Close (File_In);
Close (File_Back);
Compare_Files (In_File_Name, Out_File_Name);
end loop;
Ada.Text_IO.Put_Line (Count'Image (File_Size) & " Ok.");
exit when not Continuous;
File_Size := File_Size + 1;
end loop;
end Test;

View file

@ -0,0 +1,215 @@
----------------------------------------------------------------
-- ZLib for Ada thick binding. --
-- --
-- Copyright (C) 2002-2003 Dmitriy Anisimkov --
-- --
-- Open source license information is in the zlib.ads file. --
----------------------------------------------------------------
-- $Id: zlib-streams.adb,v 1.9 2003/08/12 13:15:31 vagul Exp $
with Ada.Unchecked_Deallocation;
package body ZLib.Streams is
-----------
-- Close --
-----------
procedure Close (Stream : in out Stream_Type) is
procedure Free is new Ada.Unchecked_Deallocation
(Stream_Element_Array, Buffer_Access);
begin
if Stream.Mode = Out_Stream or Stream.Mode = Duplex then
-- We should flush the data written by the writer.
Flush (Stream, Finish);
Close (Stream.Writer);
end if;
if Stream.Mode = In_Stream or Stream.Mode = Duplex then
Close (Stream.Reader);
Free (Stream.Buffer);
end if;
end Close;
------------
-- Create --
------------
procedure Create
(Stream : out Stream_Type;
Mode : in Stream_Mode;
Back : in Stream_Access;
Back_Compressed : in Boolean;
Level : in Compression_Level := Default_Compression;
Strategy : in Strategy_Type := Default_Strategy;
Header : in Header_Type := Default;
Read_Buffer_Size : in Ada.Streams.Stream_Element_Offset
:= Default_Buffer_Size;
Write_Buffer_Size : in Ada.Streams.Stream_Element_Offset
:= Default_Buffer_Size)
is
subtype Buffer_Subtype is Stream_Element_Array (1 .. Read_Buffer_Size);
procedure Init_Filter
(Filter : in out Filter_Type;
Compress : in Boolean);
-----------------
-- Init_Filter --
-----------------
procedure Init_Filter
(Filter : in out Filter_Type;
Compress : in Boolean) is
begin
if Compress then
Deflate_Init
(Filter, Level, Strategy, Header => Header);
else
Inflate_Init (Filter, Header => Header);
end if;
end Init_Filter;
begin
Stream.Back := Back;
Stream.Mode := Mode;
if Mode = Out_Stream or Mode = Duplex then
Init_Filter (Stream.Writer, Back_Compressed);
Stream.Buffer_Size := Write_Buffer_Size;
else
Stream.Buffer_Size := 0;
end if;
if Mode = In_Stream or Mode = Duplex then
Init_Filter (Stream.Reader, not Back_Compressed);
Stream.Buffer := new Buffer_Subtype;
Stream.Rest_First := Stream.Buffer'Last + 1;
end if;
end Create;
-----------
-- Flush --
-----------
procedure Flush
(Stream : in out Stream_Type;
Mode : in Flush_Mode := Sync_Flush)
is
Buffer : Stream_Element_Array (1 .. Stream.Buffer_Size);
Last : Stream_Element_Offset;
begin
loop
Flush (Stream.Writer, Buffer, Last, Mode);
Ada.Streams.Write (Stream.Back.all, Buffer (1 .. Last));
exit when Last < Buffer'Last;
end loop;
end Flush;
----------
-- Read --
----------
procedure Read
(Stream : in out Stream_Type;
Item : out Stream_Element_Array;
Last : out Stream_Element_Offset)
is
procedure Read
(Item : out Stream_Element_Array;
Last : out Stream_Element_Offset);
----------
-- Read --
----------
procedure Read
(Item : out Stream_Element_Array;
Last : out Stream_Element_Offset) is
begin
Ada.Streams.Read (Stream.Back.all, Item, Last);
end Read;
procedure Read is new ZLib.Read
(Read => Read,
Buffer => Stream.Buffer.all,
Rest_First => Stream.Rest_First,
Rest_Last => Stream.Rest_Last);
begin
Read (Stream.Reader, Item, Last);
end Read;
-------------------
-- Read_Total_In --
-------------------
function Read_Total_In (Stream : in Stream_Type) return Count is
begin
return Total_In (Stream.Reader);
end Read_Total_In;
--------------------
-- Read_Total_Out --
--------------------
function Read_Total_Out (Stream : in Stream_Type) return Count is
begin
return Total_Out (Stream.Reader);
end Read_Total_Out;
-----------
-- Write --
-----------
procedure Write
(Stream : in out Stream_Type;
Item : in Stream_Element_Array)
is
procedure Write (Item : in Stream_Element_Array);
-----------
-- Write --
-----------
procedure Write (Item : in Stream_Element_Array) is
begin
Ada.Streams.Write (Stream.Back.all, Item);
end Write;
procedure Write is new ZLib.Write
(Write => Write,
Buffer_Size => Stream.Buffer_Size);
begin
Write (Stream.Writer, Item, No_Flush);
end Write;
--------------------
-- Write_Total_In --
--------------------
function Write_Total_In (Stream : in Stream_Type) return Count is
begin
return Total_In (Stream.Writer);
end Write_Total_In;
---------------------
-- Write_Total_Out --
---------------------
function Write_Total_Out (Stream : in Stream_Type) return Count is
begin
return Total_Out (Stream.Writer);
end Write_Total_Out;
end ZLib.Streams;

View file

@ -0,0 +1,112 @@
----------------------------------------------------------------
-- ZLib for Ada thick binding. --
-- --
-- Copyright (C) 2002-2003 Dmitriy Anisimkov --
-- --
-- Open source license information is in the zlib.ads file. --
----------------------------------------------------------------
-- $Id: zlib-streams.ads,v 1.11 2003/08/12 13:15:31 vagul Exp $
package ZLib.Streams is
type Stream_Mode is (In_Stream, Out_Stream, Duplex);
type Stream_Access is access all Ada.Streams.Root_Stream_Type'Class;
type Stream_Type is
new Ada.Streams.Root_Stream_Type with private;
procedure Read
(Stream : in out Stream_Type;
Item : out Ada.Streams.Stream_Element_Array;
Last : out Ada.Streams.Stream_Element_Offset);
procedure Write
(Stream : in out Stream_Type;
Item : in Ada.Streams.Stream_Element_Array);
procedure Flush
(Stream : in out Stream_Type;
Mode : in Flush_Mode := Sync_Flush);
-- Flush the written data to the back stream,
-- all data placed to the compressor is flushing to the Back stream.
-- Should not be used untill necessary, becouse it is decreasing
-- compression.
function Read_Total_In (Stream : in Stream_Type) return Count;
pragma Inline (Read_Total_In);
-- Return total number of bytes read from back stream so far.
function Read_Total_Out (Stream : in Stream_Type) return Count;
pragma Inline (Read_Total_Out);
-- Return total number of bytes read so far.
function Write_Total_In (Stream : in Stream_Type) return Count;
pragma Inline (Write_Total_In);
-- Return total number of bytes written so far.
function Write_Total_Out (Stream : in Stream_Type) return Count;
pragma Inline (Write_Total_Out);
-- Return total number of bytes written to the back stream.
procedure Create
(Stream : out Stream_Type;
Mode : in Stream_Mode;
Back : in Stream_Access;
Back_Compressed : in Boolean;
Level : in Compression_Level := Default_Compression;
Strategy : in Strategy_Type := Default_Strategy;
Header : in Header_Type := Default;
Read_Buffer_Size : in Ada.Streams.Stream_Element_Offset
:= Default_Buffer_Size;
Write_Buffer_Size : in Ada.Streams.Stream_Element_Offset
:= Default_Buffer_Size);
-- Create the Comression/Decompression stream.
-- If mode is In_Stream then Write operation is disabled.
-- If mode is Out_Stream then Read operation is disabled.
-- If Back_Compressed is true then
-- Data written to the Stream is compressing to the Back stream
-- and data read from the Stream is decompressed data from the Back stream.
-- If Back_Compressed is false then
-- Data written to the Stream is decompressing to the Back stream
-- and data read from the Stream is compressed data from the Back stream.
-- !!! When the Need_Header is False ZLib-Ada is using undocumented
-- ZLib 1.1.4 functionality to do not create/wait for ZLib headers.
procedure Close (Stream : in out Stream_Type);
private
use Ada.Streams;
type Buffer_Access is access all Stream_Element_Array;
type Stream_Type
is new Root_Stream_Type with
record
Mode : Stream_Mode;
Buffer : Buffer_Access;
Rest_First : Stream_Element_Offset;
Rest_Last : Stream_Element_Offset;
-- Buffer for Read operation.
-- We need to have this buffer in the record
-- becouse not all read data from back stream
-- could be processed during the read operation.
Buffer_Size : Stream_Element_Offset;
-- Buffer size for write operation.
-- We do not need to have this buffer
-- in the record becouse all data could be
-- processed in the write operation.
Back : Stream_Access;
Reader : Filter_Type;
Writer : Filter_Type;
end record;
end ZLib.Streams;

View file

@ -0,0 +1,185 @@
----------------------------------------------------------------
-- ZLib for Ada thick binding. --
-- --
-- Copyright (C) 2002-2003 Dmitriy Anisimkov --
-- --
-- Open source license information is in the zlib.ads file. --
----------------------------------------------------------------
-- $Id: zlib-thin.adb,v 1.6 2003/01/21 15:26:37 vagul Exp $
package body ZLib.Thin is
ZLIB_VERSION : constant Chars_Ptr :=
Interfaces.C.Strings.New_String ("1.1.4");
Z_Stream_Size : constant Int := Z_Stream'Size / System.Storage_Unit;
--------------
-- Avail_In --
--------------
function Avail_In (Strm : in Z_Stream) return UInt is
begin
return Strm.Avail_In;
end Avail_In;
---------------
-- Avail_Out --
---------------
function Avail_Out (Strm : in Z_Stream) return UInt is
begin
return Strm.Avail_Out;
end Avail_Out;
------------------
-- Deflate_Init --
------------------
function Deflate_Init
(strm : in Z_Streamp;
level : in Int := Z_DEFAULT_COMPRESSION)
return Int is
begin
return deflateInit (strm, level, ZLIB_VERSION, Z_Stream_Size);
end Deflate_Init;
function Deflate_Init
(strm : Z_Streamp;
level : Int;
method : Int;
windowBits : Int;
memLevel : Int;
strategy : Int)
return Int is
begin
return deflateInit2
(strm,
level,
method,
windowBits,
memLevel,
strategy,
ZLIB_VERSION,
Z_Stream_Size);
end Deflate_Init;
------------------
-- Inflate_Init --
------------------
function Inflate_Init (strm : Z_Streamp) return Int is
begin
return inflateInit (strm, ZLIB_VERSION, Z_Stream_Size);
end Inflate_Init;
function Inflate_Init (strm : Z_Streamp; windowBits : Int) return Int is
begin
return inflateInit2 (strm, windowBits, ZLIB_VERSION, Z_Stream_Size);
end Inflate_Init;
function Last_Error_Message (Strm : in Z_Stream) return String is
use Interfaces.C.Strings;
begin
if Strm.msg = Null_Ptr then
return "";
else
return Value (Strm.msg);
end if;
end Last_Error_Message;
-------------
-- Need_In --
-------------
function Need_In (strm : Z_Stream) return Boolean is
begin
return strm.Avail_In = 0;
end Need_In;
--------------
-- Need_Out --
--------------
function Need_Out (strm : Z_Stream) return Boolean is
begin
return strm.Avail_Out = 0;
end Need_Out;
------------
-- Set_In --
------------
procedure Set_In
(Strm : in out Z_Stream;
Buffer : in Byte_Access;
Size : in UInt) is
begin
Strm.Next_In := Buffer;
Strm.Avail_In := Size;
end Set_In;
procedure Set_In
(Strm : in out Z_Stream;
Buffer : in Voidp;
Size : in UInt) is
begin
Set_In (Strm, Bytes.To_Pointer (Buffer), Size);
end Set_In;
------------------
-- Set_Mem_Func --
------------------
procedure Set_Mem_Func
(Strm : in out Z_Stream;
Opaque : in Voidp;
Alloc : in alloc_func;
Free : in free_func) is
begin
Strm.opaque := Opaque;
Strm.zalloc := Alloc;
Strm.zfree := Free;
end Set_Mem_Func;
-------------
-- Set_Out --
-------------
procedure Set_Out
(Strm : in out Z_Stream;
Buffer : in Byte_Access;
Size : in UInt) is
begin
Strm.Next_Out := Buffer;
Strm.Avail_Out := Size;
end Set_Out;
procedure Set_Out
(Strm : in out Z_Stream;
Buffer : in Voidp;
Size : in UInt) is
begin
Set_Out (Strm, Bytes.To_Pointer (Buffer), Size);
end Set_Out;
--------------
-- Total_In --
--------------
function Total_In (Strm : in Z_Stream) return ULong is
begin
return Strm.Total_In;
end Total_In;
---------------
-- Total_Out --
---------------
function Total_Out (Strm : in Z_Stream) return ULong is
begin
return Strm.Total_Out;
end Total_Out;
end ZLib.Thin;

View file

@ -0,0 +1,485 @@
----------------------------------------------------------------
-- ZLib for Ada thick binding. --
-- --
-- Copyright (C) 2002-2003 Dmitriy Anisimkov --
-- --
-- Open source license information is in the zlib.ads file. --
----------------------------------------------------------------
-- $Id: zlib-thin.ads,v 1.8 2003/08/12 13:16:51 vagul Exp $
with Interfaces.C.Strings;
with System.Address_To_Access_Conversions;
private package ZLib.Thin is
-- From zconf.h
MAX_MEM_LEVEL : constant := 9; -- zconf.h:105
-- zconf.h:105
MAX_WBITS : constant := 15; -- zconf.h:115
-- 32K LZ77 window
-- zconf.h:115
SEEK_SET : constant := 8#0000#; -- zconf.h:244
-- Seek from beginning of file.
-- zconf.h:244
SEEK_CUR : constant := 1; -- zconf.h:245
-- Seek from current position.
-- zconf.h:245
SEEK_END : constant := 2; -- zconf.h:246
-- Set file pointer to EOF plus "offset"
-- zconf.h:246
type Byte is new Interfaces.C.unsigned_char; -- 8 bits
-- zconf.h:214
type UInt is new Interfaces.C.unsigned; -- 16 bits or more
-- zconf.h:216
type Int is new Interfaces.C.int;
type ULong is new Interfaces.C.unsigned; -- 32 bits or more
-- zconf.h:217
subtype Chars_Ptr is Interfaces.C.Strings.chars_ptr;
type ULong_Access is access ULong;
type Int_Access is access Int;
subtype Voidp is System.Address; -- zconf.h:232
package Bytes is new System.Address_To_Access_Conversions (Byte);
subtype Byte_Access is Bytes.Object_Pointer;
-- end from zconf
Z_NO_FLUSH : constant := 8#0000#; -- zlib.h:125
-- zlib.h:125
Z_PARTIAL_FLUSH : constant := 1; -- zlib.h:126
-- will be removed, use
-- Z_SYNC_FLUSH instead
-- zlib.h:126
Z_SYNC_FLUSH : constant := 2; -- zlib.h:127
-- zlib.h:127
Z_FULL_FLUSH : constant := 3; -- zlib.h:128
-- zlib.h:128
Z_FINISH : constant := 4; -- zlib.h:129
-- zlib.h:129
Z_OK : constant := 8#0000#; -- zlib.h:132
-- zlib.h:132
Z_STREAM_END : constant := 1; -- zlib.h:133
-- zlib.h:133
Z_NEED_DICT : constant := 2; -- zlib.h:134
-- zlib.h:134
Z_ERRNO : constant := -1; -- zlib.h:135
-- zlib.h:135
Z_STREAM_ERROR : constant := -2; -- zlib.h:136
-- zlib.h:136
Z_DATA_ERROR : constant := -3; -- zlib.h:137
-- zlib.h:137
Z_MEM_ERROR : constant := -4; -- zlib.h:138
-- zlib.h:138
Z_BUF_ERROR : constant := -5; -- zlib.h:139
-- zlib.h:139
Z_VERSION_ERROR : constant := -6; -- zlib.h:140
-- zlib.h:140
Z_NO_COMPRESSION : constant := 8#0000#; -- zlib.h:145
-- zlib.h:145
Z_BEST_SPEED : constant := 1; -- zlib.h:146
-- zlib.h:146
Z_BEST_COMPRESSION : constant := 9; -- zlib.h:147
-- zlib.h:147
Z_DEFAULT_COMPRESSION : constant := -1; -- zlib.h:148
-- zlib.h:148
Z_FILTERED : constant := 1; -- zlib.h:151
-- zlib.h:151
Z_HUFFMAN_ONLY : constant := 2; -- zlib.h:152
-- zlib.h:152
Z_DEFAULT_STRATEGY : constant := 8#0000#; -- zlib.h:153
-- zlib.h:153
Z_BINARY : constant := 8#0000#; -- zlib.h:156
-- zlib.h:156
Z_ASCII : constant := 1; -- zlib.h:157
-- zlib.h:157
Z_UNKNOWN : constant := 2; -- zlib.h:158
-- zlib.h:158
Z_DEFLATED : constant := 8; -- zlib.h:161
-- zlib.h:161
Z_NULL : constant := 8#0000#; -- zlib.h:164
-- for initializing zalloc, zfree, opaque
-- zlib.h:164
type gzFile is new Voidp; -- zlib.h:646
type Z_Stream is private;
type Z_Streamp is access all Z_Stream; -- zlib.h:89
type alloc_func is access function
(Opaque : Voidp;
Items : UInt;
Size : UInt)
return Voidp; -- zlib.h:63
type free_func is access procedure (opaque : Voidp; address : Voidp);
function zlibVersion return Chars_Ptr;
function Deflate (strm : Z_Streamp; flush : Int) return Int;
function DeflateEnd (strm : Z_Streamp) return Int;
function Inflate (strm : Z_Streamp; flush : Int) return Int;
function InflateEnd (strm : Z_Streamp) return Int;
function deflateSetDictionary
(strm : Z_Streamp;
dictionary : Byte_Access;
dictLength : UInt)
return Int;
function deflateCopy (dest : Z_Streamp; source : Z_Streamp) return Int;
-- zlib.h:478
function deflateReset (strm : Z_Streamp) return Int; -- zlib.h:495
function deflateParams
(strm : Z_Streamp;
level : Int;
strategy : Int)
return Int; -- zlib.h:506
function inflateSetDictionary
(strm : Z_Streamp;
dictionary : Byte_Access;
dictLength : UInt)
return Int; -- zlib.h:548
function inflateSync (strm : Z_Streamp) return Int; -- zlib.h:565
function inflateReset (strm : Z_Streamp) return Int; -- zlib.h:580
function compress
(dest : Byte_Access;
destLen : ULong_Access;
source : Byte_Access;
sourceLen : ULong)
return Int; -- zlib.h:601
function compress2
(dest : Byte_Access;
destLen : ULong_Access;
source : Byte_Access;
sourceLen : ULong;
level : Int)
return Int; -- zlib.h:615
function uncompress
(dest : Byte_Access;
destLen : ULong_Access;
source : Byte_Access;
sourceLen : ULong)
return Int;
function gzopen (path : Chars_Ptr; mode : Chars_Ptr) return gzFile;
function gzdopen (fd : Int; mode : Chars_Ptr) return gzFile;
function gzsetparams
(file : gzFile;
level : Int;
strategy : Int)
return Int;
function gzread
(file : gzFile;
buf : Voidp;
len : UInt)
return Int;
function gzwrite
(file : in gzFile;
buf : in Voidp;
len : in UInt)
return Int;
function gzprintf (file : in gzFile; format : in Chars_Ptr) return Int;
function gzputs (file : in gzFile; s : in Chars_Ptr) return Int;
function gzgets
(file : gzFile;
buf : Chars_Ptr;
len : Int)
return Chars_Ptr;
function gzputc (file : gzFile; char : Int) return Int;
function gzgetc (file : gzFile) return Int;
function gzflush (file : gzFile; flush : Int) return Int;
function gzseek
(file : gzFile;
offset : Int;
whence : Int)
return Int;
function gzrewind (file : gzFile) return Int;
function gztell (file : gzFile) return Int;
function gzeof (file : gzFile) return Int;
function gzclose (file : gzFile) return Int;
function gzerror (file : gzFile; errnum : Int_Access) return Chars_Ptr;
function adler32
(adler : ULong;
buf : Byte_Access;
len : UInt)
return ULong;
function crc32
(crc : ULong;
buf : Byte_Access;
len : UInt)
return ULong;
function deflateInit
(strm : Z_Streamp;
level : Int;
version : Chars_Ptr;
stream_size : Int)
return Int;
function Deflate_Init
(strm : in Z_Streamp;
level : in Int := Z_DEFAULT_COMPRESSION)
return Int;
pragma Inline (Deflate_Init);
function deflateInit2
(strm : Z_Streamp;
level : Int;
method : Int;
windowBits : Int;
memLevel : Int;
strategy : Int;
version : Chars_Ptr;
stream_size : Int)
return Int;
function Deflate_Init
(strm : Z_Streamp;
level : Int;
method : Int;
windowBits : Int;
memLevel : Int;
strategy : Int)
return Int;
pragma Inline (Deflate_Init);
function inflateInit
(strm : Z_Streamp;
version : Chars_Ptr;
stream_size : Int)
return Int;
function Inflate_Init (strm : Z_Streamp) return Int;
pragma Inline (Inflate_Init);
function inflateInit2
(strm : in Z_Streamp;
windowBits : in Int;
version : in Chars_Ptr;
stream_size : in Int)
return Int;
function inflateBackInit
(strm : in Z_Streamp;
windowBits : in Int;
window : in Byte_Access;
version : in Chars_Ptr;
stream_size : in Int)
return Int;
-- Size of window have to be 2**windowBits.
function Inflate_Init (strm : Z_Streamp; windowBits : Int) return Int;
pragma Inline (Inflate_Init);
function zError (err : Int) return Chars_Ptr;
function inflateSyncPoint (z : Z_Streamp) return Int;
function get_crc_table return ULong_Access;
-- Interface to the available fields of the z_stream structure.
-- 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.
function Need_In (strm : in Z_Stream) return Boolean;
-- return true when we do not need to setup Next_In and Avail_In fields.
pragma Inline (Need_In);
function Need_Out (strm : in Z_Stream) return Boolean;
-- return true when we do not need to setup Next_Out and Avail_Out field.
pragma Inline (Need_Out);
procedure Set_In
(Strm : in out Z_Stream;
Buffer : in Byte_Access;
Size : in UInt);
pragma Inline (Set_In);
procedure Set_In
(Strm : in out Z_Stream;
Buffer : in Voidp;
Size : in UInt);
pragma Inline (Set_In);
procedure Set_Out
(Strm : in out Z_Stream;
Buffer : in Byte_Access;
Size : in UInt);
pragma Inline (Set_Out);
procedure Set_Out
(Strm : in out Z_Stream;
Buffer : in Voidp;
Size : in UInt);
pragma Inline (Set_Out);
procedure Set_Mem_Func
(Strm : in out Z_Stream;
Opaque : in Voidp;
Alloc : in alloc_func;
Free : in free_func);
pragma Inline (Set_Mem_Func);
function Last_Error_Message (Strm : in Z_Stream) return String;
pragma Inline (Last_Error_Message);
function Avail_Out (Strm : in Z_Stream) return UInt;
pragma Inline (Avail_Out);
function Avail_In (Strm : in Z_Stream) return UInt;
pragma Inline (Avail_In);
function Total_In (Strm : in Z_Stream) return ULong;
pragma Inline (Total_In);
function Total_Out (Strm : in Z_Stream) return ULong;
pragma Inline (Total_Out);
function inflateCopy
(dest : in Z_Streamp;
Source : in Z_Streamp)
return Int;
function compressBound (Source_Len : in ULong) return ULong;
function deflateBound
(Strm : in Z_Streamp;
Source_Len : in ULong)
return ULong;
function gzungetc (C : in Int; File : in gzFile) return Int;
function zlibCompileFlags return ULong;
function deflatePrime
(strm : Z_Streamp;
bits : Int;
value : Int)
return Int;
private
type Z_Stream is record -- zlib.h:68
Next_In : Byte_Access; -- next input byte
Avail_In : UInt := 0; -- number of bytes available at next_in
Total_In : ULong := 0; -- total nb of input bytes read so far
Next_Out : Byte_Access; -- next output byte should be put there
Avail_Out : UInt := 0; -- remaining free space at next_out
Total_Out : ULong := 0; -- total nb of bytes output so far
msg : Chars_Ptr; -- last error message, NULL if no error
state : Voidp; -- not visible by applications
zalloc : alloc_func := null; -- used to allocate the internal state
zfree : free_func := null; -- used to free the internal state
opaque : Voidp; -- private data object passed to
-- zalloc and zfree
data_type : Int; -- best guess about the data type:
-- ascii or binary
adler : ULong; -- adler32 value of the uncompressed
-- data
reserved : ULong; -- reserved for future use
end record;
pragma Convention (C, Z_Stream);
pragma Import (C, zlibVersion, "zlibVersion");
pragma Import (C, Deflate, "deflate");
pragma Import (C, DeflateEnd, "deflateEnd");
pragma Import (C, Inflate, "inflate");
pragma Import (C, InflateEnd, "inflateEnd");
pragma Import (C, deflateSetDictionary, "deflateSetDictionary");
pragma Import (C, deflateCopy, "deflateCopy");
pragma Import (C, deflateReset, "deflateReset");
pragma Import (C, deflateParams, "deflateParams");
pragma Import (C, inflateSetDictionary, "inflateSetDictionary");
pragma Import (C, inflateSync, "inflateSync");
pragma Import (C, inflateReset, "inflateReset");
pragma Import (C, compress, "compress");
pragma Import (C, compress2, "compress2");
pragma Import (C, uncompress, "uncompress");
pragma Import (C, gzopen, "gzopen");
pragma Import (C, gzdopen, "gzdopen");
pragma Import (C, gzsetparams, "gzsetparams");
pragma Import (C, gzread, "gzread");
pragma Import (C, gzwrite, "gzwrite");
pragma Import (C, gzprintf, "gzprintf");
pragma Import (C, gzputs, "gzputs");
pragma Import (C, gzgets, "gzgets");
pragma Import (C, gzputc, "gzputc");
pragma Import (C, gzgetc, "gzgetc");
pragma Import (C, gzflush, "gzflush");
pragma Import (C, gzseek, "gzseek");
pragma Import (C, gzrewind, "gzrewind");
pragma Import (C, gztell, "gztell");
pragma Import (C, gzeof, "gzeof");
pragma Import (C, gzclose, "gzclose");
pragma Import (C, gzerror, "gzerror");
pragma Import (C, adler32, "adler32");
pragma Import (C, crc32, "crc32");
pragma Import (C, deflateInit, "deflateInit_");
pragma Import (C, inflateInit, "inflateInit_");
pragma Import (C, deflateInit2, "deflateInit2_");
pragma Import (C, inflateInit2, "inflateInit2_");
pragma Import (C, zError, "zError");
pragma Import (C, inflateSyncPoint, "inflateSyncPoint");
pragma Import (C, get_crc_table, "get_crc_table");
-- added in zlib 1.2.1:
pragma Import (C, inflateCopy, "inflateCopy");
pragma Import (C, compressBound, "compressBound");
pragma Import (C, deflateBound, "deflateBound");
pragma Import (C, gzungetc, "gzungetc");
pragma Import (C, zlibCompileFlags, "zlibCompileFlags");
pragma Import (C, deflatePrime, "deflatePrime");
pragma Import (C, inflateBackInit, "inflateBackInit_");
-- I stopped binding the inflateBack routines, becouse realize that
-- it does not support zlib and gzip headers for now, and have no
-- symmetric deflateBack routines.
-- ZLib-Ada is symmetric regarding deflate/inflate data transformation
-- and has a similar generic callback interface for the
-- deflate/inflate transformation based on the regular Deflate/Inflate
-- routines.
-- pragma Import (C, inflateBack, "inflateBack");
-- pragma Import (C, inflateBackEnd, "inflateBackEnd");
end ZLib.Thin;

674
zlib/contrib/ada/zlib.adb Normal file
View file

@ -0,0 +1,674 @@
----------------------------------------------------------------
-- ZLib for Ada thick binding. --
-- --
-- Copyright (C) 2002-2003 Dmitriy Anisimkov --
-- --
-- Open source license information is in the zlib.ads file. --
----------------------------------------------------------------
-- $Id: zlib.adb,v 1.19 2003/07/13 16:02:19 vagul Exp $
with Ada.Exceptions;
with Ada.Unchecked_Conversion;
with Ada.Unchecked_Deallocation;
with Interfaces.C.Strings;
with ZLib.Thin;
package body ZLib is
use type Thin.Int;
type Z_Stream is new Thin.Z_Stream;
type Return_Code_Enum is
(OK,
STREAM_END,
NEED_DICT,
ERRNO,
STREAM_ERROR,
DATA_ERROR,
MEM_ERROR,
BUF_ERROR,
VERSION_ERROR);
type Flate_Step_Function is access
function (Strm : Thin.Z_Streamp; flush : Thin.Int) return Thin.Int;
pragma Convention (C, Flate_Step_Function);
type Flate_End_Function is access
function (Ctrm : in Thin.Z_Streamp) return Thin.Int;
pragma Convention (C, Flate_End_Function);
type Flate_Type is record
Step : Flate_Step_Function;
Done : Flate_End_Function;
end record;
subtype Footer_Array is Stream_Element_Array (1 .. 8);
Simple_GZip_Header : constant Stream_Element_Array (1 .. 10)
:= (16#1f#, 16#8b#, -- Magic header
16#08#, -- Z_DEFLATED
16#00#, -- Flags
16#00#, 16#00#, 16#00#, 16#00#, -- Time
16#00#, -- XFlags
16#03# -- OS code
);
-- The simplest gzip header is not for informational, but just for
-- gzip format compatibility.
-- Note that some code below is using assumption
-- Simple_GZip_Header'Last > Footer_Array'Last, so do not make
-- Simple_GZip_Header'Last <= Footer_Array'Last.
Return_Code : constant array (Thin.Int range <>) of Return_Code_Enum
:= (0 => OK,
1 => STREAM_END,
2 => NEED_DICT,
-1 => ERRNO,
-2 => STREAM_ERROR,
-3 => DATA_ERROR,
-4 => MEM_ERROR,
-5 => BUF_ERROR,
-6 => VERSION_ERROR);
Flate : constant array (Boolean) of Flate_Type
:= (True => (Step => Thin.Deflate'Access,
Done => Thin.DeflateEnd'Access),
False => (Step => Thin.Inflate'Access,
Done => Thin.InflateEnd'Access));
Flush_Finish : constant array (Boolean) of Flush_Mode
:= (True => Finish, False => No_Flush);
procedure Raise_Error (Stream : Z_Stream);
pragma Inline (Raise_Error);
procedure Raise_Error (Message : String);
pragma Inline (Raise_Error);
procedure Check_Error (Stream : Z_Stream; Code : Thin.Int);
procedure Free is new Ada.Unchecked_Deallocation
(Z_Stream, Z_Stream_Access);
function To_Thin_Access is new Ada.Unchecked_Conversion
(Z_Stream_Access, Thin.Z_Streamp);
procedure Translate_GZip
(Filter : in out Filter_Type;
In_Data : in Ada.Streams.Stream_Element_Array;
In_Last : out Ada.Streams.Stream_Element_Offset;
Out_Data : out Ada.Streams.Stream_Element_Array;
Out_Last : out Ada.Streams.Stream_Element_Offset;
Flush : in Flush_Mode);
-- Separate translate routine for make gzip header.
procedure Translate_Auto
(Filter : in out Filter_Type;
In_Data : in Ada.Streams.Stream_Element_Array;
In_Last : out Ada.Streams.Stream_Element_Offset;
Out_Data : out Ada.Streams.Stream_Element_Array;
Out_Last : out Ada.Streams.Stream_Element_Offset;
Flush : in Flush_Mode);
-- translate routine without additional headers.
-----------------
-- Check_Error --
-----------------
procedure Check_Error (Stream : Z_Stream; Code : Thin.Int) is
use type Thin.Int;
begin
if Code /= Thin.Z_OK then
Raise_Error
(Return_Code_Enum'Image (Return_Code (Code))
& ": " & Last_Error_Message (Stream));
end if;
end Check_Error;
-----------
-- Close --
-----------
procedure Close
(Filter : in out Filter_Type;
Ignore_Error : in Boolean := False)
is
Code : Thin.Int;
begin
Code := Flate (Filter.Compression).Done
(To_Thin_Access (Filter.Strm));
Filter.Opened := False;
if Ignore_Error or else Code = Thin.Z_OK then
Free (Filter.Strm);
else
declare
Error_Message : constant String
:= Last_Error_Message (Filter.Strm.all);
begin
Free (Filter.Strm);
Ada.Exceptions.Raise_Exception
(ZLib_Error'Identity,
Return_Code_Enum'Image (Return_Code (Code))
& ": " & Error_Message);
end;
end if;
end Close;
-----------
-- CRC32 --
-----------
function CRC32
(CRC : in Unsigned_32;
Data : in Ada.Streams.Stream_Element_Array)
return Unsigned_32
is
use Thin;
begin
return Unsigned_32 (crc32
(ULong (CRC),
Bytes.To_Pointer (Data'Address),
Data'Length));
end CRC32;
procedure CRC32
(CRC : in out Unsigned_32;
Data : in Ada.Streams.Stream_Element_Array) is
begin
CRC := CRC32 (CRC, Data);
end CRC32;
------------------
-- Deflate_Init --
------------------
procedure Deflate_Init
(Filter : in out Filter_Type;
Level : in Compression_Level := Default_Compression;
Strategy : in Strategy_Type := Default_Strategy;
Method : in Compression_Method := Deflated;
Window_Bits : in Window_Bits_Type := 15;
Memory_Level : in Memory_Level_Type := 8;
Header : in Header_Type := Default)
is
use type Thin.Int;
Win_Bits : Thin.Int := Thin.Int (Window_Bits);
begin
-- We allow ZLib to make header only in case of default header type.
-- Otherwise we would either do header by ourselfs, or do not do
-- header at all.
if Header = None or else Header = GZip then
Win_Bits := -Win_Bits;
end if;
-- For the GZip CRC calculation and make headers.
if Header = GZip then
Filter.CRC := 0;
Filter.Offset := Simple_GZip_Header'First;
else
Filter.Offset := Simple_GZip_Header'Last + 1;
end if;
Filter.Strm := new Z_Stream;
Filter.Compression := True;
Filter.Stream_End := False;
Filter.Opened := True;
Filter.Header := Header;
if Thin.Deflate_Init
(To_Thin_Access (Filter.Strm),
Level => Thin.Int (Level),
method => Thin.Int (Method),
windowBits => Win_Bits,
memLevel => Thin.Int (Memory_Level),
strategy => Thin.Int (Strategy)) /= Thin.Z_OK
then
Raise_Error (Filter.Strm.all);
end if;
end Deflate_Init;
-----------
-- Flush --
-----------
procedure Flush
(Filter : in out Filter_Type;
Out_Data : out Ada.Streams.Stream_Element_Array;
Out_Last : out Ada.Streams.Stream_Element_Offset;
Flush : in Flush_Mode)
is
No_Data : Stream_Element_Array := (1 .. 0 => 0);
Last : Stream_Element_Offset;
begin
Translate (Filter, No_Data, Last, Out_Data, Out_Last, Flush);
end Flush;
-----------------------
-- Generic_Translate --
-----------------------
procedure Generic_Translate
(Filter : in out ZLib.Filter_Type;
In_Buffer_Size : Integer := Default_Buffer_Size;
Out_Buffer_Size : Integer := Default_Buffer_Size)
is
In_Buffer : Stream_Element_Array
(1 .. Stream_Element_Offset (In_Buffer_Size));
Out_Buffer : Stream_Element_Array
(1 .. Stream_Element_Offset (Out_Buffer_Size));
Last : Stream_Element_Offset;
In_Last : Stream_Element_Offset;
In_First : Stream_Element_Offset;
Out_Last : Stream_Element_Offset;
begin
Main : loop
Data_In (In_Buffer, Last);
In_First := In_Buffer'First;
loop
Translate
(Filter,
In_Buffer (In_First .. Last),
In_Last,
Out_Buffer,
Out_Last,
Flush_Finish (Last < In_Buffer'First));
Data_Out (Out_Buffer (Out_Buffer'First .. Out_Last));
exit Main when Stream_End (Filter);
-- The end of in buffer.
exit when In_Last = Last;
In_First := In_Last + 1;
end loop;
end loop Main;
end Generic_Translate;
------------------
-- Inflate_Init --
------------------
procedure Inflate_Init
(Filter : in out Filter_Type;
Window_Bits : in Window_Bits_Type := 15;
Header : in Header_Type := Default)
is
use type Thin.Int;
Win_Bits : Thin.Int := Thin.Int (Window_Bits);
procedure Check_Version;
-- Check the latest header types compatibility.
procedure Check_Version is
begin
if Version <= "1.1.4" then
Raise_Error
("Inflate header type " & Header_Type'Image (Header)
& " incompatible with ZLib version " & Version);
end if;
end Check_Version;
begin
case Header is
when None =>
Check_Version;
-- Inflate data without headers determined
-- by negative Win_Bits.
Win_Bits := -Win_Bits;
when GZip =>
Check_Version;
-- Inflate gzip data defined by flag 16.
Win_Bits := Win_Bits + 16;
when Auto =>
Check_Version;
-- Inflate with automatic detection
-- of gzip or native header defined by flag 32.
Win_Bits := Win_Bits + 32;
when Default => null;
end case;
Filter.Strm := new Z_Stream;
Filter.Compression := False;
Filter.Stream_End := False;
Filter.Opened := True;
Filter.Header := Header;
if Thin.Inflate_Init
(To_Thin_Access (Filter.Strm), Win_Bits) /= Thin.Z_OK
then
Raise_Error (Filter.Strm.all);
end if;
end Inflate_Init;
-----------------
-- Raise_Error --
-----------------
procedure Raise_Error (Message : String) is
begin
Ada.Exceptions.Raise_Exception (ZLib_Error'Identity, Message);
end Raise_Error;
procedure Raise_Error (Stream : Z_Stream) is
begin
Raise_Error (Last_Error_Message (Stream));
end Raise_Error;
----------
-- Read --
----------
procedure Read
(Filter : in out Filter_Type;
Item : out Ada.Streams.Stream_Element_Array;
Last : out Ada.Streams.Stream_Element_Offset)
is
In_Last : Stream_Element_Offset;
Item_First : Ada.Streams.Stream_Element_Offset := Item'First;
begin
pragma Assert (Rest_First in Buffer'First .. Buffer'Last + 1);
loop
if Rest_First > Buffer'Last then
Read (Buffer, Rest_Last);
Rest_First := Buffer'First;
end if;
pragma Assert (Rest_Last in Buffer'First - 1 .. Buffer'Last);
Translate
(Filter => Filter,
In_Data => Buffer (Rest_First .. Rest_Last),
In_Last => In_Last,
Out_Data => Item (Item_First .. Item'Last),
Out_Last => Last,
Flush => Flush_Finish (Rest_Last < Rest_First));
Rest_First := In_Last + 1;
exit when Last = Item'Last or else Stream_End (Filter);
Item_First := Last + 1;
end loop;
end Read;
----------------
-- Stream_End --
----------------
function Stream_End (Filter : in Filter_Type) return Boolean is
begin
if Filter.Header = GZip and Filter.Compression then
return Filter.Stream_End
and then Filter.Offset = Footer_Array'Last + 1;
else
return Filter.Stream_End;
end if;
end Stream_End;
--------------
-- Total_In --
--------------
function Total_In (Filter : in Filter_Type) return Count is
begin
return Count (Thin.Total_In (To_Thin_Access (Filter.Strm).all));
end Total_In;
---------------
-- Total_Out --
---------------
function Total_Out (Filter : in Filter_Type) return Count is
begin
return Count (Thin.Total_Out (To_Thin_Access (Filter.Strm).all));
end Total_Out;
---------------
-- Translate --
---------------
procedure Translate
(Filter : in out Filter_Type;
In_Data : in Ada.Streams.Stream_Element_Array;
In_Last : out Ada.Streams.Stream_Element_Offset;
Out_Data : out Ada.Streams.Stream_Element_Array;
Out_Last : out Ada.Streams.Stream_Element_Offset;
Flush : in Flush_Mode) is
begin
if Filter.Header = GZip and then Filter.Compression then
Translate_GZip
(Filter => Filter,
In_Data => In_Data,
In_Last => In_Last,
Out_Data => Out_Data,
Out_Last => Out_Last,
Flush => Flush);
else
Translate_Auto
(Filter => Filter,
In_Data => In_Data,
In_Last => In_Last,
Out_Data => Out_Data,
Out_Last => Out_Last,
Flush => Flush);
end if;
end Translate;
--------------------
-- Translate_Auto --
--------------------
procedure Translate_Auto
(Filter : in out Filter_Type;
In_Data : in Ada.Streams.Stream_Element_Array;
In_Last : out Ada.Streams.Stream_Element_Offset;
Out_Data : out Ada.Streams.Stream_Element_Array;
Out_Last : out Ada.Streams.Stream_Element_Offset;
Flush : in Flush_Mode)
is
use type Thin.Int;
Code : Thin.Int;
begin
if Filter.Opened = False then
raise ZLib_Error;
end if;
if Out_Data'Length = 0 then
raise Constraint_Error;
end if;
Set_Out (Filter.Strm.all, Out_Data'Address, Out_Data'Length);
Set_In (Filter.Strm.all, In_Data'Address, In_Data'Length);
Code := Flate (Filter.Compression).Step
(To_Thin_Access (Filter.Strm),
Thin.Int (Flush));
if Code = Thin.Z_STREAM_END then
Filter.Stream_End := True;
else
Check_Error (Filter.Strm.all, Code);
end if;
In_Last := In_Data'Last
- Stream_Element_Offset (Avail_In (Filter.Strm.all));
Out_Last := Out_Data'Last
- Stream_Element_Offset (Avail_Out (Filter.Strm.all));
end Translate_Auto;
--------------------
-- Translate_GZip --
--------------------
procedure Translate_GZip
(Filter : in out Filter_Type;
In_Data : in Ada.Streams.Stream_Element_Array;
In_Last : out Ada.Streams.Stream_Element_Offset;
Out_Data : out Ada.Streams.Stream_Element_Array;
Out_Last : out Ada.Streams.Stream_Element_Offset;
Flush : in Flush_Mode)
is
Out_First : Stream_Element_Offset;
procedure Add_Data (Data : in Stream_Element_Array);
-- Add data to stream from the Filter.Offset till necessary,
-- used for add gzip headr/footer.
procedure Put_32
(Item : in out Stream_Element_Array;
Data : in Unsigned_32);
pragma Inline (Put_32);
--------------
-- Add_Data --
--------------
procedure Add_Data (Data : in Stream_Element_Array) is
Data_First : Stream_Element_Offset renames Filter.Offset;
Data_Last : Stream_Element_Offset;
Data_Len : Stream_Element_Offset; -- -1
Out_Len : Stream_Element_Offset; -- -1
begin
Out_First := Out_Last + 1;
if Data_First > Data'Last then
return;
end if;
Data_Len := Data'Last - Data_First;
Out_Len := Out_Data'Last - Out_First;
if Data_Len <= Out_Len then
Out_Last := Out_First + Data_Len;
Data_Last := Data'Last;
else
Out_Last := Out_Data'Last;
Data_Last := Data_First + Out_Len;
end if;
Out_Data (Out_First .. Out_Last) := Data (Data_First .. Data_Last);
Data_First := Data_Last + 1;
Out_First := Out_Last + 1;
end Add_Data;
------------
-- Put_32 --
------------
procedure Put_32
(Item : in out Stream_Element_Array;
Data : in Unsigned_32)
is
D : Unsigned_32 := Data;
begin
for J in Item'First .. Item'First + 3 loop
Item (J) := Stream_Element (D and 16#FF#);
D := Shift_Right (D, 8);
end loop;
end Put_32;
begin
Out_Last := Out_Data'First - 1;
if not Filter.Stream_End then
Add_Data (Simple_GZip_Header);
Translate_Auto
(Filter => Filter,
In_Data => In_Data,
In_Last => In_Last,
Out_Data => Out_Data (Out_First .. Out_Data'Last),
Out_Last => Out_Last,
Flush => Flush);
CRC32 (Filter.CRC, In_Data (In_Data'First .. In_Last));
end if;
if Filter.Stream_End and then Out_Last <= Out_Data'Last then
-- This detection method would work only when
-- Simple_GZip_Header'Last > Footer_Array'Last
if Filter.Offset = Simple_GZip_Header'Last + 1 then
Filter.Offset := Footer_Array'First;
end if;
declare
Footer : Footer_Array;
begin
Put_32 (Footer, Filter.CRC);
Put_32 (Footer (Footer'First + 4 .. Footer'Last),
Unsigned_32 (Total_In (Filter)));
Add_Data (Footer);
end;
end if;
end Translate_GZip;
-------------
-- Version --
-------------
function Version return String is
begin
return Interfaces.C.Strings.Value (Thin.zlibVersion);
end Version;
-----------
-- Write --
-----------
procedure Write
(Filter : in out Filter_Type;
Item : in Ada.Streams.Stream_Element_Array;
Flush : in Flush_Mode)
is
Buffer : Stream_Element_Array (1 .. Buffer_Size);
In_Last, Out_Last : Stream_Element_Offset;
In_First : Stream_Element_Offset := Item'First;
begin
if Item'Length = 0 and Flush = No_Flush then
return;
end if;
loop
Translate
(Filter => Filter,
In_Data => Item (In_First .. Item'Last),
In_Last => In_Last,
Out_Data => Buffer,
Out_Last => Out_Last,
Flush => Flush);
if Out_Last >= Buffer'First then
Write (Buffer (1 .. Out_Last));
end if;
exit when In_Last = Item'Last or Stream_End (Filter);
In_First := In_Last + 1;
end loop;
end Write;
end ZLib;

311
zlib/contrib/ada/zlib.ads Normal file
View file

@ -0,0 +1,311 @@
------------------------------------------------------------------------------
-- ZLib for Ada thick binding. --
-- --
-- Copyright (C) 2002-2003 Dmitriy Anisimkov --
-- --
-- This library 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 library 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 library; if not, write to the Free Software Foundation, --
-- Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. --
-- --
-- As a special exception, if other files instantiate generics from this --
-- unit, or you link this unit with other files to produce an executable, --
-- this unit does not by itself cause the resulting executable to be --
-- covered by the GNU General Public License. This exception does not --
-- however invalidate any other reasons why the executable file might be --
-- covered by the GNU Public License. --
------------------------------------------------------------------------------
-- $Id: zlib.ads,v 1.17 2003/08/12 13:19:07 vagul Exp $
with Ada.Streams;
with Interfaces;
package ZLib is
ZLib_Error : exception;
type Compression_Level is new Integer range -1 .. 9;
type Flush_Mode is private;
type Compression_Method is private;
type Window_Bits_Type is new Integer range 8 .. 15;
type Memory_Level_Type is new Integer range 1 .. 9;
type Unsigned_32 is new Interfaces.Unsigned_32;
type Strategy_Type is private;
type Header_Type is (None, Auto, Default, GZip);
-- Header type usage have a some limitation for inflate.
-- See comment for Inflate_Init.
subtype Count is Ada.Streams.Stream_Element_Count;
----------------------------------
-- Compression method constants --
----------------------------------
Deflated : constant Compression_Method;
-- Only one method allowed in this ZLib version.
---------------------------------
-- Compression level constants --
---------------------------------
No_Compression : constant Compression_Level := 0;
Best_Speed : constant Compression_Level := 1;
Best_Compression : constant Compression_Level := 9;
Default_Compression : constant Compression_Level := -1;
--------------------------
-- Flush mode constants --
--------------------------
No_Flush : constant Flush_Mode;
-- Regular way for compression, no flush
Partial_Flush : constant Flush_Mode;
-- will be removed, use Z_SYNC_FLUSH instead
Sync_Flush : constant Flush_Mode;
-- all pending output is flushed to the output buffer and the output
-- is aligned on a byte boundary, so that the decompressor can get all
-- input data available so far. (In particular avail_in is zero after the
-- call if enough output space has been provided before the call.)
-- Flushing may degrade compression for some compression algorithms and so
-- it should be used only when necessary.
Full_Flush : constant Flush_Mode;
-- all output is flushed as with SYNC_FLUSH, and the compression state
-- is reset so that decompression can restart from this point if previous
-- compressed data has been damaged or if random access is desired. Using
-- FULL_FLUSH too often can seriously degrade the compression.
Finish : constant Flush_Mode;
-- Just for tell the compressor that input data is complete.
------------------------------------
-- Compression strategy constants --
------------------------------------
-- RLE stategy could be used only in version 1.2.0 and later.
Filtered : constant Strategy_Type;
Huffman_Only : constant Strategy_Type;
RLE : constant Strategy_Type;
Default_Strategy : constant Strategy_Type;
Default_Buffer_Size : constant := 4096;
type Filter_Type is limited private;
-- The filter is for compression and for decompression.
-- The usage of the type is depend of its initialization.
function Version return String;
pragma Inline (Version);
-- Return string representation of the ZLib version.
procedure Deflate_Init
(Filter : in out Filter_Type;
Level : in Compression_Level := Default_Compression;
Strategy : in Strategy_Type := Default_Strategy;
Method : in Compression_Method := Deflated;
Window_Bits : in Window_Bits_Type := 15;
Memory_Level : in Memory_Level_Type := 8;
Header : in Header_Type := Default);
-- Compressor initialization.
-- When Header parameter is Auto or Default, then default zlib header
-- would be provided for compressed data.
-- When Header is GZip, then gzip header would be set instead of
-- default header.
-- When Header is None, no header would be set for compressed data.
procedure Inflate_Init
(Filter : in out Filter_Type;
Window_Bits : in Window_Bits_Type := 15;
Header : in Header_Type := Default);
-- Decompressor initialization.
-- Default header type mean that ZLib default header is expecting in the
-- input compressed stream.
-- Header type None mean that no header is expecting in the input stream.
-- GZip header type mean that GZip header is expecting in the
-- input compressed stream.
-- Auto header type mean that header type (GZip or Native) would be
-- detected automatically in the input stream.
-- Note that header types parameter values None, GZip and Auto is
-- supporting for inflate routine only in ZLib versions 1.2.0.2 and later.
-- Deflate_Init is supporting all header types.
procedure Close
(Filter : in out Filter_Type;
Ignore_Error : in Boolean := False);
-- Closing the compression or decompressor.
-- If stream is closing before the complete and Ignore_Error is False,
-- The exception would be raised.
generic
with procedure Data_In
(Item : out Ada.Streams.Stream_Element_Array;
Last : out Ada.Streams.Stream_Element_Offset);
with procedure Data_Out
(Item : in Ada.Streams.Stream_Element_Array);
procedure Generic_Translate
(Filter : in out Filter_Type;
In_Buffer_Size : in Integer := Default_Buffer_Size;
Out_Buffer_Size : in Integer := Default_Buffer_Size);
-- Compressing/decompressing data arrived from Data_In routine
-- to the Data_Out routine. User should provide Data_In and Data_Out
-- for compression/decompression data flow.
-- Compression or decompression depend on initialization of Filter.
function Total_In (Filter : in Filter_Type) return Count;
pragma Inline (Total_In);
-- Return total number of input bytes read so far.
function Total_Out (Filter : in Filter_Type) return Count;
pragma Inline (Total_Out);
-- Return total number of bytes output so far.
function CRC32
(CRC : in Unsigned_32;
Data : in Ada.Streams.Stream_Element_Array)
return Unsigned_32;
pragma Inline (CRC32);
-- Calculate CRC32, it could be necessary for make gzip format.
procedure CRC32
(CRC : in out Unsigned_32;
Data : in Ada.Streams.Stream_Element_Array);
pragma Inline (CRC32);
-- Calculate CRC32, it could be necessary for make gzip format.
-------------------------------------------------
-- Below is more complex low level routines. --
-------------------------------------------------
procedure Translate
(Filter : in out Filter_Type;
In_Data : in Ada.Streams.Stream_Element_Array;
In_Last : out Ada.Streams.Stream_Element_Offset;
Out_Data : out Ada.Streams.Stream_Element_Array;
Out_Last : out Ada.Streams.Stream_Element_Offset;
Flush : in Flush_Mode);
-- Compressing/decompressing the datas from In_Data buffer to the
-- Out_Data buffer.
-- In_Data is incoming data portion,
-- In_Last is the index of last element from In_Data accepted by the
-- Filter.
-- Out_Data is the buffer for output data from the filter.
-- Out_Last is the last element of the received data from Filter.
-- To tell the filter that incoming data is complete put the
-- Flush parameter to FINISH.
function Stream_End (Filter : in Filter_Type) return Boolean;
pragma Inline (Stream_End);
-- Return the true when the stream is complete.
procedure Flush
(Filter : in out Filter_Type;
Out_Data : out Ada.Streams.Stream_Element_Array;
Out_Last : out Ada.Streams.Stream_Element_Offset;
Flush : in Flush_Mode);
pragma Inline (Flush);
-- Flushing the data from the compressor.
generic
with procedure Write
(Item : in Ada.Streams.Stream_Element_Array);
-- User should provide this routine for accept
-- compressed/decompressed data.
Buffer_Size : in Ada.Streams.Stream_Element_Offset
:= Default_Buffer_Size;
-- Buffer size for Write user routine.
procedure Write
(Filter : in out Filter_Type;
Item : in Ada.Streams.Stream_Element_Array;
Flush : in Flush_Mode);
-- Compressing/Decompressing data from Item to the
-- generic parameter procedure Write.
-- Output buffer size could be set in Buffer_Size generic parameter.
generic
with procedure Read
(Item : out Ada.Streams.Stream_Element_Array;
Last : out Ada.Streams.Stream_Element_Offset);
-- User should provide data for compression/decompression
-- thru this routine.
Buffer : in out Ada.Streams.Stream_Element_Array;
-- Buffer for keep remaining data from the previous
-- back read.
Rest_First, Rest_Last : in out Ada.Streams.Stream_Element_Offset;
-- Rest_First have to be initialized to Buffer'Last + 1
-- before usage.
procedure Read
(Filter : in out Filter_Type;
Item : out Ada.Streams.Stream_Element_Array;
Last : out Ada.Streams.Stream_Element_Offset);
-- Compressing/Decompressing data from generic parameter
-- procedure Read to the Item.
-- User should provide Buffer for the operation
-- and Rest_First variable first time initialized to the Buffer'Last + 1.
private
use Ada.Streams;
type Flush_Mode is new Integer range 0 .. 4;
type Compression_Method is new Integer range 8 .. 8;
type Strategy_Type is new Integer range 0 .. 3;
No_Flush : constant Flush_Mode := 0;
Sync_Flush : constant Flush_Mode := 2;
Full_Flush : constant Flush_Mode := 3;
Finish : constant Flush_Mode := 4;
Partial_Flush : constant Flush_Mode := 1;
-- will be removed, use Z_SYNC_FLUSH instead
Filtered : constant Strategy_Type := 1;
Huffman_Only : constant Strategy_Type := 2;
RLE : constant Strategy_Type := 3;
Default_Strategy : constant Strategy_Type := 0;
Deflated : constant Compression_Method := 8;
type Z_Stream;
type Z_Stream_Access is access all Z_Stream;
type Filter_Type is record
Strm : Z_Stream_Access;
Compression : Boolean;
Stream_End : Boolean;
Header : Header_Type;
CRC : Unsigned_32;
Offset : Stream_Element_Offset;
-- Offset for gzip header/footer output.
Opened : Boolean := False;
end record;
end ZLib;

21
zlib/contrib/ada/zlib.gpr Normal file
View file

@ -0,0 +1,21 @@
project Zlib is
for Languages use ("Ada");
for Source_Dirs use (".");
for Object_Dir use ".";
for Main use ("test.adb", "mtest.adb", "read.adb");
package Compiler is
for Default_Switches ("ada") use ("-gnatwbcfilopru", "-gnatVcdfimorst", "-gnatyabcefhiklmnoprst");
end Compiler;
package Linker is
for Default_Switches ("ada") use ("-lz");
end Linker;
package Builder is
for Default_Switches ("ada") use ("-s", "-gnatQ");
end Builder;
end Zlib;

View file

@ -0,0 +1,43 @@
This is a patched version of zlib modified to use
Pentium-optimized assembly code in the deflation algorithm. The files
changed/added by this patch are:
README.586
match.S
The effectiveness of these modifications is a bit marginal, as the the
program's bottleneck seems to be mostly L1-cache contention, for which
there is no real way to work around without rewriting the basic
algorithm. The speedup on average is around 5-10% (which is generally
less than the amount of variance between subsequent executions).
However, when used at level 9 compression, the cache contention can
drop enough for the assembly version to achieve 10-20% speedup (and
sometimes more, depending on the amount of overall redundancy in the
files). Even here, though, cache contention can still be the limiting
factor, depending on the nature of the program using the zlib library.
This may also mean that better improvements will be seen on a Pentium
with MMX, which suffers much less from L1-cache contention, but I have
not yet verified this.
Note that this code has been tailored for the Pentium in particular,
and will not perform well on the Pentium Pro (due to the use of a
partial register in the inner loop).
If you are using an assembler other than GNU as, you will have to
translate match.S to use your assembler's syntax. (Have fun.)
Brian Raiter
breadbox@muppetlabs.com
April, 1998
Added for zlib 1.1.3:
The patches come from
http://www.muppetlabs.com/~breadbox/software/assembly.html
To compile zlib with this asm file, copy match.S to the zlib directory
then do:
CFLAGS="-O3 -DASMV" ./configure
make OBJA=match.o

354
zlib/contrib/asm586/match.S Normal file
View file

@ -0,0 +1,354 @@
/* match.s -- Pentium-optimized version of longest_match()
* Written for zlib 1.1.2
* Copyright (C) 1998 Brian Raiter <breadbox@muppetlabs.com>
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License.
*/
#ifndef NO_UNDERLINE
#define match_init _match_init
#define longest_match _longest_match
#endif
#define MAX_MATCH (258)
#define MIN_MATCH (3)
#define MIN_LOOKAHEAD (MAX_MATCH + MIN_MATCH + 1)
#define MAX_MATCH_8 ((MAX_MATCH + 7) & ~7)
/* stack frame offsets */
#define wmask 0 /* local copy of s->wmask */
#define window 4 /* local copy of s->window */
#define windowbestlen 8 /* s->window + bestlen */
#define chainlenscanend 12 /* high word: current chain len */
/* low word: last bytes sought */
#define scanstart 16 /* first two bytes of string */
#define scanalign 20 /* dword-misalignment of string */
#define nicematch 24 /* a good enough match size */
#define bestlen 28 /* size of best match so far */
#define scan 32 /* ptr to string wanting match */
#define LocalVarsSize (36)
/* saved ebx 36 */
/* saved edi 40 */
/* saved esi 44 */
/* saved ebp 48 */
/* return address 52 */
#define deflatestate 56 /* the function arguments */
#define curmatch 60
/* Offsets for fields in the deflate_state structure. These numbers
* are calculated from the definition of deflate_state, with the
* assumption that the compiler will dword-align the fields. (Thus,
* changing the definition of deflate_state could easily cause this
* program to crash horribly, without so much as a warning at
* compile time. Sigh.)
*/
#define dsWSize 36
#define dsWMask 44
#define dsWindow 48
#define dsPrev 56
#define dsMatchLen 88
#define dsPrevMatch 92
#define dsStrStart 100
#define dsMatchStart 104
#define dsLookahead 108
#define dsPrevLen 112
#define dsMaxChainLen 116
#define dsGoodMatch 132
#define dsNiceMatch 136
.file "match.S"
.globl match_init, longest_match
.text
/* uInt longest_match(deflate_state *deflatestate, IPos curmatch) */
longest_match:
/* Save registers that the compiler may be using, and adjust %esp to */
/* make room for our stack frame. */
pushl %ebp
pushl %edi
pushl %esi
pushl %ebx
subl $LocalVarsSize, %esp
/* Retrieve the function arguments. %ecx will hold cur_match */
/* throughout the entire function. %edx will hold the pointer to the */
/* deflate_state structure during the function's setup (before */
/* entering the main loop). */
movl deflatestate(%esp), %edx
movl curmatch(%esp), %ecx
/* if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; */
movl dsNiceMatch(%edx), %eax
movl dsLookahead(%edx), %ebx
cmpl %eax, %ebx
jl LookaheadLess
movl %eax, %ebx
LookaheadLess: movl %ebx, nicematch(%esp)
/* register Bytef *scan = s->window + s->strstart; */
movl dsWindow(%edx), %esi
movl %esi, window(%esp)
movl dsStrStart(%edx), %ebp
lea (%esi,%ebp), %edi
movl %edi, scan(%esp)
/* Determine how many bytes the scan ptr is off from being */
/* dword-aligned. */
movl %edi, %eax
negl %eax
andl $3, %eax
movl %eax, scanalign(%esp)
/* IPos limit = s->strstart > (IPos)MAX_DIST(s) ? */
/* s->strstart - (IPos)MAX_DIST(s) : NIL; */
movl dsWSize(%edx), %eax
subl $MIN_LOOKAHEAD, %eax
subl %eax, %ebp
jg LimitPositive
xorl %ebp, %ebp
LimitPositive:
/* unsigned chain_length = s->max_chain_length; */
/* if (s->prev_length >= s->good_match) { */
/* chain_length >>= 2; */
/* } */
movl dsPrevLen(%edx), %eax
movl dsGoodMatch(%edx), %ebx
cmpl %ebx, %eax
movl dsMaxChainLen(%edx), %ebx
jl LastMatchGood
shrl $2, %ebx
LastMatchGood:
/* chainlen is decremented once beforehand so that the function can */
/* use the sign flag instead of the zero flag for the exit test. */
/* It is then shifted into the high word, to make room for the scanend */
/* scanend value, which it will always accompany. */
decl %ebx
shll $16, %ebx
/* int best_len = s->prev_length; */
movl dsPrevLen(%edx), %eax
movl %eax, bestlen(%esp)
/* Store the sum of s->window + best_len in %esi locally, and in %esi. */
addl %eax, %esi
movl %esi, windowbestlen(%esp)
/* register ush scan_start = *(ushf*)scan; */
/* register ush scan_end = *(ushf*)(scan+best_len-1); */
movw (%edi), %bx
movw %bx, scanstart(%esp)
movw -1(%edi,%eax), %bx
movl %ebx, chainlenscanend(%esp)
/* Posf *prev = s->prev; */
/* uInt wmask = s->w_mask; */
movl dsPrev(%edx), %edi
movl dsWMask(%edx), %edx
mov %edx, wmask(%esp)
/* Jump into the main loop. */
jmp LoopEntry
.balign 16
/* do {
* match = s->window + cur_match;
* if (*(ushf*)(match+best_len-1) != scan_end ||
* *(ushf*)match != scan_start) continue;
* [...]
* } while ((cur_match = prev[cur_match & wmask]) > limit
* && --chain_length != 0);
*
* Here is the inner loop of the function. The function will spend the
* majority of its time in this loop, and majority of that time will
* be spent in the first ten instructions.
*
* Within this loop:
* %ebx = chainlenscanend - i.e., ((chainlen << 16) | scanend)
* %ecx = curmatch
* %edx = curmatch & wmask
* %esi = windowbestlen - i.e., (window + bestlen)
* %edi = prev
* %ebp = limit
*
* Two optimization notes on the choice of instructions:
*
* The first instruction uses a 16-bit address, which costs an extra,
* unpairable cycle. This is cheaper than doing a 32-bit access and
* zeroing the high word, due to the 3-cycle misalignment penalty which
* would occur half the time. This also turns out to be cheaper than
* doing two separate 8-bit accesses, as the memory is so rarely in the
* L1 cache.
*
* The window buffer, however, apparently spends a lot of time in the
* cache, and so it is faster to retrieve the word at the end of the
* match string with two 8-bit loads. The instructions that test the
* word at the beginning of the match string, however, are executed
* much less frequently, and there it was cheaper to use 16-bit
* instructions, which avoided the necessity of saving off and
* subsequently reloading one of the other registers.
*/
LookupLoop:
/* 1 U & V */
movw (%edi,%edx,2), %cx /* 2 U pipe */
movl wmask(%esp), %edx /* 2 V pipe */
cmpl %ebp, %ecx /* 3 U pipe */
jbe LeaveNow /* 3 V pipe */
subl $0x00010000, %ebx /* 4 U pipe */
js LeaveNow /* 4 V pipe */
LoopEntry: movb -1(%esi,%ecx), %al /* 5 U pipe */
andl %ecx, %edx /* 5 V pipe */
cmpb %bl, %al /* 6 U pipe */
jnz LookupLoop /* 6 V pipe */
movb (%esi,%ecx), %ah
cmpb %bh, %ah
jnz LookupLoop
movl window(%esp), %eax
movw (%eax,%ecx), %ax
cmpw scanstart(%esp), %ax
jnz LookupLoop
/* Store the current value of chainlen. */
movl %ebx, chainlenscanend(%esp)
/* Point %edi to the string under scrutiny, and %esi to the string we */
/* are hoping to match it up with. In actuality, %esi and %edi are */
/* both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and %edx is */
/* initialized to -(MAX_MATCH_8 - scanalign). */
movl window(%esp), %esi
movl scan(%esp), %edi
addl %ecx, %esi
movl scanalign(%esp), %eax
movl $(-MAX_MATCH_8), %edx
lea MAX_MATCH_8(%edi,%eax), %edi
lea MAX_MATCH_8(%esi,%eax), %esi
/* Test the strings for equality, 8 bytes at a time. At the end,
* adjust %edx so that it is offset to the exact byte that mismatched.
*
* We already know at this point that the first three bytes of the
* strings match each other, and they can be safely passed over before
* starting the compare loop. So what this code does is skip over 0-3
* bytes, as much as necessary in order to dword-align the %edi
* pointer. (%esi will still be misaligned three times out of four.)
*
* It should be confessed that this loop usually does not represent
* much of the total running time. Replacing it with a more
* straightforward "rep cmpsb" would not drastically degrade
* performance.
*/
LoopCmps:
movl (%esi,%edx), %eax
movl (%edi,%edx), %ebx
xorl %ebx, %eax
jnz LeaveLoopCmps
movl 4(%esi,%edx), %eax
movl 4(%edi,%edx), %ebx
xorl %ebx, %eax
jnz LeaveLoopCmps4
addl $8, %edx
jnz LoopCmps
jmp LenMaximum
LeaveLoopCmps4: addl $4, %edx
LeaveLoopCmps: testl $0x0000FFFF, %eax
jnz LenLower
addl $2, %edx
shrl $16, %eax
LenLower: subb $1, %al
adcl $0, %edx
/* Calculate the length of the match. If it is longer than MAX_MATCH, */
/* then automatically accept it as the best possible match and leave. */
lea (%edi,%edx), %eax
movl scan(%esp), %edi
subl %edi, %eax
cmpl $MAX_MATCH, %eax
jge LenMaximum
/* If the length of the match is not longer than the best match we */
/* have so far, then forget it and return to the lookup loop. */
movl deflatestate(%esp), %edx
movl bestlen(%esp), %ebx
cmpl %ebx, %eax
jg LongerMatch
movl chainlenscanend(%esp), %ebx
movl windowbestlen(%esp), %esi
movl dsPrev(%edx), %edi
movl wmask(%esp), %edx
andl %ecx, %edx
jmp LookupLoop
/* s->match_start = cur_match; */
/* best_len = len; */
/* if (len >= nice_match) break; */
/* scan_end = *(ushf*)(scan+best_len-1); */
LongerMatch: movl nicematch(%esp), %ebx
movl %eax, bestlen(%esp)
movl %ecx, dsMatchStart(%edx)
cmpl %ebx, %eax
jge LeaveNow
movl window(%esp), %esi
addl %eax, %esi
movl %esi, windowbestlen(%esp)
movl chainlenscanend(%esp), %ebx
movw -1(%edi,%eax), %bx
movl dsPrev(%edx), %edi
movl %ebx, chainlenscanend(%esp)
movl wmask(%esp), %edx
andl %ecx, %edx
jmp LookupLoop
/* Accept the current string, with the maximum possible length. */
LenMaximum: movl deflatestate(%esp), %edx
movl $MAX_MATCH, bestlen(%esp)
movl %ecx, dsMatchStart(%edx)
/* if ((uInt)best_len <= s->lookahead) return (uInt)best_len; */
/* return s->lookahead; */
LeaveNow:
movl deflatestate(%esp), %edx
movl bestlen(%esp), %ebx
movl dsLookahead(%edx), %eax
cmpl %eax, %ebx
jg LookaheadRet
movl %ebx, %eax
LookaheadRet:
/* Restore the stack and return from whence we came. */
addl $LocalVarsSize, %esp
popl %ebx
popl %esi
popl %edi
popl %ebp
match_init: ret

View file

@ -0,0 +1,34 @@
This is a patched version of zlib, modified to use
Pentium-Pro-optimized assembly code in the deflation algorithm. The
files changed/added by this patch are:
README.686
match.S
The speedup that this patch provides varies, depending on whether the
compiler used to build the original version of zlib falls afoul of the
PPro's speed traps. My own tests show a speedup of around 10-20% at
the default compression level, and 20-30% using -9, against a version
compiled using gcc 2.7.2.3. Your mileage may vary.
Note that this code has been tailored for the PPro/PII in particular,
and will not perform particuarly well on a Pentium.
If you are using an assembler other than GNU as, you will have to
translate match.S to use your assembler's syntax. (Have fun.)
Brian Raiter
breadbox@muppetlabs.com
April, 1998
Added for zlib 1.1.3:
The patches come from
http://www.muppetlabs.com/~breadbox/software/assembly.html
To compile zlib with this asm file, copy match.S to the zlib directory
then do:
CFLAGS="-O3 -DASMV" ./configure
make OBJA=match.o

327
zlib/contrib/asm686/match.S Normal file
View file

@ -0,0 +1,327 @@
/* match.s -- Pentium-Pro-optimized version of longest_match()
* Written for zlib 1.1.2
* Copyright (C) 1998 Brian Raiter <breadbox@muppetlabs.com>
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License.
*/
#ifndef NO_UNDERLINE
#define match_init _match_init
#define longest_match _longest_match
#endif
#define MAX_MATCH (258)
#define MIN_MATCH (3)
#define MIN_LOOKAHEAD (MAX_MATCH + MIN_MATCH + 1)
#define MAX_MATCH_8 ((MAX_MATCH + 7) & ~7)
/* stack frame offsets */
#define chainlenwmask 0 /* high word: current chain len */
/* low word: s->wmask */
#define window 4 /* local copy of s->window */
#define windowbestlen 8 /* s->window + bestlen */
#define scanstart 16 /* first two bytes of string */
#define scanend 12 /* last two bytes of string */
#define scanalign 20 /* dword-misalignment of string */
#define nicematch 24 /* a good enough match size */
#define bestlen 28 /* size of best match so far */
#define scan 32 /* ptr to string wanting match */
#define LocalVarsSize (36)
/* saved ebx 36 */
/* saved edi 40 */
/* saved esi 44 */
/* saved ebp 48 */
/* return address 52 */
#define deflatestate 56 /* the function arguments */
#define curmatch 60
/* Offsets for fields in the deflate_state structure. These numbers
* are calculated from the definition of deflate_state, with the
* assumption that the compiler will dword-align the fields. (Thus,
* changing the definition of deflate_state could easily cause this
* program to crash horribly, without so much as a warning at
* compile time. Sigh.)
*/
#define dsWSize 36
#define dsWMask 44
#define dsWindow 48
#define dsPrev 56
#define dsMatchLen 88
#define dsPrevMatch 92
#define dsStrStart 100
#define dsMatchStart 104
#define dsLookahead 108
#define dsPrevLen 112
#define dsMaxChainLen 116
#define dsGoodMatch 132
#define dsNiceMatch 136
.file "match.S"
.globl match_init, longest_match
.text
/* uInt longest_match(deflate_state *deflatestate, IPos curmatch) */
longest_match:
/* Save registers that the compiler may be using, and adjust %esp to */
/* make room for our stack frame. */
pushl %ebp
pushl %edi
pushl %esi
pushl %ebx
subl $LocalVarsSize, %esp
/* Retrieve the function arguments. %ecx will hold cur_match */
/* throughout the entire function. %edx will hold the pointer to the */
/* deflate_state structure during the function's setup (before */
/* entering the main loop). */
movl deflatestate(%esp), %edx
movl curmatch(%esp), %ecx
/* uInt wmask = s->w_mask; */
/* unsigned chain_length = s->max_chain_length; */
/* if (s->prev_length >= s->good_match) { */
/* chain_length >>= 2; */
/* } */
movl dsPrevLen(%edx), %eax
movl dsGoodMatch(%edx), %ebx
cmpl %ebx, %eax
movl dsWMask(%edx), %eax
movl dsMaxChainLen(%edx), %ebx
jl LastMatchGood
shrl $2, %ebx
LastMatchGood:
/* chainlen is decremented once beforehand so that the function can */
/* use the sign flag instead of the zero flag for the exit test. */
/* It is then shifted into the high word, to make room for the wmask */
/* value, which it will always accompany. */
decl %ebx
shll $16, %ebx
orl %eax, %ebx
movl %ebx, chainlenwmask(%esp)
/* if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; */
movl dsNiceMatch(%edx), %eax
movl dsLookahead(%edx), %ebx
cmpl %eax, %ebx
jl LookaheadLess
movl %eax, %ebx
LookaheadLess: movl %ebx, nicematch(%esp)
/* register Bytef *scan = s->window + s->strstart; */
movl dsWindow(%edx), %esi
movl %esi, window(%esp)
movl dsStrStart(%edx), %ebp
lea (%esi,%ebp), %edi
movl %edi, scan(%esp)
/* Determine how many bytes the scan ptr is off from being */
/* dword-aligned. */
movl %edi, %eax
negl %eax
andl $3, %eax
movl %eax, scanalign(%esp)
/* IPos limit = s->strstart > (IPos)MAX_DIST(s) ? */
/* s->strstart - (IPos)MAX_DIST(s) : NIL; */
movl dsWSize(%edx), %eax
subl $MIN_LOOKAHEAD, %eax
subl %eax, %ebp
jg LimitPositive
xorl %ebp, %ebp
LimitPositive:
/* int best_len = s->prev_length; */
movl dsPrevLen(%edx), %eax
movl %eax, bestlen(%esp)
/* Store the sum of s->window + best_len in %esi locally, and in %esi. */
addl %eax, %esi
movl %esi, windowbestlen(%esp)
/* register ush scan_start = *(ushf*)scan; */
/* register ush scan_end = *(ushf*)(scan+best_len-1); */
/* Posf *prev = s->prev; */
movzwl (%edi), %ebx
movl %ebx, scanstart(%esp)
movzwl -1(%edi,%eax), %ebx
movl %ebx, scanend(%esp)
movl dsPrev(%edx), %edi
/* Jump into the main loop. */
movl chainlenwmask(%esp), %edx
jmp LoopEntry
.balign 16
/* do {
* match = s->window + cur_match;
* if (*(ushf*)(match+best_len-1) != scan_end ||
* *(ushf*)match != scan_start) continue;
* [...]
* } while ((cur_match = prev[cur_match & wmask]) > limit
* && --chain_length != 0);
*
* Here is the inner loop of the function. The function will spend the
* majority of its time in this loop, and majority of that time will
* be spent in the first ten instructions.
*
* Within this loop:
* %ebx = scanend
* %ecx = curmatch
* %edx = chainlenwmask - i.e., ((chainlen << 16) | wmask)
* %esi = windowbestlen - i.e., (window + bestlen)
* %edi = prev
* %ebp = limit
*/
LookupLoop:
andl %edx, %ecx
movzwl (%edi,%ecx,2), %ecx
cmpl %ebp, %ecx
jbe LeaveNow
subl $0x00010000, %edx
js LeaveNow
LoopEntry: movzwl -1(%esi,%ecx), %eax
cmpl %ebx, %eax
jnz LookupLoop
movl window(%esp), %eax
movzwl (%eax,%ecx), %eax
cmpl scanstart(%esp), %eax
jnz LookupLoop
/* Store the current value of chainlen. */
movl %edx, chainlenwmask(%esp)
/* Point %edi to the string under scrutiny, and %esi to the string we */
/* are hoping to match it up with. In actuality, %esi and %edi are */
/* both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and %edx is */
/* initialized to -(MAX_MATCH_8 - scanalign). */
movl window(%esp), %esi
movl scan(%esp), %edi
addl %ecx, %esi
movl scanalign(%esp), %eax
movl $(-MAX_MATCH_8), %edx
lea MAX_MATCH_8(%edi,%eax), %edi
lea MAX_MATCH_8(%esi,%eax), %esi
/* Test the strings for equality, 8 bytes at a time. At the end,
* adjust %edx so that it is offset to the exact byte that mismatched.
*
* We already know at this point that the first three bytes of the
* strings match each other, and they can be safely passed over before
* starting the compare loop. So what this code does is skip over 0-3
* bytes, as much as necessary in order to dword-align the %edi
* pointer. (%esi will still be misaligned three times out of four.)
*
* It should be confessed that this loop usually does not represent
* much of the total running time. Replacing it with a more
* straightforward "rep cmpsb" would not drastically degrade
* performance.
*/
LoopCmps:
movl (%esi,%edx), %eax
xorl (%edi,%edx), %eax
jnz LeaveLoopCmps
movl 4(%esi,%edx), %eax
xorl 4(%edi,%edx), %eax
jnz LeaveLoopCmps4
addl $8, %edx
jnz LoopCmps
jmp LenMaximum
LeaveLoopCmps4: addl $4, %edx
LeaveLoopCmps: testl $0x0000FFFF, %eax
jnz LenLower
addl $2, %edx
shrl $16, %eax
LenLower: subb $1, %al
adcl $0, %edx
/* Calculate the length of the match. If it is longer than MAX_MATCH, */
/* then automatically accept it as the best possible match and leave. */
lea (%edi,%edx), %eax
movl scan(%esp), %edi
subl %edi, %eax
cmpl $MAX_MATCH, %eax
jge LenMaximum
/* If the length of the match is not longer than the best match we */
/* have so far, then forget it and return to the lookup loop. */
movl deflatestate(%esp), %edx
movl bestlen(%esp), %ebx
cmpl %ebx, %eax
jg LongerMatch
movl windowbestlen(%esp), %esi
movl dsPrev(%edx), %edi
movl scanend(%esp), %ebx
movl chainlenwmask(%esp), %edx
jmp LookupLoop
/* s->match_start = cur_match; */
/* best_len = len; */
/* if (len >= nice_match) break; */
/* scan_end = *(ushf*)(scan+best_len-1); */
LongerMatch: movl nicematch(%esp), %ebx
movl %eax, bestlen(%esp)
movl %ecx, dsMatchStart(%edx)
cmpl %ebx, %eax
jge LeaveNow
movl window(%esp), %esi
addl %eax, %esi
movl %esi, windowbestlen(%esp)
movzwl -1(%edi,%eax), %ebx
movl dsPrev(%edx), %edi
movl %ebx, scanend(%esp)
movl chainlenwmask(%esp), %edx
jmp LookupLoop
/* Accept the current string, with the maximum possible length. */
LenMaximum: movl deflatestate(%esp), %edx
movl $MAX_MATCH, bestlen(%esp)
movl %ecx, dsMatchStart(%edx)
/* if ((uInt)best_len <= s->lookahead) return (uInt)best_len; */
/* return s->lookahead; */
LeaveNow:
movl deflatestate(%esp), %edx
movl bestlen(%esp), %ebx
movl dsLookahead(%edx), %eax
cmpl %eax, %ebx
jg LookaheadRet
movl %ebx, %eax
LookaheadRet:
/* Restore the stack and return from whence we came. */
addl $LocalVarsSize, %esp
popl %ebx
popl %esi
popl %edi
popl %ebp
match_init: ret

View file

@ -0,0 +1,8 @@
blast: blast.c blast.h
cc -DTEST -o blast blast.c
test: blast
blast < test.pk | cmp - test.txt
clean:
rm -f blast blast.o

View file

@ -0,0 +1,4 @@
Read blast.h for purpose and usage.
Mark Adler
madler@alumni.caltech.edu

444
zlib/contrib/blast/blast.c Normal file
View file

@ -0,0 +1,444 @@
/* blast.c
* Copyright (C) 2003 Mark Adler
* For conditions of distribution and use, see copyright notice in blast.h
* version 1.1, 16 Feb 2003
*
* blast.c decompresses data compressed by the PKWare Compression Library.
* This function provides functionality similar to the explode() function of
* the PKWare library, hence the name "blast".
*
* This decompressor is based on the excellent format description provided by
* Ben Rudiak-Gould in comp.compression on August 13, 2001. Interestingly, the
* example Ben provided in the post is incorrect. The distance 110001 should
* instead be 111000. When corrected, the example byte stream becomes:
*
* 00 04 82 24 25 8f 80 7f
*
* which decompresses to "AIAIAIAIAIAIA" (without the quotes).
*/
/*
* Change history:
*
* 1.0 12 Feb 2003 - First version
* 1.1 16 Feb 2003 - Fixed distance check for > 4 GB uncompressed data
*/
#include <setjmp.h> /* for setjmp(), longjmp(), and jmp_buf */
#include "blast.h" /* prototype for blast() */
#define local static /* for local function definitions */
#define MAXBITS 13 /* maximum code length */
#define MAXWIN 4096 /* maximum window size */
/* input and output state */
struct state {
/* input state */
blast_in infun; /* input function provided by user */
void *inhow; /* opaque information passed to infun() */
unsigned char *in; /* next input location */
unsigned left; /* available input at in */
int bitbuf; /* bit buffer */
int bitcnt; /* number of bits in bit buffer */
/* input limit error return state for bits() and decode() */
jmp_buf env;
/* output state */
blast_out outfun; /* output function provided by user */
void *outhow; /* opaque information passed to outfun() */
unsigned next; /* index of next write location in out[] */
int first; /* true to check distances (for first 4K) */
unsigned char out[MAXWIN]; /* output buffer and sliding window */
};
/*
* Return need bits from the input stream. This always leaves less than
* eight bits in the buffer. bits() works properly for need == 0.
*
* Format notes:
*
* - Bits are stored in bytes from the least significant bit to the most
* significant bit. Therefore bits are dropped from the bottom of the bit
* buffer, using shift right, and new bytes are appended to the top of the
* bit buffer, using shift left.
*/
local int bits(struct state *s, int need)
{
int val; /* bit accumulator */
/* load at least need bits into val */
val = s->bitbuf;
while (s->bitcnt < need) {
if (s->left == 0) {
s->left = s->infun(s->inhow, &(s->in));
if (s->left == 0) longjmp(s->env, 1); /* out of input */
}
val |= (int)(*(s->in)++) << s->bitcnt; /* load eight bits */
s->left--;
s->bitcnt += 8;
}
/* drop need bits and update buffer, always zero to seven bits left */
s->bitbuf = val >> need;
s->bitcnt -= need;
/* return need bits, zeroing the bits above that */
return val & ((1 << need) - 1);
}
/*
* Huffman code decoding tables. count[1..MAXBITS] is the number of symbols of
* each length, which for a canonical code are stepped through in order.
* symbol[] are the symbol values in canonical order, where the number of
* entries is the sum of the counts in count[]. The decoding process can be
* seen in the function decode() below.
*/
struct huffman {
short *count; /* number of symbols of each length */
short *symbol; /* canonically ordered symbols */
};
/*
* Decode a code from the stream s using huffman table h. Return the symbol or
* a negative value if there is an error. If all of the lengths are zero, i.e.
* an empty code, or if the code is incomplete and an invalid code is received,
* then -9 is returned after reading MAXBITS bits.
*
* Format notes:
*
* - The codes as stored in the compressed data are bit-reversed relative to
* a simple integer ordering of codes of the same lengths. Hence below the
* bits are pulled from the compressed data one at a time and used to
* build the code value reversed from what is in the stream in order to
* permit simple integer comparisons for decoding.
*
* - The first code for the shortest length is all ones. Subsequent codes of
* the same length are simply integer decrements of the previous code. When
* moving up a length, a one bit is appended to the code. For a complete
* code, the last code of the longest length will be all zeros. To support
* this ordering, the bits pulled during decoding are inverted to apply the
* more "natural" ordering starting with all zeros and incrementing.
*/
local int decode(struct state *s, struct huffman *h)
{
int len; /* current number of bits in code */
int code; /* len bits being decoded */
int first; /* first code of length len */
int count; /* number of codes of length len */
int index; /* index of first code of length len in symbol table */
int bitbuf; /* bits from stream */
int left; /* bits left in next or left to process */
short *next; /* next number of codes */
bitbuf = s->bitbuf;
left = s->bitcnt;
code = first = index = 0;
len = 1;
next = h->count + 1;
while (1) {
while (left--) {
code |= (bitbuf & 1) ^ 1; /* invert code */
bitbuf >>= 1;
count = *next++;
if (code < first + count) { /* if length len, return symbol */
s->bitbuf = bitbuf;
s->bitcnt = (s->bitcnt - len) & 7;
return h->symbol[index + (code - first)];
}
index += count; /* else update for next length */
first += count;
first <<= 1;
code <<= 1;
len++;
}
left = (MAXBITS+1) - len;
if (left == 0) break;
if (s->left == 0) {
s->left = s->infun(s->inhow, &(s->in));
if (s->left == 0) longjmp(s->env, 1); /* out of input */
}
bitbuf = *(s->in)++;
s->left--;
if (left > 8) left = 8;
}
return -9; /* ran out of codes */
}
/*
* Given a list of repeated code lengths rep[0..n-1], where each byte is a
* count (high four bits + 1) and a code length (low four bits), generate the
* list of code lengths. This compaction reduces the size of the object code.
* Then given the list of code lengths length[0..n-1] representing a canonical
* Huffman code for n symbols, construct the tables required to decode those
* codes. Those tables are the number of codes of each length, and the symbols
* sorted by length, retaining their original order within each length. The
* return value is zero for a complete code set, negative for an over-
* subscribed code set, and positive for an incomplete code set. The tables
* can be used if the return value is zero or positive, but they cannot be used
* if the return value is negative. If the return value is zero, it is not
* possible for decode() using that table to return an error--any stream of
* enough bits will resolve to a symbol. If the return value is positive, then
* it is possible for decode() using that table to return an error for received
* codes past the end of the incomplete lengths.
*/
local int construct(struct huffman *h, const unsigned char *rep, int n)
{
int symbol; /* current symbol when stepping through length[] */
int len; /* current length when stepping through h->count[] */
int left; /* number of possible codes left of current length */
short offs[MAXBITS+1]; /* offsets in symbol table for each length */
short length[256]; /* code lengths */
/* convert compact repeat counts into symbol bit length list */
symbol = 0;
do {
len = *rep++;
left = (len >> 4) + 1;
len &= 15;
do {
length[symbol++] = len;
} while (--left);
} while (--n);
n = symbol;
/* count number of codes of each length */
for (len = 0; len <= MAXBITS; len++)
h->count[len] = 0;
for (symbol = 0; symbol < n; symbol++)
(h->count[length[symbol]])++; /* assumes lengths are within bounds */
if (h->count[0] == n) /* no codes! */
return 0; /* complete, but decode() will fail */
/* check for an over-subscribed or incomplete set of lengths */
left = 1; /* one possible code of zero length */
for (len = 1; len <= MAXBITS; len++) {
left <<= 1; /* one more bit, double codes left */
left -= h->count[len]; /* deduct count from possible codes */
if (left < 0) return left; /* over-subscribed--return negative */
} /* left > 0 means incomplete */
/* generate offsets into symbol table for each length for sorting */
offs[1] = 0;
for (len = 1; len < MAXBITS; len++)
offs[len + 1] = offs[len] + h->count[len];
/*
* put symbols in table sorted by length, by symbol order within each
* length
*/
for (symbol = 0; symbol < n; symbol++)
if (length[symbol] != 0)
h->symbol[offs[length[symbol]]++] = symbol;
/* return zero for complete set, positive for incomplete set */
return left;
}
/*
* Decode PKWare Compression Library stream.
*
* Format notes:
*
* - First byte is 0 if literals are uncoded or 1 if they are coded. Second
* byte is 4, 5, or 6 for the number of extra bits in the distance code.
* This is the base-2 logarithm of the dictionary size minus six.
*
* - Compressed data is a combination of literals and length/distance pairs
* terminated by an end code. Literals are either Huffman coded or
* uncoded bytes. A length/distance pair is a coded length followed by a
* coded distance to represent a string that occurs earlier in the
* uncompressed data that occurs again at the current location.
*
* - A bit preceding a literal or length/distance pair indicates which comes
* next, 0 for literals, 1 for length/distance.
*
* - If literals are uncoded, then the next eight bits are the literal, in the
* normal bit order in th stream, i.e. no bit-reversal is needed. Similarly,
* no bit reversal is needed for either the length extra bits or the distance
* extra bits.
*
* - Literal bytes are simply written to the output. A length/distance pair is
* an instruction to copy previously uncompressed bytes to the output. The
* copy is from distance bytes back in the output stream, copying for length
* bytes.
*
* - Distances pointing before the beginning of the output data are not
* permitted.
*
* - Overlapped copies, where the length is greater than the distance, are
* allowed and common. For example, a distance of one and a length of 518
* simply copies the last byte 518 times. A distance of four and a length of
* twelve copies the last four bytes three times. A simple forward copy
* ignoring whether the length is greater than the distance or not implements
* this correctly.
*/
local int decomp(struct state *s)
{
int lit; /* true if literals are coded */
int dict; /* log2(dictionary size) - 6 */
int symbol; /* decoded symbol, extra bits for distance */
int len; /* length for copy */
int dist; /* distance for copy */
int copy; /* copy counter */
unsigned char *from, *to; /* copy pointers */
static int virgin = 1; /* build tables once */
static short litcnt[MAXBITS+1], litsym[256]; /* litcode memory */
static short lencnt[MAXBITS+1], lensym[16]; /* lencode memory */
static short distcnt[MAXBITS+1], distsym[64]; /* distcode memory */
static struct huffman litcode = {litcnt, litsym}; /* length code */
static struct huffman lencode = {lencnt, lensym}; /* length code */
static struct huffman distcode = {distcnt, distsym};/* distance code */
/* bit lengths of literal codes */
static const unsigned char litlen[] = {
11, 124, 8, 7, 28, 7, 188, 13, 76, 4, 10, 8, 12, 10, 12, 10, 8, 23, 8,
9, 7, 6, 7, 8, 7, 6, 55, 8, 23, 24, 12, 11, 7, 9, 11, 12, 6, 7, 22, 5,
7, 24, 6, 11, 9, 6, 7, 22, 7, 11, 38, 7, 9, 8, 25, 11, 8, 11, 9, 12,
8, 12, 5, 38, 5, 38, 5, 11, 7, 5, 6, 21, 6, 10, 53, 8, 7, 24, 10, 27,
44, 253, 253, 253, 252, 252, 252, 13, 12, 45, 12, 45, 12, 61, 12, 45,
44, 173};
/* bit lengths of length codes 0..15 */
static const unsigned char lenlen[] = {2, 35, 36, 53, 38, 23};
/* bit lengths of distance codes 0..63 */
static const unsigned char distlen[] = {2, 20, 53, 230, 247, 151, 248};
static const short base[16] = { /* base for length codes */
3, 2, 4, 5, 6, 7, 8, 9, 10, 12, 16, 24, 40, 72, 136, 264};
static const char extra[16] = { /* extra bits for length codes */
0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8};
/* set up decoding tables (once--might not be thread-safe) */
if (virgin) {
construct(&litcode, litlen, sizeof(litlen));
construct(&lencode, lenlen, sizeof(lenlen));
construct(&distcode, distlen, sizeof(distlen));
virgin = 0;
}
/* read header */
lit = bits(s, 8);
if (lit > 1) return -1;
dict = bits(s, 8);
if (dict < 4 || dict > 6) return -2;
/* decode literals and length/distance pairs */
do {
if (bits(s, 1)) {
/* get length */
symbol = decode(s, &lencode);
len = base[symbol] + bits(s, extra[symbol]);
if (len == 519) break; /* end code */
/* get distance */
symbol = len == 2 ? 2 : dict;
dist = decode(s, &distcode) << symbol;
dist += bits(s, symbol);
dist++;
if (s->first && dist > s->next)
return -3; /* distance too far back */
/* copy length bytes from distance bytes back */
do {
to = s->out + s->next;
from = to - dist;
copy = MAXWIN;
if (s->next < dist) {
from += copy;
copy = dist;
}
copy -= s->next;
if (copy > len) copy = len;
len -= copy;
s->next += copy;
do {
*to++ = *from++;
} while (--copy);
if (s->next == MAXWIN) {
if (s->outfun(s->outhow, s->out, s->next)) return 1;
s->next = 0;
s->first = 0;
}
} while (len != 0);
}
else {
/* get literal and write it */
symbol = lit ? decode(s, &litcode) : bits(s, 8);
s->out[s->next++] = symbol;
if (s->next == MAXWIN) {
if (s->outfun(s->outhow, s->out, s->next)) return 1;
s->next = 0;
s->first = 0;
}
}
} while (1);
return 0;
}
/* See comments in blast.h */
int blast(blast_in infun, void *inhow, blast_out outfun, void *outhow)
{
struct state s; /* input/output state */
int err; /* return value */
/* initialize input state */
s.infun = infun;
s.inhow = inhow;
s.left = 0;
s.bitbuf = 0;
s.bitcnt = 0;
/* initialize output state */
s.outfun = outfun;
s.outhow = outhow;
s.next = 0;
s.first = 1;
/* return if bits() or decode() tries to read past available input */
if (setjmp(s.env) != 0) /* if came back here via longjmp(), */
err = 2; /* then skip decomp(), return error */
else
err = decomp(&s); /* decompress */
/* write any leftover output and update the error code if needed */
if (err != 1 && s.next && s.outfun(s.outhow, s.out, s.next) && err == 0)
err = 1;
return err;
}
#ifdef TEST
/* Example of how to use blast() */
#include <stdio.h>
#include <stdlib.h>
#define CHUNK 16384
local unsigned inf(void *how, unsigned char **buf)
{
static unsigned char hold[CHUNK];
*buf = hold;
return fread(hold, 1, CHUNK, (FILE *)how);
}
local int outf(void *how, unsigned char *buf, unsigned len)
{
return fwrite(buf, 1, len, (FILE *)how) != len;
}
/* Decompress a PKWare Compression Library stream from stdin to stdout */
int main(void)
{
int ret, n;
/* decompress to stdout */
ret = blast(inf, stdin, outf, stdout);
if (ret != 0) fprintf(stderr, "blast error: %d\n", ret);
/* see if there are any leftover bytes */
n = 0;
while (getchar() != EOF) n++;
if (n) fprintf(stderr, "blast warning: %d unused bytes of input\n", n);
/* return blast() error code */
return ret;
}
#endif

View file

@ -0,0 +1,71 @@
/* blast.h -- interface for blast.c
Copyright (C) 2003 Mark Adler
version 1.1, 16 Feb 2003
This software is provided 'as-is', without any express or implied
warranty. In no event will the author 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.
Mark Adler madler@alumni.caltech.edu
*/
/*
* blast() decompresses the PKWare Data Compression Library (DCL) compressed
* format. It provides the same functionality as the explode() function in
* that library. (Note: PKWare overused the "implode" verb, and the format
* used by their library implode() function is completely different and
* incompatible with the implode compression method supported by PKZIP.)
*/
typedef unsigned (*blast_in)(void *how, unsigned char **buf);
typedef int (*blast_out)(void *how, unsigned char *buf, unsigned len);
/* Definitions for input/output functions passed to blast(). See below for
* what the provided functions need to do.
*/
int blast(blast_in infun, void *inhow, blast_out outfun, void *outhow);
/* Decompress input to output using the provided infun() and outfun() calls.
* On success, the return value of blast() is zero. If there is an error in
* the source data, i.e. it is not in the proper format, then a negative value
* is returned. If there is not enough input available or there is not enough
* output space, then a positive error is returned.
*
* The input function is invoked: len = infun(how, &buf), where buf is set by
* infun() to point to the input buffer, and infun() returns the number of
* available bytes there. If infun() returns zero, then blast() returns with
* an input error. (blast() only asks for input if it needs it.) inhow is for
* use by the application to pass an input descriptor to infun(), if desired.
*
* The output function is invoked: err = outfun(how, buf, len), where the bytes
* to be written are buf[0..len-1]. If err is not zero, then blast() returns
* with an output error. outfun() is always called with len <= 4096. outhow
* is for use by the application to pass an output descriptor to outfun(), if
* desired.
*
* The return codes are:
*
* 2: ran out of input before completing decompression
* 1: output error before completing decompression
* 0: successful decompression
* -1: literal flag not zero or one
* -2: dictionary size not in 4..6
* -3: distance is too far back
*
* At the bottom of blast.c is an example program that uses blast() that can be
* compiled to produce a command-line decompression filter by defining TEST.
*/

Some files were not shown because too many files have changed in this diff Show more