//------------------------------------------------------------------------------
// ZCPU standard library and drivers set              (C) 2011 by Black Phoenix
//
// Universal device host driver. Only supports 8 devices right now
//------------------------------------------------------------------------------

#define UDH_DRIVER

//Maximum number of devices supported
#define MAX_UDH_DEVICES 8

//Address range of a single device
#define MAX_UDH_ADDRESS_RANGE 4*1024

//Maximum number of drivers that may register with UDH
#define MAX_UDH_DRIVERS 8

//Device name/string data
string udhDeviceString0,"None";
string udhDeviceString1,"Unknown";
string udhDeviceString2,"Extended bus";
string udhDeviceString3,"Address bus";
string udhDeviceString4,"Zyelios CPU";
string udhDeviceString5,"Zyelios GPU";
string udhDeviceString6,"Zyelios SPU";
string udhDeviceString7,"Flash EEPROM";
string udhDeviceString8,"ROM";
string udhDeviceString9,"Data bus";
string udhDeviceString10,"CD Ray";
string udhDeviceString11,"Console screen";
string udhDeviceString12,"Digital screen";
string udhDeviceString13,"Data plug";
string udhDeviceString14,"Data socket";
string udhDeviceString15,"Keyboard";
string udhDeviceString16,"Oscilloscope";
string udhDeviceString17,"Sound emitter";
string udhDeviceString18,"Constant value";
string udhDeviceString19,"Data port";
string udhDeviceString20,"RAM";
udhDeviceName:
  db udhDeviceString0, udhDeviceString1, udhDeviceString2;
  db udhDeviceString3, udhDeviceString4, udhDeviceString5;
  db udhDeviceString6, udhDeviceString7, udhDeviceString8;
  db udhDeviceString9, udhDeviceString10,udhDeviceString11;
  db udhDeviceString12,udhDeviceString13,udhDeviceString14;
  db udhDeviceString15,udhDeviceString16,udhDeviceString17;
  db udhDeviceString18,udhDeviceString19,udhDeviceString20;

//Extended bus offset
char* udhBusOffset;

//List of callbacks to call when querying devices
void* udhQueryCallback[MAX_UDH_DRIVERS];
float udhQueryCallbackCount = 0;

float udhSetBusAddress(char* extOffset) {
  udhBusOffset = extOffset;
  udhQueryDevices();
}

void udhQueryDevices() {
  float i;

  //Run the query
  udhBusOffset[16] = 32+MAX_UDH_DEVICES;
  udhBusOffset[17] = 1;

  //Reconfigure all devices
  //FIXME: only supports single extended bus right now
  for (i = 0; i < 8; i++) {
    udhBusOffset[i*2+0] = (4*1024)*i;
    udhBusOffset[i*2+1] = (4*1024)*i+((4*1024)-1);
  }

  //Update all drivers
  for (i = 0; i < udhQueryCallbackCount; i++) {
    void* functionPtr = udhQueryCallback[i];
    functionPtr();
  }
}

void udhRegisterDriver(void* queryDeviceFunction) {
  udhQueryCallback[udhQueryCallbackCount] = queryDeviceFunction;
  if (udhQueryCallbackCount < MAX_UDH_DRIVERS) udhQueryCallbackCount++;
}

float udhGetDeviceType(float busIndex) {
  return udhBusOffset[32+busIndex];
}

float udhGetDeviceOffset(float busIndex) {
  return 65536+32+MAX_UDH_DEVICES+udhBusOffset[busIndex*2];
}

char* udhGetDeviceName(float busIndex) {
  float deviceType = udhGetDeviceType(busIndex);
  if ((deviceType >= 0) && (deviceType <= 20)) {
    return udhDeviceName[deviceType];
  } else {
    return udhDeviceName[1];
  }
}

void udhSetDeviceOffsetSize(float busIndex, char* offst, char* size) {
  udhBusOffset[busIndex*2+0] = offst;
  udhBusOffset[busIndex*2+1] = offst+size-1;
}

float udhGetNumDevices() {
  return MAX_UDH_DEVICES;
}

float udhGetDevices(float type, float maxCount, char* deviceList) {
  float i,devPtr,n;

  devPtr = deviceList;
  n = 0;
  for (i = 0; i < MAX_UDH_DEVICES; i++) {
    if ((udhGetDeviceType(i) == type) && (n < maxCount)) {
      n++;
      *devPtr++ = i;
    }
  }

  return n;
}
