src/emu/machine/i2cmem.c
| r8457 | r8458 | |
| 1 | | /* |
| 1 | /*************************************************************************** |
| 2 | 2 | |
| 3 | 3 | I2C Memory |
| 4 | 4 | |
| r8457 | r8458 | |
| 18 | 18 | The top five address bits are set at manufacture time, two values are standard. |
| 19 | 19 | Up to 4096 bytes can be addressed. |
| 20 | 20 | |
| 21 | | */ |
| 21 | ***************************************************************************/ |
| 22 | 22 | |
| 23 | 23 | #include "emu.h" |
| 24 | 24 | #include "machine/i2cmem.h" |
| 25 | 25 | |
| 26 | #define STATE_IDLE ( 0 ) |
| 27 | #define STATE_DEVSEL ( 1 ) |
| 28 | #define STATE_BYTEADDR ( 2 ) |
| 29 | #define STATE_DATAIN ( 3 ) |
| 30 | #define STATE_DATAOUT ( 4 ) |
| 31 | |
| 32 | #define DEVSEL_RW ( 1 ) |
| 33 | #define DEVSEL_ADDRESS ( 0xfe ) |
| 34 | |
| 35 | //************************************************************************** |
| 36 | // DEBUGGING |
| 37 | //************************************************************************** |
| 38 | |
| 26 | 39 | #define VERBOSE_LEVEL ( 0 ) |
| 27 | 40 | |
| 28 | | INLINE void ATTR_PRINTF(3,4) verboselog( running_machine *machine, int n_level, const char *s_fmt, ... ) |
| 41 | INLINE void ATTR_PRINTF( 3, 4 ) verboselog( running_device *device, int n_level, const char *s_fmt, ... ) |
| 29 | 42 | { |
| 30 | 43 | if( VERBOSE_LEVEL >= n_level ) |
| 31 | 44 | { |
| r8457 | r8458 | |
| 34 | 47 | va_start( v, s_fmt ); |
| 35 | 48 | vsprintf( buf, s_fmt, v ); |
| 36 | 49 | va_end( v ); |
| 37 | | logerror( "%s: %s", cpuexec_describe_context(machine), buf ); |
| 50 | logerror( "%s: I2CMEM(%s) %s", cpuexec_describe_context( device->machine ), device->tag(), buf ); |
| 38 | 51 | } |
| 39 | 52 | } |
| 40 | 53 | |
| 41 | | struct i2cmem_chip |
| 42 | | { |
| 43 | | int slave_address; |
| 44 | | int scl; |
| 45 | | int sdaw; |
| 46 | | int e0; |
| 47 | | int e1; |
| 48 | | int e2; |
| 49 | | int wc; |
| 50 | | int sdar; |
| 51 | | int state; |
| 52 | | int bits; |
| 53 | | int shift; |
| 54 | | int devsel; |
| 55 | | int byteaddr; |
| 56 | | UINT8 *data; |
| 57 | | int data_size; |
| 58 | | UINT8 *page; |
| 59 | | int page_offset; |
| 60 | | int page_size; |
| 61 | | }; |
| 54 | //************************************************************************** |
| 55 | // GLOBAL VARIABLES |
| 56 | //************************************************************************** |
| 62 | 57 | |
| 63 | | #define STATE_IDLE ( 0 ) |
| 64 | | #define STATE_DEVSEL ( 1 ) |
| 65 | | #define STATE_BYTEADDR ( 2 ) |
| 66 | | #define STATE_DATAIN ( 3 ) |
| 67 | | #define STATE_DATAOUT ( 4 ) |
| 68 | 58 | |
| 69 | | #define DEVSEL_RW ( 1 ) |
| 70 | | #define DEVSEL_ADDRESS ( 0xfe ) |
| 59 | static ADDRESS_MAP_START( i2cmem_map8, ADDRESS_SPACE_PROGRAM, 8 ) |
| 60 | AM_RANGE(0x0000, 0x0fff) AM_RAM |
| 61 | ADDRESS_MAP_END |
| 71 | 62 | |
| 72 | | static struct i2cmem_chip i2cmem[ I2CMEM_MAXCHIP ]; |
| 73 | 63 | |
| 74 | | void i2cmem_init( running_machine *machine, int chip, int slave_address, int page_size, int data_size, UINT8 *data ) |
| 64 | |
| 65 | //************************************************************************** |
| 66 | // DEVICE CONFIGURATION |
| 67 | //************************************************************************** |
| 68 | |
| 69 | //------------------------------------------------- |
| 70 | // i2cmem_device_config - constructor |
| 71 | //------------------------------------------------- |
| 72 | |
| 73 | i2cmem_device_config::i2cmem_device_config( const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock ) : |
| 74 | device_config( mconfig, static_alloc_device_config, "I2CMEM", tag, owner, clock), |
| 75 | device_config_memory_interface(mconfig, *this), |
| 76 | device_config_nvram_interface(mconfig, *this) |
| 75 | 77 | { |
| 76 | | struct i2cmem_chip *c; |
| 77 | | UINT8 *page = NULL; |
| 78 | m_address_bits = 0; |
| 78 | 79 | |
| 79 | | if( chip >= I2CMEM_MAXCHIP ) |
| 80 | int i = m_data_size - 1; |
| 81 | while( i > 0 ) |
| 80 | 82 | { |
| 81 | | verboselog( machine, 0, "i2cmem_init( %d ) invalid chip\n", chip ); |
| 82 | | return; |
| 83 | m_address_bits++; |
| 84 | i >>= 1; |
| 83 | 85 | } |
| 86 | } |
| 84 | 87 | |
| 85 | | c = &i2cmem[ chip ]; |
| 86 | 88 | |
| 87 | | if( data == NULL ) |
| 89 | |
| 90 | //------------------------------------------------- |
| 91 | // static_alloc_device_config - allocate a new |
| 92 | // configuration object |
| 93 | //------------------------------------------------- |
| 94 | |
| 95 | device_config *i2cmem_device_config::static_alloc_device_config( const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock ) |
| 96 | { |
| 97 | return global_alloc( i2cmem_device_config( mconfig, tag, owner, clock ) ); |
| 98 | } |
| 99 | |
| 100 | |
| 101 | |
| 102 | //------------------------------------------------- |
| 103 | // alloc_device - allocate a new device object |
| 104 | //------------------------------------------------- |
| 105 | |
| 106 | device_t *i2cmem_device_config::alloc_device( running_machine &machine ) const |
| 107 | { |
| 108 | return auto_alloc( &machine, i2cmem_device( machine, *this ) ); |
| 109 | } |
| 110 | |
| 111 | |
| 112 | //------------------------------------------------- |
| 113 | // device_config_complete - perform any |
| 114 | // operations now that the configuration is |
| 115 | // complete |
| 116 | //------------------------------------------------- |
| 117 | |
| 118 | void i2cmem_device_config::device_config_complete() |
| 119 | { |
| 120 | // extract inline configuration from raw data |
| 121 | const i2cmem_interface *intf = reinterpret_cast<const i2cmem_interface *>( m_inline_data[ INLINE_INTERFACE ] ); |
| 122 | |
| 123 | // inherit a copy of the static data |
| 124 | if( intf != NULL ) |
| 88 | 125 | { |
| 89 | | data = auto_alloc_array( machine, UINT8, data_size ); |
| 126 | *static_cast<i2cmem_interface *>(this) = *intf; |
| 90 | 127 | } |
| 91 | 128 | |
| 92 | | if( page_size > 0 ) |
| 129 | m_space_config = address_space_config( "ic2mem", ENDIANNESS_BIG, 8, m_address_bits, 0, *ADDRESS_MAP_NAME( i2cmem_map8 ) ); |
| 130 | } |
| 131 | |
| 132 | |
| 133 | //------------------------------------------------- |
| 134 | // device_validity_check - perform validity checks |
| 135 | // on this device |
| 136 | //------------------------------------------------- |
| 137 | |
| 138 | bool i2cmem_device_config::device_validity_check( const game_driver &driver ) const |
| 139 | { |
| 140 | bool error = false; |
| 141 | |
| 142 | if( m_inline_data[ INLINE_INTERFACE ] == 0 ) |
| 93 | 143 | { |
| 94 | | page = auto_alloc_array( machine, UINT8, page_size ); |
| 144 | mame_printf_error( "%s: %s i2cmem device '%s' did not specify an interface\n", driver.source_file, driver.name, tag() ); |
| 145 | error = true; |
| 95 | 146 | } |
| 96 | 147 | |
| 97 | | c->slave_address = slave_address; |
| 98 | | c->data_size = data_size; |
| 99 | | c->page_size = page_size; |
| 148 | return error; |
| 149 | } |
| 100 | 150 | |
| 101 | | c->scl = 0; |
| 102 | | c->sdaw = 0; |
| 103 | | c->e0 = 0; |
| 104 | | c->e1 = 0; |
| 105 | | c->e2 = 0; |
| 106 | | c->wc = 0; |
| 107 | | c->sdar = 1; |
| 108 | | c->state = STATE_IDLE; |
| 109 | | c->bits = 0; |
| 110 | | c->shift = 0; |
| 111 | | c->devsel = 0; |
| 112 | | c->byteaddr = 0; |
| 113 | | c->data = data; |
| 114 | | c->page = page; |
| 115 | 151 | |
| 116 | | state_save_register_item( machine, "i2cmem", NULL, chip, c->scl ); |
| 117 | | state_save_register_item( machine, "i2cmem", NULL, chip, c->sdaw ); |
| 118 | | state_save_register_item( machine, "i2cmem", NULL, chip, c->e0 ); |
| 119 | | state_save_register_item( machine, "i2cmem", NULL, chip, c->e1 ); |
| 120 | | state_save_register_item( machine, "i2cmem", NULL, chip, c->e2 ); |
| 121 | | state_save_register_item( machine, "i2cmem", NULL, chip, c->wc ); |
| 122 | | state_save_register_item( machine, "i2cmem", NULL, chip, c->sdar ); |
| 123 | | state_save_register_item( machine, "i2cmem", NULL, chip, c->state ); |
| 124 | | state_save_register_item( machine, "i2cmem", NULL, chip, c->bits ); |
| 125 | | state_save_register_item( machine, "i2cmem", NULL, chip, c->shift ); |
| 126 | | state_save_register_item( machine, "i2cmem", NULL, chip, c->devsel ); |
| 127 | | state_save_register_item( machine, "i2cmem", NULL, chip, c->byteaddr ); |
| 128 | | state_save_register_item_pointer( machine, "i2cmem", NULL, chip, c->data, c->data_size ); |
| 152 | //------------------------------------------------- |
| 153 | // memory_space_config - return a description of |
| 154 | // any address spaces owned by this device |
| 155 | //------------------------------------------------- |
| 156 | |
| 157 | const address_space_config *i2cmem_device_config::memory_space_config( int spacenum ) const |
| 158 | { |
| 159 | return ( spacenum == 0 ) ? &m_space_config : NULL; |
| 129 | 160 | } |
| 130 | 161 | |
| 131 | | static int select_device( struct i2cmem_chip *c ) |
| 162 | |
| 163 | |
| 164 | //************************************************************************** |
| 165 | // LIVE DEVICE |
| 166 | //************************************************************************** |
| 167 | |
| 168 | //------------------------------------------------- |
| 169 | // i2cmem_device - constructor |
| 170 | //------------------------------------------------- |
| 171 | |
| 172 | i2cmem_device::i2cmem_device( running_machine &_machine, const i2cmem_device_config &config ) : |
| 173 | device_t( _machine, config ), |
| 174 | device_memory_interface( _machine, config, *this ), |
| 175 | device_nvram_interface( _machine, config, *this ), |
| 176 | m_config( config ), |
| 177 | m_scl( 0 ), |
| 178 | m_sdaw( 0 ), |
| 179 | m_e0( 0 ), |
| 180 | m_e1( 0 ), |
| 181 | m_e2( 0 ), |
| 182 | m_wc( 0 ), |
| 183 | m_sdar( 1 ), |
| 184 | m_state( STATE_IDLE ) |
| 132 | 185 | { |
| 133 | | int device = ( c->slave_address & 0xf0 ) | ( c->e2 << 3 ) | ( c->e1 << 2 ) | ( c->e0 << 1 ); |
| 134 | | int mask = DEVSEL_ADDRESS & ~( ( c->data_size - 1 ) >> 7 ); |
| 135 | | |
| 136 | | if( ( c->devsel & mask ) == ( device & mask ) ) |
| 186 | if( m_page_size > 0 ) |
| 137 | 187 | { |
| 138 | | return 1; |
| 188 | m_page = auto_alloc_array( machine, UINT8, m_page_size ); |
| 139 | 189 | } |
| 190 | } |
| 140 | 191 | |
| 141 | | return 0; |
| 192 | |
| 193 | //------------------------------------------------- |
| 194 | // device_start - device-specific startup |
| 195 | //------------------------------------------------- |
| 196 | |
| 197 | void i2cmem_device::device_start() |
| 198 | { |
| 199 | state_save_register_device_item( this, 0, m_scl ); |
| 200 | state_save_register_device_item( this, 0, m_sdaw ); |
| 201 | state_save_register_device_item( this, 0, m_e0 ); |
| 202 | state_save_register_device_item( this, 0, m_e1 ); |
| 203 | state_save_register_device_item( this, 0, m_e2 ); |
| 204 | state_save_register_device_item( this, 0, m_wc ); |
| 205 | state_save_register_device_item( this, 0, m_sdar ); |
| 206 | state_save_register_device_item( this, 0, m_state ); |
| 207 | state_save_register_device_item( this, 0, m_bits ); |
| 208 | state_save_register_device_item( this, 0, m_shift ); |
| 209 | state_save_register_device_item( this, 0, m_devsel ); |
| 210 | state_save_register_device_item( this, 0, m_byteaddr ); |
| 211 | state_save_register_device_item_pointer( this, 0, m_page, m_page_size ); |
| 142 | 212 | } |
| 143 | 213 | |
| 144 | | static int data_offset( struct i2cmem_chip *c ) |
| 214 | |
| 215 | //------------------------------------------------- |
| 216 | // device_reset - device-specific reset |
| 217 | //------------------------------------------------- |
| 218 | |
| 219 | void i2cmem_device::device_reset() |
| 145 | 220 | { |
| 146 | | return ( ( ( c->devsel << 7 ) & 0xff00 ) | ( c->byteaddr & 0xff ) ) & ( c->data_size - 1 ); |
| 147 | 221 | } |
| 148 | 222 | |
| 149 | | void i2cmem_write( running_machine *machine, int chip, int line, int data ) |
| 223 | |
| 224 | //------------------------------------------------- |
| 225 | // nvram_default - called to initialize NVRAM to |
| 226 | // its default state |
| 227 | //------------------------------------------------- |
| 228 | |
| 229 | void i2cmem_device::nvram_default() |
| 150 | 230 | { |
| 151 | | struct i2cmem_chip *c; |
| 231 | int i2cmem_bytes = m_config.m_data_size; |
| 152 | 232 | |
| 153 | | if( chip >= I2CMEM_MAXCHIP ) |
| 233 | UINT16 default_value = 0xff; |
| 234 | for( offs_t offs = 0; offs < i2cmem_bytes; offs++ ) |
| 154 | 235 | { |
| 155 | | verboselog( machine, 0, "i2cmem_write( %d, %d, %d ) invalid chip\n", chip, line, data ); |
| 156 | | return; |
| 236 | memory_write_byte( m_addrspace[ 0 ], offs, default_value ); |
| 157 | 237 | } |
| 158 | 238 | |
| 159 | | c = &i2cmem[ chip ]; |
| 160 | | |
| 161 | | data &= 1; |
| 162 | | |
| 163 | | switch( line ) |
| 239 | /* populate from a memory region if present */ |
| 240 | if( m_region != NULL ) |
| 164 | 241 | { |
| 165 | | case I2CMEM_E0: |
| 166 | | if( c->e0 != data ) |
| 242 | if( m_region->bytes() != i2cmem_bytes ) |
| 167 | 243 | { |
| 168 | | c->e0 = data; |
| 169 | | verboselog( machine, 2, "i2cmem_write( %d, I2CMEM_E0, %d )\n", chip, c->e0 ); |
| 244 | fatalerror( "i2cmem region '%s' wrong size (expected size = 0x%X)", tag(), i2cmem_bytes ); |
| 170 | 245 | } |
| 171 | | break; |
| 172 | 246 | |
| 173 | | case I2CMEM_E1: |
| 174 | | if( c->e1 != data ) |
| 247 | if( m_region->width() != 1 ) |
| 175 | 248 | { |
| 176 | | c->e1 = data; |
| 177 | | verboselog( machine, 2, "i2cmem_write( %d, I2CMEM_E1, %d )\n", chip, c->e1 ); |
| 249 | fatalerror( "i2cmem region '%s' needs to be an 8-bit region", tag() ); |
| 178 | 250 | } |
| 179 | | break; |
| 180 | 251 | |
| 181 | | case I2CMEM_E2: |
| 182 | | if( c->e2 != data ) |
| 252 | for( offs_t offs = 0; offs < i2cmem_bytes; offs++ ) |
| 183 | 253 | { |
| 184 | | c->e2 = data; |
| 185 | | verboselog( machine, 2, "i2cmem_write( %d, I2CMEM_E2, %d )\n", chip, c->e2 ); |
| 254 | memory_write_byte( m_addrspace[ 0 ], offs, m_region->u8( offs ) ); |
| 186 | 255 | } |
| 187 | | break; |
| 256 | } |
| 257 | } |
| 188 | 258 | |
| 189 | | case I2CMEM_SDA: |
| 190 | | if( c->sdaw != data ) |
| 259 | |
| 260 | //------------------------------------------------- |
| 261 | // nvram_read - called to read NVRAM from the |
| 262 | // .nv file |
| 263 | //------------------------------------------------- |
| 264 | |
| 265 | void i2cmem_device::nvram_read( mame_file &file ) |
| 266 | { |
| 267 | int i2cmem_bytes = m_config.m_data_size; |
| 268 | UINT8 *buffer = auto_alloc_array( &m_machine, UINT8, i2cmem_bytes ); |
| 269 | |
| 270 | mame_fread( &file, buffer, i2cmem_bytes ); |
| 271 | |
| 272 | for( offs_t offs = 0; offs < i2cmem_bytes; offs++ ) |
| 273 | { |
| 274 | memory_write_byte( m_addrspace[ 0 ], offs, buffer[ offs ] ); |
| 275 | } |
| 276 | |
| 277 | auto_free( &m_machine, buffer ); |
| 278 | } |
| 279 | |
| 280 | //------------------------------------------------- |
| 281 | // nvram_write - called to write NVRAM to the |
| 282 | // .nv file |
| 283 | //------------------------------------------------- |
| 284 | |
| 285 | void i2cmem_device::nvram_write( mame_file &file ) |
| 286 | { |
| 287 | int i2cmem_bytes = m_config.m_data_size; |
| 288 | UINT8 *buffer = auto_alloc_array( &m_machine, UINT8, i2cmem_bytes ); |
| 289 | |
| 290 | for( offs_t offs = 0; offs < i2cmem_bytes; offs++ ) |
| 291 | { |
| 292 | buffer[ offs ] = memory_read_byte( m_addrspace[ 0 ], offs ); |
| 293 | } |
| 294 | |
| 295 | mame_fwrite( &file, buffer, i2cmem_bytes ); |
| 296 | |
| 297 | auto_free( &m_machine, buffer ); |
| 298 | } |
| 299 | |
| 300 | |
| 301 | |
| 302 | //************************************************************************** |
| 303 | // READ/WRITE HANDLERS |
| 304 | //************************************************************************** |
| 305 | |
| 306 | WRITE_LINE_DEVICE_HANDLER( i2cmem_e0_write ) |
| 307 | { |
| 308 | downcast<i2cmem_device *>( device )->set_e0_line( state ); |
| 309 | } |
| 310 | |
| 311 | void i2cmem_device::set_e0_line( int state ) |
| 312 | { |
| 313 | state &= 1; |
| 314 | if( m_e0 != state ) |
| 315 | { |
| 316 | verboselog( this, 2, "set e0 %d\n", state ); |
| 317 | m_e0 = state; |
| 318 | } |
| 319 | } |
| 320 | |
| 321 | |
| 322 | WRITE_LINE_DEVICE_HANDLER( i2cmem_e1_write ) |
| 323 | { |
| 324 | downcast<i2cmem_device *>( device )->set_e1_line( state ); |
| 325 | } |
| 326 | |
| 327 | void i2cmem_device::set_e1_line( int state ) |
| 328 | { |
| 329 | state &= 1; |
| 330 | if( m_e1 != state ) |
| 331 | { |
| 332 | verboselog( this, 2, "set e1 %d\n", state ); |
| 333 | m_e1 = state; |
| 334 | } |
| 335 | } |
| 336 | |
| 337 | |
| 338 | WRITE_LINE_DEVICE_HANDLER( i2cmem_e2_write ) |
| 339 | { |
| 340 | downcast<i2cmem_device *>( device )->set_e2_line( state ); |
| 341 | } |
| 342 | |
| 343 | void i2cmem_device::set_e2_line( int state ) |
| 344 | { |
| 345 | state &= 1; |
| 346 | if( m_e2 != state ) |
| 347 | { |
| 348 | verboselog( this, 2, "set e2 %d\n", state ); |
| 349 | m_e2 = state; |
| 350 | } |
| 351 | } |
| 352 | |
| 353 | |
| 354 | WRITE_LINE_DEVICE_HANDLER( i2cmem_sda_write ) |
| 355 | { |
| 356 | downcast<i2cmem_device *>( device )->set_sda_line( state ); |
| 357 | } |
| 358 | |
| 359 | void i2cmem_device::set_sda_line( int state ) |
| 360 | { |
| 361 | state &= 1; |
| 362 | if( m_sdaw != state ) |
| 363 | { |
| 364 | verboselog( this, 2, "set sda %d\n", state ); |
| 365 | m_sdaw = state; |
| 366 | |
| 367 | if( m_scl ) |
| 191 | 368 | { |
| 192 | | c->sdaw = data; |
| 193 | | verboselog( machine, 2, "i2cmem_write( %d, I2CMEM_SDA, %d )\n", chip, c->sdaw ); |
| 194 | | |
| 195 | | if( c->scl ) |
| 369 | if( m_sdaw ) |
| 196 | 370 | { |
| 197 | | if( c->sdaw ) |
| 198 | | { |
| 199 | | verboselog( machine, 1, "i2cmem(%d) stop\n", chip ); |
| 200 | | c->state = STATE_IDLE; |
| 201 | | c->byteaddr = 0; |
| 202 | | } |
| 203 | | else |
| 204 | | { |
| 205 | | verboselog( machine, 2, "i2cmem(%d) start\n", chip ); |
| 206 | | c->state = STATE_DEVSEL; |
| 207 | | c->bits = 0; |
| 208 | | } |
| 371 | verboselog( this, 1, "stop\n" ); |
| 372 | m_state = STATE_IDLE; |
| 373 | m_byteaddr = 0; |
| 374 | } |
| 375 | else |
| 376 | { |
| 377 | verboselog( this, 2, "start\n" ); |
| 378 | m_state = STATE_DEVSEL; |
| 379 | m_bits = 0; |
| 380 | } |
| 209 | 381 | |
| 210 | | c->sdar = 1; |
| 211 | | } |
| 382 | m_sdar = 1; |
| 212 | 383 | } |
| 213 | | break; |
| 384 | } |
| 385 | } |
| 214 | 386 | |
| 215 | | case I2CMEM_SCL: |
| 216 | | if( c->scl != data ) |
| 387 | |
| 388 | WRITE_LINE_DEVICE_HANDLER( i2cmem_scl_write ) |
| 389 | { |
| 390 | downcast<i2cmem_device *>( device )->set_scl_line( state ); |
| 391 | } |
| 392 | |
| 393 | void i2cmem_device::set_scl_line( int state ) |
| 394 | { |
| 395 | if( m_scl != state ) |
| 396 | { |
| 397 | m_scl = state; |
| 398 | verboselog( this, 2, "set_scl_line %d\n", m_scl ); |
| 399 | |
| 400 | switch( m_state ) |
| 217 | 401 | { |
| 218 | | c->scl = data; |
| 219 | | verboselog( machine, 2, "i2cmem_write( %d, I2CMEM_SCL, %d )\n", chip, c->scl ); |
| 220 | | |
| 221 | | switch( c->state ) |
| 402 | case STATE_DEVSEL: |
| 403 | case STATE_BYTEADDR: |
| 404 | case STATE_DATAIN: |
| 405 | if( m_bits < 8 ) |
| 222 | 406 | { |
| 223 | | case STATE_DEVSEL: |
| 224 | | case STATE_BYTEADDR: |
| 225 | | case STATE_DATAIN: |
| 226 | | if( c->bits < 8 ) |
| 407 | if( m_scl ) |
| 227 | 408 | { |
| 228 | | if( c->scl ) |
| 229 | | { |
| 230 | | c->shift = ( ( c->shift << 1 ) | c->sdaw ) & 0xff; |
| 231 | | c->bits++; |
| 232 | | } |
| 409 | m_shift = ( ( m_shift << 1 ) | m_sdaw ) & 0xff; |
| 410 | m_bits++; |
| 233 | 411 | } |
| 234 | | else |
| 412 | } |
| 413 | else |
| 414 | { |
| 415 | if( m_scl ) |
| 235 | 416 | { |
| 236 | | if( c->scl ) |
| 417 | switch( m_state ) |
| 237 | 418 | { |
| 238 | | switch( c->state ) |
| 419 | case STATE_DEVSEL: |
| 420 | m_devsel = m_shift; |
| 421 | |
| 422 | if( !select_device() ) |
| 239 | 423 | { |
| 240 | | case STATE_DEVSEL: |
| 241 | | c->devsel = c->shift; |
| 424 | verboselog( this, 1, "devsel %02x: not this device\n", m_devsel ); |
| 425 | m_state = STATE_IDLE; |
| 426 | } |
| 427 | else if( ( m_devsel & DEVSEL_RW ) == 0 ) |
| 428 | { |
| 429 | verboselog( this, 1, "devsel %02x: write\n", m_devsel ); |
| 430 | m_state = STATE_BYTEADDR; |
| 431 | } |
| 432 | else |
| 433 | { |
| 434 | verboselog( this, 1, "devsel %02x: read\n", m_devsel ); |
| 435 | m_state = STATE_DATAOUT; |
| 436 | } |
| 437 | break; |
| 242 | 438 | |
| 243 | | if( !select_device( c ) ) |
| 244 | | { |
| 245 | | verboselog( machine, 1, "i2cmem(%d) devsel %02x: not this device\n", chip, c->devsel ); |
| 246 | | c->state = STATE_IDLE; |
| 247 | | } |
| 248 | | else if( ( c->devsel & DEVSEL_RW ) == 0 ) |
| 249 | | { |
| 250 | | verboselog( machine, 1, "i2cmem(%d) devsel %02x: write\n", chip, c->devsel ); |
| 251 | | c->state = STATE_BYTEADDR; |
| 252 | | } |
| 253 | | else |
| 254 | | { |
| 255 | | verboselog( machine, 1, "i2cmem(%d) devsel %02x: read\n", chip, c->devsel ); |
| 256 | | c->state = STATE_DATAOUT; |
| 257 | | } |
| 258 | | break; |
| 439 | case STATE_BYTEADDR: |
| 440 | m_byteaddr = m_shift; |
| 441 | m_page_offset = 0; |
| 259 | 442 | |
| 260 | | case STATE_BYTEADDR: |
| 261 | | c->byteaddr = c->shift; |
| 262 | | c->page_offset = 0; |
| 443 | verboselog( this, 1, "byteaddr %02x\n", m_byteaddr ); |
| 263 | 444 | |
| 264 | | verboselog( machine, 1, "i2cmem(%d) byteaddr %02x\n", chip, c->byteaddr ); |
| 445 | m_state = STATE_DATAIN; |
| 446 | break; |
| 265 | 447 | |
| 266 | | c->state = STATE_DATAIN; |
| 267 | | break; |
| 448 | case STATE_DATAIN: |
| 449 | if( m_wc ) |
| 450 | { |
| 451 | verboselog( this, 0, "write not enabled\n" ); |
| 452 | m_state = STATE_IDLE; |
| 453 | } |
| 454 | else if( m_page_size > 0 ) |
| 455 | { |
| 456 | m_page[ m_page_offset ] = m_shift; |
| 457 | verboselog( this, 1, "page[ %04x ] <- %02x\n", m_page_offset, m_page[ m_page_offset ] ); |
| 268 | 458 | |
| 269 | | case STATE_DATAIN: |
| 270 | | if( c->wc ) |
| 459 | m_page_offset++; |
| 460 | if( m_page_offset == m_page_size ) |
| 271 | 461 | { |
| 272 | | verboselog( machine, 0, "i2cmem(%d) write not enabled\n", chip ); |
| 273 | | c->state = STATE_IDLE; |
| 274 | | } |
| 275 | | else if( c->page_size > 0 ) |
| 276 | | { |
| 277 | | c->page[ c->page_offset ] = c->shift; |
| 278 | | verboselog( machine, 1, "i2cmem(%d) page[ %04x ] <- %02x\n", chip, c->page_offset, c->page[ c->page_offset ] ); |
| 462 | int offset = data_offset() & ~( m_page_size - 1 ); |
| 279 | 463 | |
| 280 | | c->page_offset++; |
| 281 | | if( c->page_offset == c->page_size ) |
| 464 | verboselog( this, 1, "data[ %04x to %04x ] = page\n", offset, offset + m_page_size - 1 ); |
| 465 | |
| 466 | for( int i = 0; i < m_page_size; i++ ) |
| 282 | 467 | { |
| 283 | | int offset = data_offset( c ) & ~( c->page_size - 1 ); |
| 468 | memory_write_byte( m_addrspace[ 0 ], offset + i, m_page[ i ] ); |
| 469 | } |
| 284 | 470 | |
| 285 | | memcpy( &c->data[ offset ], c->page, c->page_size ); |
| 286 | | verboselog( machine, 1, "i2cmem(%d) data[ %04x to %04x ] = page\n", chip, offset, offset + c->page_size - 1 ); |
| 287 | | |
| 288 | | c->page_offset = 0; |
| 289 | | } |
| 471 | m_page_offset = 0; |
| 290 | 472 | } |
| 291 | | else |
| 292 | | { |
| 293 | | int offset = data_offset( c ); |
| 473 | } |
| 474 | else |
| 475 | { |
| 476 | int offset = data_offset(); |
| 294 | 477 | |
| 295 | | c->data[ offset ] = c->shift; |
| 296 | | verboselog( machine, 1, "i2cmem(%d) data[ %04x ] <- %02x\n", chip, offset, c->data[ offset ] ); |
| 478 | verboselog( this, 1, "data[ %04x ] <- %02x\n", offset, m_shift ); |
| 479 | memory_write_byte( m_addrspace[ 0 ], offset, m_shift ); |
| 297 | 480 | |
| 298 | | c->byteaddr++; |
| 299 | | } |
| 300 | | break; |
| 481 | m_byteaddr++; |
| 301 | 482 | } |
| 483 | break; |
| 484 | } |
| 302 | 485 | |
| 303 | | c->bits++; |
| 486 | m_bits++; |
| 487 | } |
| 488 | else |
| 489 | { |
| 490 | if( m_bits == 8 ) |
| 491 | { |
| 492 | m_sdar = 0; |
| 304 | 493 | } |
| 305 | 494 | else |
| 306 | 495 | { |
| 307 | | if( c->bits == 8 ) |
| 308 | | { |
| 309 | | c->sdar = 0; |
| 310 | | } |
| 311 | | else |
| 312 | | { |
| 313 | | c->bits = 0; |
| 314 | | c->sdar = 1; |
| 315 | | } |
| 496 | m_bits = 0; |
| 497 | m_sdar = 1; |
| 316 | 498 | } |
| 317 | 499 | } |
| 318 | | break; |
| 500 | } |
| 501 | break; |
| 319 | 502 | |
| 320 | | case STATE_DATAOUT: |
| 321 | | if( c->bits < 8 ) |
| 503 | case STATE_DATAOUT: |
| 504 | if( m_bits < 8 ) |
| 505 | { |
| 506 | if( m_scl ) |
| 322 | 507 | { |
| 323 | | if( c->scl ) |
| 508 | if( m_bits == 0 ) |
| 324 | 509 | { |
| 325 | | if( c->bits == 0 ) |
| 326 | | { |
| 327 | | int offset = data_offset( c ); |
| 510 | int offset = data_offset(); |
| 328 | 511 | |
| 329 | | c->shift = c->data[ offset ]; |
| 330 | | verboselog( machine, 1, "i2cmem(%d) data[ %04x ] -> %02x\n", chip, offset, c->data[ offset ] ); |
| 331 | | c->byteaddr++; |
| 332 | | } |
| 512 | m_shift = memory_read_byte( m_addrspace[ 0 ], offset ); |
| 513 | verboselog( this, 1, "data[ %04x ] -> %02x\n", offset, m_shift ); |
| 514 | m_byteaddr++; |
| 515 | } |
| 333 | 516 | |
| 334 | | c->sdar = ( c->shift >> 7 ) & 1; |
| 517 | m_sdar = ( m_shift >> 7 ) & 1; |
| 335 | 518 | |
| 336 | | c->shift = ( c->shift << 1 ) & 0xff; |
| 337 | | c->bits++; |
| 519 | m_shift = ( m_shift << 1 ) & 0xff; |
| 520 | m_bits++; |
| 521 | } |
| 522 | } |
| 523 | else |
| 524 | { |
| 525 | if( m_scl ) |
| 526 | { |
| 527 | if( m_sdaw ) |
| 528 | { |
| 529 | verboselog( this, 1, "sleep\n" ); |
| 530 | m_state = STATE_IDLE; |
| 531 | m_sdar = 0; |
| 338 | 532 | } |
| 533 | |
| 534 | m_bits++; |
| 339 | 535 | } |
| 340 | 536 | else |
| 341 | 537 | { |
| 342 | | if( c->scl ) |
| 538 | if( m_bits == 8 ) |
| 343 | 539 | { |
| 344 | | if( c->sdaw ) |
| 345 | | { |
| 346 | | verboselog( machine, 1, "i2cmem(%d) sleep\n", chip ); |
| 347 | | c->state = STATE_IDLE; |
| 348 | | } |
| 349 | | |
| 350 | | c->bits++; |
| 540 | m_sdar = 1; |
| 351 | 541 | } |
| 352 | 542 | else |
| 353 | 543 | { |
| 354 | | if( c->bits == 8 ) |
| 355 | | { |
| 356 | | c->sdar = 1; |
| 357 | | } |
| 358 | | else |
| 359 | | { |
| 360 | | c->bits = 0; |
| 361 | | } |
| 544 | m_bits = 0; |
| 362 | 545 | } |
| 363 | 546 | } |
| 364 | | break; |
| 365 | 547 | } |
| 548 | break; |
| 366 | 549 | } |
| 367 | | break; |
| 550 | } |
| 551 | } |
| 368 | 552 | |
| 369 | | case I2CMEM_WC: |
| 370 | | if( c->wc != data ) |
| 371 | | { |
| 372 | | c->wc = data; |
| 373 | | verboselog( machine, 2, "i2cmem_write( %d, I2CMEM_WC, %d )\n", chip, c->wc ); |
| 374 | | } |
| 375 | | break; |
| 376 | 553 | |
| 377 | | default: |
| 378 | | verboselog( machine, 0, "i2cmem_write( %d, %d, %d ) invalid line\n", chip, line, data ); |
| 379 | | break; |
| 380 | | } |
| 554 | WRITE_LINE_DEVICE_HANDLER( i2cmem_wc_write ) |
| 555 | { |
| 556 | downcast<i2cmem_device *>( device )->set_wc_line( state ); |
| 381 | 557 | } |
| 382 | 558 | |
| 383 | | int i2cmem_read( running_machine *machine, int chip, int line ) |
| 559 | void i2cmem_device::set_wc_line( int state ) |
| 384 | 560 | { |
| 385 | | struct i2cmem_chip *c; |
| 386 | | |
| 387 | | if( chip >= I2CMEM_MAXCHIP ) |
| 561 | state &= 1; |
| 562 | if( m_wc != state ) |
| 388 | 563 | { |
| 389 | | verboselog( machine, 0, "i2cmem_read( %d, %d ) invalid chip\n", chip, line ); |
| 390 | | return 0; |
| 564 | verboselog( this, 2, "set wc %d\n", state ); |
| 565 | m_wc = state; |
| 391 | 566 | } |
| 567 | } |
| 392 | 568 | |
| 393 | | c = &i2cmem[ chip ]; |
| 394 | 569 | |
| 395 | | switch( line ) |
| 396 | | { |
| 397 | | case I2CMEM_SDA: |
| 398 | | verboselog( machine, 2, "i2cmem_read( %d, I2CMEM_SDA ) %d\n", chip, c->sdar & c->sdaw ); |
| 399 | | return c->sdar & c->sdaw; |
| 570 | READ_LINE_DEVICE_HANDLER( i2cmem_sda_read ) |
| 571 | { |
| 572 | return downcast<i2cmem_device *>( device )->read_sda_line(); |
| 573 | } |
| 400 | 574 | |
| 401 | | default: |
| 402 | | verboselog( machine, 0, "i2cmem_read( %d, %d ) invalid line\n", chip, line ); |
| 403 | | break; |
| 404 | | } |
| 575 | int i2cmem_device::read_sda_line() |
| 576 | { |
| 577 | int res = m_sdar & m_sdaw & 1; |
| 405 | 578 | |
| 406 | | return 0; |
| 579 | verboselog( this, 2, "read sda %d\n", res ); |
| 580 | |
| 581 | return res; |
| 407 | 582 | } |
| 408 | 583 | |
| 409 | | static void nvram_handler_i2cmem( running_machine *machine, mame_file *file, int read_or_write, int chip ) |
| 584 | |
| 585 | //************************************************************************** |
| 586 | // INTERNAL HELPERS |
| 587 | //************************************************************************** |
| 588 | |
| 589 | int i2cmem_device::address_mask() |
| 410 | 590 | { |
| 411 | | struct i2cmem_chip *c; |
| 591 | return ( 1 << m_config.m_address_bits ) - 1; |
| 592 | } |
| 412 | 593 | |
| 413 | | if( chip >= I2CMEM_MAXCHIP ) |
| 594 | int i2cmem_device::select_device() |
| 595 | { |
| 596 | int device = ( m_config.m_slave_address & 0xf0 ) | ( m_e2 << 3 ) | ( m_e1 << 2 ) | ( m_e0 << 1 ); |
| 597 | int mask = DEVSEL_ADDRESS & ~( address_mask() >> 7 ); |
| 598 | |
| 599 | if( ( m_devsel & mask ) == ( device & mask ) ) |
| 414 | 600 | { |
| 415 | | verboselog( machine, 0, "nvram_handler_i2cmem( %d ) invalid chip\n", chip ); |
| 416 | | return; |
| 601 | return 1; |
| 417 | 602 | } |
| 418 | 603 | |
| 419 | | c = &i2cmem[ chip ]; |
| 604 | return 0; |
| 605 | } |
| 420 | 606 | |
| 421 | | if( read_or_write ) |
| 422 | | { |
| 423 | | mame_fwrite( file, c->data, c->data_size ); |
| 424 | | } |
| 425 | | else if( file ) |
| 426 | | { |
| 427 | | mame_fread( file, c->data, c->data_size ); |
| 428 | | } |
| 607 | int i2cmem_device::data_offset() |
| 608 | { |
| 609 | return ( ( ( m_devsel << 7 ) & 0xff00 ) | ( m_byteaddr & 0xff ) ) & address_mask(); |
| 429 | 610 | } |
| 430 | 611 | |
| 431 | | NVRAM_HANDLER( i2cmem_0 ) { nvram_handler_i2cmem( machine, file, read_or_write, 0 ); } |
| 612 | const device_type I2CMEM = i2cmem_device_config::static_alloc_device_config; |
src/mess/machine/pokemini.c
| r8457 | r8458 | |
| 418 | 418 | } |
| 419 | 419 | |
| 420 | 420 | |
| 421 | | WRITE8_HANDLER( pokemini_hwreg_w ) |
| 421 | WRITE8_DEVICE_HANDLER( pokemini_hwreg_w ) |
| 422 | 422 | { |
| 423 | 423 | static const int timer_to_cycles_fast[8] = { 2, 8, 32, 64, 128, 256, 1024, 4096 }; |
| 424 | 424 | static const int timer_to_cycles_slow[8] = { 128, 256, 512, 1024, 2048, 4096, 8192, 16384 }; |
| r8457 | r8458 | |
| 437 | 437 | case 0x02: /* CPU related? |
| 438 | 438 | Bit 0-7 R/W Unknown |
| 439 | 439 | */ |
| 440 | | logerror( "%0X: Write to unknown hardware address: %02X, %02X\n", cpu_get_pc( space->cpu ), offset, data ); |
| 440 | logerror( "%0X: Write to unknown hardware address: %02X, %02X\n", cpu_get_pc( device->machine->firstcpu ), offset, data ); |
| 441 | 441 | break; |
| 442 | 442 | case 0x08: /* Seconds-timer control |
| 443 | 443 | Bit 0 R/W Timer enable |
| r8457 | r8458 | |
| 469 | 469 | Bit 5 R Battery status: 0 - battery OK, 1 - battery low |
| 470 | 470 | Bit 6-7 Unused |
| 471 | 471 | */ |
| 472 | | logerror( "%0X: Write to unknown hardware address: %02X, %02X\n", cpu_get_pc( space->cpu ), offset, data ); |
| 472 | logerror( "%0X: Write to unknown hardware address: %02X, %02X\n", cpu_get_pc( device->machine->firstcpu ), offset, data ); |
| 473 | 473 | break; |
| 474 | 474 | case 0x18: /* Timer 1 pre-scale + enable |
| 475 | 475 | Bit 0-2 R/W low timer 1 prescaler select |
| r8457 | r8458 | |
| 491 | 491 | int index = data & 0x07; |
| 492 | 492 | int cycles = ( pm_reg[0x19] & 0x01 ) ? timer_to_cycles_slow[index] : timer_to_cycles_fast[index]; |
| 493 | 493 | |
| 494 | | timer_adjust_periodic(timers.timer1, attotime_zero, 0, cputag_clocks_to_attotime(space->machine, "maincpu", cycles)); |
| 494 | timer_adjust_periodic(timers.timer1, attotime_zero, 0, cputag_clocks_to_attotime(device->machine, "maincpu", cycles)); |
| 495 | 495 | } |
| 496 | 496 | |
| 497 | 497 | /* Check for prescaler change for the high counter */ |
| r8457 | r8458 | |
| 500 | 500 | int index = ( data >> 4 ) & 0x07; |
| 501 | 501 | int cycles = ( pm_reg[0x19] & 0x02 ) ? timer_to_cycles_slow[index] : timer_to_cycles_fast[index]; |
| 502 | 502 | |
| 503 | | timer_adjust_periodic(timers.timer1_hi, attotime_zero, 0, cputag_clocks_to_attotime(space->machine, "maincpu", cycles)); |
| 503 | timer_adjust_periodic(timers.timer1_hi, attotime_zero, 0, cputag_clocks_to_attotime(device->machine, "maincpu", cycles)); |
| 504 | 504 | } |
| 505 | 505 | |
| 506 | 506 | /* Check if timer1 low should be enabled */ |
| r8457 | r8458 | |
| 541 | 541 | int index = pm_reg[0x18] & 0x07; |
| 542 | 542 | int cycles = ( data & 0x01 ) ? timer_to_cycles_slow[index] : timer_to_cycles_fast[index]; |
| 543 | 543 | |
| 544 | | timer_adjust_periodic(timers.timer1, attotime_zero, 0, cputag_clocks_to_attotime(space->machine, "maincpu", cycles)); |
| 544 | timer_adjust_periodic(timers.timer1, attotime_zero, 0, cputag_clocks_to_attotime(device->machine, "maincpu", cycles)); |
| 545 | 545 | } |
| 546 | 546 | |
| 547 | 547 | /* Check for prescaler change for the low counter */ |
| r8457 | r8458 | |
| 550 | 550 | int index = ( pm_reg[0x18] >> 4 ) & 0x07; |
| 551 | 551 | int cycles = ( data & 0x02 ) ? timer_to_cycles_slow[index] : timer_to_cycles_fast[index]; |
| 552 | 552 | |
| 553 | | timer_adjust_periodic(timers.timer1_hi, attotime_zero, 0, cputag_clocks_to_attotime(space->machine, "maincpu", cycles)); |
| 553 | timer_adjust_periodic(timers.timer1_hi, attotime_zero, 0, cputag_clocks_to_attotime(device->machine, "maincpu", cycles)); |
| 554 | 554 | } |
| 555 | 555 | |
| 556 | 556 | { |
| r8457 | r8458 | |
| 620 | 620 | int index = data & 0x07; |
| 621 | 621 | int cycles = ( pm_reg[0x1B] & 0x01 ) ? timer_to_cycles_slow[index] : timer_to_cycles_fast[index]; |
| 622 | 622 | |
| 623 | | timer_adjust_periodic(timers.timer2, attotime_zero, 0, cputag_clocks_to_attotime(space->machine, "maincpu", cycles)); |
| 623 | timer_adjust_periodic(timers.timer2, attotime_zero, 0, cputag_clocks_to_attotime(device->machine, "maincpu", cycles)); |
| 624 | 624 | } |
| 625 | 625 | |
| 626 | 626 | /* Check for prescaler change for the high counter */ |
| r8457 | r8458 | |
| 629 | 629 | int index = ( data >> 4 ) & 0x07; |
| 630 | 630 | int cycles = ( pm_reg[0x1B] & 0x02 ) ? timer_to_cycles_slow[index] : timer_to_cycles_fast[index]; |
| 631 | 631 | |
| 632 | | timer_adjust_periodic(timers.timer2_hi, attotime_zero, 0, cputag_clocks_to_attotime(space->machine, "maincpu", cycles)); |
| 632 | timer_adjust_periodic(timers.timer2_hi, attotime_zero, 0, cputag_clocks_to_attotime(device->machine, "maincpu", cycles)); |
| 633 | 633 | } |
| 634 | 634 | |
| 635 | 635 | /* Check if timer2 low should be enabled */ |
| r8457 | r8458 | |
| 666 | 666 | int index = pm_reg[0x1A] & 0x07; |
| 667 | 667 | int cycles = ( data & 0x01 ) ? timer_to_cycles_slow[index] : timer_to_cycles_fast[index]; |
| 668 | 668 | |
| 669 | | timer_adjust_periodic(timers.timer2, attotime_zero, 0, cputag_clocks_to_attotime(space->machine, "maincpu", cycles)); |
| 669 | timer_adjust_periodic(timers.timer2, attotime_zero, 0, cputag_clocks_to_attotime(device->machine, "maincpu", cycles)); |
| 670 | 670 | |
| 671 | 671 | if ( ( pm_reg[0x1A] & 0x08 ) && ( pm_reg[0x38] & 0x04 ) && |
| 672 | 672 | ( ( ( pm_reg[0x19] & 0x10 ) && ( data & 0x01 ) ) || |
| r8457 | r8458 | |
| 686 | 686 | int index = ( pm_reg[0x1A] >> 4 ) & 0x07; |
| 687 | 687 | int cycles = ( data & 0x02 ) ? timer_to_cycles_slow[index] : timer_to_cycles_fast[index]; |
| 688 | 688 | |
| 689 | | timer_adjust_periodic(timers.timer2_hi, attotime_zero, 0, cputag_clocks_to_attotime(space->machine, "maincpu", cycles)); |
| 689 | timer_adjust_periodic(timers.timer2_hi, attotime_zero, 0, cputag_clocks_to_attotime(device->machine, "maincpu", cycles)); |
| 690 | 690 | |
| 691 | 691 | if ( ( pm_reg[0x1A] & 0x80 ) && ( pm_reg[0x39] & 0x04 ) && ! ( pm_reg[0x38] & 0x80 ) && |
| 692 | 692 | ( ( ( pm_reg[0x19] & 0x10 ) && ( data & 0x02 ) ) || |
| r8457 | r8458 | |
| 720 | 720 | int index = data & 0x07; |
| 721 | 721 | int cycles = ( pm_reg[0x1D] & 0x01 ) ? timer_to_cycles_slow[index] : timer_to_cycles_fast[index]; |
| 722 | 722 | |
| 723 | | timer_adjust_periodic(timers.timer3, attotime_zero, 0, cputag_clocks_to_attotime(space->machine, "maincpu", cycles)); |
| 723 | timer_adjust_periodic(timers.timer3, attotime_zero, 0, cputag_clocks_to_attotime(device->machine, "maincpu", cycles)); |
| 724 | 724 | } |
| 725 | 725 | |
| 726 | 726 | /* Check for prescaler change for the high counter */ |
| r8457 | r8458 | |
| 729 | 729 | int index = ( data >> 4 ) & 0x07; |
| 730 | 730 | int cycles = ( pm_reg[0x1D] & 0x02 ) ? timer_to_cycles_slow[index] : timer_to_cycles_fast[index]; |
| 731 | 731 | |
| 732 | | timer_adjust_periodic(timers.timer3_hi, attotime_zero, 0, cputag_clocks_to_attotime(space->machine, "maincpu", cycles)); |
| 732 | timer_adjust_periodic(timers.timer3_hi, attotime_zero, 0, cputag_clocks_to_attotime(device->machine, "maincpu", cycles)); |
| 733 | 733 | } |
| 734 | 734 | |
| 735 | 735 | /* Check if timer2 low should be enabled */ |
| r8457 | r8458 | |
| 766 | 766 | int index = pm_reg[0x1C] & 0x07; |
| 767 | 767 | int cycles = ( data & 0x01 ) ? timer_to_cycles_slow[index] : timer_to_cycles_fast[index]; |
| 768 | 768 | |
| 769 | | timer_adjust_periodic(timers.timer3, attotime_zero, 0, cputag_clocks_to_attotime(space->machine, "maincpu", cycles)); |
| 769 | timer_adjust_periodic(timers.timer3, attotime_zero, 0, cputag_clocks_to_attotime(device->machine, "maincpu", cycles)); |
| 770 | 770 | |
| 771 | 771 | if ( ( pm_reg[0x1C] & 0x08 ) && ( pm_reg[0x48] & 0x04 ) && |
| 772 | 772 | ( ( ( pm_reg[0x19] & 0x10 ) && ( data & 0x01 ) ) || |
| r8457 | r8458 | |
| 786 | 786 | int index = ( pm_reg[0x1C] >> 4 ) & 0x07; |
| 787 | 787 | int cycles = ( data & 0x02 ) ? timer_to_cycles_slow[index] : timer_to_cycles_fast[index]; |
| 788 | 788 | |
| 789 | | timer_adjust_periodic(timers.timer3_hi, attotime_zero, 0, cputag_clocks_to_attotime(space->machine, "maincpu", cycles)); |
| 789 | timer_adjust_periodic(timers.timer3_hi, attotime_zero, 0, cputag_clocks_to_attotime(device->machine, "maincpu", cycles)); |
| 790 | 790 | |
| 791 | 791 | if ( ( pm_reg[0x1C] & 0x80 ) && ( pm_reg[0x49] & 0x04 ) && ! ( pm_reg[0x48] & 0x80 ) && |
| 792 | 792 | ( ( ( pm_reg[0x19] & 0x10 ) && ( data & 0x02 ) ) || |
| r8457 | r8458 | |
| 807 | 807 | Bit 6-7 R/W VDraw/VBlank trigger Interrupt #1-#2 |
| 808 | 808 | */ |
| 809 | 809 | pm_reg[0x20] = data; |
| 810 | | pokemini_check_irqs( space->machine ); |
| 810 | pokemini_check_irqs( device->machine ); |
| 811 | 811 | break; |
| 812 | 812 | case 0x21: /* Event #15-#22 priority |
| 813 | 813 | Bit 0-1 R/W Unknown |
| r8457 | r8458 | |
| 815 | 815 | Bit 4-7 R/W Unknown |
| 816 | 816 | */ |
| 817 | 817 | pm_reg[0x21] = data; |
| 818 | | pokemini_check_irqs( space->machine ); |
| 818 | pokemini_check_irqs( device->machine ); |
| 819 | 819 | break; |
| 820 | 820 | case 0x22: /* Event #9-#14 priority |
| 821 | 821 | Bit 0-1 R/W All #9 - #14 events - Interrupt #9-#14 |
| 822 | 822 | Bit 2-7 Unused |
| 823 | 823 | */ |
| 824 | 824 | pm_reg[0x22] = data; |
| 825 | | pokemini_check_irqs( space->machine ); |
| 825 | pokemini_check_irqs( device->machine ); |
| 826 | 826 | break; |
| 827 | 827 | case 0x23: /* Event #1-#8 enable |
| 828 | 828 | Bit 0 R/W Timer 3 overflow (mirror) - Enable Interrupt #8 |
| r8457 | r8458 | |
| 835 | 835 | Bit 7 R/W V-Blank trigger - Enable Interrupt #1 |
| 836 | 836 | */ |
| 837 | 837 | pm_reg[0x23] = data; |
| 838 | | pokemini_check_irqs( space->machine ); |
| 838 | pokemini_check_irqs( device->machine ); |
| 839 | 839 | break; |
| 840 | 840 | case 0x24: /* Event #9-#12 enable |
| 841 | 841 | Bit 0-5 R/W Unknown |
| 842 | 842 | Bit 6-7 Unused |
| 843 | 843 | */ |
| 844 | 844 | pm_reg[0x24] = data; |
| 845 | | pokemini_check_irqs( space->machine ); |
| 845 | pokemini_check_irqs( device->machine ); |
| 846 | 846 | break; |
| 847 | 847 | case 0x25: /* Event #15-#22 enable |
| 848 | 848 | Bit 0 R/W Press key "A" event - Enable interrupt #22 |
| r8457 | r8458 | |
| 855 | 855 | Bit 7 R/W Press power button event - Enable interrupt #15 |
| 856 | 856 | */ |
| 857 | 857 | pm_reg[0x25] = data; |
| 858 | | pokemini_check_irqs( space->machine ); |
| 858 | pokemini_check_irqs( device->machine ); |
| 859 | 859 | break; |
| 860 | 860 | case 0x26: /* Event #13-#14 enable |
| 861 | 861 | Bit 0-2 R/W Unknown |
| r8457 | r8458 | |
| 865 | 865 | Bit 7 R/W IR receiver - low to high trigger - Enable interrupt #13 |
| 866 | 866 | */ |
| 867 | 867 | pm_reg[0x26] = data; |
| 868 | | pokemini_check_irqs( space->machine ); |
| 868 | pokemini_check_irqs( device->machine ); |
| 869 | 869 | break; |
| 870 | 870 | case 0x27: /* Interrupt active flag #1-#8 |
| 871 | 871 | Bit 0 Timer 3 overflow (mirror) / Clear interrupt #8 |
| r8457 | r8458 | |
| 878 | 878 | Bit 7 VBlank trigger / Clear interrupt #1 |
| 879 | 879 | */ |
| 880 | 880 | pm_reg[0x27] &= ~data; |
| 881 | | pokemini_check_irqs( space->machine ); |
| 881 | pokemini_check_irqs( device->machine ); |
| 882 | 882 | return; |
| 883 | 883 | case 0x28: /* Interrupt active flag #9-#12 |
| 884 | 884 | Bit 0-1 Unknown |
| r8457 | r8458 | |
| 889 | 889 | Bit 6-7 Unknown |
| 890 | 890 | */ |
| 891 | 891 | pm_reg[0x28] &= ~data; |
| 892 | | pokemini_check_irqs( space->machine ); |
| 892 | pokemini_check_irqs( device->machine ); |
| 893 | 893 | return; |
| 894 | 894 | case 0x29: /* Interrupt active flag #15-#22 |
| 895 | 895 | Bit 0 Press key "A" event / Clear interrupt #22 |
| r8457 | r8458 | |
| 902 | 902 | Bit 7 Press power button event / Clear interrupt #15 |
| 903 | 903 | */ |
| 904 | 904 | pm_reg[0x29] &= ~data; |
| 905 | | pokemini_check_irqs( space->machine ); |
| 905 | pokemini_check_irqs( device->machine ); |
| 906 | 906 | return; |
| 907 | 907 | case 0x2A: /* Interrupt active flag #13-#14 |
| 908 | 908 | Bit 0-5 Unknown |
| r8457 | r8458 | |
| 910 | 910 | Bit 7 Unknown / Clear interrupt #13 |
| 911 | 911 | */ |
| 912 | 912 | pm_reg[0x2A] &= ~data; |
| 913 | | pokemini_check_irqs( space->machine ); |
| 913 | pokemini_check_irqs( device->machine ); |
| 914 | 914 | return; |
| 915 | 915 | case 0x30: /* Timer 1 control 1 |
| 916 | 916 | Bit 0 R/W Unknown |
| r8457 | r8458 | |
| 984 | 984 | */ |
| 985 | 985 | case 0x35: /* Timer 1 sound-pivot (high, unused) |
| 986 | 986 | */ |
| 987 | | logerror( "%0X: Write to unknown hardware address: %02X, %02X\n", cpu_get_pc( space->cpu ), offset, data ); |
| 987 | logerror( "%0X: Write to unknown hardware address: %02X, %02X\n", cpu_get_pc( device->machine->firstcpu ), offset, data ); |
| 988 | 988 | break; |
| 989 | 989 | case 0x36: /* Timer 1 counter (low), read only |
| 990 | 990 | */ |
| r8457 | r8458 | |
| 1063 | 1063 | */ |
| 1064 | 1064 | case 0x3D: /* Timer 2 sound-pivot (high, unused) |
| 1065 | 1065 | */ |
| 1066 | | logerror( "%0X: Write to unknown hardware address: %02X, %02X\n", cpu_get_pc( space->cpu ), offset, data ); |
| 1066 | logerror( "%0X: Write to unknown hardware address: %02X, %02X\n", cpu_get_pc( device->machine->firstcpu ), offset, data ); |
| 1067 | 1067 | break; |
| 1068 | 1068 | case 0x3E: /* Timer 2 counter (low), read only |
| 1069 | 1069 | Bit 0-7 R/W Timer 2 counter value bit 0-7 |
| r8457 | r8458 | |
| 1123 | 1123 | timer_enable( timers.timer3_hi, 0 ); |
| 1124 | 1124 | } |
| 1125 | 1125 | pm_reg[0x48] = data; |
| 1126 | | pokemini_update_sound( space->machine ); |
| 1126 | pokemini_update_sound( device->machine ); |
| 1127 | 1127 | break; |
| 1128 | 1128 | case 0x49: /* Timer 3 control 2 |
| 1129 | 1129 | Bit 0 R/W Unknown |
| r8457 | r8458 | |
| 1149 | 1149 | timer_enable( timers.timer3_hi, 0 ); |
| 1150 | 1150 | } |
| 1151 | 1151 | pm_reg[0x49] = data; |
| 1152 | | pokemini_update_sound( space->machine ); |
| 1152 | pokemini_update_sound( device->machine ); |
| 1153 | 1153 | break; |
| 1154 | 1154 | case 0x4A: /* Timer 3 preset value (low) |
| 1155 | 1155 | Bit 0-7 R/W Timer 3 preset value bit 0-7 |
| 1156 | 1156 | */ |
| 1157 | 1157 | pm_reg[0x4A] = data; |
| 1158 | | pokemini_update_sound( space->machine ); |
| 1158 | pokemini_update_sound( device->machine ); |
| 1159 | 1159 | break; |
| 1160 | 1160 | case 0x4B: /* Timer 3 preset value (high) |
| 1161 | 1161 | Bit 0-7 R/W Timer 3 preset value bit 8-15 |
| 1162 | 1162 | */ |
| 1163 | 1163 | pm_reg[0x4B] = data; |
| 1164 | | pokemini_update_sound( space->machine ); |
| 1164 | pokemini_update_sound( device->machine ); |
| 1165 | 1165 | break; |
| 1166 | 1166 | case 0x4C: /* Timer 3 sound-pivot (low) |
| 1167 | 1167 | Bit 0-7 R/W Timer 3 sound-pivot value bit 0-7 |
| 1168 | 1168 | */ |
| 1169 | 1169 | pm_reg[0x4C] = data; |
| 1170 | | pokemini_update_sound( space->machine ); |
| 1170 | pokemini_update_sound( device->machine ); |
| 1171 | 1171 | break; |
| 1172 | 1172 | case 0x4D: /* Timer 3 sound-pivot (high) |
| 1173 | 1173 | Bit 0-7 R/W Timer 3 sound-pivot value bit 8-15 |
| r8457 | r8458 | |
| 1178 | 1178 | Pulse-Width of 100% = Same as preset-value |
| 1179 | 1179 | */ |
| 1180 | 1180 | pm_reg[0x4D] = data; |
| 1181 | | pokemini_update_sound( space->machine ); |
| 1181 | pokemini_update_sound( device->machine ); |
| 1182 | 1182 | break; |
| 1183 | 1183 | case 0x4E: /* Timer 3 counter (low), read only |
| 1184 | 1184 | Bit 0-7 R/W Timer 3 counter value bit 0-7 |
| r8457 | r8458 | |
| 1221 | 1221 | Bit 7 R/W IR received bit (mirror, if device not selected: 0) |
| 1222 | 1222 | */ |
| 1223 | 1223 | if ( pm_reg[0x60] & 0x04 ) |
| 1224 | | i2cmem_write( space->machine, 0, I2CMEM_SDA, ( data & 0x04 ) ? 1 : 0 ); |
| 1224 | i2cmem_sda_write(device, ( data & 0x04 ) ? 1 : 0 ); |
| 1225 | 1225 | |
| 1226 | 1226 | if ( pm_reg[0x60] & 0x08 ) |
| 1227 | | i2cmem_write( space->machine, 0, I2CMEM_SCL, ( data & 0x08 ) ? 1 : 0 ); |
| 1227 | i2cmem_scl_write(device, ( data & 0x08 ) ? 1 : 0 ); |
| 1228 | 1228 | break; |
| 1229 | 1229 | case 0x70: /* Sound related */ |
| 1230 | 1230 | pm_reg[0x70] = data; |
| 1231 | | pokemini_update_sound( space->machine ); |
| 1231 | pokemini_update_sound( device->machine ); |
| 1232 | 1232 | break; |
| 1233 | 1233 | case 0x71: /* Sound volume |
| 1234 | 1234 | Bit 0-1 R/W Sound volume |
| r8457 | r8458 | |
| 1240 | 1240 | Bit 3-7 Unused |
| 1241 | 1241 | */ |
| 1242 | 1242 | pm_reg[0x71] = data; |
| 1243 | | pokemini_update_sound( space->machine ); |
| 1243 | pokemini_update_sound( device->machine ); |
| 1244 | 1244 | break; |
| 1245 | 1245 | case 0x80: /* LCD control |
| 1246 | 1246 | Bit 0 R/W Invert colors; 0 - normal, 1 - inverted |
| r8457 | r8458 | |
| 1328 | 1328 | Map size 2: 0x00 to 0x60 |
| 1329 | 1329 | Bit 7 Unused |
| 1330 | 1330 | */ |
| 1331 | | logerror( "%0X: Write to unknown hardware address: %02X, %02X\n", cpu_get_pc( space->cpu ), offset, data ); |
| 1331 | logerror( "%0X: Write to unknown hardware address: %02X, %02X\n", cpu_get_pc( device->machine->firstcpu ), offset, data ); |
| 1332 | 1332 | break; |
| 1333 | 1333 | case 0x87: /* Sprite tile data memory offset (low) |
| 1334 | 1334 | Bit 0-5 Always "0" |
| r8457 | r8458 | |
| 1369 | 1369 | // lcd_data_w( data ); |
| 1370 | 1370 | break; |
| 1371 | 1371 | default: |
| 1372 | | logerror( "%0X: Write to unknown hardware address: %02X, %02X\n", cpu_get_pc( space->cpu ), offset, data ); |
| 1372 | logerror( "%0X: Write to unknown hardware address: %02X, %02X\n", cpu_get_pc( device->machine->firstcpu ), offset, data ); |
| 1373 | 1373 | break; |
| 1374 | 1374 | } |
| 1375 | 1375 | pm_reg[offset] = data; |
| 1376 | 1376 | } |
| 1377 | 1377 | |
| 1378 | | READ8_HANDLER( pokemini_hwreg_r ) |
| 1378 | READ8_DEVICE_HANDLER( pokemini_hwreg_r ) |
| 1379 | 1379 | { |
| 1380 | 1380 | UINT8 data = pm_reg[offset]; |
| 1381 | 1381 | |
| 1382 | 1382 | switch( offset ) |
| 1383 | 1383 | { |
| 1384 | | case 0x52: return input_port_read(space->machine, "INPUTS"); |
| 1384 | case 0x52: return input_port_read(device->machine, "INPUTS"); |
| 1385 | 1385 | case 0x61: |
| 1386 | 1386 | if ( ! ( pm_reg[0x60] & 0x04 ) ) |
| 1387 | 1387 | { |
| 1388 | | data = ( data & ~ 0x04 ) | ( i2cmem_read( space->machine, 0, I2CMEM_SDA ) ? 0x04 : 0x00 ); |
| 1388 | data = ( data & ~ 0x04 ) | ( i2cmem_sda_read( device) ? 0x04 : 0x00 ); |
| 1389 | 1389 | } |
| 1390 | 1390 | |
| 1391 | 1391 | if ( ! ( pm_reg[0x60] & 0x08 ) ) |