//
// (C) 2004 Mike Brent aka Tursi aka HarmlessLion.com
// This software is provided AS-IS. No warranty
// express or implied is provided.
//
// This notice defines the entire license for this code.
// All rights not explicity granted here are reserved by the
// author.
//
// You may redistribute this software provided the original
// archive is UNCHANGED and a link back to my web page,
// http://harmlesslion.com, is provided as the author's site.
// It is acceptable to link directly to a subpage at harmlesslion.com
// provided that page offers a URL for that purpose
//
// Source code, if available, is provided for educational purposes
// only. You are welcome to read it, learn from it, mock
// it, and hack it up - for your own use only.
//
// Please contact me before distributing derived works or
// ports so that we may work out terms. I don't mind people
// using my code but it's been outright stolen before. In all
// cases the code must maintain credit to the original author(s).
//
// -COMMERCIAL USE- Contact me first. I didn't make
// any money off it - why should you? ;) If you just learned
// something from this, then go ahead. If you just pinched
// a routine or two, let me know, I'll probably just ask
// for credit. If you want to derive a commercial tool
// or use large portions, we need to talk. ;)
//
// If this, itself, is a derived work from someone else's code,
// then their original copyrights and licenses are left intact
// and in full force.
//
// http://harmlesslion.com - visit the web page for contact info
//
///////////////////////////////////////////////////
// Ami 99 - header
// M.Brent
///////////////////////////////////////////////////

// Defines
#define VERSION "QI3.5"
#define DEBUGLEN 60

#define UINT8 unsigned __int8
#define Byte unsigned __int8
#define Word unsigned __int16

#define CLOCK_MHZ 3000000
#define DEFAULT_CPF (CLOCK_MHZ/60)

#define DisplayEvent Video_hdl[0]
#define BlitEvent Video_hdl[1]

#define TYPE_GROM	'G'
#define TYPE_ROM	'C'
#define TYPE_SPEECH 'S'
#define TYPE_XB		'X'
#define TYPE_RAM	'R'
#define TYPE_VDP	'V'
#define TYPE_DSR	'D'
#define TYPE_DSR2	'E'
#define TYPE_PCODEG 'P'
#define TYPE_NONE	' '

struct IMG {
	DWORD dwImg;			// resource ID, NULL for disk type
	Word nLoadAddr;
	Word nLength;
	char nType;
	char szFileName[1024];	// filename if on disk, only if dwImg is NULL
};
struct DISKS {			// These are checked if a file can't be found in the real DSK1 ;)
	char szName[64];
	DWORD dwImg;		// resource ID
};
struct CARTS {
	char szName[64];
	struct IMG Img[4];
	struct DISKS *pDisk;
	const char *szMessage;
};

// NOTE: this keeps it safe, but forces a PC from 0x8000-0x83ff into the 0x83xx range
// This is wrong, of course, but even more so since the RAM is repeated from
// 0x8100-0x8300, and not at 0x8000. However, 0x8000-0x80ff is the memory mapped
// hardware, so if the Program Counter is there, we're in trouble ANYWAY! ;)
#define ADDPC(x) { PC+=(x); PC&=0xffff; if ((PC&0xfc00)==0x8000) PC|=0x300; }	

// Variables
extern int redraw_needed;							// redraw flag
extern int interrupt_needed;						// interrupt flag
extern int skip_interrupt;							// flag for some instructions
extern Byte VDPREG[9];								// VDP read-only registers
extern Byte VDPS;									// VDP Status register
extern Word VDPADD;									// VDP Address counter
extern int vdpaccess;								// VDP access counter
extern Word tmpVDPADD;								// VDP temp Address counter
extern Byte vdpprefetch;							// VDP prefetch
extern unsigned long hVideoThread;					// thread handle
extern Byte hzRate;									// flag for 50 or 60hz
extern Byte Recording;								// Flag for AVI recording
extern Byte RecordFrame;							// Current frame recorded (currently we only write 1/4 of the frames)
extern int MaintainAspect;							// Flag for Aspect ratio
extern int StretchMode;								// Setting for video stretching
extern Byte VDP[16384];								// Video RAM
extern HANDLE Video_hdl[2];							// Handles for Display/Blit events
extern unsigned short *framedata;					// The actual pixel data
extern unsigned short *framedata2;					// Filtered frame data
extern int FullScreenMode;							// Current full screen mode
extern int FilterMode;								// Current filter mode
extern int TIPALETTE[16];

