#ifndef RISCOS_H
#define RISCOS_H

#include <stdio.h>
extern "C" {
#include "qemu.h"
}

#include <vector>
#include <string>
#include "armswis.h"
#include "memc.h"

typedef uint32_t target_addr_t;
extern MEMC *memc;
extern bool filetype_handling;

using namespace std;

extern time_t cvt_riscos_time (unsigned int high, unsigned int low);
extern void cvt_unix_time (time_t unix_time, unsigned int *high, unsigned int *low);

// The Module class is for RISC OS modules that we simulate in C++
class Module
{
public:
  // Required to be public because SWIs may need to use it when
  // calling ARM code.
  CPUARMState *arm;

  struct riscos_object_detail
  {
    int object_type;
    int load_address;
    int execution_address;
    int object_length;
    int object_attributes;
  };

  Module (void) { };
  virtual ~Module () {};
  virtual unsigned int SWIChunkBegin (void) = 0;
  virtual unsigned int SWIChunkEnd (void) = 0;
  virtual bool SWI (unsigned int swinum, bool xbit) = 0;

  void SetState (CPUARMState *env) { arm = env; }
  void BuildError (uint32_t error_number, const char *text);

  // Utility functions
  mode_t get_protection (int attribute);
  int set_protection (mode_t mode);
  struct riscos_object_detail *get_riscos_file_details (const char *name);
  int Module::GetNameFromFd (int fd, unsigned char *buffer, int bufsiz);

  inline void MEM_READ (unsigned char *buf, target_addr_t addr, int size)
    {
      for (int i = 0; i < size; i++)
        buf[i] = ldub ((void *) (addr + i));
    }

  inline void MEM_WRITE (target_addr_t addr,
                         const unsigned char *buf, int size)
    {
      for (int i = 0; i < size; i++)
	stb ((void *) (addr + i), buf[i]);
    }

  inline void MEM_WRITE (target_addr_t addr,
                         const unsigned int *buf, int size)
    {
      MEM_WRITE (addr, (const unsigned char *) buf, size);
    }

  inline unsigned int MEM_READ_WORD (const target_addr_t addr)
    {
      return ldl ((void *) addr);
    }

  inline void MEM_WRITE_WORD (target_addr_t addr, unsigned int val)
    {
      stl ((void *) addr, val);
    }
  inline unsigned char MEM_READ_BYTE (const target_addr_t addr)
    {
      return ldub ((void *) addr);
    }

  inline void MEM_WRITE_BYTE (target_addr_t addr, unsigned char val)
    {
      ((char *) addr)[0] = val;
      //stb ((void *) addr, val);
    }

  inline void SET_V (void) { arm->cpsr |= 1<<28; }
  inline void CLEAR_V (void) { arm->cpsr &= ~1<<28; }
  inline void SET_C (void) { arm->cpsr |= 1<<29; }
  inline void CLEAR_C (void) { arm->cpsr &= ~1<<29; }
  inline void SET_N (void) { arm->cpsr |= 1<<31; }
  inline void CLEAR_N (void) { arm->cpsr &= ~1<<31; }
  inline void SET_Z (void) { arm->cpsr |= 1<<30; }
  inline void CLEAR_Z (void) { arm->cpsr &= ~1<<30; }

  inline void WRITE_REG (int regno, uint32_t val)
    {
      arm->regs[regno] = val;
    }

  inline uint32_t READ_REG (int regno)
    {
      return arm->regs[regno];
    }
};


// This class is for handling native RISC OS modules.  Native modules
// are held mainly in the MEMC native heap.  We keep a seperate record
// of the module header for fast SWI lookups.
struct native_module  // PRM1-205
{
  // Any unused values will be initialised to zero
  uint32_t start_code;
  uint32_t init_code;
  uint32_t fini_code;
  uint32_t service_call_handler;
  uint32_t title_string;
  uint32_t help_string;
  uint32_t command_table;
  uint32_t swi_chunk_base;
  uint32_t swi_handler_code;
  uint32_t swi_decode_table;
  uint32_t swi_decode_code;
  uint32_t messagetrans_file;
  uint32_t flags_word;

  uint32_t *private_word; // Pointer to the allocated private word
  void *base; // Pointer to the base address of the Module
};

typedef vector<Module *> modules_t;
typedef vector<Module *>::iterator modules_t_iter;
typedef vector<struct native_module> nmodule_t;
typedef vector<struct native_module>::iterator nmodule_t_iter;

class RISCOS
{
 private:
  modules_t modlist;
  nmodule_t native_modlist;

  void LoadModule (CPUARMState *env, const char *module_name);

 public:

  RISCOS ();
  ~RISCOS ();

  typedef struct
  {
    const char *name; // Module name
    int major_ver, minor_ver; // Major and minor version of module
    unsigned int swi_chunk_low, swi_chunk_high; // SWI chunk range implemented
  } module_t;

  vector<module_t> list;

  void Exec (CPUARMState *env, int argc, char *argv[],
	     const char *stdin_name, const char *stdout_name,
	     const char *stderr_name);

  void RegisterModule (const struct native_module &m);
  void InitModule (uint32_t *ptr, uint32_t length);
  bool ModuleCall (CPUARMState *env,
		   uint32_t *base_address, uint32_t offset);
  void LoadModules (CPUARMState *env);

  bool SWI (unsigned int swinum);
  bool SWI (CPUARMState *env, unsigned int swinum);
};

extern RISCOS *riscos;

#endif
