/* Copyright 1998 (c) by Salvador Eduardo Tropea
   This code is part of the FreeBE/AF project you can use it under the
terms and conditions of the FreeBE/AF project. */
/* TGUI Alternative bank selector */
/* It select the bank when we use a 32Kb or 64Kb window */
#define DestinationSegmentAddress 0x3D8
#define SourceSegmentAddress      0x3D9


#define INLINE extern inline

//#define IOMAPPED
//#define UNDERTEST

#ifdef UNDERTEST
#include <sys/farptr.h>
#endif

#ifdef IOMAPPED
#define MODEINIT 0x80
INLINE void Putb(unsigned pos, uchar val)    { outportb(0x2100+pos,val); }
INLINE void Putw(unsigned pos, ushort val)   { outportw(0x2100+pos,val); }
INLINE void Putl(unsigned pos, unsigned val) { outportl(0x2100+pos,val); }
INLINE uchar    Getb(unsigned pos) { return inportb(0x2100+pos); }
INLINE ushort   Getw(unsigned pos) { return inportw(0x2100+pos); }
INLINE unsigned Getl(unsigned pos) { return inportl(0x2100+pos); }
#else
// Memory mapped
#define MODEINIT 0x81
#ifdef UNDERTEST
#define MMIOBASE 0xB7F00
//#define MMIOBASE 0xBFF00
//#define MODEINIT 0x82
INLINE void Putb(unsigned pos, uchar val)    { _farnspokeb(MMIOBASE+pos,val); }
INLINE void Putw(unsigned pos, ushort val)   { _farnspokew(MMIOBASE+pos,val); }
INLINE void Putl(unsigned pos, unsigned val) { _farnspokel(MMIOBASE+pos,val); }
INLINE uchar    Getb(unsigned pos) { return _farnspeekb(MMIOBASE+pos); }
INLINE ushort   Getw(unsigned pos) { return _farnspeekw(MMIOBASE+pos); }
INLINE unsigned Getl(unsigned pos) { return _farnspeekl(MMIOBASE+pos); }
#else
extern unsigned MMIOBASE;
/*
  If I don't use volatile the stupid gcc does funny things like that:
  movl _MMIOBASE,%eax
  movl 0x32(%eax),%al
Lxxx:
  testb %al,$0x40
  jne   Lxxx

  :-)))) the silly compiler is specting some gost will change AL by magic.
  Using volatile generates good code. Some idiot reloads are performed but
that's normal in the "unoptimizer" module of gcc ;-)
  Memory mapped I/O generates much compact code and I guess faster too, I
must test it.
*/
INLINE void Putb(unsigned pos, uchar val)    { *((volatile uchar *)(MMIOBASE+pos))=val; }
INLINE void Putw(unsigned pos, ushort val)   { *((volatile ushort *)(MMIOBASE+pos))=val; }
INLINE void Putl(unsigned pos, unsigned val) { *((volatile unsigned *)(MMIOBASE+pos))=val; }
INLINE uchar    Getb(unsigned pos) { return *((volatile uchar *)(MMIOBASE+pos)); }
INLINE ushort   Getw(unsigned pos) { return *((volatile ushort *)(MMIOBASE+pos)); }
INLINE unsigned Getl(unsigned pos) { return *((volatile unsigned *)(MMIOBASE+pos)); }
#endif
#endif

// Register index
#define GECR 0x36
#define CLAR 0x21

// ****************************** GER values ********************************
// Status
#define GESR 0x20
// Operation Mode 0
#define GOMR0 0x22
// Operation Mode 1 (Not implemented in 9440)
#define GOMR1 0x23
// Command
#define GECoR 0x24
// Foreground Mix
#define FMR 0x27
// Drawing Flag 0,1,2 (Not implemented in 9440) and 3
#define GEDFR0 0x28
#define GEDFR1 0x29
#define GEDFR2 0x2A
#define GEDFR3 0x2B
/* All joined in one 32 bits: */
#define PatFromDisplay        0x00000002
#define PatFromSystem         0
#define SourceDataDisplay     0x00000004
#define SourceDataSystem      0
#define PatMono               0x00000020
#define PatColor              0
#define SourceDataMono        0x00000040
#define SourceDataColor       0
#define YDecreasing           0x00000100
#define XDecreasing           0x00000200
#define YMajor                0x00000400
#define TransparentEnable     0x00001000
#define TransparentReverse    0x00002000
#define SolidDrawing          0x00004000
#define PatternedDrawing      0
#define PatternedLines        0x00008000
// Foreground Color 0 (Low 8 bits) and 1
#define FCR0 0x2C
#define FCR1 0x2D
// Background Color 0 (Low 8 bits) and 1
#define BCR0 0x30
#define BCR1 0x31
// Pattern Location 0 (Low) and 1
// Data must be 64 bytes aligned in VRAM, in 16 bits mode the lower bit must
// be 0
#define PLR0 0x34
#define PLR1 0x35
// Destination X Location 0 (Low) and 1
#define DXL0 0x38
#define DXL1 0x39
// Destination Y Location 0 (Low) and 1
// Only 11 bits used
#define DYL0 0x3A
#define DYL1 0x3B
// Source X Location 0 (Low) and 1
// Or diagonal step for line operations (detaY-deltaX) only 12 bits signed
#define SXL0 0x3C
#define SXL1 0x3D
// Source Y Location 0 (Low) and 1
// Or axial step for line operations (detaY) only 11 bits signed
#define SYL0 0x3E
#define SYL1 0x3F
// Operation Dimension X Location 0 (Low) and 1
// Or initial error for line operations (2*detaY-deltaX) only 12 bits signed
#define ODXL0 0x40
#define ODXL1 0x41
// Operation Dimension Y Location 0 (Low) and 1
// Or length for line operations (deltaX) only 12 bits unsigned
// Various bits for short vector operations.
#define ODYL0 0x42
#define ODYL1 0x43
// Pen Style Mask 0 and 1 for lines
#define PSMR0 0x44
#define PSMR1 0x45
// Style Mask First Pixel Repeat Count for lines
#define SMFPRC 0x46
// Style Mask Repeat Count for lines
#define SMRC 0x47
// Registers 0x80 to 0xFF are for the pattern
// ************************* End of  GER values *****************************
// ****** Commands for GECoR ******
#define NOP      0
#define BitBLT   1
#define ScanLine 3
// Bresenham Line
#define BLine    4
// Short vector
#define SVector  5

