/***************************************************************************
 *   Copyright (C) 2006 Nicolas Hadacek <hadacek@kde.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.                                   *
 ***************************************************************************/
#ifndef PIC_REGISTER_H
#define PIC_REGISTER_H

#include <tqmap.h>

#include "devices/base/register.h"
#include "pic.h"

namespace Pic
{
class Data;
struct RangeData {
  Address start;
  uint length;
};

//-----------------------------------------------------------------------------
enum RegisterType { UnusedRegister, Sfr, Gpr, Mirrored};
enum RegisterBitProperty { RegisterBitUnused = 0x0,
  RegisterBitRead = 0x1, RegisterBitWrite = 0x2,
  RegisterBitOnlySoftwareClear = 0x4, RegisterBitOnlySoftwareSet = 0x8,
  MaxRegisterBitProperty = 0x15
};
TQ_DECLARE_FLAGS(RegisterBitProperties, RegisterBitProperty)
TQ_DECLARE_OPERATORS_FOR_FLAGS(RegisterBitProperties)
enum RegisterBitState { RegisterBitUnknown = 0, RegisterBitLow, RegisterBitHigh,
  RegisterBitUnchanged, RegisterBitDepends, RegisterBitDependsConfig, Nb_RegisterBitStates
};

//-----------------------------------------------------------------------------
class RegisterBitData
{
public:
  RegisterBitData() : properties(RegisterBitUnused) {}
  RegisterBitProperties properties;
  RegisterBitState por, mclr;
};
struct RegisterData
{
  Address address;
  RegisterBitData bits[Device::MAX_NB_PORT_BITS];
};
struct CombinedData
{
  Address address;
  uint    nbChars;
};

class RegistersData : public Device::RegistersData
{
public:
  RegistersData(const Data &data);
  virtual uint nbBits() const { return _data.architecture().data().nbBitsRegister; }
  uint nbBytesPerBank() const { return _data.architecture().data().registerBankLength; }
  uint nbRegistersPerBank() const { return nbBytesPerBank() / nbBytes(); }
  uint nbCharsAddress() const { return ::nbChars(nbRegisters() - 1); }
  virtual uint nbRegisters() const { return nbBanks * nbRegistersPerBank(); }
  virtual uint addressFromIndex(uint i) const { return nbBytes() * i; }
  virtual uint indexFromAddress(Address address) const { return address.toUInt() / nbBytes(); }
  bool isBankUsed(uint i) const;
  uint bankFromAddress(Address address) const { return indexFromAddress(address) / nbRegistersPerBank(); }
  bool bankHasSfrs(uint i) const; // slow
  bool hasSharedGprs(uint &firstIndex, bool &all) const; // i.e. mirrored in all banks (all is for first bank only)
  uint firstGprIndex() const; // in first bank

  uint nbBanks, accessBankSplit, unusedBankMask;
  TQMap<TQString, RegisterData> sfrs;
  TQMap<Address, TQString> sfrNames; // address -> name
  TQValueVector<TQValueVector<RangeData> > mirrored;
  TQValueVector<RangeData> unused;
  TQMap<TQString, CombinedData> combined;

  virtual Device::RegisterProperties properties(Address address) const;
  RegisterType type(Address address) const;
  TQString label(Address address) const;
  virtual TQValueList<Register::TypeData> relatedRegisters(const Register::TypeData &data) const;

  virtual bool hasPort(uint index) const;
  virtual int portIndex(Address address) const;
  virtual TQString portName(uint index) const;
  bool hasTris(uint index) const;
  TQString trisName(uint index) const;
  bool hasLatch(uint index) const;
  TQString latchName(uint index) const;
  virtual bool hasPortBit(uint index, uint bit) const;
  virtual TQString portBitName(uint index, uint bit) const;

private:
  const Data &_data;
  Address mirroredAddress(Address address) const;
};

//-----------------------------------------------------------------------------
TQDataStream &operator <<(TQDataStream &s, const RangeData &rd);
TQDataStream &operator >>(TQDataStream &s, RangeData &rd);
TQDataStream &operator <<(TQDataStream &s, const RegisterBitData &rbd);
TQDataStream &operator >>(TQDataStream &s, RegisterBitData &rbd);
TQDataStream &operator <<(TQDataStream &s, const RegisterData &rd);
TQDataStream &operator >>(TQDataStream &s, RegisterData &rd);
TQDataStream &operator <<(TQDataStream &s, const CombinedData &rd);
TQDataStream &operator >>(TQDataStream &s, CombinedData &rd);
TQDataStream &operator <<(TQDataStream &s, const RegistersData &rd);
TQDataStream &operator >>(TQDataStream &s, RegistersData &rd);

} // namespace

#endif
