1+ use crate :: memory:: Memory ;
12use crate :: nes_rom:: NametableMirroring ;
23use crate :: ppu:: ppu_memory:: PpuMemory ;
34
@@ -33,8 +34,10 @@ impl PpuAddr {
3334 ( ( self . hi as u16 ) << 8 | ( self . lo as u16 ) ) & PPU_ADDR_MASK
3435 }
3536
36- fn increment_addr ( & mut self , amount : u16 ) {
37- //TODO
37+ fn increment_addr ( & mut self , amount : u8 ) {
38+ let new_addr = self . get_addr ( ) . wrapping_add ( amount as u16 ) ;
39+ self . hi = ( new_addr >> 8 ) as u8 ;
40+ self . lo = ( new_addr & 0xFF ) as u8 ;
3841 }
3942}
4043
@@ -46,7 +49,7 @@ const PPU_SPRITE_SIZE_BIT: u8 = 5;
4649const PPU_MASTER_SLAVE_SELECT_BIT : u8 = 6 ;
4750const PPU_VBLANK_NMI_BIT : u8 = 7 ;
4851
49- struct PpuRegisters {
52+ pub struct Ppu < M : Memory > {
5053 ctrl : u8 ,
5154 mask : u8 ,
5255 status : u8 ,
@@ -56,10 +59,12 @@ struct PpuRegisters {
5659 addr : PpuAddr ,
5760 data_buffer : u8 ,
5861 oam_dma : u8 ,
62+
63+ memory : M ,
5964}
6065
61- impl PpuRegisters {
62- pub fn new ( ) -> Self {
66+ impl Ppu < PpuMemory > {
67+ pub fn new ( chr_rom : Vec < u8 > , mirroring : NametableMirroring ) -> Self {
6368 Self {
6469 ctrl : 0 ,
6570 mask : 0 ,
@@ -70,20 +75,117 @@ impl PpuRegisters {
7075 addr : PpuAddr :: new ( ) ,
7176 data_buffer : 0 ,
7277 oam_dma : 0 ,
78+ memory : PpuMemory :: new ( chr_rom, mirroring) ,
7379 }
7480 }
7581}
7682
77- pub struct Ppu {
78- registers : PpuRegisters ,
79- memory : PpuMemory ,
80- }
81-
82- impl Ppu {
83- pub fn new ( chr_rom : Vec < u8 > , mirroring : NametableMirroring ) -> Self {
83+ impl < M : Memory > Ppu < M > {
84+ fn new_with_memory ( memory : M ) -> Self {
8485 Self {
85- registers : PpuRegisters :: new ( ) ,
86- memory : PpuMemory :: new ( chr_rom, mirroring) ,
86+ ctrl : 0 ,
87+ mask : 0 ,
88+ status : 0 ,
89+ oam_addr : 0 ,
90+ oam_data : 0 ,
91+ scroll : 0 ,
92+ addr : PpuAddr :: new ( ) ,
93+ data_buffer : 0 ,
94+ oam_dma : 0 ,
95+ memory,
8796 }
8897 }
98+
99+ pub fn write_ppu_addr ( & mut self , value : u8 ) {
100+ self . addr . set ( value)
101+ }
102+
103+ pub fn read_ppu_data ( & mut self ) -> u8 {
104+ let addr = self . addr . get_addr ( ) ;
105+ let result = if ( 0x3F00 ..=0x3FFF ) . contains ( & addr) {
106+ self . memory . read ( addr)
107+ } else {
108+ let value = self . data_buffer ;
109+ self . data_buffer = self . memory . read ( addr) ;
110+ value
111+ } ;
112+
113+ self . addr . increment_addr ( self . addr_increment_amount ( ) ) ;
114+ result
115+ }
116+
117+ pub fn write_ppu_data ( & mut self , value : u8 ) {
118+ self . memory . write ( self . addr . get_addr ( ) , value) ;
119+
120+ self . addr . increment_addr ( self . addr_increment_amount ( ) ) ;
121+ }
122+
123+ pub fn get_ctrl_bit ( & self , bit : u8 ) -> bool {
124+ self . ctrl >> bit & 1 == 1
125+ }
126+
127+ pub fn set_ctrl_bit ( & mut self , bit : u8 , value : bool ) {
128+ if value {
129+ self . ctrl |= 1 << bit;
130+ } else {
131+ self . ctrl &= !( 1 << bit) ;
132+ }
133+ }
134+
135+ fn addr_increment_amount ( & self ) -> u8 {
136+ if !self . get_ctrl_bit ( PPU_VRAM_ADD_INCREMENT_BIT ) {
137+ 1 // across
138+ } else {
139+ 32 // down
140+ }
141+ }
142+ }
143+
144+ #[ cfg( test) ]
145+ mod test {
146+ use crate :: memory:: DummyMemory ;
147+ use crate :: ppu:: { Ppu , PPU_VRAM_ADD_INCREMENT_BIT } ;
148+ use std:: cell:: RefCell ;
149+ use std:: rc:: Rc ;
150+
151+ #[ test]
152+ pub fn test_ppu_addr ( ) {
153+ let memory = Rc :: new ( RefCell :: new ( DummyMemory :: new ( ) ) ) ;
154+ let mut ppu = Ppu :: new_with_memory ( memory. clone ( ) ) ;
155+
156+ ppu. set_ctrl_bit ( PPU_VRAM_ADD_INCREMENT_BIT , false ) ;
157+
158+ ppu. write_ppu_addr ( 0x34 ) ;
159+ ppu. write_ppu_addr ( 0x56 ) ;
160+ assert_eq ! ( ppu. addr. get_addr( ) , 0x3456 ) ;
161+
162+ ppu. read_ppu_data ( ) ;
163+ assert_eq ! ( memory. borrow( ) . last_read_addr( ) , 0x3456 ) ;
164+ assert_eq ! ( ppu. addr. get_addr( ) , 0x3457 ) ;
165+
166+ assert_eq ! ( ppu. read_ppu_data( ) , 0x56 ) ; // read on dummy memory returns low byte of address
167+ assert_eq ! ( memory. borrow( ) . last_read_addr( ) , 0x3457 ) ;
168+ assert_eq ! ( ppu. addr. get_addr( ) , 0x3458 ) ;
169+
170+ ppu. write_ppu_data ( 0xCA ) ;
171+ assert_eq ! ( memory. borrow( ) . last_read_addr( ) , 0x3457 ) ;
172+ assert_eq ! ( memory. borrow( ) . last_write_addr( ) , 0x3458 ) ;
173+ assert_eq ! ( memory. borrow( ) . last_write_value( ) , 0xCA ) ;
174+ assert_eq ! ( ppu. addr. get_addr( ) , 0x3459 ) ;
175+
176+ ppu. set_ctrl_bit ( PPU_VRAM_ADD_INCREMENT_BIT , true ) ;
177+ ppu. read_ppu_data ( ) ;
178+ assert_eq ! ( ppu. addr. get_addr( ) , 0x3479 ) ; // now it increments by 0x20 because of the changed ctrl bit
179+ ppu. set_ctrl_bit ( PPU_VRAM_ADD_INCREMENT_BIT , false ) ;
180+
181+ ppu. addr . set ( 0x3f ) ;
182+ ppu. addr . set ( 0xBD ) ;
183+ assert_eq ! ( ppu. addr. get_addr( ) , 0x3fBD ) ;
184+ assert_eq ! ( ppu. read_ppu_data( ) , 0xBD ) ; // read in palette range returns value immediately
185+
186+ ppu. addr . set ( 0x3f ) ;
187+ ppu. addr . set ( 0xff ) ;
188+ ppu. read_ppu_data ( ) ;
189+ assert_eq ! ( ppu. addr. get_addr( ) , 0x0000 ) ; // wraparound after 0x3fff
190+ }
89191}
0 commit comments