extern unsigned long linearAddress;
#define Screenb ((uchar *)linearAddress)
#define Screenw ((ushort *)linearAddress)
#define Screenl ((unsigned *)linearAddress)

#define SetXLocation(a) Putw(DXL0,a)
#define SetYLocation(a) Putw(DYL0,a)
#define SetXYLocation(a,b) Putl(DXL0,(a) | ((b)<<16))
#define SetXYSource(a,b) Putl(SXL0,(a) | ((b)<<16))
#define SetForeground(a) Putw(FCR0,a)
#define SetBackground(a) Putw(BCR0,a)
#define SetForegroundMix(a) Putb(FMR,a)
#define SetPenStyleMask(a) Putw(PSMR0,a)
#define SetStyleMaskRepeatCount(a) Putb(SMRC,a)

//#define SAFE_IO

INLINE
void SetLineSteps(int deltaY, int deltaX)
{
 // Diagonal step is dY-dX, Axial step is dY both 16 bits signed
 Putl(SXL0,((deltaY-deltaX) & 0xFFFF) | (deltaY<<16));
}

INLINE
void SetErrAndLen(int deltaY, int deltaX)
{
 // Initial error is 2*dY-dX (signed), Length is ABS(dX) (unsigned)
 Putl(ODXL0,((2*deltaY-deltaX) & 0xFFFF) | (deltaX<<16));
}


INLINE
void SetDimensions(int width, int height)
{
 Putl(ODXL0,width | (height<<16));
}

INLINE
void SetWidth_1(int width)
{
 Putw(ODXL0,width-1);
}

INLINE
void SetWidth(int width)
{
 Putw(ODXL0,width);
}

INLINE
void SetDrawFlags(int dir)
{
 Putl(GEDFR0,dir);
}

INLINE
void SetPatternLocation(unsigned offset)
{
 Putw(PLR0,offset);
}

/*
  Wait until the GER is idle. That's needed for the BitBlt operation because
we can't write to the screen. If I return the control to the application
and it tries to draw directly to the screen it will fail.
  In OS drivers, line Windows drivers, that's not needed because the
application NEVER will draw directly to the screen.
  An additional feature not exploited is that the GER can generate interrupts
so we can have a queue of command in memory and transfer it to the TGUI
when the GER is ready.
*/
INLINE
void WaitGE(void)
{
 while (Getb(GESR) & 0x80);
}

/*
  Wait until the FIFO of the GER is empty, if we don't do it the cached
command will use the new settings ;-)
*/
INLINE
void WaitGEfifo(void)
{
 while (Getb(GESR) & 0x20);
}

/*
 That's a very bad thing, I must put a full wait after the blit because
during the Blit the CPU can't access the VRAM.
 It could be avoided only if ALL the drawing is made by the driver, but
that's not the FreeBE/AF case.
*/
INLINE
void DoBlit(void)
{
 Putb(GECoR,BitBLT);
 #ifdef WAITTILLIDLE_NOT_NEEDED
 WaitGE();
 #endif
}

INLINE
void DoBlitDontWait(void)
{
 Putb(GECoR,BitBLT);
}

INLINE
void DoBresenhamLine(void)
{
 Putb(GECoR,BLine);
}

INLINE
void DoScan(void)
{
 Putb(GECoR,ScanLine);
}

INLINE
void SetNewMode(void)
{
 ReadSEQ(0xB);
}

INLINE
void SetOldMode(void)
{
 WriteSEQ(0xB,0);
}

/**************************** RASTER OPERATIONS ****************************/
/* Most of them are for solid colors or patterns only */
#define ROP_0     0x00
#define ROP_n_PoD 0x05
#define ROP_nPaD  0x0A
#define ROP_nP    0x0F
#define ROP_PanD  0x50
#define ROP_nD    0x55
#define ROP_PxD   0x5A
#define ROP_n_PaD 0x5F
#define ROP_PaD   0xA0
#define ROP_n_PxD 0xA5
#define ROP_D     0xAA
#define ROP_nPoD  0xAF
#define ROP_P     0xF0
#define ROP_PonD  0xF5
#define ROP_PoD   0xFA
#define ROP_1     0xFF

/* These are for image blits only */
/* 0x00 is ROP_0 */
#define ROP_n_SoD 0x11
#define ROP_nSaD  0x22
#define ROP_nS    0x33
#define ROP_SanD  0x44
/* 0x55 is ROP_nD */
#define ROP_SxD   0x66
#define ROP_n_SaD 0x77
#define ROP_SaD   0x88
#define ROP_n_SxD 0x99
/* 0xAA is ROP_D */
#define ROP_nSoD  0xBB
#define ROP_S     0xCC
#define ROP_SonD  0xDD
#define ROP_SoD   0xEE
/* 0xFF is ROP_1 */

#define VClockDiv2   0x20
#define VClockDiv4   0x40
#define VClockDiv1_5 0x60
#define DClockDiv2   0x80


