/***************************************************************************
 *   Copyright (C) 2005-2007 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_H
#define PIC_H

#include <tqstringlist.h>
#include <tqmap.h>

#include "common/global/global.h"
#include "common/common/bitvalue.h"
#include "devices/base/generic_device.h"

namespace Pic
{
class XmlToData;
class Group;
class Config;
class RegistersData;

//-----------------------------------------------------------------------------
struct VoltageData {
  double min, max, nominal;
};
inline bool operator ==(const Pic::VoltageData &v1, const Pic::VoltageData &v2) { return ( v1.min==v2.min && v1.max==v2.max && v1.nominal==v2.nominal ); }

BEGIN_DECLARE_ENUM(ProgVoltageType)
  Vpp = 0, VddBulkErase, VddWrite
END_DECLARE_ENUM_STD(ProgVoltageType)

struct CalibrationData {
  BitValue opcode, opcodeMask;
};

enum MemoryRangeTypeProperty { ReadOnly = 0, Writable = 1 };
TQ_DECLARE_FLAGS(MemoryRangeTypeProperties, MemoryRangeTypeProperty)
TQ_DECLARE_OPERATORS_FOR_FLAGS(MemoryRangeTypeProperties)
struct MemoryRangeTypeData {
  const char *key, *label;
  MemoryRangeTypeProperties properties;
};
BEGIN_DECLARE_ENUM(MemoryRangeType)
  Code = 0, Cal, UserId, DeviceId, Config, Eeprom, DebugVector, HardwareStack, CalBackup, ProgramExecutive
END_DECLARE_ENUM(MemoryRangeType, MemoryRangeTypeData)

BEGIN_DECLARE_ENUM(SelfWrite)
  Yes, No
END_DECLARE_ENUM_STD(SelfWrite)

BEGIN_DECLARE_ENUM(DeviceType)
  Normal, J, K
END_DECLARE_ENUM_STD(DeviceType)

struct ArchitectureData {
  const char *key, *label;
  uint nbBitsPC;                     // nb bits program counter
  uint nbBytesWord;                  // nb bytes per word (hex file and icd2)
  bool packed;                       // addressIncrement = (packed ? nbBytesWord : nbBytesWord/2)
  uint nbBitsRegister;
  uint registerBankLength;
  uint nbBits[MemoryRangeType::Nb_Types];  // nb bits per word
  bool hasAddressAccess;             // memory can be accessed randomly
  SelfWrite::Type selfWrite;
  DeviceType::Type deviceType;
};
BEGIN_DECLARE_ENUM(Architecture)
  P10X = 0, P16X, P17C, P18C, P18F, P18J, P24F, P24H, P30F, P33F
END_DECLARE_ENUM(Architecture, ArchitectureData)

enum MemoryRangeProperty { NotPresent = 0, Present = 1, Programmable = 2 };
TQ_DECLARE_FLAGS(MemoryRangeProperties, MemoryRangeProperty)
TQ_DECLARE_OPERATORS_FOR_FLAGS(MemoryRangeProperties)
struct MemoryRangeData {
  MemoryRangeProperties properties;
  Address start, end;
  uint hexFileOffset;
};

namespace Checksum
{
  BEGIN_DECLARE_ENUM(Algorithm)
    Normal = 0, XOR4, XNOR7, XNOR8
  END_DECLARE_ENUM_STD(Algorithm)
  class Data {
  public:
    BitValue constant;
    Algorithm algorithm;
    TQStringList protectedMaskNames;
    TQString bbsize;
    BitValue blankChecksum, checkChecksum;
  };
} // namespace

BEGIN_DECLARE_ENUM(Feature)
  CCP, ADC, SSP, LVD, USB, USART, CAN, ECAN, Ethernet, LCD, MotorControl,
  MotionFeedback, SelfWrite
END_DECLARE_ENUM_STD(Feature)

//-----------------------------------------------------------------------------
class Data : public Device::Data
{
public:
  Data();
  virtual ~Data();
  virtual TQString fname(Device::Special special) const;
  virtual TQString listViewGroup() const { return _architecture.label(); }
  bool isPresent(MemoryRangeType type) const { return (range(type).properties & Present); }
  bool isReadable(MemoryRangeType type) const;
  bool isWritable(MemoryRangeType type) const;
  uint nbAddresses(MemoryRangeType type) const;
  uint nbWords(MemoryRangeType type) const;
  uint addressIncrement(MemoryRangeType type) const;
  uint nbWordsWriteAlignment(MemoryRangeType type) const;
  MemoryRangeData range(MemoryRangeType type) const { return _ranges[type]; }
  virtual uint nbBitsAddress() const { return _nbBitsPC; }
  uint nbBitsWord(MemoryRangeType type) const { return _architecture.data().nbBits[type.type()]; }
  uint nbBytesWord(MemoryRangeType type) const { return nbBitsToNbBytes(nbBitsWord(type)); }
  uint nbCharsWord(MemoryRangeType type) const { return nbBitsToNbChars(nbBitsWord(type)); }
  BitValue mask(MemoryRangeType type) const { return uint(1 << nbBitsWord(type))-1; }
  BitValue userIdRecommendedMask() const { return _userIdRecommendedMask; }
  const Config &config() const { return *_config; }
  Architecture architecture() const { return _architecture; }
  bool is18Family() const { return ( _architecture==Architecture::P18C || _architecture==Architecture::P18F || _architecture==Architecture::P18J); }
  bool is16bitFamily() const { return ( _architecture.data().nbBitsRegister==16 ); }
  VoltageData voltage(ProgVoltageType type) const { return _voltages[type]; }
  virtual bool canWriteCalibration() const { return isWritable(MemoryRangeType::Cal); }
  bool checkCalibration(const Device::Array &data, TQString *message = 0) const;
  const TQMap<Device::Special, BitValue> ids() const { return _ids; }
  virtual bool matchId(BitValue rawId, Device::IdData &data) const;
  TQStringList idNames(const TQMap<TQString, Device::IdData> &ids) const;
  const TQMap<TQString, Checksum::Data> checksums() const { return _checksums; }
  const RegistersData &registersData() const;
  const CalibrationData &calibrationData() const { return _calibration; }

  bool hasFeature(Feature feature, bool *unknown = 0) const;
  BitValue nopInstruction() const { return 0x0; }
  Device::Array gotoInstruction(Address address, bool withPageSelection) const;
  bool isGotoInstruction(BitValue instruction) const;

private:
  Architecture _architecture;
  TQMap<Device::Special, BitValue> _ids;
  uint             _nbBitsPC;
  uint             _nbWordsCodeWrite;    // #### only for 18F/18J devices [0 for other devices]
  uint             _nbWordsCodeRowErase; // #### only for 18F/18J devices [0 for other devices or if not available]
  TQMap<ProgVoltageType, VoltageData>     _voltages;
  TQMap<MemoryRangeType, MemoryRangeData> _ranges;
  BitValue         _userIdRecommendedMask;
  Config          *_config;
  TQMap<TQString, Checksum::Data> _checksums;
  CalibrationData  _calibration;
  SelfWrite        _selfWrite;

  friend class XmlToData;
  friend class Group;
  friend TQDataStream &operator <<(TQDataStream &s, const Data &data);
  friend TQDataStream &operator >>(TQDataStream &s, Data &data);
};

TQDataStream &operator <<(TQDataStream &s, const Data &data);
TQDataStream &operator >>(TQDataStream &s, Data &data);

} // namespace

TQDataStream &operator <<(TQDataStream &s, const Pic::VoltageData &vd);
TQDataStream &operator >>(TQDataStream &s, Pic::VoltageData &vd);
TQDataStream &operator <<(TQDataStream &s, const Pic::MemoryRangeData &mrd);
TQDataStream &operator >>(TQDataStream &s, Pic::MemoryRangeData &mrd);
TQDataStream &operator <<(TQDataStream &s, const Pic::Checksum::Data &cd);
TQDataStream &operator >>(TQDataStream &s, Pic::Checksum::Data &cd);
TQDataStream &operator <<(TQDataStream &s, const Pic::CalibrationData &cd);
TQDataStream &operator >>(TQDataStream &s, Pic::CalibrationData &cd);

#endif
