#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
#include <hot.h>
#include <kria.h>

void *read_kria(void *prt){
ReadParams_t  *ReadParams = (ReadParams_t *) prt;
uint64_t volatile *baseaddress = ReadParams->baseaddress;
uint64_t volatile *statusbase = ReadParams->statusbase;
char *data_out = ReadParams->data_out;
uint64_t *data = (uint64_t *)data_out;
uint64_t words_read = 0, words_to_read = 0;
uint64_t status = 0; 

uint64_t *write_done = ReadParams->write_done;
// Wait until there is something to read
while (words_to_read == 0){
words_to_read = ((statusbase[0]>>32) & ((uint64_t)0xffff));
}

//printf("Read: status = 0x%16.16lx\n",statusbase[0]);
while (((statusbase[0]>>32) & (uint64_t)0xffff) != 0 || ((statusbase[0]>>16)&(uint64_t)0xffff) != 0 || *write_done == 0) {
words_to_read = (statusbase[0]>>32) & (uint64_t)0xffff;
//printf("Read: 2: words_to_read %ld words_read %ld\n",words_to_read,words_read);
    for(int i = 0; i < words_to_read;i++){
        data[i+ words_read] = baseaddress[0];
    }   
    words_read += words_to_read; 
}
// flush the fifo and make a mask for the last word
uint64_t flush_char = ReadParams->flush_char;
uint64_t leftover= ((statusbase[0]>>48)&(uint64_t)0xffff);
printf("leftover = %lx\n",leftover);
uint64_t mask = -1;
 //if (((statusbase[0]>>48)&(uint64_t)0xffff) != 0) {
 if ( leftover != 0) {
    leftover = ((statusbase[0]>>48)&(uint64_t)0xffff);
    for (int i = 0; i < 8-leftover;i++) { 
    baseaddress[0] = flush_char; 
    mask = mask << 8;
    }    
}
// wait until last word shows up
 //if (((statusbase[0]>>48)&(uint64_t)0xffff)%8 != 0) 
 if (((statusbase[0]>>48)&(uint64_t)0xffff) != 0) 
while (((statusbase[0]>>32)&(uint64_t)0xffff) == 0)printf("words left %lx\n",(statusbase[0]>>32)&(uint64_t)0xffff);
//apply the mask and read in the last word
//printf("mask = 0x%lx leftover = 0x%lx\n",mask,leftover);
printf("mask = 0x%lx leftover = 0x%lx data 0x%lx\n",mask,leftover,data[words_read]);
 if (((statusbase[0]>>48)&(uint64_t)0xffff) != 0) 
data[words_read++] = baseaddress[0]&mask;
printf("mask = 0x%lx leftover = 0x%lx data 0x%16.16lx\n",mask,leftover,data[words_read-1]);
ReadParams->words_read = words_read;
return((void *)NULL);
};

void *write_kria(void *prt){
WriteParams_t *WriteParams = (WriteParams_t *) prt;
uint64_t volatile *baseaddress = WriteParams->baseaddress;
uint64_t volatile *statusbase = WriteParams->statusbase;
char *data_in = WriteParams->data_in;
uint64_t *write_done = WriteParams->write_done;
uint64_t *data = (uint64_t *) data_in;
uint64_t DataTransfered = 0, status = 0, size_in_words = 0;
uint64_t fifo_size = WriteParams->fifo_size;
uint64_t size_in_bytes = 0;
uint64_t WordsInFIFO = 0, TransferSize = 0;
*write_done = 0;
size_in_bytes = WriteParams->size_in_bytes;
    if(size_in_bytes%8 == 0) size_in_words = size_in_bytes/8;
    else size_in_words = (size_in_bytes/8)+1;
     //printf("size_in_bytes  %ld\n",size_in_bytes); 
     //printf("size_in_bytes/8  %ld\n",size_in_bytes/8); 
     //printf("size_in_bytes mod 8 %ld\n",size_in_bytes%8); 
     //printf("size_in_words %ld \n", size_in_words);
     //size_in_words = size_in_bytes/8 +0;
     // FIFO is empty put in 1/2 a FIFO
    if (size_in_words < fifo_size) {
       TransferSize = size_in_words;
    }
    else TransferSize = fifo_size/2;
    for (int i = 0;i<TransferSize;i++) {
	   baseaddress[0] = data[i+DataTransfered];
    }
    DataTransfered = TransferSize;
    while(DataTransfered < size_in_words){
        if (size_in_words - DataTransfered > fifo_size/2)
            TransferSize = fifo_size/2;
        else TransferSize = (size_in_words - DataTransfered);
	// Wait for the read FIFO to empty some, as there is no backpussure in hardware
        while (((statusbase[0]>>16) & (uint64_t)0xffff) > fifo_size/8);

        for (int i = 0;i<TransferSize;i++) {
        	   baseaddress[0] = data[i+DataTransfered];
        }
        WordsInFIFO = (statusbase[0]>>16)&(uint64_t)0xffff;
        while (WordsInFIFO > fifo_size/4) { 
            WordsInFIFO = (statusbase[0]>>16)&(uint64_t)0xffff;
        }
    DataTransfered = DataTransfered + TransferSize;
}
*write_done = 1;
return((void *)NULL);
};
