/*
    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);
}

////////////////////////////////////////////
// 1 Zeichen Hex -> Int konvertieren
// Eingabe: "C" = 0x43
// Ausgabe: 0x0C
static uint8_t xtoc (uint8_t ch)
{
    uint8_t val;

    // Grossbuchstaben
    if (ch >= 'A' && ch <= 'F')
        val = (ch - 'A') + 10;
    //Kleinbuchstaben
    else if (ch >= 'a' && ch <= 'f')
        val = (ch - 'a') + 10;
    else
        val = (ch - '0');

    return val;
}

__at (ROM_START) unsigned char mem[0xffff];         // Kompletter Speicher

// Global, da viel kürzerer Code!
struct ihx_data {
       uint8_t len;
       uint16_t datalength;
       uint16_t recordsets;
       uint16_t adress;
       uint8_t record;
       uint8_t csum;
} ihx;
 
uint8_t p[4];

char ihx_decode()
{
    #define DATA_RECORD     0x00
    #define END_RECORD      0x01

   uint8_t ch,i,lo,hi,k,data;
   uint8_t check,cnt,cnt2;
   
   // Nullen.... 
   k = 0;
   cnt = 0;
   cnt2 = 0;
   ihx.datalength = 0;
   ihx.recordsets = 0;
   
   do {
        // warte auf Startzeichen
        do ch = getchar();
        while (ch != ':');
        if (++cnt2 > 2) {
            cnt2 = 0;
            if (++cnt < 54)
                addstr(".");
            else  {
                addstr("\r");
                cnt = 0;
            }    
        }        

        ihx.csum = 0;

        // Hole Anzahl Zeichen des Satzes
        hi = xtoc(getchar());
        lo = xtoc(getchar());
        ihx.len = (hi <<4 )+lo;
        ihx.csum += ihx.len;

        // Hole Zieladresse des Satzes
        for (i=0;i<4;i++)
            p[3-i] = xtoc(getchar());
        
        // Setze Adresse zusammen
        ihx.adress = (p[3]<<12) | (p[2]<<8) | (p[1]<<4) | p[0];
        ihx.csum += (p[1]<<4) | p[0];
        ihx.csum += (p[3]<<4) | p[2];
        
        // Hole Record Type
        hi = xtoc(getchar());
        lo = xtoc(getchar());
        ihx.record = (hi<<4)+lo;
        ihx.csum += ihx.record;
        ihx.recordsets++;

        // Record 0 = Daten
        if (ihx.record == DATA_RECORD)  {
            // Hole Datenbytes ab
            for (i=0;i<ihx.len;i++)
            {
                hi = xtoc(getchar());
                lo = xtoc(getchar());
                data = (hi <<4 )+lo;
                mem[ihx.adress+i] = data;
                ihx.csum += data;
                SetLedByte((hi<<4)+lo);
            }
            ihx.datalength += ihx.len;
            ihx.csum = (~ihx.csum) +1;   //Prüfsumme bilden

            // Prüfsumme holen
            hi = xtoc(getchar());
            lo = xtoc(getchar());
            check = (hi<<4)+lo;

            // Prüfsumme überprüfen
            if (check != ihx.csum)
                return (0);

            SetDigit(k++);
        }

    } while (ihx.record != END_RECORD);

    //xprintf("\rDatabytes        : %u",ihx.datalength);
    //xprintf("\rRecord Sets      : %u",ihx.recordsets);
    // Dateiende abwarten
    do
        ch = getchar();
    while (ch!=0x0a);

    return (1);

}

/////////////////////////////////////////////
// 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


