// Copyright (c) Hotwright Inc. 2022 All Rights Reserved
// this is a simple program to create an artifical neuron 
// this neuron uses saturating arithmetic to avoid overflows  
// the input has 3 bus inouts to do y=ax+b
// at a higher level you feedback the output so y=ax+(last y)
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <stdarg.h>
#include <stddef.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h> 


void print_help() {
printf("\n-o <filename> output filename\n");
printf("-f            use saturating fixed point\n");
printf("-h            print this\n\n\n");
}


void main(int argc, char *argv[]) {

FILE *neuron_file;
char filename[100];
int opt = 0;
int bitsize = 0;
int fixed = 0;

char print_string[1000] = {0};
char print_string1[1000] = {0};
char print_string2[1000] = {0};

while((opt = getopt(argc, argv, "o:fh")) != -1) {

  switch (opt) {
   case 'h': { print_help();
               exit(0);
               break;
             }
   case 'f': {
             fixed = 1;
             break;
             }
   case 'o': {
             strcpy(filename,argv[optind-1]);
             break;
             }
   default: break;
} 


}

neuron_file = fopen(filename,"w");

if (neuron_file == NULL) {
   printf("can't open file %s\n",filename);
   exit(1);
}
if (fixed == 1 && BITSIZE%2 == 1) {
printf("fixed only works with even BITSIZE\n");
exit(0);
}

fprintf(neuron_file,"//This program must be compiled with hotstate -w %d \n\n", 3*BITSIZE);
fprintf(neuron_file,"#define bool _Bool\n\n");
for (int i = 0; i < BITSIZE;i++) {
fprintf(neuron_file,"bool in_a%d;\n",i);
}
for (int i = 0; i < BITSIZE;i++) {
fprintf(neuron_file,"bool in_b%d;\n",i);
}
for (int i = 0; i < BITSIZE;i++) {
fprintf(neuron_file,"bool in_c%d;\n",i);
}
for (int i = 0; i < BITSIZE;i++) {
fprintf(neuron_file,"bool out%d = 0;\n",i);
}

fprintf(neuron_file,"\n");
fprintf(neuron_file,"char compdata;\n\n");
fprintf(neuron_file,"void\nmain() {\n");
fprintf(neuron_file,"\twhile(1) {\n");
fprintf(neuron_file,"\n");
fprintf(neuron_file,"\tswitch (compdata) { \n");
int a = 0, b = 0, c = 0, d = 0;

int state[100] = {0};

int result = 0; 
int casenum = 0;

struct {
int x:BITSIZE;
int y:BITSIZE;
int z:BITSIZE;
int output:BITSIZE;
} inputs;

int range = (int) (pow(2,BITSIZE)/2);

int mask = 1;
for (int i = 0; i< BITSIZE; i++){
    mask |= 1<< i;
}


for (int i = -range; i < range; i++) {
for (int j = -range; j < range; j++) {
for (int k = -range; k < range; k++) {

inputs.x = i;
inputs.y = j;
inputs.z = k;

inputs.output = inputs.x*inputs.y+inputs.z;
// This could be any function
result = i*j+k;
if (fixed == 1) result = result >> BITSIZE/2;
if (result < -range) inputs.output = -range;
if (result > range-1) inputs.output = range-1;
//z = x * y + z 
casenum = ( (inputs.z&mask) | ( (inputs.y&mask) << BITSIZE) | ( (inputs.x&mask) << BITSIZE*2)) ;
strcpy(print_string,"");
strcpy(print_string1,"");
strcpy(print_string2,"");


for (int i = 0; i< BITSIZE; i++){
     state[i] = (inputs.output&(1<<i))>>i;
}

sprintf(print_string,"\tcase 0x%c%d%c%d%c : {",'%',BITSIZE,'.',BITSIZE,'x');
for (int i = 0; i < BITSIZE; i++) {
sprintf(print_string2,"out%d = %d ", i , state[i]);
if(i<BITSIZE-1) strcat(print_string2,",");
else strcat(print_string2,"; continue;}\n");
strcat(print_string1,print_string2);
}
strcat(print_string,print_string1);
fprintf(neuron_file,print_string,casenum);

}

}




}
fprintf(neuron_file,"}\n");
fprintf(neuron_file,"}\n");
fprintf(neuron_file,"}\n");
fprintf(neuron_file,"\n");

}
