#ifndef DIGIRULE2_H
#define	DIGIRULE2_H

#include <xc.h>

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

#define USER_FLASH		0x1000		// where user programs are stored in flash
#define SAMPLE_PROGRAMS	1			// preload user flash with sample programs
#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		// EEPROM / Save
#define LOAD_BUTTON		PORTCbits.RC5		// EEPROM / Load
#define TEST_POINT		LATCbits.LC7		// Pin 1

#define ADDRESS_LEDS	LATD

#define GOTO_BUTTON		PORTEbits.RE0		// Program / Goto
#define DEPOSIT_BUTTON	PORTEbits.RE1		// Program / Save
#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 flash_program_load( uint8 slot );
void flash_program_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
