/***************************************************************************
 *             __________               __   ___.
 *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
 *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
 *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
 *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
 *                     \/            \/     \/    \/            \/
 *
 * Pacbox - a Pacman Emulator for Rockbox
 *
 * Based on PIE - Pacman Instructional Emulator
 *
 * Copyright (c) 1997-2003,2004 Alessandro Scotti
 * http://www.ascotti.org/
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 * KIND, either express or implied.
 *
 ****************************************************************************/

#ifndef _HARDWARE_H
#define _HARDWARE_H

extern unsigned char   ram_[20*1024];          // ROM (16K) and RAM (4K)
extern unsigned char   charset_rom_[4*1024];   // Character set ROM (4K)
extern unsigned char   spriteset_rom_[4*1024]; // Sprite set ROM (4K)
extern unsigned char dirty_[1024];
extern unsigned char video_mem_[1024];       // Video memory (1K)
extern unsigned char color_mem_[1024];       // Color memory (1K)
extern unsigned char charmap_[256*8*8];    /* Character data for 256 8x8 characters */
extern unsigned char spritemap_[64*16*16]; /* Sprite data for 64 16x16 sprites */
extern unsigned char output_devices_;  /* Output flip-flops set by the game program */
extern unsigned char   interrupt_vector_;
extern unsigned        coin_counter_;
extern unsigned char port1_;
extern unsigned char port2_;
extern unsigned char dip_switches_;

/* Output flip-flops */
enum {
    FlipScreen          = 0x01,
    PlayerOneLight      = 0x02,
    PlayerTwoLight      = 0x04,
    InterruptEnabled    = 0x08,
    SoundEnabled        = 0x10,
    CoinLockout         = 0x20,
    CoinMeter           = 0x40,
    AuxBoardEnabled     = 0x80
};

struct PacmanSprite
{
    int mode; /** Display mode (normal or flipped) */
    int x; /** X coordinate */
    int y; /** Y coordinate */
    int n; /** Shape (from 0 to 63) */
    int color; /** Base color (0=not visible) */
};

/* Internal tables and structures for faster access to data */
extern struct PacmanSprite    sprites_[8];    /* Sprites */
extern short             vchar_to_i_[1024];

void writeByte(unsigned addr, unsigned char b);
unsigned char readPort( unsigned port );
void writePort( unsigned addr, unsigned char b );
void setOutputFlipFlop( unsigned char bit, unsigned char value );

/*
    For Z80 Environment: read a byte from high memory addresses (i.e. the
    memory-mapped registers)
*/
static inline unsigned char readByte( unsigned addr ) 
{
    addr &= 0xFFFF;

    if (addr < sizeof(ram_))
        return ram_[addr];

    // Address is not in RAM, check to see if it's a memory mapped register
    switch( addr & 0xFFC0 ) {
    // IN0
    case 0x5000: 
        // bit 0 : up
        // bit 1 : left
        // bit 2 : right
        // bit 3 : down
        // bit 4 : switch: advance to next level
        // bit 5 : coin 1
        // bit 6 : coin 2
        // bit 7 : credit (same as coin but coin counter is not incremented)
        return port1_;
    // IN1
    case 0x5040: 
        // bit 0 : up (2nd player)
        // bit 1 : left (2nd player)
        // bit 2 : right (2nd player)
        // bit 3 : down (2nd player)
        // bit 4 : switch: rack test -> 0x10=off, 0=on
        // bit 5 : start 1
        // bit 6 : start 2
        // bit 7 : cabinet -> 0x80=upright, 0x00=table
        return port2_;
    // DSW1
    case 0x5080:
        // bits 0,1 : coinage -> 0=free play, 1=1 coin/play, 2=1 coin/2 play, 3=2 coin/1 play
        // bits 2,3 : lives -> 0x0=1, 0x4=2, 0x8=3, 0xC=5
        // bits 4,5 : bonus life -> 0=10000, 0x10=15000, 0x20=20000, 0x30=none
        // bit  6   : jumper pad: difficulty -> 0x40=normal, 0=hard
        // bit  7   : jumper pad: ghost name -> 0x80=normal, 0=alternate
        return dip_switches_;
    // Watchdog reset
    case 0x50C0:
        break;
    }

    return 0xFF;
}

/* Reads a 16 bit word from memory at the specified address. */
static inline unsigned readWord( unsigned addr ) {
    addr &= 0xFFFF;

    if (addr < (sizeof(ram_)-1)) {
        return ram_[addr] | ((ram_[addr+1]) << 8);
    } else {
        return readByte(addr) | (((unsigned)readByte(addr+1)) << 8);
    }
}

/* Writes a 16 bit word to memory at the specified address. */
static inline void writeWord( unsigned addr, unsigned value ) {
    writeByte( addr,   value & 0xFF );
    writeByte( addr+1, (value >> 8) & 0xFF );
}

#endif
