/*
 * picasm -- config.c
 *
 * Copyright 1995-2004 Timo Rossi, <trossi@iki.fi>
 * See the file LICENSE for license terms.
 *
 * The code in this file handles configuration fuse
 * setting with the CONFIG-directive
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "picasm.h"
#include "token.h"
#include "symtab.h"

/*
 * parse the CONFIG directive
 * 
 * This basically repeatedly expands the __do_config macro with
 * the appropriate parameters.
 *
 */
void
parse_config(void)
{
    static char keyword[260];
    struct symbol *config_macro_sym;
    char *args[2];
    int npairs;
#define MAX_PAIRS 30
    char *keywords[MAX_PAIRS];
    char *values[MAX_PAIRS];
    int i;

    if(pic_instr_set == PIC_NONE)
	fatal_error("PIC device type not set");

    config_macro_sym = lookup_symbol("__do_config", SYMTAB_GLOBAL);
    if(config_macro_sym == NULL || config_macro_sym->type != SYM_MACRO)
    {
	error(1, "__do_config not defined, cannot set configuration bits");
	return;
    }

    npairs = 0;
    for(;;)
    {
	if(token_type != TOK_IDENTIFIER)
	{
cfg_error:
	    error(1, "CONFIG syntax error");
	    return;
	}
	strcpy(keyword, token_string);
	get_token();

	/* hmm... this is a little kludge, but as
	   the tokenizer now makes 'local id's from
	   the valid config strings, this must be used... */
	if(token_type != TOK_LOCAL_ID)
	{
	    if(token_type != TOK_EQUAL)
	    {
		error(1, "'=' expected");
		return;
	    }
	    get_token();
	    if(token_type != TOK_IDENTIFIER)
		goto cfg_error;
	}

	if(npairs >= MAX_PAIRS)
	{
	    error(0, "Too many config keyword=value pairs");
	    break;
	}

	keywords[npairs] = mem_alloc(strlen(keyword) + 1);
	strcpy(keywords[npairs], keyword);

	values[npairs] = mem_alloc(strlen(token_string) + 1);
	strcpy(values[npairs], token_string);

	npairs++;

	get_token();
	if(token_type != TOK_COMMA)
	    break;

	get_token();
    }

    skip_eol();
    write_listing_line(0);
    listing_on = 0;

    for(i = 0; i < npairs; i++)
    {
	args[0] = keywords[i];
	args[1] = values[i];

	expand_macro_with_args(config_macro_sym, args, 2, 1);

	mem_free(keywords[i]);
	mem_free(values[i]);
    }
}

void
config_done(void)
{
    struct symbol *config_sym;

    config_sym = lookup_symbol("__config", SYMTAB_GLOBAL);
    if(config_sym == NULL || config_sym->type != SYM_SET)
    {
	error(0, "Internal CONFIG error: __config not defined (or wrong type)");
	return;
    }

    config_fuses = config_sym->v.value;

/*
 * This causes the config fuses to be output on the "exitm" listing line.
 * Not very clean, but at least we get the config fuses in the listing.
 */
    list_flags = LIST_VAL;
    list_val = config_fuses;

    listing_on = 1;
}


syntax highlighted by Code2HTML, v. 0.9.1