/*********************************************************************
 *      compiler.h - some defines for dsp registers
 *      Copyright (C) 2000 Rui Sousa 
 ********************************************************************* 
 *     This program is free software; you can redistribute it and/or 
 *     modify it under the terms of the GNU General Public License as 
 *     published by the Free Software Foundation; either version 2 of 
 *     the License, or (at your option) any later version. 
 * 
 *     This program is distributed in the hope that it will be useful, 
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of 
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 *     GNU General Public License for more details. 
 * 
 *     You should have received a copy of the GNU General Public 
 *     License along with this program; if not, write to the Free 
 *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 
 *     USA. 
 ********************************************************************* 
*/

#ifndef _COMPILER_H
#define _COMPILER_H

#include <string.h>
#include <stdio.h>
#include <linux/types.h>

#include "list.h"

#define DEBUG

#define DSP_CODE_SIZE 0x400

__u32 __dsp_code[DSP_CODE_SIZE];

#define PATCH_NAME_SIZE 32

char __patch_name[PATCH_NAME_SIZE];

void warning(const char *message);

#define PATCH_NAME(a) do { \
	__file = __FILE__; \
	__line = __LINE__; \
	if (strlen(a) >= PATCH_NAME_SIZE) \
		warning("patch name too long\n"); \
	strncpy(__patch_name, (a), PATCH_NAME_SIZE); \
	__patch_name[PATCH_NAME_SIZE - 1] = '\0'; \
} while (0)

/* dsp registers types */

#define GPR 0x100
#define TRAML_DATA 0x200
#define TRAML_ADDRESS 0x400
#define CONSTANT 0x800
#define INPUT 0x1000
#define OUTPUT 0x2000

/* gprs */

#define GPR_BASE 0x100
#define GPR_TOTAL 0x100

#define GPR_TYPE_IO 0x01
#define GPR_TYPE_STATIC 0x02
#define GPR_TYPE_DYNAMIC 0x04
#define GPR_TYPE_CONTROL 0x08

#define GPR_NAME_SIZE	32

struct dsp_reg {
	struct list_head list;
	__u16 type;
	__s32 value;
	__s32 max;
	__s32 min;
	__u16 address;
	char name[GPR_NAME_SIZE];
};

struct dsp_gpr_io {
	struct list_head list;
	struct dsp_reg in, out;
};

typedef struct dsp_reg *gpr;
typedef struct dsp_gpr_io *gpr_io;

#define INIT_GPR(gpr, type) \
		(__file = __FILE__, __line = __LINE__, init_gpr(&(gpr), (type)))

#define INIT_GPR_STATIC(gpr) INIT_GPR((gpr), GPR_TYPE_STATIC)
#define INIT_GPR_DYNAMIC(gpr) INIT_GPR((gpr), GPR_TYPE_DYNAMIC)
#define INIT_GPR_IO(gpr) \
		(__file = __FILE__, __line = __LINE__, init_gpr_io(&(gpr)))
#define INIT_GPR_CONTROL(gpr) INIT_GPR((gpr), GPR_TYPE_CONTROL)

#define GPR_VALUE(gpr, value) \
		(__file = __FILE__, __line = __LINE__, set_gpr_value((gpr), (value)))

#define GPR_RANGE(gpr, min, max) \
                (__file = __FILE__, __line = __LINE__, set_gpr_range((gpr), (min), (max)))

#define GPR_NAME(gpr, name) \
		(__file = __FILE__, __line = __LINE__, set_gpr_name((gpr), (name)))

#define IN(gpr)	(&(gpr)->in) 
#define OUT(gpr) (&(gpr)->out)

struct list_head __gpr_static_list;
struct list_head __gpr_dynamic_list;
struct list_head __gpr_control_list;
struct list_head __gpr_io_list;

__u8 __gpr_total_count;
__u8 __gpr_static_count;
__u8 __gpr_dynamic_count;
__u8 __gpr_io_count;
__u8 __gpr_control_count;

/* tram lines */

#define TRAML_DATA_BASE 0x200
#define TRAML_ADDR_BASE 0x300
#define TRAML_TOTAL 0xa0

