Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

570 lines
21 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: hw.h
  3. *
  4. * All the hardware specific driver file stuff. Parts are mirrored in
  5. * 'hw.inc'.
  6. *
  7. * Copyright (c) 1992-1995 Microsoft Corporation
  8. *
  9. \**************************************************************************/
  10. //
  11. // Private IOCTL definitions for communicating with the Weitek miniport.
  12. //
  13. // NOTE: These must match the Weitek miniport definitions!
  14. //
  15. #define IOCTL_VIDEO_GET_BASE_ADDR \
  16. CTL_CODE (FILE_DEVICE_VIDEO, 2048, METHOD_BUFFERED, FILE_ANY_ACCESS)
  17. typedef struct _VIDEO_COPROCESSOR_INFORMATION {
  18. ULONG CoprocessorID; // 0 == p9000, 1 = p9100
  19. ULONG FrameBufferBase;
  20. ULONG CoprocessorBase;
  21. } VIDEO_COPROCESSOR_INFORMATION, *PVIDEO_COPROCESSOR_INFORMATION;
  22. //////////////////////////////////////////////////////////////////////
  23. // Shared p9000 and p9100 Coproc Registers Address Constant definitions
  24. //
  25. #define Status 0x80000 //status register
  26. #define Wmin 0x80220 //pixel clipping window minimum register
  27. #define Wmax 0x80224 //and maximum register
  28. #define Woffset 0x80190 //window offset register
  29. #define Quad 0x80008 //draw a quadrilateral
  30. #define Bitblt 0x80004 //screen to screen blit
  31. #define Pixel8 0xE000C //host to screen color pixel transfer
  32. #define Pixel1 0xE0080 //host to screen mono pixel transfer w/ expansion
  33. #define Pixel1Full 0xE00FC //same as above w/ 32bit wide pixels
  34. #define Nextpixel 0x80014 //next pixel
  35. #define PatternOrgX 0x80210 //pattern orgin x
  36. #define PatternOrgY 0x80214 //pattern orgin y
  37. #define PatternRAM 0xE0280 //pattern ram
  38. #define Raster 0x80218 //raster register to write
  39. #define Metacord 0x81218 //meta-coordinate register
  40. #define Xy0 0x81018 //abs screen addr
  41. #define Xy1 0x81058 //r/w 16-bit x (hi)
  42. #define Xy2 0x81098 // and
  43. #define Xy3 0x810D8 // 16-bit y (lo)
  44. #define X0 0x81008 //abs screen addr
  45. #define X1 0x81048
  46. #define X2 0x81088
  47. #define X3 0x810C8
  48. #define Y0 0x81010 //abs screen addr
  49. #define Y1 0x81050
  50. #define Y2 0x81090
  51. #define Y3 0x810D0
  52. #define WoffsetBit 0x00020 //bit to set for coordinates relative
  53. //to window offset
  54. //
  55. // p9000 Coproc Registers Address Constant definitions
  56. //
  57. #define Foreground 0x80200 //P9000 foreground color register
  58. #define Background 0x80204 //P9000 background color register
  59. //
  60. // p9100 Coproc Registers Address Constant definitions
  61. //
  62. #define Wmin_b 0x802A0 //byte clipping window minimum register
  63. #define Wmax_b 0x802A4 //and maximum register
  64. #define Color0 0xE0200 //P9100 color[0] register
  65. #define Color1 0xE0204 //P9100 color[1] register
  66. #define Color2 0xE0238 //P9100 color[2] register
  67. #define Color3 0xE023C //P9100 color[3] register
  68. // We try to share as many register constants as we can between the
  69. // P9000 and the P9100, so that we don't have to duplicate code.
  70. // But the base offset for the registers we used changed somewhat;
  71. // we apply this corrector to the I/O base pointer to compensate:
  72. #define P9100_BASE_CORRECTION (0x2000L - 0x80000L)
  73. //////////////////////////////////////////////////////////////////////
  74. // Shared p9000 and p9100 Coproc Registers bit template definitions
  75. //
  76. #define BUSY 0x40000000L //busy, but can start quad or bitblit
  77. #define QBUSY 0x80000000L //busy, cannot start quad or bitblt
  78. #define QUADFAIL 0x10 //QUAD failed, use software to draw this
  79. #define MetaRect 0x100 //or with METACORD when entering rectangles
  80. #define MetaLine 0x040 //or with METACORD when entering line
  81. #define MetaQuad 0x0C0 //or with METACORD when entering quad
  82. #define MetaTri 0x080 //or with METACORD when entering triangle
  83. //
  84. // p9000 Coproc Registers bit template definitions
  85. //
  86. // For the raster register:
  87. #define P9000_ENABLE_PATTERN 0x20000 //enable pattern
  88. #define P9000_OVERSIZED 0x10000 //enable oversized mode
  89. #define P9000_F 0xff00L
  90. #define P9000_B 0xf0f0L
  91. #define P9000_S 0xccccL
  92. #define P9000_D 0xaaaaL
  93. #define P9000_OPAQUE_EXPAND 0xfc30L
  94. #define P9000_TRANSPARENT_EXPAND 0xee22L
  95. //
  96. // p9100 Coproc Registers bit template definitions
  97. //
  98. // For the raster register:
  99. #define P9100_TRANSPARENT_PATTERN 0x20000 //enable transparent pattern
  100. #define P9100_OVERSIZED 0x10000 //enable oversized mode
  101. #define P9100_PIXEL1_TRANSPARENT 0x08000 //enable pixel1 transparent mode
  102. #define P9100_FOUR_COLOR_PATTERN 0x04000 //4 colour pattern (8bpp only)
  103. #define P9100_ENABLE_PATTERN 0x02000 //enable pattern
  104. #define P9100_P 0x00f0L
  105. #define P9100_S 0x00ccL
  106. #define P9100_D 0x00aaL
  107. #define P9100_OPAQUE_EXPAND P9100_S
  108. #define P9100_TRANSPARENT_EXPAND (P9100_S | P9100_PIXEL1_TRANSPARENT)
  109. //////////////////////////////////////////////////////////////////////
  110. // Alpha and PowerPC considerations
  111. //
  112. // Both the Alpha and the PowerPC do not guarantee that I/O to
  113. // separate addresses will be executed in order. The Alpha and
  114. // PowerPC differ, however, in that the PowerPC guarantees that
  115. // output to the same address will be executed in order, while the
  116. // Alpha may cache and 'collapse' consecutive output to become only
  117. // one output.
  118. //
  119. // Consequently, we use the following synchronization macros. They
  120. // are relatively expensive in terms of performance, so we try to avoid
  121. // them whereever possible.
  122. //
  123. // CP_EIEIO() 'Ensure In-order Execution of I/O'
  124. // - Used to flush any pending I/O in situations where we wish to
  125. // avoid out-of-order execution of I/O to separate addresses.
  126. //
  127. // CP_MEMORY_BARRIER()
  128. // - Used to flush any pending I/O in situations where we wish to
  129. // avoid out-of-order execution or 'collapsing' of I/O to
  130. // the same address. On the PowerPC, this will be defined as
  131. // a null operation.
  132. #if defined(_PPC_)
  133. // On PowerPC, CP_MEMORY_BARRIER doesn't do anything.
  134. #define CP_EIEIO() MEMORY_BARRIER()
  135. #define CP_MEMORY_BARRIER()
  136. #else
  137. // On Alpha, CP_EIEIO is the same thing as a CP_MEMORY_BARRIER.
  138. // On other systems, both CP_EIEIO and CP_MEMORY_BARRIER don't do anything.
  139. #define CP_EIEIO() MEMORY_BARRIER()
  140. #define CP_MEMORY_BARRIER() MEMORY_BARRIER()
  141. #endif
  142. //////////////////////////////////////////////////////////////////////
  143. // Access macros:
  144. //
  145. #define MAX_COORD 0x3fff
  146. #define CP_OUT(pjBase, cjOffset, ul) \
  147. WRITE_REGISTER_ULONG((BYTE*) pjBase + (cjOffset), (ULONG) (ul))
  148. #define CP_IN(pjBase, cjOffset) \
  149. READ_REGISTER_ULONG((BYTE*) pjBase + (cjOffset))
  150. // Note that we have to be careful if 'y' is negative that its signed
  151. // bits don't get ORed into the 'x' component:
  152. #define PACKXY(x, y) (((x) << 16) | ((y) & 0xffff))
  153. #define CP_WAIT(ppdev, pjBase) \
  154. { \
  155. do {CP_EIEIO();} while (CP_IN(pjBase, Status) & BUSY); \
  156. CP_EIEIO(); \
  157. }
  158. #define CP_RASTER(ppdev, pjBase, x) \
  159. { \
  160. ASSERTDD(P9000(ppdev) || ((x) & 0x01f00) == 0, \
  161. "Illegal P9100 raster value"); \
  162. CP_OUT(pjBase, Raster, (x)); \
  163. }
  164. #define CP_NEXT_PIXELS(ppdev, pjBase, x) \
  165. CP_OUT(pjBase, Nextpixel, (x));
  166. #define CP_START_QUAD(ppdev, pjBase) \
  167. { \
  168. CP_EIEIO(); \
  169. CP_IN(pjBase, Quad); \
  170. CP_EIEIO(); \
  171. }
  172. #define CP_START_QUAD_STAT(ppdev, pjBase, stat) \
  173. { \
  174. CP_EIEIO(); \
  175. stat = CP_IN(pjBase, Quad); \
  176. CP_EIEIO(); \
  177. }
  178. #define CP_START_QUAD_WAIT(ppdev, pjBase) \
  179. { \
  180. do { \
  181. CP_EIEIO(); \
  182. } while (CP_IN(pjBase, Quad) & QBUSY); \
  183. CP_EIEIO(); \
  184. }
  185. #define CP_START_BLT(ppdev, pjBase) \
  186. { \
  187. CP_EIEIO(); \
  188. CP_IN(pjBase, Bitblt); \
  189. CP_EIEIO(); \
  190. }
  191. #define CP_START_BLT_WAIT(ppdev, pjBase) \
  192. { \
  193. do { \
  194. CP_EIEIO(); \
  195. } while (CP_IN(pjBase, Bitblt) & QBUSY); \
  196. CP_EIEIO(); \
  197. }
  198. #define CP_START_QUAD(ppdev, pjBase) \
  199. { \
  200. CP_EIEIO(); \
  201. CP_IN(pjBase, Quad); \
  202. CP_EIEIO(); \
  203. }
  204. #define CP_START_PIXEL8(ppdev, pjBase) \
  205. CP_EIEIO();
  206. #define CP_END_PIXEL8(ppdev, pjBase) \
  207. CP_EIEIO();
  208. #define CP_PIXEL8(ppdev, pjBase, x) \
  209. { \
  210. CP_OUT(pjBase, Pixel8, (x)); \
  211. CP_MEMORY_BARRIER(); \
  212. }
  213. #define CP_START_PIXEL1(ppdev, pjBase) \
  214. CP_EIEIO();
  215. #define CP_END_PIXEL1(ppdev, pjBase) \
  216. CP_EIEIO();
  217. #define CP_PIXEL1(ppdev, pjBase, x) \
  218. { \
  219. CP_OUT(pjBase, Pixel1Full, (x)); \
  220. CP_MEMORY_BARRIER(); \
  221. }
  222. // Note: 'count' must be pre-decremented by 1
  223. #define CP_PIXEL1_REM(ppdev, pjBase, count, x) \
  224. { \
  225. /* This EIEIO is to ensure we don't get out of */ \
  226. /* order with normal full CP_PIXEL1 writes */ \
  227. CP_EIEIO(); \
  228. CP_OUT(pjBase, Pixel1 + ((count) << 2), (x)); \
  229. }
  230. #define CP_PIXEL1_REM_REGISTER(ppdev, pjBase, count)\
  231. ((BYTE*) (pjBase) + Pixel1 + ((count) << 2))
  232. #define CP_PIXEL1_VIA_REGISTER(ppdev, pReg, x) \
  233. { \
  234. /* This EIEIO is to ensure we don't get out of */ \
  235. /* order with normal full CP_PIXEL1 writes */ \
  236. CP_EIEIO(); \
  237. WRITE_REGISTER_ULONG(pReg, (x)); \
  238. }
  239. #define CP_PATTERN(ppdev, pjBase, index, x) \
  240. CP_OUT(pjBase, PatternRAM + ((index) << 2), (x))
  241. #define CP_PATTERN_ORGX(ppdev, pjBase, x) \
  242. CP_OUT(pjBase, PatternOrgX, (x))
  243. #define CP_PATTERN_ORGY(ppdev, pjBase, x) \
  244. CP_OUT(pjBase, PatternOrgY, (x))
  245. //
  246. #define CP_METALINE(ppdev, pjBase, x, y) \
  247. { \
  248. CP_OUT(pjBase, Metacord | MetaLine, \
  249. PACKXY((x) + ppdev->xOffset, (y) + ppdev->yOffset));\
  250. CP_MEMORY_BARRIER(); \
  251. }
  252. #define CP_METARECT(ppdev, pjBase, x, y) \
  253. { \
  254. CP_OUT(pjBase, Metacord | MetaRect, \
  255. PACKXY((x) + ppdev->xOffset, (y) + ppdev->yOffset));\
  256. CP_MEMORY_BARRIER(); \
  257. }
  258. #define CP_METAQUAD(ppdev, pjBase, x, y) \
  259. { \
  260. CP_OUT(pjBase, Metacord | MetaQuad, \
  261. PACKXY((x) + ppdev->xOffset, (y) + ppdev->yOffset));\
  262. CP_MEMORY_BARRIER(); \
  263. }
  264. #define CP_METATRI(ppdev, pjBase, x, y) \
  265. { \
  266. CP_OUT(pjBase, Metacord | MetaTri, \
  267. PACKXY((x) + ppdev->xOffset, (y) + ppdev->yOffset));\
  268. CP_MEMORY_BARRIER(); \
  269. }
  270. #define CP_WOFFSET(ppdev, pjBase, x, y) \
  271. CP_OUT(pjBase, Woffset, PACKXY((x), (y)))
  272. #define CP_WMIN(ppdev, pjBase, x, y) \
  273. CP_OUT(pjBase, P9000(ppdev) ? Wmin : Wmin_b, \
  274. PACKXY(((x) + ppdev->xOffset) * ppdev->cjPel, (y) + ppdev->yOffset))
  275. #define CP_WMAX(ppdev, pjBase, x, y) \
  276. CP_OUT(pjBase, P9000(ppdev) ? Wmax : Wmax_b, \
  277. PACKXY(((x) + ppdev->xOffset + 1) * ppdev->cjPel - 1, (y) + ppdev->yOffset))
  278. #define CP_WLEFT(ppdev, pjBase, x) \
  279. CP_OUT(pjBase, P9000(ppdev) ? Wmin : Wmin_b, \
  280. PACKXY(((x) + ppdev->xOffset) * ppdev->cjPel, 0))
  281. #define CP_WRIGHT(ppdev, pjBase, x) \
  282. CP_OUT(pjBase, P9000(ppdev) ? Wmax : Wmax_b, \
  283. PACKXY(((x) + ppdev->xOffset + 1) * ppdev->cjPel - 1, MAX_COORD))
  284. #define CP_XY0(ppdev, pjBase, x, y) \
  285. CP_OUT(pjBase, Xy0, PACKXY((x) + ppdev->xOffset, (y) + ppdev->yOffset))
  286. #define CP_XY1(ppdev, pjBase, x, y) \
  287. CP_OUT(pjBase, Xy1, PACKXY((x) + ppdev->xOffset, (y) + ppdev->yOffset))
  288. #define CP_XY2(ppdev, pjBase, x, y) \
  289. CP_OUT(pjBase, Xy2, PACKXY((x) + ppdev->xOffset, (y) + ppdev->yOffset))
  290. #define CP_XY3(ppdev, pjBase, x, y) \
  291. CP_OUT(pjBase, Xy3, PACKXY((x) + ppdev->xOffset, (y) + ppdev->yOffset))
  292. #define CP_X0(ppdev, pjBase, x) \
  293. CP_OUT(pjBase, X0, (x) + ppdev->xOffset)
  294. #define CP_X1(ppdev, pjBase, x) \
  295. CP_OUT(pjBase, X1, (x) + ppdev->xOffset)
  296. #define CP_X2(ppdev, pjBase, x) \
  297. CP_OUT(pjBase, X2, (x) + ppdev->xOffset)
  298. #define CP_X3(ppdev, pjBase, x) \
  299. CP_OUT(pjBase, X3, (x) + ppdev->xOffset)
  300. #define CP_Y0(ppdev, pjBase, y) \
  301. CP_OUT(pjBase, Y0, (y) + ppdev->yOffset)
  302. #define CP_Y1(ppdev, pjBase, y) \
  303. CP_OUT(pjBase, Y1, (y) + ppdev->yOffset)
  304. #define CP_Y2(ppdev, pjBase, y) \
  305. CP_OUT(pjBase, Y2, (y) + ppdev->yOffset)
  306. #define CP_Y3(ppdev, pjBase, y) \
  307. CP_OUT(pjBase, Y3, (y) + ppdev->yOffset)
  308. //
  309. #define CP_WOFF_PACKED_XY0(ppdev, pjBase, xy) \
  310. CP_OUT(pjBase, Xy0 | WoffsetBit, (xy))
  311. #define CP_WOFF_PACKED_XY1(ppdev, pjBase, xy) \
  312. CP_OUT(pjBase, Xy1 | WoffsetBit, (xy))
  313. #define CP_WOFF_PACKED_XY2(ppdev, pjBase, xy) \
  314. CP_OUT(pjBase, Xy2 | WoffsetBit, (xy))
  315. #define CP_WOFF_PACKED_XY3(ppdev, pjBase, xy) \
  316. CP_OUT(pjBase, Xy3 | WoffsetBit, (xy))
  317. #define CP_ABS_PACKED_XY0(ppdev, pjBase, xy) \
  318. CP_OUT(pjBase, Xy0, (xy))
  319. #define CP_ABS_PACKED_XY1(ppdev, pjBase, xy) \
  320. CP_OUT(pjBase, Xy1, (xy))
  321. #define CP_ABS_PACKED_XY2(ppdev, pjBase, xy) \
  322. CP_OUT(pjBase, Xy2, (xy))
  323. #define CP_ABS_PACKED_XY3(ppdev, pjBase, xy) \
  324. CP_OUT(pjBase, Xy3, (xy))
  325. //
  326. #define CP_ABS_WMIN(ppdev, pjBase, x, y) \
  327. CP_OUT(pjBase, P9000(ppdev) ? Wmin : Wmin_b, \
  328. PACKXY((x) * ppdev->cjPel, (y)))
  329. #define CP_ABS_WMAX(ppdev, pjBase, x, y) \
  330. CP_OUT(pjBase, P9000(ppdev) ? Wmax : Wmax_b, \
  331. PACKXY(((x) + 1) * ppdev->cjPel - 1, (y)))
  332. #define CP_ABS_WLEFT(ppdev, pjBase, x) \
  333. CP_OUT(pjBase, P9000(ppdev) ? Wmin : Wmin_b, \
  334. PACKXY((x) * ppdev->cjPel, 0))
  335. #define CP_ABS_WRIGHT(ppdev, pjBase, x) \
  336. CP_OUT(pjBase, P9000(ppdev) ? Wmax : Wmax_b, \
  337. PACKXY(((x) + 1) * ppdev->cjPel - 1, MAX_COORD))
  338. #define CP_ABS_METARECT(ppdev, pjBase, x, y) \
  339. { \
  340. CP_OUT(pjBase, Metacord | MetaRect, PACKXY((x), (y)));\
  341. CP_MEMORY_BARRIER(); \
  342. }
  343. #define CP_ABS_XY0(ppdev, pjBase, x, y) \
  344. CP_OUT(pjBase, Xy0, PACKXY((x), (y)))
  345. #define CP_ABS_XY1(ppdev, pjBase, x, y) \
  346. CP_OUT(pjBase, Xy1, PACKXY((x), (y)))
  347. #define CP_ABS_XY2(ppdev, pjBase, x, y) \
  348. CP_OUT(pjBase, Xy2, PACKXY((x), (y)))
  349. #define CP_ABS_XY3(ppdev, pjBase, x, y) \
  350. CP_OUT(pjBase, Xy3, PACKXY((x), (y)))
  351. #define CP_ABS_PACKED_XY0(ppdev, pjBase, x) \
  352. CP_OUT(pjBase, Xy0, (x))
  353. #define CP_ABS_PACKED_XY1(ppdev, pjBase, x) \
  354. CP_OUT(pjBase, Xy1, (x))
  355. #define CP_ABS_PACKED_XY2(ppdev, pjBase, x) \
  356. CP_OUT(pjBase, Xy2, (x))
  357. #define CP_ABS_PACKED_XY3(ppdev, pjBase, x) \
  358. CP_OUT(pjBase, Xy3, (x))
  359. #define CP_ABS_X0(ppdev, pjBase, y) \
  360. CP_OUT(pjBase, X0, (y))
  361. #define CP_ABS_X1(ppdev, pjBase, y) \
  362. CP_OUT(pjBase, X1, (y))
  363. #define CP_ABS_X2(ppdev, pjBase, y) \
  364. CP_OUT(pjBase, X2, (y))
  365. #define CP_ABS_X3(ppdev, pjBase, y) \
  366. CP_OUT(pjBase, X3, (y))
  367. #define CP_ABS_Y0(ppdev, pjBase, y) \
  368. CP_OUT(pjBase, Y0, (y))
  369. #define CP_ABS_Y1(ppdev, pjBase, y) \
  370. CP_OUT(pjBase, Y1, (y))
  371. #define CP_ABS_Y2(ppdev, pjBase, y) \
  372. CP_OUT(pjBase, Y2, (y))
  373. #define CP_ABS_Y3(ppdev, pjBase, y) \
  374. CP_OUT(pjBase, Y3, (y))
  375. ///////////////////////////////////////////////////////////////////
  376. // P9000 only macros
  377. //
  378. #define CP_FOREGROUND(ppdev, pjBase, x) \
  379. { \
  380. ASSERTDD(ppdev->flStat & STAT_P9000, "Foreground"); \
  381. CP_OUT(pjBase, Foreground, (x)); \
  382. }
  383. #define CP_BACKGROUND(ppdev, pjBase, x) \
  384. { \
  385. ASSERTDD(ppdev->flStat & STAT_P9000, "Background"); \
  386. CP_OUT(pjBase, Background, (x)); \
  387. }
  388. ///////////////////////////////////////////////////////////////////
  389. // P9100 only macros
  390. //
  391. #define PACK_COLOR(ppdev, x, ulResult) \
  392. { \
  393. ulResult = (x); \
  394. if (ppdev->flStat & STAT_8BPP) \
  395. { \
  396. ulResult |= (ulResult << 8); \
  397. ulResult |= (ulResult << 16); \
  398. } \
  399. else if (ppdev->flStat & STAT_16BPP) \
  400. ulResult |= (ulResult << 16); \
  401. else if (ppdev->flStat & STAT_24BPP) \
  402. ulResult |= (ulResult << 24); \
  403. }
  404. #define CP_COLOR0(ppdev, pjBase, x) \
  405. { \
  406. ULONG ul; \
  407. ASSERTDD(!(ppdev->flStat & STAT_P9000), "Color0"); \
  408. PACK_COLOR(ppdev, (x), ul); \
  409. CP_OUT(pjBase, Color0, ul); \
  410. }
  411. #define CP_COLOR1(ppdev, pjBase, x) \
  412. { \
  413. ULONG ul; \
  414. ASSERTDD(!(ppdev->flStat & STAT_P9000), "Color1"); \
  415. PACK_COLOR(ppdev, (x), ul); \
  416. CP_OUT(pjBase, Color1, ul); \
  417. }
  418. // The _FAST colour macros take colours that are pre-packed for
  419. // the P9100:
  420. #define CP_COLOR0_FAST(ppdev, pjBase, x) \
  421. { \
  422. ASSERTDD(!(ppdev->flStat & STAT_P9000), "Color0"); \
  423. CP_OUT(pjBase, Color0, (x)); \
  424. }
  425. #define CP_COLOR1_FAST(ppdev, pjBase, x) \
  426. { \
  427. ASSERTDD(!(ppdev->flStat & STAT_P9000), "Color1"); \
  428. CP_OUT(pjBase, Color1, (x)); \
  429. }
  430. #define CP_COLOR2_FAST(ppdev, pjBase, x) \
  431. { \
  432. ASSERTDD(!(ppdev->flStat & STAT_P9000), "Color2"); \
  433. ASSERTDD(ppdev->flStat & STAT_8BPP, "Color2"); \
  434. CP_OUT(pjBase, Color2, (x)); \
  435. }
  436. #define CP_COLOR3_FAST(ppdev, pjBase, x) \
  437. { \
  438. ASSERTDD(!(ppdev->flStat & STAT_P9000), "Color3"); \
  439. ASSERTDD(ppdev->flStat & STAT_8BPP, "Color3"); \
  440. CP_OUT(pjBase, Color3, (x)); \
  441. }