extern HWND myWnd, memWnd, regWnd, asmWnd, dbgWnd;	// Handle to windows
extern HDC myDC;									// Handle to Device Context
extern HANDLE MyMutex;								// DD Synchronization mutex
extern int fontX, fontY;							// Non-proportional font x and y size
extern int wndXtrim, wndYtrim;						// Window trim, used for sizing
extern int quitflag;								// exit flag
extern int nCurrentDSR;									// Which DSR Bank are we on?
extern int nDSRBank[16];										// Is the DSR bank switched?

extern char key[256];								// keyboard state buffer

extern Word PC;										// Program Counter
extern Word WP;										// Workspace Pointer
extern Word X_flag;									// Set during an 'X' instruction
extern Word ST;										// Status register
extern Byte CPU[65536];								// Main CPU Memory
extern Byte CPU2[8192];								// Cartridge space bank-switched
extern Byte GROM[65536];							// GROM space
extern Byte ROMMAP[65536];							// Write-protect map of CPU space
extern Byte CRU[4096];								// CRU space
extern Byte DSR[16][16384];							// 16 CRU bases, up to 16k each (ROM >4000 space)
extern Byte PCODE[65536];							// P-Code GROM space
extern Word GRMADD;									// GROM Address counter
extern Byte grmaccess,grmdata;						// GROM Prefetch emulation
extern Word PCODEADD;								// GROM Address counter
extern Byte pcodeaccess,pcodedata;					// GROM Prefetch emulation

extern int PauseInactive;							// what to do when the window is inactive
extern int SpeechEnabled;							// whether or not speech is enabled
extern int CPUThrottle;								// Whether or not the CPU is throttled
extern Word in;										// Opcode interpretation
extern void (*opcode[65536])(void);					// CPU Opcode address table

extern char lines[30][DEBUGLEN];					// debug lines

extern char *PasteString;							// Used for Edit->Paste
extern char *PasteIndex;

extern int bank;							// Cartridge bank switch
extern int xb;										// Is second bank (XB) loaded?

// Function prototypes
int InitAvi();
void WriteFrame();
void CloseAVI();
void ConfigAVI();

void GetTVValues(double *hue, double *sat, double *cont, double *bright, double *sharp);
void SetTVValues(double hue, double sat, double cont, double bright, double sharp);
void VDPmain(void);
HRESULT InitDirectDraw( HWND hWnd );
void VDPdisplay(void);
void gettables(void);
void draw_debug(void);
void VDPgraphics(void);
void VDPgraphicsII(void);
void VDPtext(void);
void VDPtextII(void);
void VDPillegal(void);
void VDPmulticolor(void);
void VDPmulticolorII(void);
void debug_write(char *s, ...);
extern void debug_write(char *s, ...);
void doBlit(void);
void RenderFont(void);
void DrawSprites(void);
void SetupDirectDraw(int fullscreen);
void takedownDirectDraw();
int ResizeBackBuffer(int w, int h);

void textout(char *, int, int);
LONG FAR PASCAL myproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
BOOL CALLBACK AudioBoxProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
BOOL CALLBACK OptionsBoxProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
BOOL CALLBACK KBMapProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
BOOL CALLBACK TVBoxProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
void pixel(int x, int y, int col);
void bigpixel(int x, int y, int col);
void spritepixel(int x, int y, int c);