#define TRAML_TYPE_READ 0x01
#define TRAML_TYPE_WRITE 0x02

struct tram_line {
	struct list_head list;
	struct dsp_reg data;
	struct dsp_reg address;
	struct tram_block *block;
	__u32 type;
};

typedef struct tram_line *tram_line;

#define INIT_TRAML(line, type, block) \
		(__file = __FILE__, __line = __LINE__, init_tram_line(&(line), (type), (block)))

#define INIT_TRAML_READ(line, block)	INIT_TRAML((line), TRAML_TYPE_READ, (block))
#define INIT_TRAML_WRITE(line, block)	INIT_TRAML((line), TRAML_TYPE_WRITE, (block))

#define TRAML_ADDR(line, value) \
		(__file = __FILE__, __line = __LINE__, set_tram_line_address_value((line), (value)))

#define ADDR(line) \
		(__file = __FILE__, __line = __LINE__, tram_line_address((line)))

#define DATA(line) \
		(__file = __FILE__, __line = __LINE__, tram_line_data((line)))

__u8 __traml_total_count;

/* tram blocks */

#define TRAMB_MAX_SIZE 0x100000
#define TRAMB_MIN_SIZE 0x00002

#define TRAMB_TYPE_DELAYLINE 0x01
#define TRAMB_TYPE_LOOKUPTABLE 0x02

struct tram_block {
	struct list_head list;
	struct list_head line_read_list;
	struct list_head line_write_list;
	__u8 line_read_count;
	__u8 line_write_count;
	__u32 type;
	__u32 size;
};

typedef struct tram_block *tram_block;

#define INIT_TRAMB(block, type, size) \
		(__file = __FILE__, __line = __LINE__, init_tram_block(&(block), (type), (size)))

#define INIT_TRAMB_DELAYLINE(block, size) \
		INIT_TRAMB((block), TRAMB_TYPE_DELAYLINE, (size))

#define INIT_TRAMB_TABLELOOKUP(block, size) \
		INIT_TRAMB((block), TRAMB_TYPE_LOOKUPTABLE, (size))

struct list_head __tramb_delayline_list;
struct list_head __tramb_tablelookup_list;

__u16 __tramb_delayline_count;
__u16 __tramb_tablelookup_count;

/* constants */

#define CONSTANTS_BASE 0x40
#define CONSTANTS_TOTAL 0x60

struct dsp_reg *__constant[CONSTANTS_TOTAL];

#define CONST(x) (__file = __FILE__, __line = __LINE__, cnt((x)))

/* hexadecimal constants symbols */

#define C_0x0     CONST(0x00)
#define C_0x1     CONST(0x01)
#define C_0x2     CONST(0x02)
#define C_0x3     CONST(0x03)
#define C_0x4     CONST(0x04)
#define C_0x8     CONST(0x05)
#define C_0x10    CONST(0x06)
#define C_0x20    CONST(0x07)
#define C_0x100   CONST(0x08)
#define C_0x100000	CONST(0x09)
#define C_0x800000	CONST(0x0a)
#define C_0x10000000	CONST(0x0b)
#define C_0x20000000	CONST(0x0c)
#define C_0x40000000	CONST(0x0d)
#define C_0x80000000	CONST(0x0e)
#define C_0x7fffffff	CONST(0x0f)
#define C_0xffffffff	CONST(0x10)
#define C_0xfffffffe	CONST(0x11)
#define C_0xc0000000	CONST(0x12)

/* decimal constants symbols */

#define C_0	C_0x0
#define C_1	C_0x1
#define C_2	C_0x2
#define C_3	C_0x3
#define C_4	C_0x4
#define C_8	C_0x8
#define C_16	C_0x10
#define C_32	C_0x20
#define C_256	C_0x100

#define ACCUM	CONST(0x16)
#define CCR	CONST(0x17)
#define NOISE1	CONST(0x18)
#define NOISE2	CONST(0x19)
#define IRQREG  CONST(0x20)
/* inputs */

