@@ -174,11 +174,34 @@ impl From<u8> for Attr {
174174
175175pub struct Gpu {
176176 glo : Rc < RefCell < Global > > ,
177+
178+ bcps : Bgpi ,
179+ // This register allows to read/write data to the CGBs Background Palette Memory, addressed through Register FF68.
180+ // Each color is defined by two bytes (Bit 0-7 in first byte).
181+ // Bit 0-4 Red Intensity (00-1F)
182+ // Bit 5-9 Green Intensity (00-1F)
183+ // Bit 10-14 Blue Intensity (00-1F)
184+ // Much like VRAM, data in Palette Memory cannot be read/written during the time when the LCD Controller is
185+ // reading from it. (That is when the STAT register indicates Mode 3). Note: All background colors are initialized
186+ // as white by the boot ROM, but it's a good idea to initialize at least one color yourself (for example if you
187+ // include a soft-reset mechanic).
188+ //
189+ // Note: Type [[[u8; 3]; 4]; 8] equals with [u8; 64].
190+ bcpd : [ [ [ u8 ; 3 ] ; 4 ] ; 8 ] ,
191+ // Digital image with mode RGB. Size = 144 * 160 * 3.
192+ // 3---------
193+ // ----------
194+ // ----------
195+ // ---------- 160
196+ // 144
197+ data : [ [ [ u8 ; 3 ] ; SCREEN_W ] ; SCREEN_H ] ,
177198 // The LCD controller operates on a 222 Hz = 4.194 MHz dot clock. An entire frame is 154 scanlines, 70224 dots, or
178199 // 16.74 ms. On scanlines 0 through 143, the LCD controller cycles through modes 2, 3, and 0 once every 456 dots.
179200 // Scanlines 144 through 153 are mode 1.
180201 dots : u32 ,
181202 lcdc : Lcdc ,
203+ ocps : Bgpi ,
204+ ocpd : [ [ [ u8 ; 3 ] ; 4 ] ; 8 ] ,
182205 // Extra dots to add to the mode3 threshold due to sprites on the current scanline. Computed when mode2 fires;
183206 // represents floor(T_penalty/4)*4 extra dots before mode0.
184207 pena : u32 ,
@@ -191,59 +214,8 @@ pub struct Gpu {
191214 // When a new scene is rendered, synchronization is triggered.
192215 sigv : Signal ,
193216 stat : Stat ,
194- // Scroll Y (R/W), Scroll X (R/W).
195- // Specifies the position in the 256x256 pixels BG map (32x32 tiles) which is to be displayed at the upper/left LCD
196- // display position. Values in range from 0-255 may be used for X/Y each, the video controller automatically wraps
197- // back to the upper (left) position in BG map when drawing exceeds the lower (right) border of the BG map area.
198- sx : u8 ,
199- sy : u8 ,
200- // Window Y Position (R/W), Window X Position minus 7 (R/W).
201- wx : u8 ,
202- wy : u8 ,
203- // The Gameboy permanently compares the value of the LYC and LY registers. When both values are identical, the
204- // coincident bit in the STAT register becomes set, and (if enabled) a STAT interrupt is requested.
205- lc : u8 ,
206- // The LY indicates the vertical line to which the present data is transferred to the LCD Driver. The LY can take
207- // on any value between 0 through 153. The values between 144 and 153 indicate the V-Blank period. Writing will
208- // reset the counter.
209- ly : u8 ,
210-
211- // Digital image with mode RGB. Size = 144 * 160 * 3.
212- // 3---------
213- // ----------
214- // ----------
215- // ---------- 160
216- // 144
217- pub data : [ [ [ u8 ; 3 ] ; SCREEN_W ] ; SCREEN_H ] ,
218-
219- // This register assigns gray shades to the color numbers of the BG and Window tiles.
220- bgp : u8 ,
221- // This register assigns gray shades for sprite palette 0. It works exactly as BGP (FF47), except that the lower
222- // two bits aren't used because sprite data 00 is transparent.
223- op0 : u8 ,
224- // This register assigns gray shades for sprite palette 1. It works exactly as BGP (FF47), except that the lower
225- // two bits aren't used because sprite data 00 is transparent.
226- op1 : u8 ,
227-
228- cbgpi : Bgpi ,
229- // This register allows to read/write data to the CGBs Background Palette Memory, addressed through Register FF68.
230- // Each color is defined by two bytes (Bit 0-7 in first byte).
231- // Bit 0-4 Red Intensity (00-1F)
232- // Bit 5-9 Green Intensity (00-1F)
233- // Bit 10-14 Blue Intensity (00-1F)
234- // Much like VRAM, data in Palette Memory cannot be read/written during the time when the LCD Controller is
235- // reading from it. (That is when the STAT register indicates Mode 3). Note: All background colors are initialized
236- // as white by the boot ROM, but it's a good idea to initialize at least one color yourself (for example if you
237- // include a soft-reset mechanic).
238- //
239- // Note: Type [[[u8; 3]; 4]; 8] equals with [u8; 64].
240- cbgpd : [ [ [ u8 ; 3 ] ; 4 ] ; 8 ] ,
241-
242- cobpi : Bgpi ,
243- cobpd : [ [ [ u8 ; 3 ] ; 4 ] ; 8 ] ,
244-
245217 ram : [ u8 ; 0x4000 ] ,
246- ram_bank : usize ,
218+ rbk : usize ,
247219 // VRAM Sprite Attribute Table (OAM)
248220 // Gameboy video controller can display up to 40 sprites either in 8x8 or in 8x16 pixels. Because of a limitation of
249221 // hardware, only ten sprites can be displayed per scan line. Sprite patterns have the same format as BG tiles, but
@@ -274,42 +246,69 @@ pub struct Gpu {
274246 // Bit3 Tile VRAM-Bank **CGB Mode Only** (0=Bank 0, 1=Bank 1)
275247 // Bit2-0 Palette number **CGB Mode Only** (OBP0-7)
276248 oam : [ u8 ; 0xa0 ] ,
277-
249+ // This register assigns gray shades to the color numbers of the BG and Window tiles.
250+ bgp : u8 ,
251+ // This register assigns gray shades for sprite palette 0. It works exactly as BGP (FF47), except that the lower
252+ // two bits aren't used because sprite data 00 is transparent.
253+ op0 : u8 ,
254+ // This register assigns gray shades for sprite palette 1. It works exactly as BGP (FF47), except that the lower
255+ // two bits aren't used because sprite data 00 is transparent.
256+ op1 : u8 ,
257+ // Scroll Y (R/W), Scroll X (R/W).
258+ // Specifies the position in the 256x256 pixels BG map (32x32 tiles) which is to be displayed at the upper/left LCD
259+ // display position. Values in range from 0-255 may be used for X/Y each, the video controller automatically wraps
260+ // back to the upper (left) position in BG map when drawing exceeds the lower (right) border of the BG map area.
261+ sx : u8 ,
262+ sy : u8 ,
263+ // Window Y Position (R/W), Window X Position minus 7 (R/W).
264+ wx : u8 ,
265+ wy : u8 ,
266+ // The Gameboy permanently compares the value of the LYC and LY registers. When both values are identical, the
267+ // coincident bit in the STAT register becomes set, and (if enabled) a STAT interrupt is requested.
268+ lc : u8 ,
269+ // The LY indicates the vertical line to which the present data is transferred to the LCD Driver. The LY can take
270+ // on any value between 0 through 153. The values between 144 and 153 indicate the V-Blank period. Writing will
271+ // reset the counter.
272+ ly : u8 ,
278273 prio : [ ( bool , usize ) ; SCREEN_W ] ,
279274}
280275
281276impl Gpu {
282277 pub fn power_up ( glo : Rc < RefCell < Global > > ) -> Self {
283278 Self {
284279 glo,
280+ bcps : Bgpi :: power_up ( ) ,
281+ bcpd : [ [ [ 0u8 ; 3 ] ; 4 ] ; 8 ] ,
282+ data : [ [ [ 0xffu8 ; 3 ] ; SCREEN_W ] ; SCREEN_H ] ,
285283 dots : 0 ,
286284 lcdc : Lcdc :: power_up ( ) ,
285+ ocps : Bgpi :: power_up ( ) ,
286+ ocpd : [ [ [ 0u8 ; 3 ] ; 4 ] ; 8 ] ,
287287 pena : 0 ,
288288 sigh : Signal :: power_up ( ) ,
289289 sigq : 0x00 ,
290290 sigv : Signal :: power_up ( ) ,
291291 stat : Stat :: power_up ( ) ,
292+ ram : [ 0x00 ; 0x4000 ] ,
293+ rbk : 0x00 ,
294+ oam : [ 0x00 ; 0xa0 ] ,
295+ bgp : 0x00 ,
296+ op0 : 0x00 ,
297+ op1 : 0x01 ,
292298 sx : 0x00 ,
293299 sy : 0x00 ,
294300 wx : 0x00 ,
295301 wy : 0x00 ,
296302 lc : 0x00 ,
297303 ly : 0x00 ,
298- data : [ [ [ 0xffu8 ; 3 ] ; SCREEN_W ] ; SCREEN_H ] ,
299- bgp : 0x00 ,
300- op0 : 0x00 ,
301- op1 : 0x01 ,
302- cbgpi : Bgpi :: power_up ( ) ,
303- cbgpd : [ [ [ 0u8 ; 3 ] ; 4 ] ; 8 ] ,
304- cobpi : Bgpi :: power_up ( ) ,
305- cobpd : [ [ [ 0u8 ; 3 ] ; 4 ] ; 8 ] ,
306- ram : [ 0x00 ; 0x4000 ] ,
307- ram_bank : 0x00 ,
308- oam : [ 0x00 ; 0xa0 ] ,
309304 prio : [ ( true , 0 ) ; SCREEN_W ] ,
310305 }
311306 }
312307
308+ pub fn image ( & self ) -> & [ [ [ u8 ; 3 ] ; SCREEN_W ] ; SCREEN_H ] {
309+ & self . data
310+ }
311+
313312 // DMG OAM corruption (mode 2 only). Row 0 and rows ≥20 are immune.
314313 pub fn oam_corrupt ( & mut self , kind : OamBug ) {
315314 if !self . lcdc . bit7 ( ) || self . stat . mode ( ) != 2 || self . ly >= 144 {
@@ -410,7 +409,7 @@ impl Gpu {
410409 match self . glo . clone ( ) . borrow ( ) . term {
411410 Term :: DMG => self . pixel_gre ( x, self . gray_shades ( self . bgp , col) ) ,
412411 Term :: CGB => {
413- let [ r, g, b] = self . cbgpd [ attr. paln ( ) ] [ col] ;
412+ let [ r, g, b] = self . bcpd [ attr. paln ( ) ] [ col] ;
414413 self . pixel_rgb ( x, r, g, b)
415414 }
416415 }
@@ -501,7 +500,7 @@ impl Gpu {
501500 self . pixel_gre ( sx as usize , self . gray_shades ( pal, col) ) ;
502501 }
503502 Term :: CGB => {
504- let [ r, g, b] = self . cobpd [ at. paln ( ) ] [ col] ;
503+ let [ r, g, b] = self . ocpd [ at. paln ( ) ] [ col] ;
505504 self . pixel_rgb ( sx as usize , r, g, b) ;
506505 }
507506 }
@@ -610,7 +609,7 @@ impl Memory for Gpu {
610609 // VRAM is locked during mode 3, and also during the 4T pre-mode-3 period (mode 2, dots >= 76) where
611610 // the bus is already claimed by the GPU, matching real DMG hardware bus timing.
612611 let locked = self . stat . mode ( ) == 3 || ( self . stat . mode ( ) == 2 && self . dots >= 76 ) ;
613- if !locked { self . ram [ self . ram_bank * 0x2000 + a as usize - 0x8000 ] } else { 0xff }
612+ if !locked { self . ram [ self . rbk * 0x2000 + a as usize - 0x8000 ] } else { 0xff }
614613 }
615614 0xfe00 ..=0xfe9f => {
616615 // OAM is locked (returns 0xFF) during mode 2 (OAM scan) and mode 3 (pixel transfer). It is also locked
@@ -631,32 +630,32 @@ impl Memory for Gpu {
631630 0xff49 => self . op1 ,
632631 0xff4a => self . wy ,
633632 0xff4b => self . wx ,
634- 0xff4f => 0xfe | self . ram_bank as u8 ,
635- 0xff68 => self . cbgpi . lb ( 0xff68 ) ,
633+ 0xff4f => 0xfe | self . rbk as u8 ,
634+ 0xff68 => self . bcps . lb ( 0xff68 ) ,
636635 0xff69 => {
637- let r = self . cbgpi . addr ( ) as usize >> 3 ;
638- let c = self . cbgpi . addr ( ) as usize >> 1 & 0x3 ;
639- if self . cbgpi . addr ( ) & 0x01 == 0x00 {
640- let a = self . cbgpd [ r] [ c] [ 0 ] ;
641- let b = self . cbgpd [ r] [ c] [ 1 ] << 5 ;
636+ let r = self . bcps . addr ( ) as usize >> 3 ;
637+ let c = self . bcps . addr ( ) as usize >> 1 & 0x3 ;
638+ if self . bcps . addr ( ) & 0x01 == 0x00 {
639+ let a = self . bcpd [ r] [ c] [ 0 ] ;
640+ let b = self . bcpd [ r] [ c] [ 1 ] << 5 ;
642641 a | b
643642 } else {
644- let a = self . cbgpd [ r] [ c] [ 1 ] >> 3 ;
645- let b = self . cbgpd [ r] [ c] [ 2 ] << 2 ;
643+ let a = self . bcpd [ r] [ c] [ 1 ] >> 3 ;
644+ let b = self . bcpd [ r] [ c] [ 2 ] << 2 ;
646645 a | b
647646 }
648647 }
649- 0xff6a => self . cobpi . lb ( 0xff6a ) ,
648+ 0xff6a => self . ocps . lb ( 0xff6a ) ,
650649 0xff6b => {
651- let r = self . cobpi . addr ( ) as usize >> 3 ;
652- let c = self . cobpi . addr ( ) as usize >> 1 & 0x3 ;
653- if self . cobpi . addr ( ) & 0x01 == 0x00 {
654- let a = self . cobpd [ r] [ c] [ 0 ] ;
655- let b = self . cobpd [ r] [ c] [ 1 ] << 5 ;
650+ let r = self . ocps . addr ( ) as usize >> 3 ;
651+ let c = self . ocps . addr ( ) as usize >> 1 & 0x3 ;
652+ if self . ocps . addr ( ) & 0x01 == 0x00 {
653+ let a = self . ocpd [ r] [ c] [ 0 ] ;
654+ let b = self . ocpd [ r] [ c] [ 1 ] << 5 ;
656655 a | b
657656 } else {
658- let a = self . cobpd [ r] [ c] [ 1 ] >> 3 ;
659- let b = self . cobpd [ r] [ c] [ 2 ] << 2 ;
657+ let a = self . ocpd [ r] [ c] [ 1 ] >> 3 ;
658+ let b = self . ocpd [ r] [ c] [ 2 ] << 2 ;
660659 a | b
661660 }
662661 }
@@ -670,7 +669,7 @@ impl Memory for Gpu {
670669 if self . stat . mode ( ) == 3 {
671670 return ;
672671 }
673- self . ram [ self . ram_bank * 0x2000 + a as usize - 0x8000 ] = v;
672+ self . ram [ self . rbk * 0x2000 + a as usize - 0x8000 ] = v;
674673 }
675674 0xfe00 ..=0xfe9f => {
676675 // OAM writes are ignored during mode 3 (pixel transfer) and during mode 2 (OAM scan) while dots < 76.
@@ -726,35 +725,35 @@ impl Memory for Gpu {
726725 0xff49 => self . op1 = v,
727726 0xff4a => self . wy = v,
728727 0xff4b => self . wx = v,
729- 0xff4f => self . ram_bank = ( v & 0x01 ) as usize ,
730- 0xff68 => self . cbgpi . sb ( 0xff68 , v) ,
728+ 0xff4f => self . rbk = ( v & 0x01 ) as usize ,
729+ 0xff68 => self . bcps . sb ( 0xff68 , v) ,
731730 0xff69 => {
732- let r = self . cbgpi . addr ( ) as usize >> 3 ;
733- let c = self . cbgpi . addr ( ) as usize >> 1 & 0x03 ;
734- if self . cbgpi . addr ( ) & 0x01 == 0x00 {
735- self . cbgpd [ r] [ c] [ 0 ] = v & 0x1f ;
736- self . cbgpd [ r] [ c] [ 1 ] = ( self . cbgpd [ r] [ c] [ 1 ] & 0x18 ) | ( v >> 5 ) ;
731+ let r = self . bcps . addr ( ) as usize >> 3 ;
732+ let c = self . bcps . addr ( ) as usize >> 1 & 0x03 ;
733+ if self . bcps . addr ( ) & 0x01 == 0x00 {
734+ self . bcpd [ r] [ c] [ 0 ] = v & 0x1f ;
735+ self . bcpd [ r] [ c] [ 1 ] = ( self . bcpd [ r] [ c] [ 1 ] & 0x18 ) | ( v >> 5 ) ;
737736 } else {
738- self . cbgpd [ r] [ c] [ 1 ] = ( self . cbgpd [ r] [ c] [ 1 ] & 0x07 ) | ( ( v & 0x03 ) << 3 ) ;
739- self . cbgpd [ r] [ c] [ 2 ] = ( v >> 2 ) & 0x1f ;
737+ self . bcpd [ r] [ c] [ 1 ] = ( self . bcpd [ r] [ c] [ 1 ] & 0x07 ) | ( ( v & 0x03 ) << 3 ) ;
738+ self . bcpd [ r] [ c] [ 2 ] = ( v >> 2 ) & 0x1f ;
740739 }
741- if self . cbgpi . auto ( ) {
742- self . cbgpi . incr ( ) ;
740+ if self . bcps . auto ( ) {
741+ self . bcps . incr ( ) ;
743742 }
744743 }
745- 0xff6a => self . cobpi . sb ( 0xff6a , v) ,
744+ 0xff6a => self . ocps . sb ( 0xff6a , v) ,
746745 0xff6b => {
747- let r = self . cobpi . addr ( ) as usize >> 3 ;
748- let c = self . cobpi . addr ( ) as usize >> 1 & 0x03 ;
749- if self . cobpi . addr ( ) & 0x01 == 0x00 {
750- self . cobpd [ r] [ c] [ 0 ] = v & 0x1f ;
751- self . cobpd [ r] [ c] [ 1 ] = ( self . cobpd [ r] [ c] [ 1 ] & 0x18 ) | ( v >> 5 ) ;
746+ let r = self . ocps . addr ( ) as usize >> 3 ;
747+ let c = self . ocps . addr ( ) as usize >> 1 & 0x03 ;
748+ if self . ocps . addr ( ) & 0x01 == 0x00 {
749+ self . ocpd [ r] [ c] [ 0 ] = v & 0x1f ;
750+ self . ocpd [ r] [ c] [ 1 ] = ( self . ocpd [ r] [ c] [ 1 ] & 0x18 ) | ( v >> 5 ) ;
752751 } else {
753- self . cobpd [ r] [ c] [ 1 ] = ( self . cobpd [ r] [ c] [ 1 ] & 0x07 ) | ( ( v & 0x03 ) << 3 ) ;
754- self . cobpd [ r] [ c] [ 2 ] = ( v >> 2 ) & 0x1f ;
752+ self . ocpd [ r] [ c] [ 1 ] = ( self . ocpd [ r] [ c] [ 1 ] & 0x07 ) | ( ( v & 0x03 ) << 3 ) ;
753+ self . ocpd [ r] [ c] [ 2 ] = ( v >> 2 ) & 0x1f ;
755754 }
756- if self . cobpi . auto ( ) {
757- self . cobpi . incr ( ) ;
755+ if self . ocps . auto ( ) {
756+ self . ocps . incr ( ) ;
758757 }
759758 }
760759 _ => unreachable ! ( ) ,
0 commit comments