trunk/src/emu/machine/x76f100.c
| r26479 | r26480 | |
| 1 | // license:MAME |
| 2 | // copyright-holders:smf |
| 1 | 3 | /* |
| 2 | 4 | * x76f100.c |
| 3 | 5 | * |
| r26479 | r26480 | |
| 12 | 14 | #include "emu.h" |
| 13 | 15 | #include "machine/x76f100.h" |
| 14 | 16 | |
| 15 | | #define VERBOSE_LEVEL 0 |
| 17 | #define VERBOSE_LEVEL ( 0 ) |
| 16 | 18 | |
| 17 | | inline void ATTR_PRINTF(3,4) x76f100_device::verboselog(int n_level, const char *s_fmt, ...) |
| 19 | inline void ATTR_PRINTF( 3, 4 ) x76f100_device::verboselog( int n_level, const char *s_fmt, ... ) |
| 18 | 20 | { |
| 19 | | if(VERBOSE_LEVEL >= n_level) |
| 21 | if( VERBOSE_LEVEL >= n_level ) |
| 20 | 22 | { |
| 21 | 23 | va_list v; |
| 22 | | char buf[32768]; |
| 23 | | va_start(v, s_fmt); |
| 24 | | vsprintf(buf, s_fmt, v); |
| 25 | | va_end(v); |
| 26 | | logerror("x76f100 %s %s: %s", tag(), machine().describe_context(), buf); |
| 24 | char buf[ 32768 ]; |
| 25 | va_start( v, s_fmt ); |
| 26 | vsprintf( buf, s_fmt, v ); |
| 27 | va_end( v ); |
| 28 | logerror( "%s: x76f100(%s) %s", machine().describe_context(), tag(), buf ); |
| 27 | 29 | } |
| 28 | 30 | } |
| 29 | 31 | |
| 30 | 32 | // device type definition |
| 31 | 33 | const device_type X76F100 = &device_creator<x76f100_device>; |
| 32 | 34 | |
| 33 | | x76f100_device::x76f100_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 34 | | : device_secure_serial_flash(mconfig, X76F100, "X76F100", tag, owner, clock, "x76f100", __FILE__) |
| 35 | x76f100_device::x76f100_device( const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock ) |
| 36 | : device_t( mconfig, X76F100, "X76F100", tag, owner, clock, "x76f100", __FILE__ ), |
| 37 | device_nvram_interface(mconfig, *this), |
| 38 | m_cs( 0 ), |
| 39 | m_rst( 0 ), |
| 40 | m_scl( 0 ), |
| 41 | m_sdaw( 0 ), |
| 42 | m_sdar( 0 ), |
| 43 | m_state( STATE_STOP ), |
| 44 | m_shift( 0 ), |
| 45 | m_bit( 0 ), |
| 46 | m_byte( 0 ), |
| 47 | m_command( 0 ) |
| 35 | 48 | { |
| 36 | 49 | } |
| 37 | 50 | |
| 38 | 51 | void x76f100_device::device_start() |
| 39 | 52 | { |
| 40 | | device_secure_serial_flash::device_start(); |
| 41 | | save_item(NAME(state)); |
| 42 | | save_item(NAME(shift)); |
| 43 | | save_item(NAME(bit)); |
| 44 | | save_item(NAME(byte)); |
| 45 | | save_item(NAME(command)); |
| 46 | | save_item(NAME(write_buffer)); |
| 47 | | save_item(NAME(response_to_reset)); |
| 48 | | save_item(NAME(write_password)); |
| 49 | | save_item(NAME(read_password)); |
| 50 | | save_item(NAME(data)); |
| 51 | | } |
| 53 | memset( m_write_buffer, 0, sizeof( m_write_buffer ) ); |
| 52 | 54 | |
| 53 | | void x76f100_device::device_reset() |
| 54 | | { |
| 55 | | device_secure_serial_flash::device_reset(); |
| 56 | | state = STATE_STOP; |
| 57 | | shift = 0; |
| 58 | | bit = 0; |
| 59 | | byte = 0; |
| 60 | | command = 0; |
| 61 | | memset(write_buffer, 0, SIZE_WRITE_BUFFER); |
| 55 | save_item( NAME( m_cs ) ); |
| 56 | save_item( NAME( m_rst ) ); |
| 57 | save_item( NAME( m_scl ) ); |
| 58 | save_item( NAME( m_sdaw ) ); |
| 59 | save_item( NAME( m_sdar ) ); |
| 60 | save_item( NAME( m_state ) ); |
| 61 | save_item( NAME( m_shift ) ); |
| 62 | save_item( NAME( m_bit ) ); |
| 63 | save_item( NAME( m_byte ) ); |
| 64 | save_item( NAME( m_command ) ); |
| 65 | save_item( NAME( m_write_buffer ) ); |
| 66 | save_item( NAME( m_response_to_reset ) ); |
| 67 | save_item( NAME( m_write_password ) ); |
| 68 | save_item( NAME( m_read_password ) ); |
| 69 | save_item( NAME( m_data ) ); |
| 62 | 70 | } |
| 63 | 71 | |
| 64 | | void x76f100_device::nvram_default() |
| 72 | WRITE_LINE_MEMBER( x76f100_device::write_cs ) |
| 65 | 73 | { |
| 66 | | // region always wins |
| 67 | | if(m_region) |
| 74 | if( m_cs != state ) |
| 68 | 75 | { |
| 69 | | // Ensure the size is correct though |
| 70 | | if(m_region->bytes() != SIZE_RESPONSE_TO_RESET+SIZE_WRITE_PASSWORD+SIZE_READ_PASSWORD+SIZE_DATA) |
| 71 | | logerror("x76f100 %s: Wrong region length for initialization data, expected 0x%x, got 0x%x\n", |
| 72 | | tag(), |
| 73 | | SIZE_RESPONSE_TO_RESET+SIZE_WRITE_PASSWORD+SIZE_READ_PASSWORD+SIZE_DATA, |
| 74 | | m_region->bytes()); |
| 75 | | else { |
| 76 | | UINT8 *rb = m_region->base(); |
| 77 | | int offset = 0; |
| 78 | | memcpy(response_to_reset, rb + offset, SIZE_RESPONSE_TO_RESET); offset += SIZE_RESPONSE_TO_RESET; |
| 79 | | memcpy(write_password, rb + offset, SIZE_WRITE_PASSWORD); offset += SIZE_WRITE_PASSWORD; |
| 80 | | memcpy(read_password, rb + offset, SIZE_READ_PASSWORD); offset += SIZE_READ_PASSWORD; |
| 81 | | memcpy(data, rb + offset, SIZE_DATA); offset += SIZE_DATA; |
| 82 | | return; |
| 83 | | } |
| 76 | verboselog( 2, "cs=%d\n", state ); |
| 84 | 77 | } |
| 85 | 78 | |
| 86 | | // That chip isn't really usable without the passwords, so bitch |
| 87 | | // if there's no region |
| 88 | | logerror("x76f100 %s: Warning, no default data provided, chip is unusable.\n", tag()); |
| 89 | | memset(response_to_reset, 0, SIZE_RESPONSE_TO_RESET); |
| 90 | | memset(write_password, 0, SIZE_WRITE_PASSWORD); |
| 91 | | memset(read_password, 0, SIZE_READ_PASSWORD); |
| 92 | | memset(data, 0, SIZE_DATA); |
| 93 | | } |
| 79 | if( m_cs != 0 && state == 0 ) |
| 80 | { |
| 81 | /* enable chip */ |
| 82 | m_state = STATE_STOP; |
| 83 | } |
| 94 | 84 | |
| 95 | | void x76f100_device::cs_0() |
| 96 | | { |
| 97 | | /* enable chip */ |
| 98 | | state = STATE_STOP; |
| 99 | | } |
| 85 | if( m_cs == 0 && state != 0 ) |
| 86 | { |
| 87 | /* disable chip */ |
| 88 | m_state = STATE_STOP; |
| 89 | /* high impendence? */ |
| 90 | m_sdar = 0; |
| 91 | } |
| 100 | 92 | |
| 101 | | void x76f100_device::cs_1() |
| 102 | | { |
| 103 | | /* disable chip */ |
| 104 | | state = STATE_STOP; |
| 105 | | /* high impendence? */ |
| 106 | | sdar = 0; |
| 93 | m_cs = state; |
| 107 | 94 | } |
| 108 | 95 | |
| 109 | | void x76f100_device::rst_0() |
| 96 | WRITE_LINE_MEMBER( x76f100_device::write_rst ) |
| 110 | 97 | { |
| 111 | | } |
| 98 | if( m_rst != state ) |
| 99 | { |
| 100 | verboselog( 2, "rst=%d\n", state ); |
| 101 | } |
| 112 | 102 | |
| 113 | | void x76f100_device::rst_1() |
| 114 | | { |
| 115 | | if(!cs) { |
| 116 | | verboselog(1, "goto response to reset\n"); |
| 117 | | state = STATE_RESPONSE_TO_RESET; |
| 118 | | bit = 0; |
| 119 | | byte = 0; |
| 103 | if( m_rst == 0 && state != 0 && m_cs == 0 ) |
| 104 | { |
| 105 | verboselog( 1, "goto response to reset\n" ); |
| 106 | m_state = STATE_RESPONSE_TO_RESET; |
| 107 | m_bit = 0; |
| 108 | m_byte = 0; |
| 120 | 109 | } |
| 110 | |
| 111 | m_rst = state; |
| 121 | 112 | } |
| 122 | 113 | |
| 123 | 114 | UINT8 *x76f100_device::password() |
| 124 | 115 | { |
| 125 | | if((command & 0xe1) == COMMAND_READ) |
| 116 | if( ( m_command & 0xe1 ) == COMMAND_READ ) |
| 126 | 117 | { |
| 127 | | return read_password; |
| 118 | return m_read_password; |
| 128 | 119 | } |
| 129 | 120 | |
| 130 | | return write_password; |
| 121 | return m_write_password; |
| 131 | 122 | } |
| 132 | 123 | |
| 133 | 124 | void x76f100_device::password_ok() |
| 134 | 125 | { |
| 135 | | if((command & 0xe1) == COMMAND_READ) |
| 126 | if( ( m_command & 0xe1 ) == COMMAND_READ ) |
| 136 | 127 | { |
| 137 | | state = STATE_READ_DATA; |
| 128 | m_state = STATE_READ_DATA; |
| 138 | 129 | } |
| 139 | | else if((command & 0xe1) == COMMAND_WRITE) |
| 130 | else if( ( m_command & 0xe1 ) == COMMAND_WRITE ) |
| 140 | 131 | { |
| 141 | | state = STATE_WRITE_DATA; |
| 132 | m_state = STATE_WRITE_DATA; |
| 142 | 133 | } |
| 143 | 134 | else |
| 144 | 135 | { |
| r26479 | r26480 | |
| 148 | 139 | |
| 149 | 140 | int x76f100_device::data_offset() |
| 150 | 141 | { |
| 151 | | int block_offset = (command >> 1) & 0x0f; |
| 142 | int block_offset = ( m_command >> 1 ) & 0x0f; |
| 152 | 143 | |
| 153 | | return block_offset * SIZE_WRITE_BUFFER + byte; |
| 144 | return ( block_offset * sizeof( m_write_buffer ) ) + m_byte; |
| 154 | 145 | } |
| 155 | 146 | |
| 156 | | void x76f100_device::scl_0() |
| 147 | WRITE_LINE_MEMBER( x76f100_device::write_scl ) |
| 157 | 148 | { |
| 158 | | if(cs) |
| 159 | | return; |
| 149 | if( m_scl != state ) |
| 150 | { |
| 151 | verboselog( 2, "scl=%d\n", state ); |
| 152 | } |
| 160 | 153 | |
| 161 | | switch(state) { |
| 162 | | case STATE_RESPONSE_TO_RESET: |
| 163 | | if(bit == 0) { |
| 164 | | shift = response_to_reset[byte]; |
| 165 | | verboselog(1, "<- response_to_reset[%d]: %02x\n", byte, shift); |
| 166 | | } |
| 154 | if( m_cs == 0 ) |
| 155 | { |
| 156 | switch( m_state ) |
| 157 | { |
| 158 | case STATE_STOP: |
| 159 | break; |
| 167 | 160 | |
| 168 | | sdar = shift & 1; |
| 169 | | shift >>= 1; |
| 170 | | bit++; |
| 161 | case STATE_RESPONSE_TO_RESET: |
| 162 | if( m_scl != 0 && state == 0 ) |
| 163 | { |
| 164 | if( m_bit == 0 ) |
| 165 | { |
| 166 | m_shift = m_response_to_reset[ m_byte ]; |
| 167 | verboselog( 1, "<- response_to_reset[%d]: %02x\n", m_byte, m_shift ); |
| 168 | } |
| 171 | 169 | |
| 172 | | if(bit == 8) { |
| 173 | | bit = 0; |
| 174 | | byte++; |
| 175 | | if(byte == 4) |
| 176 | | byte = 0; |
| 170 | m_sdar = m_shift & 1; |
| 171 | m_shift >>= 1; |
| 172 | m_bit++; |
| 173 | |
| 174 | if( m_bit == 8 ) |
| 175 | { |
| 176 | m_bit = 0; |
| 177 | m_byte++; |
| 178 | |
| 179 | if( m_byte == sizeof( m_response_to_reset ) ) |
| 180 | { |
| 181 | m_byte = 0; |
| 182 | } |
| 183 | } |
| 184 | } |
| 185 | break; |
| 186 | |
| 187 | case STATE_LOAD_COMMAND: |
| 188 | case STATE_LOAD_PASSWORD: |
| 189 | case STATE_VERIFY_PASSWORD: |
| 190 | case STATE_WRITE_DATA: |
| 191 | if( m_scl == 0 && state != 0 ) |
| 192 | { |
| 193 | if( m_bit < 8 ) |
| 194 | { |
| 195 | verboselog( 2, "clock\n" ); |
| 196 | m_shift <<= 1; |
| 197 | |
| 198 | if( m_sdaw != 0 ) |
| 199 | { |
| 200 | m_shift |= 1; |
| 201 | } |
| 202 | |
| 203 | m_bit++; |
| 204 | } |
| 205 | else |
| 206 | { |
| 207 | m_sdar = 0; |
| 208 | |
| 209 | switch( m_state ) |
| 210 | { |
| 211 | case STATE_LOAD_COMMAND: |
| 212 | m_command = m_shift; |
| 213 | verboselog( 1, "-> command: %02x\n", m_command ); |
| 214 | /* todo: verify command is valid? */ |
| 215 | m_state = STATE_LOAD_PASSWORD; |
| 216 | break; |
| 217 | |
| 218 | case STATE_LOAD_PASSWORD: |
| 219 | verboselog( 1, "-> password: %02x\n", m_shift ); |
| 220 | m_write_buffer[ m_byte++ ] = m_shift; |
| 221 | |
| 222 | if( m_byte == sizeof( m_write_buffer ) ) |
| 223 | { |
| 224 | m_state = STATE_VERIFY_PASSWORD; |
| 225 | } |
| 226 | break; |
| 227 | |
| 228 | case STATE_VERIFY_PASSWORD: |
| 229 | verboselog( 1, "-> verify password: %02x\n", m_shift ); |
| 230 | |
| 231 | /* todo: this should probably be handled as a command */ |
| 232 | if( m_shift == COMMAND_ACK_PASSWORD ) |
| 233 | { |
| 234 | /* todo: this should take 10ms before it returns ok. */ |
| 235 | if( memcmp( password(), m_write_buffer, sizeof( m_write_buffer ) ) == 0 ) |
| 236 | { |
| 237 | password_ok(); |
| 238 | } |
| 239 | else |
| 240 | { |
| 241 | m_sdar = 1; |
| 242 | } |
| 243 | } |
| 244 | break; |
| 245 | |
| 246 | case STATE_WRITE_DATA: |
| 247 | verboselog( 2, "-> data: %02x\n", m_shift ); |
| 248 | m_write_buffer[ m_byte++ ] = m_shift; |
| 249 | |
| 250 | if( m_byte == sizeof( m_write_buffer ) ) |
| 251 | { |
| 252 | for( m_byte = 0; m_byte < sizeof( m_write_buffer ); m_byte++ ) |
| 253 | { |
| 254 | int offset = data_offset(); |
| 255 | verboselog( 1, "-> data[ %03x ]: %02x\n", offset, m_write_buffer[ m_byte ] ); |
| 256 | m_data[ offset ] = m_write_buffer[ m_byte ]; |
| 257 | } |
| 258 | |
| 259 | m_byte = 0; |
| 260 | |
| 261 | verboselog( 1, "data flushed\n" ); |
| 262 | } |
| 263 | break; |
| 264 | } |
| 265 | |
| 266 | m_bit = 0; |
| 267 | m_shift = 0; |
| 268 | } |
| 269 | } |
| 270 | break; |
| 271 | |
| 272 | case STATE_READ_DATA: |
| 273 | if( m_scl == 0 && state != 0 ) |
| 274 | { |
| 275 | if( m_bit < 8 ) |
| 276 | { |
| 277 | if( m_bit == 0 ) |
| 278 | { |
| 279 | int offset; |
| 280 | |
| 281 | switch( m_state ) |
| 282 | { |
| 283 | case STATE_READ_DATA: |
| 284 | offset = data_offset(); |
| 285 | m_shift = m_data[ offset ]; |
| 286 | verboselog( 1, "<- data[ %02x ]: %02x\n", offset, m_shift ); |
| 287 | break; |
| 288 | } |
| 289 | } |
| 290 | |
| 291 | m_sdar = ( m_shift >> 7 ) & 1; |
| 292 | m_shift <<= 1; |
| 293 | m_bit++; |
| 294 | } |
| 295 | else |
| 296 | { |
| 297 | m_bit = 0; |
| 298 | m_sdar = 0; |
| 299 | |
| 300 | if( m_sdaw == 0 ) |
| 301 | { |
| 302 | verboselog( 2, "ack <-\n" ); |
| 303 | m_byte++; |
| 304 | } |
| 305 | else |
| 306 | { |
| 307 | verboselog( 2, "nak <-\n" ); |
| 308 | } |
| 309 | } |
| 310 | } |
| 311 | break; |
| 177 | 312 | } |
| 178 | | break; |
| 179 | 313 | } |
| 314 | |
| 315 | m_scl = state; |
| 180 | 316 | } |
| 181 | 317 | |
| 182 | | void x76f100_device::scl_1() |
| 318 | WRITE_LINE_MEMBER( x76f100_device::write_sda ) |
| 183 | 319 | { |
| 184 | | if(cs) |
| 185 | | return; |
| 320 | if( m_sdaw != state ) |
| 321 | { |
| 322 | verboselog( 2, "sdaw=%d\n", state ); |
| 323 | } |
| 186 | 324 | |
| 187 | | switch(state) { |
| 188 | | case STATE_RESPONSE_TO_RESET: |
| 189 | | break; |
| 325 | if( m_cs == 0 && m_scl != 0 ) |
| 326 | { |
| 327 | if( m_sdaw == 0 && state != 0 ) |
| 328 | { |
| 329 | verboselog( 1, "goto stop\n" ); |
| 330 | m_state = STATE_STOP; |
| 331 | m_sdar = 0; |
| 332 | } |
| 190 | 333 | |
| 191 | | case STATE_LOAD_COMMAND: |
| 192 | | case STATE_LOAD_PASSWORD: |
| 193 | | case STATE_VERIFY_PASSWORD: |
| 194 | | case STATE_WRITE_DATA: |
| 195 | | if(bit < 8) { |
| 196 | | verboselog(2, "clock\n"); |
| 197 | | shift <<= 1; |
| 198 | | if(sdaw) |
| 199 | | shift |= 1; |
| 200 | | bit++; |
| 201 | | } else { |
| 202 | | switch(state) { |
| 203 | | case STATE_LOAD_COMMAND: |
| 204 | | verboselog(1, "-> command: %02x\n", command); |
| 205 | | sdar = false; |
| 206 | | command = shift; |
| 207 | | /* todo: verify command is valid? */ |
| 208 | | state = STATE_LOAD_PASSWORD; |
| 209 | | bit = 0; |
| 210 | | shift = 0; |
| 334 | if( m_sdaw != 0 && state == 0 ) |
| 335 | { |
| 336 | switch( m_state ) |
| 337 | { |
| 338 | case STATE_STOP: |
| 339 | verboselog( 1, "goto start\n" ); |
| 340 | m_state = STATE_LOAD_COMMAND; |
| 211 | 341 | break; |
| 212 | 342 | |
| 213 | 343 | case STATE_LOAD_PASSWORD: |
| 214 | | verboselog(1, "-> password: %02x\n", shift); |
| 215 | | sdar = false; |
| 216 | | write_buffer[byte++] = shift; |
| 217 | | if(byte == SIZE_WRITE_BUFFER) |
| 218 | | state = STATE_VERIFY_PASSWORD; |
| 219 | | bit = 0; |
| 220 | | shift = 0; |
| 344 | /* todo: this will be the 0xc0 command, but it's not handled as a command yet. */ |
| 345 | verboselog( 1, "goto start\n" ); |
| 221 | 346 | break; |
| 222 | 347 | |
| 223 | | case STATE_VERIFY_PASSWORD: |
| 224 | | verboselog(1, "-> verify password: %02x\n", shift); |
| 225 | | sdar = false; |
| 226 | | /* todo: this should probably be handled as a command */ |
| 227 | | if(shift == COMMAND_ACK_PASSWORD) { |
| 228 | | /* todo: this should take 10ms before it returns ok. */ |
| 229 | | if(!memcmp(password(), write_buffer, SIZE_WRITE_BUFFER)) |
| 230 | | password_ok(); |
| 231 | | else |
| 232 | | sdar = true; |
| 233 | | } |
| 234 | | bit = 0; |
| 235 | | shift = 0; |
| 348 | case STATE_READ_DATA: |
| 349 | verboselog( 1, "continue reading??\n" ); |
| 350 | // verboselog( 1, "goto load address\n" ); |
| 351 | // m_state = STATE_LOAD_ADDRESS; |
| 236 | 352 | break; |
| 237 | 353 | |
| 238 | | case STATE_WRITE_DATA: |
| 239 | | verboselog(1, "-> data: %02x\n", shift ); |
| 240 | | sdar = false; |
| 241 | | write_buffer[byte++] = shift; |
| 242 | | if(byte == SIZE_WRITE_BUFFER) { |
| 243 | | for(byte = 0; byte < SIZE_WRITE_BUFFER; byte++) |
| 244 | | data[data_offset()] = write_buffer[byte]; |
| 245 | | byte = 0; |
| 246 | | } |
| 247 | | bit = 0; |
| 248 | | shift = 0; |
| 354 | default: |
| 355 | verboselog( 1, "skipped start (default)\n" ); |
| 249 | 356 | break; |
| 250 | 357 | } |
| 251 | | } |
| 252 | | break; |
| 253 | 358 | |
| 254 | | case STATE_READ_DATA: |
| 255 | | if(bit < 8) { |
| 256 | | if(bit == 0) { |
| 257 | | shift = data[data_offset()]; |
| 258 | | verboselog(1, "<- data: %02x\n", shift ); |
| 259 | | } |
| 260 | | sdar = (shift >> 7) & 1; |
| 261 | | shift <<= 1; |
| 262 | | bit++; |
| 263 | | } else { |
| 264 | | bit = 0; |
| 265 | | sdar = false; |
| 266 | | if(!sdaw) { |
| 267 | | verboselog(2, "ack <-\n"); |
| 268 | | byte++; |
| 269 | | } else { |
| 270 | | verboselog(2, "nak <-\n"); |
| 271 | | } |
| 359 | m_bit = 0; |
| 360 | m_byte = 0; |
| 361 | m_shift = 0; |
| 362 | m_sdar = 0; |
| 272 | 363 | } |
| 273 | | break; |
| 274 | 364 | } |
| 365 | |
| 366 | m_sdaw = state; |
| 275 | 367 | } |
| 276 | 368 | |
| 277 | | void x76f100_device::sda_0() |
| 369 | READ_LINE_MEMBER( x76f100_device::read_sda ) |
| 278 | 370 | { |
| 279 | | if(cs || !scl) |
| 280 | | return; |
| 371 | if( m_cs != 0 ) |
| 372 | { |
| 373 | verboselog( 2, "not selected\n" ); |
| 374 | return 1; |
| 375 | } |
| 281 | 376 | |
| 282 | | switch(state) { |
| 283 | | case STATE_STOP: |
| 284 | | state = STATE_LOAD_COMMAND; |
| 285 | | break; |
| 377 | verboselog( 2, "sdar=%d\n", m_sdar ); |
| 378 | return m_sdar; |
| 379 | } |
| 286 | 380 | |
| 287 | | case STATE_LOAD_PASSWORD: |
| 288 | | /* todo: this will be the 0xc0 command, but it's not handled as a command yet. */ |
| 289 | | break; |
| 381 | void x76f100_device::nvram_default() |
| 382 | { |
| 383 | m_response_to_reset[ 0 ] = 0x19; |
| 384 | m_response_to_reset[ 1 ] = 0x00; |
| 385 | m_response_to_reset[ 2 ] = 0xaa; |
| 386 | m_response_to_reset[ 3 ] = 0x55, |
| 290 | 387 | |
| 291 | | case STATE_READ_DATA: |
| 292 | | // c->state = STATE_LOAD_ADDRESS; |
| 293 | | break; |
| 388 | memset( m_write_password, 0, sizeof( m_write_password ) ); |
| 389 | memset( m_read_password, 0, sizeof( m_read_password ) ); |
| 390 | memset( m_data, 0, sizeof( m_data ) ); |
| 294 | 391 | |
| 295 | | default: |
| 296 | | break; |
| 392 | int expected_size = sizeof( m_response_to_reset ) + sizeof( m_write_password ) + sizeof( m_read_password ) + sizeof( m_data ); |
| 393 | |
| 394 | if( !m_region ) |
| 395 | { |
| 396 | logerror( "x76f100(%s) region not found\n", tag() ); |
| 297 | 397 | } |
| 398 | else if( m_region->bytes() != expected_size ) |
| 399 | { |
| 400 | logerror("x76f100(%s) region length 0x%x expected 0x%x\n", tag(), m_region->bytes(), expected_size ); |
| 401 | } |
| 402 | else |
| 403 | { |
| 404 | UINT8 *region = m_region->base(); |
| 298 | 405 | |
| 299 | | bit = 0; |
| 300 | | byte = 0; |
| 301 | | shift = 0; |
| 302 | | sdar = false; |
| 406 | memcpy( m_response_to_reset, region, sizeof( m_response_to_reset )); region += sizeof( m_response_to_reset ); |
| 407 | memcpy( m_write_password, region, sizeof( m_write_password )); region += sizeof( m_write_password ); |
| 408 | memcpy( m_read_password, region, sizeof( m_read_password )); region += sizeof( m_read_password ); |
| 409 | memcpy( m_data, region, sizeof( m_data )); region += sizeof( m_data ); |
| 410 | } |
| 303 | 411 | } |
| 304 | 412 | |
| 305 | | void x76f100_device::sda_1() |
| 413 | void x76f100_device::nvram_read( emu_file &file ) |
| 306 | 414 | { |
| 307 | | if(cs || !scl) |
| 308 | | return; |
| 309 | | |
| 310 | | state = STATE_STOP; |
| 311 | | sdar = false; |
| 415 | file.read( m_response_to_reset, sizeof( m_response_to_reset ) ); |
| 416 | file.read( m_write_password, sizeof( m_write_password ) ); |
| 417 | file.read( m_read_password, sizeof( m_read_password ) ); |
| 418 | file.read( m_data, sizeof( m_data ) ); |
| 312 | 419 | } |
| 313 | 420 | |
| 314 | | void x76f100_device::nvram_read(emu_file &file) |
| 421 | void x76f100_device::nvram_write( emu_file &file ) |
| 315 | 422 | { |
| 316 | | file.read(response_to_reset, SIZE_RESPONSE_TO_RESET); |
| 317 | | file.read(write_password, SIZE_WRITE_PASSWORD); |
| 318 | | file.read(read_password, SIZE_READ_PASSWORD); |
| 319 | | file.read(data, SIZE_DATA); |
| 423 | file.write( m_response_to_reset, sizeof( m_response_to_reset ) ); |
| 424 | file.write( m_write_password, sizeof( m_write_password ) ); |
| 425 | file.write( m_read_password, sizeof( m_read_password ) ); |
| 426 | file.write( m_data, sizeof( m_data ) ); |
| 320 | 427 | } |
| 321 | | |
| 322 | | void x76f100_device::nvram_write(emu_file &file) |
| 323 | | { |
| 324 | | file.write(response_to_reset, SIZE_RESPONSE_TO_RESET); |
| 325 | | file.write(write_password, SIZE_WRITE_PASSWORD); |
| 326 | | file.write(read_password, SIZE_READ_PASSWORD); |
| 327 | | file.write(data, SIZE_DATA); |
| 328 | | } |
trunk/src/emu/machine/x76f041.c
| r26479 | r26480 | |
| 1 | // license:MAME |
| 2 | // copyright-holders:smf |
| 1 | 3 | /* |
| 2 | 4 | * x76f041.c |
| 3 | 5 | * |
| r26479 | r26480 | |
| 14 | 16 | #include "emu.h" |
| 15 | 17 | #include "machine/x76f041.h" |
| 16 | 18 | |
| 17 | | #define VERBOSE_LEVEL 0 |
| 19 | #define VERBOSE_LEVEL ( 0 ) |
| 18 | 20 | |
| 19 | | inline void ATTR_PRINTF(3,4) x76f041_device::verboselog(int n_level, const char *s_fmt, ...) |
| 21 | inline void ATTR_PRINTF( 3, 4 ) x76f041_device::verboselog( int n_level, const char *s_fmt, ... ) |
| 20 | 22 | { |
| 21 | | if(VERBOSE_LEVEL >= n_level) |
| 23 | if( VERBOSE_LEVEL >= n_level ) |
| 22 | 24 | { |
| 23 | 25 | va_list v; |
| 24 | | char buf[32768]; |
| 25 | | va_start(v, s_fmt); |
| 26 | | vsprintf(buf, s_fmt, v); |
| 27 | | va_end(v); |
| 28 | | logerror("x76f041 %s %s: %s", tag(), machine().describe_context(), buf); |
| 26 | char buf[ 32768 ]; |
| 27 | va_start( v, s_fmt ); |
| 28 | vsprintf( buf, s_fmt, v ); |
| 29 | va_end( v ); |
| 30 | logerror( "%s: x76f041(%s) %s", machine().describe_context(), tag(), buf ); |
| 29 | 31 | } |
| 30 | 32 | } |
| 31 | 33 | |
| 32 | 34 | // device type definition |
| 33 | 35 | const device_type X76F041 = &device_creator<x76f041_device>; |
| 34 | 36 | |
| 35 | | x76f041_device::x76f041_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 36 | | : device_secure_serial_flash(mconfig, X76F041, "X76F041", tag, owner, clock, "x76f041", __FILE__) |
| 37 | x76f041_device::x76f041_device( const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock ) |
| 38 | : device_t( mconfig, X76F041, "X76F041", tag, owner, clock, "x76f041", __FILE__ ), |
| 39 | device_nvram_interface(mconfig, *this), |
| 40 | m_cs( 0 ), |
| 41 | m_rst( 0 ), |
| 42 | m_scl( 0 ), |
| 43 | m_sdaw( 0 ), |
| 44 | m_sdar( 0 ), |
| 45 | m_state( STATE_STOP ), |
| 46 | m_shift( 0 ), |
| 47 | m_bit( 0 ), |
| 48 | m_byte( 0 ), |
| 49 | m_command( 0 ), |
| 50 | m_address( 0 ) |
| 37 | 51 | { |
| 38 | 52 | } |
| 39 | 53 | |
| 40 | 54 | void x76f041_device::device_start() |
| 41 | 55 | { |
| 42 | | device_secure_serial_flash::device_start(); |
| 43 | | save_item(NAME(state)); |
| 44 | | save_item(NAME(shift)); |
| 45 | | save_item(NAME(bit)); |
| 46 | | save_item(NAME(byte)); |
| 47 | | save_item(NAME(command)); |
| 48 | | save_item(NAME(address)); |
| 49 | | save_item(NAME(write_buffer)); |
| 50 | | save_item(NAME(response_to_reset)); |
| 51 | | save_item(NAME(write_password)); |
| 52 | | save_item(NAME(read_password)); |
| 53 | | save_item(NAME(configuration_password)); |
| 54 | | save_item(NAME(configuration_registers)); |
| 55 | | save_item(NAME(data)); |
| 56 | | } |
| 56 | memset( m_write_buffer, 0, sizeof( m_write_buffer ) ); |
| 57 | 57 | |
| 58 | | void x76f041_device::device_reset() |
| 59 | | { |
| 60 | | device_secure_serial_flash::device_reset(); |
| 61 | | state = STATE_STOP; |
| 62 | | shift = 0; |
| 63 | | bit = 0; |
| 64 | | byte = 0; |
| 65 | | command = 0; |
| 66 | | address = 0; |
| 67 | | memset(write_buffer, 0, SIZE_WRITE_BUFFER); |
| 58 | save_item( NAME( m_cs ) ); |
| 59 | save_item( NAME( m_rst ) ); |
| 60 | save_item( NAME( m_scl ) ); |
| 61 | save_item( NAME( m_sdaw ) ); |
| 62 | save_item( NAME( m_sdar ) ); |
| 63 | save_item( NAME( m_state ) ); |
| 64 | save_item( NAME( m_shift ) ); |
| 65 | save_item( NAME( m_bit ) ); |
| 66 | save_item( NAME( m_byte ) ); |
| 67 | save_item( NAME( m_command ) ); |
| 68 | save_item( NAME( m_address ) ); |
| 69 | save_item( NAME( m_write_buffer ) ); |
| 70 | save_item( NAME( m_response_to_reset ) ); |
| 71 | save_item( NAME( m_write_password ) ); |
| 72 | save_item( NAME( m_read_password ) ); |
| 73 | save_item( NAME( m_configuration_password ) ); |
| 74 | save_item( NAME( m_configuration_registers ) ); |
| 75 | save_item( NAME( m_data ) ); |
| 68 | 76 | } |
| 69 | 77 | |
| 70 | | void x76f041_device::nvram_default() |
| 78 | WRITE_LINE_MEMBER( x76f041_device::write_cs ) |
| 71 | 79 | { |
| 72 | | // region always wins |
| 73 | | if(m_region) |
| 80 | if( m_cs != state ) |
| 74 | 81 | { |
| 75 | | // Ensure the size is correct though |
| 76 | | if(m_region->bytes() != SIZE_RESPONSE_TO_RESET+SIZE_WRITE_PASSWORD+ |
| 77 | | SIZE_READ_PASSWORD+SIZE_CONFIGURATION_PASSWORD+SIZE_CONFIGURATION_REGISTERS+SIZE_DATA) |
| 78 | | logerror("X76F041: Wrong region length for initialization data, expected 0x%x, got 0x%x\n", |
| 79 | | SIZE_RESPONSE_TO_RESET+SIZE_WRITE_PASSWORD+ |
| 80 | | SIZE_READ_PASSWORD+SIZE_CONFIGURATION_PASSWORD+SIZE_CONFIGURATION_REGISTERS+SIZE_DATA, |
| 81 | | m_region->bytes()); |
| 82 | | else { |
| 83 | | UINT8 *rb = m_region->base(); |
| 84 | | int offset = 0; |
| 85 | | memcpy(response_to_reset, rb + offset, SIZE_RESPONSE_TO_RESET); offset += SIZE_RESPONSE_TO_RESET; |
| 86 | | memcpy(write_password, rb + offset, SIZE_WRITE_PASSWORD); offset += SIZE_WRITE_PASSWORD; |
| 87 | | memcpy(read_password, rb + offset, SIZE_READ_PASSWORD); offset += SIZE_READ_PASSWORD; |
| 88 | | memcpy(configuration_password, rb + offset, SIZE_CONFIGURATION_PASSWORD); offset += SIZE_CONFIGURATION_PASSWORD; |
| 89 | | memcpy(configuration_registers, rb + offset, SIZE_CONFIGURATION_REGISTERS); offset += SIZE_CONFIGURATION_REGISTERS; |
| 90 | | memcpy(data, rb + offset, SIZE_DATA); offset += SIZE_DATA; |
| 91 | | return; |
| 92 | | } |
| 82 | verboselog( 2, "cs=%d\n", state ); |
| 93 | 83 | } |
| 94 | 84 | |
| 95 | | // That chip isn't really usable without the passwords, so bitch |
| 96 | | // if there's no region |
| 97 | | logerror("X76F041: Warning, no default data provided, chip is unusable.\n"); |
| 98 | | memset(response_to_reset, 0, SIZE_RESPONSE_TO_RESET); |
| 99 | | memset(write_password, 0, SIZE_WRITE_PASSWORD); |
| 100 | | memset(read_password, 0, SIZE_READ_PASSWORD); |
| 101 | | memset(configuration_password, 0, SIZE_CONFIGURATION_PASSWORD); |
| 102 | | memset(configuration_registers, 0, SIZE_CONFIGURATION_REGISTERS); |
| 103 | | memset(data, 0, SIZE_DATA); |
| 104 | | } |
| 85 | if( m_cs != 0 && state == 0 ) |
| 86 | { |
| 87 | /* enable chip */ |
| 88 | m_state = STATE_STOP; |
| 89 | } |
| 105 | 90 | |
| 106 | | void x76f041_device::cs_0() |
| 107 | | { |
| 108 | | /* enable chip */ |
| 109 | | state = STATE_STOP; |
| 110 | | } |
| 91 | if( m_cs == 0 && state != 0 ) |
| 92 | { |
| 93 | /* disable chip */ |
| 94 | m_state = STATE_STOP; |
| 95 | /* high impendence? */ |
| 96 | m_sdar = 0; |
| 97 | } |
| 111 | 98 | |
| 112 | | void x76f041_device::cs_1() |
| 113 | | { |
| 114 | | /* disable chip */ |
| 115 | | state = STATE_STOP; |
| 116 | | /* high impendence? */ |
| 117 | | sdar = false; |
| 99 | m_cs = state; |
| 118 | 100 | } |
| 119 | 101 | |
| 120 | | void x76f041_device::rst_0() |
| 102 | WRITE_LINE_MEMBER( x76f041_device::write_rst ) |
| 121 | 103 | { |
| 122 | | } |
| 104 | if( m_rst != state ) |
| 105 | { |
| 106 | verboselog( 2, "rst=%d\n", state ); |
| 107 | } |
| 123 | 108 | |
| 124 | | void x76f041_device::rst_1() |
| 125 | | { |
| 126 | | if(!cs) { |
| 127 | | verboselog(1, "goto response to reset\n"); |
| 128 | | state = STATE_RESPONSE_TO_RESET; |
| 129 | | bit = 0; |
| 130 | | byte = 0; |
| 109 | if( m_rst == 0 && state != 0 && m_cs == 0 ) |
| 110 | { |
| 111 | verboselog( 1, "goto response to reset\n" ); |
| 112 | m_state = STATE_RESPONSE_TO_RESET; |
| 113 | m_bit = 0; |
| 114 | m_byte = 0; |
| 131 | 115 | } |
| 116 | |
| 117 | m_rst = state; |
| 132 | 118 | } |
| 133 | 119 | |
| 134 | 120 | UINT8 *x76f041_device::password() |
| 135 | 121 | { |
| 136 | | switch(command & 0xe0) { |
| 122 | switch( m_command & 0xe0 ) |
| 123 | { |
| 137 | 124 | case COMMAND_WRITE: |
| 138 | | return write_password; |
| 125 | return m_write_password; |
| 126 | |
| 139 | 127 | case COMMAND_READ: |
| 140 | | return read_password; |
| 128 | return m_read_password; |
| 129 | |
| 141 | 130 | default: |
| 142 | | return configuration_password; |
| 131 | return m_configuration_password; |
| 143 | 132 | } |
| 144 | 133 | } |
| 145 | 134 | |
| 146 | 135 | void x76f041_device::password_ok() |
| 147 | 136 | { |
| 148 | | switch(command & 0xe0) { |
| 137 | switch( m_command & 0xe0 ) |
| 138 | { |
| 149 | 139 | case COMMAND_WRITE: |
| 150 | | state = STATE_WRITE_DATA; |
| 140 | m_state = STATE_WRITE_DATA; |
| 151 | 141 | break; |
| 152 | 142 | case COMMAND_READ: |
| 153 | | state = STATE_READ_DATA; |
| 143 | m_state = STATE_READ_DATA; |
| 154 | 144 | break; |
| 155 | 145 | case COMMAND_WRITE_USE_CONFIGURATION_PASSWORD: |
| 156 | | state = STATE_WRITE_DATA; |
| 146 | m_state = STATE_WRITE_DATA; |
| 157 | 147 | break; |
| 158 | 148 | case COMMAND_READ_USE_CONFIGURATION_PASSWORD: |
| 159 | | state = STATE_READ_DATA; |
| 149 | m_state = STATE_READ_DATA; |
| 160 | 150 | break; |
| 161 | 151 | case COMMAND_CONFIGURATION: |
| 162 | | switch( address ) { |
| 152 | switch( m_address ) |
| 153 | { |
| 163 | 154 | case CONFIGURATION_PROGRAM_WRITE_PASSWORD: |
| 164 | 155 | break; |
| 165 | 156 | case CONFIGURATION_PROGRAM_READ_PASSWORD: |
| r26479 | r26480 | |
| 171 | 162 | case CONFIGURATION_RESET_READ_PASSWORD: |
| 172 | 163 | break; |
| 173 | 164 | case CONFIGURATION_PROGRAM_CONFIGURATION_REGISTERS: |
| 174 | | state = STATE_WRITE_CONFIGURATION_REGISTERS; |
| 175 | | byte = 0; |
| 165 | m_state = STATE_WRITE_CONFIGURATION_REGISTERS; |
| 166 | m_byte = 0; |
| 176 | 167 | break; |
| 177 | 168 | case CONFIGURATION_READ_CONFIGURATION_REGISTERS: |
| 178 | | state = STATE_READ_CONFIGURATION_REGISTERS; |
| 179 | | byte = 0; |
| 169 | m_state = STATE_READ_CONFIGURATION_REGISTERS; |
| 170 | m_byte = 0; |
| 180 | 171 | break; |
| 181 | 172 | case CONFIGURATION_MASS_PROGRAM: |
| 182 | 173 | break; |
| r26479 | r26480 | |
| 193 | 184 | /* todo: handle other bcr bits */ |
| 194 | 185 | int bcr; |
| 195 | 186 | |
| 196 | | address = shift; |
| 187 | m_address = m_shift; |
| 197 | 188 | |
| 198 | | verboselog(1, "-> address: %02x\n", address); |
| 189 | verboselog( 1, "-> address: %02x\n", m_address ); |
| 199 | 190 | |
| 200 | | if(!(command & 1 )) |
| 201 | | bcr = configuration_registers[CONFIG_BCR1]; |
| 191 | if( ( m_command & 1 ) == 0 ) |
| 192 | { |
| 193 | bcr = m_configuration_registers[ CONFIG_BCR1 ]; |
| 194 | } |
| 202 | 195 | else |
| 203 | | bcr = configuration_registers[CONFIG_BCR2]; |
| 204 | | |
| 205 | | if(address & 0x80) |
| 196 | { |
| 197 | bcr = m_configuration_registers[ CONFIG_BCR2 ]; |
| 198 | } |
| 199 | if( ( m_address & 0x80 ) != 0 ) |
| 200 | { |
| 206 | 201 | bcr >>= 4; |
| 202 | } |
| 207 | 203 | |
| 208 | | if(((command & 0xe0) == COMMAND_READ && (bcr & BCR_Z) && (bcr & BCR_T)) || |
| 209 | | ((command & 0xe0) == COMMAND_WRITE && (bcr & BCR_Z))) { |
| 204 | if( ( ( m_command & 0xe0 ) == COMMAND_READ && ( bcr & BCR_Z ) != 0 && ( bcr & BCR_T ) != 0 ) || |
| 205 | ( ( m_command & 0xe0 ) == COMMAND_WRITE && ( bcr & BCR_Z ) != 0 ) ) |
| 206 | { |
| 210 | 207 | /* todo: find out when this is really checked. */ |
| 211 | | verboselog(1, "command not allowed\n"); |
| 212 | | state = STATE_STOP; |
| 213 | | sdar = false; |
| 214 | | |
| 215 | | } else if(((command & 0xe0) == COMMAND_WRITE && !(bcr & BCR_X)) || |
| 216 | | ((command & 0xe0) == COMMAND_READ && !(bcr & BCR_Y))) { |
| 217 | | verboselog(1, "password not required\n"); |
| 208 | verboselog( 1, "command not allowed\n" ); |
| 209 | m_state = STATE_STOP; |
| 210 | m_sdar = 0; |
| 211 | } |
| 212 | else if( ( ( m_command & 0xe0 ) == COMMAND_WRITE && ( bcr & BCR_X ) == 0 ) || |
| 213 | ( ( m_command & 0xe0 ) == COMMAND_READ && ( bcr & BCR_Y ) == 0 ) ) |
| 214 | { |
| 215 | verboselog( 1, "password not required\n" ); |
| 218 | 216 | password_ok(); |
| 219 | | |
| 220 | | } else { |
| 221 | | verboselog(1, "send password\n"); |
| 222 | | state = STATE_LOAD_PASSWORD; |
| 223 | | byte = 0; |
| 224 | 217 | } |
| 218 | else |
| 219 | { |
| 220 | verboselog( 1, "send password\n" ); |
| 221 | m_state = STATE_LOAD_PASSWORD; |
| 222 | m_byte = 0; |
| 223 | } |
| 225 | 224 | } |
| 226 | 225 | |
| 227 | 226 | int x76f041_device::data_offset() |
| 228 | 227 | { |
| 229 | | int block_offset = ((command & 1) << 8) + address; |
| 228 | int block_offset = ( ( m_command & 1 ) << 8 ) + m_address; |
| 230 | 229 | |
| 231 | 230 | // TODO: confirm block_start doesn't wrap. |
| 232 | 231 | |
| 233 | | return (block_offset & 0x180) | ((block_offset + byte) & 0x7f); |
| 232 | return ( block_offset & 0x180 ) | ( ( block_offset + m_byte ) & 0x7f ); |
| 234 | 233 | } |
| 235 | 234 | |
| 236 | | void x76f041_device::scl_0() |
| 235 | WRITE_LINE_MEMBER( x76f041_device::write_scl ) |
| 237 | 236 | { |
| 238 | | if(!cs) { |
| 239 | | switch(state) { |
| 240 | | case STATE_RESPONSE_TO_RESET: |
| 241 | | sdar = (response_to_reset[byte] >> bit) & 1; |
| 242 | | verboselog(2, "in response to reset %d (%d/%d)\n", sdar, byte, bit); |
| 243 | | bit++; |
| 244 | | if(bit == 8) { |
| 245 | | bit = 0; |
| 246 | | byte++; |
| 247 | | if( byte == 4 ) |
| 248 | | byte = 0; |
| 249 | | } |
| 250 | | break; |
| 251 | | } |
| 237 | if( m_scl != state ) |
| 238 | { |
| 239 | verboselog( 2, "scl=%d\n", state ); |
| 252 | 240 | } |
| 253 | | } |
| 254 | 241 | |
| 255 | | void x76f041_device::scl_1() |
| 256 | | { |
| 257 | | if(!cs) { |
| 258 | | switch(state) { |
| 242 | if( m_cs == 0 ) |
| 243 | { |
| 244 | switch( m_state ) |
| 245 | { |
| 259 | 246 | case STATE_STOP: |
| 260 | 247 | break; |
| 248 | |
| 261 | 249 | case STATE_RESPONSE_TO_RESET: |
| 250 | if( m_scl != 0 && state == 0 ) |
| 251 | { |
| 252 | m_sdar = ( m_response_to_reset[ m_byte ] >> m_bit ) & 1; |
| 253 | verboselog( 2, "in response to reset %d (%d/%d)\n", m_sdar, m_byte, m_bit ); |
| 254 | m_bit++; |
| 255 | |
| 256 | if( m_bit == 8 ) |
| 257 | { |
| 258 | m_bit = 0; |
| 259 | m_byte++; |
| 260 | |
| 261 | if( m_byte == sizeof( m_response_to_reset ) ) |
| 262 | { |
| 263 | m_byte = 0; |
| 264 | } |
| 265 | } |
| 266 | } |
| 262 | 267 | break; |
| 268 | |
| 263 | 269 | case STATE_LOAD_COMMAND: |
| 264 | 270 | case STATE_LOAD_ADDRESS: |
| 265 | 271 | case STATE_LOAD_PASSWORD: |
| 266 | 272 | case STATE_VERIFY_PASSWORD: |
| 267 | 273 | case STATE_WRITE_DATA: |
| 268 | 274 | case STATE_WRITE_CONFIGURATION_REGISTERS: |
| 269 | | if(bit < 8) { |
| 270 | | verboselog(2, "clock\n"); |
| 271 | | shift <<= 1; |
| 272 | | if(sdaw) |
| 273 | | shift |= 1; |
| 274 | | bit++; |
| 275 | | } else { |
| 276 | | sdar = false; |
| 275 | if( m_scl == 0 && state != 0 ) |
| 276 | { |
| 277 | if( m_bit < 8 ) |
| 278 | { |
| 279 | verboselog( 2, "clock\n" ); |
| 280 | m_shift <<= 1; |
| 277 | 281 | |
| 278 | | switch(state) { |
| 279 | | case STATE_LOAD_COMMAND: |
| 280 | | command = shift; |
| 281 | | verboselog(1, "-> command: %02x\n", command); |
| 282 | | /* todo: verify command is valid? */ |
| 283 | | state = STATE_LOAD_ADDRESS; |
| 284 | | break; |
| 285 | | case STATE_LOAD_ADDRESS: |
| 286 | | load_address(); |
| 287 | | break; |
| 288 | | case STATE_LOAD_PASSWORD: |
| 289 | | verboselog(1, "-> password: %02x\n", shift ); |
| 290 | | write_buffer[byte++] = shift; |
| 291 | | if(byte == SIZE_WRITE_BUFFER) |
| 292 | | state = STATE_VERIFY_PASSWORD; |
| 293 | | break; |
| 294 | | case STATE_VERIFY_PASSWORD: |
| 295 | | verboselog(1, "-> verify password: %02x\n", shift); |
| 296 | | /* todo: this should probably be handled as a command */ |
| 297 | | if(shift == 0xc0) { |
| 298 | | /* todo: this should take 10ms before it returns ok. */ |
| 299 | | if(!memcmp(password(), write_buffer, SIZE_WRITE_BUFFER)) |
| 300 | | password_ok(); |
| 301 | | else |
| 302 | | sdar = true; |
| 282 | if( m_sdaw != 0 ) |
| 283 | { |
| 284 | m_shift |= 1; |
| 303 | 285 | } |
| 304 | | break; |
| 305 | | case STATE_WRITE_DATA: |
| 306 | | verboselog(1, "-> data: %02x\n", shift); |
| 307 | | write_buffer[byte++] = shift; |
| 308 | | if(byte == SIZE_WRITE_BUFFER) { |
| 309 | | for(byte = 0; byte < SIZE_WRITE_BUFFER; byte++) |
| 310 | | data[data_offset()] = write_buffer[byte]; |
| 311 | | byte = 0; |
| 312 | | verboselog(1, "data flushed\n"); |
| 286 | |
| 287 | m_bit++; |
| 288 | } |
| 289 | else |
| 290 | { |
| 291 | m_sdar = 0; |
| 292 | |
| 293 | switch( m_state ) |
| 294 | { |
| 295 | case STATE_LOAD_COMMAND: |
| 296 | m_command = m_shift; |
| 297 | verboselog( 1, "-> command: %02x\n", m_command ); |
| 298 | /* todo: verify command is valid? */ |
| 299 | m_state = STATE_LOAD_ADDRESS; |
| 300 | break; |
| 301 | |
| 302 | case STATE_LOAD_ADDRESS: |
| 303 | load_address(); |
| 304 | break; |
| 305 | |
| 306 | case STATE_LOAD_PASSWORD: |
| 307 | verboselog( 1, "-> password: %02x\n", m_shift ); |
| 308 | m_write_buffer[ m_byte++ ] = m_shift; |
| 309 | |
| 310 | if( m_byte == sizeof( m_write_buffer ) ) |
| 311 | { |
| 312 | m_state = STATE_VERIFY_PASSWORD; |
| 313 | } |
| 314 | break; |
| 315 | |
| 316 | case STATE_VERIFY_PASSWORD: |
| 317 | verboselog( 1, "-> verify password: %02x\n", m_shift ); |
| 318 | |
| 319 | /* todo: this should probably be handled as a command */ |
| 320 | if( m_shift == 0xc0 ) |
| 321 | { |
| 322 | /* todo: this should take 10ms before it returns ok. */ |
| 323 | if( memcmp( password(), m_write_buffer, sizeof( m_write_buffer ) ) == 0 ) |
| 324 | { |
| 325 | password_ok(); |
| 326 | } |
| 327 | else |
| 328 | { |
| 329 | m_sdar = 1; |
| 330 | } |
| 331 | } |
| 332 | break; |
| 333 | |
| 334 | case STATE_WRITE_DATA: |
| 335 | verboselog( 2, "-> data: %02x\n", m_shift ); |
| 336 | m_write_buffer[ m_byte++ ] = m_shift; |
| 337 | |
| 338 | if( m_byte == sizeof( m_write_buffer ) ) |
| 339 | { |
| 340 | for( m_byte = 0; m_byte < sizeof( m_write_buffer ); m_byte++ ) |
| 341 | { |
| 342 | int offset = data_offset(); |
| 343 | verboselog( 1, "-> data[ %03x ]: %02x\n", offset, m_write_buffer[ m_byte ] ); |
| 344 | m_data[ offset ] = m_write_buffer[ m_byte ]; |
| 345 | } |
| 346 | m_byte = 0; |
| 347 | |
| 348 | verboselog( 1, "data flushed\n" ); |
| 349 | } |
| 350 | break; |
| 351 | |
| 352 | case STATE_WRITE_CONFIGURATION_REGISTERS: |
| 353 | verboselog( 1, "-> configuration register[ %d ]: %02x\n", m_byte, m_shift ); |
| 354 | /* todo: write after all bytes received? */ |
| 355 | m_configuration_registers[ m_byte++ ] = m_shift; |
| 356 | |
| 357 | if( m_byte == sizeof( m_configuration_registers ) ) |
| 358 | { |
| 359 | m_byte = 0; |
| 360 | } |
| 361 | break; |
| 313 | 362 | } |
| 314 | | break; |
| 315 | | case STATE_WRITE_CONFIGURATION_REGISTERS: |
| 316 | | verboselog(1, "-> configuration register: %02x\n", shift); |
| 317 | | /* todo: write after all bytes received? */ |
| 318 | | configuration_registers[byte++] = shift; |
| 319 | | if(byte == SIZE_CONFIGURATION_REGISTERS) |
| 320 | | byte = 0; |
| 321 | | break; |
| 363 | |
| 364 | m_bit = 0; |
| 365 | m_shift = 0; |
| 322 | 366 | } |
| 323 | | |
| 324 | | bit = 0; |
| 325 | | shift = 0; |
| 326 | 367 | } |
| 327 | 368 | break; |
| 369 | |
| 328 | 370 | case STATE_READ_DATA: |
| 329 | 371 | case STATE_READ_CONFIGURATION_REGISTERS: |
| 330 | | if(bit < 8) { |
| 331 | | if(bit == 0) { |
| 332 | | switch(state) { |
| 333 | | case STATE_READ_DATA: |
| 334 | | shift = data[data_offset()]; |
| 335 | | verboselog(1, "<- data: %02x\n", shift); |
| 336 | | break; |
| 337 | | case STATE_READ_CONFIGURATION_REGISTERS: |
| 338 | | shift = configuration_registers[byte & 7]; |
| 339 | | verboselog(1, "<- configuration register: %02x\n", shift ); |
| 340 | | break; |
| 372 | if( m_scl == 0 && state != 0 ) |
| 373 | { |
| 374 | if( m_bit < 8 ) |
| 375 | { |
| 376 | if( m_bit == 0 ) |
| 377 | { |
| 378 | int offset; |
| 379 | |
| 380 | switch( m_state ) |
| 381 | { |
| 382 | case STATE_READ_DATA: |
| 383 | offset = data_offset(); |
| 384 | m_shift = m_data[ offset ]; |
| 385 | verboselog( 1, "<- data[ %03x ]: %02x\n", offset, m_shift ); |
| 386 | break; |
| 387 | |
| 388 | case STATE_READ_CONFIGURATION_REGISTERS: |
| 389 | offset = m_byte & 7; |
| 390 | m_shift = m_configuration_registers[ offset ]; |
| 391 | verboselog( 1, "<- configuration register[ %d ]: %02x\n", offset, m_shift ); |
| 392 | break; |
| 393 | } |
| 341 | 394 | } |
| 395 | |
| 396 | m_sdar = ( m_shift >> 7 ) & 1; |
| 397 | m_shift <<= 1; |
| 398 | m_bit++; |
| 342 | 399 | } |
| 343 | | sdar = ( shift >> 7 ) & 1; |
| 344 | | shift <<= 1; |
| 345 | | bit++; |
| 346 | | } else { |
| 347 | | bit = 0; |
| 348 | | sdar = false; |
| 349 | | if(!sdaw) { |
| 350 | | verboselog(2, "ack <-\n"); |
| 351 | | byte++; |
| 352 | | } else { |
| 353 | | verboselog(2, "nak <-\n"); |
| 400 | else |
| 401 | { |
| 402 | m_bit = 0; |
| 403 | m_sdar = 0; |
| 404 | |
| 405 | if( m_sdaw == 0 ) |
| 406 | { |
| 407 | verboselog( 2, "ack <-\n" ); |
| 408 | m_byte++; |
| 409 | } |
| 410 | else |
| 411 | { |
| 412 | verboselog( 2, "nak <-\n" ); |
| 413 | } |
| 354 | 414 | } |
| 355 | 415 | } |
| 356 | 416 | break; |
| 357 | 417 | } |
| 358 | 418 | } |
| 419 | |
| 420 | m_scl = state; |
| 359 | 421 | } |
| 360 | 422 | |
| 361 | | void x76f041_device::sda_0() |
| 423 | WRITE_LINE_MEMBER( x76f041_device::write_sda ) |
| 362 | 424 | { |
| 363 | | if(!cs && scl) { |
| 364 | | switch(state) { |
| 365 | | case STATE_STOP: |
| 366 | | verboselog(1, "goto start (1)\n"); |
| 367 | | state = STATE_LOAD_COMMAND; |
| 368 | | break; |
| 369 | | case STATE_LOAD_PASSWORD: |
| 370 | | /* todo: this will be the 0xc0 command, but it's not handled as a command yet. */ |
| 371 | | verboselog(1, "goto start (2)\n"); |
| 372 | | break; |
| 373 | | case STATE_READ_DATA: |
| 374 | | verboselog(1, "goto load address\n"); |
| 375 | | state = STATE_LOAD_ADDRESS; |
| 376 | | break; |
| 377 | | default: |
| 378 | | verboselog(1, "skipped start (default)\n"); |
| 379 | | break; |
| 425 | if( m_sdaw != state ) |
| 426 | { |
| 427 | verboselog( 2, "sdaw=%d\n", state ); |
| 428 | } |
| 429 | |
| 430 | if( m_cs == 0 && m_scl != 0 ) |
| 431 | { |
| 432 | if( m_sdaw == 0 && state != 0 ) |
| 433 | { |
| 434 | verboselog( 1, "goto stop\n" ); |
| 435 | m_state = STATE_STOP; |
| 436 | m_sdar = 0; |
| 380 | 437 | } |
| 381 | 438 | |
| 382 | | bit = 0; |
| 383 | | byte = 0; |
| 384 | | shift = 0; |
| 385 | | sdar = false; |
| 439 | if( m_sdaw != 0 && state == 0 ) |
| 440 | { |
| 441 | switch( m_state ) |
| 442 | { |
| 443 | case STATE_STOP: |
| 444 | verboselog( 1, "goto start\n" ); |
| 445 | m_state = STATE_LOAD_COMMAND; |
| 446 | break; |
| 447 | |
| 448 | case STATE_LOAD_PASSWORD: |
| 449 | /* todo: this will be the 0xc0 command, but it's not handled as a command yet. */ |
| 450 | verboselog( 1, "goto start\n" ); |
| 451 | break; |
| 452 | |
| 453 | case STATE_READ_DATA: |
| 454 | verboselog( 1, "goto load address\n" ); |
| 455 | m_state = STATE_LOAD_ADDRESS; |
| 456 | break; |
| 457 | |
| 458 | default: |
| 459 | verboselog( 1, "skipped start (default)\n" ); |
| 460 | break; |
| 461 | } |
| 462 | |
| 463 | m_bit = 0; |
| 464 | m_byte = 0; |
| 465 | m_shift = 0; |
| 466 | m_sdar = 0; |
| 467 | } |
| 386 | 468 | } |
| 469 | |
| 470 | m_sdaw = state; |
| 387 | 471 | } |
| 388 | 472 | |
| 389 | | void x76f041_device::sda_1() |
| 473 | READ_LINE_MEMBER( x76f041_device::read_sda ) |
| 390 | 474 | { |
| 391 | | if(!cs && scl) { |
| 392 | | verboselog(1, "goto stop\n"); |
| 393 | | state = STATE_STOP; |
| 394 | | sdar = false; |
| 475 | if( m_cs != 0 ) |
| 476 | { |
| 477 | verboselog( 2, "not selected\n" ); |
| 478 | return 1; |
| 395 | 479 | } |
| 480 | |
| 481 | verboselog( 2, "sdar=%d\n", m_sdar ); |
| 482 | return m_sdar; |
| 396 | 483 | } |
| 397 | 484 | |
| 398 | | void x76f041_device::nvram_read(emu_file &file) |
| 485 | void x76f041_device::nvram_default() |
| 399 | 486 | { |
| 400 | | file.read(response_to_reset, SIZE_RESPONSE_TO_RESET); |
| 401 | | file.read(write_password, SIZE_WRITE_PASSWORD); |
| 402 | | file.read(read_password, SIZE_READ_PASSWORD); |
| 403 | | file.read(configuration_password, SIZE_CONFIGURATION_PASSWORD); |
| 404 | | file.read(configuration_registers, SIZE_CONFIGURATION_REGISTERS); |
| 405 | | file.read(data, SIZE_DATA); |
| 487 | m_response_to_reset[0] = 0x19; |
| 488 | m_response_to_reset[1] = 0x55; |
| 489 | m_response_to_reset[2] = 0xaa; |
| 490 | m_response_to_reset[3] = 0x55, |
| 491 | |
| 492 | memset( m_write_password, 0, sizeof( m_write_password ) ); |
| 493 | memset( m_read_password, 0, sizeof( m_read_password ) ); |
| 494 | memset( m_configuration_password, 0, sizeof( m_configuration_password ) ); |
| 495 | memset( m_configuration_registers, 0, sizeof( m_configuration_registers ) ); |
| 496 | memset( m_data, 0, sizeof( m_data ) ); |
| 497 | |
| 498 | int expected_bytes = sizeof( m_response_to_reset ) + sizeof( m_write_password ) + sizeof( m_read_password ) + |
| 499 | sizeof( m_configuration_password ) + sizeof( m_configuration_registers ) + sizeof( m_data ); |
| 500 | |
| 501 | if( !m_region ) |
| 502 | { |
| 503 | logerror( "x76f041(%s) region not found\n", tag() ); |
| 504 | } |
| 505 | else if( m_region->bytes() != expected_bytes ) |
| 506 | { |
| 507 | logerror( "x76f041(%s) region length 0x%x expected 0x%x\n", tag(), m_region->bytes(), expected_bytes ); |
| 508 | } |
| 509 | else |
| 510 | { |
| 511 | UINT8 *region = m_region->base(); |
| 512 | |
| 513 | memcpy( m_response_to_reset, region, sizeof( m_response_to_reset ) ); region += sizeof( m_response_to_reset ); |
| 514 | memcpy( m_write_password, region, sizeof( m_write_password ) ); region += sizeof( m_write_password ); |
| 515 | memcpy( m_read_password, region, sizeof( m_read_password ) ); region += sizeof( m_read_password ); |
| 516 | memcpy( m_configuration_password, region, sizeof( m_configuration_password ) ); region += sizeof( m_configuration_password ); |
| 517 | memcpy( m_configuration_registers, region, sizeof( m_configuration_registers ) ); region += sizeof( m_configuration_registers ); |
| 518 | memcpy( m_data, region, sizeof( m_data ) ); region += sizeof( m_data ); |
| 519 | } |
| 406 | 520 | } |
| 407 | 521 | |
| 408 | | void x76f041_device::nvram_write(emu_file &file) |
| 522 | void x76f041_device::nvram_read( emu_file &file ) |
| 409 | 523 | { |
| 410 | | file.write(response_to_reset, SIZE_RESPONSE_TO_RESET); |
| 411 | | file.write(write_password, SIZE_WRITE_PASSWORD); |
| 412 | | file.write(read_password, SIZE_READ_PASSWORD); |
| 413 | | file.write(configuration_password, SIZE_CONFIGURATION_PASSWORD); |
| 414 | | file.write(configuration_registers, SIZE_CONFIGURATION_REGISTERS); |
| 415 | | file.write(data, SIZE_DATA); |
| 524 | file.read( m_response_to_reset, sizeof( m_response_to_reset ) ); |
| 525 | file.read( m_write_password, sizeof( m_write_password ) ); |
| 526 | file.read( m_read_password, sizeof( m_read_password ) ); |
| 527 | file.read( m_configuration_password, sizeof( m_configuration_password ) ); |
| 528 | file.read( m_configuration_registers, sizeof( m_configuration_registers ) ); |
| 529 | file.read( m_data, sizeof( m_data ) ); |
| 416 | 530 | } |
| 531 | |
| 532 | void x76f041_device::nvram_write( emu_file &file ) |
| 533 | { |
| 534 | file.write( m_response_to_reset, sizeof( m_response_to_reset ) ); |
| 535 | file.write( m_write_password, sizeof( m_write_password ) ); |
| 536 | file.write( m_read_password, sizeof( m_read_password ) ); |
| 537 | file.write( m_configuration_password, sizeof( m_configuration_password ) ); |
| 538 | file.write( m_configuration_registers, sizeof( m_configuration_registers ) ); |
| 539 | file.write( m_data, sizeof( m_data ) ); |
| 540 | } |
trunk/src/mame/drivers/twinkle.c
| r26479 | r26480 | |
| 235 | 235 | #include "machine/am53cf96.h" |
| 236 | 236 | #include "machine/rtc65271.h" |
| 237 | 237 | #include "machine/i2cmem.h" |
| 238 | #include "machine/x76f041.h" |
| 238 | 239 | #include "machine/ataintf.h" |
| 239 | 240 | #include "sound/spu.h" |
| 240 | 241 | #include "sound/cdda.h" |
| r26479 | r26480 | |
| 903 | 904 | MCFG_SOUND_ROUTE( 1, "^^^speakerright", 1.0 ) |
| 904 | 905 | MACHINE_CONFIG_END |
| 905 | 906 | |
| 907 | static MACHINE_CONFIG_DERIVED( twinklex, twinkle ) |
| 908 | MCFG_X76F041_ADD( "security" ) |
| 909 | MACHINE_CONFIG_END |
| 910 | |
| 906 | 911 | static MACHINE_CONFIG_DERIVED( twinklei, twinkle ) |
| 907 | | MCFG_I2CMEM_ADD("security") |
| 908 | | MCFG_I2CMEM_DATA_SIZE(0x100) |
| 912 | MCFG_I2CMEM_ADD( "security" ) |
| 913 | MCFG_I2CMEM_DATA_SIZE( 0x100 ) |
| 909 | 914 | MACHINE_CONFIG_END |
| 910 | 915 | |
| 911 | 916 | static INPUT_PORTS_START( twinkle ) |
| r26479 | r26480 | |
| 958 | 963 | PORT_START("INSEC") |
| 959 | 964 | INPUT_PORTS_END |
| 960 | 965 | |
| 966 | static INPUT_PORTS_START( twinklex ) |
| 967 | PORT_INCLUDE( twinkle ) |
| 968 | |
| 969 | PORT_MODIFY("OUTSEC") |
| 970 | PORT_BIT( 0x00000010, IP_ACTIVE_HIGH, IPT_OUTPUT ) PORT_WRITE_LINE_DEVICE_MEMBER("security", x76f041_device, write_scl) |
| 971 | PORT_BIT( 0x00000008, IP_ACTIVE_HIGH, IPT_OUTPUT ) PORT_WRITE_LINE_DEVICE_MEMBER("security", x76f041_device, write_sda) |
| 972 | PORT_BIT( 0x00000004, IP_ACTIVE_HIGH, IPT_OUTPUT ) PORT_WRITE_LINE_DEVICE_MEMBER("security", x76f041_device, write_cs) |
| 973 | |
| 974 | PORT_MODIFY("INSEC") |
| 975 | PORT_BIT( 0x00001000, IP_ACTIVE_HIGH, IPT_OUTPUT ) PORT_READ_LINE_DEVICE_MEMBER("security", x76f041_device, read_sda) |
| 976 | INPUT_PORTS_END |
| 977 | |
| 961 | 978 | static INPUT_PORTS_START( twinklei ) |
| 962 | 979 | PORT_INCLUDE( twinkle ) |
| 963 | 980 | |
| r26479 | r26480 | |
| 985 | 1002 | ROM_START( bmiidx ) |
| 986 | 1003 | TWINKLE_BIOS |
| 987 | 1004 | |
| 988 | | ROM_REGION( 0x100, "security", 0 ) |
| 989 | | ROM_LOAD( "863a02", 0x000000, 0x000100, NO_DUMP ) |
| 1005 | ROM_REGION( 0x224, "security", 0 ) |
| 1006 | ROM_LOAD( "863a02", 0x000000, 0x000224, BAD_DUMP CRC(7b2a429b) SHA1(f710d19c7b900a58584c07ab8fd3ab7b9f0121d7) ) |
| 990 | 1007 | |
| 991 | 1008 | DISK_REGION( "scsi:cdrom" ) // program |
| 992 | 1009 | DISK_IMAGE_READONLY( "gq863-jab01", 0, SHA1(331f80b40ed560c7e017621b7daeeb8275d92b9a) ) |
| r26479 | r26480 | |
| 1001 | 1018 | ROM_START( bmiidxa ) |
| 1002 | 1019 | TWINKLE_BIOS |
| 1003 | 1020 | |
| 1004 | | ROM_REGION( 0x100, "security", 0 ) |
| 1005 | | ROM_LOAD( "863a02", 0x000000, 0x000100, NO_DUMP ) |
| 1021 | ROM_REGION( 0x224, "security", 0 ) |
| 1022 | ROM_LOAD( "863a02", 0x000000, 0x000224, BAD_DUMP CRC(7b2a429b) SHA1(f710d19c7b900a58584c07ab8fd3ab7b9f0121d7) ) |
| 1006 | 1023 | |
| 1007 | 1024 | DISK_REGION( "scsi:cdrom" ) // program |
| 1008 | 1025 | DISK_IMAGE_READONLY( "gq863a01", 0, SHA1(07fc467f6500504729becbaf77dabc093a134e65) ) |
| r26479 | r26480 | |
| 1161 | 1178 | ROM_START( bmiidxc ) |
| 1162 | 1179 | TWINKLE_BIOS |
| 1163 | 1180 | |
| 1164 | | ROM_REGION( 0x100, "security", 0 ) |
| 1165 | | ROM_LOAD( "896a02", 0x000000, 0x000100, NO_DUMP ) |
| 1181 | ROM_REGION( 0x224, "security", 0 ) |
| 1182 | ROM_LOAD( "896a02", 0x000000, 0x000224, BAD_DUMP CRC(7b2a429b) SHA1(f710d19c7b900a58584c07ab8fd3ab7b9f0121d7) ) |
| 1166 | 1183 | |
| 1167 | 1184 | DISK_REGION( "scsi:cdrom" ) |
| 1168 | 1185 | DISK_IMAGE_READONLY( "896jabbm", 0, BAD_DUMP SHA1(117ae4c876207bbaf9e8fe0fdf5bb161155c1bdb) ) |
| r26479 | r26480 | |
| 1177 | 1194 | ROM_START( bmiidxca ) |
| 1178 | 1195 | TWINKLE_BIOS |
| 1179 | 1196 | |
| 1180 | | ROM_REGION( 0x100, "security", 0 ) |
| 1181 | | ROM_LOAD( "896a02", 0x000000, 0x000100, NO_DUMP ) |
| 1197 | ROM_REGION( 0x224, "security", 0 ) |
| 1198 | ROM_LOAD( "896a02", 0x000000, 0x000224, BAD_DUMP CRC(7b2a429b) SHA1(f710d19c7b900a58584c07ab8fd3ab7b9f0121d7) ) |
| 1182 | 1199 | |
| 1183 | 1200 | DISK_REGION( "scsi:cdrom" ) |
| 1184 | 1201 | DISK_IMAGE_READONLY( "896jaabm", 0, SHA1(ea7205f86543d9273efcc226666ab530c32b23c1) ) |
| r26479 | r26480 | |
| 1193 | 1210 | ROM_START( bmiidxs ) |
| 1194 | 1211 | TWINKLE_BIOS |
| 1195 | 1212 | |
| 1196 | | ROM_REGION( 0x100, "security", 0 ) |
| 1197 | | ROM_LOAD( "983a02", 0x000000, 0x000100, NO_DUMP ) |
| 1213 | ROM_REGION( 0x224, "security", 0 ) |
| 1214 | ROM_LOAD( "983a02", 0x000000, 0x000224, NO_DUMP ) |
| 1198 | 1215 | |
| 1199 | 1216 | DISK_REGION( "scsi:cdrom" ) |
| 1200 | 1217 | DISK_IMAGE_READONLY( "gc983a01", 0, NO_DUMP ) |
| r26479 | r26480 | |
| 1209 | 1226 | ROM_START( bmiidxc2 ) |
| 1210 | 1227 | TWINKLE_BIOS |
| 1211 | 1228 | |
| 1212 | | ROM_REGION( 0x100, "security", 0 ) |
| 1213 | | ROM_LOAD( "984a02", 0x000000, 0x000100, NO_DUMP ) |
| 1229 | ROM_REGION( 0x224, "security", 0 ) |
| 1230 | ROM_LOAD( "984a02", 0x000000, 0x000224, BAD_DUMP CRC(5b08e1ef) SHA1(d43ad5d958313ccb2420246621d9180230b4782d) ) |
| 1214 | 1231 | |
| 1215 | 1232 | DISK_REGION( "scsi:cdrom" ) |
| 1216 | 1233 | DISK_IMAGE_READONLY( "ge984a01(bm)", 0, SHA1(03b083ba09652dfab6f328000c3c9de2a7a4e618) ) |
| r26479 | r26480 | |
| 1224 | 1241 | |
| 1225 | 1242 | GAME( 1999, gq863, 0, twinkle, twinkle, driver_device, 0, ROT0, "Konami", "Twinkle System", GAME_IS_BIOS_ROOT ) |
| 1226 | 1243 | |
| 1227 | | GAME( 1999, bmiidx, gq863, twinkle, twinkle, driver_device, 0, ROT0, "Konami", "beatmania IIDX (863 JAB)", GAME_IMPERFECT_SOUND | GAME_IMPERFECT_GRAPHICS | GAME_NOT_WORKING ) |
| 1228 | | GAME( 1999, bmiidxa, bmiidx, twinkle, twinkle, driver_device, 0, ROT0, "Konami", "beatmania IIDX (863 JAA)", GAME_IMPERFECT_SOUND | GAME_IMPERFECT_GRAPHICS | GAME_NOT_WORKING ) |
| 1229 | | GAME( 1999, bmiidxc, gq863, twinkle, twinkle, driver_device, 0, ROT0, "Konami", "beatmania IIDX with DDR 2nd Club Version (896 JAB)", GAME_IMPERFECT_SOUND | GAME_IMPERFECT_GRAPHICS | GAME_NOT_WORKING ) |
| 1230 | | GAME( 1999, bmiidxca, bmiidxc, twinkle, twinkle, driver_device, 0, ROT0, "Konami", "beatmania IIDX with DDR 2nd Club Version (896 JAA)", GAME_IMPERFECT_SOUND | GAME_IMPERFECT_GRAPHICS | GAME_NOT_WORKING ) |
| 1231 | | GAME( 1999, bmiidxs, gq863, twinkle, twinkle, driver_device, 0, ROT0, "Konami", "beatmania IIDX Substream (983 JAA)", GAME_IMPERFECT_SOUND | GAME_IMPERFECT_GRAPHICS | GAME_NOT_WORKING ) |
| 1232 | | GAME( 1999, bmiidxc2, gq863, twinkle, twinkle, driver_device, 0, ROT0, "Konami", "Beatmania IIDX Substream with DDR 2nd Club Version 2 (984 A01 BM)", GAME_IMPERFECT_SOUND | GAME_IMPERFECT_GRAPHICS | GAME_NOT_WORKING ) |
| 1244 | GAME( 1999, bmiidx, gq863, twinklex, twinklex, driver_device, 0, ROT0, "Konami", "beatmania IIDX (863 JAB)", GAME_IMPERFECT_SOUND | GAME_IMPERFECT_GRAPHICS | GAME_NOT_WORKING ) |
| 1245 | GAME( 1999, bmiidxa, bmiidx, twinklex, twinklex, driver_device, 0, ROT0, "Konami", "beatmania IIDX (863 JAA)", GAME_IMPERFECT_SOUND | GAME_IMPERFECT_GRAPHICS | GAME_NOT_WORKING ) |
| 1246 | GAME( 1999, bmiidxc, gq863, twinklex, twinklex, driver_device, 0, ROT0, "Konami", "beatmania IIDX with DDR 2nd Club Version (896 JAB)", GAME_IMPERFECT_SOUND | GAME_IMPERFECT_GRAPHICS | GAME_NOT_WORKING ) |
| 1247 | GAME( 1999, bmiidxca, bmiidxc, twinklex, twinklex, driver_device, 0, ROT0, "Konami", "beatmania IIDX with DDR 2nd Club Version (896 JAA)", GAME_IMPERFECT_SOUND | GAME_IMPERFECT_GRAPHICS | GAME_NOT_WORKING ) |
| 1248 | GAME( 1999, bmiidxs, gq863, twinklex, twinklex, driver_device, 0, ROT0, "Konami", "beatmania IIDX Substream (983 JAA)", GAME_IMPERFECT_SOUND | GAME_IMPERFECT_GRAPHICS | GAME_NOT_WORKING ) |
| 1249 | GAME( 1999, bmiidxc2, gq863, twinklex, twinklex, driver_device, 0, ROT0, "Konami", "Beatmania IIDX Substream with DDR 2nd Club Version 2 (984 A01 BM)", GAME_IMPERFECT_SOUND | GAME_IMPERFECT_GRAPHICS | GAME_NOT_WORKING ) |
| 1233 | 1250 | GAME( 1999, bmiidx2, gq863, twinklei, twinklei, driver_device, 0, ROT0, "Konami", "beatmania IIDX 2nd style (GC985 JAA)", GAME_IMPERFECT_SOUND | GAME_IMPERFECT_GRAPHICS | GAME_NOT_WORKING ) |
| 1234 | 1251 | GAME( 2000, bmiidx3, gq863, twinklei, twinklei, driver_device, 0, ROT0, "Konami", "beatmania IIDX 3rd style (GC992 JAC)", GAME_IMPERFECT_SOUND | GAME_IMPERFECT_GRAPHICS | GAME_NOT_WORKING ) |
| 1235 | 1252 | GAME( 2000, bmiidx3a, bmiidx3, twinklei, twinklei, driver_device, 0, ROT0, "Konami", "beatmania IIDX 3rd style (GC992 JAA)", GAME_IMPERFECT_SOUND | GAME_IMPERFECT_GRAPHICS | GAME_NOT_WORKING ) |
trunk/src/mame/machine/zs01.c
| r26479 | r26480 | |
| 1 | // license:MAME |
| 2 | // copyright-holders:smf |
| 1 | 3 | /* |
| 2 | 4 | * zs01.c |
| 3 | 5 | * |
| r26479 | r26480 | |
| 7 | 9 | * |
| 8 | 10 | */ |
| 9 | 11 | |
| 10 | | #include "emu.h" |
| 11 | 12 | #include "machine/zs01.h" |
| 12 | 13 | |
| 13 | | #define VERBOSE_LEVEL 0 |
| 14 | #define VERBOSE_LEVEL ( 0 ) |
| 14 | 15 | |
| 15 | | inline void ATTR_PRINTF(3,4) zs01_device::verboselog(int n_level, const char *s_fmt, ...) |
| 16 | inline void ATTR_PRINTF( 3, 4 ) zs01_device::verboselog( int n_level, const char *s_fmt, ... ) |
| 16 | 17 | { |
| 17 | | if(VERBOSE_LEVEL >= n_level) |
| 18 | if( VERBOSE_LEVEL >= n_level ) |
| 18 | 19 | { |
| 19 | 20 | va_list v; |
| 20 | | char buf[32768]; |
| 21 | | va_start(v, s_fmt); |
| 22 | | vsprintf(buf, s_fmt, v); |
| 23 | | va_end(v); |
| 24 | | logerror("zs01 %s %s: %s", tag(), machine().describe_context(), buf); |
| 21 | char buf[ 32768 ]; |
| 22 | va_start( v, s_fmt ); |
| 23 | vsprintf( buf, s_fmt, v ); |
| 24 | va_end( v ); |
| 25 | logerror( "%s: zs01(%s) %s", machine().describe_context(), tag(), buf ); |
| 25 | 26 | } |
| 26 | 27 | } |
| 27 | 28 | |
| 28 | 29 | // device type definition |
| 29 | 30 | const device_type ZS01 = &device_creator<zs01_device>; |
| 30 | 31 | |
| 31 | | void zs01_device::static_set_ds2401_tag(device_t &device, const char *ds2401_tag) |
| 32 | zs01_device::zs01_device( const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock ) |
| 33 | : device_t( mconfig, ZS01, "ZS01", tag, owner, clock, "zs01", __FILE__ ), |
| 34 | device_nvram_interface(mconfig, *this), |
| 35 | m_cs( 0 ), |
| 36 | m_rst( 0 ), |
| 37 | m_scl( 0 ), |
| 38 | m_sdaw( 0 ), |
| 39 | m_sdar( 0 ), |
| 40 | m_state( STATE_STOP ), |
| 41 | m_shift( 0 ), |
| 42 | m_bit( 0 ), |
| 43 | m_byte( 0 ) |
| 32 | 44 | { |
| 33 | | zs01_device &zs01 = downcast<zs01_device &>(device); |
| 34 | | zs01.ds2401_tag = ds2401_tag; |
| 35 | 45 | } |
| 36 | 46 | |
| 37 | | zs01_device::zs01_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 38 | | : device_secure_serial_flash(mconfig, ZS01, "ZS01", tag, owner, clock, "zs01", __FILE__) |
| 39 | | { |
| 40 | | } |
| 41 | | |
| 42 | 47 | void zs01_device::device_start() |
| 43 | 48 | { |
| 44 | | device_secure_serial_flash::device_start(); |
| 45 | | save_item(NAME(state)); |
| 46 | | save_item(NAME(shift)); |
| 47 | | save_item(NAME(bit)); |
| 48 | | save_item(NAME(byte)); |
| 49 | | save_item(NAME(write_buffer)); |
| 50 | | save_item(NAME(read_buffer)); |
| 51 | | save_item(NAME(response_key)); |
| 52 | | save_item(NAME(response_to_reset)); |
| 53 | | save_item(NAME(command_key)); |
| 54 | | save_item(NAME(data_key)); |
| 55 | | |
| 56 | | m_ds2401 = siblingdevice<ds2401_device>(ds2401_tag); |
| 49 | m_ds2401 = siblingdevice<ds2401_device>(m_ds2401_tag); |
| 57 | 50 | if( m_ds2401 == NULL ) |
| 58 | 51 | { |
| 59 | | logerror( "ds2401 '%s' not found\n", ds2401_tag ); |
| 52 | logerror( "ds2401 '%s' not found\n", m_ds2401_tag ); |
| 60 | 53 | } |
| 61 | | } |
| 62 | 54 | |
| 63 | | void zs01_device::device_reset() |
| 64 | | { |
| 65 | | device_secure_serial_flash::device_reset(); |
| 66 | | state = STATE_STOP; |
| 67 | | shift = 0; |
| 68 | | bit = 0; |
| 69 | | byte = 0; |
| 70 | | memset(write_buffer, 0, SIZE_WRITE_BUFFER); |
| 71 | | memset(read_buffer, 0, SIZE_READ_BUFFER); |
| 72 | | memset(response_key, 0, SIZE_KEY); |
| 55 | memset( m_write_buffer, 0, sizeof( m_write_buffer ) ); |
| 56 | memset( m_read_buffer, 0, sizeof( m_read_buffer ) ); |
| 57 | memset( m_response_key, 0, sizeof( m_response_key ) ); |
| 58 | |
| 59 | save_item( NAME( m_cs ) ); |
| 60 | save_item( NAME( m_rst ) ); |
| 61 | save_item( NAME( m_scl ) ); |
| 62 | save_item( NAME( m_sdaw ) ); |
| 63 | save_item( NAME( m_sdar ) ); |
| 64 | save_item( NAME( m_state ) ); |
| 65 | save_item( NAME( m_shift ) ); |
| 66 | save_item( NAME( m_bit ) ); |
| 67 | save_item( NAME( m_byte ) ); |
| 68 | save_item( NAME( m_write_buffer ) ); |
| 69 | save_item( NAME( m_read_buffer ) ); |
| 70 | save_item( NAME( m_response_key ) ); |
| 71 | save_item( NAME( m_response_to_reset ) ); |
| 72 | save_item( NAME( m_command_key ) ); |
| 73 | save_item( NAME( m_data_key ) ); |
| 74 | save_item( NAME( m_data ) ); |
| 73 | 75 | } |
| 74 | 76 | |
| 75 | | void zs01_device::nvram_default() |
| 77 | WRITE_LINE_MEMBER( zs01_device::write_rst ) |
| 76 | 78 | { |
| 77 | | // region always wins |
| 78 | | if(m_region) |
| 79 | if( m_rst != state ) |
| 79 | 80 | { |
| 80 | | // Ensure the size is correct though |
| 81 | | if(m_region->bytes() != SIZE_RESPONSE_TO_RESET+SIZE_KEY+SIZE_KEY+SIZE_DATA) |
| 82 | | logerror("zs01 %s: Wrong region length for initialization data, expected 0x%x, got 0x%x\n", |
| 83 | | tag(), |
| 84 | | SIZE_RESPONSE_TO_RESET+SIZE_KEY+SIZE_KEY+SIZE_DATA, |
| 85 | | m_region->bytes()); |
| 86 | | else { |
| 87 | | UINT8 *rb = m_region->base(); |
| 88 | | int offset = 0; |
| 89 | | memcpy(response_to_reset, rb + offset, SIZE_RESPONSE_TO_RESET); offset += SIZE_RESPONSE_TO_RESET; |
| 90 | | memcpy(command_key, rb + offset, SIZE_KEY); offset += SIZE_KEY; |
| 91 | | memcpy(data_key, rb + offset, SIZE_KEY); offset += SIZE_KEY; |
| 92 | | memcpy(data, rb + offset, SIZE_DATA); offset += SIZE_DATA; |
| 93 | | return; |
| 94 | | } |
| 81 | verboselog( 2, "rst=%d\n", state ); |
| 95 | 82 | } |
| 96 | 83 | |
| 97 | | // That chip isn't really usable without the passwords, so bitch |
| 98 | | // if there's no region |
| 99 | | logerror("zs01 %s: Warning, no default data provided, chip is unusable.\n", tag()); |
| 100 | | memset(response_to_reset, 0, SIZE_RESPONSE_TO_RESET); |
| 101 | | memset(command_key, 0, SIZE_KEY); |
| 102 | | memset(data_key, 0, SIZE_KEY); |
| 103 | | memset(data, 0, SIZE_DATA); |
| 104 | | } |
| 84 | if( m_rst == 0 && state != 0 && m_cs == 0 ) |
| 85 | { |
| 86 | verboselog( 1, "goto response to reset\n" ); |
| 87 | m_state = STATE_RESPONSE_TO_RESET; |
| 88 | m_bit = 0; |
| 89 | m_byte = 0; |
| 90 | } |
| 105 | 91 | |
| 106 | | void zs01_device::cs_0() |
| 107 | | { |
| 92 | m_rst = state; |
| 108 | 93 | } |
| 109 | 94 | |
| 110 | | void zs01_device::cs_1() |
| 95 | WRITE_LINE_MEMBER( zs01_device::write_cs ) |
| 111 | 96 | { |
| 112 | | } |
| 97 | if( m_cs != state ) |
| 98 | { |
| 99 | verboselog( 2, "cs=%d\n", state ); |
| 100 | } |
| 113 | 101 | |
| 114 | | void zs01_device::rst_0() |
| 115 | | { |
| 116 | | } |
| 102 | // if( m_cs != 0 && state == 0 ) |
| 103 | // { |
| 104 | // /* enable chip */ |
| 105 | // m_state = STATE_STOP; |
| 106 | // } |
| 117 | 107 | |
| 118 | | void zs01_device::rst_1() |
| 119 | | { |
| 120 | | if(!cs) { |
| 121 | | verboselog(1, "goto response to reset\n"); |
| 122 | | state = STATE_RESPONSE_TO_RESET; |
| 123 | | bit = 0; |
| 124 | | byte = 0; |
| 125 | | } |
| 108 | // if( m_cs == 0 && state != 0 ) |
| 109 | // { |
| 110 | // /* disable chip */ |
| 111 | // m_state = STATE_STOP; |
| 112 | // /* high impendence? */ |
| 113 | // m_sdar = 0; |
| 114 | // } |
| 115 | |
| 116 | m_cs = state; |
| 126 | 117 | } |
| 127 | 118 | |
| 128 | | void zs01_device::decrypt(UINT8 *destination, UINT8 *source, int length, UINT8 *key, UINT8 previous_byte) |
| 119 | void zs01_device::decrypt( UINT8 *destination, UINT8 *source, int length, UINT8 *key, UINT8 previous_byte ) |
| 129 | 120 | { |
| 130 | 121 | UINT32 a0; |
| 131 | 122 | UINT32 v1; |
| r26479 | r26480 | |
| 172 | 163 | } |
| 173 | 164 | } |
| 174 | 165 | |
| 175 | | void zs01_device::decrypt2(UINT8 *destination, UINT8 *source, int length, UINT8 *key, UINT8 previous_byte) |
| 166 | void zs01_device::decrypt2( UINT8 *destination, UINT8 *source, int length, UINT8 *key, UINT8 previous_byte ) |
| 176 | 167 | { |
| 177 | 168 | UINT32 a0; |
| 178 | 169 | UINT32 v1; |
| r26479 | r26480 | |
| 220 | 211 | } |
| 221 | 212 | } |
| 222 | 213 | |
| 223 | | void zs01_device::encrypt(UINT8 *destination, UINT8 *source, int length, UINT8 *key, UINT32 previous_byte) |
| 214 | void zs01_device::encrypt( UINT8 *destination, UINT8 *source, int length, UINT8 *key, UINT32 previous_byte ) |
| 224 | 215 | { |
| 225 | 216 | UINT32 t0; |
| 226 | 217 | UINT32 v0; |
| r26479 | r26480 | |
| 268 | 259 | } |
| 269 | 260 | } |
| 270 | 261 | |
| 271 | | UINT16 zs01_device::do_crc(UINT8 *buffer, UINT32 length) |
| 262 | UINT16 zs01_device::calc_crc( UINT8 *buffer, UINT32 length ) |
| 272 | 263 | { |
| 273 | 264 | UINT32 v1; |
| 274 | 265 | UINT32 a3; |
| r26479 | r26480 | |
| 318 | 309 | |
| 319 | 310 | int zs01_device::data_offset() |
| 320 | 311 | { |
| 321 | | int block = ( (write_buffer[0] & 2 ) << 7 ) | write_buffer[1]; |
| 312 | int block = ( ( m_write_buffer[ 0 ] & 2 ) << 7 ) | m_write_buffer[ 1 ]; |
| 322 | 313 | |
| 323 | 314 | return block * SIZE_DATA_BUFFER; |
| 324 | 315 | } |
| 325 | 316 | |
| 326 | | void zs01_device::scl_0() |
| 317 | WRITE_LINE_MEMBER( zs01_device::write_scl ) |
| 327 | 318 | { |
| 328 | | if(!cs) { |
| 329 | | switch(state) { |
| 319 | if( m_scl != state ) |
| 320 | { |
| 321 | verboselog( 2, "scl=%d\n", state ); |
| 322 | } |
| 323 | |
| 324 | if( m_cs == 0 ) |
| 325 | { |
| 326 | switch( m_state ) |
| 327 | { |
| 330 | 328 | case STATE_STOP: |
| 331 | 329 | break; |
| 332 | 330 | |
| 333 | 331 | case STATE_RESPONSE_TO_RESET: |
| 334 | | if(!bit) { |
| 335 | | shift = response_to_reset[byte]; |
| 336 | | verboselog(1, "<- response_to_reset[%d]: %02x\n", byte, shift); |
| 337 | | } |
| 332 | if( m_scl != 0 && state == 0 ) |
| 333 | { |
| 334 | if( m_bit == 0 ) |
| 335 | { |
| 336 | m_shift = m_response_to_reset[ m_byte ]; |
| 337 | verboselog( 1, "<- response_to_reset[ %d ]: %02x\n", m_byte, m_shift ); |
| 338 | } |
| 338 | 339 | |
| 339 | | sdar = (shift >> 7) & 1; |
| 340 | | shift <<= 1; |
| 341 | | bit++; |
| 340 | m_sdar = ( m_shift >> 7 ) & 1; |
| 341 | m_shift <<= 1; |
| 342 | m_bit++; |
| 342 | 343 | |
| 343 | | if( bit == 8 ) { |
| 344 | | bit = 0; |
| 345 | | byte++; |
| 346 | | if( byte == 4 ) { |
| 347 | | sdar = true; |
| 348 | | verboselog(1, "goto stop\n"); |
| 349 | | state = STATE_STOP; |
| 344 | if( m_bit == 8 ) |
| 345 | { |
| 346 | m_bit = 0; |
| 347 | m_byte++; |
| 348 | |
| 349 | if( m_byte == sizeof( m_response_to_reset ) ) |
| 350 | { |
| 351 | m_sdar = 1; |
| 352 | verboselog( 1, "goto stop\n" ); |
| 353 | m_state = STATE_STOP; |
| 354 | } |
| 350 | 355 | } |
| 351 | 356 | } |
| 352 | 357 | break; |
| 353 | 358 | |
| 354 | 359 | case STATE_LOAD_COMMAND: |
| 355 | | break; |
| 360 | if( m_scl == 0 && state != 0 ) |
| 361 | { |
| 362 | if( m_bit < 8 ) |
| 363 | { |
| 364 | verboselog( 2, "clock\n" ); |
| 365 | m_shift <<= 1; |
| 356 | 366 | |
| 357 | | case STATE_READ_DATA: |
| 358 | | break; |
| 359 | | } |
| 360 | | } |
| 361 | | } |
| 367 | if( m_sdaw != 0 ) |
| 368 | { |
| 369 | m_shift |= 1; |
| 370 | } |
| 362 | 371 | |
| 363 | | void zs01_device::scl_1() |
| 364 | | { |
| 365 | | if(!cs) { |
| 366 | | switch(state) { |
| 367 | | case STATE_STOP: |
| 368 | | break; |
| 372 | m_bit++; |
| 373 | } |
| 374 | else |
| 375 | { |
| 376 | m_sdar = 0; |
| 369 | 377 | |
| 370 | | case STATE_RESPONSE_TO_RESET: |
| 371 | | break; |
| 378 | switch( m_state ) |
| 379 | { |
| 380 | case STATE_LOAD_COMMAND: |
| 381 | m_write_buffer[ m_byte ] = m_shift; |
| 382 | verboselog( 2, "-> write_buffer[ %d ]: %02x\n", m_byte, m_write_buffer[ m_byte ] ); |
| 372 | 383 | |
| 373 | | case STATE_LOAD_COMMAND: |
| 374 | | if(bit < 8) { |
| 375 | | shift <<= 1; |
| 376 | | if(sdaw) |
| 377 | | shift |= 1; |
| 378 | | bit++; |
| 379 | | verboselog(2, "clock %d %02x\n", bit, shift); |
| 380 | | } else { |
| 381 | | sdar = false; |
| 384 | m_byte++; |
| 385 | if( m_byte == sizeof( m_write_buffer ) ) |
| 386 | { |
| 387 | decrypt( m_write_buffer, m_write_buffer, sizeof( m_write_buffer ), m_command_key, 0xff ); |
| 382 | 388 | |
| 383 | | switch(state) { |
| 384 | | case STATE_LOAD_COMMAND: |
| 385 | | write_buffer[byte] = shift; |
| 386 | | verboselog(2, "-> write_buffer[%d]: %02x\n", byte, write_buffer[byte]); |
| 387 | | byte++; |
| 388 | | if(byte == SIZE_WRITE_BUFFER) { |
| 389 | | UINT16 crc; |
| 389 | if( ( m_write_buffer[ 0 ] & 4 ) != 0 ) |
| 390 | { |
| 391 | decrypt2( &m_write_buffer[ 2 ], &m_write_buffer[ 2 ], SIZE_DATA_BUFFER, m_data_key, 0x00 ); |
| 392 | } |
| 390 | 393 | |
| 391 | | decrypt(write_buffer, write_buffer, SIZE_WRITE_BUFFER, command_key, 0xff); |
| 394 | UINT16 crc = calc_crc( m_write_buffer, 10 ); |
| 392 | 395 | |
| 393 | | if(write_buffer[0] & 4) |
| 394 | | decrypt2(&write_buffer[2], &write_buffer[2], SIZE_DATA_BUFFER, data_key, 0x00); |
| 396 | if( crc == ( ( m_write_buffer[ 10 ] << 8 ) | m_write_buffer[ 11 ] ) ) |
| 397 | { |
| 398 | verboselog( 1, "-> command: %02x\n", m_write_buffer[ 0 ] ); |
| 399 | verboselog( 1, "-> address: %02x\n", m_write_buffer[ 1 ] ); |
| 400 | verboselog( 1, "-> data: %02x%02x%02x%02x%02x%02x%02x%02x\n", |
| 401 | m_write_buffer[ 2 ], m_write_buffer[ 3 ], m_write_buffer[ 4 ], m_write_buffer[ 5 ], |
| 402 | m_write_buffer[ 6 ], m_write_buffer[ 7 ], m_write_buffer[ 8 ], m_write_buffer[ 9 ] ); |
| 403 | verboselog( 1, "-> crc: %02x%02x\n", m_write_buffer[ 10 ], m_write_buffer[ 11 ] ); |
| 395 | 404 | |
| 396 | | crc = do_crc(write_buffer, 10); |
| 405 | switch( m_write_buffer[ 0 ] & 1 ) |
| 406 | { |
| 407 | case COMMAND_WRITE: |
| 408 | memcpy( &m_data[ data_offset() ], &m_write_buffer[ 2 ], SIZE_DATA_BUFFER ); |
| 397 | 409 | |
| 398 | | if(crc == ((write_buffer[10] << 8) | write_buffer[11])) { |
| 399 | | verboselog(1, "-> command: %02x\n", write_buffer[0]); |
| 400 | | verboselog(1, "-> address: %02x\n", write_buffer[1]); |
| 401 | | verboselog(1, "-> data: %02x%02x%02x%02x%02x%02x%02x%02x\n", |
| 402 | | write_buffer[2], write_buffer[3], write_buffer[4], write_buffer[5], |
| 403 | | write_buffer[6], write_buffer[7], write_buffer[8], write_buffer[9]); |
| 404 | | verboselog(1, "-> crc: %02x%02x\n", write_buffer[10], write_buffer[11]); |
| 405 | | switch(write_buffer[0] & 1) { |
| 406 | | case COMMAND_WRITE: |
| 407 | | memcpy(&data[data_offset()], &write_buffer[2], SIZE_DATA_BUFFER); |
| 410 | /* todo: find out what should be returned. */ |
| 411 | memset( &m_read_buffer[ 0 ], 0, sizeof( m_write_buffer ) ); |
| 412 | break; |
| 408 | 413 | |
| 409 | | /* todo: find out what should be returned. */ |
| 410 | | memset(&read_buffer[0] , 0, SIZE_WRITE_BUFFER); |
| 411 | | break; |
| 414 | case COMMAND_READ: |
| 415 | /* todo: find out what should be returned. */ |
| 416 | memset( &m_read_buffer[ 0 ], 0, 2 ); |
| 412 | 417 | |
| 413 | | case COMMAND_READ: |
| 414 | | /* todo: find out what should be returned. */ |
| 415 | | memset(&read_buffer[0], 0, 2); |
| 418 | switch( m_write_buffer[ 1 ] ) |
| 419 | { |
| 420 | case 0xfd: |
| 421 | { |
| 422 | /* TODO: use read/write to talk to the ds2401, which will require a timer. */ |
| 423 | for( int i = 0; i < SIZE_DATA_BUFFER; i++ ) |
| 424 | { |
| 425 | m_read_buffer[ 2 + i ] = m_ds2401->direct_read( SIZE_DATA_BUFFER - i - 1 ); |
| 426 | } |
| 427 | } |
| 428 | break; |
| 416 | 429 | |
| 417 | | switch(write_buffer[1]) { |
| 418 | | case 0xfd: { |
| 419 | | /* TODO: use read/write to talk to the ds2401, which will require a timer. */ |
| 420 | | if( m_ds2401 != NULL ) |
| 421 | | for(int i = 0; i < SIZE_DATA_BUFFER; i++) |
| 422 | | read_buffer[2+i] = m_ds2401->direct_read(SIZE_DATA_BUFFER-i-1); |
| 430 | default: |
| 431 | memcpy( &m_read_buffer[ 2 ], &m_data[ data_offset() ], SIZE_DATA_BUFFER ); |
| 432 | break; |
| 433 | } |
| 434 | |
| 435 | memcpy( m_response_key, &m_write_buffer[ 2 ], sizeof( m_response_key ) ); |
| 423 | 436 | break; |
| 424 | 437 | } |
| 425 | | default: |
| 426 | | memcpy(&read_buffer[2], &data[data_offset()], SIZE_DATA_BUFFER); |
| 427 | | break; |
| 428 | | } |
| 438 | } |
| 439 | else |
| 440 | { |
| 441 | verboselog( 0, "bad crc\n" ); |
| 429 | 442 | |
| 430 | | memcpy(response_key, &write_buffer[2], SIZE_KEY); |
| 431 | | break; |
| 443 | /* todo: find out what should be returned. */ |
| 444 | memset( &m_read_buffer[ 0 ], 0xff, 2 ); |
| 432 | 445 | } |
| 433 | | } else { |
| 434 | | verboselog(0, "bad crc\n"); |
| 435 | | /* todo: find out what should be returned. */ |
| 436 | | memset(&read_buffer[0], 0xff, 2 ); |
| 437 | | } |
| 438 | 446 | |
| 439 | | verboselog(1, "<- status: %02x%02x\n", |
| 440 | | read_buffer[0], read_buffer[1]); |
| 447 | verboselog( 1, "<- status: %02x%02x\n", |
| 448 | m_read_buffer[ 0 ], m_read_buffer[ 1 ] ); |
| 441 | 449 | |
| 442 | | verboselog(1, "<- data: %02x%02x%02x%02x%02x%02x%02x%02x\n", |
| 443 | | read_buffer[2], read_buffer[3], read_buffer[4], read_buffer[5], |
| 444 | | read_buffer[6], read_buffer[7], read_buffer[8], read_buffer[9]); |
| 450 | verboselog( 1, "<- data: %02x%02x%02x%02x%02x%02x%02x%02x\n", |
| 451 | m_read_buffer[ 2 ], m_read_buffer[ 3 ], m_read_buffer[ 4 ], m_read_buffer[ 5 ], |
| 452 | m_read_buffer[ 6 ], m_read_buffer[ 7 ], m_read_buffer[ 8 ], m_read_buffer[ 9 ] ); |
| 445 | 453 | |
| 446 | | crc = do_crc(read_buffer, 10); |
| 447 | | read_buffer[10] = crc >> 8; |
| 448 | | read_buffer[11] = crc & 255; |
| 454 | crc = calc_crc( m_read_buffer, 10 ); |
| 455 | m_read_buffer[ 10 ] = crc >> 8; |
| 456 | m_read_buffer[ 11 ] = crc & 255; |
| 449 | 457 | |
| 450 | | encrypt(read_buffer, read_buffer, SIZE_READ_BUFFER, response_key, 0xff); |
| 458 | encrypt( m_read_buffer, m_read_buffer, sizeof( m_read_buffer ), m_response_key, 0xff ); |
| 451 | 459 | |
| 452 | | byte = 0; |
| 453 | | state = STATE_READ_DATA; |
| 460 | m_byte = 0; |
| 461 | m_state = STATE_READ_DATA; |
| 462 | } |
| 463 | break; |
| 454 | 464 | } |
| 455 | | break; |
| 465 | |
| 466 | m_bit = 0; |
| 467 | m_shift = 0; |
| 456 | 468 | } |
| 457 | | |
| 458 | | bit = 0; |
| 459 | | shift = 0; |
| 460 | 469 | } |
| 461 | 470 | break; |
| 462 | 471 | |
| 463 | 472 | case STATE_READ_DATA: |
| 464 | | if(bit < 8) { |
| 465 | | if(bit == 0) { |
| 466 | | switch(state) { |
| 467 | | case STATE_READ_DATA: |
| 468 | | shift = read_buffer[byte]; |
| 469 | | verboselog(2, "<- read_buffer[%d]: %02x\n", byte, shift); |
| 470 | | break; |
| 473 | if( m_scl == 0 && state != 0 ) |
| 474 | { |
| 475 | if( m_bit < 8 ) |
| 476 | { |
| 477 | if( m_bit == 0 ) |
| 478 | { |
| 479 | switch( m_state ) |
| 480 | { |
| 481 | case STATE_READ_DATA: |
| 482 | m_shift = m_read_buffer[ m_byte ]; |
| 483 | verboselog( 2, "<- read_buffer[ %d ]: %02x\n", m_byte, m_shift ); |
| 484 | break; |
| 485 | } |
| 471 | 486 | } |
| 487 | |
| 488 | m_sdar = ( m_shift >> 7 ) & 1; |
| 489 | m_shift <<= 1; |
| 490 | m_bit++; |
| 472 | 491 | } |
| 473 | | sdar = (shift >> 7) & 1; |
| 474 | | shift <<= 1; |
| 475 | | bit++; |
| 476 | | } else { |
| 477 | | bit = 0; |
| 478 | | sdar = false; |
| 479 | | if(!sdaw) { |
| 480 | | verboselog(2, "ack <-\n"); |
| 481 | | byte++; |
| 482 | | if(byte == SIZE_READ_BUFFER) { |
| 483 | | byte = 0; |
| 484 | | sdar = true; |
| 485 | | state = STATE_LOAD_COMMAND; |
| 492 | else |
| 493 | { |
| 494 | m_bit = 0; |
| 495 | m_sdar = 0; |
| 496 | |
| 497 | if( m_sdaw == 0 ) |
| 498 | { |
| 499 | verboselog( 2, "ack <-\n" ); |
| 500 | m_byte++; |
| 501 | |
| 502 | if( m_byte == sizeof( m_read_buffer ) ) |
| 503 | { |
| 504 | m_byte = 0; |
| 505 | m_sdar = 1; |
| 506 | m_state = STATE_LOAD_COMMAND; |
| 507 | } |
| 486 | 508 | } |
| 487 | | } else { |
| 488 | | verboselog(2, "nak <-\n"); |
| 509 | else |
| 510 | { |
| 511 | verboselog( 2, "nak <-\n" ); |
| 512 | } |
| 489 | 513 | } |
| 490 | 514 | } |
| 491 | 515 | break; |
| 492 | 516 | } |
| 493 | 517 | } |
| 518 | |
| 519 | m_scl = state; |
| 494 | 520 | } |
| 495 | 521 | |
| 496 | | void zs01_device::sda_1() |
| 522 | WRITE_LINE_MEMBER( zs01_device::write_sda ) |
| 497 | 523 | { |
| 498 | | if(!cs && scl){ |
| 499 | | // state = STATE_STOP; |
| 500 | | // sdar = false; |
| 524 | if( m_sdaw != state ) |
| 525 | { |
| 526 | verboselog( 2, "sdaw=%d\n", state ); |
| 501 | 527 | } |
| 528 | |
| 529 | if( m_cs == 0 && m_scl != 0 ) |
| 530 | { |
| 531 | // if( m_sdaw == 0 && state != 0 ) |
| 532 | // { |
| 533 | // verboselog( 1, "goto stop\n" ); |
| 534 | // m_state = STATE_STOP; |
| 535 | // m_sdar = 0; |
| 536 | // } |
| 537 | |
| 538 | if( m_sdaw != 0 && state == 0 ) |
| 539 | { |
| 540 | switch( m_state ) |
| 541 | { |
| 542 | case STATE_STOP: |
| 543 | verboselog( 1, "goto start\n" ); |
| 544 | m_state = STATE_LOAD_COMMAND; |
| 545 | break; |
| 546 | |
| 547 | // default: |
| 548 | // verboselog( 1, "skipped start (default)\n" ); |
| 549 | // break; |
| 550 | } |
| 551 | |
| 552 | m_bit = 0; |
| 553 | m_byte = 0; |
| 554 | m_shift = 0; |
| 555 | m_sdar = 0; |
| 556 | } |
| 557 | } |
| 558 | |
| 559 | m_sdaw = state; |
| 502 | 560 | } |
| 503 | 561 | |
| 504 | | void zs01_device::sda_0() |
| 562 | READ_LINE_MEMBER( zs01_device::read_sda ) |
| 505 | 563 | { |
| 506 | | if(!cs && scl) { |
| 507 | | switch(state) { |
| 508 | | case STATE_STOP: |
| 509 | | verboselog(1, "goto start\n"); |
| 510 | | state = STATE_LOAD_COMMAND; |
| 511 | | break; |
| 512 | | // default: |
| 513 | | // verboselog(1, "skipped start (default)\n"); |
| 514 | | // break; |
| 515 | | } |
| 564 | if( m_cs != 0 ) |
| 565 | { |
| 566 | verboselog( 2, "not selected\n" ); |
| 567 | return 1; |
| 568 | } |
| 516 | 569 | |
| 517 | | bit = 0; |
| 518 | | byte = 0; |
| 519 | | shift = 0; |
| 520 | | sdar = false; |
| 570 | verboselog( 2, "sdar=%d\n", m_sdar ); |
| 571 | |
| 572 | return m_sdar; |
| 573 | } |
| 574 | |
| 575 | void zs01_device::nvram_default() |
| 576 | { |
| 577 | memset( m_response_to_reset, 0, sizeof( m_response_to_reset ) ); |
| 578 | memset( m_command_key, 0, sizeof( m_command_key ) ); |
| 579 | memset( m_data_key, 0, sizeof( m_data_key ) ); |
| 580 | memset( m_data, 0, sizeof( m_data ) ); |
| 581 | |
| 582 | int expected_bytes = sizeof( m_response_to_reset ) + sizeof( m_command_key ) + sizeof( m_data_key ) + sizeof( m_data ); |
| 583 | |
| 584 | if( !m_region ) |
| 585 | { |
| 586 | logerror( "zs01(%s) region not found\n", tag() ); |
| 521 | 587 | } |
| 588 | else if( m_region->bytes() != expected_bytes ) |
| 589 | { |
| 590 | logerror( "zs01(%s) region length 0x%x expected 0x%x\n", tag(), m_region->bytes(), expected_bytes ); |
| 591 | } |
| 592 | else |
| 593 | { |
| 594 | UINT8 *region = m_region->base(); |
| 595 | |
| 596 | memcpy( m_response_to_reset, region, sizeof( m_response_to_reset ) ); region += sizeof( m_response_to_reset ); |
| 597 | memcpy( m_command_key, region, sizeof( m_command_key ) ); region += sizeof( m_command_key ); |
| 598 | memcpy( m_data_key, region, sizeof( m_data_key ) ); region += sizeof( m_data_key ); |
| 599 | memcpy( m_data, region, sizeof( m_data ) ); region += sizeof( m_data ); |
| 600 | } |
| 522 | 601 | } |
| 523 | 602 | |
| 524 | | void zs01_device::nvram_read(emu_file &file) |
| 603 | void zs01_device::nvram_read( emu_file &file ) |
| 525 | 604 | { |
| 526 | | file.read(response_to_reset, SIZE_RESPONSE_TO_RESET); |
| 527 | | file.read(command_key, SIZE_KEY); |
| 528 | | file.read(data_key, SIZE_KEY); |
| 529 | | file.read(data, SIZE_DATA); |
| 605 | file.read( m_response_to_reset, sizeof( m_response_to_reset ) ); |
| 606 | file.read( m_command_key, sizeof( m_command_key ) ); |
| 607 | file.read( m_data_key, sizeof( m_data_key ) ); |
| 608 | file.read( m_data, sizeof( m_data ) ); |
| 530 | 609 | } |
| 531 | 610 | |
| 532 | | void zs01_device::nvram_write(emu_file &file) |
| 611 | void zs01_device::nvram_write( emu_file &file ) |
| 533 | 612 | { |
| 534 | | file.write(response_to_reset, SIZE_RESPONSE_TO_RESET); |
| 535 | | file.write(command_key, SIZE_KEY); |
| 536 | | file.write(data_key, SIZE_KEY); |
| 537 | | file.write(data, SIZE_DATA); |
| 613 | file.write( m_response_to_reset, sizeof( m_response_to_reset ) ); |
| 614 | file.write( m_command_key, sizeof( m_command_key ) ); |
| 615 | file.write( m_data_key, sizeof( m_data_key ) ); |
| 616 | file.write( m_data, sizeof( m_data ) ); |
| 538 | 617 | } |