/*
    tools.c
    Nützliche Routinen, die oft benötigt werden.
*/
#include <asm/z80/features.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <ctype.h>
#include "mcurses.h"
#include "tools.h"
#include "driver.h"
#include "xprintf.h"
#include "main.h"

////////////////////////////////////////////
// Statuszeile unten ausgeben
void statusline(char* zeile)
{
    char xpos,ypos;

    getyx(ypos,xpos);           // Alte Pos speichern
    move(23,0);                 // Statuszeile
    deleteln();
    attrset(A_UNDERLINE);
    addstr("Z80 > ");
    addstr(zeile);
    attrset(A_NORMAL);
    move(ypos,xpos);
}

//////////////////////////////////////////////
//       Intel Hex Decodierung
//////////////////////////////////////////////

__at (ROM_START) unsigned char mem[0xffff];         // Kompletter Speicher

uint8_t csum;

// Hole 1 Zeichen und wandle es in char
static uint8_t gethex_digit(void) 
{
  uint8_t c;

  c = toupper(getchar());
  c -= '0';
  if (c > 9)
    c -= ('A' - '0' - 10);
    
  return c;
}

// Hole 2 stelligen HEX Wert
static uint8_t gethex()
{
  uint8_t val = (gethex_digit() << 4) + gethex_digit();
  csum += val;

  return val;
}

char ihx_decode()
{
    #define DATA_RECORD     0x00
    #define END_RECORD      0x01

   uint8_t len,record;
   uint16_t adress;
    
   uint8_t ch,i;
   uint8_t k    = 0;
   uint8_t cnt  = 0;
   uint8_t cnt2 = 0;

   do {
        // warte auf Startzeichen
        do ch = getchar();
        while (ch != ':');

        csum = 0;
        len = gethex();                          // Hole Anzahl Zeichen des Satzes
        adress = (gethex() << 8) + gethex();     // Hole Zieladresse des Satzes
        // Hole Record Type
        record = gethex();
        
        // Record 0 = Daten
        if (record == DATA_RECORD)  {
            // Hole Datenbytes ab
            for (i=0;i<len;i++) {
                mem[adress+i] = gethex();
                SetLedByte(mem[adress+i]);
            }

            gethex();        // Prüfsumme überprüfen
            if (csum != 0)  
                return (0);

                SetDigit(k++);
        }
    } while (record != END_RECORD);

    // Dateiende abwarten
    do
        ch = getchar();
    while (ch!=0x0a);

    return (1);

    #undef DATA_RECORD
    #undef END_RECORD
}

/////////////////////////////////////////////
// Zufallszahlengenerator

#ifdef USE_SIMPLE_RANDOM

static uint16_t seed=10000;

void sprng(uint16_t start)
{
    seed = start;
}

uint16_t prng(uint16_t max)
{
    uint16_t result;

    seed ^= seed<<7;
    seed ^= seed>>9;
    seed ^= seed<<5;
    seed ^= seed>>3;
    result = seed % max;

    return (result);
}

#endif

// Mersenne - Twister Algorithmus

#ifdef USE_MERSENNE_TWISTER

uint32_t TT800(uint16_t range) {
#define N  25
#define M   7
   static const uint32_t A[2] = { 0, 0x8ebfd028 };
   static uint32_t y[N];
   static int index = N+1;
   uint32_t  e;

   if (index >= N) {
     int k;
     if (index > N) {
        unsigned r = 9, s = 3402;
        for (k=0; k<N; ++k) {
          r = 509845221 * r + 3;
          s *= s + 1;
          y[k] = s + (r >> 10);
        }
     }
     for (k=0; k<N-M; ++k)
        y[k] = y[k+M] ^ (y[k] >> 1) ^ A[y[k] & 1];
     for (; k<N; ++k)
        y[k] = y[k+(M-N)] ^ (y[k] >> 1) ^ A[y[k] & 1];
     index = 0;
   }

   e = y[index++];

   e ^= (e <<  7) & 0x2b5b2500;
   e ^= (e << 15) & 0xdb8b0000;
   e ^= (e >> 16);
   return (e % range);
#undef N
#undef M
}

#endif


