2021-10-26 02:31:28 +00:00
use std ::iter ::Iterator ;
use std ::sync ::{ Arc , Mutex } ;
use crate ::error ::Error ;
use crate ::system ::System ;
2021-10-31 18:00:14 +00:00
use crate ::signals ::SyncSignal ;
2021-10-26 02:31:28 +00:00
use crate ::devices ::{ Clock , ClockElapsed , Address , Addressable , Steppable , Transmutable , MAX_READ , read_beu16 , read_beu32 , write_beu16 } ;
use crate ::host ::traits ::{ Host , BlitableSurface } ;
use crate ::host ::gfx ::{ Frame , FrameSwapper } ;
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 ;
// Register 0x06 Unused
const REG_BACKGROUND : usize = 0x07 ;
// Register 0x08 Unused
// Register 0x09 Unused
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 ;
// Register 0x0E Unused
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 ;
const STATUS_PAL_MODE : u16 = 0x0001 ;
const STATUS_DMA_BUSY : u16 = 0x0002 ;
const STATUS_IN_HBLANK : u16 = 0x0004 ;
const STATUS_IN_VBLANK : u16 = 0x0008 ;
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 ;
const STATUS_FIFO_EMPTY : u16 = 0x0200 ;
const MODE1_BF_ENABLE_HV_COUNTER : u8 = 0x02 ;
const MODE1_BF_HSYNC_INTERRUPT : u8 = 0x10 ;
const MODE2_BF_V_CELL_MODE : u8 = 0x08 ;
const MODE2_BF_VSYNC_INTERRUPT : u8 = 0x20 ;
const MODE4_BF_H_CELL_MODE : u8 = 0x01 ;
const DEV_NAME : & 'static str = " ym7101 " ;
#[ derive(Copy, Clone, Debug, PartialEq) ]
pub enum DmaType {
None ,
Memory ,
Fill ,
Copy ,
}
#[ derive(Copy, Clone, Debug, PartialEq) ]
pub enum TargetType {
2021-10-30 23:16:09 +00:00
Vram ,
Cram ,
Vsram ,
2021-10-26 02:31:28 +00:00
}
pub struct Ym7101State {
pub status : u16 ,
pub regs : [ u8 ; 24 ] ,
pub vram : [ u8 ; 0x10000 ] ,
pub cram : [ u8 ; 128 ] ,
pub vsram : [ u8 ; 80 ] ,
pub transfer_type : u8 ,
pub transfer_addr : u32 ,
pub transfer_fill : u16 ,
pub transfer_run : DmaType ,
pub transfer_target : TargetType ,
pub transfer_upper : Option < u16 > ,
pub last_clock : Clock ,
pub h_clock : u32 ,
pub v_clock : u32 ,
pub h_scanlines : u8 ,
}
impl Ym7101State {
pub fn new ( ) -> Self {
Self {
2021-10-30 23:16:09 +00:00
status : 0x3400 | STATUS_FIFO_EMPTY ,
2021-10-26 02:31:28 +00:00
regs : [ 0 ; 24 ] ,
vram : [ 0 ; 0x10000 ] ,
cram : [ 0 ; 128 ] ,
vsram : [ 0 ; 80 ] ,
transfer_type : 0 ,
transfer_addr : 0 ,
transfer_fill : 0 ,
transfer_run : DmaType ::None ,
transfer_target : TargetType ::Vram ,
transfer_upper : None ,
last_clock : 0 ,
h_clock : 0 ,
v_clock : 0 ,
h_scanlines : 0 ,
}
}
fn set_register ( & mut self , data : u16 ) {
let reg = ( data & 0x1F00 ) > > 8 ;
self . regs [ reg as usize ] = ( data & 0x00FF ) as u8 ;
2021-10-28 04:01:18 +00:00
info! ( " {}: register {:x} set to {:x} " , DEV_NAME , reg , self . regs [ reg as usize ] ) ;
2021-10-26 02:31:28 +00:00
}
pub fn set_dma_mode ( & mut self , mode : DmaType ) {
match mode {
DmaType ::None = > {
self . status & = ! STATUS_DMA_BUSY ;
self . transfer_run = DmaType ::None ;
} ,
_ = > {
self . status | = STATUS_DMA_BUSY ;
self . transfer_run = mode ;
} ,
}
}
pub fn get_dma_src_addr ( & mut self ) -> u32 {
let src_addr = ( ( ( self . regs [ REG_DMA_ADDR_HIGH ] & 0x7F ) as u32 ) < < 17 )
| ( ( self . regs [ REG_DMA_ADDR_MID ] as u32 ) < < 9 )
| ( ( self . regs [ REG_DMA_ADDR_LOW ] as u32 ) < < 1 ) ;
if ( self . regs [ REG_DMA_ADDR_HIGH ] & 0x80 ) = = 0 {
src_addr
} else {
src_addr & ! 0x00800000
}
}
pub fn get_dma_count ( & mut self ) -> i32 {
( ( ( self . regs [ REG_DMA_COUNTER_HIGH ] as u32 ) < < 8 ) | ( self . regs [ REG_DMA_COUNTER_LOW ] as u32 ) ) as i32
}
2021-10-28 04:01:18 +00:00
pub fn setup_transfer ( & mut self , upper : u16 , lower : u16 ) {
2021-10-26 02:31:28 +00:00
self . transfer_upper = None ;
self . transfer_type = ( ( ( ( upper & 0xC000 ) > > 14 ) | ( ( lower & 0x00F0 ) > > 2 ) ) ) as u8 ;
self . transfer_addr = ( ( upper & 0x3FFF ) | ( ( lower & 0x0003 ) < < 14 ) ) as u32 ;
self . transfer_target = match self . transfer_type & 0x0E {
0 = > TargetType ::Vram ,
4 = > TargetType ::Vsram ,
_ = > TargetType ::Cram ,
} ;
2021-10-28 04:01:18 +00:00
info! ( " {}: transfer requested of type {:x} ({:?}) to address {:x} " , DEV_NAME , self . transfer_type , self . transfer_target , self . transfer_addr ) ;
2021-10-26 02:31:28 +00:00
if ( self . transfer_type & 0x20 ) ! = 0 {
if ( self . transfer_type & 0x10 ) ! = 0 {
self . set_dma_mode ( DmaType ::Copy ) ;
} else if ( self . regs [ REG_DMA_ADDR_HIGH ] & 0x80 ) = = 0 {
self . set_dma_mode ( DmaType ::Memory ) ;
}
}
}
pub fn get_transfer_target_mut ( & mut self ) -> & mut [ u8 ] {
match self . transfer_target {
TargetType ::Vram = > & mut self . vram ,
TargetType ::Cram = > & mut self . cram ,
TargetType ::Vsram = > & mut self . vsram ,
}
}
#[ inline(always) ]
fn hsync_int_enabled ( & self ) -> bool {
( self . regs [ REG_MODE_SET_1 ] & MODE1_BF_HSYNC_INTERRUPT ) ! = 0
}
2021-10-30 23:16:09 +00:00
#[ inline(always) ]
2021-10-26 02:31:28 +00:00
fn vsync_int_enabled ( & self ) -> bool {
( self . regs [ REG_MODE_SET_2 ] & MODE2_BF_VSYNC_INTERRUPT ) ! = 0
}
pub fn get_vram_scroll_a_addr ( & self ) -> u32 {
( ( self . regs [ REG_SCROLL_A_ADDR ] as u16 ) < < 10 ) as u32
}
pub fn get_vram_scroll_b_addr ( & self ) -> u32 {
( ( self . regs [ REG_SCROLL_B_ADDR ] as u16 ) < < 13 ) as u32
}
pub fn get_vram_window_addr ( & self ) -> u32 {
( ( self . regs [ REG_WINDOW_ADDR ] as u16 ) < < 10 ) as u32
}
pub fn get_palette_colour ( & self , palette : u8 , colour : u8 ) -> u32 {
2021-10-28 04:01:18 +00:00
if colour = = 0 {
return 0 ;
}
let rgb = read_beu16 ( & self . cram [ ( ( ( palette * 16 ) + colour ) * 2 ) as usize .. ] ) ;
2021-10-26 02:31:28 +00:00
( ( ( rgb & 0xF00 ) as u32 ) > > 4 ) | ( ( ( rgb & 0x0F0 ) as u32 ) < < 8 ) | ( ( ( rgb & 0x00F ) as u32 ) < < 20 )
}
pub fn get_pattern_iter < ' a > ( & ' a self , pattern_name : u16 ) -> PatternIterator < ' a > {
let pattern_addr = ( pattern_name & 0x07FF ) < < 5 ;
let pattern_palette = ( ( pattern_name & 0x6000 ) > > 13 ) as u8 ;
2021-10-28 04:01:18 +00:00
let h_rev = ( pattern_name & 0x0800 ) ! = 0 ;
let v_rev = ( pattern_name & 0x1000 ) ! = 0 ;
PatternIterator ::new ( & self , pattern_addr as u32 , pattern_palette , h_rev , v_rev )
2021-10-26 02:31:28 +00:00
}
pub fn get_scroll_size ( & self ) -> ( u16 , u16 ) {
let h = scroll_size ( self . regs [ REG_SCROLL_SIZE ] & 0x03 ) ;
let v = scroll_size ( ( self . regs [ REG_SCROLL_SIZE ] > > 4 ) & 0x03 ) ;
( h , v )
}
2021-10-30 23:16:09 +00:00
pub fn get_screen_size ( & self ) -> ( u16 , u16 ) {
2021-10-26 02:31:28 +00:00
let h_cells = if ( self . regs [ REG_MODE_SET_4 ] & MODE4_BF_H_CELL_MODE ) = = 0 { 32 } else { 40 } ;
let v_cells = if ( self . regs [ REG_MODE_SET_2 ] & MODE2_BF_V_CELL_MODE ) = = 0 { 28 } else { 30 } ;
2021-10-30 23:16:09 +00:00
( h_cells , v_cells )
}
pub fn get_window_coords ( & self , screen_size : ( u16 , u16 ) ) -> ( u16 , u16 ) {
2021-10-26 02:31:28 +00:00
let win_h = ( ( self . regs [ REG_WINDOW_H_POS ] & 0x1F ) < < 1 ) as u16 ;
let win_v = ( self . regs [ REG_WINDOW_V_POS ] & 0x1F ) as u16 ;
2021-10-30 23:16:09 +00:00
let right = ( self . regs [ REG_WINDOW_H_POS ] & 0x80 ) ! = 0 ;
let down = ( self . regs [ REG_WINDOW_V_POS ] & 0x80 ) ! = 0 ;
match ( right , down ) {
( false , false ) = > ( win_h , win_v ) ,
( true , false ) = > ( win_h - screen_size . 0 , win_v ) ,
( false , true ) = > ( win_h , win_v - screen_size . 1 ) ,
( true , true ) = > ( win_h - screen_size . 0 , win_v - screen_size . 1 ) ,
2021-10-26 02:31:28 +00:00
}
}
pub fn draw_frame ( & mut self , frame : & mut Frame ) {
let bg_colour = self . get_palette_colour ( ( self . regs [ REG_BACKGROUND ] & 0x30 ) > > 4 , self . regs [ REG_BACKGROUND ] & 0x0f ) ;
for i in 0 .. ( frame . width as usize * frame . height as usize ) {
frame . bitmap [ i ] = bg_colour ;
}
2021-10-30 23:16:09 +00:00
self . draw_cell_table ( frame , self . get_vram_scroll_b_addr ( ) ) ;
self . draw_cell_table ( frame , self . get_vram_scroll_a_addr ( ) ) ;
//self.draw_window(frame);
self . draw_sprites ( frame ) ;
}
pub fn draw_cell_table ( & mut self , frame : & mut Frame , cell_table : u32 ) {
let ( scroll_h , scroll_v ) = self . get_scroll_size ( ) ;
let ( cells_h , cells_v ) = self . get_screen_size ( ) ;
let ( offset_x , offset_y ) = self . get_window_coords ( ( cells_h , cells_v ) ) ;
for cell_y in 0 .. cells_v {
for cell_x in 0 .. cells_h {
let pattern_name = read_beu16 ( & self . vram [ ( cell_table + ( ( ( cell_x + offset_x ) + ( ( cell_y + offset_y ) * scroll_h ) ) < < 1 ) as u32 ) as usize .. ] ) ;
let iter = self . get_pattern_iter ( pattern_name ) ;
frame . blit ( ( cell_x < < 3 ) as u32 , ( cell_y < < 3 ) as u32 , iter , 8 , 8 ) ;
}
}
2021-10-26 02:31:28 +00:00
}
2021-10-30 23:16:09 +00:00
pub fn draw_window ( & mut self , frame : & mut Frame ) {
let cell_table = self . get_vram_window_addr ( ) ;
let ( scroll_h , scroll_v ) = self . get_scroll_size ( ) ;
let ( cells_h , cells_v ) = self . get_screen_size ( ) ;
for cell_y in 0 .. cells_v {
for cell_x in 0 .. cells_h {
let pattern_name = read_beu16 ( & self . vram [ ( cell_table + ( ( cell_x + ( cell_y * scroll_h ) ) < < 1 ) as u32 ) as usize .. ] ) ;
2021-10-26 02:31:28 +00:00
let iter = self . get_pattern_iter ( pattern_name ) ;
frame . blit ( ( cell_x < < 3 ) as u32 , ( cell_y < < 3 ) as u32 , iter , 8 , 8 ) ;
}
}
}
2021-10-30 23:16:09 +00:00
pub fn draw_sprites ( & mut self , frame : & mut Frame ) {
let sprite_table = ( self . regs [ REG_SPRITES_ADDR ] as u32 ) < < 9 ;
let ( scroll_h , scroll_v ) = self . get_scroll_size ( ) ;
2021-10-26 02:31:28 +00:00
2021-10-30 23:16:09 +00:00
for i in 0 .. ( scroll_h as u32 * 2 ) {
2021-10-31 18:00:14 +00:00
let sprite_data = & self . vram [ ( ( sprite_table + ( i * 8 ) ) as usize ) .. ] ;
let v_pos = read_beu16 ( & sprite_data [ 0 .. ] ) ;
let size = sprite_data [ 2 ] ;
let link = sprite_data [ 3 ] ;
let pattern_name = read_beu16 ( & sprite_data [ 4 .. ] ) ;
let h_pos = read_beu16 ( & sprite_data [ 6 .. ] ) ;
2021-10-30 23:16:09 +00:00
let ( size_h , size_v ) = ( ( ( size > > 2 ) & 0x03 ) as u16 , ( size & 0x03 ) as u16 ) ;
2021-10-26 02:31:28 +00:00
2021-10-30 23:16:09 +00:00
for h in 0 .. size_h {
for v in 0 .. size_v {
let iter = self . get_pattern_iter ( pattern_name + ( h * size_v ) + v ) ;
2021-10-31 18:00:14 +00:00
frame . blit ( ( h_pos + ( h * 8 ) ) as u32 , ( v_pos + ( v * 8 ) ) as u32 , iter , 8 , 8 ) ;
2021-10-30 23:16:09 +00:00
}
}
2021-10-26 02:31:28 +00:00
}
}
}
fn scroll_size ( size : u8 ) -> u16 {
match size {
0b00 = > 32 ,
0b01 = > 64 ,
0b11 = > 128 ,
_ = > panic! ( " {} : invalid scroll size option {:x} " , DEV_NAME , size ) ,
}
}
pub struct PatternIterator < ' a > {
state : & ' a Ym7101State ,
palette : u8 ,
2021-10-28 04:01:18 +00:00
base : usize ,
h_rev : bool ,
v_rev : bool ,
line : i8 ,
col : i8 ,
2021-10-26 02:31:28 +00:00
second : bool ,
}
impl < ' a > PatternIterator < ' a > {
2021-10-28 04:01:18 +00:00
pub fn new ( state : & ' a Ym7101State , start : u32 , palette : u8 , h_rev : bool , v_rev : bool ) -> Self {
2021-10-26 02:31:28 +00:00
Self {
state ,
palette ,
2021-10-28 04:01:18 +00:00
base : start as usize ,
h_rev ,
v_rev ,
line : 0 ,
col : 0 ,
2021-10-26 02:31:28 +00:00
second : false ,
}
}
}
impl < ' a > Iterator for PatternIterator < ' a > {
type Item = u32 ;
fn next ( & mut self ) -> Option < Self ::Item > {
2021-10-28 04:01:18 +00:00
let offset = self . base + ( if ! self . v_rev { self . line } else { 7 - self . line } ) as usize * 4 + ( if ! self . h_rev { self . col } else { 3 - self . col } ) as usize ;
let value = if ( ! self . h_rev & & ! self . second ) | | ( self . h_rev & & self . second ) {
self . state . get_palette_colour ( self . palette , self . state . vram [ offset ] > > 4 )
} else {
self . state . get_palette_colour ( self . palette , self . state . vram [ offset ] & 0x0f )
} ;
2021-10-26 02:31:28 +00:00
if ! self . second {
self . second = true ;
} else {
self . second = false ;
2021-10-28 04:01:18 +00:00
self . col + = 1 ;
if self . col > = 4 {
self . col = 0 ;
self . line + = 1 ;
}
2021-10-26 02:31:28 +00:00
}
2021-10-28 04:01:18 +00:00
Some ( value )
2021-10-26 02:31:28 +00:00
}
}
pub struct Ym7101 {
pub swapper : Arc < Mutex < FrameSwapper > > ,
pub state : Ym7101State ,
2021-10-31 18:00:14 +00:00
pub external_interrupt : SyncSignal < bool > ,
2021-10-26 02:31:28 +00:00
}
impl Ym7101 {
2021-10-31 18:00:14 +00:00
pub fn new < H : Host > ( host : & H , external_interrupt : SyncSignal < bool > ) -> Ym7101 {
2021-10-26 02:31:28 +00:00
let swapper = FrameSwapper ::new_shared ( ) ;
swapper . lock ( ) . map ( | mut swapper | {
swapper . current . set_size ( 320 , 224 ) ;
swapper . previous . set_size ( 320 , 224 ) ;
} ) ;
host . add_window ( FrameSwapper ::to_boxed ( swapper . clone ( ) ) ) ;
Ym7101 {
swapper ,
state : Ym7101State ::new ( ) ,
2021-10-31 18:00:14 +00:00
external_interrupt ,
2021-10-26 02:31:28 +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 )
}
}
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 ;
2021-10-31 18:00:14 +00:00
if self . external_interrupt . get ( ) {
self . external_interrupt . set ( false ) ;
system . get_interrupt_controller ( ) . set ( true , 2 , 26 ) ? ;
2021-10-26 02:31:28 +00:00
}
self . state . h_clock + = diff ;
2021-10-28 04:01:18 +00:00
if ( self . state . status & STATUS_IN_HBLANK ) = = 0 & & self . state . v_clock > 58_820 {
self . state . status | = STATUS_IN_HBLANK ;
}
2021-10-26 02:31:28 +00:00
if self . state . h_clock > 63_500 {
2021-10-28 04:01:18 +00:00
self . state . status & = ! STATUS_IN_HBLANK ;
2021-10-26 02:31:28 +00:00
self . state . h_clock = 0 ;
2021-10-28 04:01:18 +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 . regs [ REG_H_INTERRUPT ] ;
2021-10-26 02:31:28 +00:00
system . get_interrupt_controller ( ) . set ( true , 4 , 28 ) ? ;
}
}
self . state . v_clock + = diff ;
2021-10-28 04:01:18 +00:00
if ( self . state . status & STATUS_IN_VBLANK ) = = 0 & & self . state . v_clock > 14_218_000 {
self . state . status | = STATUS_IN_VBLANK ;
}
2021-10-26 02:31:28 +00:00
if self . state . v_clock > 16_630_000 {
2021-10-28 04:01:18 +00:00
self . state . status & = ! STATUS_IN_VBLANK ;
2021-10-26 02:31:28 +00:00
self . state . v_clock = 0 ;
if self . state . vsync_int_enabled ( ) {
system . get_interrupt_controller ( ) . set ( true , 6 , 30 ) ? ;
}
let mut swapper = self . swapper . lock ( ) . unwrap ( ) ;
self . state . draw_frame ( & mut swapper . current ) ;
2021-10-28 04:01:18 +00:00
//let mut swapper = self.swapper.lock().unwrap();
//let iter = PatternIterator::new(&self.state, 0x260, 0, true, true);
//swapper.current.blit(0, 0, iter, 8, 8);
2021-10-26 02:31:28 +00:00
/*
// Print Palette
for i in 0 .. 16 {
println! ( " {:x} " , self . state . get_palette_colour ( 0 , i ) ) ;
}
* /
/*
// Print Pattern Table
let mut swapper = self . swapper . lock ( ) . unwrap ( ) ;
let coords = self . state . get_window_coords ( ) ;
for cell_y in coords . 0. 1 .. coords . 1.1 {
for cell_x in coords . 0. 0 .. coords . 1.0 {
let pattern_addr = ( cell_x + ( cell_y * 40 ) ) * 32 ;
let iter = PatternIterator ::new ( & self . state , pattern_addr as u32 , 0 ) ;
swapper . current . blit ( ( cell_x < < 3 ) as u32 , ( cell_y < < 3 ) as u32 , iter , 8 , 8 ) ;
}
}
* /
}
if self . state . transfer_run ! = DmaType ::None {
// TODO we will just do the full dma transfer here, but it really should be stepped
match self . state . transfer_run {
DmaType ::Memory = > {
let mut src_addr = self . state . get_dma_src_addr ( ) ;
let mut count = self . state . get_dma_count ( ) ;
2021-10-28 04:01:18 +00:00
info! ( " {}: starting dma transfer {:x} from Mem:{:x} to {:?}:{:x} ({} bytes) " , DEV_NAME , self . state . transfer_type , src_addr , self . state . transfer_target , self . state . transfer_addr , count ) ;
2021-10-26 02:31:28 +00:00
let mut bus = system . get_bus ( ) ;
2021-10-28 04:01:18 +00:00
// TODO temporary for debugging, will break at the first cram transfer after the display is on
//if (self.state.regs[REG_MODE_SET_2] & 0x40) != 0 && self.state.transfer_target == TargetType::Cram {
// system.get_interrupt_controller().target.as_ref().map(|cpu| cpu.borrow_mut().as_debuggable().unwrap().enable_debugging());
//}
//bus.dump_memory(src_addr as Address, count as Address);
2021-10-26 02:31:28 +00:00
while count > 0 {
2021-10-28 04:01:18 +00:00
let mut data = [ 0 ; 2 ] ;
bus . read ( src_addr as Address , & mut data ) ? ;
2021-10-26 02:31:28 +00:00
{
let addr = self . state . transfer_addr ;
let mut target = self . state . get_transfer_target_mut ( ) ;
target [ addr as usize ] = data [ 0 ] ;
target [ addr as usize + 1 ] = data [ 1 ] ;
}
self . state . transfer_addr + = self . state . regs [ REG_AUTO_INCREMENT ] as u32 ;
src_addr + = 2 ;
count - = 2 ;
}
} ,
DmaType ::Copy = > {
let mut src_addr = self . state . get_dma_src_addr ( ) ;
let mut count = self . state . get_dma_count ( ) ;
2021-10-28 04:01:18 +00:00
info! ( " {}: starting dma copy from VRAM:{:x} to VRAM:{:x} ({} bytes) " , DEV_NAME , src_addr , self . state . transfer_addr , count ) ;
2021-10-26 02:31:28 +00:00
while count > 0 {
self . state . vram [ self . state . transfer_addr as usize ] = self . state . vram [ src_addr as usize ] ;
self . state . transfer_addr + = self . state . regs [ REG_AUTO_INCREMENT ] as u32 ;
src_addr + = 1 ;
count - = 1 ;
}
} ,
DmaType ::Fill = > {
let mut count = self . state . get_dma_count ( ) ;
2021-10-28 04:01:18 +00:00
info! ( " {}: starting dma fill to VRAM:{:x} ({} bytes) with {:x} " , DEV_NAME , self . state . transfer_addr , count , self . state . transfer_fill ) ;
2021-10-26 02:31:28 +00:00
while count > 0 {
self . state . vram [ self . state . transfer_addr as usize ] = self . state . transfer_fill as u8 ;
self . state . transfer_addr + = self . state . regs [ REG_AUTO_INCREMENT ] as u32 ;
count - = 1 ;
}
} ,
_ = > { warning! ( " {}: !!! error unexpected transfer mode {:x} " , DEV_NAME , self . state . transfer_type ) ; } ,
}
self . state . set_dma_mode ( DmaType ::None ) ;
}
2021-10-29 22:05:41 +00:00
Ok ( ( 1_000_000_000 / 13_423_294 ) * 4 )
2021-10-26 02:31:28 +00:00
}
}
impl Addressable for Ym7101 {
fn len ( & self ) -> usize {
0x20
}
2021-10-28 04:01:18 +00:00
fn read ( & mut self , addr : Address , data : & mut [ u8 ] ) -> Result < ( ) , Error > {
2021-10-26 02:31:28 +00:00
match addr {
// Read from Data Port
2021-10-28 04:01:18 +00:00
0x00 | 0x02 = > {
2021-10-26 02:31:28 +00:00
{
let addr = self . state . transfer_addr ;
let target = self . state . get_transfer_target_mut ( ) ;
2021-10-28 04:01:18 +00:00
for i in 0 .. data . len ( ) {
2021-10-26 02:31:28 +00:00
data [ i ] = target [ addr as usize + i ] ;
}
}
self . state . transfer_addr + = self . state . regs [ REG_AUTO_INCREMENT ] as u32 ;
2021-10-28 04:01:18 +00:00
info! ( " {}: data port read {} bytes from {:?}:{:x} returning {:x},{:x} " , DEV_NAME , data . len ( ) , self . state . transfer_target , addr , data [ 0 ] , data [ 1 ] ) ;
2021-10-26 02:31:28 +00:00
} ,
// Read from Control Port
0x04 | 0x06 = > {
debug! ( " {}: read status byte {:x} " , DEV_NAME , self . state . status ) ;
data [ 0 ] = ( self . state . status > > 8 ) as u8 ;
data [ 1 ] = ( self . state . status & 0x00FF ) as u8 ;
} ,
_ = > { 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
2021-10-28 04:01:18 +00:00
0x00 | 0x02 = > {
2021-10-26 02:31:28 +00:00
if ( self . state . transfer_type & 0x30 ) = = 0x20 {
self . state . transfer_upper = None ;
2021-10-30 23:16:09 +00:00
self . state . transfer_fill = if data . len ( ) > = 2 { read_beu16 ( data ) } else { data [ 0 ] as u16 } ;
2021-10-26 02:31:28 +00:00
self . state . set_dma_mode ( DmaType ::Fill ) ;
} else {
2021-10-28 04:01:18 +00:00
info! ( " {}: data port write {} bytes to {:?}:{:x} with {:?} " , DEV_NAME , data . len ( ) , self . state . transfer_target , self . state . transfer_addr , data ) ;
2021-10-26 02:31:28 +00:00
{
let addr = self . state . transfer_addr as usize ;
let target = self . state . get_transfer_target_mut ( ) ;
for i in 0 .. data . len ( ) {
target [ addr + i ] = data [ i ] ;
}
}
self . state . transfer_addr + = self . state . regs [ REG_AUTO_INCREMENT ] as u32 ;
}
} ,
// Write to Control Port
0x04 | 0x06 = > {
2021-10-28 04:01:18 +00:00
debug! ( " {}: write {} bytes to port {:x} with data {:?} " , DEV_NAME , data . len ( ) , addr , data ) ;
2021-10-26 02:31:28 +00:00
let value = read_beu16 ( data ) ;
if ( value & 0xC000 ) = = 0x8000 {
self . state . set_register ( value ) ;
if data . len ( ) = = 4 {
let value = read_beu16 ( & data [ 2 .. ] ) ;
if ( value & 0xC000 ) ! = 0x8000 {
panic! ( " Unexpected " ) ;
}
self . state . set_register ( value ) ;
}
} else {
match ( data . len ( ) , self . state . transfer_upper ) {
( 2 , None ) = > { self . state . transfer_upper = Some ( value ) } ,
2021-10-28 04:01:18 +00:00
( 2 , Some ( upper ) ) = > self . state . setup_transfer ( upper , read_beu16 ( data ) ) ,
( 4 , None ) = > self . state . setup_transfer ( value , read_beu16 ( & data [ 2 .. ] ) ) ,
2021-10-26 02:31:28 +00:00
_ = > { error! ( " {}: !!! error when writing to control port with {} bytes of {:?} " , DEV_NAME , data . len ( ) , data ) ; } ,
}
}
} ,
_ = > { warning! ( " {}: !!! unhandled write to {:x} with {:?} " , DEV_NAME , addr , data ) ; } ,
}
Ok ( ( ) )
}
}