#define INPUTS_BASE 0x00
#define INPUTS_TOTAL 0x20

struct dsp_reg *__input[INPUTS_TOTAL];

//#define IN(x) (__file = __FILE__, __line = __LINE__, input((x)))

/* outputs */

#define OUTPUTS_BASE 0x20
#define OUTPUTS_TOTAL 0x20

struct dsp_reg *__output[OUTPUTS_TOTAL];

//#define OUT(x) (__file = __FILE__, __line = __LINE__, output((x)))

int __ip, __line, __arg;
char *__file;

/* nicer names */

#define OP(op, z, w, x, y) \
	(__file = __FILE__, __line = __LINE__, \
	operation((op), (__arg = 1, (z)), (__arg = 2, (w)), (__arg = 3, (x)), (__arg = 4, (y))))

/* dsp instructions */

#define macs(z, w, x, y) OP(0x0, (z), (w), (x), (y))
#define macs1(z, w, x, y) OP(0x1, (z), (w), (x), (y))
#define macw(z, w, x, y) OP(0x2, (z), (w), (x), (y))
#define macw1(z, w, x, y) OP(0x3, (z), (w), (x), (y))

#define macints(z, w, x, y) OP(0x4, (z), (w), (x), (y))
#define macintw(z, w, x, y) OP(0x5, (z), (w), (x), (y))

#define acc3(z, w, x, y) OP(0x6, (z), (w), (x), (y))
#define macmv(z, w, x, y) OP(0x7, (z), (w), (x), (y))
#define andxor(z, w, x, y) OP(0x8, (z), (w), (x), (y))
#define tstneg(z, w, x, y) OP(0x9, (z), (w), (x), (y))
#define limit(z, w, x, y) OP(0xa, (z), (w), (x), (y))
#define limit1(z, w, x, y) OP(0xb, (z), (w), (x), (y))
#define log(z, w, x, y) OP(0xc, (z), (w), (x), (y))
#define exp(z, w, x, y) OP(0xd, (z), (w), (x), (y))
#define interp(z, w, x, y) OP(0xe, (z), (w), (x), (y))
#define skip(z, w, x, y) OP(0xf, (z), (w), (x), (y))

#define and(z, x , y)	andxor((z), (x), (y), C_0x0)
#define xor(z, x, y)	andxor((z), C_0xffffffff, (x), (y))
#define not(z, x)	andxor((z), (x), C_0xffffffff, C_0xffffffff)
#define nand(z, x, y)	andxor((z), (x), (y), C_0xffffffff)
#define abs(z, x)	tstneg((z), (x), (x), C_0x0)
#define neg(z, x)	macs1((z), C_0x0, (x), C_0x7fffffff)

#define stoccr(z)      skip((z), CCR, C_0x0, C_0x0)

#define bra(n) skip(C_0x0, C_0x7fffffff, C_0x7fffffff, (n))
#define beq(n) skip(CCR, CCR, C_0x8, (n))
#define bne(n) skip(CCR, CCR, C_0x100, (n))
#define blt(n) skip(CCR, CCR, C_0x4, (n))

/* auxiliary functions */

void init_gpr(struct dsp_reg **, __u32);
void init_gpr_io(struct dsp_gpr_io **);
void init_tram_block(struct tram_block **, __u32, __u32);
void init_tram_line(struct tram_line **, __u32, struct tram_block *);
struct dsp_reg *tram_line_data(struct tram_line *);
struct dsp_reg *tram_line_address(struct tram_line *);
void set_gpr_value(struct dsp_reg *, __s32);
void set_gpr_range(struct dsp_reg *, __s32, __s32);
void set_gpr_name(struct dsp_reg *, const char *);
void set_tram_line_address_value(struct tram_line *, __u32);
void set_tram_line_data_value(struct tram_line *, __u32);
struct dsp_reg *cnt(int);
struct dsp_reg *input(int);
struct dsp_reg *output(int);
void operation(int op, struct dsp_reg *z, struct dsp_reg *w, struct dsp_reg *x,
	       struct dsp_reg *y);

#endif
