diff options
Diffstat (limited to 'SrcShared/Hardware/EmRegsMediaQ11xx.cpp')
-rw-r--r-- | SrcShared/Hardware/EmRegsMediaQ11xx.cpp | 4791 |
1 files changed, 4791 insertions, 0 deletions
diff --git a/SrcShared/Hardware/EmRegsMediaQ11xx.cpp b/SrcShared/Hardware/EmRegsMediaQ11xx.cpp new file mode 100644 index 0000000..19506b0 --- /dev/null +++ b/SrcShared/Hardware/EmRegsMediaQ11xx.cpp @@ -0,0 +1,4791 @@ +/* -*- mode: C++; tab-width: 4 -*- */ +/* ===================================================================== *\ + Copyright (c) 2001 Palm, Inc. or its subsidiaries. + All rights reserved. + + This file is part of the Palm OS Emulator. + + 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. +\* ===================================================================== */ + +#include "EmCommon.h" +#include "EmRegsMediaQ11xx.h" + +#include "EmCPU68K.h" // gCPU68K +#include "EmPixMap.h" // EmPixMap::GetLCDScanlines +#include "EmScreen.h" // EmScreen::InvalidateAll +#include "SessionFile.h" // + +#include "Logging.h" // LogAppendMsg + +#include <algorithm> // swap + + +#define LOG_LINE 0 +#define PRINTF_LINE if (!LOG_LINE) ; else LogAppendMsg + +#define LOG_BLIT 0 +#define PRINTF_BLIT if (!LOG_BLIT) ; else LogAppendMsg + + +/* --------------------------------------------------------------------------- *\ + MediaQ Graphics Engine overview and description + ----------------------------------------------- + + The MediaQ 1100/1132 chip contains a graphics engine used for accelerating + graphics drawing operations. It has the following features: + + * Line drawing + * Rectangle operations (fill, scroll, and BLT) + * Arbitrary transfer operations (using Windows ROP definitions) + * Monochrome and color source data + * Monochrome pattern data + * Colorization of monochrome source and pattern data + * Transparency support + * Clipping support + * Automatic screen flipping + + There are 20 registers reserved for the graphics accelerator. The MediaQ + client generally works by storing necessary values in a subset of those + registers, and then kicks off the drawing process by updating the register + that receives the drawing command. This register (GE00R) is the master + control register. It contains all of the top-level information about what + is to be drawn and how. As needed, other registers are queried for + additional values needed for the operation. Registers not required for + the drawing operation need not be updated before the drawing command is + issued. The drawing operation takes place asynchronously, freeing up the + MediaQ client for other tasks. + + The graphics chip makes use of two FIFOs: a command FIFO and a source data + FIFO. The command FIFO is used to make sure that registers are not + updated and changed out from under a drawing operation currently in + progress. That is, any write access to a register really results in an + entry being added to the command FIFO. Entries are then popped off and + used to update the registers. If the command register is written to, the + drawing operation commences. Any subsequent writes to registers will + still be added to the FIFO, but will stay there until the drawing + operation has completed. If the FIFO is full (it has room only for 16 + commands), the main CPU will stall if it tries to add any more commands. + + Sometimes the drawing operation requires "source data", that is, data from + main memory. The MediaQ chip doesn't have direct access to main RAM, and + so data from there needs to be fed in through a source FIFO. After a + drawing command has been started that requires source data, the MediaQ + client must go into a loop and ensure that this source data FIFO is filled + with the necessary data. Note that this source FIFO contains 16 64-bit + slots. Therefore, the client needs to make sure that information written + to the FIFO occurs in multiples of 64-bits (or 8 bytes). + + GEState + ------- + + This Poser-defined structure is a mirror of the registers used by the + MediaQ graphics acceleration engine. It breaks out all of the pieces of + information packed into those registers, and stores each piece into its + own field for easy access. This unpacking takes place as needed, + generally when a graphics drawing command is issued. + + Following is a description of all the registers and the fields within + those registers. After that are included some notes on how those + registers fit into the bigger picture. + + ************************************************************************** + ========================================================================== + GE00R + ========================================================================== + + GE00R[7:0] rasterOperation + ----------------------------------------------- + Specifies the transfer mode. That is, it defines the way in which the + source data, destination data, and pattern data are combined to + produce the final destination or output data. The values that can be + used here are the same that Microsoft has defined for GDI. + + This register can contain either the ternary ROP codes or the binary + ROP2 codes, depending on the setting of rop2Select (GE00R[25]). + + GE00R[10:8] commandType + ----------------------------------------------- + Specifies the drawing command. Can be one of three values: + + 0 = NOP + 2 = BitBLT + 4 = Line + + All other values are either reserved or undefined. + + Note that BitBLT is used for drawing filled rectangles, scrolling + images in the screen memory, or copy images from main memory to the + screen memory. Monochrome and color source data and patterns are + supported. + + GE00R[11] xDirection + GE00R[12] yDirection + ----------------------------------------------- + Defines the direction in which a BitBLT or line drawing operation + occurs. Values of zero indicate the positive (right or down) + direction; values of one indicate the negative (left or up) direction. + When drawing a line, note that these fields are used only if the + useXY field is set. + + GE00R[13] systemMemory + ----------------------------------------------- + If true, specifies that any source data comes from the source FIFO. + Otherwise, the data comes from display memory, and xSrc (GE03R[11:0]) + and ySrc (GE03R[27:16]) need to be programmed. + + GE00R[14] monoSource + ----------------------------------------------- + Specifies whether the source data is a monochrome (aka, bitonal) + bitmap where each pixel is represented by a single bit, or that the + source data is in color format, where each pixel is defined by an 8 or + 16 bit value, depending on the setting of colorDepth (GE0AR[31:30]). + + GE00R[15] monoPattern + ----------------------------------------------- + Specifies whether the pattern data is a monochrome (aka, bitonal) + bitmap where each pixel is represented by a single bit, or that the + pattern data is in color format, where each pixel is defined by an 8 + or 16 bit value. Note that in the current chip, this bit *MUST* be + set to 1, indicating a monochrome pattern. There doesn't appear to be + any support or any way to specify a color pattern. + + GE00R[16] colorTransEnable + ----------------------------------------------- + Setting this bit enables transparent BitBLT operations when the source + data is in color format. It works in conjunction with + destTransPolarity, colorTransCmpSrc, and destTransColor to determine + if the destination pixel is updated or stays the same. + + GE00R[17] destTransPolarity + ----------------------------------------------- + If color transparency is enabled (that is, colorTransEnable is set), + determines how transparency is achieved. Depending on the setting of + colorTransCmpSrc, either the source data or the dest data is compared + to destTransColor. If destTransPolarity is zero, then the destination + pixel is updated if the result of the comparison is not equal. If + destTransPolarity is one, then the destination pixel is update if the + result is equal. + + GE00R[18] monoTransEnable + ----------------------------------------------- + Setting this bit enables transparent BitBLT operations when the source + data is in monochrome format. It works in conjunction with + monoTransPolarity to determine if the destination pixel is updated or + stays the same. + + GE00R[19] monoTransPolarity + ----------------------------------------------- + If monochrome transparency is enabled (that is, monoTransEnable is + set), determines how transparency is achieved. If this value is zero, + then background (that is, zero) bits in the source are treated as + transparent and don't update the destination. If this value is one, + then foreground (that is, one) bits in the source data are treated as + transparent. + + GE00R[20] memToScreen + ----------------------------------------------- + Specifies LINED (memToScreen == 0) or PACKED (memToScreen == 1) blit + transfer mode. PACKED Mode allows bitmaps that are compact to be + transferred more efficiently. LINE Mode requires each line of bitmap + to be aligned at 64-bit and thus could require padding and realignment + if each line of bitmap to be transfer is non-64-bit aligned. + + GE00R[23] solidSourceColor + ----------------------------------------------- + If set, the actual color source data is effectively ignored, and + instead treated as if it were all fgColorMonoSrc. + + GE00R[24] srcEqualDestStride + ----------------------------------------------- + Specifies whether or not the dest and source have the same "strides" + (that is, "rowBytes" in other terminologies). If the source is the + display, then the source will always be the same as the dest. But if + the source is main memory, then the data comes in through the source + FIFO, and I'm not sure how stride comes in to play there. + + GE00R[25] rop2Select + ----------------------------------------------- + Causes the value in rasterOperation (GE00R[7:0]) to be treated as a + binary ROP2 value instead of a ternary ROP value. The documentation + says that "[3:0] is duplicated to [7:4]". However, it's not clear to + me is the programmer is required to write the register in this + duplicated fashion, or if the hardware aliases the low values into the + high values in some way. In either case, I'm not sure why the + hardware cares. Why wouldn't it just look at the low 4 bits and + ignore the upper 4 bits. My guess is that the hardware performs this + aliasing on its own, and that the result when looking at all 8 bits + has the result of acting like a binary ROP2 code (that is, the any + source data will be ignored -- see comments in PrvUsesSource on how + the ROP value can be examined to see if the pattern, source or + destination have any role in determining the final output value). + + GE00R[26] clipEnable + ----------------------------------------------- + Enable clipping according to the clipLeft, clipTop, clipRight, and + clipBottom fields (registers GE05R and GE06R). + + GE00R[27] autoExecute + ----------------------------------------------- + Setting this bit enables auto-execution of the command after the + destination XY register (GE02R) is written. If it's clear, the + graphics engine command execution starts the command register (GE00R) + is written. + + GE00R[30] solidPattern + ----------------------------------------------- + If set, then all pattern data is forced to the value of the pattern + foreground color register (GE12R). + + GE00R[31] colorTransCmpSrc + ----------------------------------------------- + Used in conjunction with the transparency-enable bits, determines if + the color to be compared comes from the source or destination. + Compare to the source data if it's zero, destination if it's one. + + ========================================================================== + GE01R + ========================================================================== + + GE01R[11:0] (BitBLT) width + GE01R[27:16] (BitBLT) height + ----------------------------------------------- + When a BitBLT operation has been specified, these fields contain the + dimensions (in pixels) of the operation. It is used for both the + source and destination. + + GE01R[31] (BitBLT) xyConversion + ----------------------------------------------- + When a BitBLT operation has been specified, this field controls how + the starting x/y values are interpreted. If this bit is clear, then + the specified x/y values are the first pixel updated. If this bit is + set, then the specified x/y values are the top/left corner of the + rectangle that's updated. + + GE01R[16:0] (Line) gamma + ----------------------------------------------- + When a line drawing operation has been specified, contains a value + identified as "gamma". This is defined in the documentation as + "either -(dm >> 1) - 1 or -(dm >> 1), depending on the quadrant", + where "dm" is the major axis delta. However, there's no mention of + which value is used in what situations. As well, our source code + writes to this field a value that has the same magnitude of dm. That + is dm gets written to its designated field, and -dm gets written to + gamma. + + GE01R[28:17] (Line) majorLength + ----------------------------------------------- + When a line drawing operation has been specified, contains the length + along the major axis. + + GE01R[29] (Line) yIsMajor + ----------------------------------------------- + When a line drawing operation has been specified, specifies which axis + is the major axis (that is, the "long" axis -- a "mostly horizontal" + line has X as the major axis, while a "mostly vertical" line has Y as + the major axis, and a diagonal line can have either defines as its + major axis). If set, Y is the major axis. Otherwise, X is the major + axis. Note that this field is used only if the useXY field is set. + + GE01R[30] (Line) drawLastPixel + ----------------------------------------------- + When a line drawing operation has been specified, specifies whether or + not the last pixel in the rasterization process is drawn. + + GE01R[31] (Line) useXY + ----------------------------------------------- + When a line drawing operation has been specified, specifies the method + used to determine in which direction the line should be drawn. If + this field is set, then the information about direction and slope is + taken from the xDirection, yDirection, and yIsMajor fields. If this + field is clear, then the information is taken from the quadrant field. + + ========================================================================== + GE02R + ========================================================================== + + GE02R[11:0] (BitBLT) xDest + GE02R[27:16] (BitBLT) yDest + ----------------------------------------------- + When a BitBLT operation has been specified, these fields contain the + initial x,y location to receive the blitted data. Note that these + values are always the topLeft of the destination area, regardless of + xDirection and yDirection. + + GE02R[15:13] (BitBLT) monoPatternXOffset + GE02R[31:29] (BitBLT) monoPatternYOffset + ----------------------------------------------- + When a BitBLT operation has been specified, these fields contain the + initial x,y offsets into the monochrome pattern being used. + + GE02R[11:0] (Line) xStart + ----------------------------------------------- + When a line drawing operation has been specified, specifies starting X + position of the line. + + GE02R[28:12] (Line) deltaMajor + ----------------------------------------------- + When a line drawing operation has been specified, specifies the length + of the line along the major axis. See yIsMajor for a definition of + "major axis". + + GE02R[31:29] (Line) quadrant + ----------------------------------------------- + When a line drawing operation has been specified, specifies the + direction and angle in which the line is drawn. This is used only + when the useXY field is clear, and replaces the same information + provided by xDirection, yDirection, and yIsMajor. The field contains + a value from 0 to 7, indicating one of the following 8 quadrants: + + Quadrant 0 (x-major, positive x and y directions) + Quadrant 1 (y-major, positive x and y directions) + Quadrant 2 (y-major, negative x and positive y directions) + Quadrant 3 (x-major, negative x and positive y directions) + Quadrant 4 (x-major, negative x and y directions) + Quadrant 5 (y-major, negative x and y directions) + Quadrant 6 (y-major, positive x and negative y directions) + Quadrant 7 (x-major, positive x and negative y directions) + + ========================================================================== + GE03R + ========================================================================== + + GE03R[11:0] (BitBLT) xSrc + GE03R[27:16] (BitBLT) ySrc + ----------------------------------------------- + When a BitBLT operation has been specified, these fields contain the + initial x,y location from which to read the source data. Only used + when the source data is coming from display memory and not the source + FIFO. That is, used in scrolling operations. Note that these values + are always the topLeft of the source area, regardless of xDirection + and yDirection. + + GE03R[11:0] (Line) yStart + ----------------------------------------------- + When a line drawing operation has been specified, specifies starting Y + position of the line. + + GE03R[28:12] (Line) deltaMinor + ----------------------------------------------- + When a line drawing operation has been specified, specifies the length + of the line along the minor axis. The "minor axis" is the X or Y axis + that is not designated as the major axis. See yIsMajor for a + definition of "major axis". + + ========================================================================== + GE04R + ========================================================================== + + GE04R[15:0] destTransColor + ----------------------------------------------- + When color transparency has been enabled by setting the + colorTransEnable field, specifies the color that should be compared + against. + + ========================================================================== + GE05R/GE06R + ========================================================================== + + GE05R[10:0] clipLeft + GE05R[25:16] clipTop + GE06R[10:0] clipRight + GE06R[25:16] clipBottom + ----------------------------------------------- + When the clippingEnable bit is set, these four fields specify the + clipping boundary. Pixels outside this rectangle are not written. + + ========================================================================== + GE07R/GE08R + ========================================================================== + + GE07R[15:0] fgColorMonoSrc + GE08R[15:0] bgColorMonoSrc + ----------------------------------------------- + When a monochrome source is being used, these two fields contain the + fore- and background colors that should be applied to the bits + representing the pixels. Any 1 bit is replace with fgColorMonoSrc, + and any 0 bit is replaces with bgColorMonoSrc. + + ========================================================================== + GE09R + ========================================================================== + + GE09R[9:0] (Lined) srcLineStride + ----------------------------------------------- + When Lined mode is being used (see memToScreen (GE00R[20])) and + srcEqualDestStride is false, contains the number of bytes in a line + of source data. + + GE09R[27:25] (Lined) srcBitOffset + ----------------------------------------------- + When Lined mode is being used (see memToScreen (GE00R[20])), contains + the bit offset into the byte containing the leftmost pixel. Makes + sense only with a monochrome source. + + GE09R[30:28] (Lined) srcByteOffset + ----------------------------------------------- + When Lined mode is being used (see memToScreen (GE00R[20])), contains + the byte offset of the byte containing the leftmost pixel. + + GE09R[2:0] (Packed) srcLeadingBits + ----------------------------------------------- + When Packed mode is being used (see memToScreen (GE00R[20])), contains + the bit offset into the byte containing the leftmost pixel. Makes + sense only with a monochrome source. + + GE09R[5:3] (Packed) srcLeadingBytes + ----------------------------------------------- + When Packed mode is being used (see memToScreen (GE00R[20])), contains + the byte offset of the byte containing the leftmost pixel. + + GE09R[15:6] (Packed) srcNumBytes + ----------------------------------------------- + When Packed mode is being used (see memToScreen (GE00R[20])), described + in the manual as: Number of 8 bytes amount that MIU needs to fetch from + frame buffer. For off-screen to on-screen packed mode, these 10 bits + represent the number of 8 bytes needed to be fetched by the MIU; the + maximum amount it can address is 16 Kbyte, which is the off screen + monochrome font or monochrome image graphics engine can support for + packed mode. + + GE09R[27:25] (Packed) srcTrailingBits + ----------------------------------------------- + When Packed mode is being used (see memToScreen (GE00R[20])), contains + the number of unused trailing bits in the last byte containing pixel + data. Makes sense only in monochrome mode. + + GE09R[31:28] (Packed) srcTrailingBytes + ----------------------------------------------- + When Packed mode is being used (see memToScreen (GE00R[20])), contains + the number of unused trailing bytes. + + ========================================================================== + GE0AR + ========================================================================== + + GE0AR[9:0] destLineStride + ----------------------------------------------- + Specifies the stride (or rowBytes) of the destination bitmap. The + stride is the number of bytes between the first pixel of one line and + the first pixel of the following lines. This information duplicates + that stored in the graphic controller, but presumably is stored here + as well because the controller and accelerator are separate modules. + + GE0AR[28] monoSrcBitSwap + ----------------------------------------------- + Determines the interpretation of the bits in a monochrome pattern or + source bitmap. If this bit is clear, then bit 7 of a byte is the + leftmost pixel and bit 0 is the rightmost pixel. If this bit is set, + then bit 0 is the leftmost pixel and bit 7 is the rightmost. Having + this bit clear is consistent with Windows CE and Palm, and having it + set is consistent with EPOC. + + GE0AR[29] rotate90 + ----------------------------------------------- + If set, rotates all drawing operation 90 degrees clockwise. + + GE0AR[31:30] colorDepth + ----------------------------------------------- + Determines the number of bits per pixel. If zero, BPP == 8. If one, + BPP == 16. All other settings are undefined. This information + duplicates that stored in the graphic controller, but presumably is + stored here as well because the controller and accelerator are + separate modules. + + ========================================================================== + GE0BR + ========================================================================== + + GE0BR[19:0] baseAddr + ----------------------------------------------- + Determines the base address of the frame buffer, relative to the start + of the buffer. That is, a value of 0x00000 indicates the beginning of + the buffer, not the beginning of RAM. This information duplicates + that stored in the graphic controller, but presumably is stored here + as well because the controller and accelerator are separate modules. + + GE0BR[29] testModeEnable + GE0BR[31:30] testModeControl + ----------------------------------------------- + Test enable and control bits. Unsupported in Poser. + + ========================================================================== + GE0CR + ========================================================================== + + GE0CR[9:0] cmdLineStart + GE0CR[21:12] cmdLineEnd + ----------------------------------------------- + Specifies the beginning and end of the "command start window". + However, there is no explanation of what this window is. + + GE0CR[24] cmdLineControl + ----------------------------------------------- + Controls whether or not the graphics engine needs to check with + graphics controller before starting a command. However, there's no + explanation of how the graphics controller decides whether or not a + command should be started. + + GE0CR[27:26] gc1SwitchControl + ----------------------------------------------- + Controls automatics switching between the main and alternate windows + in the graphic controller. A value of 0 or 2 means that no switching + is performed. A value of 1 means to switch to the main window after + the current drawing command is done. A value of 3 means to switch to + the alternate window when the command is done. + + ========================================================================== + GE0FR + ========================================================================== + + GE0FR[31:0] + ----------------------------------------------- + If testModeEnable is on, this field receives various values, as + defined by testModeControl. + + ========================================================================== + GE10R/GE11R + ========================================================================== + + GE10R[31:0] monoPattern1 + GE11R[31:0] monoPattern2 + ----------------------------------------------- + Together, these fields specify 64 bits of an 8x8 monochrome pattern. + The low-order byte of monoPattern1 contains the 8 bits for the first + line, the next-order byte of monoPattern1 contains the 8 bits for the + next line, etc., all the way up to the high-order byte of monoPattern2 + containing the 8 bits for the last line. + + ========================================================================== + GE12R/GE13R + ========================================================================== + + GE12R[15:0] fgColorMonoPat + GE13R[15:0] bgColorMonoPat + ----------------------------------------------- + When a monochrome pattern is being used, these two fields contain the + fore- and background colors that should be applied to the bits + representing the pixels. Any 1 bit is replace with fgColorMonoPat, + and any 0 bit is replaces with bgColorMonoPat. + + ************************************************************************** + + Notes: + ----------------------------------------------- + Transparency + ----------------------------------------------- + Use destTransPolarity, colorTransCmpSrc, and destTransColor to + determine if the destination needs to be updated. All told, it should + lay out like this: + + destTransPolarity == 0 + colorTransCmpSrc == 0 + Compare destTransColor to the source pixel. + If ==, do not update the destination. + + That is, treat all destTransColor colored pixels + in the source as transparent. + + colorTransCmpSrc == 1 + Compare destTransColor to the destination pixel. + If ==, do not update the destination. + + That is, leave all destTransColor colored pixels + in the destination alone. + + destTransPolarity == 1 + colorTransCmpSrc == 0 + Compare destTransColor to the source pixel. + If !=, do not update the destination. + + That is, transfer all destTransColor colored pixels + from the source to the destination. + + colorTransCmpSrc == 1 + Compare destTransColor to the destination pixel. + If !=, do not update the destination. + + That is, update all destTransColor colored pixels + in the destination with source pixels. + + ROPs + ----------------------------------------------- + Take the pattern, source, and destination, and consider each value one + bit at a time. The three bits from the three values can form eight + combinations. The raster opcode is a bitfield containing the desired + output from each of the combinations. Thus: + + P S D O (output) + --- --- --- --- + 0 0 0 b0 + 0 0 1 b1 + 0 1 0 b2 + 0 1 1 b3 + 1 0 0 b4 + 1 0 1 b5 + 1 1 0 b6 + 1 1 1 b7 + + The output is the byte <b7><b6><b5><b4><b3><b2><b1><b0>. And this + output value is what becomes the raster opcode. Thus, if the raster + opcode is, for example, 0xCC, the table would be: + + P S D O (output) + --- --- --- --- + 0 0 0 0 + 0 0 1 0 + 0 1 0 1 + 0 1 1 1 + 1 0 0 0 + 1 0 1 0 + 1 1 0 1 + 1 1 1 1 + + So, the we look at three bits from the source and they're all zero, + then the output is zero. If they're all one, then the output is one. + If the pattern is one and the source and destination are zero, then + the output is zero. Overall, + + Output[x] = ROP[P[x],S[x],D[x]] + + where "x" is 0..7, and "P[x],S[x],D[x]" is a bitfield composed of the + given bits. + +\* --------------------------------------------------------------------------- */ + +// Given a register (specified by its field name), return its address +// in emulated space. + +#define addressof(x) ( \ + ((emuptr) fRegs.x.GetPtr ()) - \ + ((emuptr) fRegs.GetPtr ()) + \ + ((emuptr) this->GetAddressStart ()) \ + ) + + +// Macro to help the installation of handlers for a register. + +#define INSTALL_HANDLER(read, write, reg) \ + this->SetHandler ( (ReadFunction) &EmRegsMediaQ11xx::read, \ + (WriteFunction) &EmRegsMediaQ11xx::write, \ + addressof (reg), 4) + +// Private inline function for reading a LE register. + +static inline +uint32 PrvReadRegister(uint8* p) +{ +#if EM_HOST_BYTE_ORDER == EM_LITTLE_ENDIAN + + return *(uint32*) p; + +#else + + return + (((UInt32) p[0]) << 0) + + (((UInt32) p[1]) << 8) + + (((UInt32) p[2]) << 16) + + (((UInt32) p[3]) << 24); + +#endif +} + +// Private inline function for writing a LE register + +static inline +void PrvWriteRegister(uint8* p, uint32 value) +{ +#if EM_HOST_BYTE_ORDER == EM_LITTLE_ENDIAN + + *(uint32*) p = value; + +#else + + p[0] = value >> 0; + p[1] = value >> 8; + p[2] = value >> 16; + p[3] = value >> 24; + +#endif +} + + +// Macros to make calling PrvReadRegister and PrvWriteRegister easier. + +#define READ_REGISTER(reg) ::PrvReadRegister ((uint8*) (fRegs.reg.GetPtr ())) +#define WRITE_REGISTER(reg, value) ::PrvWriteRegister ((uint8*) (fRegs.reg.GetPtr ()), value) + + +// ROP values + +#define ROP_SRCCOPY 0xcc +#define ROP_SRCAND 0x88 +//#define ROP_SRCANDNOT 0x77 +#define ROP_SRCANDNOT 0x22 +#define ROP_SRCXOR 0x66 +#define ROP_SRCOR 0xee +#define ROP_SRCCOPYNOT 0x33 +#define ROP_SRCORNOT 0xbb +#define ROP_SRCXORNOT 0x99 + +#define ROP_PATCOPY 0xf0 +#define ROP_PATAND 0xa0 +//#define ROP_PATANDNOT 0x5f +#define ROP_PATANDNOT 0x0a +#define ROP_PATXOR 0x5a +#define ROP_PATOR 0xfa +#define ROP_PATCOPYNOT 0x0f +#define ROP_PATORNOT 0xaf +#define ROP_PATXORNOT 0xa5 + +#define ROP_BLACKNESS 0x00 + + + +#define CMD_FIFO_MASK (0x0000001F) +#define CMD_FIFO_EMPTY (0x00000010) +#define CMD_SRC_MASK (0x00001F00) +#define CMD_SRC_EMPTY (0x00001000) +#define GE_BUSY_H (0x00010000) + + +///////////////////////////////////////////////////////////////////////////// +// Graphics Controller Registers +// +#define GC_CONTROL (0x00) // Graphics Controll Control Reg +#define GC_PWR_SEQ_CONTROL (0x01) // Power Sequencing Control register +#define GC_HTOTAL_HEND (0x02) // Horizontal Display Total & End +#define GC_VTOTAL_VEND (0x03) // Vertical Display Total and End +#define GC_HSYNC (0x04) // Horizontal Sync Start and End +#define GC_VSYNC (0x05) // Vertical Sync Start and End +#define GC_HWINDOW (0x08) // Horizontal Window Start & End +#define GC_VWINDOW (0x09) // Vertical Window Start & End +#define GC_LINE_CLOCK (0x0B) // Line Clock Control +#define GC_START_ADDR (0x0C) // Image Window Start Address +#define GC_ALTWIN_START_ADDR (0x0D) // Alt Image Window Start Address +#define GC_STRIDE (0x0E) // (Alt) Image Window Stride +#define GC_FRAME_CLOCK (0x1A) // Frame Clock Control +#define GC_SIGNALS (0x1B) // Miscellaneous signal register (read only) +#define GC_HPARAM (0x1C) // Horizontal parameter register (read only) +#define GC_VPARAM (0x1D) // Vertical parameter register (read only) + + +// GC_CONTROL register bit definition + +#define GC_ENABLE (1UL << 0) // Controll enabled +#define GC_H_PIX_DBLNG (1UL << 14) // Enable Horizontal Pixel Doubling +#define GC_V_PIX_DBLNG (1UL << 15) // Enable Vertical Scan Line Doubling +#define GC_PIX_DBLNG_MASK (GC_H_PIX_DBLNG | GC_V_PIX_DBLNG) + + +// Palette masks + +#define RED_MASK 0x0000000FC +#define GREEN_MASK 0x00000FC00 +#define BLUE_MASK 0x000FC0000 + + +#define kColorDepth8 0 +#define kColorDepth16 1 + +#define kCommandNOP 0 +#define kCommandBitBLT 2 +#define kCommandLine 4 + +#define kAllRegisters -1 + +static const char* kCommands[] = +{ + "NOP", + "Undefined", + "BitBLT", + "Reserved", + "Line Draw", + "Reserved", + "Undefined", + "Reserved", +}; + +static const char* kDirections[] = +{ + "Positive", + "Negative" +}; + +const struct +{ + uint16 yIsMajor; // 0 = x is major, 1 = y is major + uint16 xDirection; // 0 = x is positive, 1 = x is negative + uint16 yDirection; // 0 = y is positive, 1 = y is negative + const char* text; // Description for debugging. +} kQuadrantDecode[] = +{ + { 0, 0, 0, "x-major, positive x and y directions" }, + { 1, 0, 0, "y-major, positive x and y directions" }, + { 1, 1, 0, "y-major, negative x and positive y directions" }, + { 0, 1, 0, "x-major, negative x and positive y directions" }, + { 0, 1, 1, "x-major, negative x and y directions" }, + { 1, 1, 1, "y-major, negative x and y directions" }, + { 1, 0, 1, "y-major, positive x and negative y directions" }, + { 0, 0, 1, "x-major, positive x and negative y directions" } +}; + +static char* kROPs[] = +{ + "0 BLACKNESS", "DPSoon", "DPSona", "PSon", + "SDPona", "DPon", "PDSxnon", "PDSaon", + "SDPnaa", "PDSxon", "DPna", "PSDnaon", + "SPna", "PDSnaon", "PDSonon", "Pn", + "PDSona", "DSon NOTSRCERASE", "SDPxnon", "SDPaon", + "DPSxnon", "DPSaon", "PSDPSanaxx", "SSPxDSxaxn", + "SPxPDxa", "SDPSanaxn", "PDSPaox", "SDPSxaxn", + "PSDPaox", "DSPDxaxn", "PDSox", "PDSoan", + "DPSnaa", "SDPxon", "DSna", "SPDnaon", + "SPxDSxa", "PDSPanaxn", "SDPSaox", "SDPSxnox", + "DPSxa", "PSDPSaoxxn", "DPSana", "SSPxPDxaxn", + "SPDSoax", "PSDnox", "PSDPxox", "PSDnoan", + "PSna", "SDPnaon", "SDPSoox", "Sn NOTSRCCOPY", + "SPDSaox", "SPDSxnox", "SDPox", "SDPoan", + "PSDPoax", "SPDnox", "SPDSxox", "SPDnoan", + "PSx", "SPDSonox", "SPDSnaox", "PSan", + "PSDnaa", "DPSxon", "SDxPDxa", "SPDSanaxn", + "SDna SRCERASE", "DPSnaon", "DSPDaox", "PSDPxaxn", + "SDPxa", "PDSPDaoxxn", "DPSDoax", "PDSnox", + "SDPana", "SSPxDSxoxn", "PDSPxox", "PDSnoan", + "PDna", "DSPnaon", "DPSDaox", "SPDSxaxn", + "DPSonon", "Dn DSTINVERT", "DPSox", "DPSoan", + "PDSPoax", "DPSnox", "DPx PATINVERT", "DPSDonox", + "DPSDxox", "DPSnoan", "DPSDnaox", "DPan", + "PDSxa", "DSPDSaoxxn", "DSPDoax", "SDPnox", + "SDPSoax", "DSPnox", "DSx SRCINVERT", "SDPSonox", + "DSPDSonoxxn", "PDSxxn", "DPSax", "PSDPSoaxxn", + "SDPax", "PDSPDoaxxn", "SDPSnoax", "PDSxnan", + "PDSana", "SSDxPDxaxn", "SDPSxox", "SDPnoan", + "DSPDxox", "DSPnoan", "SDPSnaox", "DSan", + "PDSax", "DSPDSoaxxn", "DPSDnoax", "SDPxnan", + "SPDSnoax", "DPSxnan", "SPxDSxo", "DPSaan", + "DPSaa", "SPxDSxon", "DPSxna", "SPDSnoaxn", + "SDPxna", "PDSPnoaxn", "DSPDSoaxx", "PDSaxn", + "DSa SRCAND", "SDPSnaoxn", "DSPnoa", "DSPDxoxn", + "SDPnoa", "SDPSxoxn", "SSDxPDxax", "PDSanan", + "PDSxna", "SDPSnoaxn", "DPSDPoaxx", "SPDaxn", + "PSDPSoaxx", "DPSaxn", "DPSxx", "PSDPSonoxx", + "SDPSonoxn", "DSxn", "DPSnax", "SDPSoaxn", + "SPDnax", "DSPDoaxn", "DSPDSaoxx", "PDSxan", + "DPa", "PDSPnaoxn", "DPSnoa", "DPSDxoxn", + "PDSPonoxn", "PDxn", "DSPnax", "PDSPoaxn", + "DPSoa", "DPSoxn", "D", "DPSono", + "SPDSxax", "DPSDaoxn", "DSPnao", "DPno", + "PDSnoa", "PDSPxoxn", "SSPxDSxox", "SDPanan", + "PSDnax", "DPSDoaxn", "DPSDPaoxx", "SDPxan", + "PSDPxax", "DSPDaoxn", "DPSnao", "DSno MERGEPAINT", + "SPDSanax", "SDxPDxan", "DPSxo", "DPSano", + "PSa MERGECOPY", "SPDSnaoxn", "SPDSonoxn", "PSxn", + "SPDnoa", "SPDSxoxn", "SDPnax", "PSDPoaxn", + "SDPoa", "SPDoxn", "DPSDxax", "SPDSaoxn", + "S SRCCOPY", "SDPono", "SDPnao", "SPno", + "PSDnoa", "PSDPxoxn", "PDSnax", "SPDSoaxn", + "SSPxPDxax", "DPSanan", "PSDPSaoxx", "DPSxan", + "PDSPxax", "SDPSaoxn", "DPSDanax", "SPxDSxan", + "SPDnao", "SDno", "SDPxo", "SDPano", + "PDSoa", "PDSoxn", "DSPDxax", "PSDPaoxn", + "SDPSxax", "PDSPaoxn", "SDPSanax", "SPxPDxan", + "SSPxDSxax", "DSPDSanaxxn", "DPSao", "DPSxno", + "SDPao", "SDPxno", "DSo SRCPAINT", "SDPnoo", + "P PATCOPY", "PDSono", "PDSnao", "PSno", + "PSDnao", "PDno", "PDSxo", "PDSano", + "PDSao", "PDSxno", "DPo", "DPSnoo PATPAINT", + "PSo", "PSDnoo", "DPSoo", "1 WHITENESS" +}; + + +// Inline functions. + +inline uint32 EmRegsMediaQ11xx::PrvGetBPP (void) +{ + return 1 << ((READ_REGISTER (gcREG[GC_CONTROL]) & 0x00000070) >> 4); +} + +inline uint32 EmRegsMediaQ11xx::PrvGetWidth (void) +{ + return (READ_REGISTER (gcREG[GC_HWINDOW]) >> 16) + 1; +} + +inline uint32 EmRegsMediaQ11xx::PrvGetHeight (void) +{ + return (READ_REGISTER (gcREG[GC_VWINDOW]) >> 16) + 1; +} + +inline uint32 EmRegsMediaQ11xx::PrvGetRowBytes (void) +{ + return READ_REGISTER (gcREG[GC_STRIDE]) & 0x0000FFFF; +} + +inline uint32 EmRegsMediaQ11xx::PrvGetVideoOffset (void) +{ + return READ_REGISTER (gcREG[GC_START_ADDR]) & 0x0003FFFF; +} + +inline emuptr EmRegsMediaQ11xx::PrvGetVideoBase (void) +{ + return fBaseVideoAddr; +} + +inline emuptr EmRegsMediaQ11xx::PrvGetFrameBuffer (void) +{ + return this->PrvGetVideoBase () + this->PrvGetVideoOffset (); +} + +inline Bool EmRegsMediaQ11xx::PrvGetXDoubling (void) +{ + return (READ_REGISTER (gcREG[GC_CONTROL]) & GC_H_PIX_DBLNG) != 0; +} + +inline Bool EmRegsMediaQ11xx::PrvGetYDoubling (void) +{ + return (READ_REGISTER (gcREG[GC_CONTROL]) & GC_V_PIX_DBLNG) != 0; +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::EmRegsMediaQ11xx +// --------------------------------------------------------------------------- + +EmRegsMediaQ11xx::EmRegsMediaQ11xx (emuptr baseRegsAddr, emuptr baseVideoAddr) : + fBaseRegsAddr (baseRegsAddr), + fBaseVideoAddr (baseVideoAddr), + fRegs (), +/* fState (), */ +/* fByteLanes (), */ + fLastAddress (EmMemNULL), + fLastSize (0), + fSourceFifo (), + fBlitInProgress (false), + fCurXOffset (0), + fCurYOffset (0), + fUsesPattern (false), + fUsesSource (false), + fLeadingSourcePixels (0), + fTrailingSourcePixels (0), +/* fPatternPipe (), */ + fXPattern (0), + fYPattern (0), +/* fSourcePipe (), */ + fSourcePipeIndex (0), + fSourcePipeMax (0), + fSourcePipeSkip (0), + fXSrc (0), + fYSrc (0), + fXDest (0), + fYDest (0) +{ +#if LOG_LINE || LOG_BLIT + LogGetStdLog ()->SetLogSize (32 * 1024L * 1024L); +#endif + + COMPILE_TIME_ASSERT(countof (kCommands) == 8); + COMPILE_TIME_ASSERT(countof (kDirections) == 2); + COMPILE_TIME_ASSERT(countof (kQuadrantDecode) == 8); + COMPILE_TIME_ASSERT(countof (kROPs) == 256); +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::~EmRegsMediaQ11xx +// --------------------------------------------------------------------------- + +EmRegsMediaQ11xx::~EmRegsMediaQ11xx (void) +{ +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::Initialize +// --------------------------------------------------------------------------- + +void EmRegsMediaQ11xx::Initialize (void) +{ + EmRegs::Initialize (); +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::Reset +// --------------------------------------------------------------------------- + +void EmRegsMediaQ11xx::Reset (Bool hardwareReset) +{ + EmRegs::Reset (hardwareReset); + + if (hardwareReset) + { + WRITE_REGISTER (ccREG[0x00], 0x00000000); + WRITE_REGISTER (ccREG[0x01], 0x00000000); + WRITE_REGISTER (ccREG[0x02], 0x00000000); + WRITE_REGISTER (ccREG[0x03], 0x00000000); + WRITE_REGISTER (ccREG[0x04], 0x00000000); + + WRITE_REGISTER (mmREG[0x00], 0x00000000); // (Low nybble only) + WRITE_REGISTER (mmREG[0x01], 0x00000000); // (Low nybble only) + WRITE_REGISTER (mmREG[0x02], 0x00000000); // (Low nybble only) + + WRITE_REGISTER (inREG[0x00], 0x00000000); + WRITE_REGISTER (inREG[0x01], 0x00000000); + WRITE_REGISTER (inREG[0x02], 0x00000000); + WRITE_REGISTER (inREG[0x03], 0x00000000); + + WRITE_REGISTER (gcREG[0x00], 0x00000000); + WRITE_REGISTER (gcREG[0x01], 0x00000000); // (Low byte only) + WRITE_REGISTER (gcREG[0x06], 0x00000000); // (Low word only) + WRITE_REGISTER (gcREG[0x07], 0x00000000); // (Low word only) + + // GC_CONTROL (0x00) // Graphics Controll Control Reg + // GC_PWR_SEQ_CONTROL (0x01) // Power Sequencing Control register + // GC_HTOTAL_HEND (0x02) // Horizontal Display Total & End + // GC_VTOTAL_VEND (0x03) // Vertical Display Total and End + // GC_HSYNC (0x04) // Horizontal Sync Start and End + // GC_VSYNC (0x05) // Vertical Sync Start and End + // GC_HWINDOW (0x08) // Horizontal Window Start & End + // GC_VWINDOW (0x09) // Vertical Window Start & End + // GC_LINE_CLOCK (0x0B) // Line Clock Control + // GC_START_ADDR (0x0C) // Image Window Start Address + // GC_ALTWIN_START_ADDR (0x0D) // Alt Image Window Start Address + // GC_STRIDE (0x0E) // (Alt) Image Window Stride + // GC_FRAME_CLOCK (0x1A) // Frame Clock Control + + // For now, let's initialize all the graphics controller registers to 0. + for (int i = 0x00; i < 0x20; i++) + { + WRITE_REGISTER (gcREG[i], 0x00000000); + } + + WRITE_REGISTER (geREG[0x00], 0x00000000); + WRITE_REGISTER (geREG[0x0C], 0x00000000); + + WRITE_REGISTER (ssREG[0x00], 0x00000000); + WRITE_REGISTER (ssREG[0x01], 0x00000000); + WRITE_REGISTER (ssREG[0x04], 0x00000000); // (Low nybble only) + WRITE_REGISTER (ssREG[0x08], 0x00000000); // (Low byte only) + WRITE_REGISTER (ssREG[0x09], 0x00000000); // (Low byte only) + WRITE_REGISTER (ssREG[0x0A], 0x00000000); // (Low byte only) + WRITE_REGISTER (ssREG[0x0B], 0x00000000); // (Low byte only) + WRITE_REGISTER (ssREG[0x10], 0x00000000); + WRITE_REGISTER (ssREG[0x11], 0x00000000); + WRITE_REGISTER (ssREG[0x13], 0x00000000); + + WRITE_REGISTER (spREG[0x00], 0x00000000); + WRITE_REGISTER (spREG[0x01], 0xF0000000); + WRITE_REGISTER (spREG[0x02], 0x00000000); + WRITE_REGISTER (spREG[0x03], 0x00000000); + WRITE_REGISTER (spREG[0x04], 0x00000000); + WRITE_REGISTER (spREG[0x05], 0x00000000); + WRITE_REGISTER (spREG[0x06], 0x00000000); + WRITE_REGISTER (spREG[0x07], 0x00000000); + WRITE_REGISTER (spREG[0x08], 0x00000000); + + WRITE_REGISTER (dcREG[0x00], 0x00000000); + WRITE_REGISTER (dcREG[0x01], 0xF0000000); + WRITE_REGISTER (dcREG[0x02], 0x00000000); + WRITE_REGISTER (dcREG[0x03], 0x00000000); + WRITE_REGISTER (dcREG[0x04], 0x00000000); + WRITE_REGISTER (dcREG[0x05], 0x00000000); + WRITE_REGISTER (dcREG[0x06], 0x00000000); + WRITE_REGISTER (dcREG[0x07], 0x00000000); + + WRITE_REGISTER (pcREG[0x00], 0x01204D51); + WRITE_REGISTER (pcREG[0x01], 0x02800000); + WRITE_REGISTER (pcREG[0x02], 0x03800000); + WRITE_REGISTER (pcREG[0x03], 0x00000000); + WRITE_REGISTER (pcREG[0x0B], 0x00000100); + WRITE_REGISTER (pcREG[0x0F], 0x00000100); + + WRITE_REGISTER (uhREG[0x00], 0x00000010); // (Low byte only) + WRITE_REGISTER (uhREG[0x01], 0x00000000); + WRITE_REGISTER (uhREG[0x02], 0x00000000); + WRITE_REGISTER (uhREG[0x03], 0x00000000); + WRITE_REGISTER (uhREG[0x04], 0x00000000); + WRITE_REGISTER (uhREG[0x05], 0x00000000); + WRITE_REGISTER (uhREG[0x06], 0x00000000); + WRITE_REGISTER (uhREG[0x07], 0x00000000); + WRITE_REGISTER (uhREG[0x08], 0x00000000); + WRITE_REGISTER (uhREG[0x09], 0x00000000); + WRITE_REGISTER (uhREG[0x0A], 0x00000000); + WRITE_REGISTER (uhREG[0x0B], 0x00000000); + WRITE_REGISTER (uhREG[0x0C], 0x00000000); + WRITE_REGISTER (uhREG[0x0D], 0x00002EDF); + WRITE_REGISTER (uhREG[0x0E], 0x00000000); + WRITE_REGISTER (uhREG[0x0F], 0x00000000); + WRITE_REGISTER (uhREG[0x10], 0x00000000); // (Low word only) + WRITE_REGISTER (uhREG[0x11], 0x00000628); + WRITE_REGISTER (uhREG[0x12], 0x00001102); + WRITE_REGISTER (uhREG[0x13], 0x00000000); + WRITE_REGISTER (uhREG[0x14], 0x00000000); + WRITE_REGISTER (uhREG[0x15], 0x00000000); + WRITE_REGISTER (uhREG[0x16], 0x00000000); + + WRITE_REGISTER (fpREG[0x00], 0x00000000); + WRITE_REGISTER (fpREG[0x01], 0x00000000); + WRITE_REGISTER (fpREG[0x02], 0x0FFCFCFF); + WRITE_REGISTER (fpREG[0x03], 0x00000000); + WRITE_REGISTER (fpREG[0x04], 0x00000000); + WRITE_REGISTER (fpREG[0x05], 0x00000000); + WRITE_REGISTER (fpREG[0x06], 0x00000000); + WRITE_REGISTER (fpREG[0x07], 0x00000000); + WRITE_REGISTER (fpREG[0x0A], 0xF0030000); + WRITE_REGISTER (fpREG[0x0B], 0x00000000); // (Low 12-bits only) + WRITE_REGISTER (fpREG[0x0E], 0x00000000); // (Low byte only) + WRITE_REGISTER (fpREG[0x0F], 0x00000000); + + // (No reset values for color palette and source FIFO) + + WRITE_REGISTER (udREG[0x00], 0x00000000); + WRITE_REGISTER (udREG[0x01], 0x00000000); + WRITE_REGISTER (udREG[0x02], 0x00000000); + WRITE_REGISTER (udREG[0x03], 0x00000000); + WRITE_REGISTER (udREG[0x04], 0x00000000); + WRITE_REGISTER (udREG[0x05], 0x00000000); + WRITE_REGISTER (udREG[0x06], 0x00000000); + WRITE_REGISTER (udREG[0x07], 0x00000000); + WRITE_REGISTER (udREG[0x08], 0x00000000); + WRITE_REGISTER (udREG[0x09], 0x00000000); + WRITE_REGISTER (udREG[0x0A], 0x00000000); + WRITE_REGISTER (udREG[0x0B], 0x00000000); // (Low byte only) + WRITE_REGISTER (udREG[0x0C], 0x00000000); + WRITE_REGISTER (udREG[0x0D], 0x00000000); + WRITE_REGISTER (udREG[0x0E], 0x00000000); + WRITE_REGISTER (udREG[0x0F], 0x00000000); + WRITE_REGISTER (udREG[0x00], 0x00000000); + WRITE_REGISTER (udREG[0x01], 0x00000000); + WRITE_REGISTER (udREG[0x02], 0x00000000); + + // Because DC00R is reset to zero, establish the + // byteswapping lanes corresponding to that. + + this->PrvUpdateByteLanes (); + + fLastAddress = EmMemNULL; + fLastSize = 0; + + fBlitInProgress = false; + + this->PrvGetGEState (kAllRegisters); + } +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::Save +// --------------------------------------------------------------------------- + +void EmRegsMediaQ11xx::Save (SessionFile& f) +{ + const long kCurrentMediaQVersion = 1; + + EmRegs::Save (f); + + Chunk chunk; + EmStreamChunk s (chunk); + + s << kCurrentMediaQVersion; + + s.PutBytes (fRegs.GetPtr (), fRegs.GetSize ()); + + f.WriteMediaQRegsType (chunk); +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::Load +// --------------------------------------------------------------------------- + +void EmRegsMediaQ11xx::Load (SessionFile& f) +{ + EmRegs::Load (f); + + Chunk chunk; + + if (!f.ReadMediaQRegsType (chunk)) + { + f.SetCanReload (false); + } + else + { + long version; + + EmStreamChunk s (chunk); + + s >> version; + + if (version >= 1) + { + s.GetBytes (fRegs.GetPtr (), fRegs.GetSize ()); + } + } + + this->PrvUpdateByteLanes (); + + // !!! Save and restore these? + + fLastAddress = EmMemNULL; + fLastSize = 0; + + fBlitInProgress = false; + + this->PrvGetGEState (kAllRegisters); +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::Dispose +// --------------------------------------------------------------------------- + +void EmRegsMediaQ11xx::Dispose (void) +{ + EmRegs::Dispose (); +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::SetSubBankHandlers +// --------------------------------------------------------------------------- + +void EmRegsMediaQ11xx::SetSubBankHandlers (void) +{ + // Install base handlers. + + EmRegs::SetSubBankHandlers (); + + // Now add standard/specialized handers for the defined registers. + + INSTALL_HANDLER (MQRead, MQWrite, ccREG[0x00]); + INSTALL_HANDLER (CC01Read, MQWrite, ccREG[0x01]); + INSTALL_HANDLER (MQRead, MQWrite, ccREG[0x02]); + INSTALL_HANDLER (MQRead, MQWrite, ccREG[0x03]); + INSTALL_HANDLER (MQRead, MQWrite, ccREG[0x04]); + + INSTALL_HANDLER (MQRead, MQWrite, mmREG[0x00]); + INSTALL_HANDLER (MQRead, MQWrite, mmREG[0x01]); + INSTALL_HANDLER (MQRead, MQWrite, mmREG[0x02]); + INSTALL_HANDLER (MQRead, MQWrite, mmREG[0x03]); + INSTALL_HANDLER (MQRead, MQWrite, mmREG[0x04]); + + INSTALL_HANDLER (MQRead, MQWrite, inREG[0x00]); + INSTALL_HANDLER (MQRead, MQWrite, inREG[0x01]); + INSTALL_HANDLER (MQRead, MQWrite, inREG[0x02]); + INSTALL_HANDLER (MQRead, MQWrite, inREG[0x03]); + + INSTALL_HANDLER (MQRead, invalidateWrite, gcREG[0x00]); // BPP (et al) + INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x01]); + INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x02]); + INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x03]); + INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x04]); + INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x05]); + INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x06]); + INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x07]); + INSTALL_HANDLER (MQRead, invalidateWrite, gcREG[0x08]); // Width + INSTALL_HANDLER (MQRead, invalidateWrite, gcREG[0x09]); // Height + INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x0A]); + INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x0B]); + INSTALL_HANDLER (MQRead, invalidateWrite, gcREG[0x0C]); // Base Address + INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x0D]); + INSTALL_HANDLER (MQRead, invalidateWrite, gcREG[0x0E]); // Stride + INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x0F]); + INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x10]); + INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x11]); + INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x12]); + INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x13]); + INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x14]); + INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x15]); + INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x16]); + INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x17]); + INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x18]); + INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x19]); + INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x1A]); + INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x1B]); + INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x1C]); + INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x1D]); + INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x1E]); + INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x1F]); + + INSTALL_HANDLER (MQRead, GE00Write, geREG[0x00]); + INSTALL_HANDLER (MQRead, MQWrite, geREG[0x01]); + INSTALL_HANDLER (MQRead, GE02Write, geREG[0x02]); + INSTALL_HANDLER (MQRead, MQWrite, geREG[0x03]); + INSTALL_HANDLER (MQRead, MQWrite, geREG[0x04]); + INSTALL_HANDLER (MQRead, MQWrite, geREG[0x05]); + INSTALL_HANDLER (MQRead, MQWrite, geREG[0x06]); + INSTALL_HANDLER (MQRead, MQWrite, geREG[0x07]); + INSTALL_HANDLER (MQRead, MQWrite, geREG[0x08]); + INSTALL_HANDLER (MQRead, MQWrite, geREG[0x09]); + INSTALL_HANDLER (MQRead, MQWrite, geREG[0x0A]); + INSTALL_HANDLER (MQRead, MQWrite, geREG[0x0B]); + INSTALL_HANDLER (MQRead, MQWrite, geREG[0x0C]); + INSTALL_HANDLER (MQRead, MQWrite, geREG[0x0D]); + INSTALL_HANDLER (MQRead, MQWrite, geREG[0x0E]); + INSTALL_HANDLER (MQRead, MQWrite, geREG[0x0F]); + INSTALL_HANDLER (MQRead, MQWrite, geREG[0x10]); + INSTALL_HANDLER (MQRead, MQWrite, geREG[0x11]); + INSTALL_HANDLER (MQRead, MQWrite, geREG[0x12]); + INSTALL_HANDLER (MQRead, MQWrite, geREG[0x13]); + + INSTALL_HANDLER (MQRead, MQWrite, ssREG[0x00]); + INSTALL_HANDLER (MQRead, MQWrite, ssREG[0x01]); + INSTALL_HANDLER (MQRead, MQWrite, ssREG[0x04]); // Skip some here + INSTALL_HANDLER (MQRead, MQWrite, ssREG[0x08]); // Skip some here + INSTALL_HANDLER (MQRead, MQWrite, ssREG[0x09]); + INSTALL_HANDLER (MQRead, MQWrite, ssREG[0x0A]); + INSTALL_HANDLER (MQRead, MQWrite, ssREG[0x0B]); + INSTALL_HANDLER (MQRead, MQWrite, ssREG[0x0C]); + INSTALL_HANDLER (MQRead, MQWrite, ssREG[0x0D]); + INSTALL_HANDLER (MQRead, MQWrite, ssREG[0x10]); // Skip some here + INSTALL_HANDLER (MQRead, MQWrite, ssREG[0x11]); + INSTALL_HANDLER (MQRead, MQWrite, ssREG[0x12]); + INSTALL_HANDLER (MQRead, MQWrite, ssREG[0x13]); + INSTALL_HANDLER (MQRead, MQWrite, ssREG[0x14]); + INSTALL_HANDLER (MQRead, MQWrite, ssREG[0x15]); + + INSTALL_HANDLER (MQRead, MQWrite, spREG[0x00]); + INSTALL_HANDLER (MQRead, MQWrite, spREG[0x01]); + INSTALL_HANDLER (MQRead, MQWrite, spREG[0x02]); + INSTALL_HANDLER (MQRead, MQWrite, spREG[0x03]); + INSTALL_HANDLER (MQRead, MQWrite, spREG[0x04]); + INSTALL_HANDLER (MQRead, MQWrite, spREG[0x05]); + INSTALL_HANDLER (MQRead, MQWrite, spREG[0x06]); + INSTALL_HANDLER (MQRead, MQWrite, spREG[0x07]); + INSTALL_HANDLER (MQRead, MQWrite, spREG[0x08]); + + INSTALL_HANDLER (MQRead, DC00Write, dcREG[0x00]); + INSTALL_HANDLER (MQRead, MQWrite, dcREG[0x01]); + INSTALL_HANDLER (MQRead, MQWrite, dcREG[0x02]); + INSTALL_HANDLER (MQRead, MQWrite, dcREG[0x03]); + INSTALL_HANDLER (MQRead, MQWrite, dcREG[0x04]); + INSTALL_HANDLER (MQRead, MQWrite, dcREG[0x05]); + INSTALL_HANDLER (MQRead, MQWrite, dcREG[0x06]); + INSTALL_HANDLER (MQRead, MQWrite, dcREG[0x07]); + + INSTALL_HANDLER (MQRead, MQWrite, pcREG[0x00]); + INSTALL_HANDLER (MQRead, MQWrite, pcREG[0x01]); + INSTALL_HANDLER (MQRead, MQWrite, pcREG[0x02]); + INSTALL_HANDLER (MQRead, MQWrite, pcREG[0x03]); + INSTALL_HANDLER (MQRead, MQWrite, pcREG[0x04]); + INSTALL_HANDLER (MQRead, MQWrite, pcREG[0x05]); + INSTALL_HANDLER (MQRead, MQWrite, pcREG[0x0B]); // Skip some here + INSTALL_HANDLER (MQRead, MQWrite, pcREG[0x0F]); // Skip some here + + INSTALL_HANDLER (MQRead, MQWrite, uhREG[0x00]); + INSTALL_HANDLER (MQRead, MQWrite, uhREG[0x01]); + INSTALL_HANDLER (MQRead, MQWrite, uhREG[0x02]); + INSTALL_HANDLER (MQRead, MQWrite, uhREG[0x03]); + INSTALL_HANDLER (MQRead, MQWrite, uhREG[0x04]); + INSTALL_HANDLER (MQRead, MQWrite, uhREG[0x05]); + INSTALL_HANDLER (MQRead, MQWrite, uhREG[0x06]); + INSTALL_HANDLER (MQRead, MQWrite, uhREG[0x07]); + INSTALL_HANDLER (MQRead, MQWrite, uhREG[0x08]); + INSTALL_HANDLER (MQRead, MQWrite, uhREG[0x09]); + INSTALL_HANDLER (MQRead, MQWrite, uhREG[0x0A]); + INSTALL_HANDLER (MQRead, MQWrite, uhREG[0x0B]); + INSTALL_HANDLER (MQRead, MQWrite, uhREG[0x0C]); + INSTALL_HANDLER (MQRead, MQWrite, uhREG[0x0D]); + INSTALL_HANDLER (MQRead, MQWrite, uhREG[0x0E]); + INSTALL_HANDLER (MQRead, MQWrite, uhREG[0x0F]); + INSTALL_HANDLER (MQRead, MQWrite, uhREG[0x10]); + INSTALL_HANDLER (MQRead, MQWrite, uhREG[0x11]); + INSTALL_HANDLER (MQRead, MQWrite, uhREG[0x12]); + INSTALL_HANDLER (MQRead, MQWrite, uhREG[0x13]); + INSTALL_HANDLER (MQRead, MQWrite, uhREG[0x14]); + INSTALL_HANDLER (MQRead, MQWrite, uhREG[0x15]); + INSTALL_HANDLER (MQRead, MQWrite, uhREG[0x16]); + + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x00]); + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x01]); + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x02]); + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x03]); + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x04]); + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x05]); + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x06]); + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x07]); + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x08]); + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x09]); + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x0A]); + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x0B]); + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x0E]); // Skip some here + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x0F]); + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x10]); + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x11]); + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x12]); + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x13]); + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x14]); + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x15]); + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x16]); + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x17]); + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x18]); + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x19]); + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x1A]); + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x1B]); + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x1C]); + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x1D]); + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x1E]); + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x1F]); + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x20]); + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x21]); + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x22]); + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x23]); + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x24]); + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x25]); + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x26]); + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x27]); + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x28]); + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x29]); + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x2A]); + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x2B]); + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x2C]); + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x2D]); + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x2E]); + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x2F]); + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x30]); + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x31]); + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x32]); + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x33]); + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x34]); + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x35]); + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x36]); + INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x37]); + + this->SetHandler ( (ReadFunction) &EmRegsMediaQ11xx::MQRead, + (WriteFunction) &EmRegsMediaQ11xx::invalidateWrite, + addressof (cpREG), 0x0400); + + this->SetHandler ( (ReadFunction) &EmRegsMediaQ11xx::MQRead, + (WriteFunction) &EmRegsMediaQ11xx::SourceFifoWrite, + addressof (sfREG), 0x0400); + + INSTALL_HANDLER (MQRead, MQWrite, udREG[0x00]); + INSTALL_HANDLER (MQRead, MQWrite, udREG[0x01]); + INSTALL_HANDLER (MQRead, MQWrite, udREG[0x02]); + INSTALL_HANDLER (MQRead, MQWrite, udREG[0x03]); + INSTALL_HANDLER (MQRead, MQWrite, udREG[0x04]); + INSTALL_HANDLER (MQRead, MQWrite, udREG[0x05]); + INSTALL_HANDLER (MQRead, MQWrite, udREG[0x06]); + INSTALL_HANDLER (MQRead, MQWrite, udREG[0x07]); + INSTALL_HANDLER (MQRead, MQWrite, udREG[0x08]); + INSTALL_HANDLER (MQRead, MQWrite, udREG[0x09]); + INSTALL_HANDLER (MQRead, MQWrite, udREG[0x0A]); + INSTALL_HANDLER (MQRead, MQWrite, udREG[0x0B]); + INSTALL_HANDLER (MQRead, MQWrite, udREG[0x0C]); + INSTALL_HANDLER (MQRead, MQWrite, udREG[0x0D]); + INSTALL_HANDLER (MQRead, MQWrite, udREG[0x0E]); + INSTALL_HANDLER (MQRead, MQWrite, udREG[0x0F]); + INSTALL_HANDLER (MQRead, MQWrite, udREG[0x10]); + INSTALL_HANDLER (MQRead, MQWrite, udREG[0x11]); + INSTALL_HANDLER (MQRead, MQWrite, udREG[0x12]); +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::GetRealAddress +// --------------------------------------------------------------------------- + +uint8* EmRegsMediaQ11xx::GetRealAddress (emuptr address) +{ + return (uint8*) fRegs.GetPtr () + (address - this->GetAddressStart ()); +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::GetAddressStart +// --------------------------------------------------------------------------- + +emuptr EmRegsMediaQ11xx::GetAddressStart (void) +{ + return fBaseRegsAddr; +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::GetAddressRange +// --------------------------------------------------------------------------- + +uint32 EmRegsMediaQ11xx::GetAddressRange (void) +{ + return fRegs.GetSize (); +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::GetLCDScreenOn +// --------------------------------------------------------------------------- + +Bool EmRegsMediaQ11xx::GetLCDScreenOn (void) +{ + return ((READ_REGISTER (gcREG[GC_CONTROL]) & GC_ENABLE) != 0); +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::GetLCDBacklightOn +// --------------------------------------------------------------------------- + +Bool EmRegsMediaQ11xx::GetLCDBacklightOn (void) +{ + return true; +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::GetLCDHasFrame +// --------------------------------------------------------------------------- + +Bool EmRegsMediaQ11xx::GetLCDHasFrame (void) +{ + return true; +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::GetLCDBeginEnd +// --------------------------------------------------------------------------- + +void EmRegsMediaQ11xx::GetLCDBeginEnd (emuptr& begin, emuptr& end) +{ + int32 height = this->PrvGetHeight (); + int32 rowBytes = this->PrvGetRowBytes (); + emuptr baseAddr = this->PrvGetFrameBuffer (); + + begin = baseAddr; + end = baseAddr + rowBytes * height; +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::GetLCDScanlines +// --------------------------------------------------------------------------- + +void EmRegsMediaQ11xx::GetLCDScanlines (EmScreenUpdateInfo& info) +{ + // Get the screen metrics. + int32 bpp = this->PrvGetBPP (); + int32 width = this->PrvGetWidth (); + int32 height = this->PrvGetHeight (); + int32 rowBytes = this->PrvGetRowBytes (); + emuptr baseAddr = this->PrvGetFrameBuffer (); + +#ifdef _DEBUG + Bool xDoubling = this->PrvGetXDoubling (); + Bool yDoubling = this->PrvGetYDoubling (); + + EmAssert (xDoubling == 0 && yDoubling == 0); +#endif + + info.fLeftMargin = 0; + + if (bpp <= 8) + { + EmPixMapFormat format = bpp == 1 ? kPixMapFormat1 : + bpp == 2 ? kPixMapFormat2 : + bpp == 4 ? kPixMapFormat4 : + kPixMapFormat8; + + RGBList colorTable; + this->PrvGetPalette (colorTable); + + // Set format, size, and color table of EmPixMap. + + info.fImage.SetSize (EmPoint (width, height)); + info.fImage.SetFormat (format); + info.fImage.SetRowBytes (rowBytes); + info.fImage.SetColorTable (colorTable); + + // Determine first and last scanlines to fetch, and fetch them. + + info.fFirstLine = (info.fScreenLow - baseAddr) / rowBytes; + info.fLastLine = (info.fScreenHigh - baseAddr - 1) / rowBytes + 1; + + long firstLineOffset = info.fFirstLine * rowBytes; + long lastLineOffset = info.fLastLine * rowBytes; + + EmMem_memcpy ( + (void*) ((uint8*) info.fImage.GetBits () + firstLineOffset), + baseAddr + firstLineOffset, + lastLineOffset - firstLineOffset); + } + else + { + // Set depth, size, and color table of EmPixMap. + + info.fImage.SetSize (EmPoint (width, height)); + info.fImage.SetFormat (kPixMapFormat24RGB); + + // Determine first and last scanlines to fetch. + + info.fFirstLine = (info.fScreenLow - baseAddr) / rowBytes; + info.fLastLine = (info.fScreenHigh - baseAddr - 1) / rowBytes + 1; + + // Get location and rowBytes of source bytes. + + uint8* srcStart = EmMemGetRealAddress (baseAddr); + int32 srcRowBytes = rowBytes; + uint8* srcPtr = srcStart + srcRowBytes * info.fFirstLine; + uint8* srcPtr0 = srcPtr; + + // Get location and rowBytes of destination bytes. + + uint8* destStart = (uint8*) info.fImage.GetBits (); + int32 destRowBytes = info.fImage.GetRowBytes (); + uint8* destPtr = destStart + destRowBytes * info.fFirstLine; + uint8* destPtr0 = destPtr; + + // Get height of range to copy. + + int32 height = info.fLastLine - info.fFirstLine; + + // Copy the pixels from source to dest. + + for (int yy = 0; yy < height; ++yy) + { + for (int xx = 0; xx < width; ++xx) + { + uint8 p1 = EmMemDoGet8 (srcPtr++); // GGGBBBBB + uint8 p2 = EmMemDoGet8 (srcPtr++); // RRRRRGGG + + // Merge the two together so that we get RRRRRGGG GGGBBBBB + + uint16 p; + + p = (p1 << 8) | p2; + + // Shift the bits around, forming RRRRRrrr, GGGGGGgg, and + // BBBBBbbb values, where the lower-case bits are copies of + // the least significant bits in the upper-case bits. + // + // Note that all of this could also be done with three 64K + // lookup tables. If speed is an issue, we might want to + // investigate that. + + if (bpp == 1) + { + uint8 green = ((p >> 3) & 0xFC) | ((p >> 5) & 0x03); + *destPtr++ = green; + *destPtr++ = green; + *destPtr++ = green; + } + else + { + *destPtr++ = ((p >> 8) & 0xF8) | ((p >> 11) & 0x07); + *destPtr++ = ((p >> 3) & 0xFC) | ((p >> 5) & 0x03); + *destPtr++ = ((p << 3) & 0xF8) | ((p >> 0) & 0x07); + } + } + + srcPtr = srcPtr0 += srcRowBytes; + destPtr = destPtr0 += destRowBytes; + } + } +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::MQRead +// --------------------------------------------------------------------------- + +uint32 EmRegsMediaQ11xx::MQRead (emuptr address, int size) +{ + // Determine the offset from the beginning of the register memory range + // to the location we want to read. + + uint32 offset = address - this->GetAddressStart (); + + EmAssert (offset < this->GetAddressRange ()); + + // Determine the index for the register being read (treating the entire + // memory range as an array of 32-bit values), and determine the delta + // into the register. + + int index = offset / 4; + int delta = offset - (index * 4); + + EmAssert (delta >= 0); + EmAssert (delta < 4); + + // Get the pointer to the register to read from. + + UInt32 value; + UInt8* p = (UInt8*) fRegs.ccREG[index].GetPtr (); + + if (size == 4) + { + // Make sure we're reading the whole register. + + if ((delta & 3) != 0) + this->AddressError (address, size, true); + + // Get a pointer to the "bytelanes" array that will sort out + // any 32-bit or 16-bit byteswapping for us. + + int* bytelanes = &this->fBytelanes[delta]; + + // Read the value a byte at a time, reconstructing it according + // to the byteswapping rules. + + value = + (((UInt32) p[bytelanes[0]]) << 24) | + (((UInt32) p[bytelanes[1]]) << 16) | + (((UInt32) p[bytelanes[2]]) << 8) | + (((UInt32) p[bytelanes[3]]) << 0); + } + else if (size == 2) + { + // Make sure we're reading from an even address. + // !!! This is really a characteristic of the host + // CPU and bus, not the MediaQ chip. + + if ((delta & 1) != 0) + this->AddressError (address, size, true); + + // Get a pointer to the "bytelanes" array that will sort out + // any 32-bit or 16-bit byteswapping for us. + + int* bytelanes = &this->fBytelanes[delta]; + + // Read the value a byte at a time, reconstructing it according + // to the byteswapping rules. + + value = + (((UInt32) p[bytelanes[0]]) << 8) | + (((UInt32) p[bytelanes[1]]) << 0); + } + else if (size == 1) + { + // Get a pointer to the "bytelanes" array that will sort out + // any 32-bit or 16-bit byteswapping for us. + + int* bytelanes = &this->fBytelanes[delta]; + + // Read the value a byte at a time, reconstructing it according + // to the byteswapping rules. + + value = + (((UInt32) p[bytelanes[0]]) << 0); + } + else + { + EmAssert (false); + value = 0; + } + + return value; +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::MQWrite +// --------------------------------------------------------------------------- + +void EmRegsMediaQ11xx::MQWrite (emuptr address, int size, uint32 value) +{ + // Determine the offset from the beginning of the register memory range + // to the location we want to update. + + uint32 offset = address - this->GetAddressStart (); + + EmAssert (offset < this->GetAddressRange ()); + + // Determine the index for the register being updated (treating the entire + // memory range as an array of 32-bit values), and determine the delta + // into the register. + + int index = offset / 4; + int delta = offset - (index * 4); + + EmAssert (delta >= 0); + EmAssert (delta < 4); + + // Get the pointer to the register to update. + + UInt8* p = (UInt8*) fRegs.ccREG[index].GetPtr (); + + if (size == 4) + { + // Make sure we're updating the whole register. + + if ((delta & 3) != 0) + this->AddressError (address, size, false); + + // Get a pointer to the "bytelanes" array that will sort out + // any 32-bit or 16-bit byteswapping for us. + + int* bytelanes = &this->fBytelanes[delta]; + + // Write the value a byte at a time, using the bytelanes array + // to sort out the byteswapping for us. + + p[bytelanes[0]] = value >> 24; + p[bytelanes[1]] = value >> 16; + p[bytelanes[2]] = value >> 8; + p[bytelanes[3]] = value >> 0; + } + else if (size == 2) + { + // Make sure we're updating to an even address. + // !!! This is really a characteristic of the host + // CPU and bus, not the MediaQ chip. + + if ((delta & 1) != 0) + this->AddressError (address, size, false); + + // Get a pointer to the "bytelanes" array that will sort out + // any 32-bit or 16-bit byteswapping for us. + + int* bytelanes = &this->fBytelanes[delta]; + + // Write the value a byte at a time, using the bytelanes array + // to sort out the byteswapping for us. + + p[bytelanes[0]] = value >> 8; + p[bytelanes[1]] = value >> 0; + } + else if (size == 1) + { + // Get a pointer to the "bytelanes" array that will sort out + // any 32-bit or 16-bit byteswapping for us. + + int* bytelanes = &this->fBytelanes[delta]; + + // Write the value a byte at a time, using the bytelanes array + // to sort out the byteswapping for us. + + p[bytelanes[0]] = value >> 0; + } + else + { + EmAssert (false); + } + + fLastAddress = address; + fLastSize = size; + + if (index >= 0x080 && index <= 0x093) + { + this->PrvGetGEState (index - 0x080); + } +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::CC01Read +// --------------------------------------------------------------------------- + +uint32 EmRegsMediaQ11xx::CC01Read (emuptr address, int size) +{ + // Update the Command FIFO size. + // Update the Source FIFO size. + // Also make sure the busy bit is clear. + + uint32 CC01 = READ_REGISTER (ccREG[0x01]); + + CC01 = (CC01 & ~CMD_FIFO_MASK) | (CMD_FIFO_EMPTY & CMD_FIFO_MASK); + CC01 = (CC01 & ~CMD_SRC_MASK) | (CMD_SRC_EMPTY & CMD_SRC_MASK); + CC01 = CC01 & ~GE_BUSY_H; + + WRITE_REGISTER (ccREG[0x01], CC01); + + // Perform a standard read. + + uint32 result = MQRead (address, size); + + return result; +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::DC00Write +// --------------------------------------------------------------------------- + +void EmRegsMediaQ11xx::DC00Write (emuptr address, int size, uint32 value) +{ + // Perform a standard update. + + this->MQWrite (address, size, value); + + this->PrvUpdateByteLanes (); +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::GE00Write +// --------------------------------------------------------------------------- + +void EmRegsMediaQ11xx::GE00Write (emuptr address, int size, uint32 value) +{ + emuptr lastAddress = this->fLastAddress; + int lastSize = this->fLastSize; + + // Perform a standard update. + + this->MQWrite (address, size, value); + + // If a command was issued, execute it (if autoExecute is false). + + uint32 reg = READ_REGISTER (geREG[0]); + + if ((reg & (1 << 27)) == 0) + { + if (size == 4) + { + this->PrvDoCommand (); + } + else if (size == 2 && lastSize == 2 && address == (lastAddress + 2)) + { + this->PrvDoCommand (); + } + } +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::GE02Write +// --------------------------------------------------------------------------- + +void EmRegsMediaQ11xx::GE02Write (emuptr address, int size, uint32 value) +{ + emuptr lastAddress = this->fLastAddress; + int lastSize = this->fLastSize; + + // Perform a standard update. + + this->MQWrite (address, size, value); + + // If a command was issued, execute it (if autoExecute is true). + + uint32 reg = READ_REGISTER (geREG[0]); + + if ((reg & (1 << 27)) != 0) + { + if (size == 4) + { + this->PrvDoCommand (); + } + else if (size == 2 && lastSize == 2 && address == (lastAddress + 2)) + { + this->PrvDoCommand (); + } + } +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::SourceFifoWrite +// --------------------------------------------------------------------------- + +void EmRegsMediaQ11xx::SourceFifoWrite (emuptr address, int size, uint32 value) +{ + emuptr lastAddress = this->fLastAddress; + int lastSize = this->fLastSize; + + // Perform a standard update. + + this->MQWrite (address, size, value); + + // If a complete entry was added, push it onto the FIFO, and give the + // blitter a chance to run. + + if (size == 4) + { + value = READ_REGISTER (sfREG[(address >> 2) & 0x0FF]); + fSourceFifo.push_back (value); + this->PrvIncBlitterRun (); + } + else if (size == 2 && lastSize == 2 && address == (lastAddress + 2)) + { + value = READ_REGISTER (sfREG[(address >> 2) & 0x0FF]); + fSourceFifo.push_back (value); + this->PrvIncBlitterRun (); + } +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::invalidateWrite +// --------------------------------------------------------------------------- + +void EmRegsMediaQ11xx::invalidateWrite (emuptr address, int size, uint32 value) +{ + // Perform a standard update. + + this->MQWrite (address, size, value); + + // Invalidate the entire LCD area so that it can get redrawn with + // the new palette information. + + EmScreen::InvalidateAll (); +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::AddressError +// --------------------------------------------------------------------------- + +void EmRegsMediaQ11xx::AddressError (emuptr address, long size, Bool forRead) +{ + EmAssert (false); + EmAssert (gCPU68K); + gCPU68K->AddressError (address, size, forRead); +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::PrvGetPalette +// --------------------------------------------------------------------------- + +void EmRegsMediaQ11xx::PrvGetPalette (RGBList& thePalette) +{ + int32 bpp = this->PrvGetBPP (); + int32 numColors = 1 << bpp; + + thePalette.resize (numColors); + + for (int ii = 0; ii < numColors; ++ii) + { + uint32 reg = READ_REGISTER (cpREG[ii]); + + thePalette[ii].fRed = (reg & RED_MASK) >> 0; + thePalette[ii].fGreen = (reg & GREEN_MASK) >> 8; + thePalette[ii].fBlue = (reg & BLUE_MASK) >> 16; + } +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::PrvUpdateByteLanes +// --------------------------------------------------------------------------- +/* + Figuring out byteswapping: + + Our source code has the following function for writing data to registers: + + void sREGW (volatile UCHAR* addr, ULONG data) + { + UInt16 _data16; + UInt16* dc00R = (UInt16*) (MMIO_BASE + DC_BASE); + + if (*dc00R & 1) // no need to swap data (16BPP mode) within word16 + { + *((UInt16*) addr) = (UInt16) data; // write without swap + *((UInt16*) (addr + 2)) = (UInt16) __rol (data, 16); // get next word16 + } + else + { + _data16 = (UInt16) (data); + _data16 = __rol (_data16, 8); // bswap for Big Endian + *((UInt16*) addr) = _data16; + + _data16 = (UInt16) __rol (data, 16); // get next word16 + _data16 = __rol (_data16, 8); // bswap for Big Endian + *((UInt16 *)(addr + 2)) = _data16; + } + } + + My assumption here is that we want to take a data pattern like 0x01234567 + and end up with it stored in the register as 67 45 23 01. Working from + the code above, if byteswapping is off, we execute the following: + + *((UInt16*) addr) = (UInt16) data; // write without swap + *((UInt16*) (addr + 2)) = (UInt16) __rol (data, 16); // get next word16 + + or: + + *((UInt16*) addr) = 0x4567; // write without swap + *((UInt16*) (addr + 2)) = 0x0123; // get next word16 + + In order for this to result in the right bytes getting written to the + right places in memory, 16-bit byteswapping must be on at the hardware + level. Confirming with the code in the "else" statement: + + _data16 = (UInt16) (data); + _data16 = __rol (_data16, 8); // bswap for Big Endian + *((UInt16*) addr) = _data16; + + _data16 = (UInt16) __rol (data, 16); // get next word16 + _data16 = __rol (_data16, 8); // bswap for Big Endian + *((UInt16 *)(addr + 2)) = _data16; + + or: + + _data16 = 0x4567; + _data16 = 0x6745; // bswap for Big Endian + *((UInt16*) addr) = 0x6745; + + _data16 = 0x0123; // get next word16 + _data16 = 0x2301; // bswap for Big Endian + *((UInt16 *)(addr + 2)) = 0x2301; + + In this case, if 16-bit byteswapping is turned on in the device + configuration register, then that will counteract the byteswapping + performed by the hardware. If, however, 32-bit byteswapping is + enabled in the device configuration register, I'm not sure what + will happen. + + Let's take a look at another example. Registers are often written + using the geREG16 macro. This macro is called twice in order to + update the whole 32-bit register: + + geREG16( GE_WIDTH_L, width ); + geREG16( GE_HEIGHT_H, height ); + + Where: + + #define GE_WIDTH_L (GE_WIDTH_HEIGHT) // 40204h + #define GE_HEIGHT_H (GE_WIDTH_HEIGHT + 2) // 40206h + + There is also a geREG macro used to update the whole 32-bit register + at once: + + geREG( GE_DEST_XY, dstAddr ); + + I find a number of definitions of these macros. The two sets that + appear most likely to be the ones used in our ROM are as follows: + + # mqgeHAL.h + + #define geREG16(id, data) *(pGE16 + (id)) = (UInt16)(data) + #define geREG(id, data) *(pGE + (id)) = (UInt32)(data) + + # mqge.h + + #define geREG16(id, data) *((UInt16 *)(pGE + id)) = __rol( data, 8 ) + #define geREG(id, data) \ + { \ + register UInt32 _data32; \ + _data32 = (data); \ + geREG16(id, (UInt16)_data32); \ + geREG16((id + 2), (UInt16)(_data32 >> 16) ); \ + } + + The second set appears to be more consistant with our first + study case, so let's assume that it represents what's going + on in our ROM. + + What's left unclear is what really happens when writing a 32-bit + value to a 32-bit register, and how the 64-bit source data FIFO + is handled. +*/ + +void EmRegsMediaQ11xx::PrvUpdateByteLanes (void) +{ + // Read the register. + + uint32 reg = READ_REGISTER (dcREG[0x00]); + + // Adjust the bytelanes array to reflect the byteswapping options. + // Without any other adjustments, it appears that the CPU bytelanes + // are set up to swap 16-bit values with the MediaQ chip. + + this->fBytelanes[0] = 1; + this->fBytelanes[1] = 0; + this->fBytelanes[2] = 3; + this->fBytelanes[3] = 2; + + if ((reg & 1) == 1) + { + // Enable little endian mode. Byte swapping is not performed on data. + + } + else if ((reg & 2) == 2) + { + // Enable 32-bit byte swapping for big endian to little endian conversion. + // byte0 <-> byte3, byte1 <-> byte2 + + std::swap (this->fBytelanes[0], this->fBytelanes[3]); + std::swap (this->fBytelanes[1], this->fBytelanes[2]); + } + else + { + // Enable 16-bit Byte swapping for big endian to little endian conversion. + // byte0 <-> byte1, byte2 <-> byte3 + + std::swap (this->fBytelanes[0], this->fBytelanes[1]); + std::swap (this->fBytelanes[2], this->fBytelanes[3]); + } +} + + +#pragma mark - + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::PrvGetGEState +// --------------------------------------------------------------------------- + +void EmRegsMediaQ11xx::PrvGetGEState (int regNum) +{ + uint32 reg; + + // ==================== GE00R ==================== + + if (regNum == kAllRegisters || regNum == 0) + { + reg = READ_REGISTER (geREG[0x00]); + + fState.rasterOperation = (reg >> 0) & 0x000000FF; + fState.commandType = (reg >> 8) & 0x00000007; + fState.xDirection = (reg >> 11) & 0x00000001; + fState.yDirection = (reg >> 12) & 0x00000001; + fState.systemMemory = (reg >> 13) & 0x00000001; + fState.monoSource = (reg >> 14) & 0x00000001; + fState.monoPattern = (reg >> 15) & 0x00000001; + fState.colorTransEnable = (reg >> 16) & 0x00000001; + fState.destTransPolarity = (reg >> 17) & 0x00000001; + fState.monoTransEnable = (reg >> 18) & 0x00000001; + fState.monoTransPolarity = (reg >> 19) & 0x00000001; + fState.memToScreen = (reg >> 20) & 0x00000001; + fState.solidSourceColor = (reg >> 23) & 0x00000001; + fState.srcEqualDestStride = (reg >> 24) & 0x00000001; + fState.rop2Select = (reg >> 25) & 0x00000001; + fState.clipEnable = (reg >> 26) & 0x00000001; + fState.autoExecute = (reg >> 27) & 0x00000001; + fState.solidPattern = (reg >> 30) & 0x00000001; + fState.colorTransCmpSrc = (reg >> 31) & 0x00000001; + } + + // ==================== GE01R ==================== + + if (regNum == kAllRegisters || regNum == 1) + { + reg = READ_REGISTER (geREG[0x01]); + + // BitBLT + + fState.width = (reg >> 0) & 0x00000FFF; + fState.height = (reg >> 16) & 0x00000FFF; + fState.xyConversion = (reg >> 31) & 0x00000001; + + // Line + + fState.gamma = (reg >> 0) & 0x0001FFFF; fState.gamma |= 0xFFFE0000; + fState.majorLength = (reg >> 17) & 0x00000FFF; + fState.yIsMajor = (reg >> 29) & 0x00000001; + fState.drawLastPixel = (reg >> 30) & 0x00000001; + fState.useXY = (reg >> 31) & 0x00000001; + } + + // ==================== GE02R ==================== + + if (regNum == kAllRegisters || regNum == 2) + { + reg = READ_REGISTER (geREG[0x02]); + + // BitBLT + + fState.xDest = (reg >> 0) & 0x00000FFF; + fState.monoPatternXOffset = (reg >> 13) & 0x00000007; + fState.yDest = (reg >> 16) & 0x00000FFF; + fState.monoPatternYOffset = (reg >> 29) & 0x00000007; + + // Line + + fState.xStart = (reg >> 0) & 0x00000FFF; + fState.deltaMajor = (reg >> 12) & 0x0001FFFF; + fState.quadrant = (reg >> 29) & 0x00000007; + } + + // ==================== GE03R ==================== + + if (regNum == kAllRegisters || regNum == 3) + { + reg = READ_REGISTER (geREG[0x03]); + + // BitBLT + + fState.xSrc = (reg >> 0) & 0x00000FFF; + fState.ySrc = (reg >> 16) & 0x00000FFF; + + // Line + + fState.yStart = (reg >> 0) & 0x00000FFF; + fState.deltaMinor = (reg >> 12) & 0x0001FFFF; + } + + // ==================== GE04R ==================== + + if (regNum == kAllRegisters || regNum == 4) + { + reg = READ_REGISTER (geREG[0x04]); + + fState.destTransColor = (reg >> 0) & 0x0000FFFF; + } + + // ==================== GE05R ==================== + + if (regNum == kAllRegisters || regNum == 5) + { + reg = READ_REGISTER (geREG[0x05]); + + fState.clipLeft = (reg >> 0) & 0x000007FF; + fState.clipTop = (reg >> 16) & 0x000003FF; + } + + // ==================== GE06R ==================== + + if (regNum == kAllRegisters || regNum == 6) + { + reg = READ_REGISTER (geREG[0x06]); + + fState.clipRight = (reg >> 0) & 0x000007FF; + fState.clipBottom = (reg >> 16) & 0x000003FF; + } + + // ==================== GE07R ==================== + + if (regNum == kAllRegisters || regNum == 7) + { + reg = READ_REGISTER (geREG[0x07]); + + fState.fgColorMonoSrc = (reg >> 0) & 0x0000FFFF; + } + + // ==================== GE08R ==================== + + if (regNum == kAllRegisters || regNum == 8) + { + reg = READ_REGISTER (geREG[0x08]); + + fState.bgColorMonoSrc = (reg >> 0) & 0x0000FFFF; + } + + // ==================== GE09R ==================== + + if (regNum == kAllRegisters || regNum == 9) + { + reg = READ_REGISTER (geREG[0x09]); + + // Lined Mode + + fState.srcLineStride = (reg >> 0) & 0x000003FF; + fState.srcBitOffset = (reg >> 25) & 0x00000007; + fState.srcByteOffset = (reg >> 28) & 0x00000007; + + // Packed Mode + + fState.srcLeadingBits = (reg >> 0) & 0x00000007; + fState.srcLeadingBytes = (reg >> 3) & 0x00000007; + fState.srcNumBytes = (reg >> 6) & 0x000003FF; + fState.srcTrailingBits = (reg >> 25) & 0x00000007; + fState.srcTrailingBytes = (reg >> 28) & 0x0000000F; + } + + // ==================== GE0AR ==================== + + if (regNum == kAllRegisters || regNum == 10) + { + reg = READ_REGISTER (geREG[0x0A]); + + fState.destLineStride = (reg >> 0) & 0x000003FF; + fState.monoSrcBitSwap = (reg >> 28) & 0x00000001; + fState.rotate90 = (reg >> 29) & 0x00000001; + fState.colorDepth = (reg >> 30) & 0x00000003; + } + + // ==================== GE0BR ==================== + + if (regNum == kAllRegisters || regNum == 11) + { + reg = READ_REGISTER (geREG[0x0B]); + + fState.baseAddr = (reg >> 0) & 0x000FFFFF; + } + + // ==================== GE0CR ==================== + + if (regNum == kAllRegisters || regNum == 12) + { + reg = READ_REGISTER (geREG[0x0C]); + + fState.cmdLineStart = (reg >> 0) & 0x000003FF; + fState.cmdLineEnd = (reg >> 12) & 0x000003FF; + fState.cmdLineControl = (reg >> 24) & 0x00000001; + fState.gc1SwitchControl = (reg >> 26) & 0x00000003; + } + + // ==================== GE0FR ==================== + + // ==================== GE10R ==================== + + if (regNum == kAllRegisters || regNum == 16) + { + reg = READ_REGISTER (geREG[0x10]); + + fState.monoPattern1 = (reg >> 0) & 0xFFFFFFFF; + } + + // ==================== GE11R ==================== + + if (regNum == kAllRegisters || regNum == 17) + { + reg = READ_REGISTER (geREG[0x11]); + + fState.monoPattern2 = (reg >> 0) & 0xFFFFFFFF; + } + + // ==================== GE12R ==================== + + if (regNum == kAllRegisters || regNum == 18) + { + reg = READ_REGISTER (geREG[0x12]); + + fState.fgColorMonoPat = (reg >> 0) & 0x0000FFFF; + } + + // ==================== GE13R ==================== + + if (regNum == kAllRegisters || regNum == 19) + { + reg = READ_REGISTER (geREG[0x13]); + + fState.bgColorMonoPat = (reg >> 0) & 0x0000FFFF; + } +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::PrvLogGEState +// --------------------------------------------------------------------------- + +void EmRegsMediaQ11xx::PrvLogGEState (void) +{ + LogAppendMsg ("========================================"); + + // ==================== GE00R ==================== + + LogAppendMsg ("GC00R:"); + LogAppendMsg (" xDoubling %s", this->PrvGetXDoubling () ? "TRUE" : "FALSE"); + LogAppendMsg (" yDoubling %s", this->PrvGetYDoubling () ? "TRUE" : "FALSE"); + LogAppendMsg (""); + + // ==================== GE00R ==================== + + LogAppendMsg ("GE00R:"); + LogAppendMsg (" rasterOperation 0x%02X (%s)", fState.rasterOperation, kROPs[fState.rasterOperation]); + LogAppendMsg (" commandType %u (%s)", fState.commandType, kCommands[fState.commandType]); + LogAppendMsg (" xDirection %u (%s)", fState.xDirection, kDirections[fState.xDirection]); + LogAppendMsg (" yDirection %u (%s)", fState.yDirection, kDirections[fState.yDirection]); + LogAppendMsg (" systemMemory %u", fState.systemMemory); + LogAppendMsg (" monoSource %u", fState.monoSource); + LogAppendMsg (" monoPattern %u", fState.monoPattern); + LogAppendMsg (" colorTransEnable %u", fState.colorTransEnable); + LogAppendMsg (" destTransPolarity %u (Transparent if pixel is %s to test color)", fState.destTransPolarity, fState.destTransPolarity ? "NOT equal" : "equal"); + LogAppendMsg (" monoTransEnable %u", fState.monoTransEnable); + LogAppendMsg (" monoTransPolarity %u", fState.monoTransPolarity); + LogAppendMsg (" memToScreen %u (%s)", fState.memToScreen, fState.memToScreen ? "PACKED" : "LINED"); + LogAppendMsg (" solidSourceColor %u", fState.solidSourceColor); + LogAppendMsg (" srcEqualDestStride %u", fState.srcEqualDestStride); + LogAppendMsg (" rop2Select %u", fState.rop2Select); + LogAppendMsg (" clipEnable %u", fState.clipEnable); + LogAppendMsg (" autoExecute %u", fState.autoExecute); + LogAppendMsg (" solidPattern %u", fState.solidPattern); + LogAppendMsg (" colorTransCmpSrc %u (Compare to %s)", fState.colorTransCmpSrc, fState.colorTransCmpSrc ? "Destination" : "Source"); + LogAppendMsg (""); + + // ==================== GE01R ==================== + + // BitBLT + + if (fState.commandType == kCommandBitBLT) + { + LogAppendMsg ("GE01R (BitBLT):"); + LogAppendMsg (" width %u", fState.width); + LogAppendMsg (" height %u", fState.height); + LogAppendMsg (" xyConversion %u", fState.xyConversion); + LogAppendMsg (""); + } + + // Line + + if (fState.commandType == kCommandLine) + { + LogAppendMsg ("GE01R (Line):"); + LogAppendMsg (" gamma %d", fState.gamma); + LogAppendMsg (" majorLength %u", fState.majorLength); + LogAppendMsg (" yIsMajor %u", fState.yIsMajor); + LogAppendMsg (" drawLastPixel %u", fState.drawLastPixel); + LogAppendMsg (" useXY %u", fState.useXY); + LogAppendMsg (""); + } + + // ==================== GE02R ==================== + + // BitBLT + + if (fState.commandType == kCommandBitBLT) + { + LogAppendMsg ("GE02R (BitBLT):"); + LogAppendMsg (" xDest %u", fState.xDest); + LogAppendMsg (" yDest %u", fState.yDest); + LogAppendMsg (" monoPatternXOffset %u", fState.monoPatternXOffset); + LogAppendMsg (" monoPatternYOffset %u", fState.monoPatternYOffset); + LogAppendMsg (""); + } + + // Line + + if (fState.commandType == kCommandLine) + { + LogAppendMsg ("GE02R (Line):"); + LogAppendMsg (" xStart %u", fState.xStart); + LogAppendMsg (" deltaMajor %u", fState.deltaMajor); + LogAppendMsg (" quadrant %u (%s)", fState.quadrant, kQuadrantDecode[fState.quadrant].text); + LogAppendMsg (""); + } + + // ==================== GE03R ==================== + + // BitBLT + + if (fState.commandType == kCommandBitBLT) + { + LogAppendMsg ("GE03R (BitBLT):"); + LogAppendMsg (" xSrc %u", fState.xSrc); + LogAppendMsg (" ySrc %u", fState.ySrc); + LogAppendMsg (""); + } + + // Line + + if (fState.commandType == kCommandLine) + { + LogAppendMsg ("GE03R (Line):"); + LogAppendMsg (" yStart %u", fState.yStart); + LogAppendMsg (" deltaMinor %u", fState.deltaMinor); + LogAppendMsg (""); + } + + // ==================== GE04R ==================== + + if (fState.colorTransEnable) + { + LogAppendMsg ("GE04R:"); + LogAppendMsg (" destTransColor 0x%04X", fState.destTransColor); + LogAppendMsg (""); + } + + // ==================== GE05R/GE06R ==================== + + if (fState.clipEnable) + { + LogAppendMsg ("GE05R/GE06R:"); + LogAppendMsg (" clipLeft %u", fState.clipLeft); + LogAppendMsg (" clipTop %u", fState.clipTop); + LogAppendMsg (" clipRight %u", fState.clipRight); + LogAppendMsg (" clipBottom %u", fState.clipBottom); + LogAppendMsg (""); + } + + // ==================== GE07R/GE08R ==================== + + if (fState.monoSource) + { + LogAppendMsg ("GE07R/GE08R:"); + LogAppendMsg (" fgColorMonoSrc 0x%04X", fState.fgColorMonoSrc); + LogAppendMsg (" bgColorMonoSrc 0x%04X", fState.bgColorMonoSrc); + LogAppendMsg (""); + } + + // ==================== GE09R ==================== + + // Lined Mode + + if (fState.memToScreen == 0) + { + LogAppendMsg ("GE09R (Lined):"); + LogAppendMsg (" srcLineStride %u", fState.srcLineStride); + LogAppendMsg (" srcBitOffset %u", fState.srcBitOffset); + LogAppendMsg (" srcByteOffset %u", fState.srcByteOffset); + LogAppendMsg (""); + } + + // Packed Mode + + if (fState.memToScreen == 1) + { + LogAppendMsg ("GE09R (Packed):"); + LogAppendMsg (" srcLeadingBits %u", fState.srcLeadingBits); + LogAppendMsg (" srcLeadingBytes %u", fState.srcLeadingBytes); + LogAppendMsg (" srcNumBytes %u", fState.srcNumBytes); + LogAppendMsg (" srcTrailingBits %u", fState.srcTrailingBits); + LogAppendMsg (" srcTrailingBytes %u", fState.srcTrailingBytes); + LogAppendMsg (""); + } + + // ==================== GE0AR ==================== + + LogAppendMsg ("GE0AR:"); + LogAppendMsg (" destLineStride %u", fState.destLineStride); + LogAppendMsg (" monoSrcBitSwap %u", fState.monoSrcBitSwap); + LogAppendMsg (" rotate90 %u", fState.rotate90); + LogAppendMsg (" colorDepth %u", fState.colorDepth); + LogAppendMsg (""); + + // ==================== GE0BR ==================== + + LogAppendMsg ("GE0AR:"); + LogAppendMsg (" baseAddr 0x%08X", fState.baseAddr); + LogAppendMsg (""); + + // ==================== GE0CR ==================== + + LogAppendMsg ("GE0CR:"); + LogAppendMsg (" cmdLineStart %u", fState.cmdLineStart); + LogAppendMsg (" cmdLineEnd %u", fState.cmdLineEnd); + LogAppendMsg (" cmdLineControl %u", fState.cmdLineControl); + LogAppendMsg (" gc1SwitchControl %u", fState.gc1SwitchControl); + LogAppendMsg (""); + + // ==================== GE0FR ==================== + + // ==================== GE10R/GE11R ==================== + + if (fState.monoPattern) + { + LogAppendMsg ("GE10R/GE11R:"); + LogAppendMsg (" monoPattern1 0x%08X", fState.monoPattern1); + LogAppendMsg (" monoPattern2 0x%08X", fState.monoPattern2); + LogAppendMsg (""); + } + + // ==================== GE12R/GE13R ==================== + + if (fState.monoPattern) + { + LogAppendMsg ("GE12R/GE13R:"); + LogAppendMsg (" fgColorMonoPat 0x%04X", fState.fgColorMonoPat); + LogAppendMsg (" bgColorMonoPat 0x%04X", fState.bgColorMonoPat); + } + + LogAppendMsg ("========================================"); + + if (fState.commandType == kCommandBitBLT) + { + EmAssert (!( + (fState.width == 25) && + (fState.height == 19) && + (fState.xDest == 0) && + (fState.yDest == 320) && + (fState.xSrc == 0) && + (fState.ySrc == 320) && + 1)); + } +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::PrvDoCommand +// --------------------------------------------------------------------------- + +void EmRegsMediaQ11xx::PrvDoCommand (void) +{ + switch (fState.commandType) + { + case kCommandNOP: + // NOP command -- do nothing + break; + + case kCommandBitBLT: + this->PrvDoBitBLT (); + break; + + case kCommandLine: + this->PrvDoLine (); + break; + + default: + this->PrvIllegalCommand (); + break; + } +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::PrvDoBitBLT +// --------------------------------------------------------------------------- + +void EmRegsMediaQ11xx::PrvDoBitBLT (void) +{ + this->PrvIncBlitterInit (); + this->PrvIncBlitterRun (); +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::PrvDoLine +// --------------------------------------------------------------------------- + +void EmRegsMediaQ11xx::PrvDoLine (void) +{ + PRINTF_LINE (" PrvDoLine: &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&"); + +#if LOG_LINE + this->PrvLogGEState (); +#endif + + // Draw a line using the information in the GE registers, + // using a Bresenham line drawing algorithm. For a good + // tutorial on this algorithm, see: + // + // <http://www.gamedev.net/reference/articles/article1275.asp> + + // Figure out our starting and ending points. The starting + // point is in the registers. The ending point needs to + // be determined by looking at deltaMajor, deltaMinor, the + // flag that says if the major is the X or Y access, and the + // X and Y directions. + + uint16 yIsMajor; // 0 = x is major, 1 = y is major + uint16 xDirection; // 0 = x is positive, 1 = x is negative + uint16 yDirection; // 0 = y is positive, 1 = y is negative + + if (fState.useXY) + { + yIsMajor = fState.yIsMajor; + xDirection = fState.xDirection; + yDirection = fState.yDirection; + } + else + { + yIsMajor = kQuadrantDecode[fState.quadrant].yIsMajor; + xDirection = kQuadrantDecode[fState.quadrant].xDirection; + yDirection = kQuadrantDecode[fState.quadrant].yDirection; + } + + PRINTF_LINE (" yIsMajor: %d", yIsMajor); + PRINTF_LINE (" xDirection: %d", xDirection); + PRINTF_LINE (" yDirection: %d", yDirection); + + // Get the starting x,y position. We'll be updating these + // variables as we draw the line. + + uint16 x = fState.xStart; + uint16 y = fState.yStart; + + PRINTF_LINE (" x: %d", x); + PRINTF_LINE (" y: %d", y); + + // Get the direction in which the x,y coordinates needs to + // be updated. + + int xAdjust = xDirection ? -1 : 1; + int yAdjust = yDirection ? -1 : 1; + + PRINTF_LINE (" xAdjust: %d", xAdjust); + PRINTF_LINE (" yAdjust: %d", yAdjust); + + // Based on which axis is the major axis, get pointers to + // the major and minor coordinates and the values that will + // be used to update them. + + uint16* major; + uint16* minor; + + int majorAdjust; + int minorAdjust; + + if (yIsMajor) + { + major = &y; + minor = &x; + + majorAdjust = yAdjust; + minorAdjust = xAdjust; + } + else + { + major = &x; + minor = &y; + + majorAdjust = xAdjust; + minorAdjust = yAdjust; + } + + PRINTF_LINE (" major: %d", *major); + PRINTF_LINE (" minor: %d", *minor); + + PRINTF_LINE (" majorAdjust: %d", majorAdjust); + PRINTF_LINE (" minorAdjust: %d", minorAdjust); + + PRINTF_LINE (" gamma: %d", fState.gamma); + PRINTF_LINE (" majorLength: %d", fState.majorLength); + PRINTF_LINE (" deltaMajor: %d", fState.deltaMajor); + + PRINTF_LINE (" ..................."); + + // Initialize "error" (which is used to determine when we + // need to increment the minor axis coordinate) and "count" + // (which is used to iterate over the major axis). + + int error = 0; + uint16 count = 0; + + // Iterate over all the points along the major axis. + + while (count < fState.majorLength) + { + PRINTF_LINE (" count: %d", count); + PRINTF_LINE (" major: %d", *major); + PRINTF_LINE (" minor: %d", *minor); + + // Plot a point. + + uint16 src = 0; // Dummy value. The ROP had better not be one that makes use of a source pixel! + uint16 pen = fState.fgColorMonoPat; + uint16 dest = this->PrvGetPixel (x, y); + + uint16 output = this->PrvAdjustPixel (pen, src, dest, fState.rasterOperation); + + this->PrvSetPixel (output, x, y); + + // Update the major axis coordinate and adjust the error factor. + + *major += majorAdjust; + error += 2 * fState.deltaMinor; + + // See if it's time to update the minor access coordinate. + + if (error > fState.deltaMajor) + { + // Update the minor axis coordinate and adjust the error factor. + + *minor += minorAdjust; + error -= 2 * fState.deltaMajor; + } + + // Keep track of how many points we've plotted. + + count += 1; + } + + PRINTF_LINE (" ..................."); + + // If we need to draw the last pixel, then do it. + + if (fState.drawLastPixel) + { + PRINTF_LINE (" count: %d", count); + PRINTF_LINE (" major: %d", *major); + PRINTF_LINE (" minor: %d", *minor); + + PRINTF_LINE (" ..................."); + + uint16 src = 0; // Dummy value. The ROP had better not be one that makes use of a source pixel! + uint16 pen = fState.fgColorMonoPat; + uint16 dest = this->PrvGetPixel (x, y); + + uint16 output = this->PrvAdjustPixel (pen, src, dest, fState.rasterOperation); + + this->PrvSetPixel (output, x, y); + } + + PRINTF_LINE (" PrvDoLine: &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&"); +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::PrvIllegalCommand +// --------------------------------------------------------------------------- + +void EmRegsMediaQ11xx::PrvIllegalCommand (void) +{ +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::PrvSrcFifoFilledSlots +// --------------------------------------------------------------------------- + +int EmRegsMediaQ11xx::PrvSrcFifoFilledSlots (void) +{ + return fSourceFifo.size () / 2; +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::PrvGetSrcFifoSlot +// --------------------------------------------------------------------------- + +void EmRegsMediaQ11xx::PrvGetSrcFifoSlot (uint32& a, uint32& b) +{ + a = fSourceFifo[0]; + fSourceFifo.erase (fSourceFifo.begin ()); + + b = fSourceFifo[0]; + fSourceFifo.erase (fSourceFifo.begin ()); +} + + +// --------------------------------------------------------------------------- +// Drawing Functions +// --------------------------------------------------------------------------- + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::PrvAdjustPixel +// --------------------------------------------------------------------------- + +uint16 EmRegsMediaQ11xx::PrvAdjustPixel (uint16 pen, uint16 dest, uint8 rOpCode) +{ + uint16 result; + + /* + (From MSDN) + + Each raster-operation code represents a Boolean operation in which the + values of the pixels in the selected pen and the destination bitmap are + combined. The following are the two operands used in these operations. + + Operand Meaning + ------- ------- + P Selected pen + D Destination bitmap + + The Boolean operators used in these operations follow. + + Operator Meaning + -------- ------- + a Bitwise AND + n Bitwise NOT (inverse) + o Bitwise OR + x Bitwise exclusive OR (XOR) + + All Boolean operations are presented in reverse Polish notation. For + example, the following operation replaces the values of the pixels in + the destination bitmap with a combination of the pixel values of the + pen and the selected brush: + + DPo + + Each raster-operation code is a 32-bit integer whose high-order word + is a Boolean operation index and whose low-order word is the operation + code. The 16-bit operation index is a zero-extended 8-bit value that + represents all possible outcomes resulting from the Boolean operation + on two parameters (in this case, the pen and destination values). For + example, the operation indexes for the DPo and DPan operations are shown + in the following list. + + P D DPo Dpan + 0 0 0 1 + 0 1 1 1 + 1 0 1 1 + 1 1 1 0 + + The following list outlines the drawing modes and the Boolean operations + that they represent. + + Raster operation Boolean operation + ---------------- ----------------- + R2_BLACK 0 + R2_COPYPEN P + R2_MASKNOTPEN DPna + R2_MASKPEN DPa + R2_MASKPENNOT PDna + R2_MERGENOTPEN DPno + R2_MERGEPEN DPo + R2_MERGEPENNOT PDno + R2_NOP D + R2_NOT Dn + R2_NOTCOPYPEN Pn + R2_NOTMASKPEN DPan + R2_NOTMERGEPEN DPon + R2_NOTXORPEN DPxn + R2_WHITE 1 + R2_XORPEN DPx + */ + + switch (rOpCode) + { + case 0: /* 0 */ + result = 0; + break; + + case 1: /* DPon */ + result = ~(dest | pen); + break; + + case 2: /* DPna */ + result = dest & ~pen; + break; + + case 3: /* PN */ + result = ~pen; + break; + + case 4: /* PDna */ + result = pen & ~dest; + break; + + case 5: /* Dn */ + result = ~dest; + break; + + case 6: /* DPx */ + result = dest ^ pen; + break; + + case 7: /* DPan */ + result = ~(dest & pen); + break; + + case 8: /* DPa */ + result = dest & pen; + break; + + case 9: /* DPxn */ + result = ~(dest ^ pen); + break; + + case 10: /* D */ + result = dest; + break; + + case 11: /* DPno */ + result = dest | ~pen; + break; + + case 12: /* P */ + result = pen; + break; + + case 13: /* PDno */ + result = pen & ~dest; + break; + + case 14: /* DPo */ + result = dest | pen; + break; + + case 15: /* 1 */ + result = ~0; + break; + + default: + EmAssert (false); + result = 0; + break; + } + +#ifdef _DEBUG + // Double-check the special cases with the generalized code. + + { + const int kNumBits = 8 * sizeof (result); + + uint16 result2 = 0; + + for (int bitNumber = 0; bitNumber < kNumBits; ++bitNumber) + { + uint8 index = (((pen >> bitNumber) & 1) << 1) | + (((dest >> bitNumber) & 1) << 0); + + result2 |= (((rOpCode >> index) & 1) << bitNumber); + } + + EmAssert (result == result2); + } +#endif + + return result; +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::PrvAdjustPixel +// --------------------------------------------------------------------------- + +uint16 EmRegsMediaQ11xx::PrvAdjustPixel (uint16 pattern, uint16 src, uint16 dest, uint8 rOpCode) +{ + uint16 result; + + /* + (From MSDN) + + Each raster-operation code represents a Boolean operation in which + the values of the pixels in the source, the selected brush, and the + destination are combined. The following are the three operands used + in these operations. + + Operand Meaning + ------- ------- + D Destination bitmap + P Selected brush (also called pattern) + S Source bitmap + + Boolean operators used in these operations follow. + + Operator Meaning + -------- ------- + a Bitwise AND + n Bitwise NOT (inverse) + o Bitwise OR + x Bitwise exclusive OR (XOR) + + --------------------------------------------------------------------- + + (From Keith) + + Here's another way to think about it: take the pattern, source, and + destination, and consider each value one bit at a time. The three + bits from the three values can form eight combinations. The raster + opcode is a bitfield containing the desired output from each of the + combinations. Thus: + + P S D O (output) + --- --- --- --- + 0 0 0 b0 + 0 0 1 b1 + 0 1 0 b2 + 0 1 1 b3 + 1 0 0 b4 + 1 0 1 b5 + 1 1 0 b6 + 1 1 1 b7 + + The output is the byte <b7><b6><b5><b4><b3><b2><b1><b0>. And this + output value is what becomes the raster opcode. Thus, if the raster + opcode is, for example, 0xCC, the table would be: + + P S D O (output) + --- --- --- --- + 0 0 0 0 + 0 0 1 0 + 0 1 0 1 + 0 1 1 1 + 1 0 0 0 + 1 0 1 0 + 1 1 0 1 + 1 1 1 1 + + So, the we look at three bits from the source and they're all zero, + then the output is zero. If they're all one, then the output is + one. If the pattern is one and the source and destination are zero, + then the output is zero. Overall, + + Output[x] = ROP[P[x],S[x],D[x]] + + where "x" is 0..7, and "P[x],S[x],D[x]" is a bitfield composed of + the given bits. + + We will use this generalization for the default case. However, for + the most common raster ops, we can manipulate all bits of all the + incumbant values simultaneously. We special-case those opcodes. + */ + + switch (rOpCode) + { + case 0x00: // 00000042 0 BLACKNESS + result = 0; + break; + + // case 0x01: // 00010289 DPSoon – + // case 0x02: // 00020C89 DPSona – + // case 0x03: // 000300AA PSon – + // case 0x04: // 00040C88 SDPona – + // case 0x05: // 000500A9 DPon – + // case 0x06: // 00060865 PDSxnon – + // case 0x07: // 000702C5 PDSaon – + // case 0x08: // 00080F08 SDPnaa – + // case 0x09: // 00090245 PDSxon – + case 0x0A: // 000A0329 DPna – + result = dest & ~pattern; + break; + + // case 0x0B: // 000B0B2A PSDnaon – + // case 0x0C: // 000C0324 SPna – + // case 0x0D: // 000D0B25 PDSnaon – + // case 0x0E: // 000E08A5 PDSonon – + case 0x0F: // 000F0001 Pn – + result = ~pattern; + break; + + // case 0x10: // 00100C85 PDSona – + case 0x11: // 001100A6 DSon NOTSRCERASE + result = ~(dest | src); + break; + + // case 0x12: // 00120868 SDPxnon – + // case 0x13: // 001302C8 SDPaon – + // case 0x14: // 00140869 DPSxnon – + // case 0x15: // 001502C9 DPSaon – + // case 0x16: // 00165CCA PSDPSanaxx – + // case 0x17: // 00171D54 SSPxDSxaxn – + // case 0x18: // 00180D59 SPxPDxa – + // case 0x19: // 00191CC8 SDPSanaxn – + // case 0x1A: // 001A06C5 PDSPaox – + // case 0x1B: // 001B0768 SDPSxaxn – + // case 0x1C: // 001C06CA PSDPaox – + // case 0x1D: // 001D0766 DSPDxaxn – + // case 0x1E: // 001E01A5 PDSox – + // case 0x1F: // 001F0385 PDSoan – + // case 0x20: // 00200F09 DPSnaa – + // case 0x21: // 00210248 SDPxon – + case 0x22: // 00220326 DSna – + result = dest & ~src; + break; + + // case 0x23: // 00230B24 SPDnaon – + // case 0x24: // 00240D55 SPxDSxa – + // case 0x25: // 00251CC5 PDSPanaxn – + // case 0x26: // 002606C8 SDPSaox – + // case 0x27: // 00271868 SDPSxnox – + // case 0x28: // 00280369 DPSxa – + // case 0x29: // 002916CA PSDPSaoxxn – + // case 0x2A: // 002A0CC9 DPSana – + // case 0x2B: // 002B1D58 SSPxPDxaxn – + // case 0x2C: // 002C0784 SPDSoax – + // case 0x2D: // 002D060A PSDnox – + // case 0x2E: // 002E064A PSDPxox – + // case 0x2F: // 002F0E2A PSDnoan – + // case 0x30: // 0030032A PSna – + // case 0x31: // 00310B28 SDPnaon – + // case 0x32: // 00320688 SDPSoox – + case 0x33: // 00330008 Sn NOTSRCCOPY + result = ~src; + break; + + // case 0x34: // 003406C4 SPDSaox – + // case 0x35: // 00351864 SPDSxnox – + // case 0x36: // 003601A8 SDPox – + // case 0x37: // 00370388 SDPoan – + // case 0x38: // 0038078A PSDPoax – + // case 0x39: // 00390604 SPDnox – + // case 0x3A: // 003A0644 SPDSxox – + // case 0x3B: // 003B0E24 SPDnoan – + // case 0x3C: // 003C004A PSx – + // case 0x3D: // 003D18A4 SPDSonox – + // case 0x3E: // 003E1B24 SPDSnaox – + // case 0x3F: // 003F00EA PSan – + // case 0x40: // 00400F0A PSDnaa – + // case 0x41: // 00410249 DPSxon – + // case 0x42: // 00420D5D SDxPDxa – + // case 0x43: // 00431CC4 SPDSanaxn – + case 0x44: // 00440328 SDna SRCERASE + result = src & ~dest; + break; + + // case 0x45: // 00450B29 DPSnaon – + // case 0x46: // 004606C6 DSPDaox – + // case 0x47: // 0047076A PSDPxaxn – + // case 0x48: // 00480368 SDPxa – + // case 0x49: // 004916C5 PDSPDaoxxn – + // case 0x4A: // 004A0789 DPSDoax – + // case 0x4B: // 004B0605 PDSnox – + // case 0x4C: // 004C0CC8 SDPana – + // case 0x4D: // 004D1954 SSPxDSxoxn – + // case 0x4E: // 004E0645 PDSPxox – + // case 0x4F: // 004F0E25 PDSnoan – + // case 0x50: // 00500325 PDna – + // case 0x51: // 00510B26 DSPnaon – + // case 0x52: // 005206C9 DPSDaox – + // case 0x53: // 00530764 SPDSxaxn – + // case 0x54: // 005408A9 DPSonon – + case 0x55: // 00550009 Dn DSTINVERT + result = ~dest; + break; + + // case 0x56: // 005601A9 DPSox – + // case 0x57: // 00570389 DPSoan – + // case 0x58: // 00580785 PDSPoax – + // case 0x59: // 00590609 DPSnox – + case 0x5A: // 005A0049 DPx PATINVERT + result = dest ^ pattern; + break; + + // case 0x5B: // 005B18A9 DPSDonox – + // case 0x5C: // 005C0649 DPSDxox – + // case 0x5D: // 005D0E29 DPSnoan – + // case 0x5E: // 005E1B29 DPSDnaox – + case 0x5F: // 005F00E9 DPan – + result = ~(dest & pattern); + break; + + // case 0x60: // 00600365 PDSxa – + // case 0x61: // 006116C6 DSPDSaoxxn – + // case 0x62: // 00620786 DSPDoax – + // case 0x63: // 00630608 SDPnox – + // case 0x64: // 00640788 SDPSoax – + // case 0x65: // 00650606 DSPnox – + case 0x66: // 00660046 DSx SRCINVERT + result = dest ^ src; + break; + + // case 0x67: // 006718A8 SDPSonox – + // case 0x68: // 006858A6 DSPDSonoxxn – + // case 0x69: // 00690145 PDSxxn – + // case 0x6A: // 006A01E9 DPSax – + // case 0x6B: // 006B178A PSDPSoaxxn – + // case 0x6C: // 006C01E8 SDPax – + // case 0x6D: // 006D1785 PDSPDoaxxn – + // case 0x6E: // 006E1E28 SDPSnoax – + // case 0x6F: // 006F0C65 PDSxnan – + // case 0x70: // 00700CC5 PDSana – + // case 0x71: // 00711D5C SSDxPDxaxn – + // case 0x72: // 00720648 SDPSxox – + // case 0x73: // 00730E28 SDPnoan – + // case 0x74: // 00740646 DSPDxox – + // case 0x75: // 00750E26 DSPnoan – + // case 0x76: // 00761B28 SDPSnaox – + case 0x77: // 007700E6 DSan – + result = ~(dest & src); + break; + + // case 0x78: // 007801E5 PDSax – + // case 0x79: // 00791786 DSPDSoaxxn – + // case 0x7A: // 007A1E29 DPSDnoax – + // case 0x7B: // 007B0C68 SDPxnan – + // case 0x7C: // 007C1E24 SPDSnoax – + // case 0x7D: // 007D0C69 DPSxnan – + // case 0x7E: // 007E0955 SPxDSxo – + // case 0x7F: // 007F03C9 DPSaan – + // case 0x80: // 008003E9 DPSaa – + // case 0x81: // 00810975 SPxDSxon – + // case 0x82: // 00820C49 DPSxna – + // case 0x83: // 00831E04 SPDSnoaxn – + // case 0x84: // 00840C48 SDPxna – + // case 0x85: // 00851E05 PDSPnoaxn – + // case 0x86: // 008617A6 DSPDSoaxx – + // case 0x87: // 008701C5 PDSaxn – + case 0x88: // 008800C6 DSa SRCAND + result = dest & src; + break; + + // case 0x89: // 00891B08 SDPSnaoxn – + // case 0x8A: // 008A0E06 DSPnoa – + // case 0x8B: // 008B0666 DSPDxoxn – + // case 0x8C: // 008C0E08 SDPnoa – + // case 0x8D: // 008D0668 SDPSxoxn – + // case 0x8E: // 008E1D7C SSDxPDxax – + // case 0x8F: // 008F0CE5 PDSanan – + // case 0x90: // 00900C45 PDSxna – + // case 0x91: // 00911E08 SDPSnoaxn – + // case 0x92: // 009217A9 DPSDPoaxx – + // case 0x93: // 009301C4 SPDaxn – + // case 0x94: // 009417AA PSDPSoaxx – + // case 0x95: // 009501C9 DPSaxn – + // case 0x96: // 00960169 DPSxx – + // case 0x97: // 0097588A PSDPSonoxx – + // case 0x98: // 00981888 SDPSonoxn – + case 0x99: // 00990066 DSxn – + result = ~(dest ^ src); + break; + + // case 0x9A: // 009A0709 DPSnax – + // case 0x9B: // 009B07A8 SDPSoaxn – + // case 0x9C: // 009C0704 SPDnax – + // case 0x9D: // 009D07A6 DSPDoaxn – + // case 0x9E: // 009E16E6 DSPDSaoxx – + // case 0x9F: // 009F0345 PDSxan – + case 0xA0: // 00A000C9 DPa – + result = dest & pattern; + break; + + // case 0xA1: // 00A11B05 PDSPnaoxn – + // case 0xA2: // 00A20E09 DPSnoa – + // case 0xA3: // 00A30669 DPSDxoxn – + // case 0xA4: // 00A41885 PDSPonoxn – + case 0xA5: // 00A50065 PDxn – + result = ~(pattern ^ dest); + break; + + // case 0xA6: // 00A60706 DSPnax – + // case 0xA7: // 00A707A5 PDSPoaxn – + // case 0xA8: // 00A803A9 DPSoa – + // case 0xA9: // 00A90189 DPSoxn – + // case 0xAA: // 00AA0029 D – + // case 0xAB: // 00AB0889 DPSono – + // case 0xAC: // 00AC0744 SPDSxax – + // case 0xAD: // 00AD06E9 DPSDaoxn – + // case 0xAE: // 00AE0B06 DSPnao – + case 0xAF: // 00AF0229 DPno – + result = dest | ~pattern; + break; + + // case 0xB0: // 00B00E05 PDSnoa – + // case 0xB1: // 00B10665 PDSPxoxn – + // case 0xB2: // 00B21974 SSPxDSxox – + // case 0xB3: // 00B30CE8 SDPanan – + // case 0xB4: // 00B4070A PSDnax – + // case 0xB5: // 00B507A9 DPSDoaxn – + // case 0xB6: // 00B616E9 DPSDPaoxx – + // case 0xB7: // 00B70348 SDPxan – + // case 0xB8: // 00B8074A PSDPxax – + // case 0xB9: // 00B906E6 DSPDaoxn – + // case 0xBA: // 00BA0B09 DPSnao – + case 0xBB: // 00BB0226 DSno MERGEPAINT + result = dest | ~src; + break; + + // case 0xBC: // 00BC1CE4 SPDSanax – + // case 0xBD: // 00BD0D7D SDxPDxan – + // case 0xBE: // 00BE0269 DPSxo – + // case 0xBF: // 00BF08C9 DPSano – + case 0xC0: // 00C000CA PSa MERGECOPY + result = pattern & src; + break; + + // case 0xC1: // 00C11B04 SPDSnaoxn – + // case 0xC2: // 00C21884 SPDSonoxn – + // case 0xC3: // 00C3006A PSxn – + // case 0xC4: // 00C40E04 SPDnoa – + // case 0xC5: // 00C50664 SPDSxoxn – + // case 0xC6: // 00C60708 SDPnax – + // case 0xC7: // 00C707AA PSDPoaxn – + // case 0xC8: // 00C803A8 SDPoa – + // case 0xC9: // 00C90184 SPDoxn – + // case 0xCA: // 00CA0749 DPSDxax – + // case 0xCB: // 00CB06E4 SPDSaoxn – + case 0xCC: // 00CC0020 S SRCCOPY + result = src; + break; + + // case 0xCD: // 00CD0888 SDPono – + // case 0xCE: // 00CE0B08 SDPnao – + // case 0xCF: // 00CF0224 SPno – + // case 0xD0: // 00D00E0A PSDnoa – + // case 0xD1: // 00D1066A PSDPxoxn – + // case 0xD2: // 00D20705 PDSnax – + // case 0xD3: // 00D307A4 SPDSoaxn – + // case 0xD4: // 00D41D78 SSPxPDxax – + // case 0xD5: // 00D50CE9 DPSanan – + // case 0xD6: // 00D616EA PSDPSaoxx – + // case 0xD7: // 00D70349 DPSxan – + // case 0xD8: // 00D80745 PDSPxax – + // case 0xD9: // 00D906E8 SDPSaoxn – + // case 0xDA: // 00DA1CE9 DPSDanax – + // case 0xDB: // 00DB0D75 SPxDSxan – + // case 0xDC: // 00DC0B04 SPDnao – + // case 0xDD: // 00DD0228 SDno – + // case 0xDE: // 00DE0268 SDPxo – + // case 0xDF: // 00DF08C8 SDPano – + // case 0xE0: // 00E003A5 PDSoa – + // case 0xE1: // 00E10185 PDSoxn – + // case 0xE2: // 00E20746 DSPDxax – + // case 0xE3: // 00E306EA PSDPaoxn – + // case 0xE4: // 00E40748 SDPSxax – + // case 0xE5: // 00E506E5 PDSPaoxn – + // case 0xE6: // 00E61CE8 SDPSanax – + // case 0xE7: // 00E70D79 SPxPDxan – + // case 0xE8: // 00E81D74 SSPxDSxax – + // case 0xE9: // 00E95CE6 DSPDSanaxxn – + // case 0xEA: // 00EA02E9 DPSao – + // case 0xEB: // 00EB0849 DPSxno – + // case 0xEC: // 00EC02E8 SDPao – + // case 0xED: // 00ED0848 SDPxno – + case 0xEE: // 00EE0086 DSo SRCPAINT + result = dest | src; + break; + + // case 0xEF: // 00EF0A08 SDPnoo – + case 0xF0: // 00F00021 P PATCOPY + result = pattern; + break; + + // case 0xF1: // 00F10885 PDSono – + // case 0xF2: // 00F20B05 PDSnao – + // case 0xF3: // 00F3022A PSno – + // case 0xF4: // 00F40B0A PSDnao – + // case 0xF5: // 00F50225 PDno – + // case 0xF6: // 00F60265 PDSxo – + // case 0xF7: // 00F708C5 PDSano – + // case 0xF8: // 00F802E5 PDSao – + // case 0xF9: // 00F90845 PDSxno – + case 0xFA: // 00FA0089 DPo – + result = dest | pattern; + break; + + case 0xFB: // 00FB0A09 DPSnoo PATPAINT + result = dest | (pattern | ~src); + break; + + // case 0xFC: // 00FC008A PSo – + // case 0xFD: // 00FD0A0A PSDnoo – + // case 0xFE: // 00FE02A9 DPSoo – + case 0xFF: // 00FF0062 1 WHITENESS + result = ~0; + break; + + default: + { + const int kNumBits = 8 * sizeof (result); + + result = 0; + + for (int bitNumber = 0; bitNumber < kNumBits; ++bitNumber) + { + uint8 index = (((pattern >> bitNumber) & 1) << 2) | + (((src >> bitNumber) & 1) << 1) | + (((dest >> bitNumber) & 1) << 0); + + result |= (((rOpCode >> index) & 1) << bitNumber); + } + } + break; + } + +#ifdef _DEBUG + // Double-check the special cases with the generalized code. + + { + const int kNumBits = 8 * sizeof (result); + + uint16 result2 = 0; + + for (int bitNumber = 0; bitNumber < kNumBits; ++bitNumber) + { + uint8 index = (((pattern >> bitNumber) & 1) << 2) | + (((src >> bitNumber) & 1) << 1) | + (((dest >> bitNumber) & 1) << 0); + + result2 |= (((rOpCode >> index) & 1) << bitNumber); + } + + EmAssert (result == result2); + } +#endif + + return result; +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::PrvSetPixel +// --------------------------------------------------------------------------- + +void EmRegsMediaQ11xx::PrvSetPixel (uint16 pixel, uint16 x, uint16 y) +{ + emuptr pixelLocation = this->PrvGetPixelLocation (x, y); + + switch (fState.colorDepth) + { + case kColorDepth8: + EmMemPut8 (pixelLocation, pixel); + break; + + case kColorDepth16: + EmAssert (::IsEven (pixelLocation)); + EmMemPut16 (pixelLocation, pixel); + break; + + default: + EmAssert (false); + } +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::PrvGetPixel +// --------------------------------------------------------------------------- + +uint16 EmRegsMediaQ11xx::PrvGetPixel (uint16 x, uint16 y) +{ + uint16 result; + emuptr pixelLocation = this->PrvGetPixelLocation (x, y); + + switch (fState.colorDepth) + { + case kColorDepth8: + result = EmMemGet8 (pixelLocation); + break; + + case kColorDepth16: + EmAssert (::IsEven (pixelLocation)); + result = EmMemGet16 (pixelLocation); + break; + + default: + EmAssert (false); + result = 0; + } + + return result; +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::PrvGetPixelLocation +// --------------------------------------------------------------------------- + +emuptr EmRegsMediaQ11xx::PrvGetPixelLocation (uint16 x, uint16 y) +{ + int bytesPerPixel; + + switch (fState.colorDepth) + { + case kColorDepth8: + bytesPerPixel = 1; + break; + + case kColorDepth16: + bytesPerPixel = 2; + break; + + default: + EmAssert (false); + return 0; + } + + if (fState.rotate90) + { + // Rotate 90 deg clockwise. + + /* + -----x y-- + |+--------------------+| + || || + y| 1 || + | 2 |x + | | + | | + | | + | | + | | + | | + | | + +--------------------+ + + Point 1 is the original point. + Point 2 is the rotated point. + */ + + int16 newX = fState.destLineStride * bytesPerPixel - y; + int16 newY = x; + + x = newX; + y = newY; + } + + emuptr frameBuffer = this->PrvGetVideoBase () + fState.baseAddr; + emuptr scanLine = frameBuffer + (y * fState.destLineStride); + emuptr scanByte = scanLine + (x * bytesPerPixel); + + EmAssert (scanByte >= fBaseVideoAddr); + EmAssert (scanByte + bytesPerPixel <= fBaseVideoAddr + MMIO_OFFSET); + + return scanByte; +} + + +#pragma mark - + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::PrvIncBlitterInit +// --------------------------------------------------------------------------- + +void EmRegsMediaQ11xx::PrvIncBlitterInit (void) +{ + PRINTF_BLIT (" PrvIncBlitterInit: &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&"); + +#if LOG_BLIT + this->PrvLogGEState (); +#endif + + fBlitInProgress = true; + + fCurXOffset = 0; + fCurYOffset = 0; + + fUsesPattern = this->PrvUsesPattern (); + fUsesSource = this->PrvUsesSource (); + + if (!fUsesPattern) + PRINTF_BLIT (" PrvIncBlitterInit: pattern not used..."); + + if (!fUsesSource) + PRINTF_BLIT (" PrvIncBlitterInit: source data not used..."); + + if (fState.monoSource) + { + if (fState.monoTransEnable) + { + if (fState.monoTransPolarity) + { + PRINTF_BLIT (" PrvIncBlitterInit: Foreground is transparent..."); + } + else + { + PRINTF_BLIT (" PrvIncBlitterInit: Background is transparent..."); + } + } + } + else if (fState.colorTransEnable) + { + if (fState.destTransPolarity == 0) + { + if (fState.colorTransCmpSrc == 0) + { + PRINTF_BLIT (" PrvIncBlitterInit: Treat all destTransColor pixels in the source as transparent..."); + } + else + { + PRINTF_BLIT (" PrvIncBlitterInit: Leave all destTransColor pixels in the destination alone..."); + } + } + else + { + if (fState.colorTransCmpSrc == 0) + { + PRINTF_BLIT (" PrvIncBlitterInit: Transfer only destTransColor pixels from the source to the destination..."); + } + else + { + PRINTF_BLIT (" PrvIncBlitterInit: Update only destTransColor pixels in the destination with source pixels..."); + } + } + } + + this->PrvPatternPipeInit (); + this->PrvSrcPipeInit (); + this->PrvDestPipeInit (); + + PRINTF_BLIT (" PrvIncBlitterInit: &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&"); +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::PrvIncBlitterRun +// --------------------------------------------------------------------------- + +void EmRegsMediaQ11xx::PrvIncBlitterRun (void) +{ + if (!fBlitInProgress) + return; + + static long counter = 0; + + PRINTF_BLIT (" PrvIncBlitterRun: **************************************************"); + PRINTF_BLIT (" PrvIncBlitterRun: counter: %u", ++counter); + PRINTF_BLIT (" PrvIncBlitterRun: **************************************************"); + + while (fBlitInProgress) + { + Bool stalled; + + // Get the relevent pixel values. + + uint16 source = this->PrvSrcPipeNextPixel (stalled); + + // If the source FIFO stalled (no more input data for now), + // return false, indicating that the BLT operation is still + // in progress. + + if (stalled) + { + PRINTF_BLIT (" PrvIncBlitterRun: stalled..."); + break; + } + + // Continue getting more pixel values. + + uint16 pattern = this->PrvPatternPipeNextPixel (); + uint16 dest = this->PrvDestPipeNextPixel (); + uint16 output = this->PrvAdjustPixel (pattern, source, dest, + fState.rasterOperation); + + PRINTF_BLIT (" PrvIncBlitterRun: pattern: 0x%04X", pattern); + PRINTF_BLIT (" PrvIncBlitterRun: source: 0x%04X", source); + PRINTF_BLIT (" PrvIncBlitterRun: dest: 0x%04X", dest); + PRINTF_BLIT (" PrvIncBlitterRun: output: 0x%04X", output); + + // Write this pixel as long as it's not transparent or clipped out. + + if (!this->PrvTransparent (source, dest, pattern) && !this->PrvClipped ()) + { + PRINTF_BLIT (" PrvIncBlitterRun: setting..."); + + this->PrvSetPixel (output, fXDest, fYDest); + } + else + { + PRINTF_BLIT (" PrvIncBlitterRun: skipping..."); + } + + // Move to the next X/Y position. + + fBlitInProgress = this->PrvNextXY (); + + if (!fBlitInProgress) + { + EmAssert (this->PrvSrcFifoFilledSlots () == 0); + PRINTF_BLIT (" PrvIncBlitterRun: Completed!"); + } + } + + PRINTF_BLIT (" PrvIncBlitterRun: **************************************************"); +} + + +#pragma mark - + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::PrvPatternPipeInit +// --------------------------------------------------------------------------- + +void EmRegsMediaQ11xx::PrvPatternPipeInit (void) +{ + fXPattern = fState.monoPatternXOffset; + fYPattern = fState.monoPatternYOffset; + + PRINTF_BLIT (" PrvPatternPipeInit: fXPattern: %u", fXPattern); + PRINTF_BLIT (" PrvPatternPipeInit: fYPattern: %u", fYPattern); + + // Expand the specified pattern into a pixel array. + + if (fUsesPattern) + { + // Force the pattern data to be a solid color, if specified. + + if (fState.solidPattern) + { + PRINTF_BLIT (" PrvPatternPipeInit: filling with: 0x%04X", + fState.fgColorMonoPat); + + for (int ii = 0; ii < 64; ++ii) + { + fPatternPipe [ii] = fState.fgColorMonoPat; + } + } + + // If the pattern is specified as a 64-bit array, expand it + // into a 64-byte array with the fore- and background colors set. + + else if (fState.monoPattern) + { + /* + A pattern is an 8x8 structure, for a total of 64 bits. + This is represented on the Palm as an 8 element array + of 8-bit bytes. When translated into MediaQ terms, they + are transferred to the registers with: + + gePAT16( GE_MONO_PAT0_L, *patPtr++ ); + gePAT16( GE_MONO_PAT0_H, *patPtr++ ); + gePAT16( GE_MONO_PAT1_L, *patPtr++ ); + gePAT16( GE_MONO_PAT1_H, *patPtr ); + + where "patPtr" is a UInt16*. Thus, when read back out + as two DWORDs, the LSB of monoPattern1 contains the first + byte of the pattern, the next LSB contains the second + byte, all the way up to where the MSB of monoPattern2 + contains the last byte. + */ + + PRINTF_BLIT (" PrvPatternPipeInit: expanding: 0x%08X 0x%08X", + fState.monoPattern1, fState.monoPattern2); + + this->PrvExpandMono32 (fState.monoPattern1, &fPatternPipe [0], + fState.fgColorMonoPat, fState.bgColorMonoPat); + + this->PrvExpandMono32 (fState.monoPattern2, &fPatternPipe [32], + fState.fgColorMonoPat, fState.bgColorMonoPat); + + uint16* p = fPatternPipe; + UNUSED_PARAM(p); + + PRINTF_BLIT (" PrvPatternPipeInit: 0: 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X", + p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); + PRINTF_BLIT (" PrvPatternPipeInit: 1: 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X", + p[8+0], p[8+1], p[8+2], p[8+3], p[8+4], p[8+5], p[8+6], p[8+7]); + PRINTF_BLIT (" PrvPatternPipeInit: 2: 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X", + p[16+0], p[16+1], p[16+2], p[16+3], p[16+4], p[16+5], p[16+6], p[16+7]); + PRINTF_BLIT (" PrvPatternPipeInit: 3: 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X", + p[24+0], p[24+1], p[24+2], p[24+3], p[24+4], p[24+5], p[24+6], p[24+7]); + PRINTF_BLIT (" PrvPatternPipeInit: 4: 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X", + p[32+0], p[32+1], p[32+2], p[32+3], p[32+4], p[32+5], p[32+6], p[32+7]); + PRINTF_BLIT (" PrvPatternPipeInit: 5: 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X", + p[40+0], p[40+1], p[40+2], p[40+3], p[40+4], p[40+5], p[40+6], p[40+7]); + PRINTF_BLIT (" PrvPatternPipeInit: 6: 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X", + p[48+0], p[48+1], p[48+2], p[48+3], p[48+4], p[48+5], p[48+6], p[48+7]); + PRINTF_BLIT (" PrvPatternPipeInit: 7: 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X", + p[56+0], p[56+1], p[56+2], p[56+3], p[56+4], p[56+5], p[56+6], p[56+7]); + } + else + { + // The monoPattern bit MUST be programmed to 1, according to + // the docs. Color patterns don't appear to be supported. + + EmAssert (false); + } + } + + // We're not making use of any pattern data. + + else + { + // Do nothing. The pattern array will be garbage, but the theory + // here is that it's not going to be used. + } +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::PrvPatternPipeNextPixel +// --------------------------------------------------------------------------- + +uint16 EmRegsMediaQ11xx::PrvPatternPipeNextPixel (void) +{ + uint16 result = fPatternPipe [fXPattern + fYPattern * 8]; + + PRINTF_BLIT (" PrvPatternPipeNextPixel: fXPattern: %u", fXPattern); + PRINTF_BLIT (" PrvPatternPipeNextPixel: fYPattern: %u", fYPattern); + PRINTF_BLIT (" PrvPatternPipeNextPixel: result: 0x%04X", result); + + return result; +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::PrvPatternPipeNextX +// --------------------------------------------------------------------------- + +void EmRegsMediaQ11xx::PrvPatternPipeNextX (void) +{ + ++fXPattern; + + if (fXPattern == 8) + { + fXPattern = 0; + } +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::PrvPatternPipeNextY +// --------------------------------------------------------------------------- + +void EmRegsMediaQ11xx::PrvPatternPipeNextY (void) +{ + ++fYPattern; + fXPattern = fState.monoPatternXOffset; + + if (fYPattern == 8) + { + fYPattern = 0; + } +} + + +#pragma mark - + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::PrvSrcPipeInit +// --------------------------------------------------------------------------- + +void EmRegsMediaQ11xx::PrvSrcPipeInit (void) +{ + fXSrc = fState.xSrc; + fYSrc = fState.ySrc; + + if (fState.xyConversion) + { + if (fState.xDirection) + fXSrc += fState.width - 1; + + if (fState.yDirection) + fYSrc += fState.height - 1; + } + + if (fUsesSource && !fState.solidSourceColor && fState.systemMemory) + { + fLeadingSourcePixels = this->PrvLeadingPixels (); + fTrailingSourcePixels = this->PrvTrailingPixels (); + + PRINTF_BLIT (" PrvSrcPipeInit: fLeadingSourcePixels: %u", fLeadingSourcePixels); + PRINTF_BLIT (" PrvSrcPipeInit: fTrailingSourcePixels: %u", fTrailingSourcePixels); + } + + // Setting both of these variables to the same value will force the + // source pipe to fill itself from the source data FIFO the first + // time we access it (assuming that that's where the source data is + // coming from). + + fSourcePipeIndex = 0; + fSourcePipeMax = 0; + + fSourcePipeSkip = fLeadingSourcePixels; + + PRINTF_BLIT (" PrvSrcPipeInit: fXSrc: %u", fXSrc); + PRINTF_BLIT (" PrvSrcPipeInit: fYSrc: %u", fYSrc); + PRINTF_BLIT (" PrvSrcPipeInit: fSourcePipeSkip: %u", fSourcePipeSkip); +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::PrvSrcPipeNextPixel +// --------------------------------------------------------------------------- + +uint16 EmRegsMediaQ11xx::PrvSrcPipeNextPixel (Bool& stalled) +{ + stalled = false; + + if (!fUsesSource) + { + // Return a dummy value. The theory here is that it's not + // going to be used. + + PRINTF_BLIT (" PrvSrcPipeNextPixel: result: <dummy>"); + + return 0; + } + + // Force the source data to be a solid color, if specified. + + if (fState.solidSourceColor) + { + PRINTF_BLIT (" PrvSrcPipeNextPixel: result: 0x%04X (solid)", fState.fgColorMonoSrc); + + return fState.fgColorMonoSrc; + } + + // If we're getting source data from system memory, then read + // the data from the source FIFO. + + if (fState.systemMemory) + { + uint16 result; + + // Loop getting source pixels. Normally, we'll just return + // the first pixel, but we may need to skip some in case we're + // in the part of the scanline before the first valid pixel + // or after the last one. + + while (1) + { + if (fSourcePipeIndex == fSourcePipeMax) + { + this->PrvSrcPipeFill (stalled); + + if (stalled) + return 0; // Return a dummy value + + fSourcePipeIndex = 0; + } + + result = fSourcePipe [fSourcePipeIndex++]; + + if (fSourcePipeSkip == 0) + { + break; + } + + PRINTF_BLIT (" PrvSrcPipeNextPixel: skipping... %u", fSourcePipeSkip); + + --fSourcePipeSkip; + } + + PRINTF_BLIT (" PrvSrcPipeNextPixel: result: 0x%04X", result); + + return result; + } + + // We're getting the source pixel value from the display memory. + + uint16 result = this->PrvGetPixel (fXSrc, fYSrc); + + PRINTF_BLIT (" PrvSrcPipeNextPixel: fXSrc: %u", fXSrc); + PRINTF_BLIT (" PrvSrcPipeNextPixel: fYSrc: %u", fYSrc); + PRINTF_BLIT (" PrvSrcPipeNextPixel: result: 0x%04X", result); + + return result; +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::PrvSrcPipeNextX +// --------------------------------------------------------------------------- + +void EmRegsMediaQ11xx::PrvSrcPipeNextX (void) +{ + fXSrc += (fState.xDirection == 0) ? 1 : -1; +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::PrvSrcPipeNextY +// --------------------------------------------------------------------------- + +void EmRegsMediaQ11xx::PrvSrcPipeNextY (void) +{ + fYSrc += (fState.yDirection == 0) ? 1 : -1; + fXSrc = fState.xSrc; + + if (fState.xyConversion) + { + if (fState.xDirection) + fXSrc += fState.width - 1; + } + + fSourcePipeSkip = fTrailingSourcePixels/* + fLeadingSourcePixels*/; + + PRINTF_BLIT (" PrvSrcPipeNextY: fXSrc: %u", fXSrc); + PRINTF_BLIT (" PrvSrcPipeNextY: fYSrc: %u", fYSrc); + PRINTF_BLIT (" PrvSrcPipeNextY: fSourcePipeSkip: %u", fSourcePipeSkip); +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::PrvSrcPipeFill +// --------------------------------------------------------------------------- + +void EmRegsMediaQ11xx::PrvSrcPipeFill (Bool& stalled) +{ + // If there's no data in the FIFO, bail out. + + if (this->PrvSrcFifoFilledSlots () == 0) + { + PRINTF_BLIT (" PrvSrcPipeFill: stalled..."); + + stalled = true; + return; + } + + uint16* p = fSourcePipe; + UNUSED_PARAM(p); + + uint32 source1; + uint32 source2; + + this->PrvGetSrcFifoSlot (source1, source2); + + // If the source is monochrome, then expand it. + + if (fState.monoSource) + { + fSourcePipeMax = 64; + + PRINTF_BLIT (" PrvSrcPipeFill: expanding: 0x%08X 0x%08X", + source1, source2); + + this->PrvExpandMono32 (source1, &fSourcePipe[0], + fState.fgColorMonoSrc, fState.bgColorMonoSrc); + + this->PrvExpandMono32 (source2, &fSourcePipe[32], + fState.fgColorMonoSrc, fState.bgColorMonoSrc); + + PRINTF_BLIT (" PrvSrcPipeFill: 0: 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X", + p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); + PRINTF_BLIT (" PrvSrcPipeFill: 1: 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X", + p[8+0], p[8+1], p[8+2], p[8+3], p[8+4], p[8+5], p[8+6], p[8+7]); + PRINTF_BLIT (" PrvSrcPipeFill: 2: 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X", + p[16+0], p[16+1], p[16+2], p[16+3], p[16+4], p[16+5], p[16+6], p[16+7]); + PRINTF_BLIT (" PrvSrcPipeFill: 3: 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X", + p[24+0], p[24+1], p[24+2], p[24+3], p[24+4], p[24+5], p[24+6], p[24+7]); + PRINTF_BLIT (" PrvSrcPipeFill: 4: 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X", + p[32+0], p[32+1], p[32+2], p[32+3], p[32+4], p[32+5], p[32+6], p[32+7]); + PRINTF_BLIT (" PrvSrcPipeFill: 5: 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X", + p[40+0], p[40+1], p[40+2], p[40+3], p[40+4], p[40+5], p[40+6], p[40+7]); + PRINTF_BLIT (" PrvSrcPipeFill: 6: 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X", + p[48+0], p[48+1], p[48+2], p[48+3], p[48+4], p[48+5], p[48+6], p[48+7]); + PRINTF_BLIT (" PrvSrcPipeFill: 7: 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X", + p[54+0], p[54+1], p[54+2], p[54+3], p[54+4], p[54+5], p[54+6], p[54+7]); + } + + // If the source is in color, then break apart the 64-bit + // value we read into individual pixels. We'll get either + // 4 or 8 pixels, depending on the source depth. + + else if (fState.colorDepth == kColorDepth8) + { + fSourcePipeMax = 8; + + fSourcePipe[0] = (source1 >> 0) & 0x000000FF; + fSourcePipe[1] = (source1 >> 8) & 0x000000FF; + fSourcePipe[2] = (source1 >> 16) & 0x000000FF; + fSourcePipe[3] = (source1 >> 24) & 0x000000FF; + + fSourcePipe[4] = (source2 >> 0) & 0x000000FF; + fSourcePipe[5] = (source2 >> 8) & 0x000000FF; + fSourcePipe[6] = (source2 >> 16) & 0x000000FF; + fSourcePipe[7] = (source2 >> 24) & 0x000000FF; + + PRINTF_BLIT (" PrvSrcPipeFill: 0: 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X", + p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); + } + else if (fState.colorDepth == kColorDepth16) + { + fSourcePipeMax = 4; + + fSourcePipe[0] = (source1 >> 0) & 0x0000FFFF; + fSourcePipe[1] = (source1 >> 16) & 0x0000FFFF; + + fSourcePipe[2] = (source2 >> 0) & 0x0000FFFF; + fSourcePipe[3] = (source2 >> 16) & 0x0000FFFF; + + PRINTF_BLIT (" PrvSrcPipeFill: 0: 0x%04X 0x%04X 0x%04X 0x%04X", + p[0], p[1], p[2], p[3]); + } + else + { + EmAssert (false); + } +} + + +#pragma mark - + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::PrvDestPipeInit +// --------------------------------------------------------------------------- + +void EmRegsMediaQ11xx::PrvDestPipeInit (void) +{ + fXDest = fState.xDest; + fYDest = fState.yDest; + + if (fState.xyConversion) + { + if (fState.xDirection) + fXDest += fState.width - 1; + + if (fState.yDirection) + fYDest += fState.height - 1; + } + + PRINTF_BLIT (" PrvDestPipeInit: fXDest: %u", fXDest); + PRINTF_BLIT (" PrvDestPipeInit: fYDest: %u", fYDest); +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::PrvDestPipeNextPixel +// --------------------------------------------------------------------------- + +uint16 EmRegsMediaQ11xx::PrvDestPipeNextPixel (void) +{ + uint16 result = this->PrvGetPixel (fXDest, fYDest); + + PRINTF_BLIT (" PrvDestPipeNextPixel: fXDest: %u", fXDest); + PRINTF_BLIT (" PrvDestPipeNextPixel: fYDest: %u", fYDest); + PRINTF_BLIT (" PrvDestPipeNextPixel: result: 0x%04X", result); + + return result; +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::PrvDestPipeNextX +// --------------------------------------------------------------------------- + +void EmRegsMediaQ11xx::PrvDestPipeNextX (void) +{ + fXDest += (fState.xDirection == 0) ? 1 : -1; +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::PrvDestPipeNextY +// --------------------------------------------------------------------------- + +void EmRegsMediaQ11xx::PrvDestPipeNextY (void) +{ + fYDest += (fState.yDirection == 0) ? 1 : -1; + fXDest = fState.xDest; + + if (fState.xyConversion) + { + if (fState.xDirection) + fXDest += fState.width - 1; + } +} + + +#pragma mark - + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::PrvNextXY +// --------------------------------------------------------------------------- +// Increment our X and Y counters. If we we're done, return false. If we've +// moved to the next line, inform the various pipes that we've done that. If +// we've merely moved to the next pixel on the same line, inform the pipes +// that we've done that. + +Bool EmRegsMediaQ11xx::PrvNextXY (void) +{ + fCurXOffset += 1; + + if (fCurXOffset == fState.width) + { + fCurXOffset = 0; + fCurYOffset += 1; + + if (fCurYOffset == fState.height) + { + return false; + } + + this->PrvPatternPipeNextY (); + this->PrvSrcPipeNextY (); + this->PrvDestPipeNextY (); + } + else + { + this->PrvPatternPipeNextX (); + this->PrvSrcPipeNextX (); + this->PrvDestPipeNextX (); + } + + return true; +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::PrvTransparent +// --------------------------------------------------------------------------- + +Bool EmRegsMediaQ11xx::PrvTransparent (uint16 source, uint16 dest, uint16 pattern) +{ + if (fState.monoTransEnable) + { + if (fState.monoSource) + { + if (fState.monoTransPolarity == 0) + { + // Source background is transparent. + + if (source == fState.bgColorMonoSrc) + { + PRINTF_BLIT (" PrvTransparent: source == fState.bgColorMonoSrc..."); + return true; + } + } + else + { + // Source foreground is transparent. + + if (source == fState.fgColorMonoSrc) + { + PRINTF_BLIT (" PrvTransparent: source == fState.fgColorMonoSrc..."); + return true; + } + } + } + + if (fState.monoPattern) + { + if (fState.monoTransPolarity == 0) + { + // Source background is transparent. + + if (pattern == fState.bgColorMonoPat) + { + PRINTF_BLIT (" PrvTransparent: pattern == fState.bgColorMonoPat..."); + return true; + } + } + else + { + // Source foreground is transparent. + + if (pattern == fState.fgColorMonoPat) + { + PRINTF_BLIT (" PrvTransparent: pattern == fState.fgColorMonoPat..."); + return true; + } + } + } + } + + if (fState.colorTransEnable) + { + // Compare to source data. + + if (fState.colorTransCmpSrc == 0) + { + if (!fState.monoSource) + { + // Transparent if source is the same as the test color. + + if (fState.destTransPolarity == 0) + { + if (source == fState.destTransColor) + { + PRINTF_BLIT (" PrvTransparent: source == fState.destTransColor..."); + return true; + } + } + + // Transparent if source is different from the test color. + + else + { + if (source != fState.destTransColor) + { + PRINTF_BLIT (" PrvTransparent: source != fState.destTransColor..."); + return true; + } + } + } + } + + // Compare to destination data. + + else + { + // Transparent if dest is the same as the test color. + + if (fState.destTransPolarity == 0) + { + if (dest == fState.destTransColor) + { + PRINTF_BLIT (" PrvTransparent: dest == fState.destTransColor..."); + return true; + } + } + + // Transparent if dest is different from the test color. + + else + { + if (dest != fState.destTransColor) + { + PRINTF_BLIT (" PrvTransparent: dest != fState.destTransColor..."); + return true; + } + } + } + } + + return false; +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::PrvClipped +// --------------------------------------------------------------------------- + +Bool EmRegsMediaQ11xx::PrvClipped (void) +{ + if (fState.clipEnable) + { + if (fXDest < fState.clipLeft || fXDest >= fState.clipRight || + fYDest < fState.clipTop || fYDest >= fState.clipBottom) + { + PRINTF_BLIT (" PrvWriteIt: clipped out..."); + + return true; + } + } + + return false; +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::PrvLeadingPixels +// --------------------------------------------------------------------------- + +uint16 EmRegsMediaQ11xx::PrvLeadingPixels (void) +{ + uint16 result; + + if (fState.memToScreen) + { + // Packed Mode + + if (fState.monoSource) + { + result = fState.srcLeadingBits + 8 * fState.srcLeadingBytes; + } + else if (fState.colorDepth == kColorDepth8) + { + result = fState.srcLeadingBytes; + } + else if (fState.colorDepth == kColorDepth16) + { + EmAssert (::IsEven (fState.srcLeadingBytes)); + result = fState.srcLeadingBytes / 2; + } + else + { + EmAssert (false); + result = 0; + } + } + else + { + // Lined Mode + + if (fState.monoSource) + { + result = fState.srcBitOffset + 8 * fState.srcByteOffset; + } + else if (fState.colorDepth == kColorDepth8) + { + result = fState.srcByteOffset; + } + else if (fState.colorDepth == kColorDepth16) + { + EmAssert (::IsEven (fState.srcByteOffset)); + result = fState.srcByteOffset / 2; + } + else + { + EmAssert (false); + result = 0; + } + } + + EmAssert (result < 64); + + return result; +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::PrvTrailingPixels +// --------------------------------------------------------------------------- + +uint16 EmRegsMediaQ11xx::PrvTrailingPixels (void) +{ + uint16 result; + + if (fState.memToScreen) + { + // Packed Mode + + if (fState.monoSource) + { + result = fState.srcTrailingBits + 8 * fState.srcTrailingBytes; + } + else if (fState.colorDepth == kColorDepth8) + { + result = fState.srcTrailingBytes; + } + else if (fState.colorDepth == kColorDepth16) + { + EmAssert (::IsEven (fState.srcTrailingBytes)); + result = fState.srcTrailingBytes / 2; + } + else + { + EmAssert (false); + result = 0; + } + } + else + { + // Lined Mode + + uint16 bytesPerLine; + + if (!fState.systemMemory || fState.srcEqualDestStride) + { + bytesPerLine = fState.destLineStride; + } + else + { + bytesPerLine = fState.srcLineStride; + } + + uint16 pixelsPerLine; + + if (fState.monoSource) + { + pixelsPerLine = bytesPerLine * 8; + } + else if (fState.colorDepth == kColorDepth8) + { + pixelsPerLine = bytesPerLine; + } + else if (fState.colorDepth == kColorDepth16) + { + EmAssert (::IsEven (bytesPerLine)); + pixelsPerLine = bytesPerLine / 2; + } + else + { + EmAssert (false); + pixelsPerLine = 0; + } + + result = pixelsPerLine - (fState.width + fLeadingSourcePixels); + } + + EmAssert (result < 64); + + return result; +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::PrvUsesPattern +// --------------------------------------------------------------------------- +// Return whether or not the specified rasterOperation will require the use +// of a "pattern" value (that is, a pixel value from the pattern registers). +// +// To see if P is used in the output, consider the P, S, D combination +// table again: +// +// P S D O (output) +// --- --- --- --- +// 0 0 0 b0 +// 0 0 1 b1 +// 0 1 0 b2 +// 0 1 1 b3 +// 1 0 0 b4 +// 1 0 1 b5 +// 1 1 0 b6 +// 1 1 1 b7 +// +// If b0 == b4, b1 == b5, b2 == b6, and b3 == b7, then P has not figured into +// the result at all. That is, for any S & D combination, we got the same +// output regardless of what P was. Therefore, we can compare those bits to +// see if P is relevent to the outcome or not. +// +// We can quickly compare the bits by taking the ROP: +// +// b7 b6 b5 b4 b3 b2 b1 b0 +// +// Making a copy of it: +// +// b7 b6 b5 b4 b3 b2 b1 b0 +// b7 b6 b5 b4 b3 b2 b1 b0 +// +// Shifting the copy: +// +// b7 b6 b5 b4 b3 b2 b1 b0 +// 0 0 0 0 b7 b6 b5 b4 +// +// XORing the two: +// +// (b7^0) (b6^0) (b5^0) (b4^0) (b3^b7) (b2^b6) (b1^b5) (b0^b4) +// +// And then masking out bits 4, 5, 6, and 7, as they don't include +// results that we want: +// +// 0 0 0 0 (b3^b7) (b2^b6) (b1^b5) (b0^b4) +// +// Here, we have a bitfield containing the results of comparing the bits +// that we're interested in. We can test the whole result to see if it's +// zero or non-zero. + +Bool EmRegsMediaQ11xx::PrvUsesPattern (void) +{ + uint8 rop = fState.rasterOperation; + uint8 shifted = rop >> 4; + uint8 xored = rop ^ shifted; + uint8 masked = xored & 0x0F; + + return masked != 0; +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::PrvUsesSource +// --------------------------------------------------------------------------- +// Return whether or not the specified rasterOperation will require the use +// of a "source" value (that is, a pixel value from a source buffer). +// +// To see if S is used in the output, consider the P, S, D combination +// table again: +// +// P S D O (output) +// --- --- --- --- +// 0 0 0 b0 +// 0 0 1 b1 +// 0 1 0 b2 +// 0 1 1 b3 +// 1 0 0 b4 +// 1 0 1 b5 +// 1 1 0 b6 +// 1 1 1 b7 +// +// If b0 == b2, b1 == b3, b4 == b6, and b5 == b7, then S has not figured into +// the result at all. That is, for any P & D combination, we got the same +// output regardless of what S was. Therefore, we can compare those bits to +// see if S is relevent to the outcome or not. +// +// We can quickly compare the bits by taking the ROP: +// +// b7 b6 b5 b4 b3 b2 b1 b0 +// +// Making a copy of it: +// +// b7 b6 b5 b4 b3 b2 b1 b0 +// b7 b6 b5 b4 b3 b2 b1 b0 +// +// Shifting the copy: +// +// b7 b6 b5 b4 b3 b2 b1 b0 +// 0 0 b7 b6 b5 b4 b3 b2 +// +// XORing the two: +// +// (b7^0) (b6^0) (b5^b7) (b4^b6) (b3^b5) (b2^b4) (b1^b3) (b0^b2) +// +// And then masking out bits 2, 3, 6, and 7, as they don't include +// results that we want: +// +// 0 0 (b5^b7) (b4^b6) 0 0 (b1^b3) (b0^b2) +// +// Here, we have a bitfield containing the results of comparing the bits +// that we're interested in. We can test the whole result to see if it's +// zero or non-zero. + +Bool EmRegsMediaQ11xx::PrvUsesSource (void) +{ + uint8 rop = fState.rasterOperation; + uint8 shifted = rop >> 2; + uint8 xored = rop ^ shifted; + uint8 masked = xored & 0x33; + + return masked != 0; +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::PrvExpandMono8 +// --------------------------------------------------------------------------- +// Take a bit pattern, and expand it into an array of color values, where +// elements of the array are set to the foreground color if the bit in the +// pattern is one, and the background color if the bit is zero. + +void EmRegsMediaQ11xx::PrvExpandMono8 (uint8 bits, uint16* results, + uint16 fgColor, uint16 bgColor) +{ + if (fState.monoSrcBitSwap) + { + for (int ii = 0; ii < 8; ++ii) + { + if ((bits & (1 << ii)) != 0) + { + results[ii] = fgColor; + } + else + { + results[ii] = bgColor; + } + } + } + else + { + for (int ii = 0; ii < 8; ++ii) + { + if ((bits & (0x080 >> ii)) != 0) + { + results[ii] = fgColor; + } + else + { + results[ii] = bgColor; + } + } + } +} + + +// --------------------------------------------------------------------------- +// ¥ EmRegsMediaQ11xx::PrvExpandMono32 +// --------------------------------------------------------------------------- +// Wrapper to perform the expansion of 4 8-bit bitfields in a DWORD. + +void EmRegsMediaQ11xx::PrvExpandMono32 (uint32 bits, uint16* results, + uint16 fgColor, uint16 bgColor) +{ + this->PrvExpandMono8 (bits >> 0, &results[ 0], fgColor, bgColor); + this->PrvExpandMono8 (bits >> 8, &results[ 8], fgColor, bgColor); + this->PrvExpandMono8 (bits >> 16, &results[16], fgColor, bgColor); + this->PrvExpandMono8 (bits >> 24, &results[24], fgColor, bgColor); +} |