2021-10-26 02:31:28 +00:00
2022-10-09 16:40:20 +00:00
use moa_core ::{ debug , warn , error } ;
2022-09-25 06:14:03 +00:00
use moa_core ::{ System , Error , EdgeSignal , Clock , ClockElapsed , Address , Addressable , Steppable , Inspectable , Transmutable , TransmutableBox , read_beu16 , dump_slice } ;
use moa_core ::host ::{ Host , BlitableSurface , HostData } ;
2022-10-01 19:12:25 +00:00
use moa_core ::host ::gfx ::{ Frame , FrameQueue } ;
2021-10-26 02:31:28 +00:00
const REG_MODE_SET_1 : usize = 0x00 ;
const REG_MODE_SET_2 : usize = 0x01 ;
const REG_SCROLL_A_ADDR : usize = 0x02 ;
const REG_WINDOW_ADDR : usize = 0x03 ;
const REG_SCROLL_B_ADDR : usize = 0x04 ;
const REG_SPRITES_ADDR : usize = 0x05 ;
2021-12-04 21:58:50 +00:00
// Register 0x06 Unused
2021-10-26 02:31:28 +00:00
const REG_BACKGROUND : usize = 0x07 ;
2021-12-04 21:58:50 +00:00
// Register 0x08 Unused
// Register 0x09 Unused
2021-10-26 02:31:28 +00:00
const REG_H_INTERRUPT : usize = 0x0A ;
const REG_MODE_SET_3 : usize = 0x0B ;
const REG_MODE_SET_4 : usize = 0x0C ;
const REG_HSCROLL_ADDR : usize = 0x0D ;
2021-12-04 21:58:50 +00:00
// Register 0x0E Unused
2021-10-26 02:31:28 +00:00
const REG_AUTO_INCREMENT : usize = 0x0F ;
const REG_SCROLL_SIZE : usize = 0x10 ;
const REG_WINDOW_H_POS : usize = 0x11 ;
const REG_WINDOW_V_POS : usize = 0x12 ;
const REG_DMA_COUNTER_LOW : usize = 0x13 ;
const REG_DMA_COUNTER_HIGH : usize = 0x14 ;
const REG_DMA_ADDR_LOW : usize = 0x15 ;
const REG_DMA_ADDR_MID : usize = 0x16 ;
const REG_DMA_ADDR_HIGH : usize = 0x17 ;
2021-12-13 20:00:24 +00:00
//const STATUS_PAL_MODE: u16 = 0x0001;
2021-10-26 02:31:28 +00:00
const STATUS_DMA_BUSY : u16 = 0x0002 ;
const STATUS_IN_HBLANK : u16 = 0x0004 ;
const STATUS_IN_VBLANK : u16 = 0x0008 ;
2021-12-13 20:00:24 +00:00
//const STATUS_ODD_FRAME: u16 = 0x0010;
//const STATUS_SPRITE_COLLISION: u16 = 0x0020;
//const STATUS_SPRITE_OVERFLOW: u16 = 0x0040;
//const STATUS_V_INTERRUPT: u16 = 0x0080;
//const STATUS_FIFO_FULL: u16 = 0x0100;
2021-10-26 02:31:28 +00:00
const STATUS_FIFO_EMPTY : u16 = 0x0200 ;
2022-01-16 18:56:32 +00:00
const MODE1_BF_DISABLE_DISPLAY : u8 = 0x01 ;
2021-12-13 20:00:24 +00:00
//const MODE1_BF_ENABLE_HV_COUNTER: u8 = 0x02;
2021-10-26 02:31:28 +00:00
const MODE1_BF_HSYNC_INTERRUPT : u8 = 0x10 ;
const MODE2_BF_V_CELL_MODE : u8 = 0x08 ;
2021-11-29 19:11:32 +00:00
const MODE2_BF_DMA_ENABLED : u8 = 0x10 ;
2021-10-26 02:31:28 +00:00
const MODE2_BF_VSYNC_INTERRUPT : u8 = 0x20 ;
2021-11-01 06:01:56 +00:00
const MODE3_BF_EXTERNAL_INTERRUPT : u8 = 0x08 ;
2021-12-05 05:04:03 +00:00
const MODE3_BF_V_SCROLL_MODE : u8 = 0x04 ;
const MODE3_BF_H_SCROLL_MODE : u8 = 0x03 ;
2021-11-01 06:01:56 +00:00
2021-10-26 02:31:28 +00:00
const MODE4_BF_H_CELL_MODE : u8 = 0x01 ;
2021-12-29 18:54:43 +00:00
const MODE4_BF_SHADOW_HIGHLIGHT : u8 = 0x08 ;
2021-10-26 02:31:28 +00:00
2023-03-06 04:19:49 +00:00
const DEV_NAME : & str = " ym7101 " ;
2021-10-26 02:31:28 +00:00
2023-03-06 04:19:49 +00:00
#[ derive(Copy, Clone, Debug, PartialEq, Eq) ]
2021-10-26 02:31:28 +00:00
pub enum DmaType {
None ,
Memory ,
Fill ,
Copy ,
}
2023-03-06 04:19:49 +00:00
#[ derive(Copy, Clone, Debug, PartialEq, Eq) ]
2021-12-30 19:27:50 +00:00
pub enum Memory {
2021-10-30 23:16:09 +00:00
Vram ,
Cram ,
Vsram ,
2021-10-26 02:31:28 +00:00
}
2021-12-30 19:27:50 +00:00
pub struct Ym7101Memory {
pub vram : [ u8 ; 0x10000 ] ,
pub cram : [ u8 ; 128 ] ,
pub vsram : [ u8 ; 80 ] ,
pub transfer_type : u8 ,
pub transfer_bits : u8 ,
pub transfer_count : u32 ,
pub transfer_remain : u32 ,
pub transfer_src_addr : u32 ,
pub transfer_dest_addr : u32 ,
pub transfer_auto_inc : u32 ,
pub transfer_fill_word : u16 ,
pub transfer_run : DmaType ,
pub transfer_target : Memory ,
pub transfer_dma_busy : bool ,
pub ctrl_port_buffer : Option < u16 > ,
}
2023-03-06 04:19:49 +00:00
impl Default for Ym7101Memory {
fn default ( ) -> Self {
2021-12-30 19:27:50 +00:00
Self {
vram : [ 0 ; 0x10000 ] ,
cram : [ 0 ; 128 ] ,
vsram : [ 0 ; 80 ] ,
transfer_type : 0 ,
transfer_bits : 0 ,
transfer_count : 0 ,
transfer_remain : 0 ,
transfer_src_addr : 0 ,
transfer_dest_addr : 0 ,
transfer_auto_inc : 0 ,
transfer_fill_word : 0 ,
transfer_run : DmaType ::None ,
transfer_target : Memory ::Vram ,
transfer_dma_busy : false ,
ctrl_port_buffer : None ,
}
}
2023-03-06 04:19:49 +00:00
}
2021-12-30 19:27:50 +00:00
2023-03-06 04:19:49 +00:00
impl Ym7101Memory {
2021-12-30 19:27:50 +00:00
#[ inline(always) ]
fn read_beu16 ( & self , target : Memory , addr : usize ) -> u16 {
let addr = match target {
Memory ::Vram = > & self . vram [ addr .. ] ,
Memory ::Cram = > & self . cram [ addr .. ] ,
Memory ::Vsram = > & self . vsram [ addr .. ] ,
} ;
read_beu16 ( addr )
}
pub fn set_dma_mode ( & mut self , mode : DmaType ) {
match mode {
DmaType ::None = > {
//self.status &= !STATUS_DMA_BUSY;
self . transfer_dma_busy = false ;
self . transfer_run = DmaType ::None ;
} ,
_ = > {
//self.status |= STATUS_DMA_BUSY;
self . transfer_dma_busy = true ;
self . transfer_run = mode ;
} ,
}
}
2022-01-07 07:40:22 +00:00
pub fn setup_transfer ( & mut self , first : u16 , second : u16 ) {
2021-12-30 19:27:50 +00:00
self . ctrl_port_buffer = None ;
2023-03-06 04:19:49 +00:00
self . transfer_type = ( ( ( first & 0xC000 ) > > 14 ) | ( ( second & 0x00F0 ) > > 2 ) ) as u8 ;
2022-01-07 07:40:22 +00:00
self . transfer_dest_addr = ( ( first & 0x3FFF ) | ( ( second & 0x0003 ) < < 14 ) ) as u32 ;
2021-12-30 19:27:50 +00:00
self . transfer_target = match self . transfer_type & 0x0E {
0 = > Memory ::Vram ,
4 = > Memory ::Vsram ,
_ = > Memory ::Cram ,
} ;
2022-01-16 18:39:57 +00:00
debug! ( " {}: transfer requested of type {:x} ({:?}) to address {:x} " , DEV_NAME , self . transfer_type , self . transfer_target , self . transfer_dest_addr ) ;
2021-12-30 19:27:50 +00:00
if ( self . transfer_type & 0x20 ) ! = 0 {
if ( self . transfer_type & 0x10 ) ! = 0 {
self . set_dma_mode ( DmaType ::Copy ) ;
} else if ( self . transfer_bits & 0x80 ) = = 0 {
self . set_dma_mode ( DmaType ::Memory ) ;
}
}
}
2022-01-09 03:48:04 +00:00
pub fn get_transfer_target_mut ( & mut self ) -> & mut [ u8 ] {
2021-12-30 19:27:50 +00:00
match self . transfer_target {
2022-01-09 03:48:04 +00:00
Memory ::Vram = > & mut self . vram ,
Memory ::Cram = > & mut self . cram ,
Memory ::Vsram = > & mut self . vsram ,
2021-12-30 19:27:50 +00:00
}
}
pub fn read_data_port ( & mut self , addr : Address , data : & mut [ u8 ] ) -> Result < ( ) , Error > {
{
let addr = self . transfer_dest_addr ;
2022-01-09 03:48:04 +00:00
let target = self . get_transfer_target_mut ( ) ;
2021-12-30 19:27:50 +00:00
for i in 0 .. data . len ( ) {
2022-01-09 03:48:04 +00:00
data [ i ] = target [ ( addr as usize + i ) % target . len ( ) ] ;
2021-12-30 19:27:50 +00:00
}
}
self . transfer_dest_addr + = self . transfer_auto_inc ;
debug! ( " {}: data port read {} bytes from {:?}:{:x} returning {:x},{:x} " , DEV_NAME , data . len ( ) , self . transfer_target , addr , data [ 0 ] , data [ 1 ] ) ;
Ok ( ( ) )
}
2022-09-10 05:31:55 +00:00
pub fn write_data_port ( & mut self , data : & [ u8 ] ) -> Result < ( ) , Error > {
2021-12-30 19:27:50 +00:00
if ( self . transfer_type & 0x30 ) = = 0x20 {
self . ctrl_port_buffer = None ;
self . transfer_fill_word = if data . len ( ) > = 2 { read_beu16 ( data ) } else { data [ 0 ] as u16 } ;
self . set_dma_mode ( DmaType ::Fill ) ;
} else {
debug! ( " {}: data port write {} bytes to {:?}:{:x} with {:?} " , DEV_NAME , data . len ( ) , self . transfer_target , self . transfer_dest_addr , data ) ;
{
let addr = self . transfer_dest_addr as usize ;
2022-01-09 03:48:04 +00:00
let target = self . get_transfer_target_mut ( ) ;
2021-12-30 19:27:50 +00:00
for i in 0 .. data . len ( ) {
2022-01-09 03:48:04 +00:00
target [ ( addr + i ) % target . len ( ) ] = data [ i ] ;
2021-12-30 19:27:50 +00:00
}
}
self . transfer_dest_addr + = self . transfer_auto_inc ;
}
Ok ( ( ) )
}
2022-09-10 05:31:55 +00:00
pub fn write_control_port ( & mut self , data : & [ u8 ] ) -> Result < ( ) , Error > {
2021-12-30 19:27:50 +00:00
let value = read_beu16 ( data ) ;
match ( data . len ( ) , self . ctrl_port_buffer ) {
( 2 , None ) = > { self . ctrl_port_buffer = Some ( value ) } ,
( 2 , Some ( upper ) ) = > self . setup_transfer ( upper , read_beu16 ( data ) ) ,
( 4 , None ) = > self . setup_transfer ( value , read_beu16 ( & data [ 2 .. ] ) ) ,
_ = > { error! ( " {}: !!! error when writing to control port with {} bytes of {:?} " , DEV_NAME , data . len ( ) , data ) ; } ,
}
Ok ( ( ) )
}
pub fn step_dma ( & mut self , system : & System ) -> Result < ( ) , Error > {
if self . transfer_run ! = DmaType ::None {
// TODO we will just do the full dma transfer here, but it really should be stepped
match self . transfer_run {
DmaType ::Memory = > {
2022-01-16 18:39:57 +00:00
debug! ( " {}: starting dma transfer {:x} from Mem:{:x} to {:?}:{:x} ({} bytes) " , DEV_NAME , self . transfer_type , self . transfer_src_addr , self . transfer_target , self . transfer_dest_addr , self . transfer_remain ) ;
2021-12-30 19:27:50 +00:00
let mut bus = system . get_bus ( ) ;
while self . transfer_remain > 0 {
let mut data = [ 0 ; 2 ] ;
bus . read ( self . transfer_src_addr as Address , & mut data ) ? ;
2022-01-09 03:48:04 +00:00
let addr = self . transfer_dest_addr as usize ;
let target = self . get_transfer_target_mut ( ) ;
target [ addr % target . len ( ) ] = data [ 0 ] ;
target [ ( addr + 1 ) % target . len ( ) ] = data [ 1 ] ;
2021-12-30 19:27:50 +00:00
self . transfer_dest_addr + = self . transfer_auto_inc ;
self . transfer_src_addr + = 2 ;
self . transfer_remain - = 1 ;
}
} ,
DmaType ::Copy = > {
2022-01-16 18:39:57 +00:00
debug! ( " {}: starting dma copy from VRAM:{:x} to VRAM:{:x} ({} bytes) " , DEV_NAME , self . transfer_src_addr , self . transfer_dest_addr , self . transfer_remain ) ;
2021-12-30 19:27:50 +00:00
while self . transfer_remain > 0 {
self . vram [ self . transfer_dest_addr as usize ] = self . vram [ self . transfer_src_addr as usize ] ;
self . transfer_dest_addr + = self . transfer_auto_inc ;
self . transfer_src_addr + = 1 ;
self . transfer_remain - = 1 ;
}
} ,
DmaType ::Fill = > {
2022-01-16 18:39:57 +00:00
debug! ( " {}: starting dma fill to VRAM:{:x} ({} bytes) with {:x} " , DEV_NAME , self . transfer_dest_addr , self . transfer_remain , self . transfer_fill_word ) ;
2021-12-30 19:27:50 +00:00
while self . transfer_remain > 0 {
self . vram [ self . transfer_dest_addr as usize ] = self . transfer_fill_word as u8 ;
self . transfer_dest_addr + = self . transfer_auto_inc ;
self . transfer_remain - = 1 ;
}
} ,
2022-10-09 16:40:20 +00:00
_ = > { warn! ( " {}: !!! error unexpected transfer mode {:x} " , DEV_NAME , self . transfer_type ) ; } ,
2021-12-30 19:27:50 +00:00
}
self . set_dma_mode ( DmaType ::None ) ;
}
Ok ( ( ) )
}
}
2023-03-06 04:19:49 +00:00
#[ derive(Copy, Clone, Debug, PartialEq, Eq) ]
2021-12-29 18:54:43 +00:00
pub enum ColourMode {
Normal ,
Shadow ,
Highlight ,
}
2023-03-06 04:19:49 +00:00
#[ derive(Copy, Clone, Debug, PartialEq, Eq) ]
2021-12-31 06:46:57 +00:00
pub enum Scroll {
ScrollA ,
ScrollB ,
}
2021-10-26 02:31:28 +00:00
pub struct Ym7101State {
pub status : u16 ,
2021-12-30 19:27:50 +00:00
pub memory : Ym7101Memory ,
2021-12-04 21:55:58 +00:00
pub mode_1 : u8 ,
pub mode_2 : u8 ,
pub mode_3 : u8 ,
pub mode_4 : u8 ,
2021-12-06 01:19:27 +00:00
pub h_int_lines : u8 ,
pub screen_size : ( usize , usize ) ,
pub scroll_size : ( usize , usize ) ,
2021-12-31 19:40:13 +00:00
pub window_pos : ( ( usize , usize ) , ( usize , usize ) ) ,
pub window_values : ( u8 , u8 ) ,
2021-12-04 21:55:58 +00:00
pub background : u8 ,
2021-12-05 05:04:03 +00:00
pub scroll_a_addr : usize ,
pub scroll_b_addr : usize ,
pub window_addr : usize ,
pub sprites_addr : usize ,
pub hscroll_addr : usize ,
2021-12-04 21:55:58 +00:00
2021-12-31 22:00:55 +00:00
pub sprites : Vec < Sprite > ,
pub sprites_by_line : Vec < Vec < usize > > ,
2021-10-26 02:31:28 +00:00
pub last_clock : Clock ,
2022-01-02 23:44:41 +00:00
pub p_clock : u32 ,
2021-10-26 02:31:28 +00:00
pub h_clock : u32 ,
pub v_clock : u32 ,
pub h_scanlines : u8 ,
2022-01-02 23:44:41 +00:00
pub current_x : i32 ,
pub current_y : i32 ,
2021-10-26 02:31:28 +00:00
}
2023-03-06 04:19:49 +00:00
impl Default for Ym7101State {
fn default ( ) -> Self {
2021-10-26 02:31:28 +00:00
Self {
2021-10-30 23:16:09 +00:00
status : 0x3400 | STATUS_FIFO_EMPTY ,
2023-03-06 04:19:49 +00:00
memory : Ym7101Memory ::default ( ) ,
2021-12-04 21:55:58 +00:00
mode_1 : 0 ,
mode_2 : 0 ,
mode_3 : 0 ,
mode_4 : 0 ,
h_int_lines : 0 ,
2021-12-06 01:19:27 +00:00
screen_size : ( 0 , 0 ) ,
2021-12-04 21:55:58 +00:00
scroll_size : ( 0 , 0 ) ,
2021-12-31 19:40:13 +00:00
window_pos : ( ( 0 , 0 ) , ( 0 , 0 ) ) ,
window_values : ( 0 , 0 ) ,
2021-12-04 21:55:58 +00:00
background : 0 ,
scroll_a_addr : 0 ,
scroll_b_addr : 0 ,
window_addr : 0 ,
sprites_addr : 0 ,
hscroll_addr : 0 ,
2021-12-31 22:00:55 +00:00
sprites : vec ! [ ] ,
sprites_by_line : vec ! [ ] ,
2021-10-26 02:31:28 +00:00
last_clock : 0 ,
2022-01-02 23:44:41 +00:00
p_clock : 0 ,
2021-10-26 02:31:28 +00:00
h_clock : 0 ,
v_clock : 0 ,
h_scanlines : 0 ,
2022-01-02 23:44:41 +00:00
current_x : 0 ,
current_y : 0 ,
2021-10-26 02:31:28 +00:00
}
}
2023-03-06 04:19:49 +00:00
}
2021-10-26 02:31:28 +00:00
2023-03-06 04:19:49 +00:00
impl Ym7101State {
2021-10-26 02:31:28 +00:00
#[ inline(always) ]
fn hsync_int_enabled ( & self ) -> bool {
2021-12-04 21:55:58 +00:00
( self . mode_1 & MODE1_BF_HSYNC_INTERRUPT ) ! = 0
2021-10-26 02:31:28 +00:00
}
2021-10-30 23:16:09 +00:00
#[ inline(always) ]
2021-10-26 02:31:28 +00:00
fn vsync_int_enabled ( & self ) -> bool {
2021-12-04 21:55:58 +00:00
( self . mode_2 & MODE2_BF_VSYNC_INTERRUPT ) ! = 0
2021-10-26 02:31:28 +00:00
}
2021-11-01 06:01:56 +00:00
#[ inline(always) ]
fn external_int_enabled ( & self ) -> bool {
2021-12-04 21:55:58 +00:00
( self . mode_3 & MODE3_BF_EXTERNAL_INTERRUPT ) ! = 0
2021-11-29 19:11:32 +00:00
}
2021-12-31 19:40:13 +00:00
pub fn update_screen_size ( & mut self ) {
let h_cells = if ( self . mode_4 & MODE4_BF_H_CELL_MODE ) = = 0 { 32 } else { 40 } ;
let v_cells = if ( self . mode_2 & MODE2_BF_V_CELL_MODE ) = = 0 { 28 } else { 30 } ;
self . screen_size = ( h_cells , v_cells ) ;
}
pub fn update_window_position ( & mut self ) {
let win_h = ( ( self . window_values . 0 & 0x1F ) < < 1 ) as usize ;
let win_v = ( self . window_values . 1 & 0x1F ) as usize ;
let right = ( self . window_values . 0 & 0x80 ) ! = 0 ;
let down = ( self . window_values . 1 & 0x80 ) ! = 0 ;
self . window_pos = match ( right , down ) {
( false , false ) = > ( ( 0 , 0 ) , ( win_h , win_v ) ) ,
( true , false ) = > ( ( win_h , 0 ) , ( self . screen_size . 0 , win_v ) ) ,
( false , true ) = > ( ( 0 , win_v ) , ( win_h , self . screen_size . 1 ) ) ,
( true , true ) = > ( ( win_h , win_v ) , ( self . screen_size . 0 , self . screen_size . 1 ) ) ,
2021-10-28 04:01:18 +00:00
}
2021-12-31 19:40:13 +00:00
}
2022-01-09 03:48:04 +00:00
fn is_inside_window ( & mut self , x : usize , y : usize ) -> bool {
2021-12-31 19:40:13 +00:00
x > = self . window_pos . 0.0 & & x < = self . window_pos . 1.0 & & y > = self . window_pos . 0.1 & & y < = self . window_pos . 1.1
}
2022-01-09 03:48:04 +00:00
fn get_palette_colour ( & self , palette : u8 , colour : u8 , mode : ColourMode ) -> u32 {
2021-12-29 18:54:43 +00:00
let shift_enabled = ( self . mode_4 & MODE4_BF_SHADOW_HIGHLIGHT ) ! = 0 ;
2021-12-30 19:27:50 +00:00
let rgb = self . memory . read_beu16 ( Memory ::Cram , ( ( ( palette * 16 ) + colour ) * 2 ) as usize ) ;
2021-12-29 18:54:43 +00:00
if ! shift_enabled | | mode = = ColourMode ::Normal {
( ( ( rgb & 0xF00 ) as u32 ) > > 4 ) | ( ( ( rgb & 0x0F0 ) as u32 ) < < 8 ) | ( ( ( rgb & 0x00F ) as u32 ) < < 20 )
} else {
let offset = if mode = = ColourMode ::Highlight { 0x808080 } else { 0x00 } ;
( ( ( rgb & 0xF00 ) as u32 ) > > 5 ) | ( ( ( rgb & 0x0F0 ) as u32 ) < < 7 ) | ( ( ( rgb & 0x00F ) as u32 ) < < 19 ) | offset
}
2021-10-26 02:31:28 +00:00
}
2022-01-09 03:48:04 +00:00
fn get_hscroll ( & self , hcell : usize , line : usize ) -> ( usize , usize ) {
2021-12-31 06:46:57 +00:00
let scroll_addr = match self . mode_3 & MODE3_BF_H_SCROLL_MODE {
2021-12-05 22:26:21 +00:00
0 = > self . hscroll_addr ,
2021-12-27 05:29:01 +00:00
2 = > self . hscroll_addr + ( hcell < < 5 ) ,
2021-12-31 06:46:57 +00:00
3 = > self . hscroll_addr + ( hcell < < 5 ) + ( line * 2 * 2 ) ,
2021-12-05 05:04:03 +00:00
_ = > panic! ( " Unsupported horizontal scroll mode " ) ,
} ;
2021-12-05 22:26:21 +00:00
2021-12-31 06:46:57 +00:00
let scroll_a = self . memory . read_beu16 ( Memory ::Vram , scroll_addr ) as usize & 0x3FF ;
let scroll_b = self . memory . read_beu16 ( Memory ::Vram , scroll_addr + 2 ) as usize & 0x3FF ;
2021-12-05 22:26:21 +00:00
( scroll_a , scroll_b )
2021-12-05 05:04:03 +00:00
}
2022-01-09 03:48:04 +00:00
fn get_vscroll ( & self , vcell : usize ) -> ( usize , usize ) {
let scroll_addr = if ( self . mode_3 & MODE3_BF_V_SCROLL_MODE ) = = 0 {
2021-12-05 22:26:21 +00:00
0
2021-12-05 05:04:03 +00:00
} else {
2021-12-05 22:26:21 +00:00
vcell > > 1
2021-12-05 05:04:03 +00:00
} ;
2021-12-05 22:26:21 +00:00
2022-01-09 03:48:04 +00:00
let scroll_a = self . memory . read_beu16 ( Memory ::Vsram , scroll_addr ) as usize & 0x3FF ;
let scroll_b = self . memory . read_beu16 ( Memory ::Vsram , scroll_addr + 2 ) as usize & 0x3FF ;
2021-12-05 22:26:21 +00:00
( scroll_a , scroll_b )
2021-12-05 05:04:03 +00:00
}
2021-12-06 01:19:27 +00:00
#[ inline(always) ]
2022-01-09 03:48:04 +00:00
fn get_pattern_addr ( & self , cell_table : usize , cell_x : usize , cell_y : usize ) -> usize {
2023-03-06 04:34:30 +00:00
cell_table + ( ( cell_x + ( cell_y * self . scroll_size . 0 ) ) < < 1 )
2021-12-06 01:19:27 +00:00
}
2022-01-09 03:48:04 +00:00
fn build_sprites_lists ( & mut self ) {
2021-12-31 06:46:57 +00:00
let sprite_table = self . sprites_addr ;
let max_lines = self . screen_size . 1 * 8 ;
2021-12-31 22:00:55 +00:00
self . sprites . clear ( ) ;
self . sprites_by_line = vec! [ vec! [ ] ; max_lines ] ;
2021-12-31 06:46:57 +00:00
let mut link = 0 ;
loop {
let sprite = Sprite ::new ( & self . memory . vram [ sprite_table + ( link * 8 ) .. ] ) ;
let start_y = sprite . pos . 1 ;
for y in 0 .. ( sprite . size . 1 as i16 * 8 ) {
let pos_y = start_y + y ;
if pos_y > = 0 & & pos_y < max_lines as i16 {
2021-12-31 22:00:55 +00:00
self . sprites_by_line [ pos_y as usize ] . push ( self . sprites . len ( ) ) ;
2021-12-31 06:46:57 +00:00
}
}
link = sprite . link as usize ;
2021-12-31 22:00:55 +00:00
self . sprites . push ( sprite ) ;
2021-12-31 06:46:57 +00:00
if link = = 0 {
break ;
}
}
}
2022-01-09 03:48:04 +00:00
fn get_pattern_pixel ( & self , pattern_word : u16 , x : usize , y : usize ) -> ( u8 , u8 ) {
2021-12-31 06:46:57 +00:00
let pattern_addr = ( pattern_word & 0x07FF ) < < 5 ;
let palette = ( ( pattern_word & 0x6000 ) > > 13 ) as u8 ;
let h_rev = ( pattern_word & 0x0800 ) ! = 0 ;
let v_rev = ( pattern_word & 0x1000 ) ! = 0 ;
2022-01-09 03:48:04 +00:00
let line = if ! v_rev { y } else { 7 - y } ;
let column = if ! h_rev { x / 2 } else { 3 - ( x / 2 ) } ;
let offset = pattern_addr as usize + line * 4 + column ;
2021-12-31 06:46:57 +00:00
let second = x % 2 = = 1 ;
2023-03-06 04:19:49 +00:00
if ( ! h_rev & & ! second ) | | ( h_rev & & second ) {
2021-12-31 19:40:13 +00:00
( palette , self . memory . vram [ offset ] > > 4 )
2021-12-31 06:46:57 +00:00
} else {
2021-12-31 19:40:13 +00:00
( palette , self . memory . vram [ offset ] & 0x0f )
2023-03-06 04:19:49 +00:00
}
2021-12-31 06:46:57 +00:00
}
pub fn draw_frame ( & mut self , frame : & mut Frame ) {
2021-12-31 22:00:55 +00:00
self . build_sprites_lists ( ) ;
2021-12-31 06:46:57 +00:00
for y in 0 .. ( self . screen_size . 1 * 8 ) {
2021-12-31 22:00:55 +00:00
self . draw_frame_line ( frame , y ) ;
}
}
2021-12-31 06:46:57 +00:00
2021-12-31 22:00:55 +00:00
pub fn draw_frame_line ( & mut self , frame : & mut Frame , y : usize ) {
let bg_colour = ( ( self . background & 0x30 ) > > 4 , self . background & 0x0f ) ;
let ( hscrolling_a , hscrolling_b ) = self . get_hscroll ( y / 8 , y % 8 ) ;
for x in 0 .. ( self . screen_size . 0 * 8 ) {
let ( vscrolling_a , vscrolling_b ) = self . get_vscroll ( x / 8 ) ;
let pixel_b_x = ( x - hscrolling_b ) % ( self . scroll_size . 0 * 8 ) ;
let pixel_b_y = ( y + vscrolling_b ) % ( self . scroll_size . 1 * 8 ) ;
let pattern_b_addr = self . get_pattern_addr ( self . scroll_b_addr , pixel_b_x / 8 , pixel_b_y / 8 ) ;
let pattern_b_word = self . memory . read_beu16 ( Memory ::Vram , pattern_b_addr ) ;
let priority_b = ( pattern_b_word & 0x8000 ) ! = 0 ;
let pixel_b = self . get_pattern_pixel ( pattern_b_word , pixel_b_x % 8 , pixel_b_y % 8 ) ;
2022-01-09 03:48:04 +00:00
let pixel_a_x = ( x - hscrolling_a ) % ( self . scroll_size . 0 * 8 ) ;
let pixel_a_y = ( y + vscrolling_a ) % ( self . scroll_size . 1 * 8 ) ;
let pattern_a_addr = self . get_pattern_addr ( self . scroll_a_addr , pixel_a_x / 8 , pixel_a_y / 8 ) ;
let pattern_a_word = self . memory . read_beu16 ( Memory ::Vram , pattern_a_addr ) ;
let mut priority_a = ( pattern_a_word & 0x8000 ) ! = 0 ;
let mut pixel_a = self . get_pattern_pixel ( pattern_a_word , pixel_a_x % 8 , pixel_a_y % 8 ) ;
if self . window_addr ! = 0 & & self . is_inside_window ( x , y ) {
2021-12-31 22:00:55 +00:00
let pixel_win_x = x - self . window_pos . 0.0 * 8 ;
let pixel_win_y = y - self . window_pos . 0.1 * 8 ;
let pattern_win_addr = self . get_pattern_addr ( self . window_addr , pixel_win_x / 8 , pixel_win_y / 8 ) ;
let pattern_win_word = self . memory . read_beu16 ( Memory ::Vram , pattern_win_addr ) ;
2022-01-09 03:48:04 +00:00
// Scroll A is not displayed where ever the Window is displayed, so we replace Scroll A's data
priority_a = ( pattern_win_word & 0x8000 ) ! = 0 ;
pixel_a = self . get_pattern_pixel ( pattern_win_word , pixel_win_x % 8 , pixel_win_y % 8 ) ;
2021-12-31 22:00:55 +00:00
} ;
let mut pixel_sprite = ( 0 , 0 ) ;
let mut priority_sprite = false ;
for sprite_num in self . sprites_by_line [ y ] . iter ( ) {
let sprite = & self . sprites [ * sprite_num ] ;
let offset_x = x as i16 - sprite . pos . 0 ;
let offset_y = y as i16 - sprite . pos . 1 ;
if offset_x > = 0 & & offset_x < ( sprite . size . 0 as i16 * 8 ) {
let pattern = sprite . calculate_pattern ( offset_x as usize / 8 , offset_y as usize / 8 ) ;
priority_sprite = ( pattern & 0x8000 ) ! = 0 ;
pixel_sprite = self . get_pattern_pixel ( pattern , offset_x as usize % 8 , offset_y as usize % 8 ) ;
if pixel_sprite . 1 ! = 0 {
2021-12-31 06:46:57 +00:00
break ;
}
}
}
2021-12-31 22:00:55 +00:00
let pixels = match ( priority_sprite , priority_a , priority_b ) {
2022-01-09 03:48:04 +00:00
( false , false , true ) = > [ pixel_b , pixel_sprite , pixel_a , bg_colour ] ,
( true , false , true ) = > [ pixel_sprite , pixel_b , pixel_a , bg_colour ] ,
( false , true , false ) = > [ pixel_a , pixel_sprite , pixel_b , bg_colour ] ,
( false , true , true ) = > [ pixel_a , pixel_b , pixel_sprite , bg_colour ] ,
_ = > [ pixel_sprite , pixel_a , pixel_b , bg_colour ] ,
2021-12-31 22:00:55 +00:00
} ;
2023-03-05 21:32:45 +00:00
for ( i , pixel ) in pixels . iter ( ) . enumerate ( ) {
if pixel . 1 ! = 0 | | i = = pixels . len ( ) - 1 {
let mode = if * pixel = = ( 3 , 14 ) {
2021-12-31 22:00:55 +00:00
ColourMode ::Highlight
2023-03-05 21:32:45 +00:00
} else if ( ! priority_a & & ! priority_b ) | | * pixel = = ( 3 , 15 ) {
2021-12-31 22:00:55 +00:00
ColourMode ::Shadow
} else {
ColourMode ::Normal
} ;
2023-03-05 21:32:45 +00:00
frame . set_pixel ( x as u32 , y as u32 , self . get_palette_colour ( pixel . 0 , pixel . 1 , mode ) ) ;
2021-12-31 22:00:55 +00:00
break ;
}
}
2021-12-31 06:46:57 +00:00
}
}
2021-10-26 02:31:28 +00:00
}
2021-12-31 06:46:57 +00:00
pub struct Sprite {
pub pos : ( i16 , i16 ) ,
pub size : ( u16 , u16 ) ,
pub rev : ( bool , bool ) ,
pub pattern : u16 ,
pub link : u8 ,
}
impl Sprite {
pub fn new ( sprite_data : & [ u8 ] ) -> Self {
let v_pos = read_beu16 ( & sprite_data [ 0 .. ] ) ;
let size = sprite_data [ 2 ] ;
let link = sprite_data [ 3 ] ;
let pattern = read_beu16 ( & sprite_data [ 4 .. ] ) ;
let h_pos = read_beu16 ( & sprite_data [ 6 .. ] ) ;
let ( size_h , size_v ) = ( ( ( size > > 2 ) & 0x03 ) as u16 + 1 , ( size & 0x03 ) as u16 + 1 ) ;
let h_rev = ( pattern & 0x0800 ) ! = 0 ;
let v_rev = ( pattern & 0x1000 ) ! = 0 ;
Self {
pos : ( h_pos as i16 - 128 , v_pos as i16 - 128 ) ,
size : ( size_h , size_v ) ,
rev : ( h_rev , v_rev ) ,
pattern ,
link ,
}
}
pub fn calculate_pattern ( & self , cell_x : usize , cell_y : usize ) -> u16 {
let ( h , v ) = ( if ! self . rev . 0 { cell_x } else { self . size . 0 as usize - 1 - cell_x } , if ! self . rev . 1 { cell_y } else { self . size . 1 as usize - 1 - cell_y } ) ;
( self . pattern & 0xF800 ) | ( ( self . pattern & 0x07FF ) + ( h as u16 * self . size . 1 ) + v as u16 )
}
}
2021-12-31 22:00:55 +00:00
impl Steppable for Ym7101 {
fn step ( & mut self , system : & System ) -> Result < ClockElapsed , Error > {
let diff = ( system . clock - self . state . last_clock ) as u32 ;
self . state . last_clock = system . clock ;
if self . state . external_int_enabled ( ) & & self . external_interrupt . get ( ) {
self . external_interrupt . set ( false ) ;
system . get_interrupt_controller ( ) . set ( true , 2 , 26 ) ? ;
}
2022-01-02 23:44:41 +00:00
let clocks_per_pixel = 63_500 / ( self . state . screen_size . 0 as u32 * 8 + 88 ) ;
self . state . p_clock + = diff ;
if self . state . p_clock > = clocks_per_pixel {
let pixels = self . state . p_clock / clocks_per_pixel ;
self . state . p_clock - = pixels * clocks_per_pixel ;
self . state . current_x + = pixels as i32 ;
}
2021-12-31 22:00:55 +00:00
self . state . h_clock + = diff ;
if ( self . state . status & STATUS_IN_HBLANK ) ! = 0 & & self . state . h_clock > = 2_340 & & self . state . h_clock < = 61_160 {
self . state . status & = ! STATUS_IN_HBLANK ;
2022-01-02 23:44:41 +00:00
self . state . current_x = 0 ;
2021-12-31 22:00:55 +00:00
}
if ( self . state . status & STATUS_IN_HBLANK ) = = 0 & & self . state . h_clock > = 61_160 {
self . state . status | = STATUS_IN_HBLANK ;
2022-01-02 23:44:41 +00:00
self . state . current_y + = 1 ;
2021-12-31 22:00:55 +00:00
self . state . h_scanlines = self . state . h_scanlines . wrapping_sub ( 1 ) ;
if self . state . hsync_int_enabled ( ) & & self . state . h_scanlines = = 0 {
self . state . h_scanlines = self . state . h_int_lines ;
system . get_interrupt_controller ( ) . set ( true , 4 , 28 ) ? ;
}
}
if self . state . h_clock > 63_500 {
self . state . h_clock - = 63_500 ;
}
self . state . v_clock + = diff ;
if ( self . state . status & STATUS_IN_VBLANK ) ! = 0 & & self . state . v_clock > = 1_205_992 & & self . state . v_clock < = 15_424_008 {
self . state . status & = ! STATUS_IN_VBLANK ;
2022-01-02 23:44:41 +00:00
self . state . current_y = 0 ;
2021-12-31 22:00:55 +00:00
}
if ( self . state . status & STATUS_IN_VBLANK ) = = 0 & & self . state . v_clock > = 15_424_008 {
self . state . status | = STATUS_IN_VBLANK ;
if self . state . vsync_int_enabled ( ) {
system . get_interrupt_controller ( ) . set ( true , 6 , 30 ) ? ;
}
2022-01-16 18:56:32 +00:00
if ( self . state . mode_1 & MODE1_BF_DISABLE_DISPLAY ) = = 0 {
2022-10-01 19:12:25 +00:00
let mut frame = Frame ::new ( self . state . screen_size . 0 as u32 * 8 , self . state . screen_size . 1 as u32 * 8 ) ;
2022-01-16 18:56:32 +00:00
self . state . draw_frame ( & mut frame ) ;
2022-10-01 19:12:25 +00:00
self . queue . add ( system . clock , frame ) ;
2022-01-16 18:56:32 +00:00
}
2021-12-31 22:00:55 +00:00
self . frame_complete . signal ( ) ;
}
if self . state . v_clock > 16_630_000 {
self . state . v_clock - = 16_630_000 ;
}
if ( self . state . mode_2 & MODE2_BF_DMA_ENABLED ) ! = 0 {
self . state . memory . step_dma ( system ) ? ;
self . state . status = ( self . state . status & ! STATUS_DMA_BUSY ) | ( if self . state . memory . transfer_dma_busy { STATUS_DMA_BUSY } else { 0 } ) ;
}
Ok ( ( 1_000_000_000 / 13_423_294 ) * 4 )
}
}
2021-10-26 02:31:28 +00:00
pub struct Ym7101 {
2022-10-01 19:12:25 +00:00
queue : FrameQueue ,
2021-12-13 20:00:24 +00:00
state : Ym7101State ,
2022-09-09 02:51:29 +00:00
sn_sound : TransmutableBox ,
2021-12-13 20:00:24 +00:00
2021-12-07 22:29:38 +00:00
pub external_interrupt : HostData < bool > ,
2021-12-09 03:07:27 +00:00
pub frame_complete : EdgeSignal ,
2021-10-26 02:31:28 +00:00
}
impl Ym7101 {
2022-09-09 02:51:29 +00:00
pub fn new < H : Host > ( host : & mut H , external_interrupt : HostData < bool > , sn_sound : TransmutableBox ) -> Ym7101 {
2022-10-01 19:12:25 +00:00
let queue = FrameQueue ::new ( 320 , 224 ) ;
host . add_window ( Box ::new ( queue . clone ( ) ) ) . unwrap ( ) ;
2021-10-26 02:31:28 +00:00
Ym7101 {
2022-10-01 19:12:25 +00:00
queue ,
2023-03-06 04:19:49 +00:00
state : Ym7101State ::default ( ) ,
2022-09-09 02:51:29 +00:00
sn_sound ,
2021-10-31 18:00:14 +00:00
external_interrupt ,
2023-03-06 04:19:49 +00:00
frame_complete : EdgeSignal ::default ( ) ,
2021-10-26 02:31:28 +00:00
}
}
2021-12-30 19:27:50 +00:00
fn set_register ( & mut self , word : u16 ) {
let reg = ( ( word & 0x1F00 ) > > 8 ) as usize ;
let data = ( word & 0x00FF ) as u8 ;
2022-01-16 18:39:57 +00:00
debug! ( " {}: register {:x} set to {:x} " , DEV_NAME , reg , data ) ;
2021-12-30 19:27:50 +00:00
self . update_register_value ( reg , data ) ;
2021-10-26 02:31:28 +00:00
}
2021-12-30 19:27:50 +00:00
fn update_register_value ( & mut self , reg : usize , data : u8 ) {
match reg {
REG_MODE_SET_1 = > { self . state . mode_1 = data ; } ,
REG_MODE_SET_2 = > {
self . state . mode_2 = data ;
self . state . update_screen_size ( ) ;
} ,
REG_SCROLL_A_ADDR = > { self . state . scroll_a_addr = ( data as usize ) < < 10 ; } ,
REG_WINDOW_ADDR = > { self . state . window_addr = ( data as usize ) < < 10 ; } ,
REG_SCROLL_B_ADDR = > { self . state . scroll_b_addr = ( data as usize ) < < 13 ; } ,
REG_SPRITES_ADDR = > { self . state . sprites_addr = ( data as usize ) < < 9 ; } ,
REG_BACKGROUND = > { self . state . background = data ; } ,
REG_H_INTERRUPT = > { self . state . h_int_lines = data ; } ,
REG_MODE_SET_3 = > { self . state . mode_3 = data ; } ,
REG_MODE_SET_4 = > {
self . state . mode_4 = data ;
self . state . update_screen_size ( ) ;
} ,
REG_HSCROLL_ADDR = > { self . state . hscroll_addr = ( data as usize ) < < 10 ; } ,
REG_AUTO_INCREMENT = > { self . state . memory . transfer_auto_inc = data as u32 ; } ,
REG_SCROLL_SIZE = > {
let h = decode_scroll_size ( data & 0x03 ) ;
let v = decode_scroll_size ( ( data > > 4 ) & 0x03 ) ;
self . state . scroll_size = ( h , v ) ;
} ,
REG_WINDOW_H_POS = > {
2021-12-31 19:40:13 +00:00
self . state . window_values . 0 = data ;
self . state . update_window_position ( ) ;
2021-12-30 19:27:50 +00:00
} ,
REG_WINDOW_V_POS = > {
2021-12-31 19:40:13 +00:00
self . state . window_values . 1 = data ;
self . state . update_window_position ( ) ;
2021-12-30 19:27:50 +00:00
} ,
REG_DMA_COUNTER_LOW = > {
self . state . memory . transfer_count = ( self . state . memory . transfer_count & 0xFF00 ) | data as u32 ;
self . state . memory . transfer_remain = self . state . memory . transfer_count ;
} ,
REG_DMA_COUNTER_HIGH = > {
self . state . memory . transfer_count = ( self . state . memory . transfer_count & 0x00FF ) | ( ( data as u32 ) < < 8 ) ;
self . state . memory . transfer_remain = self . state . memory . transfer_count ;
} ,
REG_DMA_ADDR_LOW = > {
self . state . memory . transfer_src_addr = ( self . state . memory . transfer_src_addr & 0xFFFE00 ) | ( ( data as u32 ) < < 1 ) ;
} ,
REG_DMA_ADDR_MID = > {
self . state . memory . transfer_src_addr = ( self . state . memory . transfer_src_addr & 0xFE01FF ) | ( ( data as u32 ) < < 9 ) ;
} ,
REG_DMA_ADDR_HIGH = > {
let mask = if ( data & 0x80 ) = = 0 { 0x7F } else { 0x3F } ;
self . state . memory . transfer_bits = data & 0xC0 ;
self . state . memory . transfer_src_addr = ( self . state . memory . transfer_src_addr & 0x01FFFF ) | ( ( ( data & mask ) as u32 ) < < 17 ) ;
} ,
0x6 | 0x8 | 0x9 | 0xE = > { /* Reserved */ } ,
_ = > { panic! ( " {} : unknown register: {:?} " , DEV_NAME , reg ) ; } ,
}
2021-10-26 02:31:28 +00:00
}
2021-12-30 19:27:50 +00:00
}
2021-11-29 19:11:32 +00:00
2021-12-30 19:27:50 +00:00
fn decode_scroll_size ( size : u8 ) -> usize {
match size {
0b00 = > 32 ,
0b01 = > 64 ,
0b11 = > 128 ,
_ = > panic! ( " {} : invalid scroll size option {:x} " , DEV_NAME , size ) ,
2021-11-29 19:11:32 +00:00
}
2021-10-26 02:31:28 +00:00
}
impl Addressable for Ym7101 {
fn len ( & self ) -> usize {
0x20
}
2021-12-27 00:32:15 +00:00
fn read ( & mut self , mut addr : Address , data : & mut [ u8 ] ) -> Result < ( ) , Error > {
2021-10-26 02:31:28 +00:00
match addr {
// Read from Data Port
2021-12-30 19:27:50 +00:00
0x00 | 0x02 = > self . state . memory . read_data_port ( addr , data ) ? ,
2021-10-26 02:31:28 +00:00
// Read from Control Port
2021-12-27 00:32:15 +00:00
0x04 | 0x05 | 0x06 | 0x07 = > {
2021-10-26 02:31:28 +00:00
debug! ( " {}: read status byte {:x} " , DEV_NAME , self . state . status ) ;
2023-03-06 04:19:49 +00:00
for item in data {
* item = if ( addr % 2 ) = = 0 {
2021-12-27 00:32:15 +00:00
( self . state . status > > 8 ) as u8
} else {
( self . state . status & 0x00FF ) as u8
} ;
addr + = 1 ;
}
2021-10-26 02:31:28 +00:00
} ,
2022-01-02 23:44:41 +00:00
// Read from H/V Counter
0x08 | 0x0A = > {
data [ 0 ] = self . state . current_y as u8 ;
if data . len ( ) > 1 {
data [ 1 ] = ( self . state . current_x > > 1 ) as u8 ;
}
} ,
2021-10-26 02:31:28 +00:00
_ = > { println! ( " {} : !!! unhandled read from {:x} " , DEV_NAME , addr ) ; } ,
}
2021-10-28 04:01:18 +00:00
Ok ( ( ) )
2021-10-26 02:31:28 +00:00
}
fn write ( & mut self , addr : Address , data : & [ u8 ] ) -> Result < ( ) , Error > {
match addr {
// Write to Data Port
2022-09-10 05:31:55 +00:00
0x00 | 0x02 = > self . state . memory . write_data_port ( data ) ? ,
2021-10-26 02:31:28 +00:00
// Write to Control Port
0x04 | 0x06 = > {
2021-12-01 18:45:24 +00:00
debug! ( " {}: write {} bytes to port {:x} with data {:?} " , DEV_NAME , data . len ( ) , addr , data ) ;
2021-10-28 04:01:18 +00:00
2021-10-26 02:31:28 +00:00
let value = read_beu16 ( data ) ;
if ( value & 0xC000 ) = = 0x8000 {
2021-12-30 19:27:50 +00:00
self . set_register ( value ) ;
2021-10-26 02:31:28 +00:00
if data . len ( ) = = 4 {
let value = read_beu16 ( & data [ 2 .. ] ) ;
if ( value & 0xC000 ) ! = 0x8000 {
2021-12-23 03:27:20 +00:00
return Err ( Error ::new ( & format! ( " {} : unexpected second byte {:x} " , DEV_NAME , value ) ) ) ;
2021-10-26 02:31:28 +00:00
}
2021-12-30 19:27:50 +00:00
self . set_register ( value ) ;
2021-10-26 02:31:28 +00:00
}
} else {
2022-09-10 05:31:55 +00:00
self . state . memory . write_control_port ( data ) ? ;
2021-12-30 19:27:50 +00:00
self . state . status = ( self . state . status & ! STATUS_DMA_BUSY ) | ( if self . state . memory . transfer_dma_busy { STATUS_DMA_BUSY } else { 0 } ) ;
2021-10-26 02:31:28 +00:00
}
} ,
2022-09-09 02:51:29 +00:00
0x11 | 0x12 = > {
self . sn_sound . borrow_mut ( ) . as_addressable ( ) . unwrap ( ) . write ( 0 , data ) ? ;
} ,
2022-10-09 16:40:20 +00:00
_ = > { warn! ( " {}: !!! unhandled write to {:x} with {:?} " , DEV_NAME , addr , data ) ; } ,
2021-10-26 02:31:28 +00:00
}
Ok ( ( ) )
}
}
2021-12-30 19:27:50 +00:00
impl Transmutable for Ym7101 {
fn as_addressable ( & mut self ) -> Option < & mut dyn Addressable > {
Some ( self )
}
fn as_steppable ( & mut self ) -> Option < & mut dyn Steppable > {
Some ( self )
}
fn as_inspectable ( & mut self ) -> Option < & mut dyn Inspectable > {
Some ( self )
}
}
2021-11-29 19:11:32 +00:00
impl Inspectable for Ym7101 {
2021-12-13 20:00:24 +00:00
fn inspect ( & mut self , _system : & System , args : & [ & str ] ) -> Result < ( ) , Error > {
2021-12-01 18:45:24 +00:00
match args [ 0 ] {
2021-11-29 19:11:32 +00:00
" " | " state " = > {
self . state . dump_state ( ) ;
} ,
" vram " = > {
self . state . dump_vram ( ) ;
} ,
2021-12-02 23:04:41 +00:00
" vsram " = > {
self . state . dump_vsram ( ) ;
} ,
2021-11-29 19:11:32 +00:00
_ = > { } ,
}
Ok ( ( ) )
}
}
impl Ym7101State {
pub fn dump_state ( & self ) {
2023-03-06 04:19:49 +00:00
println! ( ) ;
2021-12-04 21:55:58 +00:00
println! ( " Mode1: {:#04x} " , self . mode_1 ) ;
println! ( " Mode2: {:#04x} " , self . mode_2 ) ;
println! ( " Mode3: {:#04x} " , self . mode_3 ) ;
println! ( " Mode4: {:#04x} " , self . mode_4 ) ;
2023-03-06 04:19:49 +00:00
println! ( ) ;
2021-12-04 21:55:58 +00:00
println! ( " Scroll A : {:#06x} " , self . scroll_a_addr ) ;
println! ( " Window : {:#06x} " , self . window_addr ) ;
println! ( " Scroll B : {:#06x} " , self . scroll_b_addr ) ;
println! ( " HScroll : {:#06x} " , self . hscroll_addr ) ;
println! ( " Sprites : {:#06x} " , self . sprites_addr ) ;
2023-03-06 04:19:49 +00:00
println! ( ) ;
2021-12-30 19:27:50 +00:00
println! ( " DMA type : {:?} " , self . memory . transfer_type ) ;
println! ( " DMA Source: {:#06x} " , self . memory . transfer_src_addr ) ;
println! ( " DMA Dest : {:#06x} " , self . memory . transfer_dest_addr ) ;
println! ( " DMA Count : {:#06x} " , self . memory . transfer_count ) ;
println! ( " Auto-Inc : {:#06x} " , self . memory . transfer_auto_inc ) ;
2021-11-29 19:11:32 +00:00
}
pub fn dump_vram ( & self ) {
2021-12-30 19:27:50 +00:00
dump_slice ( & self . memory . vram , 65536 ) ;
2021-11-29 19:11:32 +00:00
}
2021-12-02 23:04:41 +00:00
pub fn dump_vsram ( & self ) {
2021-12-30 19:27:50 +00:00
dump_slice ( & self . memory . vsram , 80 ) ;
2021-12-02 23:04:41 +00:00
}
2021-11-29 19:11:32 +00:00
}