//***************************************************************************
// File name : startup.c
// Designer : Chih-Chieh Tsao
// Create date: Sep. 30, 2007
// Description:
//
//
//***************************************************************************

#include <math.h>
#include "locator.h"
#include "startup.h"

#define base_reg "R1"
#define data_reg "R5"


//#define DEBUG
#define DEBUG_A

/*******************************************************************
* Name: startup
* Input: 
*        char *file_name : input file name
* Output: int
* Description: 
*        determine where the task would be placed 
*        in five preallocated task area statically.
*        For static locator, determined by user. (this function)
*        For dynamic locator, determined by OS.
*******************************************************************/
int startup(char *file_name)
{
    FILE *fp, *outfp;
    char *output_file_name, *data4;
    char getStringLine[STRING_LINE];
    int i=0, length=0;
    gVars *tmp_bss=bss, *tmp_data=all_data;

    // open read file and error check
    fp = fopen(file_name, "r");
    if(fp == NULL)
    {
	fprintf(stderr, "input file error\n");
	return -1;
    }
    
    file_name = strtok(file_name, ".");

    // open write file and error check
    output_file_name = strcat(file_name, ".asm");   //output file with Startup code (.s)
    outfp = fopen(output_file_name, "w");
    if(outfp == NULL)
    {
 	fprintf(stderr, "output file error\n");
	return -1;
    }      

    //include 
    fprintf(outfp, "\n#include \"intr.h\"\n");
    fprintf(outfp, "#include \"defines.h\"\n\n");

    //disable interrupt
    fprintf(outfp, "//disable interrupt\n");
    fprintf(outfp, "P0 WriteSFR.and sfr_intrctrl, 0xFE\n\n");

    //set the initial values for data
    fprintf(outfp, "\n//set the initial values(data)\n");
    while(tmp_data != NULL)
    {        
        //assign task data start address
        fprintf(outfp, "\n  lea %s, %#x\n", base_reg, taskD_addr+tmp_data->start);

        for(i=0; i<eval_num_vars(tmp_data->start, tmp_data->end); i++)
        {
            data4 = tmp_data->variables[i];
            length = strlen(data4+2);

            if (i%2 == 0)
            {
                if(length < 4)
                {
                    fprintf(outfp, "P0 loadi.z.0 %s, 0x%s\n", data_reg, data4+2);
                    fprintf(outfp, "P0 store.8 %s, %s, %d\n", data_reg, base_reg, DataSize*i/2);
                    i++;
                    continue;
                }
                else
                {
                    fprintf(outfp, "P0 loadi.z.0 %s, 0x%s\n", data_reg, data4+2+length-4);
                    *(data4+2+length-4) = '\0';
                    fprintf(outfp, "P0 loadi.k.1 %s, 0x%s\n", data_reg, data4+2);
                    if(length != 8)
                    {
                        fprintf(outfp, "P0 store.8 %s, %s, %d\n", data_reg, base_reg, DataSize*i/2);
                        i++;
                        continue;
                    }
                }
            }
            else
            {
                if(length < 4)
                {
                    fprintf(outfp, "P0 loadi.k.2 %s, 0x%s\n", data_reg, data4+2);
                }
                else
                {
                    fprintf(outfp, "P0 loadi.k.2 %s, 0x%s\n", data_reg, data4+2+length-4);
                    *(data4+2+length-4) = '\0';
                    fprintf(outfp, "P0 loadi.k.3 %s, 0x%s\n", data_reg, data4+2);
                }

                fprintf(outfp, "P0 store.8 %s, %s, %d\n", data_reg, base_reg, DataSize*(i-1)/2);
            }
        }

        tmp_data = (gVars *)tmp_data->link;
    }


    //clear all variables to zero for bss
    fprintf(outfp, "\n//clear variables(bss) to zero\n");
    while(tmp_bss != NULL)
    {
        //assign task data start address
        fprintf(outfp, "\n  lea %s, %#x\n", base_reg, taskD_addr+tmp_bss->start);

        for(i=0; i<eval_num_vars(tmp_bss->start, tmp_bss->end); i++)
        {
            data4 = tmp_bss->variables[i];
            fprintf(outfp, "P0 loadi.z.0 %s, 0x%s\n", data_reg, data4+2);
            fprintf(outfp, "P0 store.8 %s, %s, %d\n", data_reg, base_reg, DataSize*i/2);
            i++;
            continue;
        }

        tmp_bss = (gVars *)tmp_bss->link;
    }




    //assign stack and frame pointer of task
    fprintf(outfp, "\n//assign stack and frame pointer\n");
    //fprintf(outfp, "  lea R29, %#x\n", taskS_addr);
    fprintf(outfp, "  lea R29, %#x\n", taskF_addr - DataSize);
    fprintf(outfp, "  lea R30, %#x\n", taskF_addr);

    //enable interrupt
    fprintf(outfp, "\n//enable interrupt\n");
    fprintf(outfp, "  ResetClock\n");
    fprintf(outfp, "  STI\n");
    fprintf(outfp, "  StartT0\n");

    //call main function and return
    fprintf(outfp, "\n//call main() function\n");
    /*fgets(getStringLine, STRING_LINE, fp);
    fprintf(outfp, "%s", getStringLine);*/
    fprintf(outfp, "P0 jmp main\n");
    fprintf(outfp, "P0 jmp.reg R31\n\n");

    fgets(getStringLine, STRING_LINE, fp);
    //attach task code
    while(fgets(getStringLine, STRING_LINE, fp) != NULL)
    {
        fprintf(outfp, "%s", getStringLine);
    }

    fprintf(stderr, "  Output file: %s\n", output_file_name);
    
    fclose(fp);
    fclose(outfp);
    
    return 0;
}

