@@ -7,6 +7,7 @@ const EXT_RAM_BANK_SIZE: usize = 0x2000;
77const MBC2_RAM_SIZE : usize = 512 ;
88const MBC2_RAM_END : u16 = 0xA1FF ;
99const OPEN_BUS : u8 = 0xFF ;
10+ const CYCLES_PER_SECOND : u32 = 4_194_304 ;
1011
1112#[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
1213pub enum MbcError {
@@ -72,6 +73,12 @@ impl Mbc {
7273 MbcKind :: Mbc5 ( mbc5) => mbc5. write8 ( cartridge, addr, value) ,
7374 }
7475 }
76+
77+ pub fn tick ( & mut self , cycles : u32 ) {
78+ if let MbcKind :: Mbc3 ( mbc3) = & mut self . kind {
79+ mbc3. tick ( cycles) ;
80+ }
81+ }
7582}
7683
7784#[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
@@ -268,6 +275,54 @@ impl Rtc {
268275 RtcRegister :: DayHigh => self . day_high = value,
269276 }
270277 }
278+
279+ fn tick_seconds ( & mut self , seconds : u32 ) {
280+ if self . day_high & 0x40 != 0 {
281+ return ;
282+ }
283+
284+ let mut remaining = seconds;
285+ while remaining > 0 {
286+ remaining -= 1 ;
287+ self . increment_one_second ( ) ;
288+ }
289+ }
290+
291+ fn increment_one_second ( & mut self ) {
292+ self . seconds = self . seconds . wrapping_add ( 1 ) ;
293+ if self . seconds < 60 {
294+ return ;
295+ }
296+ self . seconds = 0 ;
297+ self . minutes = self . minutes . wrapping_add ( 1 ) ;
298+ if self . minutes < 60 {
299+ return ;
300+ }
301+ self . minutes = 0 ;
302+ self . hours = self . hours . wrapping_add ( 1 ) ;
303+ if self . hours < 24 {
304+ return ;
305+ }
306+ self . hours = 0 ;
307+
308+ let day = self . day_counter ( ) ;
309+ if day == 0x1FF {
310+ self . set_day_counter ( 0 ) ;
311+ self . day_high |= 0x80 ;
312+ } else {
313+ self . set_day_counter ( day + 1 ) ;
314+ }
315+ }
316+
317+ fn day_counter ( & self ) -> u16 {
318+ let high = ( self . day_high & 0x01 ) as u16 ;
319+ u16:: from ( self . day_low ) | ( high << 8 )
320+ }
321+
322+ fn set_day_counter ( & mut self , day : u16 ) {
323+ self . day_low = day as u8 ;
324+ self . day_high = ( self . day_high & 0xFE ) | ( ( day >> 8 ) as u8 & 0x01 ) ;
325+ }
271326}
272327
273328#[ derive( Debug , Clone ) ]
@@ -277,6 +332,7 @@ struct Mbc3 {
277332 rtc_reg : Option < RtcRegister > ,
278333 ram_enabled : bool ,
279334 latch_pending : bool ,
335+ rtc_counter : u32 ,
280336 rtc : Rtc ,
281337 rtc_latched : Rtc ,
282338 latched : bool ,
@@ -297,6 +353,7 @@ impl Mbc3 {
297353 rtc_reg : None ,
298354 ram_enabled : false ,
299355 latch_pending : false ,
356+ rtc_counter : 0 ,
300357 rtc,
301358 rtc_latched : rtc,
302359 latched : false ,
@@ -373,6 +430,14 @@ impl Mbc3 {
373430 _ => { }
374431 }
375432 }
433+
434+ fn tick ( & mut self , cycles : u32 ) {
435+ self . rtc_counter = self . rtc_counter . wrapping_add ( cycles) ;
436+ while self . rtc_counter >= CYCLES_PER_SECOND {
437+ self . rtc_counter -= CYCLES_PER_SECOND ;
438+ self . rtc . tick_seconds ( 1 ) ;
439+ }
440+ }
376441}
377442
378443#[ derive( Debug , Clone ) ]
@@ -529,7 +594,7 @@ fn normalize_switchable_bank(bank: usize, bank_count: usize) -> usize {
529594
530595#[ cfg( test) ]
531596mod tests {
532- use super :: { Mbc , bank_count} ;
597+ use super :: { CYCLES_PER_SECOND , Mbc , bank_count} ;
533598 use crate :: domain:: Cartridge ;
534599 use crate :: domain:: cartridge:: ROM_BANK_SIZE ;
535600
@@ -656,6 +721,22 @@ mod tests {
656721 assert_eq ! ( mbc. read8( & cartridge, 0xA000 ) , 0x25 ) ;
657722 }
658723
724+ #[ test]
725+ fn mbc3_rtc_ticks_with_cycles ( ) {
726+ let mut bytes = vec ! [ 0 ; ROM_BANK_SIZE * 2 ] ;
727+ bytes[ 0x0147 ] = 0x0F ;
728+ bytes[ 0x0149 ] = 0x02 ;
729+
730+ let mut cartridge = Cartridge :: from_bytes ( bytes) . expect ( "cartridge" ) ;
731+ let mut mbc = Mbc :: new ( & cartridge) . expect ( "mbc" ) ;
732+
733+ mbc. write8 ( & mut cartridge, 0x0000 , 0x0A ) ;
734+ mbc. write8 ( & mut cartridge, 0x4000 , 0x08 ) ;
735+ mbc. tick ( CYCLES_PER_SECOND ) ;
736+
737+ assert_eq ! ( mbc. read8( & cartridge, 0xA000 ) , 1 ) ;
738+ }
739+
659740 #[ test]
660741 fn mbc5_uses_9bit_rom_bank ( ) {
661742 let mut bytes = vec ! [ 0 ; ROM_BANK_SIZE * 260 ] ;
0 commit comments