#ifndef DIGIRULE2_H
#define	DIGIRULE2_H

#include <xc.h>

///////////////////////////////////////////////////////////////////////////////
// build options

#define FILE_ADDR		0x1000		// location in flash where files are stored
#define SAMPLE_PROGRAMS	1			// preload sample program files
#define STACK_DEPTH		4
#define LEGACY_ADDRPC	0			// provide original ADDRPC instruction behavior

///////////////////////////////////////////////////////////////////////////////
// general macros

#define RAM		ram.byte
#define ACCUM	accum.low_byte
#define ZERO	ram.status_reg.flags.zero
#define CARRY	ram.status_reg.flags.carry

#define ELEMENTSOF( a ) (sizeof( a ) / sizeof( (a)[0] ))

#define IS_REG_ADDR( addr )	((addr) >= StatusRegAddr)

///////////////////////////////////////////////////////////////////////////////
// port bit assignments

#define DATA_LEDS		LATA
#define DATA0_LED		LATAbits.LA0
#define DATA1_LED		LATAbits.LA1
#define DATA2_LED		LATAbits.LA2
#define DATA3_LED		LATAbits.LA3
#define DATA4_LED		LATAbits.LA4
#define DATA5_LED		LATAbits.LA5
#define DATA6_LED		LATAbits.LA6
#define DATA7_LED		LATAbits.LA7

#define DATA_BUTTONS	PORTB

#define RUN_STOP_BUTTON	PORTCbits.RC0		// Control / Run/Stop
#define RUN_LED			LATCbits.LC3
#define SAVE_BUTTON		PORTCbits.RC4		// File / Save
#define LOAD_BUTTON		PORTCbits.RC5		// File / Load
#define TEST_POINT		LATCbits.LC7		// Pin 1

#define ADDRESS_LEDS	LATD

#define GOTO_BUTTON		PORTEbits.RE0		// Program / Goto
#define STORE_BUTTON	PORTEbits.RE1		// Program / Store
#define PREV_BUTTON		PORTEbits.RE2		// Program / Prev
#define NEXT_BUTTON		PORTEbits.RE3		// Program / Next

///////////////////////////////////////////////////////////////////////////////
// type declarations

typedef enum { false, true } bool_t;
typedef unsigned char uint8;
typedef unsigned short uint16;

typedef union
{
	uint16 word;
	struct
	{
		uint8 low_byte, high_byte;
	};
	struct
	{
		uint8 bit0  : 1;
		uint8 bit1  : 1;
		uint8 bit2  : 1;
		uint8 bit3  : 1;
		uint8 bit4  : 1;
		uint8 bit5  : 1;
		uint8 bit6  : 1;
		uint8 bit7  : 1;
		uint8 bit8  : 1;
		uint8 bit9  : 1;
		uint8 bit10 : 1;
		uint8 bit11 : 1;
		uint8 bit12 : 1;
		uint8 bit13 : 1;
		uint8 bit14 : 1;
		uint8 bit15 : 1;
	};
} union16_t;

typedef union
{
	uint8 byte[256];
	struct
	{
		uint8 padding[252];
		union
		{
			uint8 byte;
			struct
			{
				uint8 zero					: 1;
				uint8 carry					: 1;
				uint8 show_address_led_reg	: 1;
				uint8						: 5;
			} flags;
		} status_reg;
		uint8 button_reg;
		uint8 address_led_reg;
		uint8 data_led_reg;
	};
} ram_t;

enum
{
	StatusRegAddr = 252,
	ButtonRegAddr,
	AddressLEDRegAddr,
	DataLEDRegAddr,
};

enum
{
	HALT,		// original instructions
	NOP,
	SPEED,
	COPYLR,
	COPYLA,
	COPYAR,
	COPYRA,
	COPYRR,
	ADDLA,
	ADDRA,
	SUBLA,
	SUBRA,
	ANDLA,
	ANDRA,
	ORLA,
	ORRA,
	XORLA,
	XORRA,
	DECR,
	INCR,
	DECRJZ,
	INCRJZ,
	SHIFTRL,
	SHIFTRR,
	CBR,
	SBR,
	BCRSC,
	BCRSS,
	JUMP,
	CALL,
	RETLA,
	RETURN,
	ADDRPC,
	
	INITSP,		// new instructions
	RANDA,
};

///////////////////////////////////////////////////////////////////////////////
// public function declarations

void cpu_process( void );
void cpu_reset( void );
void file_load( uint8 slot );
void file_save( uint8 slot );
void lamp_test( void );
void sleep_ms( uint8 ms );
void ui_process( void );

///////////////////////////////////////////////////////////////////////////////
// public variable declarations

extern bool_t t1ms, address_blanking;
extern uint8 pc;
extern const uint16 speed_to_rate[];
extern ram_t ram;

#endif	// DIGIRULE2_H