void startvdp(void);
void startsound(void);
void warn(char[]);
void fail(char[]);
Word romword(Word);
Byte romwordbyte(Word);
void wrword(Word,Word);
void wrwordbyte(Word,Byte);
void emulti(void);
void readroms(void);
Word hex2dec(char[]);
void double2tifloat(double d, Byte *p);
double tifloat2double(Byte *p);
void do1(void);
void opcode0(Word);
void opcode02(Word);
void opcode03(Word); 
void opcode04(Word);
void opcode05(Word);
void opcode06(Word);
void opcode07(Word);
void opcode1(Word);
void opcode2(Word);
void opcode3(Word);
Byte rcpubyte(Word);
void wcpubyte(Word,Byte);
void increment_vdpadd();
Byte rvdpbyte(Word);
void wvdpbyte(Word,Byte);
void pset(int dx, int dy, int c, int a, int l);
Byte rspeechbyte(Word);
void wspeechbyte(Word, Byte);
void SpeechUpdate();
void wVDPreg(Byte,Byte);
void wsndbyte(Byte);
Byte rgrmbyte(Word);
void wgrmbyte(Word,Byte);
Byte rpcodebyte(Word);
void wpcodebyte(Word,Byte);
void wcru(Word,int);
int rcru(Word);
void fixDS(void);
void parity(Byte);
void op_a(void);
void op_ab(void);
void op_abs(void);
void op_ai(void);
void op_dec(void);
void op_dect(void);
void op_div(void);
void op_inc(void);
void op_inct(void);
void op_mpy(void);
void op_neg(void);
void op_s(void);
void op_sb(void);
void op_b(void);
void op_bl(void);
void op_blwp(void);
void op_jeq(void);
void op_jgt(void);
void op_jhe(void);
void op_jh(void);
void op_jl(void);
void op_jle(void);
void op_jlt(void);
void op_jmp(void);
void op_jnc(void);
void op_jne(void);
void op_jno(void);
void op_jop(void);
void op_joc(void);
void op_rtwp(void);
void op_x(void);
void op_xop(void);
void op_c(void);
void op_cb(void);
void op_ci(void);
void op_coc(void);
void op_czc(void);
void op_ldcr(void);
void op_sbo(void);
void op_sbz(void);
void op_stcr(void);
void op_tb(void);
void op_ckof(void);
void op_ckon(void);
void op_idle(void);
void op_rset(void);
void op_lrex(void);
void op_li(void);
void op_limi(void);
void op_lwpi(void);
void op_mov(void);
void op_movb(void);
void op_stst(void);
void op_stwp(void);
void op_swpb(void);
void op_andi(void);
void op_ori(void);
void op_xor(void);
void op_inv(void);
void op_clr(void);
void op_seto(void);
void op_soc(void);
void op_socb(void);
void op_szc(void);
void op_szcb(void);
void op_sra(void);
void op_srl(void);
void op_sla(void);
void op_src(void);
void buildcpu(void);
void op_bad(void);

int Dasm9900 (char *buffer, int pc);

void do_files(int n);
void do_dsrlnk(void);
void load(char *filename, int PAB);
void save(char *filename, int PAB);
void read(char *filename, int PAB);
void write(char *filename, int PAB);
void setfileerror(int PAB, Byte errcode);
void setnofileerror(int PAB);
void buildfilename(char *filename, int PAB);
void do_sbrlnk();
char detectfiletype(FILE *fp, char *p);
int detectfixedorvar(FILE *fp, int len);
void GetFileInfo(char *filename);
void WriteFileHeader(char type, FILE *fp, int PAB);

int nodot(void);
Byte GetSafeByte(int x);
Word GetSafeWord(int x);

void read_sect(Byte drive, int sect, char *buffer);

#if 0		// commented on main code
void read_image_file(int PAB, char *buffer, int offset, int len);
#endif

void ConsoleInterrupt(void);

void __cdecl TimerThread();
void Counting();
void __cdecl SpeakThread();
char *stpcpy(char *dest, char *src);
char *stpncpy(char *dest, char *src, int n);


