/* -*- 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 // 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 . 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: // // // 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 . 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: "); 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); }