src/mess/includes/vc1541.h
| r6732 | r6733 | |
| 1 | | /***************************************************************************** |
| 2 | | * |
| 3 | | * includes/vc1541.h |
| 4 | | * |
| 5 | | * Commodore VC1541 floppy disk drive |
| 6 | | * |
| 7 | | ****************************************************************************/ |
| 8 | | |
| 9 | | #ifndef VC1541_H_ |
| 10 | | #define VC1541_H_ |
| 11 | | |
| 12 | | /*----------- defined in machine/vc1541.c -----------*/ |
| 13 | | |
| 14 | | /* we currently have preliminary support for 1541 & 1551 only */ |
| 15 | | enum { |
| 16 | | type_1541 = 0, |
| 17 | | type_1541ii, |
| 18 | | type_1551, |
| 19 | | type_1570, |
| 20 | | type_1571, |
| 21 | | type_1571cr, |
| 22 | | type_1581, |
| 23 | | type_2031, |
| 24 | | type_2040, |
| 25 | | type_3040, |
| 26 | | type_4040, |
| 27 | | type_1001, |
| 28 | | type_8050, |
| 29 | | type_8250, |
| 30 | | }; |
| 31 | | |
| 32 | | enum { |
| 33 | | format_d64 = 0, /* 1541 image, 35 tracks */ |
| 34 | | format_d64_err, /* 1541 image, 35 tracks + error table */ |
| 35 | | format_d64_40t, /* 1541 image, 40 tracks */ |
| 36 | | format_d64_40t_err, /* 1541 image, 40 tracks + error table */ |
| 37 | | format_d67, /* 2040 image, 35 tracks DOS1 format */ |
| 38 | | format_d71, /* 1571 image, 70 tracks */ |
| 39 | | format_d71_err, /* 1571 image, 70 tracks + error table */ |
| 40 | | format_d81, /* 1581 image, 80 tracks */ |
| 41 | | format_d80, /* 8050 image, 77 tracks */ |
| 42 | | format_d82, /* 8250 image, 154 tracks (read as 77?) */ |
| 43 | | format_g64, /* 1541 image in GCR format */ |
| 44 | | }; |
| 45 | | |
| 46 | | |
| 47 | | void cbm_drive_config(running_machine *machine, int type, int id, int mode, const char *cputag, int devicenr); |
| 48 | | void c1551_config(running_machine *machine, const char *cputag); |
| 49 | | void cbm_drive_reset(running_machine *machine); |
| 50 | | void c1551_drive_reset(void); |
| 51 | | |
| 52 | | void vc1541_device_getinfo(const mess_device_class *devclass, UINT32 state, union devinfo *info); |
| 53 | | void c1551_device_getinfo(const mess_device_class *devclass, UINT32 state, union devinfo *info); |
| 54 | | void c1571_device_getinfo(const mess_device_class *devclass, UINT32 state, union devinfo *info); |
| 55 | | void c1581_device_getinfo(const mess_device_class *devclass, UINT32 state, union devinfo *info); |
| 56 | | /* the ones below are still not used in any drivers */ |
| 57 | | void c2031_device_getinfo(const mess_device_class *devclass, UINT32 state, union devinfo *info); |
| 58 | | void c2040_device_getinfo(const mess_device_class *devclass, UINT32 state, union devinfo *info); |
| 59 | | void c8050_device_getinfo(const mess_device_class *devclass, UINT32 state, union devinfo *info); |
| 60 | | void c8250_device_getinfo(const mess_device_class *devclass, UINT32 state, union devinfo *info); |
| 61 | | |
| 62 | | |
| 63 | | MACHINE_DRIVER_EXTERN( cpu_vc1540 ); |
| 64 | | MACHINE_DRIVER_EXTERN( cpu_vc1541 ); |
| 65 | | MACHINE_DRIVER_EXTERN( cpu_c1571 ); |
| 66 | | MACHINE_DRIVER_EXTERN( cpu_c1571cr ); |
| 67 | | MACHINE_DRIVER_EXTERN( cpu_c1581 ); |
| 68 | | MACHINE_DRIVER_EXTERN( cpu_c2031 ); |
| 69 | | MACHINE_DRIVER_EXTERN( cpu_c1551 ); |
| 70 | | |
| 71 | | // currently not used (hacked drive firmware with more RAM) |
| 72 | | MACHINE_DRIVER_EXTERN( cpu_dolphin ); |
| 73 | | |
| 74 | | |
| 75 | | /* IEC interface for c16 with c1551 */ |
| 76 | | |
| 77 | | /* To be passed directly to the drivers */ |
| 78 | | WRITE8_DEVICE_HANDLER( c1551x_write_data ); |
| 79 | | READ8_DEVICE_HANDLER( c1551x_read_data ); |
| 80 | | WRITE8_DEVICE_HANDLER( c1551x_write_handshake ); |
| 81 | | READ8_DEVICE_HANDLER( c1551x_read_handshake ); |
| 82 | | READ8_DEVICE_HANDLER( c1551x_read_status ); |
| 83 | | |
| 84 | | |
| 85 | | /* Floppy drive ROMs */ |
| 86 | | |
| 87 | | /**************************************************************************** |
| 88 | | |
| 89 | | Info from zimmers.net |
| 90 | | |
| 91 | | 1551 Parts |
| 92 | | |
| 93 | | Location Part Number Description |
| 94 | | U4 318008-01 23128 ROM DOS 2.6 C000-FFFF |
| 95 | | U5 6116 2K x 8 Static RAM |
| 96 | | U6 HD61J215P 42 pin Gate Array |
| 97 | | U7 251829-01 64H157 20 pin Gate Array |
| 98 | | U2 6510T CPU |
| 99 | | U3 6525A TPI |
| 100 | | U11 251853-01 R/W Hybrid |
| 101 | | |
| 102 | | Interface Cartridge: |
| 103 | | U2 6523 Tri-Port Interface |
| 104 | | U1 251641-03 82S100 PLA |
| 105 | | |
| 106 | | ****************************************************************************/ |
| 107 | | |
| 108 | | #define C1551_ROM( cpu ) \ |
| 109 | | ROM_REGION( 0x10000, cpu, 0 ) \ |
| 110 | | ROM_LOAD( "318008-01.u4", 0xc000, 0x4000, CRC(6d16d024) SHA1(fae3c788ad9a6cc2dbdfbcf6c0264b2ca921d55e) ) |
| 111 | | |
| 112 | | |
| 113 | | |
| 114 | | /**************************************************************************** |
| 115 | | |
| 116 | | Info from zimmers.net |
| 117 | | |
| 118 | | 1540/1541/1541A/SX-64 Parts |
| 119 | | |
| 120 | | Location Part Number Description |
| 121 | | 2016 2K x 8 bit Static RAM (short board) |
| 122 | | UA2-UB3 2114 (4) 1K x 4 bit Static RAM (long board) |
| 123 | | 325302-01 2364-130 ROM DOS 2.6 C000-DFFF |
| 124 | | 325303-01 2364-131 ROM DOS 2.6 (1540) E000-FFFF |
| 125 | | 901229-01 2364-173 ROM DOS 2.6 (1541) E000-FFFF |
| 126 | | 901229-03 2364-197 ROM DOS 2.6 rev. 1 E000-FFFF |
| 127 | | 901229-05 2364 ROM DOS 2.6 rev. 2 E000-FFFF |
| 128 | | 325572-01 64H105 40 pin Gate Array (short board) |
| 129 | | 6502 CPU |
| 130 | | 6522 (2) VIA |
| 131 | | drive Alps DFB111M25A |
| 132 | | drive Alps FDM2111-B2 |
| 133 | | drive Newtronics D500 |
| 134 | | |
| 135 | | 1541B/1541C Parts |
| 136 | | |
| 137 | | Location Part Number Description |
| 138 | | UA3 2016 2K x 8 bit Static RAM |
| 139 | | UA2 251968-01 23128 ROM DOS 2.6 rev. 3 C000-FFFF |
| 140 | | UA2 251968-01 27128 EPROM DOS 2.6 rev. 3 C000-FFFF |
| 141 | | UC4 251828-02 64H156 42 pin Gate Array |
| 142 | | UC5 251829-01 64H157 20 pin Gate Array |
| 143 | | UC2 6502 CPU |
| 144 | | UC1, UC3 6522 (2) CIA |
| 145 | | UD1 * 251853-01 R/W Hybrid |
| 146 | | UD1 * 251853-02 R/W Hybrid |
| 147 | | drive Newtronics D500 |
| 148 | | * Not interchangeable. |
| 149 | | |
| 150 | | 1541-II Parts |
| 151 | | |
| 152 | | Location Part Number Description |
| 153 | | U5 2016-15 2K x 8 bit Static RAM |
| 154 | | U12 SONY CX20185 R/W Amp. |
| 155 | | U4 251968-03 16K ROM DOS 2.6 rev. 4 C000-FFFF |
| 156 | | U10 251828-01 64H156 40 pin Gate Array |
| 157 | | U3 6502A CPU |
| 158 | | U6, U8 6522 (2) CIA |
| 159 | | drive Chinon FZ-501M REV A |
| 160 | | drive Digital System DS-50F |
| 161 | | drive Newtronics D500 |
| 162 | | drive Safronic DS-50F |
| 163 | | |
| 164 | | |
| 165 | | |
| 166 | | Note: according to additional docs at zimmers.net, ROMs in these drive |
| 167 | | were interchangeable: you could burn later revisions on EEPROM and put |
| 168 | | them in older drives and they would work perfectly. |
| 169 | | |
| 170 | | ****************************************************************************/ |
| 171 | | |
| 172 | | // I'm not 100% sure about UA2/UB3 locations used below for ROM names |
| 173 | | // I need a picture to confirm these, since the part listing above is not really clear (without a pic of the board) |
| 174 | | #define VC1540_ROM( cpu ) \ |
| 175 | | ROM_REGION( 0x10000, cpu, 0 ) \ |
| 176 | | ROM_LOAD( "325302-01.ua2", 0xc000, 0x2000, CRC(29ae9752) SHA1(8e0547430135ba462525c224e76356bd3d430f11) ) \ |
| 177 | | ROM_LOAD( "325303-01.ub3", 0xe000, 0x2000, CRC(10b39158) SHA1(56dfe79b26f50af4e83fd9604857756d196516b9) ) |
| 178 | | |
| 179 | | /* |
| 180 | | rev. 01 - It is believed to be the first revision of the 1541 firmware. The service manual says that this ROM |
| 181 | | is for North America and Japan only. |
| 182 | | rev. 02 - Second version of the 1541 firmware. The service manual says that this ROM was not available in North |
| 183 | | America (Japan only?). |
| 184 | | rev. 03 - It is said to be the first version that is usable in Europe (in the service manual?). |
| 185 | | rev. 05 - From an old-style 1541 with short board. |
| 186 | | rev. 06AA - From an old-style 1541 with short board. |
| 187 | | */ |
| 188 | | #define VC1541_ROM( cpu ) \ |
| 189 | | ROM_REGION( 0x10000, cpu, 0 ) \ |
| 190 | | ROM_SYSTEM_BIOS( 0, "rev1", "VC-1541 rev. 01" ) \ |
| 191 | | ROMX_LOAD( "325302-01.ua2", 0xc000, 0x2000, CRC(29ae9752) SHA1(8e0547430135ba462525c224e76356bd3d430f11), ROM_BIOS(1) ) \ |
| 192 | | ROMX_LOAD( "901229-01.ub3", 0xe000, 0x2000, CRC(9a48d3f0) SHA1(7a1054c6156b51c25410caec0f609efb079d3a77), ROM_BIOS(1) ) \ |
| 193 | | ROM_SYSTEM_BIOS( 1, "rev2", "VC-1541 rev. 02" ) \ |
| 194 | | ROMX_LOAD( "325302-01.ua2", 0xc000, 0x2000, CRC(29ae9752) SHA1(8e0547430135ba462525c224e76356bd3d430f11), ROM_BIOS(2) ) \ |
| 195 | | ROMX_LOAD( "901229-02.ub3", 0xe000, 0x2000, CRC(b29bab75) SHA1(91321142e226168b1139c30c83896933f317d000), ROM_BIOS(2) ) \ |
| 196 | | ROM_SYSTEM_BIOS( 2, "rev3", "VC-1541 rev. 03" ) \ |
| 197 | | ROMX_LOAD( "325302-01.ua2", 0xc000, 0x2000, CRC(29ae9752) SHA1(8e0547430135ba462525c224e76356bd3d430f11), ROM_BIOS(3) ) \ |
| 198 | | ROMX_LOAD( "901229-03.ub3", 0xe000, 0x2000, CRC(9126e74a) SHA1(03d17bd745066f1ead801c5183ac1d3af7809744), ROM_BIOS(3) ) \ |
| 199 | | ROM_SYSTEM_BIOS( 3, "rev5", "VC-1541 rev. 05" ) \ |
| 200 | | ROMX_LOAD( "325302-01.ua2", 0xc000, 0x2000, CRC(29ae9752) SHA1(8e0547430135ba462525c224e76356bd3d430f11), ROM_BIOS(4) ) \ |
| 201 | | ROMX_LOAD( "901229-05.ub3", 0xe000, 0x2000, CRC(361c9f37) SHA1(f5d60777440829e46dc91285e662ba072acd2d8b), ROM_BIOS(4) ) \ |
| 202 | | ROM_SYSTEM_BIOS( 4, "rev6aa", "VC-1541 rev. 06AA" ) \ |
| 203 | | ROMX_LOAD( "325302-01.ua2", 0xc000, 0x2000, CRC(29ae9752) SHA1(8e0547430135ba462525c224e76356bd3d430f11), ROM_BIOS(5) ) \ |
| 204 | | ROMX_LOAD( "901229-06aa.ub3", 0xe000, 0x2000, CRC(3a235039) SHA1(c7f94f4f51d6de4cdc21ecbb7e57bb209f0530c0), ROM_BIOS(5) ) \ |
| 205 | | ROM_SYSTEM_BIOS( 5, "rev1c", "VC-1541C rev. 01" ) \ |
| 206 | | ROMX_LOAD( "251968-01.ua2", 0xc000, 0x4000, CRC(1b3ca08d) SHA1(8e893932de8cce244117fcea4c46b7c39c6a7765), ROM_BIOS(6) ) \ |
| 207 | | ROM_SYSTEM_BIOS( 6, "rev2c", "VC-1541C rev. 02" ) \ |
| 208 | | ROMX_LOAD( "251968-02.ua2", 0xc000, 0x4000, CRC(2d862d20) SHA1(38a7a489c7bbc8661cf63476bf1eb07b38b1c704), ROM_BIOS(7) ) \ |
| 209 | | ROM_SYSTEM_BIOS( 7, "rev3ii", "VC-1541-II" ) \ |
| 210 | | ROMX_LOAD( "251968-03.u4", 0xc000, 0x4000, CRC(899fa3c5) SHA1(d3b78c3dbac55f5199f33f3fe0036439811f7fb3), ROM_BIOS(8) ) \ |
| 211 | | ROM_SYSTEM_BIOS( 8, "reviin", "VC-1541-II (with Newtronics D500)" ) \ |
| 212 | | ROMX_LOAD( "355640-01.u4", 0xc000, 0x4000, CRC(57224cde) SHA1(ab16f56989b27d89babe5f89c5a8cb3da71a82f0), ROM_BIOS(9) ) \ |
| 213 | | |
| 214 | | |
| 215 | | |
| 216 | | // currently not used (hacked drive firmware with more RAM) |
| 217 | | #define DOLPHIN_ROM( cpu ) \ |
| 218 | | ROM_REGION( 0x10000, cpu, 0 ) \ |
| 219 | | ROM_LOAD( "c1541.rom", 0xa000, 0x6000, CRC(bd8e42b2) SHA1(d6aff55fc70876fa72be45c666b6f42b92689b4d) ) |
| 220 | | |
| 221 | | |
| 222 | | |
| 223 | | /**************************************************************************** |
| 224 | | |
| 225 | | Info from zimmers.net |
| 226 | | |
| 227 | | 1570 Parts |
| 228 | | |
| 229 | | Location Part Number Description |
| 230 | | 315090-01 32K ROM DOS 3.0 |
| 231 | | drive Alps |
| 232 | | |
| 233 | | 1571 Parts |
| 234 | | |
| 235 | | Location Part Number Description |
| 236 | | U11 WD1770 FDC |
| 237 | | U11 WD1772 FDC |
| 238 | | U3 2016-20 2K x 8 bit Static RAM |
| 239 | | U1 6502A CPU |
| 240 | | U4, U9 65C22A (2) CIA |
| 241 | | U20 6526A CIA |
| 242 | | U20 8520 CIA |
| 243 | | U6 251828-01 64H156 40 pin Gate Array |
| 244 | | U5 251829-01 64H157 20 pin Gate Array |
| 245 | | U7 251853-01 R/W Hybrid |
| 246 | | U2 310654-03 23256 ROM DOS 3.0 |
| 247 | | U2 310654-05 32K ROM DOS 3.0 rev. |
| 248 | | drive Alps |
| 249 | | drive Newtronics D502 |
| 250 | | |
| 251 | | C128D Parts |
| 252 | | |
| 253 | | Location Part Number Description |
| 254 | | U103 2016-20 2K x 8 bit Static RAM |
| 255 | | U108 252308-01 MC2871A R/W Amp. |
| 256 | | U107 252371-01 MOS5710 FDC and Gate Array |
| 257 | | U101 6502A CPU |
| 258 | | U104, U106 65C22 (2) CIA |
| 259 | | U105 251828-01 64H156 40 pin Gate Array |
| 260 | | U102 318047-01 23256 ROM DOS 3.1 |
| 261 | | drive Newtronics D502 |
| 262 | | |
| 263 | | |
| 264 | | ****************************************************************************/ |
| 265 | | |
| 266 | | // no locations available for this, I need a picture of the board |
| 267 | | // currently, we add 1570 to 1571, to preserve the firmware. |
| 268 | | // this will be used later, when proper drives will be added to each system |
| 269 | | #define C1570_ROM( cpu ) \ |
| 270 | | ROM_REGION( 0x10000, cpu, 0) \ |
| 271 | | ROM_LOAD( "315090-01.bin", 0x8000, 0x8000, CRC(5a0c7937) SHA1(5fc06dc82ff6840f183bd43a4d9b8a16956b2f56) ) |
| 272 | | |
| 273 | | |
| 274 | | #define C1571_ROM( cpu ) \ |
| 275 | | ROM_REGION( 0x10000, cpu, 0 ) \ |
| 276 | | ROM_SYSTEM_BIOS( 0, "rev5", "1571 rev. 05" ) \ |
| 277 | | ROMX_LOAD( "310654-05.u2", 0x8000, 0x8000, CRC(5755bae3) SHA1(f1be619c106641a685f6609e4d43d6fc9eac1e70), ROM_BIOS(1) ) \ |
| 278 | | ROM_SYSTEM_BIOS( 1, "rev3", "1571 rev. 03" ) \ |
| 279 | | ROMX_LOAD( "310654-03.u2", 0x8000, 0x8000, CRC(3889b8b8) SHA1(e649ef4419d65829d2afd65e07d31f3ce147d6eb), ROM_BIOS(2) ) \ |
| 280 | | /* This should not be here... */ \ |
| 281 | | ROM_SYSTEM_BIOS( 2, "1570", "1570" ) \ |
| 282 | | ROMX_LOAD( "315090-01.bin", 0x8000, 0x8000, CRC(5a0c7937) SHA1(5fc06dc82ff6840f183bd43a4d9b8a16956b2f56), ROM_BIOS(3) ) |
| 283 | | |
| 284 | | |
| 285 | | #define C1571CR_ROM( cpu ) \ |
| 286 | | ROM_REGION( 0x10000, cpu, 0) \ |
| 287 | | ROM_LOAD( "318047-01.u102", 0x8000, 0x8000, CRC(f24efcc4) SHA1(14ee7a0fb7e1c59c51fbf781f944387037daa3ee) ) |
| 288 | | |
| 289 | | |
| 290 | | // no locations available for this, I need a picture of the board |
| 291 | | /* |
| 292 | | rev. 01 - First revision of 1581 firmware |
| 293 | | rev. 02 - Second revision of 1581 firmware |
| 294 | | beta - Probably a beta version |
| 295 | | 1563 - This comes from a prototype unit of the so-called c128d/81 (a c128d with built-in 1581 drive). |
| 296 | | Despite the label, is a 1581 firmaware |
| 297 | | */ |
| 298 | | #define C1581_ROM( cpu ) \ |
| 299 | | ROM_REGION( 0x10000, cpu, 0 ) \ |
| 300 | | ROM_SYSTEM_BIOS( 0, "rev2", "1581 rev. 02" ) \ |
| 301 | | ROMX_LOAD( "318045-02.bin", 0x8000, 0x8000, CRC(a9011b84) SHA1(01228eae6f066bd9b7b2b6a7fa3f667e41dad393), ROM_BIOS(1) ) \ |
| 302 | | ROM_SYSTEM_BIOS( 1, "rev1", "1581 rev. 01" ) \ |
| 303 | | ROMX_LOAD( "318045-01.bin", 0x8000, 0x8000, CRC(113af078) SHA1(3fc088349ab83e8f5948b7670c866a3c954e6164), ROM_BIOS(2) ) \ |
| 304 | | ROM_SYSTEM_BIOS( 2, "beta", "1581 beta?" ) \ |
| 305 | | ROMX_LOAD( "1581-beta.bin", 0x8000, 0x8000, CRC(ecc223cd) SHA1(a331d0d46ead1f0275b4ca594f87c6694d9d9594), ROM_BIOS(3) ) \ |
| 306 | | ROM_SYSTEM_BIOS( 3, "1563", "1563 (from C128D/81)" ) \ |
| 307 | | ROMX_LOAD( "1563.bin", 0x8000, 0x8000, CRC(1d184687) SHA1(2c5111a9c15be7b7955f6c8775fea25ec10c0ca0), ROM_BIOS(4) ) |
| 308 | | |
| 309 | | |
| 310 | | |
| 311 | | /* Older drive - currently these are only added as documentation (no driver uses them yet) */ |
| 312 | | /* They all use IEEE-448 connector */ |
| 313 | | |
| 314 | | /**************************************************************************** |
| 315 | | |
| 316 | | Info from zimmers.net |
| 317 | | |
| 318 | | 2031 Parts |
| 319 | | |
| 320 | | Location Part Number Description |
| 321 | | UB2 2016 2K x 8 bit static RAM (HP) |
| 322 | | U3B-U3E 2114 (4) 1K x 4 bit static RAM (LP) |
| 323 | | 901484-03 2364-107 ROM DOS 2.6 C000-DFFF |
| 324 | | 901484-05 2364-123 ROM DOS 2.6 E000-FFFF |
| 325 | | 6502 CPU |
| 326 | | 6522 (2) VIA |
| 327 | | drive Alps DFB111M25A (LP) |
| 328 | | drive Alps FDM2111-B2 (LP) |
| 329 | | drive Shugart 390 (HP) |
| 330 | | |
| 331 | | ****************************************************************************/ |
| 332 | | |
| 333 | | // I'm not 100% sure about U3B/U3E locations used below for ROM names |
| 334 | | // I need a picture to confirm these, since the part listing above is not really clear (without a pic of the board) |
| 335 | | #define C2031_ROM( cpu ) \ |
| 336 | | ROM_REGION( 0x10000, cpu, 0 ) \ |
| 337 | | ROM_LOAD( "901484-03.u3b", 0xc000, 0x2000, CRC(ee4b893b) SHA1(54d608f7f07860f24186749f21c96724dd48bc50) ) \ |
| 338 | | ROM_LOAD( "901484-05.u3e", 0xe000, 0x2000, CRC(6a629054) SHA1(ec6b75ecfdd4744e5d57979ef6af990444c11ae1) ) |
| 339 | | |
| 340 | | |
| 341 | | |
| 342 | | /**************************************************************************** |
| 343 | | |
| 344 | | Info from zimmers.net |
| 345 | | |
| 346 | | SFD-1001 Parts |
| 347 | | |
| 348 | | Location Part Number Description |
| 349 | | 7G, 9G 2116 (2) 2K x 8 static RAM |
| 350 | | |
| 351 | | DOS: |
| 352 | | 1J 901887-01 2364 ROM DOS 2.7 C000-DFFF |
| 353 | | 3J 901887-02 2364 ROM DOS 2.7 E000-FFFF |
| 354 | | 3J 901888-01 2364 ROM DOS 2.7 E000-FFFF |
| 355 | | 2H 6502 CPU |
| 356 | | 4J, 6J 6532 (2) RIOT |
| 357 | | |
| 358 | | Controller: |
| 359 | | 5C 901467-01 6316-017 ROM GCR |
| 360 | | 1E 6502 CPU |
| 361 | | 5E 6522 VIA |
| 362 | | 3E 251232 adapter board |
| 363 | | drive Matsushita JU-570-2 |
| 364 | | |
| 365 | | Adapter Board: |
| 366 | | U2 251257-02A 2716 EPROM controller |
| 367 | | U1 6530 RIOT (ROM disabled) |
| 368 | | |
| 369 | | |
| 370 | | Notes: The DOS 2.7 ROM in SFD-1001 is the same as in 8250 drives. Differences: |
| 371 | | |
| 372 | | CBM 8050 - dual 5" 1/4 floppy drive, disks are written on one side |
| 373 | | with double density |
| 374 | | CBM 8250 / 8250LP - dual 5.25" 1/4 floppy drive, disks are written |
| 375 | | on both sides. it reads 8050-disks, LP version has smaller case |
| 376 | | SFD-1001 - single 5" 1/4 floppy drive, same as CBM 8250LP, but only |
| 377 | | one drive and 1541-case |
| 378 | | |
| 379 | | ****************************************************************************/ |
| 380 | | |
| 381 | | #define SFD1001_ROM( cpu ) \ |
| 382 | | ROM_REGION( 0x10800, cpu, 0 ) \ |
| 383 | | ROM_LOAD( "901887-01.1j", 0xc000, 0x2000, CRC(0073b8b2) ) \ |
| 384 | | ROM_LOAD( "901888-01.3j", 0xe000, 0x2000, CRC(de9b6132) ) \ |
| 385 | | ROM_LOAD( "251257-02a.u2", 0x10000, 0x800, CRC(b51150de) ) /* Floppy Disc Controller */ |
| 386 | | |
| 387 | | |
| 388 | | #define C8250_ROM( cpu ) \ |
| 389 | | ROM_REGION( 0x10000, cpu, 0 ) |
| 390 | | |
| 391 | | // still to be sorted out |
| 392 | | |
| 393 | | /**************************************************************************** |
| 394 | | |
| 395 | | Info from zimmers.net |
| 396 | | |
| 397 | | 2040/3040/4040 Parts |
| 398 | | |
| 399 | | Location Part Number Description |
| 400 | | UC4-UF5 2114 (8) 1K x 4 bit static RAM |
| 401 | | |
| 402 | | DOS: |
| 403 | | UL1 901468-06 2332-020 ROM DOS 1 E000-EFFF |
| 404 | | UH1 901468-07 2332-021 ROM DOS 1 F000-FFFF |
| 405 | | UJ1 901468-11 2332 ROM DOS 2 D000-DFFF |
| 406 | | UL1 901468-12 2332 ROM DOS 2 E000-EFFF |
| 407 | | UH1 901468-13 2332 ROM DOS 2 F000-FFFF |
| 408 | | UJ1 901468-14 2332-191 ROM DOS 2 rev. D000-DFFF |
| 409 | | UL1 901468-15 2332-192 ROM DOS 2 rev. E000-EFFF |
| 410 | | UH1 901468-16 2332-193 ROM DOS 2 rev. F000-FFFF |
| 411 | | UN1 6502 CPU |
| 412 | | UC1, UE1 6532 (2) RIOT |
| 413 | | |
| 414 | | Controller: |
| 415 | | UH3 6504 CPU |
| 416 | | UM3 6522 VIA |
| 417 | | UK3 901466-02 6530-028 RIOT DOS 1 |
| 418 | | UK3 901466-04 6530-034 RIOT DOS 2 |
| 419 | | UK6 901467-01 6316-017 ROM GCR |
| 420 | | drive Shugart 390 |
| 421 | | |
| 422 | | ****************************************************************************/ |
| 423 | | |
| 424 | | #define C4040_ROM( cpu ) \ |
| 425 | | ROM_REGION( 0x10000, cpu, 0 ) |
| 426 | | |
| 427 | | // still to be sorted out |
| 428 | | |
| 429 | | |
| 430 | | /**************************************************************************** |
| 431 | | |
| 432 | | Info from zimmers.net |
| 433 | | |
| 434 | | 9060/9090 Parts |
| 435 | | |
| 436 | | Location Part Number Description |
| 437 | | 5A-5H 2114 (8) 1K x 4 bit Static RAM |
| 438 | | |
| 439 | | DOS: |
| 440 | | 7C 300516-002 * 2564 EPROM DOS 3.0 C000-DFFF (rev. B) |
| 441 | | 7D 300517-002 * 2564 EPROM DOS 3.0 E000-FFFF (rev. B) |
| 442 | | 7C 300516-001 + 2764 EPROM DOS 3.0 C000-DFFF (rev. B) |
| 443 | | 7D 300517-001 + 2764 EPROM DOS 3.0 E000-FFFF (rev. B) |
| 444 | | 7C 300516 * 2564 EPROM DOS 3.0 rev. C000-DFFF (rev. C) |
| 445 | | 7D 300517 * 2564 EPROM DOS 3.0 rev. E000-FFFF (rev. C) |
| 446 | | 7C 300516 + 2764 EPROM DOS 3.0 rev. C000-DFFF (rev. C) |
| 447 | | 7D 300517 + 2764 EPROM DOS 3.0 rev. E000-FFFF (rev. C) |
| 448 | | 7E 6502 CPU |
| 449 | | 7F, 7G 6532 (2) RIOT |
| 450 | | * 2564 are used on PCB 300012-001 |
| 451 | | + 2764 are used on PCB 230012-002 |
| 452 | | |
| 453 | | Controller: |
| 454 | | 4C 300515 2716 EPROM DOS 3.0 (rev. A) |
| 455 | | 4C 300515-001 2716 EPROM DOS 3.0 (rev. B) |
| 456 | | 4A 6502 CPU |
| 457 | | 4B 6522 VIA |
| 458 | | 4D 6810 128 x 8 bit Static RAM |
| 459 | | |
| 460 | | Winchester Controller: |
| 461 | | 9D Am2910 12 bit Bit/Slice Controller |
| 462 | | drive Tandon TM602S (9060) |
| 463 | | drive Tandon TM603S (9090) |
| 464 | | |
| 465 | | |
| 466 | | Note: The Commodore D9060 and D9090 can use the same firmware. The |
| 467 | | difference between these units is that the jumper J14 on the DOS board |
| 468 | | is open in the D9060, and closed in the D9090 to select a 4-head vs. |
| 469 | | 6-head drive. The jumper J13 seems to be unused. |
| 470 | | |
| 471 | | ****************************************************************************/ |
| 472 | | |
| 473 | | #define D9090_ROM( cpu ) \ |
| 474 | | ROM_REGION( 0x10800, cpu, 0 ) \ |
| 475 | | ROM_SYSTEM_BIOS( 0, "reva", "D9090 rev. A" ) \ |
| 476 | | ROMX_LOAD( "300516-revb.7c", 0xc000, 0x2000, CRC(2d758a14), ROM_BIOS(1) ) /* No Rev A available for this! */ \ |
| 477 | | ROMX_LOAD( "300517-reva.7d", 0xe000, 0x2000, CRC(566df630), ROM_BIOS(1) ) \ |
| 478 | | ROMX_LOAD( "300515-reva.4c", 0x10000, 0x800, CRC(99e096f7), ROM_BIOS(1) ) /* Floppy Disc Controller Rev. A - label "300515 Rev A" */ \ |
| 479 | | ROM_SYSTEM_BIOS( 1, "revb", "D9090 rev. B" ) \ |
| 480 | | ROMX_LOAD( "300516-revb.7c", 0xc000, 0x2000, CRC(2d758a14), ROM_BIOS(2) ) \ |
| 481 | | ROMX_LOAD( "300517-revb.7d", 0xe000, 0x2000, CRC(f0382bc3), ROM_BIOS(2) ) \ |
| 482 | | ROMX_LOAD( "300515-revb.4c", 0x10000, 0x800, CRC(49adf4fb), ROM_BIOS(2) ) /* Floppy Disc Controller Rev. B - label "300515 Rev B" or "300515-001" */ \ |
| 483 | | ROM_SYSTEM_BIOS( 2, "revc", "D9090 rev. C" ) \ |
| 484 | | ROMX_LOAD( "300516-revc.7c", 0xc000, 0x2000, CRC(d6a3e88f), ROM_BIOS(3) ) \ |
| 485 | | ROMX_LOAD( "300517-revc.7d", 0xe000, 0x2000, CRC(2a9ad4ad), ROM_BIOS(3) ) \ |
| 486 | | ROMX_LOAD( "300515-revb.4c", 0x10000, 0x800, CRC(49adf4fb), ROM_BIOS(3) ) /* Floppy Disc Controller Rev. B - label "300515 Rev B" or "300515-001" */ |
| 487 | | |
| 488 | | |
| 489 | | /**************************************************************************** |
| 490 | | |
| 491 | | Dual 8" floppy drive. Related to any other drive? What about 8060? |
| 492 | | |
| 493 | | ****************************************************************************/ |
| 494 | | |
| 495 | | #define C8280_ROM( cpu ) \ |
| 496 | | ROM_REGION( 0x10800, cpu, 0 ) \ |
| 497 | | ROM_LOAD( "300542-001.bin", 0xc000, 0x2000, CRC(3c6eee1e) ) \ |
| 498 | | ROM_LOAD( "300543-001.bin", 0xe000, 0x2000, CRC(f58e665e) ) \ |
| 499 | | ROM_LOAD( "300541-001.bin", 0x10000, 0x800, CRC(cb07b2db) ) /* GCR encoding/decoding tables? */ |
| 500 | | |
| 501 | | |
| 502 | | |
| 503 | | #if 0 |
| 504 | | ROM_LOAD("dos2040", 0x?000, 0x2000, CRC(d04c1fbb)) |
| 505 | | |
| 506 | | ROM_LOAD("dos3040", 0x?000, 0x3000, CRC(f4967a7f)) |
| 507 | | |
| 508 | | ROM_LOAD("dos4040", 0x?000, 0x3000, CRC(40e0ebaa)) |
| 509 | | |
| 510 | | ROM_LOAD("dos1001", 0xc000, 0x4000, CRC(87e6a94e)) |
| 511 | | |
| 512 | | /* dolphin vc1541 */ |
| 513 | | ROM_LOAD("c1541.rom", 0xa000, 0x6000, CRC(bd8e42b2)) |
| 514 | | |
| 515 | | /* modified drive 0x2000-0x3ffe ram, 0x3fff 6529 */ |
| 516 | | ROM_LOAD("1581rom5.bin", 0x8000, 0x8000, CRC(e08801d7)) |
| 517 | | |
| 518 | | ROM_LOAD("", 0xc000, 0x4000, CRC()) |
| 519 | | #endif |
| 520 | | |
| 521 | | #endif /* VC1541_H_ */ |
src/mess/machine/vc1541.c
| r6732 | r6733 | |
| 1 | | /*************************************************************************** |
| 2 | | |
| 3 | | commodore vc1541 floppy disk drive |
| 4 | | |
| 5 | | ***************************************************************************/ |
| 6 | | |
| 7 | | /* |
| 8 | | vc1540 |
| 9 | | higher serial bus timing than the vc1541, to fast for c64 |
| 10 | | vc1541 |
| 11 | | (also build in in sx64) |
| 12 | | used with commodore vc20, c64, c16, c128 |
| 13 | | floppy disk drive 5 1/4 inch, single sided, double density, |
| 14 | | 40 tracks (tone head to big to use 80 tracks?) |
| 15 | | gcr encoding |
| 16 | | |
| 17 | | computer M6502, 2x VIA6522, 2 KByte RAM, 16 KByte ROM |
| 18 | | 1 Commodore serial bus (2 connectors) |
| 19 | | |
| 20 | | vc1541 ieee488 hardware modification |
| 21 | | additional ieee488 connection, modified rom |
| 22 | | |
| 23 | | vc1541 II |
| 24 | | ? |
| 25 | | |
| 26 | | dolphin drives |
| 27 | | vc1541 clone? |
| 28 | | additional 8 KByte RAM at 0x8000 (complete track buffer ?) |
| 29 | | 24 KByte rom |
| 30 | | |
| 31 | | c1551 |
| 32 | | used with commodore c16 |
| 33 | | m6510t? processor (4 MHz???), |
| 34 | | (m6510t internal 4 MHz clock?, 8 port pins?) |
| 35 | | VIA6522 ?, CIA6526 ?, |
| 36 | | 2 KByte RAM, 16 KByte ROM |
| 37 | | connector commodore C16 expansion cartridge |
| 38 | | parallel protocoll |
| 39 | | |
| 40 | | 1750 |
| 41 | | single sided 1751 |
| 42 | | 1751 |
| 43 | | (also build in in c128d series) |
| 44 | | used with c128 (vic20,c16,c64 possible?) |
| 45 | | double sided |
| 46 | | can read some other disk formats (mfm encoded?) |
| 47 | | modified commodore serial bus (with quick serial transmission) |
| 48 | | (m6510?, cia6526?) |
| 49 | | 0000-00FF Zero page work area, job queue, variables |
| 50 | | 0100-01FF GCR overflow area and stack (1571 mode BAM side 1) |
| 51 | | 0200-02FF Command buffer, parser, tables, variables |
| 52 | | 0300-07FF 5 data buffers, 0-4 one of which is used for BAM |
| 53 | | 1800-1BFF 65C22A, serial, controller ports |
| 54 | | 1C00-1FFF 65C22A, controller ports |
| 55 | | 8000-FFE5 32K byte ROM, DOS and controller routines |
| 56 | | FFE6-FFFF JMP table, user command vectors |
| 57 | | |
| 58 | | 1581 |
| 59 | | 3 1/2 inch, double sided, double density, 80 tracks |
| 60 | | used with c128 (vic20,c16,c64 possible?) |
| 61 | | only mfm encoding? |
| 62 | | 0000-00FF Zero page work area, job queue, variables |
| 63 | | 0100-01FF Stack, variables, vectors |
| 64 | | 0200-02FF Command buffer, tables, variables |
| 65 | | 0300-09FF Data buffers (0-6) |
| 66 | | 0A00-0AFF BAM for tracks 0-39 |
| 67 | | 0B00-0BFF BAM for tracks 40-79 |
| 68 | | 0C00-1FFF Track cache buffer |
| 69 | | 4000-5FFF 8520A CIA |
| 70 | | 6000-7FFF WD177X FDC |
| 71 | | 8000-FEFF 32K byte ROM, DOS and controller routines |
| 72 | | FF00-FFFF Jump table, vectors |
| 73 | | |
| 74 | | 2031/4031 |
| 75 | | ieee488 interface |
| 76 | | 1541 with ieee488 bus instead of serial bus |
| 77 | | $1800 via6522 used for ieee488 interface? |
| 78 | | maybe like in pet series? |
| 79 | | port a data in/out? |
| 80 | | port b ce port, ddr 31 |
| 81 | | |
| 82 | | 2040/3040 |
| 83 | | ieee488 interface |
| 84 | | 2 drives |
| 85 | | |
| 86 | | 2041 |
| 87 | | ieee488 interface |
| 88 | | |
| 89 | | 4040 |
| 90 | | ieee488 interface |
| 91 | | 2 drives |
| 92 | | |
| 93 | | sfd1001 |
| 94 | | ieee488 interface |
| 95 | | 5 1/4 inch high density |
| 96 | | 2 heads |
| 97 | | |
| 98 | | */ |
| 99 | | /* 2008-09 FP |
| 100 | | Started some work on the floppy emulation code: |
| 101 | | + made the functions / structs less vc1541-centric & d64-centric |
| 102 | | + unified config & reset functions, using type variable |
| 103 | | to choose the actions to be done |
| 104 | | + moved GCR encoding at loading time (wip untested code) |
| 105 | | |
| 106 | | A limitation is clear: only a single occurrence of emulated drive |
| 107 | | is expected. |
| 108 | | At a later stage, at least drive_config & drive_reset will need |
| 109 | | an index to choose between the drives |
| 110 | | In the end, we could also split the floppy drives emulation from the |
| 111 | | disk image handling... |
| 112 | | |
| 113 | | Current status: |
| 114 | | + preliminary vc1541 & c1551 implementation (quite slow, especially |
| 115 | | if you turn on logging) |
| 116 | | + no support for other drive types (even if now I list all |
| 117 | | the variants supported by Vice in the enum) |
| 118 | | + communications between the drive CPU and the computer CPU have |
| 119 | | to be checked, debugged and improved: somehow it works, but no |
| 120 | | sync bit is set (encoding bug? timers-related bug?) and the drive |
| 121 | | keeps reading beyond the end of the track (synchronization |
| 122 | | problems?) |
| 123 | | + all but .g64 images should be correctly encoded at loading time |
| 124 | | (I actually have doubts about some .d82 details) |
| 125 | | + error maps are not still used, even if their presence is |
| 126 | | acknowledged |
| 127 | | + floppy drives should become devices and use ROMREGION_LOADBYNAME |
| 128 | | for their ROMs (not the current defines) |
| 129 | | + all available drive dumps are included for each systems using it |
| 130 | | (vc1541 = sx64, vip64, c16v, plus4v; vc1571 = c128d; vc1571cr = c128dcr; |
| 131 | | vc1581 = c128d81; vc1540 = vc20v, vic20plv; c2031 = vc20i (only dumps added); |
| 132 | | c1551 = c16c, plus4c). this is only a temporary workaround to document |
| 133 | | available dumps. correct revisions will be used with each systems when |
| 134 | | emulation works (or 'default' bios will be used for most common |
| 135 | | configurations, when machines were compatible with more than a single |
| 136 | | drive model) |
| 137 | | */ |
| 138 | | /* |
| 139 | | Informations on the fileformats (which the code is based on) |
| 140 | | |
| 141 | | D64 - http://ist.uwaterloo.ca/~schepers/formats/D64.TXT |
| 142 | | D71 - http://ist.uwaterloo.ca/~schepers/formats/D71.TXT |
| 143 | | D81 - http://ist.uwaterloo.ca/~schepers/formats/D81.TXT |
| 144 | | D80 & D82 - http://ist.uwaterloo.ca/~schepers/formats/D80-D82.TXT |
| 145 | | G64 & GCR - http://ist.uwaterloo.ca/~schepers/formats/G64.TXT |
| 146 | | GCR - http://www.baltissen.org/newhtm/1541c.htm |
| 147 | | |
| 148 | | Other info sources: |
| 149 | | http://sta.c64.org/cbm1541mem.html |
| 150 | | |
| 151 | | */ |
| 152 | | |
| 153 | | |
| 154 | | #include "driver.h" |
| 155 | | #include "image.h" |
| 156 | | #include "cpu/m6502/m6502.h" |
| 157 | | #include "machine/6525tpi.h" |
| 158 | | #include "machine/6522via.h" |
| 159 | | #include "includes/cbmserb.h" |
| 160 | | |
| 161 | | #include "includes/vc1541.h" |
| 162 | | |
| 163 | | |
| 164 | | #define VERBOSE_LEVEL 0 |
| 165 | | #define DBG_LOG( MACHINE, N, M, A ) \ |
| 166 | | do { \ |
| 167 | | if(VERBOSE_LEVEL >= N) \ |
| 168 | | { \ |
| 169 | | if( M ) \ |
| 170 | | logerror("%11.6f: %-24s", attotime_to_double(timer_get_time(MACHINE)), (char*) M ); \ |
| 171 | | logerror A; \ |
| 172 | | } \ |
| 173 | | } while (0) |
| 174 | | |
| 175 | | #define XTAL_16_MHz 16000000 |
| 176 | | |
| 177 | | |
| 178 | | /* |
| 179 | | * only for testing at the moment |
| 180 | | */ |
| 181 | | |
| 182 | | #define WRITEPROTECTED 0 |
| 183 | | |
| 184 | | |
| 185 | | /******************************************* |
| 186 | | |
| 187 | | Structures |
| 188 | | |
| 189 | | *******************************************/ |
| 190 | | |
| 191 | | /* Legacy code. At a later stage, we should convert everything to devices. |
| 192 | | However, fixing the C64 / Floppy drive communications is a priority over |
| 193 | | cleaning up of this part */ |
| 194 | | |
| 195 | | |
| 196 | | /* 0 summarized, 1 computer, 2 vc1541 */ |
| 197 | | static struct |
| 198 | | { |
| 199 | | int atn[3], data[3], clock[3]; |
| 200 | | } |
| 201 | | serial; |
| 202 | | |
| 203 | | typedef struct |
| 204 | | { |
| 205 | | int sync; // active after > 9 '1's |
| 206 | | int ones_count; |
| 207 | | int ready; // needed for 1551 |
| 208 | | UINT8 *data; // entire d64 image encoded at loading time |
| 209 | | } GCR_data; |
| 210 | | |
| 211 | | typedef struct |
| 212 | | { |
| 213 | | const char *cputag; |
| 214 | | int type; |
| 215 | | |
| 216 | | int led, motor, frequency; |
| 217 | | |
| 218 | | double track; |
| 219 | | int clock; |
| 220 | | int start_pos, pos; // start_pos = start of half track ; pos = position from the beginning of the current half-track! |
| 221 | | |
| 222 | | void *timer; |
| 223 | | |
| 224 | | GCR_data gcr; |
| 225 | | |
| 226 | | /* vc1541 specific */ |
| 227 | | struct { |
| 228 | | int deviceid; |
| 229 | | int serial_atn, serial_clock, serial_data; |
| 230 | | int acka, data; |
| 231 | | } vc1541_serial; |
| 232 | | |
| 233 | | int via0irq, via1irq; |
| 234 | | |
| 235 | | } _vc1541_drive_emu_t; |
| 236 | | |
| 237 | | typedef struct |
| 238 | | { |
| 239 | | const char *cputag; |
| 240 | | int type; |
| 241 | | |
| 242 | | int led, motor, frequency; |
| 243 | | |
| 244 | | double track; |
| 245 | | int clock; |
| 246 | | int start_pos, pos; // start_pos = start of half track ; pos = position from the beginning of the current half-track! |
| 247 | | |
| 248 | | void *timer; |
| 249 | | |
| 250 | | GCR_data gcr; |
| 251 | | |
| 252 | | /* c1551 specific */ |
| 253 | | UINT8 cpu_ddr, cpu_port; |
| 254 | | void *irq_timer; |
| 255 | | |
| 256 | | } _c1551_drive_emu_t; |
| 257 | | |
| 258 | | static _vc1541_drive_emu_t vc1541_drive; |
| 259 | | static _c1551_drive_emu_t c1551_drive; |
| 260 | | |
| 261 | | |
| 262 | | /******************************************* |
| 263 | | |
| 264 | | Format specific code |
| 265 | | |
| 266 | | *******************************************/ |
| 267 | | |
| 268 | | |
| 269 | | /* Are there other formats to support which could require more tracks? */ |
| 270 | | #define IMAGE_MAX_TRACKS 154 |
| 271 | | |
| 272 | | #define D64_MAX_TRACKS 35 |
| 273 | | #define D64_40T_MAX_TRACKS 40 |
| 274 | | |
| 275 | | static const int d64_sectors_per_track[] = |
| 276 | | { |
| 277 | | 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, |
| 278 | | 19, 19, 19, 19, 19, 19, 19, |
| 279 | | 18, 18, 18, 18, 18, 18, |
| 280 | | 17, 17, 17, 17, 17, |
| 281 | | 17, 17, 17, 17, 17, /* only for 40 tracks d64 */ |
| 282 | | 17, 17 /* in principle the drive could read 42 tracks */ |
| 283 | | }; |
| 284 | | |
| 285 | | #define D71_MAX_TRACKS 70 |
| 286 | | |
| 287 | | static const int d71_sectors_per_track[] = |
| 288 | | { |
| 289 | | 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, |
| 290 | | 19, 19, 19, 19, 19, 19, 19, |
| 291 | | 18, 18, 18, 18, 18, 18, |
| 292 | | 17, 17, 17, 17, 17, |
| 293 | | 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, |
| 294 | | 19, 19, 19, 19, 19, 19, 19, |
| 295 | | 18, 18, 18, 18, 18, 18, |
| 296 | | 17, 17, 17, 17, 17 |
| 297 | | }; |
| 298 | | |
| 299 | | #define D81_MAX_TRACKS 80 |
| 300 | | |
| 301 | | /* Each track in a d81 file has 40 sectors, so no need of a sectors_per_track table */ |
| 302 | | |
| 303 | | #define D80_MAX_TRACKS 77 |
| 304 | | |
| 305 | | static const int d80_sectors_per_track[] = |
| 306 | | { |
| 307 | | 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, |
| 308 | | 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, |
| 309 | | 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, |
| 310 | | 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, |
| 311 | | 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23 |
| 312 | | }; |
| 313 | | |
| 314 | | |
| 315 | | /* Still have to investigate if these are read as 154 or as 77 in the drive... */ |
| 316 | | /* For now we assume it's 154, but I'm not sure */ |
| 317 | | #define D82_MAX_TRACKS 154 |
| 318 | | |
| 319 | | static const int d82_sectors_per_track[] = |
| 320 | | { |
| 321 | | 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, |
| 322 | | 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, |
| 323 | | 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, |
| 324 | | 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, |
| 325 | | 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, |
| 326 | | 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, |
| 327 | | 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, |
| 328 | | 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, |
| 329 | | 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, |
| 330 | | 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23 |
| 331 | | }; |
| 332 | | |
| 333 | | |
| 334 | | static const int max_tracks_per_format[] = |
| 335 | | { |
| 336 | | D64_MAX_TRACKS, |
| 337 | | D64_MAX_TRACKS, |
| 338 | | D64_40T_MAX_TRACKS, |
| 339 | | D64_40T_MAX_TRACKS, |
| 340 | | D64_MAX_TRACKS, |
| 341 | | D71_MAX_TRACKS, |
| 342 | | D71_MAX_TRACKS, |
| 343 | | D81_MAX_TRACKS, |
| 344 | | D80_MAX_TRACKS, |
| 345 | | D82_MAX_TRACKS, |
| 346 | | 0 /* Still to add support for .g64 */ |
| 347 | | }; |
| 348 | | |
| 349 | | static int image_offset[IMAGE_MAX_TRACKS]; |
| 350 | | static int gcr_offset[IMAGE_MAX_TRACKS]; |
| 351 | | |
| 352 | | /******************************************* |
| 353 | | |
| 354 | | Offset initialization |
| 355 | | |
| 356 | | *******************************************/ |
| 357 | | |
| 358 | | /* This is twice useful: with length = 256, it allows to determine the starting offset of each |
| 359 | | track in the .d64 image; with length = 368, it allows to determine the starting offset of each |
| 360 | | track in the GCR encoded image */ |
| 361 | | static void offset_init( int format, int *offset_list, int length ) |
| 362 | | { |
| 363 | | int i; |
| 364 | | |
| 365 | | /* Track # starts from 1, hence Track k will start at image_offset[k-1] */ |
| 366 | | offset_list[0] = 0; |
| 367 | | |
| 368 | | switch (format) |
| 369 | | { |
| 370 | | case format_d64: |
| 371 | | case format_d64_err: |
| 372 | | case format_d67: |
| 373 | | for (i = 1; i < D64_MAX_TRACKS; i++) |
| 374 | | offset_list[i] = offset_list[i - 1] + d64_sectors_per_track[i - 1] * length; |
| 375 | | break; |
| 376 | | |
| 377 | | case format_d64_40t: |
| 378 | | case format_d64_40t_err: |
| 379 | | for (i = 1; i < D64_40T_MAX_TRACKS; i++) |
| 380 | | offset_list[i] = offset_list[i - 1] + d64_sectors_per_track[i - 1] * length; |
| 381 | | break; |
| 382 | | |
| 383 | | case format_d71: |
| 384 | | case format_d71_err: |
| 385 | | for (i = 1; i < D71_MAX_TRACKS; i++) |
| 386 | | offset_list[i] = offset_list[i - 1] + d71_sectors_per_track[i - 1] * length; |
| 387 | | break; |
| 388 | | |
| 389 | | case format_d81: |
| 390 | | for (i = 1; i < D81_MAX_TRACKS; i++) |
| 391 | | offset_list[i] = offset_list[i - 1] + 40 * length; |
| 392 | | break; |
| 393 | | |
| 394 | | case format_d80: |
| 395 | | for (i = 1; i < D80_MAX_TRACKS; i++) |
| 396 | | offset_list[i] = offset_list[i - 1] + d80_sectors_per_track[i - 1] * length; |
| 397 | | break; |
| 398 | | |
| 399 | | case format_d82: |
| 400 | | for (i = 1; i < D82_MAX_TRACKS; i++) |
| 401 | | offset_list[i] = offset_list[i - 1] + d82_sectors_per_track[i - 1] * length; |
| 402 | | break; |
| 403 | | |
| 404 | | default: |
| 405 | | /* Still have to work on g64 images */ |
| 406 | | logerror("Unsupported format\n"); |
| 407 | | break; |
| 408 | | } |
| 409 | | } |
| 410 | | |
| 411 | | |
| 412 | | /******************************************* |
| 413 | | |
| 414 | | Generic image handling |
| 415 | | |
| 416 | | *******************************************/ |
| 417 | | |
| 418 | | |
| 419 | | /* This calculates starting offset (from the beginning of the image file) of a sector */ |
| 420 | | /* Since sectors are always 256 bytes large, this works no matter the file format! */ |
| 421 | | static int image_tracksector2offset( int track, int sector ) |
| 422 | | { |
| 423 | | return image_offset[track - 1] + sector * 256; |
| 424 | | } |
| 425 | | |
| 426 | | #ifdef UNUSED_FUNCTION |
| 427 | | // WARNING: this would work with a d64 image... it has to be adapted to work with GCR image we store at loading time |
| 428 | | static void image_offset2tracksector( int offset ) |
| 429 | | { |
| 430 | | int track = 0, sector = 0, helper, i = 0; |
| 431 | | |
| 432 | | helper = offset; |
| 433 | | |
| 434 | | do |
| 435 | | { |
| 436 | | helper -= (d64_sectors_per_track[++i] * 256); |
| 437 | | } while (helper > 0); |
| 438 | | |
| 439 | | track = i; |
| 440 | | |
| 441 | | sector = (offset - image_offset[track]) / 256; |
| 442 | | |
| 443 | | logerror("We are reading at offset %d, which is in track %d and sector %d \n", offset, track, sector); |
| 444 | | } |
| 445 | | #endif |
| 446 | | |
| 447 | | |
| 448 | | /* These functions return the Disk ID stored in the disk BAM */ |
| 449 | | /* It is not necessarily the one some copy protection checks, and |
| 450 | | indeed, in these cases a g64 image is needed (which stores the |
| 451 | | Disk ID as coded in the GCR data) */ |
| 452 | | |
| 453 | | static int disk_id1( int format ) |
| 454 | | { |
| 455 | | int id1 = 0; |
| 456 | | |
| 457 | | switch (format) |
| 458 | | { |
| 459 | | case format_d64: |
| 460 | | case format_d64_err: |
| 461 | | case format_d64_40t: |
| 462 | | case format_d64_40t_err: |
| 463 | | case format_d67: |
| 464 | | case format_d71: |
| 465 | | case format_d71_err: |
| 466 | | id1 = image_tracksector2offset(18, 0) + 0xa2; |
| 467 | | break; |
| 468 | | |
| 469 | | case format_d81: |
| 470 | | id1 = image_tracksector2offset(40, 0) + 0x16; |
| 471 | | break; |
| 472 | | |
| 473 | | case format_d80: |
| 474 | | case format_d82: |
| 475 | | id1 = image_tracksector2offset(39, 0) + 0x18; |
| 476 | | break; |
| 477 | | |
| 478 | | default: |
| 479 | | /* Still have to work on g64 images */ |
| 480 | | logerror("Unsupported format\n"); |
| 481 | | break; |
| 482 | | } |
| 483 | | |
| 484 | | return id1; |
| 485 | | } |
| 486 | | |
| 487 | | |
| 488 | | static int disk_id2( int format ) |
| 489 | | { |
| 490 | | int id2 = 0; |
| 491 | | |
| 492 | | switch (format) |
| 493 | | { |
| 494 | | case format_d64: |
| 495 | | case format_d64_err: |
| 496 | | case format_d64_40t: |
| 497 | | case format_d64_40t_err: |
| 498 | | case format_d67: |
| 499 | | case format_d71: |
| 500 | | case format_d71_err: |
| 501 | | id2 = image_tracksector2offset(18, 0) + 0xa3; |
| 502 | | break; |
| 503 | | |
| 504 | | case format_d81: |
| 505 | | id2 = image_tracksector2offset(40, 0) + 0x17; |
| 506 | | break; |
| 507 | | |
| 508 | | case format_d80: |
| 509 | | case format_d82: |
| 510 | | id2 = image_tracksector2offset(39, 0) + 0x19; |
| 511 | | break; |
| 512 | | |
| 513 | | default: |
| 514 | | /* Still have to work on g64 images */ |
| 515 | | logerror("Unsupported format\n"); |
| 516 | | break; |
| 517 | | } |
| 518 | | |
| 519 | | return id2; |
| 520 | | } |
| 521 | | |
| 522 | | |
| 523 | | /* Four different frequencies for the 4 different zones on the disk */ |
| 524 | | /* These work for 1541 drives, are the same for other drives? */ |
| 525 | | static const double drive_times[4]= |
| 526 | | { |
| 527 | | XTAL_16_MHz / 13, XTAL_16_MHz / 14, XTAL_16_MHz / 15, XTAL_16_MHz / 16 |
| 528 | | }; |
| 529 | | |
| 530 | | |
| 531 | | /* Commodore GCR format */ |
| 532 | | /* |
| 533 | | Original Encoded |
| 534 | | 4 bits 5 bits |
| 535 | | |
| 536 | | 0000 -> 01010 = 0x0a |
| 537 | | 0001 -> 01011 = 0x0b |
| 538 | | 0010 -> 10010 = 0x12 |
| 539 | | 0011 -> 10011 = 0x13 |
| 540 | | 0100 -> 01110 = 0x0e |
| 541 | | 0101 -> 01111 = 0x0f |
| 542 | | 0110 -> 10110 = 0x16 |
| 543 | | 0111 -> 10111 = 0x17 |
| 544 | | 1000 -> 01001 = 0x09 |
| 545 | | 1001 -> 11001 = 0x19 |
| 546 | | 1010 -> 11010 = 0x1a |
| 547 | | 1011 -> 11011 = 0x1b |
| 548 | | 1100 -> 01101 = 0x0d |
| 549 | | 1101 -> 11101 = 0x1d |
| 550 | | 1110 -> 11110 = 0x1e |
| 551 | | 1111 -> 10101 = 0x15 |
| 552 | | |
| 553 | | We use the encoded values in bytes because we use them to encode |
| 554 | | groups of 4 bytes into groups of 5 bytes, below. |
| 555 | | */ |
| 556 | | |
| 557 | | static const int bin_2_gcr[] = |
| 558 | | { |
| 559 | | 0x0a, 0x0b, 0x12, 0x13, 0x0e, 0x0f, 0x16, 0x17, |
| 560 | | 0x09, 0x19, 0x1a, 0x1b, 0x0d, 0x1d, 0x1e, 0x15 |
| 561 | | }; |
| 562 | | |
| 563 | | |
| 564 | | /* This could be of use if we ever implement saving in .d64 format, to convert back GCR -> d64 */ |
| 565 | | #if 0 |
| 566 | | static const int gcr_2_bin[] = |
| 567 | | { |
| 568 | | -1, -1, -1, -1, |
| 569 | | -1, -1, -1, -1, |
| 570 | | -1, 0x08, 0x00, 0x01, |
| 571 | | -1, 0x0c, 0x04, 0x05, |
| 572 | | -1, -1, 0x02, 0x03, |
| 573 | | -1, 0x0f, 0x06, 0x07, |
| 574 | | -1, 0x09, 0x0a, 0x0b, |
| 575 | | -1, 0x0d, 0x0e, -1 |
| 576 | | }; |
| 577 | | #endif |
| 578 | | |
| 579 | | |
| 580 | | /* gcr_double_2_gcr takes 4 bytes (a, b, c, d) and shuffles their nibbles to obtain 5 bytes in dest */ |
| 581 | | /* The result is basically res = (enc(a) << 15) | (enc(b) << 10) | (enc(c) << 5) | enc(d) |
| 582 | | * with res being 5 bytes long and enc(x) being the GCR encode of x. |
| 583 | | * In fact, we store the result as five separate bytes in the dest argument |
| 584 | | */ |
| 585 | | static void gcr_double_2_gcr( UINT8 a, UINT8 b, UINT8 c, UINT8 d, UINT8 *dest ) |
| 586 | | { |
| 587 | | UINT8 gcr[8]; |
| 588 | | |
| 589 | | /* Encode each nibble to 5 bits */ |
| 590 | | gcr[0] = bin_2_gcr[a >> 4]; |
| 591 | | gcr[1] = bin_2_gcr[a & 0x0f]; |
| 592 | | gcr[2] = bin_2_gcr[b >> 4]; |
| 593 | | gcr[3] = bin_2_gcr[b & 0x0f]; |
| 594 | | gcr[4] = bin_2_gcr[c >> 4]; |
| 595 | | gcr[5] = bin_2_gcr[c & 0x0f]; |
| 596 | | gcr[6] = bin_2_gcr[d >> 4]; |
| 597 | | gcr[7] = bin_2_gcr[d & 0x0f]; |
| 598 | | |
| 599 | | /* Re-order the encoded data to only keep the 5 lower bits of each byte */ |
| 600 | | dest[0] = (gcr[0] << 3) | (gcr[1] >> 2); |
| 601 | | dest[1] = (gcr[1] << 6) | (gcr[2] << 1) | (gcr[3] >> 4); |
| 602 | | dest[2] = (gcr[3] << 4) | (gcr[4] >> 1); |
| 603 | | dest[3] = (gcr[4] << 7) | (gcr[5] << 2) | (gcr[6] >> 3); |
| 604 | | dest[4] = (gcr[6] << 5) | gcr[7]; |
| 605 | | } |
| 606 | | |
| 607 | | /* FIXME: temp workaround */ |
| 608 | | static void filling_byte( UINT8 a, UINT8 *dest ) |
| 609 | | { |
| 610 | | dest[0] = a; |
| 611 | | } |
| 612 | | |
| 613 | | |
| 614 | | /************************************** |
| 615 | | |
| 616 | | Drive timers (aka floppy reading) |
| 617 | | |
| 618 | | **************************************/ |
| 619 | | |
| 620 | | static TIMER_CALLBACK( vc1541_drive_timer ) |
| 621 | | { |
| 622 | | const device_config *via_1 = devtag_get_device(machine, "_1541_via_1"); |
| 623 | | |
| 624 | | if (vc1541_drive.clock == 0) |
| 625 | | { |
| 626 | | vc1541_drive.gcr.ready = 0; |
| 627 | | // why put sync back to 0 here?!? it would break the sync count, isn't it? |
| 628 | | // or is it the way the serial port reads the sync count?!? |
| 629 | | vc1541_drive.gcr.sync = 0; |
| 630 | | |
| 631 | | cputag_set_input_line(machine, vc1541_drive.cputag, M6502_SET_OVERFLOW, 1); |
| 632 | | via_ca1_w(via_1, 0, 1); |
| 633 | | |
| 634 | | vc1541_drive.clock = 1; |
| 635 | | return; |
| 636 | | } |
| 637 | | |
| 638 | | // this code has 2 effects: move on the pos on the data and reset it to 0 at the end of the track! |
| 639 | | // size of the track is: (# sectors in the track) * (size of sector GCR endoded) |
| 640 | | // Here, size of sector is 368 because of our choices in the loading: 9 bytes of header gap & 14 bytes of sector gap |
| 641 | | // We will need to set the size at loading time when adding support for G64 images |
| 642 | | if (++(vc1541_drive.pos) >= (d64_sectors_per_track[(int)vc1541_drive.track - 1] * 368)) |
| 643 | | vc1541_drive.pos = 0; |
| 644 | | // should we check if there is a change of track? to reset the pos in that case as well? |
| 645 | | |
| 646 | | vc1541_drive.gcr.ready = 1; |
| 647 | | |
| 648 | | // notice that if there is a sequence of more than 40 1s it correctly does not reset the sync |
| 649 | | // counter until a 0 is found |
| 650 | | if (vc1541_drive.gcr.data[vc1541_drive.pos] == 0xff) |
| 651 | | { |
| 652 | | vc1541_drive.gcr.ones_count++; |
| 653 | | |
| 654 | | // if (vc1541_drive.gcr.ones_count == 2) // 9 ones should already mark it as a sync, even if CBM chose to use 40 of them |
| 655 | | if (vc1541_drive.gcr.ones_count == 5) |
| 656 | | vc1541_drive.gcr.sync = 1; |
| 657 | | } |
| 658 | | else |
| 659 | | { |
| 660 | | vc1541_drive.gcr.ones_count = 0; |
| 661 | | vc1541_drive.gcr.sync = 0; |
| 662 | | } |
| 663 | | |
| 664 | | cputag_set_input_line(machine, vc1541_drive.cputag, M6502_SET_OVERFLOW, 0); |
| 665 | | via_ca1_w(via_1, 0, 0); |
| 666 | | |
| 667 | | vc1541_drive.clock = 0; |
| 668 | | } |
| 669 | | |
| 670 | | static TIMER_CALLBACK( c1551_drive_timer ) |
| 671 | | { |
| 672 | | if (c1551_drive.clock == 0) |
| 673 | | { |
| 674 | | c1551_drive.gcr.ready = 0; |
| 675 | | // why put sync back to 0 here?!? it would break the sync count, isn't it? |
| 676 | | // or is it the way the serial port reads the sync count?!? |
| 677 | | c1551_drive.gcr.sync = 0; |
| 678 | | |
| 679 | | c1551_drive.clock = 1; |
| 680 | | return; |
| 681 | | } |
| 682 | | |
| 683 | | // this code has 2 effects: move on the pos on the data and reset it to 0 at the end of the track! |
| 684 | | // size of the track is: (# sectors in the track) * (size of sector GCR endoded) |
| 685 | | // Here, size of sector is 368 because of our choices in the loading: 9 bytes of header gap & 14 bytes of sector gap |
| 686 | | // We will need to set the size at loading time when adding support for G64 images |
| 687 | | if (++(c1551_drive.pos) >= (d64_sectors_per_track[(int)c1551_drive.track - 1] * 368)) |
| 688 | | c1551_drive.pos = 0; |
| 689 | | // should we check if there is a change of track? to reset the pos in that case as well? |
| 690 | | |
| 691 | | c1551_drive.gcr.ready = 1; |
| 692 | | |
| 693 | | // notice that if there is a sequence of more than 40 1s it correctly does not reset the sync |
| 694 | | // counter until a 0 is found |
| 695 | | if (c1551_drive.gcr.data[c1551_drive.pos] == 0xff) |
| 696 | | { |
| 697 | | c1551_drive.gcr.ones_count++; |
| 698 | | |
| 699 | | // if (c1551_drive.gcr.ones_count == 2) // 9 ones should already mark it as a sync, even if CBM chose to use 40 of them |
| 700 | | if (c1551_drive.gcr.ones_count == 5) |
| 701 | | c1551_drive.gcr.sync = 1; |
| 702 | | } |
| 703 | | else |
| 704 | | { |
| 705 | | c1551_drive.gcr.ones_count = 0; |
| 706 | | c1551_drive.gcr.sync = 0; |
| 707 | | } |
| 708 | | |
| 709 | | c1551_drive.clock = 0; |
| 710 | | } |
| 711 | | |
| 712 | | |
| 713 | | /************************************** |
| 714 | | |
| 715 | | VC1541 Serial Bus Device Interface |
| 716 | | |
| 717 | | **************************************/ |
| 718 | | |
| 719 | | /* 2009-05 FP - Note: I could use directly these functions as DEVICE_HANDLERs for |
| 720 | | the serial bus device, but these are also used in the VIA interface above, so I |
| 721 | | prefer to keep the handlers separated at this stage. Further work on the serial |
| 722 | | bus emulation should allow to remove the duplicated code. */ |
| 723 | | |
| 724 | | static void vc1541_serial_reset_write( running_machine *machine, int which, int level ) |
| 725 | | { |
| 726 | | } |
| 727 | | |
| 728 | | static UINT8 vc1541_serial_atn_read( running_machine *machine, int which ) |
| 729 | | { |
| 730 | | /* there is no more cpu_getactivecpu! */ |
| 731 | | #ifdef CPU_SYNC |
| 732 | | if (cpu_getactivecpu()==0) cpu_sync(); |
| 733 | | #endif |
| 734 | | return serial.atn[0]; |
| 735 | | } |
| 736 | | |
| 737 | | static void vc1541_serial_atn_write( running_machine *machine, int which, int level ) |
| 738 | | { |
| 739 | | const device_config *via_0 = devtag_get_device(machine, "_1541_via_0"); |
| 740 | | #if 0 |
| 741 | | int value; |
| 742 | | #endif |
| 743 | | if (serial.atn[1 + which] != level) |
| 744 | | { |
| 745 | | /* there is no more cpu_getactivecpu! */ |
| 746 | | #ifdef CPU_SYNC |
| 747 | | if (cpu_getactivecpu()==0) cpu_sync(); |
| 748 | | #endif |
| 749 | | serial.atn[1 + which] = level; |
| 750 | | if (serial.atn[0] != level) |
| 751 | | { |
| 752 | | serial.atn[0] = serial.atn[1] && serial.atn[2]; |
| 753 | | if (serial.atn[0] == level) |
| 754 | | { |
| 755 | | #if 0 |
| 756 | | DBG_LOG(machine, 1, "vc1541",("%d:%.4x atn %s\n", |
| 757 | | cpu_getactivecpu (), |
| 758 | | activecpu_get_pc(), |
| 759 | | serial.atn[0]?"ATN":"atn")); |
| 760 | | #endif |
| 761 | | via_ca1_w (via_0, 0, !level); |
| 762 | | #if 0 |
| 763 | | value = vc1541_drive.vc1541_serial.data; |
| 764 | | if (vc1541_drive.vc1541_serial.acka != !level) |
| 765 | | value = 0; |
| 766 | | if (value != serial.data[2]) |
| 767 | | { |
| 768 | | serial.data[2] = value; |
| 769 | | if (serial.data[0] != value) |
| 770 | | { |
| 771 | | serial.data[0] = serial.data[1] && serial.data[2]; |
| 772 | | } |
| 773 | | } |
| 774 | | #endif |
| 775 | | } |
| 776 | | } |
| 777 | | } |
| 778 | | } |
| 779 | | |
| 780 | | static UINT8 vc1541_serial_data_read( running_machine *machine, int which ) |
| 781 | | { |
| 782 | | /* there is no more cpu_getactivecpu! */ |
| 783 | | #ifdef CPU_SYNC |
| 784 | | if (cpu_getactivecpu()==0) cpu_sync(); |
| 785 | | #endif |
| 786 | | return serial.data[0]; |
| 787 | | } |
| 788 | | |
| 789 | | static void vc1541_serial_data_write( running_machine *machine, int which, int level ) |
| 790 | | { |
| 791 | | if (serial.data[1 + which] != level) |
| 792 | | { |
| 793 | | /* there is no more cpu_getactivecpu! */ |
| 794 | | #ifdef CPU_SYNC |
| 795 | | if (cpu_getactivecpu()==0) cpu_sync(); |
| 796 | | #endif |
| 797 | | serial.data[1 + which] = level; |
| 798 | | if (serial.data[0] != level) |
| 799 | | { |
| 800 | | serial.data[0] = serial.data[1] && serial.data[2]; |
| 801 | | #if 0 |
| 802 | | if (serial.data[0] == level) |
| 803 | | { |
| 804 | | DBG_LOG(machine, 1, "vc1541",("%d:%.4x data %s\n", |
| 805 | | cpu_getactivecpu (), |
| 806 | | activecpu_get_pc(), |
| 807 | | serial.data[0]?"DATA":"data")); |
| 808 | | } |
| 809 | | #endif |
| 810 | | } |
| 811 | | } |
| 812 | | } |
| 813 | | |
| 814 | | static UINT8 vc1541_serial_clock_read( running_machine *machine, int which ) |
| 815 | | { |
| 816 | | /* there is no more cpu_getactivecpu! */ |
| 817 | | #ifdef CPU_SYNC |
| 818 | | if (cpu_getactivecpu()==0) cpu_sync(); |
| 819 | | #endif |
| 820 | | return serial.clock[0]; |
| 821 | | } |
| 822 | | |
| 823 | | static void vc1541_serial_clock_write( running_machine *machine, int which, int level ) |
| 824 | | { |
| 825 | | if (serial.clock[1 + which] != level) |
| 826 | | { |
| 827 | | /* there is no more cpu_getactivecpu! */ |
| 828 | | #ifdef CPU_SYNC |
| 829 | | if (cpu_getactivecpu()==0) cpu_sync(); |
| 830 | | #endif |
| 831 | | serial.clock[1 + which] = level; |
| 832 | | if (serial.clock[0] != level) |
| 833 | | { |
| 834 | | serial.clock[0] = serial.clock[1] && serial.clock[2]; |
| 835 | | if (serial.clock[0] == level) |
| 836 | | { |
| 837 | | /* DBG_LOG(machine, 1, "vc1541",("%d:%.4x clock %s\n", |
| 838 | | cpu_getactivecpu (), |
| 839 | | activecpu_get_pc(), |
| 840 | | serial.clock[0]?"CLOCK":"clock"));*/ |
| 841 | | } |
| 842 | | } |
| 843 | | } |
| 844 | | } |
| 845 | | |
| 846 | | static UINT8 vc1541_serial_request_read( running_machine *machine, int which ) |
| 847 | | { |
| 848 | | return 1; |
| 849 | | } |
| 850 | | |
| 851 | | static void vc1541_serial_request_write( running_machine *machine, int which, int level ) |
| 852 | | { |
| 853 | | } |
| 854 | | |
| 855 | | |
| 856 | | /* 2009-05 FP - TODO: better implementation of the DEVICE_HANDLERs below. Right now they are |
| 857 | | redundant (see also my Note above) */ |
| 858 | | static READ8_DEVICE_HANDLER( emu_drive_atn_read ) |
| 859 | | { |
| 860 | | return vc1541_serial_atn_read(device->machine, 0); |
| 861 | | } |
| 862 | | |
| 863 | | static READ8_DEVICE_HANDLER( emu_drive_clock_read ) |
| 864 | | { |
| 865 | | return vc1541_serial_clock_read(device->machine, 0); |
| 866 | | } |
| 867 | | |
| 868 | | static READ8_DEVICE_HANDLER( emu_drive_data_read ) |
| 869 | | { |
| 870 | | return vc1541_serial_data_read(device->machine, 0); |
| 871 | | } |
| 872 | | |
| 873 | | static READ8_DEVICE_HANDLER( emu_drive_request_read ) |
| 874 | | { |
| 875 | | return vc1541_serial_request_read(device->machine, 0); |
| 876 | | } |
| 877 | | |
| 878 | | static WRITE8_DEVICE_HANDLER( emu_drive_atn_write ) |
| 879 | | { |
| 880 | | vc1541_serial_atn_write(device->machine, 0, data); |
| 881 | | } |
| 882 | | |
| 883 | | static WRITE8_DEVICE_HANDLER( emu_drive_clock_write ) |
| 884 | | { |
| 885 | | vc1541_serial_clock_write(device->machine, 0, data); |
| 886 | | } |
| 887 | | |
| 888 | | static WRITE8_DEVICE_HANDLER( emu_drive_data_write ) |
| 889 | | { |
| 890 | | vc1541_serial_data_write(device->machine, 0, data); |
| 891 | | } |
| 892 | | |
| 893 | | static WRITE8_DEVICE_HANDLER( emu_drive_request_write ) |
| 894 | | { |
| 895 | | vc1541_serial_request_write(device->machine, 0, data); |
| 896 | | } |
| 897 | | |
| 898 | | static WRITE8_DEVICE_HANDLER( emu_drive_reset_write ) |
| 899 | | { |
| 900 | | vc1541_serial_reset_write(device->machine, 0, data); |
| 901 | | } |
| 902 | | |
| 903 | | |
| 904 | | static const cbm_serial_bus_interface cbm_emu_drive_interface = |
| 905 | | { |
| 906 | | DEVCB_HANDLER(emu_drive_atn_read), |
| 907 | | DEVCB_HANDLER(emu_drive_clock_read), |
| 908 | | DEVCB_HANDLER(emu_drive_data_read), |
| 909 | | DEVCB_HANDLER(emu_drive_request_read), |
| 910 | | DEVCB_HANDLER(emu_drive_atn_write), |
| 911 | | DEVCB_HANDLER(emu_drive_clock_write), |
| 912 | | DEVCB_HANDLER(emu_drive_data_write), |
| 913 | | DEVCB_HANDLER(emu_drive_request_write), |
| 914 | | |
| 915 | | DEVCB_HANDLER(emu_drive_reset_write) |
| 916 | | }; |
| 917 | | |
| 918 | | |
| 919 | | |
| 920 | | /************************************************************************** |
| 921 | | * VIA 6522 at 0x1800 |
| 922 | | * |
| 923 | | * 0x1800 port B |
| 924 | | * bit 0 : data in (inverted: 0 = Low, 1 = High) |
| 925 | | * bit 1 : data out (inverted: 0 = Low, 1 = High) |
| 926 | | * bit 2 : clock in (inverted: 0 = Low, 1 = High) |
| 927 | | * bit 3 : clock out (inverted: 0 = Low, 1 = High) |
| 928 | | * bit 4 : atna out (inverted: 0 = Low, 1 = High) |
| 929 | | * bit 5 : device id 1 |
| 930 | | * bit 6 : device id 2 |
| 931 | | * device ID number is set by a jumper: |
| 932 | | * 00 = 8 (default), 01 = 9, 10 = 10, 11 = 11 |
| 933 | | * bit 7 : atn in (inverted: 0 = Low, 1 = High) |
| 934 | | * 0x1801 port A - Read to acknowledge interrupt generated by ATN IN going high. |
| 935 | | * 0x1802 port B data direction register. |
| 936 | | * if a bit here is 0, then the corresponding bit of portB can only be read |
| 937 | | * if a bit here is 1, then the corresponding bit of portB can be read and written |
| 938 | | * default value 0x1a |
| 939 | | * 0x1803 port A data direction register. |
| 940 | | * default value 0xff |
| 941 | | * 0x1804 timer 1 counter (low) |
| 942 | | * 0x1805 timer 1 counter (high) / Timer one counter |
| 943 | | * Read low byte or write high byte to start timer or restart timer upon underflow. |
| 944 | | * 0x1806 timer 1 latch (low) |
| 945 | | * 0x1807 timer 1 latch (high) |
| 946 | | * read/write starting value of timer from/to here. |
| 947 | | * 0x1808 timer 2 counter (low) |
| 948 | | * 0x1809 timer 2 counter (high) |
| 949 | | * 0x180a shift register |
| 950 | | * 0x180b auxiliary control register. bit 6: 0 = Stop timer; 1 = Start timer. |
| 951 | | * 0x180c peripheral control register |
| 952 | | * 0x180d interrupt flag register. bit 1: 1 = ATN IN went high, bit 6: 1 = Timer underflow occurred. |
| 953 | | * 0x180e interrupt enable register. |
| 954 | | * bit 1: write - 1 = Enable interrupts generated by ATN IN going high |
| 955 | | * bit 7: read - interrupt has been generated. |
| 956 | | * bit 7: write - Fill bit: bits 0-6, that are set to 1, get their values from this bit; bits 0-6, that are set to 0, are left unchanged |
| 957 | | * |
| 958 | | * also ca1 (books says cb2) |
| 959 | | * irq to m6502 irq connected (or with second via irq) |
| 960 | | * |
| 961 | | **************************************************************************/ |
| 962 | | |
| 963 | | static void vc1541_via0_irq( const device_config *device, int level ) |
| 964 | | { |
| 965 | | vc1541_drive.via0irq = level; |
| 966 | | DBG_LOG(device->machine, 2, "vc1541 via0 irq", ("level %d %d\n", vc1541_drive.via0irq, vc1541_drive.via1irq)); |
| 967 | | |
| 968 | | cputag_set_input_line(device->machine, vc1541_drive.cputag, M6502_IRQ_LINE, vc1541_drive.via1irq || vc1541_drive.via0irq); |
| 969 | | } |
| 970 | | |
| 971 | | static READ8_DEVICE_HANDLER( vc1541_via0_read_portb ) |
| 972 | | { |
| 973 | | int value = 0x7a; |
| 974 | | |
| 975 | | if (!vc1541_drive.vc1541_serial.serial_data || !serial.data[0]) |
| 976 | | value |= 0x01; |
| 977 | | |
| 978 | | if (!vc1541_drive.vc1541_serial.serial_clock || !serial.clock[0]) |
| 979 | | value |= 0x04; |
| 980 | | |
| 981 | | if (!serial.atn[0]) |
| 982 | | value |= 0x80; |
| 983 | | |
| 984 | | switch (vc1541_drive.vc1541_serial.deviceid) |
| 985 | | { |
| 986 | | case 8: |
| 987 | | value &= ~0x60; |
| 988 | | break; |
| 989 | | case 9: |
| 990 | | value &= ~0x40; |
| 991 | | break; |
| 992 | | case 10: |
| 993 | | value &= ~0x20; |
| 994 | | break; |
| 995 | | case 11: |
| 996 | | break; |
| 997 | | } |
| 998 | | |
| 999 | | return value; |
| 1000 | | } |
| 1001 | | |
| 1002 | | static WRITE8_DEVICE_HANDLER( vc1541_via0_write_portb ) |
| 1003 | | { |
| 1004 | | DBG_LOG(device->machine, 2, "vc1541 serial write", ("%s %s %s\n", |
| 1005 | | data & 0x10 ? "ATN" : "atn", |
| 1006 | | data & 0x08 ? "CLOCK" : "clock", |
| 1007 | | data & 0x02 ? "DATA" : "data")); |
| 1008 | | |
| 1009 | | vc1541_drive.vc1541_serial.data = data & 0x02 ? 0 : 1; |
| 1010 | | vc1541_drive.vc1541_serial.acka = data & 0x10 ? 1 : 0; |
| 1011 | | |
| 1012 | | if ((!(data & 0x02)) != vc1541_drive.vc1541_serial.serial_data) |
| 1013 | | { |
| 1014 | | vc1541_serial_data_write(device->machine, 1, vc1541_drive.vc1541_serial.serial_data = !(data & 0x02)); |
| 1015 | | } |
| 1016 | | |
| 1017 | | if ((!(data & 0x08)) != vc1541_drive.vc1541_serial.serial_clock) |
| 1018 | | { |
| 1019 | | vc1541_serial_clock_write(device->machine, 1, vc1541_drive.vc1541_serial.serial_clock = !(data & 0x08)); |
| 1020 | | } |
| 1021 | | |
| 1022 | | vc1541_serial_atn_write(device->machine, 1, vc1541_drive.vc1541_serial.serial_atn = 1); |
| 1023 | | } |
| 1024 | | |
| 1025 | | static const via6522_interface vc1541_via0 = |
| 1026 | | { |
| 1027 | | DEVCB_NULL, /*via0_read_porta, */ |
| 1028 | | DEVCB_HANDLER(vc1541_via0_read_portb), |
| 1029 | | DEVCB_NULL, /*via0_read_ca1, */ |
| 1030 | | DEVCB_NULL, /*via0_read_cb1, */ |
| 1031 | | DEVCB_NULL, /*via0_read_ca2, */ |
| 1032 | | DEVCB_NULL, /*via0_read_cb2, */ |
| 1033 | | DEVCB_NULL, /*via0_write_porta, */ |
| 1034 | | DEVCB_HANDLER(vc1541_via0_write_portb), |
| 1035 | | DEVCB_NULL, /*via0_write_ca1, */ |
| 1036 | | DEVCB_NULL, /*via0_write_cb1, */ |
| 1037 | | DEVCB_NULL, /*via0_write_ca2, */ |
| 1038 | | DEVCB_NULL, /*via0_write_cb2, */ |
| 1039 | | DEVCB_LINE(vc1541_via0_irq) |
| 1040 | | }; |
| 1041 | | |
| 1042 | | |
| 1043 | | /************************************************************************** |
| 1044 | | * VIA 6522 at 0x1c00 |
| 1045 | | * |
| 1046 | | * 0x1c00 port B - Disk controller i/o control line |
| 1047 | | * bit 0 : step head motor output 1 |
| 1048 | | * bit 1 : step head motor output 2 |
| 1049 | | * bit 2 : motor on output (0 = Off, 1 = On) - 300 revolutions per minute |
| 1050 | | * bit 3 : LED control output (0 = Off, 1 = On) |
| 1051 | | * bit 4 : write protect sense (0 = protected, 1 = unprotected) |
| 1052 | | * bit 5 : density select 0 |
| 1053 | | * bit 6 : density select 1 |
| 1054 | | * data density (track dependend): 00 = lowest (faster time), 11 = highest (slower timer) |
| 1055 | | * bit 7 : sync signal (more then nine 1 bits) detect |
| 1056 | | * 0x1c01 Port A - byte in gcr format from or to floppy |
| 1057 | | * 0x1c02 Port B data direction register + LED output - default 0x6f |
| 1058 | | * 0x1c03 Port A data direction register - 0x00 read from disk, 0xff write to disk |
| 1059 | | * 0x1c04 Timer 1 counter (low) |
| 1060 | | * 0x1c05 Timer 1 counter (high) |
| 1061 | | * Read low byte or write high byte to start timer or restart timer upon underflow. |
| 1062 | | * 0x1c06 Timer 1 latch (low) |
| 1063 | | * 0x1c07 Timer 1 latch (high) |
| 1064 | | * read/write starting value of timer from/to here. |
| 1065 | | * 0x1c08 Timer 2 latch (low) |
| 1066 | | * 0x1c09 Timer 2 latch (high) |
| 1067 | | * 0x1c0a Shift register |
| 1068 | | * 0x1c0b Auxiliary control register. bit 6: 0 = Stop timer; 1 = Start timer. |
| 1069 | | * 0x1c0c Peripheral control register |
| 1070 | | * 0x1c0d Interrupt flag register. bit 6: 1 = Timer underflow occurred. |
| 1071 | | * 0x1c0e Interrupt enable register |
| 1072 | | * bit 6: write - 1 = Enable interrupts generated by timer underflow |
| 1073 | | * bit 7: read - interrupt has been generated. |
| 1074 | | * bit 7: write - Fill bit: bits 0-6, that are set to 1, get their values from this bit; bits 0-6, that are set to 0, are left unchanged |
| 1075 | | * |
| 1076 | | * ca1 byte ready input (also m6502 set overflow input) |
| 1077 | | * ca2 set overflow enable for 6502 |
| 1078 | | * ca3 read/write |
| 1079 | | * |
| 1080 | | * irq to m6502 irq connected |
| 1081 | | * |
| 1082 | | **************************************************************************/ |
| 1083 | | |
| 1084 | | |
| 1085 | | static void vc1541_via1_irq( const device_config *device, int level ) |
| 1086 | | { |
| 1087 | | vc1541_drive.via1irq = level; |
| 1088 | | DBG_LOG(device->machine, 2, "vc1541 via1 irq", ("level %d %d\n", vc1541_drive.via0irq, vc1541_drive.via1irq)); |
| 1089 | | |
| 1090 | | cputag_set_input_line(device->machine, vc1541_drive.cputag, M6502_IRQ_LINE, vc1541_drive.via1irq || vc1541_drive.via0irq); |
| 1091 | | } |
| 1092 | | |
| 1093 | | static READ8_DEVICE_HANDLER( vc1541_via1_read_porta ) |
| 1094 | | { |
| 1095 | | UINT8 data = vc1541_drive.gcr.data[vc1541_drive.start_pos + vc1541_drive.pos]; |
| 1096 | | |
| 1097 | | // logerror("Data read: Track %.1f Pos %d\n", vc1541_drive.track, vc1541_drive.pos); |
| 1098 | | |
| 1099 | | DBG_LOG(device->machine, 2, "vc1541 drive", ("port a read %.2x\n", data)); |
| 1100 | | return data; |
| 1101 | | } |
| 1102 | | |
| 1103 | | static WRITE8_DEVICE_HANDLER( vc1541_via1_write_porta ) |
| 1104 | | { |
| 1105 | | DBG_LOG(device->machine, 1, "vc1541 drive", ("port a write %.2x\n", data)); |
| 1106 | | } |
| 1107 | | |
| 1108 | | static READ8_DEVICE_HANDLER( vc1541_via1_read_portb ) |
| 1109 | | { |
| 1110 | | UINT8 value = 0xff; |
| 1111 | | |
| 1112 | | #if 0 |
| 1113 | | if (WRITEPROTECTED) |
| 1114 | | value &= ~0x10; |
| 1115 | | #endif |
| 1116 | | |
| 1117 | | if (vc1541_drive.gcr.sync) |
| 1118 | | { |
| 1119 | | value &= ~0x80; |
| 1120 | | } |
| 1121 | | |
| 1122 | | return value; |
| 1123 | | } |
| 1124 | | |
| 1125 | | static int old = 0; |
| 1126 | | |
| 1127 | | static WRITE8_DEVICE_HANDLER( vc1541_via1_write_portb ) |
| 1128 | | { |
| 1129 | | if (data != old) |
| 1130 | | { |
| 1131 | | DBG_LOG(device->machine, 1, "vc1541 drive",("%.2x\n", data)); |
| 1132 | | |
| 1133 | | /* decrease value (%00-%11-%10-%01-%00...) to move head downwards; */ |
| 1134 | | /* increase value (%00-%01-%10-%11-%00...) to move head upwards. */ |
| 1135 | | if ((old & 0x03) != (data & 0x03)) |
| 1136 | | { |
| 1137 | | switch (old & 0x03) |
| 1138 | | { |
| 1139 | | case 0: |
| 1140 | | if ((data & 0x03) == 1) |
| 1141 | | vc1541_drive.track += 0.5; |
| 1142 | | else if ((data & 0x03) == 3) |
| 1143 | | vc1541_drive.track -= 0.5; |
| 1144 | | break; |
| 1145 | | |
| 1146 | | case 1: |
| 1147 | | if ((data & 0x03) == 2) |
| 1148 | | vc1541_drive.track += 0.5; |
| 1149 | | else if ((data & 0x03) == 0) |
| 1150 | | vc1541_drive.track -= 0.5; |
| 1151 | | break; |
| 1152 | | |
| 1153 | | case 2: |
| 1154 | | if ((data & 0x03) == 3) |
| 1155 | | vc1541_drive.track += 0.5; |
| 1156 | | else if ((data & 0x03) == 1) |
| 1157 | | vc1541_drive.track -= 0.5; |
| 1158 | | break; |
| 1159 | | |
| 1160 | | case 3: |
| 1161 | | if ((data & 0x03) == 0) |
| 1162 | | vc1541_drive.track += 0.5; |
| 1163 | | else if ((data & 0x03) == 2) |
| 1164 | | vc1541_drive.track -= 0.5; |
| 1165 | | break; |
| 1166 | | } |
| 1167 | | |
| 1168 | | /* If we have reached the first or last track, we cannot proceed further! */ |
| 1169 | | if (vc1541_drive.track < 1) |
| 1170 | | vc1541_drive.track = 1.0; |
| 1171 | | if (vc1541_drive.track > 35) |
| 1172 | | vc1541_drive.track = 35.0; |
| 1173 | | |
| 1174 | | logerror("Track #: %.1f\n", vc1541_drive.track); |
| 1175 | | |
| 1176 | | /* We now adjust the vc1541_drive.pos according to the new track */ |
| 1177 | | /* This seems a simple way to deal with half tracks */ |
| 1178 | | vc1541_drive.pos = 0; |
| 1179 | | vc1541_drive.start_pos = gcr_offset[(int)vc1541_drive.track - 1] // starting point of Track # |
| 1180 | | + (int)(2 * (vc1541_drive.track - (int)vc1541_drive.track)) * 184 / 2; // half track if needed (again, 184 comes from out loading choices) |
| 1181 | | } |
| 1182 | | |
| 1183 | | if ((vc1541_drive.motor != (data & 0x04)) || (vc1541_drive.frequency != (data & 0x60))) |
| 1184 | | { |
| 1185 | | double tme; |
| 1186 | | vc1541_drive.motor = data & 0x04; |
| 1187 | | vc1541_drive.frequency = data & 0x60; |
| 1188 | | tme = drive_times[vc1541_drive.frequency >> 5]; |
| 1189 | | |
| 1190 | | if (vc1541_drive.motor) |
| 1191 | | { |
| 1192 | | if (attotime_to_double(timer_timeelapsed(vc1541_drive.timer)) > 1.0e29) |
| 1193 | | { |
| 1194 | | timer_reset(vc1541_drive.timer, attotime_never); |
| 1195 | | } |
| 1196 | | else |
| 1197 | | { |
| 1198 | | timer_adjust_periodic(vc1541_drive.timer, attotime_zero, 0, ATTOTIME_IN_HZ(tme)); |
| 1199 | | logerror("Freq changed: %f\n", tme); |
| 1200 | | } |
| 1201 | | } |
| 1202 | | else |
| 1203 | | { |
| 1204 | | timer_reset(vc1541_drive.timer, attotime_never); |
| 1205 | | logerror("Motor turned off\n"); |
| 1206 | | } |
| 1207 | | } |
| 1208 | | old = data; |
| 1209 | | } |
| 1210 | | |
| 1211 | | vc1541_drive.led = data & 0x08; |
| 1212 | | } |
| 1213 | | |
| 1214 | | static const via6522_interface vc1541_via1 = |
| 1215 | | { |
| 1216 | | DEVCB_HANDLER(vc1541_via1_read_porta), |
| 1217 | | DEVCB_HANDLER(vc1541_via1_read_portb), |
| 1218 | | DEVCB_NULL, /*via3_read_ca1, */ |
| 1219 | | DEVCB_NULL, /*via3_read_cb1, */ |
| 1220 | | DEVCB_NULL, /*via3_read_ca2, */ |
| 1221 | | DEVCB_NULL, /*via3_read_cb2, */ |
| 1222 | | DEVCB_HANDLER(vc1541_via1_write_porta), |
| 1223 | | DEVCB_HANDLER(vc1541_via1_write_portb), |
| 1224 | | DEVCB_NULL, /*via3_write_ca1, */ |
| 1225 | | DEVCB_NULL, /*via3_write_cb1, */ |
| 1226 | | DEVCB_NULL, /*via3_write_ca2, */ |
| 1227 | | DEVCB_NULL, /*via3_write_cb2, */ |
| 1228 | | DEVCB_LINE(vc1541_via1_irq) |
| 1229 | | }; |
| 1230 | | |
| 1231 | | |
| 1232 | | /************************************** |
| 1233 | | |
| 1234 | | 1541 / 1541B / 1541C / 1541II / |
| 1235 | | 2031 (same as 1541 but IEEE) |
| 1236 | | |
| 1237 | | **************************************/ |
| 1238 | | |
| 1239 | | static ADDRESS_MAP_START( _1541_map, ADDRESS_SPACE_PROGRAM, 8 ) |
| 1240 | | AM_RANGE(0x0000, 0x07ff) AM_RAM |
| 1241 | | AM_RANGE(0x1800, 0x180f) AM_DEVREADWRITE("_1541_via_0", via_r, via_w) /* 0 and 1 used in vc20 */ // IEC Bus |
| 1242 | | AM_RANGE(0x1c00, 0x1c0f) AM_DEVREADWRITE("_1541_via_1", via_r, via_w) // Drive |
| 1243 | | AM_RANGE(0xc000, 0xffff) AM_ROM |
| 1244 | | ADDRESS_MAP_END |
| 1245 | | |
| 1246 | | |
| 1247 | | static ADDRESS_MAP_START( dolphin_map, ADDRESS_SPACE_PROGRAM, 8 ) |
| 1248 | | AM_RANGE(0x0000, 0x07ff) AM_RAM |
| 1249 | | AM_RANGE(0x1800, 0x180f) AM_DEVREADWRITE("_1541_via_0", via_r, via_w) /* 0 and 1 used in vc20 */ |
| 1250 | | AM_RANGE(0x1c00, 0x1c0f) AM_DEVREADWRITE("_1541_via_1", via_r, via_w) |
| 1251 | | AM_RANGE(0x8000, 0x9fff) AM_RAM |
| 1252 | | AM_RANGE(0xa000, 0xffff) AM_ROM |
| 1253 | | ADDRESS_MAP_END |
| 1254 | | |
| 1255 | | /************************************** |
| 1256 | | |
| 1257 | | 1570 / 1571 / 1571CR |
| 1258 | | |
| 1259 | | **************************************/ |
| 1260 | | |
| 1261 | | static ADDRESS_MAP_START( _1571_map, ADDRESS_SPACE_PROGRAM, 8 ) |
| 1262 | | AM_RANGE(0x0000, 0x07ff) AM_RAM |
| 1263 | | AM_RANGE(0x1800, 0x180f) AM_DEVREADWRITE("_1541_via_0", via_r, via_w) /* 0 and 1 used in vc20 */ |
| 1264 | | AM_RANGE(0x1c00, 0x1c0f) AM_DEVREADWRITE("_1541_via_1", via_r, via_w) |
| 1265 | | // AM_RANGE(0x2000, 0x2003) // WD17xx |
| 1266 | | // AM_RANGE(0x4000, 0x400f) // CIA |
| 1267 | | AM_RANGE(0x8000, 0xffff) AM_ROM |
| 1268 | | ADDRESS_MAP_END |
| 1269 | | |
| 1270 | | // for the C128DCR Drive |
| 1271 | | /* |
| 1272 | | David Gahris provided info about differences between 128DCR and stand-alone 1571s |
| 1273 | | |
| 1274 | | * There is no 6526 or 8521 in the drive section of the 128DCR. I believe the |
| 1275 | | 5710 handles fast serial because the 5710 is a Commodore custom chip and |
| 1276 | | 128 fast serial is a Commodore custom protocol. [Ed's note: Commodore lists |
| 1277 | | NTE229, ECG229, SK3246A/229, and 121-Z9021 as substitutes of the 5710.] |
| 1278 | | |
| 1279 | | * There is no 177x or heat-shrink-wrapped daughterboard in the drive section |
| 1280 | | of the 128DCR. I believe the Motorola plastic quad flat-pack chip handles |
| 1281 | | MFM because I am pretty sure that I have seen this chip in IBM PC drive |
| 1282 | | mechanisms. |
| 1283 | | |
| 1284 | | * The 1571cr ROM works great in 1541 mode but not at all in 1571 mode in a |
| 1285 | | standalone 1571. |
| 1286 | | |
| 1287 | | * Olaf Seibert informed me that the 1571cr ROM contains a string to the |
| 1288 | | effect of "5710 (c) 1986 by c. hauck" |
| 1289 | | */ |
| 1290 | | static ADDRESS_MAP_START( _1571cr_map, ADDRESS_SPACE_PROGRAM, 8 ) |
| 1291 | | AM_RANGE(0x0000, 0x07ff) AM_RAM |
| 1292 | | AM_RANGE(0x1800, 0x180f) AM_DEVREADWRITE("_1541_via_0", via_r, via_w) /* 0 and 1 used in vc20 */ |
| 1293 | | AM_RANGE(0x1c00, 0x1c0f) AM_DEVREADWRITE("_1541_via_1", via_r, via_w) |
| 1294 | | // AM_RANGE(0x2000, 0x2005) // 5710 FDC |
| 1295 | | // AM_RANGE(0x400c, 0x400f) // 5710 CIA Serial Port |
| 1296 | | // AM_RANGE(0x4010, 0x4017) // 5710 FDC2 |
| 1297 | | // AM_RANGE(0x6000, 0x7fff) // RAM shadows |
| 1298 | | AM_RANGE(0x8000, 0xffff) AM_ROM |
| 1299 | | ADDRESS_MAP_END |
| 1300 | | |
| 1301 | | |
| 1302 | | /************************************** |
| 1303 | | |
| 1304 | | 1581 |
| 1305 | | |
| 1306 | | **************************************/ |
| 1307 | | |
| 1308 | | static ADDRESS_MAP_START( _1581_map, ADDRESS_SPACE_PROGRAM, 8 ) |
| 1309 | | // AM_RANGE(0x4000, 0x400f) // CIA |
| 1310 | | // AM_RANGE(0x6000, 0x6003) // WD17xx |
| 1311 | | AM_RANGE(0x8000, 0xffff) AM_ROM |
| 1312 | | ADDRESS_MAP_END |
| 1313 | | |
| 1314 | | |
| 1315 | | /************************************** |
| 1316 | | |
| 1317 | | 1001 / 8050 / 8250 |
| 1318 | | |
| 1319 | | http://www.zimmers.net/anonftp/pub/cbm/firmware/drives/old/8050/d/8250.notes |
| 1320 | | |
| 1321 | | **************************************/ |
| 1322 | | |
| 1323 | | static ADDRESS_MAP_START( sfd1001_map, ADDRESS_SPACE_PROGRAM, 8 ) |
| 1324 | | // AM_RANGE(0x0200, 0x021f) // RIOT1 |
| 1325 | | // AM_RANGE(0x0280, 0x029f) // RIOT2 |
| 1326 | | AM_RANGE(0xc000, 0xffff) AM_ROM |
| 1327 | | ADDRESS_MAP_END |
| 1328 | | |
| 1329 | | |
| 1330 | | /************************************** |
| 1331 | | |
| 1332 | | 2040 / 3040 / 4040 |
| 1333 | | |
| 1334 | | http://www.zimmers.net/anonftp/pub/cbm/schematics/drives/old/4040/memorymap.txt |
| 1335 | | |
| 1336 | | **************************************/ |
| 1337 | | |
| 1338 | | static ADDRESS_MAP_START( _4040_map, ADDRESS_SPACE_PROGRAM, 8 ) |
| 1339 | | ADDRESS_MAP_END |
| 1340 | | |
| 1341 | | |
| 1342 | | /************************************** |
| 1343 | | |
| 1344 | | 1551 |
| 1345 | | |
| 1346 | | **************************************/ |
| 1347 | | |
| 1348 | | /* |
| 1349 | | c1551 irq line |
| 1350 | | only timing related??? (60 Hz?), delivered from c16? |
| 1351 | | */ |
| 1352 | | static TIMER_CALLBACK(c1551_irq_timer) |
| 1353 | | { |
| 1354 | | cputag_set_input_line(machine, c1551_drive.cputag, M6502_IRQ_LINE, ASSERT_LINE); |
| 1355 | | } |
| 1356 | | |
| 1357 | | /* |
| 1358 | | ddr 0x6f (p0 .. p5? in pinout) |
| 1359 | | 0,1: output stepper motor |
| 1360 | | 2 output motor (rotation) (300 revolutions per minute) |
| 1361 | | 3 output led ? |
| 1362 | | 4 input disk not write protected ? |
| 1363 | | 5,6: output frequency select |
| 1364 | | 7: input byte ready |
| 1365 | | */ |
| 1366 | | |
| 1367 | | static WRITE8_HANDLER( c1551_port_w ) |
| 1368 | | { |
| 1369 | | if (offset) |
| 1370 | | { |
| 1371 | | DBG_LOG(space->machine, 1, "c1551 port",("write %.2x\n", data)); |
| 1372 | | c1551_drive.cpu_port = data; |
| 1373 | | |
| 1374 | | if (data != old) |
| 1375 | | { |
| 1376 | | DBG_LOG(space->machine, 1, "c1551 drive",("%.2x\n", data)); |
| 1377 | | |
| 1378 | | if ((old & 0x03) != (data & 0x03)) |
| 1379 | | { |
| 1380 | | switch (old & 0x03) |
| 1381 | | { |
| 1382 | | case 0: |
| 1383 | | if ((data & 0x03) == 1) |
| 1384 | | c1551_drive.track += 0.5; |
| 1385 | | else if ((data & 0x03) == 3) |
| 1386 | | c1551_drive.track -= 0.5; |
| 1387 | | break; |
| 1388 | | |
| 1389 | | case 1: |
| 1390 | | if ((data & 0x03) == 2) |
| 1391 | | c1551_drive.track += 0.5; |
| 1392 | | else if ((data & 0x03) == 0) |
| 1393 | | c1551_drive.track -= 0.5; |
| 1394 | | break; |
| 1395 | | |
| 1396 | | case 2: |
| 1397 | | if ((data & 0x03) == 3) |
| 1398 | | c1551_drive.track += 0.5; |
| 1399 | | else if ((data & 0x03) == 1) |
| 1400 | | c1551_drive.track -= 0.5; |
| 1401 | | break; |
| 1402 | | |
| 1403 | | case 3: |
| 1404 | | if ((data & 0x03) == 0) |
| 1405 | | c1551_drive.track += 0.5; |
| 1406 | | else if ((data & 0x03) == 2) |
| 1407 | | c1551_drive.track -= 0.5; |
| 1408 | | break; |
| 1409 | | } |
| 1410 | | |
| 1411 | | /* If we have reached the first or last track, we cannot proceed further! */ |
| 1412 | | if (c1551_drive.track < 1) |
| 1413 | | c1551_drive.track = 1.0; |
| 1414 | | if (c1551_drive.track > 35) |
| 1415 | | c1551_drive.track = 35.0; |
| 1416 | | |
| 1417 | | logerror("Track #: %.1f\n", c1551_drive.track); |
| 1418 | | |
| 1419 | | /* We now adjust the c1551_drive.pos according to the new track */ |
| 1420 | | /* This seems a simple way to deal with half tracks */ |
| 1421 | | c1551_drive.pos = 0; |
| 1422 | | c1551_drive.start_pos = gcr_offset[(int)c1551_drive.track - 1] // starting point of Track # |
| 1423 | | + (int)(2 * (c1551_drive.track - (int)c1551_drive.track)) * 184 / 2; // half track if needed (again, 184 comes from out loading choices) |
| 1424 | | } |
| 1425 | | |
| 1426 | | if ((c1551_drive.motor != (data & 0x04)) || (c1551_drive.frequency != (data & 0x60))) |
| 1427 | | { |
| 1428 | | double tme; |
| 1429 | | c1551_drive.motor = data & 0x04; |
| 1430 | | c1551_drive.frequency = data & 0x60; |
| 1431 | | |
| 1432 | | tme = drive_times[c1551_drive.frequency >> 5]; |
| 1433 | | if (c1551_drive.motor) |
| 1434 | | { |
| 1435 | | if (attotime_to_double(timer_timeelapsed(c1551_drive.timer)) > 1.0e29) |
| 1436 | | timer_reset(c1551_drive.timer, attotime_never); |
| 1437 | | else |
| 1438 | | timer_adjust_periodic(c1551_drive.timer, attotime_zero, 0, ATTOTIME_IN_HZ(tme)); |
| 1439 | | } |
| 1440 | | else |
| 1441 | | { |
| 1442 | | timer_reset(c1551_drive.timer, attotime_never); |
| 1443 | | } |
| 1444 | | } |
| 1445 | | old = data; |
| 1446 | | } |
| 1447 | | c1551_drive.led = data & 0x08; |
| 1448 | | } |
| 1449 | | else |
| 1450 | | { |
| 1451 | | c1551_drive.cpu_ddr = data; |
| 1452 | | DBG_LOG(space->machine, 1, "c1551 ddr", ("write %.2x\n", data)); |
| 1453 | | } |
| 1454 | | } |
| 1455 | | |
| 1456 | | static READ8_HANDLER( c1551_port_r ) |
| 1457 | | { |
| 1458 | | int data; |
| 1459 | | |
| 1460 | | if (offset) |
| 1461 | | { |
| 1462 | | data = 0x7f; |
| 1463 | | #if 0 |
| 1464 | | if (WRITEPROTECTED) |
| 1465 | | data &= ~0x10; |
| 1466 | | #endif |
| 1467 | | if (c1551_drive.gcr.ready) |
| 1468 | | { |
| 1469 | | data |= 0x80; |
| 1470 | | c1551_drive.gcr.ready = 0; |
| 1471 | | } |
| 1472 | | |
| 1473 | | data &= ~c1551_drive.cpu_ddr; |
| 1474 | | data |= c1551_drive.cpu_ddr & c1551_drive.cpu_port; |
| 1475 | | DBG_LOG(space->machine, 3, "c1551 port",("read %.2x\n", data)); |
| 1476 | | } |
| 1477 | | else |
| 1478 | | { |
| 1479 | | data = c1551_drive.cpu_ddr; |
| 1480 | | DBG_LOG(space->machine, 3, "c1551 ddr",("read %.2x\n", data)); |
| 1481 | | } |
| 1482 | | return data; |
| 1483 | | } |
| 1484 | | |
| 1485 | | |
| 1486 | | static ADDRESS_MAP_START( _1551_map, ADDRESS_SPACE_PROGRAM, 8 ) |
| 1487 | | AM_RANGE(0x0000, 0x0001) AM_READWRITE(c1551_port_r, c1551_port_w) |
| 1488 | | AM_RANGE(0x0002, 0x07ff) AM_RAM |
| 1489 | | AM_RANGE(0x4000, 0x4007) AM_DEVREADWRITE("c1551_tpi", tpi6525_r, tpi6525_w) |
| 1490 | | AM_RANGE(0xc000, 0xffff) AM_ROM |
| 1491 | | ADDRESS_MAP_END |
| 1492 | | |
| 1493 | | |
| 1494 | | /******************** Handlers for the C1551 TPI ********************/ |
| 1495 | | |
| 1496 | | /* |
| 1497 | | tia6523 |
| 1498 | | port a |
| 1499 | | c16 communication in/out |
| 1500 | | port b |
| 1501 | | drive data in/out |
| 1502 | | port c ddr (0x1f) |
| 1503 | | 0 output status out |
| 1504 | | 1 output status out |
| 1505 | | 2 output |
| 1506 | | 3 output handshake out |
| 1507 | | 4 output |
| 1508 | | 5 input drive number 9 |
| 1509 | | 6 input sync 0 active |
| 1510 | | 7 input handshake in |
| 1511 | | */ |
| 1512 | | static READ8_DEVICE_HANDLER( c1551_port_c_r ) |
| 1513 | | { |
| 1514 | | int data = 0xff; |
| 1515 | | |
| 1516 | | data &= ~0x20; |
| 1517 | | |
| 1518 | | if (c1551_drive.gcr.sync) |
| 1519 | | data &= ~0x40; |
| 1520 | | |
| 1521 | | return data; |
| 1522 | | } |
| 1523 | | |
| 1524 | | static READ8_DEVICE_HANDLER( c1551_port_b_r ) |
| 1525 | | { |
| 1526 | | UINT8 data = c1551_drive.gcr.data[c1551_drive.start_pos + c1551_drive.pos]; |
| 1527 | | |
| 1528 | | DBG_LOG(device->machine, 2, "c1551 drive",("port a read %.2x\n", data)); |
| 1529 | | return data; |
| 1530 | | } |
| 1531 | | |
| 1532 | | static const tpi6525_interface c1551_tpi_intf = |
| 1533 | | { |
| 1534 | | NULL, |
| 1535 | | c1551_port_b_r, |
| 1536 | | c1551_port_c_r, |
| 1537 | | NULL, |
| 1538 | | NULL, |
| 1539 | | NULL, |
| 1540 | | NULL, |
| 1541 | | NULL, |
| 1542 | | NULL |
| 1543 | | }; |
| 1544 | | |
| 1545 | | |
| 1546 | | /******************** Handlers for the C16 TPI ********************/ |
| 1547 | | |
| 1548 | | WRITE8_DEVICE_HANDLER( c1551x_write_data ) |
| 1549 | | { |
| 1550 | | // DBG_LOG(device->machine, 1, "c1551 cpu", ("%d write data %.2x\n", cpu_getactivecpu (), data)); |
| 1551 | | #ifdef CPU_SYNC |
| 1552 | | cpu_sync(); |
| 1553 | | #endif |
| 1554 | | const device_config *tpi_0 = devtag_get_device(device->machine, "c1551_tpi"); |
| 1555 | | |
| 1556 | | tpi6525_porta_w(tpi_0, 0, data); |
| 1557 | | } |
| 1558 | | |
| 1559 | | READ8_DEVICE_HANDLER( c1551x_read_data ) |
| 1560 | | { |
| 1561 | | UINT8 data = 0xff; |
| 1562 | | const device_config *tpi_0 = devtag_get_device(device->machine, "c1551_tpi"); |
| 1563 | | |
| 1564 | | #ifdef CPU_SYNC |
| 1565 | | cpu_sync (); |
| 1566 | | #endif |
| 1567 | | |
| 1568 | | data = tpi6525_porta_r(tpi_0, 0); |
| 1569 | | // DBG_LOG(device->machine, 2, "c1551 cpu",("%d read data %.2x\n", cpu_getactivecpu (), data)); |
| 1570 | | return data; |
| 1571 | | } |
| 1572 | | |
| 1573 | | WRITE8_DEVICE_HANDLER( c1551x_write_handshake ) |
| 1574 | | { |
| 1575 | | const device_config *tpi_0 = devtag_get_device(device->machine, "c1551_tpi"); |
| 1576 | | // DBG_LOG(device->machine, 1, "c1551 cpu",("%d write handshake %.2x\n", cpu_getactivecpu (), data)); |
| 1577 | | #ifdef CPU_SYNC |
| 1578 | | cpu_sync(); |
| 1579 | | #endif |
| 1580 | | |
| 1581 | | tpi6525_portc_w(tpi_0, 0, data & 0x40 ? 0xff : 0x7f); |
| 1582 | | } |
| 1583 | | |
| 1584 | | READ8_DEVICE_HANDLER( c1551x_read_handshake ) |
| 1585 | | { |
| 1586 | | const device_config *tpi_0 = devtag_get_device(device->machine, "c1551_tpi"); |
| 1587 | | UINT8 data = 0xff; |
| 1588 | | #ifdef CPU_SYNC |
| 1589 | | cpu_sync(); |
| 1590 | | #endif |
| 1591 | | |
| 1592 | | data = tpi6525_portc_r(tpi_0, 0) & 0x08 ? 0x80 : 0x00; |
| 1593 | | // DBG_LOG(device->machine, 2, "c1551 cpu",("%d read handshake %.2x\n", cpu_getactivecpu (), data)); |
| 1594 | | return data; |
| 1595 | | } |
| 1596 | | |
| 1597 | | READ8_DEVICE_HANDLER( c1551x_read_status ) |
| 1598 | | { |
| 1599 | | const device_config *tpi_0 = devtag_get_device(device->machine, "c1551_tpi"); |
| 1600 | | UINT8 data = 0xff; |
| 1601 | | #ifdef CPU_SYNC |
| 1602 | | cpu_sync(); |
| 1603 | | #endif |
| 1604 | | |
| 1605 | | data = tpi6525_portc_r(tpi_0, 0) & 0x03; |
| 1606 | | // DBG_LOG(device->machine, 1, "c1551 cpu",("%d read status %.2x\n", cpu_getactivecpu (), data)); |
| 1607 | | |
| 1608 | | return data; |
| 1609 | | } |
| 1610 | | |
| 1611 | | |
| 1612 | | |
| 1613 | | /************************************** |
| 1614 | | |
| 1615 | | Machine drivers |
| 1616 | | |
| 1617 | | **************************************/ |
| 1618 | | |
| 1619 | | |
| 1620 | | MACHINE_DRIVER_START( cpu_vc1540 ) |
| 1621 | | MDRV_CPU_ADD("cpu_vc1540", M6502, XTAL_16_MHz / 16) |
| 1622 | | MDRV_CPU_PROGRAM_MAP(_1541_map) |
| 1623 | | |
| 1624 | | MDRV_VIA6522_ADD("_1541_via_0", 0, vc1541_via0) |
| 1625 | | MDRV_VIA6522_ADD("_1541_via_1", 0, vc1541_via1) |
| 1626 | | |
| 1627 | | MDRV_CBM_SERBUS_ADD("serial_bus", cbm_emu_drive_interface) |
| 1628 | | MACHINE_DRIVER_END |
| 1629 | | |
| 1630 | | MACHINE_DRIVER_START( cpu_vc1541 ) |
| 1631 | | MDRV_IMPORT_FROM(cpu_vc1540) |
| 1632 | | MACHINE_DRIVER_END |
| 1633 | | |
| 1634 | | MACHINE_DRIVER_START( cpu_c1571 ) |
| 1635 | | MDRV_CPU_ADD("cpu_vc1571", M6502, XTAL_16_MHz / 16) |
| 1636 | | MDRV_CPU_PROGRAM_MAP(_1571_map) |
| 1637 | | |
| 1638 | | MDRV_VIA6522_ADD("_1541_via_0", 0, vc1541_via0) |
| 1639 | | MDRV_VIA6522_ADD("_1541_via_1", 0, vc1541_via1) |
| 1640 | | |
| 1641 | | MDRV_CBM_SERBUS_ADD("serial_bus", cbm_emu_drive_interface) |
| 1642 | | MACHINE_DRIVER_END |
| 1643 | | |
| 1644 | | MACHINE_DRIVER_START( cpu_c1571cr ) |
| 1645 | | MDRV_CPU_ADD("cpu_vc1571", M6502, XTAL_16_MHz / 16) |
| 1646 | | MDRV_CPU_PROGRAM_MAP(_1571cr_map) |
| 1647 | | |
| 1648 | | MDRV_VIA6522_ADD("_1541_via_0", 0, vc1541_via0) |
| 1649 | | MDRV_VIA6522_ADD("_1541_via_1", 0, vc1541_via1) |
| 1650 | | |
| 1651 | | MDRV_CBM_SERBUS_ADD("serial_bus", cbm_emu_drive_interface) |
| 1652 | | MACHINE_DRIVER_END |
| 1653 | | |
| 1654 | | MACHINE_DRIVER_START( cpu_c1581 ) |
| 1655 | | MDRV_IMPORT_FROM(cpu_c1571) // obviously incorrect: we need proper 1581 memory map and emulation! |
| 1656 | | MACHINE_DRIVER_END |
| 1657 | | |
| 1658 | | MACHINE_DRIVER_START( cpu_c2031 ) |
| 1659 | | MDRV_IMPORT_FROM(cpu_vc1540) // not sure the memory map is exactly the vc1541 one! |
| 1660 | | MACHINE_DRIVER_END |
| 1661 | | |
| 1662 | | MACHINE_DRIVER_START( cpu_dolphin ) |
| 1663 | | MDRV_CPU_ADD("cpu_dolphin", M6502, XTAL_16_MHz / 16) |
| 1664 | | MDRV_CPU_PROGRAM_MAP(dolphin_map) |
| 1665 | | MACHINE_DRIVER_END |
| 1666 | | |
| 1667 | | MACHINE_DRIVER_START( cpu_c1551 ) |
| 1668 | | MDRV_CPU_ADD("cpu_c1551", M6510T, 2000000) |
| 1669 | | MDRV_CPU_PROGRAM_MAP(_1551_map) |
| 1670 | | |
| 1671 | | /* tpi */ |
| 1672 | | MDRV_TPI6525_ADD("c1551_tpi", c1551_tpi_intf) |
| 1673 | | |
| 1674 | | MDRV_CBM_SERBUS_ADD("serial_bus", cbm_emu_drive_interface) // in the current code, serial bus device is tied to the floppy drive |
| 1675 | | // and c16 reads/writes to serial bus in m7501_port_r/w! |
| 1676 | | MACHINE_DRIVER_END |
| 1677 | | |
| 1678 | | |
| 1679 | | |
| 1680 | | /************************************** |
| 1681 | | |
| 1682 | | Drive init & reset |
| 1683 | | |
| 1684 | | **************************************/ |
| 1685 | | |
| 1686 | | void cbm_drive_config( running_machine *machine, int type, int id, int mode, const char *cputag, int devicenr ) |
| 1687 | | { |
| 1688 | | vc1541_drive.type = type; |
| 1689 | | vc1541_drive.cputag = cputag; |
| 1690 | | vc1541_drive.vc1541_serial.deviceid = devicenr; |
| 1691 | | vc1541_drive.timer = timer_alloc(machine, vc1541_drive_timer, NULL); |
| 1692 | | vc1541_drive.gcr.data = (UINT8*)auto_alloc_array(machine, UINT8, 0x500000); |
| 1693 | | } |
| 1694 | | |
| 1695 | | void c1551_config( running_machine *machine, const char *cputag ) |
| 1696 | | { |
| 1697 | | c1551_drive.type = type_1551; |
| 1698 | | c1551_drive.cputag = cputag; |
| 1699 | | c1551_drive.timer = timer_alloc(machine, c1551_drive_timer, NULL); |
| 1700 | | c1551_drive.gcr.data = (UINT8*)auto_alloc_array(machine, UINT8, 0x500000); |
| 1701 | | |
| 1702 | | /* time should be small enough to allow quitting of the irq |
| 1703 | | line before the next interrupt is triggered */ |
| 1704 | | c1551_drive.irq_timer = timer_alloc(machine, c1551_irq_timer, NULL); |
| 1705 | | timer_adjust_periodic(c1551_drive.irq_timer, attotime_zero, 0, ATTOTIME_IN_HZ(60)); |
| 1706 | | } |
| 1707 | | |
| 1708 | | void cbm_drive_reset( running_machine* machine ) |
| 1709 | | { |
| 1710 | | int i; |
| 1711 | | |
| 1712 | | if (vc1541_drive.type == type_1541) |
| 1713 | | { |
| 1714 | | for (i = 0; i < ARRAY_LENGTH(serial.atn); i++) |
| 1715 | | { |
| 1716 | | serial.atn[i] = serial.data[i] = serial.clock[i] = 1; |
| 1717 | | } |
| 1718 | | } |
| 1719 | | |
| 1720 | | /* Create offset map for GCR encoded images: it speeds up finding position where to read data from */ |
| 1721 | | switch (vc1541_drive.type) |
| 1722 | | { |
| 1723 | | case type_1541: |
| 1724 | | case type_1541ii: |
| 1725 | | offset_init(format_d64_40t, gcr_offset, 368); // offset map is the same for both 35 and 40 track discs |
| 1726 | | break; |
| 1727 | | |
| 1728 | | case type_1570: |
| 1729 | | case type_1571: |
| 1730 | | case type_1571cr: |
| 1731 | | offset_init(format_d71, gcr_offset, 368); |
| 1732 | | break; |
| 1733 | | |
| 1734 | | case type_1581: |
| 1735 | | offset_init(format_d81, gcr_offset, 368); |
| 1736 | | break; |
| 1737 | | |
| 1738 | | default: |
| 1739 | | logerror("GCR offset map not created\n"); |
| 1740 | | } |
| 1741 | | |
| 1742 | | vc1541_drive.gcr.sync = 0; |
| 1743 | | vc1541_drive.gcr.ones_count = 0; |
| 1744 | | vc1541_drive.gcr.ready = 0; |
| 1745 | | |
| 1746 | | vc1541_drive.track = 1.0; |
| 1747 | | vc1541_drive.start_pos = 0; |
| 1748 | | vc1541_drive.pos = 0; |
| 1749 | | vc1541_drive.led = 0; |
| 1750 | | vc1541_drive.motor = 0; |
| 1751 | | vc1541_drive.frequency = 0; |
| 1752 | | vc1541_drive.clock = 0; |
| 1753 | | |
| 1754 | | vc1541_drive.vc1541_serial.acka = 0; |
| 1755 | | vc1541_drive.vc1541_serial.data = 0; |
| 1756 | | |
| 1757 | | } |
| 1758 | | |
| 1759 | | void c1551_drive_reset( void ) |
| 1760 | | { |
| 1761 | | offset_init(format_d64_40t, gcr_offset, 368); // offset map is the same for both 35 and 40 track discs |
| 1762 | | |
| 1763 | | c1551_drive.gcr.sync = 0; |
| 1764 | | c1551_drive.gcr.ones_count = 0; |
| 1765 | | c1551_drive.gcr.ready = 0; |
| 1766 | | |
| 1767 | | c1551_drive.track = 1.0; |
| 1768 | | c1551_drive.start_pos = 0; |
| 1769 | | c1551_drive.pos = 0; |
| 1770 | | c1551_drive.led = 0; |
| 1771 | | c1551_drive.motor = 0; |
| 1772 | | c1551_drive.frequency = 0; |
| 1773 | | c1551_drive.clock = 0; |
| 1774 | | } |
| 1775 | | |
| 1776 | | |
| 1777 | | |
| 1778 | | /************************************** |
| 1779 | | |
| 1780 | | Device configurations |
| 1781 | | |
| 1782 | | **************************************/ |
| 1783 | | |
| 1784 | | /* Floppy loading clean-up, part 1: with cbm_floppy_image_loading we can finally split c1551 from vc1541 |
| 1785 | | Both struct have a GCR_data gcr component where we store the floppy data, but remaining parts are finally separated! |
| 1786 | | Later, everything should be changed to use devices for the drives... */ |
| 1787 | | static void cbm_floppy_image_loading( int format, int id1, int id2, UINT8 *copy, GCR_data gcr ) |
| 1788 | | { |
| 1789 | | UINT8 sector_checksum; |
| 1790 | | int i = 0, j, k, l, pos; |
| 1791 | | |
| 1792 | | for (k = 1; k <= max_tracks_per_format[format]; k++) |
| 1793 | | { |
| 1794 | | /* logerror("decoding track %d offset %d %d %d %d %d\n", k, |
| 1795 | | image_tracksector2offset(k, 0) / (16*16*16*16), |
| 1796 | | (image_tracksector2offset(k, 0) % (16*16*16*16)) / (16*16*16), |
| 1797 | | (image_tracksector2offset(k, 0) % (16*16*16)) / (16*16), |
| 1798 | | (image_tracksector2offset(k, 0) % (16*16)) / 16, |
| 1799 | | image_tracksector2offset(k, 0) % 16); |
| 1800 | | */ |
| 1801 | | |
| 1802 | | for (l = 0; l < d64_sectors_per_track[k - 1]; l++) |
| 1803 | | { |
| 1804 | | // here we convert the sector data to gcr directly! |
| 1805 | | // IMPORTANT: we shall implement errors in reading sectors! |
| 1806 | | // these can modify e.g. header info $01 & $05 |
| 1807 | | |
| 1808 | | // first we set the position at which sector data starts in the image |
| 1809 | | pos = image_tracksector2offset(k, l); |
| 1810 | | |
| 1811 | | /* |
| 1812 | | 1. Header sync FF FF FF FF FF (40 'on' bits, not GCR encoded) |
| 1813 | | 2. Header info 52 54 B5 29 4B 7A 5E 95 55 55 (10 GCR bytes) |
| 1814 | | 3. Header gap 55 55 55 55 55 55 55 55 55 (9 bytes, never read) |
| 1815 | | 4. Data sync FF FF FF FF FF (40 'on' bits, not GCR encoded) |
| 1816 | | 5. Data block 55...4A (325 GCR bytes) |
| 1817 | | 6. Inter-sector gap 55 55 55 55...55 55 (4 to 19 bytes, never read) |
| 1818 | | */ |
| 1819 | | |
| 1820 | | /* Header sync */ |
| 1821 | | for (j = 0; j < 5; j++) |
| 1822 | | filling_byte(0xff, gcr.data + i + j); |
| 1823 | | i += 5; |
| 1824 | | |
| 1825 | | /* Header info */ |
| 1826 | | /* These are 8 bytes unencoded, which become 10 bytes encoded */ |
| 1827 | | // $00 - header block ID ($08) // this byte can be modified by error code 20 -> 0xff |
| 1828 | | // $01 - header block checksum (EOR of $02-$05) // this byte can be modified by error code 27 -> ^ 0xff |
| 1829 | | // $02 - Sector# of data block |
| 1830 | | // $03 - Track# of data block |
| 1831 | | gcr_double_2_gcr(0x08, l ^ k ^ id2 ^ id1, l, k, gcr.data + i); |
| 1832 | | i += 5; |
| 1833 | | |
| 1834 | | // $04 - Format ID byte #2 |
| 1835 | | // $05 - Format ID byte #1 |
| 1836 | | // $06 - $0F ("off" byte) |
| 1837 | | // $07 - $0F ("off" byte) |
| 1838 | | gcr_double_2_gcr(id2, id1, 0x0f, 0x0f, gcr.data + i); |
| 1839 | | i += 5; |
| 1840 | | |
| 1841 | | /* Header gap */ |
| 1842 | | for (j = 0; j < 9; j++) |
| 1843 | | filling_byte(0x55, gcr.data + i + j); |
| 1844 | | i += 9; |
| 1845 | | |
| 1846 | | /* Data sync */ |
| 1847 | | for (j = 0; j < 5; j++) |
| 1848 | | filling_byte(0xff, gcr.data + i + j); |
| 1849 | | i += 5; |
| 1850 | | |
| 1851 | | /* Data block */ |
| 1852 | | // we first need to calculate the checksum of the 256 bytes of the sector |
| 1853 | | sector_checksum = copy[pos]; |
| 1854 | | for (j = 1; j < 256; j++) |
| 1855 | | sector_checksum ^= copy[pos + j]; |
| 1856 | | |
| 1857 | | /* |
| 1858 | | $00 - data block ID ($07) |
| 1859 | | $01-100 - 256 bytes sector data |
| 1860 | | $101 - data block checksum (EOR of $01-100) |
| 1861 | | $102-103 - $00 ("off" bytes, to make the sector size a multiple of 5) |
| 1862 | | */ |
| 1863 | | gcr_double_2_gcr(0x07, copy[pos], copy[pos + 1], |
| 1864 | | copy[pos + 2], gcr.data + i); |
| 1865 | | i += 5; |
| 1866 | | |
| 1867 | | for (j = 1; j < 64; j++) |
| 1868 | | { |
| 1869 | | gcr_double_2_gcr(copy[pos + 4 * j - 1], copy[pos + 4 * j], |
| 1870 | | copy[pos + 4 * j + 1], copy[pos + 4 * j + 2], gcr.data + i); |
| 1871 | | i += 5; |
| 1872 | | } |
| 1873 | | |
| 1874 | | gcr_double_2_gcr(copy[pos + 255], sector_checksum, 0x00, 0x00, gcr.data + i); |
| 1875 | | i += 5; |
| 1876 | | |
| 1877 | | /* Inter-sector gap */ |
| 1878 | | // "In tests that the author conducted on a real 1541 disk, gap sizes of 8 to 19 bytes were seen." |
| 1879 | | // Here we put 14 as an average... |
| 1880 | | for (j = 0; j < 14; j++) |
| 1881 | | filling_byte(0x55, gcr.data + i + j); |
| 1882 | | i += 14; |
| 1883 | | } |
| 1884 | | } |
| 1885 | | |
| 1886 | | } |
| 1887 | | |
| 1888 | | static DEVICE_IMAGE_LOAD( _1541 ) |
| 1889 | | { |
| 1890 | | UINT8 format_id_1, format_id_2; |
| 1891 | | int format = 0, filesize; |
| 1892 | | UINT8 *temp_copy = NULL; |
| 1893 | | const char *filetype; |
| 1894 | | |
| 1895 | | filesize = image_length(image); |
| 1896 | | filetype = image_filetype(image); |
| 1897 | | |
| 1898 | | /* Find out which type of image we are loading */ |
| 1899 | | if (!mame_stricmp (filetype, "d64")) |
| 1900 | | { |
| 1901 | | switch (filesize) |
| 1902 | | { |
| 1903 | | case 0x2ab00: |
| 1904 | | format = format_d64; |
| 1905 | | break; |
| 1906 | | case (0x2ab00 + 0x2ab): |
| 1907 | | format = format_d64_err; |
| 1908 | | break; |
| 1909 | | case 0x30000: |
| 1910 | | format = format_d64_40t; |
| 1911 | | break; |
| 1912 | | case (0x30000 + 0x300): |
| 1913 | | format = format_d64_40t_err; |
| 1914 | | break; |
| 1915 | | default: |
| 1916 | | logerror("The image you're trying to load has not the regular size of a .d64 image: \n"); |
| 1917 | | logerror("Image %s size %d\n", image_filename(image), filesize); |
| 1918 | | return INIT_FAIL; |
| 1919 | | } |
| 1920 | | } |
| 1921 | | // these are not supported yet! |
| 1922 | | else if (!mame_stricmp (filetype, "d71")) |
| 1923 | | { |
| 1924 | | switch (filesize) |
| 1925 | | { |
| 1926 | | case 0x55600: |
| 1927 | | format = format_d71; |
| 1928 | | break; |
| 1929 | | case (0x55600 + 0x556): |
| 1930 | | format = format_d71_err; |
| 1931 | | break; |
| 1932 | | default: |
| 1933 | | logerror("The image you're trying to load has not the regular size of a .d71 image: \n"); |
| 1934 | | logerror("Image %s size %d\n", image_filename(image), filesize); |
| 1935 | | return INIT_FAIL; |
| 1936 | | } |
| 1937 | | } |
| 1938 | | else if (!mame_stricmp (filetype, "d67")) |
| 1939 | | format = format_d67; |
| 1940 | | else if (!mame_stricmp (filetype, "d81")) |
| 1941 | | format = format_d81; |
| 1942 | | else if (!mame_stricmp (filetype, "d80")) |
| 1943 | | format = format_d80; |
| 1944 | | else if (!mame_stricmp (filetype, "d82")) |
| 1945 | | format = format_d82; |
| 1946 | | else |
| 1947 | | { |
| 1948 | | /* Still have to work on g64 images */ |
| 1949 | | logerror("Unsupported format\n"); |
| 1950 | | return INIT_FAIL; |
| 1951 | | } |
| 1952 | | |
| 1953 | | /* Set up track / sector map according to the format of the image */ |
| 1954 | | offset_init(format, image_offset, 256); |
| 1955 | | |
| 1956 | | /* Claim memory */ |
| 1957 | | temp_copy = auto_alloc_array(image->machine, UINT8, filesize); |
| 1958 | | |
| 1959 | | if ((image_fread( image, temp_copy, filesize ) != filesize) || !filesize) |
| 1960 | | return INIT_FAIL; |
| 1961 | | |
| 1962 | | /* Start GCR encoding */ |
| 1963 | | format_id_1 = temp_copy[disk_id1(format)]; // can be modified by error code 29 -> ^ 0xff |
| 1964 | | format_id_2 = temp_copy[disk_id2(format)]; |
| 1965 | | |
| 1966 | | /* Disk is encoded and stored in xxx_drive.gcr.data */ |
| 1967 | | cbm_floppy_image_loading( format, format_id_1, format_id_2, temp_copy, vc1541_drive.gcr ); |
| 1968 | | |
| 1969 | | logerror("Floppy image %s successfully loaded\n", image_filename(image)); |
| 1970 | | return INIT_PASS; |
| 1971 | | } |
| 1972 | | |
| 1973 | | static DEVICE_IMAGE_LOAD( _1551 ) |
| 1974 | | { |
| 1975 | | UINT8 format_id_1, format_id_2; |
| 1976 | | int format = 0, filesize; |
| 1977 | | UINT8 *temp_copy = NULL; |
| 1978 | | const char *filetype; |
| 1979 | | |
| 1980 | | filesize = image_length(image); |
| 1981 | | filetype = image_filetype(image); |
| 1982 | | |
| 1983 | | /* Find out which type of image we are loading */ |
| 1984 | | if (!mame_stricmp (filetype, "d64")) |
| 1985 | | { |
| 1986 | | switch (filesize) |
| 1987 | | { |
| 1988 | | case 0x2ab00: |
| 1989 | | format = format_d64; |
| 1990 | | break; |
| 1991 | | case (0x2ab00 + 0x2ab): |
| 1992 | | format = format_d64_err; |
| 1993 | | break; |
| 1994 | | case 0x30000: |
| 1995 | | format = format_d64_40t; |
| 1996 | | break; |
| 1997 | | case (0x30000 + 0x300): |
| 1998 | | format = format_d64_40t_err; |
| 1999 | | break; |
| 2000 | | default: |
| 2001 | | logerror("The image you're trying to load has not the regular size of a .d64 image: \n"); |
| 2002 | | logerror("Image %s size %d\n", image_filename(image), filesize); |
| 2003 | | return INIT_FAIL; |
| 2004 | | } |
| 2005 | | } |
| 2006 | | else |
| 2007 | | { |
| 2008 | | logerror("Unsupported format\n"); |
| 2009 | | return INIT_FAIL; |
| 2010 | | } |
| 2011 | | |
| 2012 | | /* Set up track / sector map according to the format of the image */ |
| 2013 | | offset_init(format, image_offset, 256); |
| 2014 | | |
| 2015 | | /* Claim memory */ |
| 2016 | | temp_copy = auto_alloc_array(image->machine, UINT8, filesize); |
| 2017 | | |
| 2018 | | if ((image_fread( image, temp_copy, filesize ) != filesize) || !filesize) |
| 2019 | | return INIT_FAIL; |
| 2020 | | |
| 2021 | | /* Start GCR encoding */ |
| 2022 | | format_id_1 = temp_copy[disk_id1(format)]; // can be modified by error code 29 -> ^ 0xff |
| 2023 | | format_id_2 = temp_copy[disk_id2(format)]; |
| 2024 | | |
| 2025 | | /* Disk is encoded and stored in xxx_drive.gcr.data */ |
| 2026 | | cbm_floppy_image_loading( format, format_id_1, format_id_2, temp_copy, c1551_drive.gcr ); |
| 2027 | | |
| 2028 | | logerror("Floppy image %s successfully loaded\n", image_filename(image)); |
| 2029 | | return INIT_PASS; |
| 2030 | | } |
| 2031 | | |
| 2032 | | static DEVICE_IMAGE_UNLOAD( _1541 ) |
| 2033 | | { |
| 2034 | | } |
| 2035 | | |
| 2036 | | void vc1541_device_getinfo(const mess_device_class *devclass, UINT32 state, union devinfo *info) |
| 2037 | | { |
| 2038 | | switch(state) |
| 2039 | | { |
| 2040 | | /* --- the following bits of info are returned as 64-bit signed integers --- */ |
| 2041 | | case MESS_DEVINFO_INT_TYPE: info->i = IO_FLOPPY; break; |
| 2042 | | case MESS_DEVINFO_INT_COUNT: info->i = 1; break; |
| 2043 | | case MESS_DEVINFO_INT_READABLE: info->i = 1; break; |
| 2044 | | case MESS_DEVINFO_INT_WRITEABLE: info->i = 0; break; |
| 2045 | | case MESS_DEVINFO_INT_CREATABLE: info->i = 0; break; |
| 2046 | | case MESS_DEVINFO_INT_RESET_ON_LOAD: info->i = 1; break; |
| 2047 | | |
| 2048 | | /* --- the following bits of info are returned as pointers to data or functions --- */ |
| 2049 | | case MESS_DEVINFO_PTR_LOAD: info->load = DEVICE_IMAGE_LOAD_NAME(_1541); break; |
| 2050 | | case MESS_DEVINFO_PTR_UNLOAD: info->unload = DEVICE_IMAGE_UNLOAD_NAME(_1541); break; |
| 2051 | | case MESS_DEVINFO_PTR_DEV_SPECIFIC: info->f = (genf *) cbm_drive_config; break; |
| 2052 | | |
| 2053 | | /* --- the following bits of info are returned as NULL-terminated strings --- */ |
| 2054 | | case MESS_DEVINFO_STR_FILE_EXTENSIONS: strcpy(info->s = device_temp_str(), "d64"); break; |
| 2055 | | } |
| 2056 | | } |
| 2057 | | |
| 2058 | | |
| 2059 | | void c2031_device_getinfo(const mess_device_class *devclass, UINT32 state, union devinfo *info) |
| 2060 | | { |
| 2061 | | vc1541_device_getinfo(devclass, state, info); |
| 2062 | | } |
| 2063 | | |
| 2064 | | |
| 2065 | | void c1551_device_getinfo(const mess_device_class *devclass, UINT32 state, union devinfo *info) |
| 2066 | | { |
| 2067 | | switch(state) |
| 2068 | | { |
| 2069 | | /* --- the following bits of info are returned as pointers to data or functions --- */ |
| 2070 | | case MESS_DEVINFO_PTR_LOAD: info->load = DEVICE_IMAGE_LOAD_NAME(_1551); break; |
| 2071 | | case MESS_DEVINFO_PTR_DEV_SPECIFIC: info->f = (genf *) c1551_config; break; |
| 2072 | | |
| 2073 | | default: vc1541_device_getinfo(devclass, state, info); |
| 2074 | | } |
| 2075 | | } |
| 2076 | | |
| 2077 | | |
| 2078 | | void c1571_device_getinfo(const mess_device_class *devclass, UINT32 state, union devinfo *info) |
| 2079 | | { |
| 2080 | | switch(state) |
| 2081 | | { |
| 2082 | | /* --- the following bits of info are returned as NULL-terminated strings --- */ |
| 2083 | | case MESS_DEVINFO_STR_FILE_EXTENSIONS: strcpy(info->s = device_temp_str(), "d71"); break; |
| 2084 | | |
| 2085 | | default: vc1541_device_getinfo(devclass, state, info); |
| 2086 | | } |
| 2087 | | } |
| 2088 | | |
| 2089 | | void c1581_device_getinfo(const mess_device_class *devclass, UINT32 state, union devinfo *info) |
| 2090 | | { |
| 2091 | | switch(state) |
| 2092 | | { |
| 2093 | | /* --- the following bits of info are returned as NULL-terminated strings --- */ |
| 2094 | | case MESS_DEVINFO_STR_FILE_EXTENSIONS: strcpy(info->s = device_temp_str(), "d81"); break; |
| 2095 | | |
| 2096 | | default: vc1541_device_getinfo(devclass, state, info); |
| 2097 | | } |
| 2098 | | } |
| 2099 | | |
| 2100 | | void c8050_device_getinfo(const mess_device_class *devclass, UINT32 state, union devinfo *info) |
| 2101 | | { |
| 2102 | | switch(state) |
| 2103 | | { |
| 2104 | | /* --- the following bits of info are returned as NULL-terminated strings --- */ |
| 2105 | | case MESS_DEVINFO_STR_FILE_EXTENSIONS: strcpy(info->s = device_temp_str(), "d80"); break; |
| 2106 | | |
| 2107 | | default: vc1541_device_getinfo(devclass, state, info); |
| 2108 | | } |
| 2109 | | } |
| 2110 | | |
| 2111 | | void c8250_device_getinfo(const mess_device_class *devclass, UINT32 state, union devinfo *info) |
| 2112 | | { |
| 2113 | | switch(state) |
| 2114 | | { |
| 2115 | | /* --- the following bits of info are returned as NULL-terminated strings --- */ |
| 2116 | | case MESS_DEVINFO_STR_FILE_EXTENSIONS: strcpy(info->s = device_temp_str(), "d82"); break; |
| 2117 | | |
| 2118 | | default: vc1541_device_getinfo(devclass, state, info); |
| 2119 | | } |
| 2120 | | } |
| 2121 | | |
| 2122 | | void c2040_device_getinfo(const mess_device_class *devclass, UINT32 state, union devinfo *info) |
| 2123 | | { |
| 2124 | | switch(state) |
| 2125 | | { |
| 2126 | | /* --- the following bits of info are returned as NULL-terminated strings --- */ |
| 2127 | | case MESS_DEVINFO_STR_FILE_EXTENSIONS: strcpy(info->s = device_temp_str(), "d67"); break; |
| 2128 | | |
| 2129 | | default: vc1541_device_getinfo(devclass, state, info); |
| 2130 | | } |
| 2131 | | } |
src/mess/machine/cbmdrive.c
| r6732 | r6733 | |
| 1 | | /*************************************************************** |
| 2 | | |
| 3 | | CBM Floppy Drive Simulation |
| 4 | | |
| 5 | | This code incercepts commands from the CBM machine and |
| 6 | | send/return the appropriate data to/from the disk image |
| 7 | | |
| 8 | | This code will be eventually replaced by proper emulation |
| 9 | | (see vc1541.c) |
| 10 | | |
| 11 | | ***************************************************************/ |
| 12 | | |
| 13 | | #include <ctype.h> |
| 14 | | #include "driver.h" |
| 15 | | |
| 16 | | #include "includes/cbmserb.h" |
| 17 | | #include "includes/cbmieeeb.h" |
| 18 | | |
| 19 | | #include "includes/cbmdrive.h" |
| 20 | | |
| 21 | | #define VERBOSE_LEVEL 0 |
| 22 | | #define DBG_LOG( MACHINE, N, M, A ) \ |
| 23 | | do { \ |
| 24 | | if(VERBOSE_LEVEL >= N) \ |
| 25 | | { \ |
| 26 | | if( M ) \ |
| 27 | | logerror("%11.6f: %-24s", attotime_to_double(timer_get_time(MACHINE)), (char*) M ); \ |
| 28 | | logerror A; \ |
| 29 | | } \ |
| 30 | | } while (0) |
| 31 | | |
| 32 | | /*********************************************** |
| 33 | | |
| 34 | | D64 images handling |
| 35 | | |
| 36 | | ***********************************************/ |
| 37 | | |
| 38 | | /* tracks 1 to 35 |
| 39 | | * sectors number from 0 |
| 40 | | * each sector holds 256 data bytes |
| 41 | | * directory and Bitmap Allocation Memory in track 18 |
| 42 | | * sector 0: |
| 43 | | * 0: track# of directory begin (this linkage of sector often used) |
| 44 | | * 1: sector# of directory begin |
| 45 | | * |
| 46 | | * BAM entries (one per track) |
| 47 | | * offset 0: # of free sectors |
| 48 | | * offset 1: sector 0 (lsb) free to sector 7 |
| 49 | | * offset 2: sector 8 to 15 |
| 50 | | * offset 3: sector 16 to whatever the number to sectors in track is |
| 51 | | * |
| 52 | | * directory sector: |
| 53 | | * 0,1: track sector of next directory sector |
| 54 | | * 2, 34, 66, ... : 8 directory entries |
| 55 | | * |
| 56 | | * directory entry: |
| 57 | | * 0: file type |
| 58 | | * (0x = scratched/splat, 8x = alive, Cx = locked |
| 59 | | * where x: 0=DEL, 1=SEQ, 2=PRG, 3=USR, 4=REL) |
| 60 | | * 1,2: track and sector of file |
| 61 | | * 3..18: file name padded with a0 |
| 62 | | * 19,20: REL files side sector |
| 63 | | * 21: REL files record length |
| 64 | | * 28,29: number of blocks in file |
| 65 | | * ended with illegal track and sector numbers |
| 66 | | */ |
| 67 | | |
| 68 | | #define D64_MAX_TRACKS 35 |
| 69 | | |
| 70 | | static const int d64_sectors_per_track[] = |
| 71 | | { |
| 72 | | 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, |
| 73 | | 19, 19, 19, 19, 19, 19, 19, |
| 74 | | 18, 18, 18, 18, 18, 18, |
| 75 | | 17, 17, 17, 17, 17 |
| 76 | | }; |
| 77 | | |
| 78 | | static int d64_offset[D64_MAX_TRACKS]; /* offset of begin of track in d64 file */ |
| 79 | | |
| 80 | | /* must be called before other functions */ |
| 81 | | void cbm_drive_open_helper( void ) |
| 82 | | { |
| 83 | | int i; |
| 84 | | |
| 85 | | d64_offset[0] = 0; |
| 86 | | for (i = 1; i < D64_MAX_TRACKS; i++) |
| 87 | | d64_offset[i] = d64_offset[i - 1] + d64_sectors_per_track[i - 1] * 256; |
| 88 | | } |
| 89 | | |
| 90 | | /* calculates offset to beginning of d64 file for sector beginning */ |
| 91 | | static int d64_tracksector2offset( int track, int sector ) |
| 92 | | { |
| 93 | | return d64_offset[track - 1] + sector * 256; |
| 94 | | } |
| 95 | | |
| 96 | | static int cbm_compareNames( unsigned char *left, unsigned char *right ) |
| 97 | | { |
| 98 | | int i; |
| 99 | | |
| 100 | | for (i = 0; i < 16; i++) |
| 101 | | { |
| 102 | | if ((left[i] == '*') || (right[i] == '*')) |
| 103 | | return 1; |
| 104 | | if (left[i] == right[i]) |
| 105 | | continue; |
| 106 | | if ((left[i] == 0xa0) && (right[i] == 0)) |
| 107 | | return 1; |
| 108 | | if ((right[i] == 0xa0) && (left[i] == 0)) |
| 109 | | return 1; |
| 110 | | return 0; |
| 111 | | } |
| 112 | | return 1; |
| 113 | | } |
| 114 | | |
| 115 | | /* searches program with given name in directory |
| 116 | | * delivers -1 if not found |
| 117 | | * or pos in image of directory node */ |
| 118 | | static int d64_find( CBM_Drive * drive, unsigned char *name ) |
| 119 | | { |
| 120 | | int pos, track, sector, i; |
| 121 | | |
| 122 | | pos = d64_tracksector2offset(18, 0); |
| 123 | | track = drive->image[pos]; |
| 124 | | sector = drive->image[pos + 1]; |
| 125 | | |
| 126 | | while ((track >= 1) && (track <= 35)) |
| 127 | | { |
| 128 | | pos = d64_tracksector2offset(track, sector); |
| 129 | | for (i = 2; i < 256; i += 32) |
| 130 | | { |
| 131 | | if (drive->image[pos + i] & 0x80) |
| 132 | | { |
| 133 | | if (mame_stricmp((char *) name, (char *) "*") == 0) |
| 134 | | return pos + i; |
| 135 | | if (cbm_compareNames(name, drive->image + pos + i + 3)) |
| 136 | | return pos + i; |
| 137 | | } |
| 138 | | } |
| 139 | | track = drive->image[pos]; |
| 140 | | sector = drive->image[pos + 1]; |
| 141 | | } |
| 142 | | return -1; |
| 143 | | } |
| 144 | | |
| 145 | | /* reads file into buffer */ |
| 146 | | static void d64_readprg( running_machine *machine, CBM_Drive * drive, int pos ) |
| 147 | | { |
| 148 | | int i; |
| 149 | | |
| 150 | | for (i = 0; i < 16; i++) |
| 151 | | drive->filename[i] = toupper(drive->image[pos + i + 3]); |
| 152 | | |
| 153 | | drive->filename[i] = 0; |
| 154 | | |
| 155 | | pos = d64_tracksector2offset(drive->image[pos + 1], drive->image[pos + 2]); |
| 156 | | |
| 157 | | i = pos; |
| 158 | | drive->size = 0; |
| 159 | | while (drive->image[i] != 0) |
| 160 | | { |
| 161 | | drive->size += 254; |
| 162 | | i = d64_tracksector2offset(drive->image[i], drive->image[i + 1]); |
| 163 | | } |
| 164 | | drive->size += drive->image[i + 1]; |
| 165 | | |
| 166 | | DBG_LOG(machine, 3, "d64 readprg", ("size %d\n", drive->size)); |
| 167 | | |
| 168 | | drive->buffer = (UINT8*)realloc(drive->buffer, drive->size); |
| 169 | | if (!drive->buffer) |
| 170 | | fatalerror("out of memory %s %d\n", __FILE__, __LINE__); |
| 171 | | |
| 172 | | drive->size--; |
| 173 | | |
| 174 | | DBG_LOG(machine, 3, "d64 readprg", ("track: %d sector: %d\n", |
| 175 | | drive->image[pos + 1], |
| 176 | | drive->image[pos + 2])); |
| 177 | | |
| 178 | | for (i = 0; i < drive->size; i += 254) |
| 179 | | { |
| 180 | | if (i + 254 < drive->size) |
| 181 | | { /* not last sector */ |
| 182 | | memcpy(drive->buffer + i, drive->image + pos + 2, 254); |
| 183 | | pos = d64_tracksector2offset(drive->image[pos + 0], |
| 184 | | drive->image[pos + 1]); |
| 185 | | DBG_LOG(machine, 3, "d64 readprg", ("track: %d sector: %d\n", |
| 186 | | drive->image[pos], |
| 187 | | drive->image[pos + 1])); |
| 188 | | } |
| 189 | | else |
| 190 | | { |
| 191 | | memcpy(drive->buffer + i, drive->image + pos + 2, drive->size - i); |
| 192 | | } |
| 193 | | } |
| 194 | | } |
| 195 | | |
| 196 | | /* reads sector into buffer */ |
| 197 | | static void d64_read_sector( CBM_Drive * drive, int track, int sector ) |
| 198 | | { |
| 199 | | int pos; |
| 200 | | |
| 201 | | snprintf(drive->filename, sizeof (drive->filename), |
| 202 | | "track %d sector %d", track, sector); |
| 203 | | |
| 204 | | pos = d64_tracksector2offset (track, sector); |
| 205 | | |
| 206 | | drive->buffer = (UINT8*)realloc(drive->buffer,256); |
| 207 | | if (!drive->buffer) |
| 208 | | fatalerror("out of memory %s %d\n", __FILE__, __LINE__); |
| 209 | | |
| 210 | | logerror("d64 read track %d sector %d\n", track, sector); |
| 211 | | |
| 212 | | memcpy(drive->buffer, drive->image + pos, 256); |
| 213 | | drive->size = 256; |
| 214 | | drive->pos = 0; |
| 215 | | } |
| 216 | | |
| 217 | | /* reads directory into buffer */ |
| 218 | | static void d64_read_directory( CBM_Drive * drive ) |
| 219 | | { |
| 220 | | int pos, track, sector, i, j, blocksfree, addr = 0x0101/*0x1001*/; |
| 221 | | |
| 222 | | drive->buffer = (UINT8*)realloc(drive->buffer, 8 * 18 * 25); |
| 223 | | if (!drive->buffer) |
| 224 | | fatalerror("out of memory %s %d\n", __FILE__, __LINE__); |
| 225 | | |
| 226 | | drive->size = 0; |
| 227 | | |
| 228 | | pos = d64_tracksector2offset(18, 0); |
| 229 | | track = drive->image[pos]; |
| 230 | | sector = drive->image[pos + 1]; |
| 231 | | |
| 232 | | blocksfree = 0; |
| 233 | | for (j = 1, i = 4; j <= 35; j++, i += 4) |
| 234 | | { |
| 235 | | blocksfree += drive->image[pos + i]; |
| 236 | | } |
| 237 | | drive->buffer[drive->size++] = addr & 0xff; |
| 238 | | drive->buffer[drive->size++] = addr >> 8; |
| 239 | | addr += 29; |
| 240 | | drive->buffer[drive->size++] = addr & 0xff; |
| 241 | | drive->buffer[drive->size++] = addr >> 8; |
| 242 | | drive->buffer[drive->size++] = 0; |
| 243 | | drive->buffer[drive->size++] = 0; |
| 244 | | drive->buffer[drive->size++] = '\"'; |
| 245 | | for (j = 0; j < 16; j++) |
| 246 | | drive->buffer[drive->size++] = drive->image[pos + 0x90 + j]; |
| 247 | | /*memcpy(drive->buffer+drive->size,drive->image+pos+0x90, 16);drive->size+=16; */ |
| 248 | | drive->buffer[drive->size++] = '\"'; |
| 249 | | drive->buffer[drive->size++] = ' '; |
| 250 | | drive->buffer[drive->size++] = drive->image[pos + 162]; |
| 251 | | drive->buffer[drive->size++] = drive->image[pos + 163]; |
| 252 | | drive->buffer[drive->size++] = ' '; |
| 253 | | drive->buffer[drive->size++] = drive->image[pos + 165]; |
| 254 | | drive->buffer[drive->size++] = drive->image[pos + 166]; |
| 255 | | drive->buffer[drive->size++] = 0; |
| 256 | | |
| 257 | | while ((track >= 1) && (track <= 35)) |
| 258 | | { |
| 259 | | pos = d64_tracksector2offset(track, sector); |
| 260 | | for (i = 2; i < 256; i += 32) |
| 261 | | { |
| 262 | | if (drive->image[pos + i] & 0x80) |
| 263 | | { |
| 264 | | int len, blocks = drive->image[pos + i + 28] |
| 265 | | + 256 * drive->image[pos + i + 29]; |
| 266 | | char dummy[10]; |
| 267 | | |
| 268 | | sprintf(dummy, "%d", blocks); |
| 269 | | len = strlen (dummy); |
| 270 | | addr += 29 - len; |
| 271 | | drive->buffer[drive->size++] = addr & 0xff; |
| 272 | | drive->buffer[drive->size++] = addr >> 8; |
| 273 | | drive->buffer[drive->size++] = drive->image[pos + i + 28]; |
| 274 | | drive->buffer[drive->size++] = drive->image[pos + i + 29]; |
| 275 | | for (j = 4; j > len; j--) |
| 276 | | drive->buffer[drive->size++] = ' '; |
| 277 | | drive->buffer[drive->size++] = '\"'; |
| 278 | | for (j = 0; j < 16; j++) |
| 279 | | drive->buffer[drive->size++] = drive->image[pos + i + 3 + j]; |
| 280 | | drive->buffer[drive->size++] = '\"'; |
| 281 | | drive->buffer[drive->size++] = ' '; |
| 282 | | switch (drive->image[pos + i] & 0x3f) |
| 283 | | { |
| 284 | | case 0: |
| 285 | | drive->buffer[drive->size++] = 'D'; |
| 286 | | drive->buffer[drive->size++] = 'E'; |
| 287 | | drive->buffer[drive->size++] = 'L'; |
| 288 | | break; |
| 289 | | case 1: |
| 290 | | drive->buffer[drive->size++] = 'S'; |
| 291 | | drive->buffer[drive->size++] = 'E'; |
| 292 | | drive->buffer[drive->size++] = 'Q'; |
| 293 | | break; |
| 294 | | case 2: |
| 295 | | drive->buffer[drive->size++] = 'P'; |
| 296 | | drive->buffer[drive->size++] = 'R'; |
| 297 | | drive->buffer[drive->size++] = 'G'; |
| 298 | | break; |
| 299 | | case 3: |
| 300 | | drive->buffer[drive->size++] = 'U'; |
| 301 | | drive->buffer[drive->size++] = 'S'; |
| 302 | | drive->buffer[drive->size++] = 'R'; |
| 303 | | break; |
| 304 | | case 4: |
| 305 | | drive->buffer[drive->size++] = 'R'; |
| 306 | | drive->buffer[drive->size++] = 'E'; |
| 307 | | drive->buffer[drive->size++] = 'L'; |
| 308 | | break; |
| 309 | | } |
| 310 | | drive->buffer[drive->size++] = 0; |
| 311 | | } |
| 312 | | } |
| 313 | | track = drive->image[pos]; |
| 314 | | sector = drive->image[pos + 1]; |
| 315 | | } |
| 316 | | addr += 14; |
| 317 | | drive->buffer[drive->size++] = addr & 0xff; |
| 318 | | drive->buffer[drive->size++] = addr >> 8; |
| 319 | | drive->buffer[drive->size++] = blocksfree & 0xff; |
| 320 | | drive->buffer[drive->size++] = blocksfree >> 8; |
| 321 | | memcpy(drive->buffer + drive->size, "BLOCKS FREE", 11); |
| 322 | | drive->size += 11; |
| 323 | | drive->buffer[drive->size++] = 0; |
| 324 | | |
| 325 | | strcpy(drive->filename, "$"); |
| 326 | | } |
| 327 | | |
| 328 | | static int d64_command( running_machine *machine, CBM_Drive * drive, unsigned char *name ) |
| 329 | | { |
| 330 | | int pos; |
| 331 | | |
| 332 | | /* name eventuell mit 0xa0 auffuellen */ |
| 333 | | |
| 334 | | if (mame_stricmp((char *) name, (char *) "$") == 0) |
| 335 | | { |
| 336 | | d64_read_directory(drive); |
| 337 | | } |
| 338 | | else |
| 339 | | { |
| 340 | | if ((pos = d64_find (drive, name)) == -1) |
| 341 | | { |
| 342 | | return 1; |
| 343 | | } |
| 344 | | d64_readprg(machine, drive, pos); |
| 345 | | } |
| 346 | | return 0; |
| 347 | | } |
| 348 | | |
| 349 | | /** |
| 350 | | 7.1 Serial bus |
| 351 | | |
| 352 | | CBM Serial Bus Control Codes |
| 353 | | |
| 354 | | 20 Talk |
| 355 | | 3F Untalk |
| 356 | | 40 Listen |
| 357 | | 5F Unlisten |
| 358 | | 60 Open Channel |
| 359 | | 70 - |
| 360 | | 80 - |
| 361 | | 90 - |
| 362 | | A0 - |
| 363 | | B0 - |
| 364 | | C0 - |
| 365 | | D0 - |
| 366 | | E0 Close |
| 367 | | F0 Open |
| 368 | | |
| 369 | | |
| 370 | | |
| 371 | | How the C1541 is called by the C64: |
| 372 | | |
| 373 | | read (drive 8) |
| 374 | | /28 /f0 filename /3f |
| 375 | | /48 /60 read data /5f |
| 376 | | /28 /e0 /3f |
| 377 | | |
| 378 | | write (drive 8) |
| 379 | | /28 /f0 filename /3f |
| 380 | | /28 /60 send data /3f |
| 381 | | /28 /e0 /3f |
| 382 | | |
| 383 | | I used '/' to denote bytes sent under Attention (ATN low). |
| 384 | | |
| 385 | | 28 == LISTEN command + device number 8 |
| 386 | | f0 == secondary addres for OPEN file on channel 0 |
| 387 | | |
| 388 | | Note that there's no acknowledge bit, but timeout/EOI handshake for each |
| 389 | | byte. Check the C64 Kernel for exact description... |
| 390 | | |
| 391 | | computer master |
| 392 | | |
| 393 | | c16 called |
| 394 | | dload |
| 395 | | 20 f0 30 3a name 3f |
| 396 | | 40 60 listening 5f |
| 397 | | 20 e0 3f |
| 398 | | |
| 399 | | load |
| 400 | | 20 f0 name 3f |
| 401 | | */ |
| 402 | | static void cbm_command( running_machine *machine, CBM_Drive * drive ) |
| 403 | | { |
| 404 | | unsigned char name[20], type = 'P', mode = 0; |
| 405 | | int channel, head, track, sector; |
| 406 | | int j, i, rc; |
| 407 | | |
| 408 | | if ((drive->cmdpos == 4) |
| 409 | | && ((drive->cmdbuffer[0] & 0xf0) == 0x20) |
| 410 | | && ((drive->cmdbuffer[1] & 0xf0) == 0xf0) |
| 411 | | && (drive->cmdbuffer[2] == '#') |
| 412 | | && (drive->cmdbuffer[3] == 0x3f)) |
| 413 | | { |
| 414 | | logerror("floppy direct access channel %d opened\n", |
| 415 | | (unsigned) drive->cmdbuffer[1] & 0xf); |
| 416 | | } |
| 417 | | else if ((drive->cmdpos >= 4) |
| 418 | | && (((unsigned) drive->cmdbuffer[0] & 0xf0) == 0x20) |
| 419 | | && (((unsigned) drive->cmdbuffer[1] & 0xf0) == 0xf0) |
| 420 | | && (drive->cmdbuffer[drive->cmdpos - 1] == 0x3f)) |
| 421 | | { |
| 422 | | if (drive->cmdbuffer[3] == ':') |
| 423 | | j = 4; |
| 424 | | else |
| 425 | | j = 2; |
| 426 | | |
| 427 | | for (i = 0; (j < sizeof (name)) && (drive->cmdbuffer[j] != 0x3f) |
| 428 | | && (drive->cmdbuffer[j] != ','); |
| 429 | | i++, j++) |
| 430 | | name[i] = drive->cmdbuffer[j]; |
| 431 | | name[i] = 0; |
| 432 | | |
| 433 | | if (drive->cmdbuffer[j] == ',') |
| 434 | | { |
| 435 | | j++; |
| 436 | | if (j < drive->cmdpos) |
| 437 | | { |
| 438 | | type = drive->cmdbuffer[j]; |
| 439 | | j++; |
| 440 | | if ((j < drive->cmdpos) && (drive->cmdbuffer[j] == 'j')) |
| 441 | | { |
| 442 | | j++; |
| 443 | | if (j < drive->cmdpos) |
| 444 | | mode = drive->cmdbuffer[j]; |
| 445 | | } |
| 446 | | } |
| 447 | | } |
| 448 | | rc = 1; |
| 449 | | if (drive->drive == D64_IMAGE) |
| 450 | | { |
| 451 | | if ((type == 'P') || (type == 'S')) |
| 452 | | rc = d64_command (machine, drive, name); |
| 453 | | } |
| 454 | | if (!rc) |
| 455 | | { |
| 456 | | drive->state = OPEN; |
| 457 | | drive->pos = 0; |
| 458 | | } |
| 459 | | DBG_LOG(machine, 1, "cbm_open", ("%s %s type:%c %c\n", name, |
| 460 | | rc ? "failed" : "success", type, mode ? mode : ' ')); |
| 461 | | } |
| 462 | | else if ((drive->cmdpos == 1) && (drive->cmdbuffer[0] == 0x5f)) |
| 463 | | { |
| 464 | | drive->state = OPEN; |
| 465 | | } |
| 466 | | else if ((drive->cmdpos == 3) && ((drive->cmdbuffer[0] & 0xf0) == 0x20) |
| 467 | | && ((drive->cmdbuffer[1] & 0xf0) == 0xe0) |
| 468 | | && (drive->cmdbuffer[2] == 0x3f)) |
| 469 | | { |
| 470 | | /* if (drive->buffer) free(drive->buffer);drive->buffer=0; */ |
| 471 | | drive->state = 0; |
| 472 | | } |
| 473 | | else if ((drive->cmdpos == 2) && ((drive->cmdbuffer[0] & 0xf0) == 0x40) |
| 474 | | && ((drive->cmdbuffer[1] & 0xf0) == 0x60)) |
| 475 | | { |
| 476 | | if (drive->state == OPEN) |
| 477 | | { |
| 478 | | drive->state = READING; |
| 479 | | } |
| 480 | | } |
| 481 | | else if ((drive->cmdpos == 2) && ((drive->cmdbuffer[0] & 0xf0) == 0x20) |
| 482 | | && ((drive->cmdbuffer[1] & 0xf0) == 0x60)) |
| 483 | | { |
| 484 | | drive->state = WRITING; |
| 485 | | } |
| 486 | | else if ((drive->cmdpos == 1) && (drive->cmdbuffer[0] == 0x3f)) |
| 487 | | { |
| 488 | | drive->state = OPEN; |
| 489 | | } |
| 490 | | else if ((drive->drive == D64_IMAGE) |
| 491 | | && (4 == sscanf ((char *) drive->cmdbuffer, "U1: %d %d %d %d\x0d", |
| 492 | | &channel, &head, &track, §or))) |
| 493 | | { |
| 494 | | d64_read_sector (drive, track, sector); |
| 495 | | drive->state = OPEN; |
| 496 | | } |
| 497 | | else |
| 498 | | { |
| 499 | | |
| 500 | | logerror("unknown floppycommand(size:%d):", drive->cmdpos); |
| 501 | | for (i = 0; i < drive->cmdpos; i++) |
| 502 | | logerror("%.2x", drive->cmdbuffer[i]); |
| 503 | | logerror(" "); |
| 504 | | for (i = 0; i < drive->cmdpos; i++) |
| 505 | | logerror("%c", drive->cmdbuffer[i]); |
| 506 | | logerror("\n"); |
| 507 | | |
| 508 | | drive->state = 0; |
| 509 | | } |
| 510 | | drive->cmdpos = 0; |
| 511 | | } |
| 512 | | |
| 513 | | |
| 514 | | /*********************************************** |
| 515 | | |
| 516 | | Drive state update |
| 517 | | |
| 518 | | ***********************************************/ |
| 519 | | |
| 520 | | |
| 521 | | /* |
| 522 | | * 0x55 begin of command |
| 523 | | * |
| 524 | | * frame |
| 525 | | * selector |
| 526 | | * 0x81 device id |
| 527 | | * 0x82 command |
| 528 | | * 0x83 data |
| 529 | | * 0x84 read byte |
| 530 | | * handshake low |
| 531 | | * |
| 532 | | * byte (like in serial bus!) |
| 533 | | * |
| 534 | | * floppy drive delivers |
| 535 | | * status 3 for file not found |
| 536 | | * or filedata ended with status 3 |
| 537 | | */ |
| 538 | | void c1551_state( running_machine *machine, CBM_Drive * drive ) |
| 539 | | { |
| 540 | | static int oldstate; |
| 541 | | |
| 542 | | oldstate = drive->i.iec.state; |
| 543 | | |
| 544 | | switch (drive->i.iec.state) |
| 545 | | { |
| 546 | | case -1: /* currently neccessary for correct init */ |
| 547 | | if (drive->i.iec.handshakein) |
| 548 | | { |
| 549 | | drive->i.iec.state++; |
| 550 | | } |
| 551 | | break; |
| 552 | | case 0: |
| 553 | | if (drive->i.iec.datain == 0x55) |
| 554 | | { |
| 555 | | drive->i.iec.status = 0; |
| 556 | | drive->i.iec.state++; |
| 557 | | } |
| 558 | | break; |
| 559 | | case 1: |
| 560 | | if (drive->i.iec.datain != 0x55) |
| 561 | | { |
| 562 | | drive->i.iec.state = 10; |
| 563 | | } |
| 564 | | break; |
| 565 | | case 10: |
| 566 | | if (drive->i.iec.datain != 0) |
| 567 | | { |
| 568 | | drive->i.iec.handshakeout = 0; |
| 569 | | if (drive->i.iec.datain == 0x84) |
| 570 | | { |
| 571 | | drive->i.iec.state = 20; |
| 572 | | if (drive->pos + 1 == drive->size) |
| 573 | | drive->i.iec.status = 3; |
| 574 | | } |
| 575 | | else if (drive->i.iec.datain == 0x83) |
| 576 | | { |
| 577 | | drive->i.iec.state = 40; |
| 578 | | } |
| 579 | | else |
| 580 | | { |
| 581 | | drive->i.iec.status = 0; |
| 582 | | drive->i.iec.state++; |
| 583 | | } |
| 584 | | } |
| 585 | | break; |
| 586 | | case 11: |
| 587 | | if (!drive->i.iec.handshakein) |
| 588 | | { |
| 589 | | drive->i.iec.state++; |
| 590 | | DBG_LOG(machine, 1,"c1551",("taken data %.2x\n",drive->i.iec.datain)); |
| 591 | | if (drive->cmdpos < sizeof (drive->cmdbuffer)) |
| 592 | | drive->cmdbuffer[drive->cmdpos++] = drive->i.iec.datain; |
| 593 | | if ((drive->i.iec.datain == 0x3f) || (drive->i.iec.datain == 0x5f)) |
| 594 | | { |
| 595 | | cbm_command (machine, drive); |
| 596 | | drive->i.iec.state = 30; |
| 597 | | } |
| 598 | | else if (((drive->i.iec.datain & 0xf0) == 0x60)) |
| 599 | | { |
| 600 | | cbm_command (machine, drive); |
| 601 | | if (drive->state == READING) |
| 602 | | { |
| 603 | | } |
| 604 | | else if (drive->state == WRITING) |
| 605 | | { |
| 606 | | } |
| 607 | | else |
| 608 | | drive->i.iec.status = 3; |
| 609 | | } |
| 610 | | drive->i.iec.handshakeout = 1; |
| 611 | | } |
| 612 | | break; |
| 613 | | case 12: |
| 614 | | if (drive->i.iec.datain == 0) |
| 615 | | { |
| 616 | | drive->i.iec.state++; |
| 617 | | } |
| 618 | | break; |
| 619 | | case 13: |
| 620 | | if (drive->i.iec.handshakein) |
| 621 | | { |
| 622 | | drive->i.iec.state = 10; |
| 623 | | } |
| 624 | | break; |
| 625 | | |
| 626 | | case 20: /* reading data */ |
| 627 | | if (!drive->i.iec.handshakein) |
| 628 | | { |
| 629 | | drive->i.iec.handshakeout = 1; |
| 630 | | if (drive->state == READING) |
| 631 | | drive->i.iec.dataout = drive->buffer[drive->pos++]; |
| 632 | | drive->i.iec.state++; |
| 633 | | } |
| 634 | | break; |
| 635 | | case 21: /* reading data */ |
| 636 | | if (drive->i.iec.handshakein) |
| 637 | | { |
| 638 | | drive->i.iec.handshakeout = 0; |
| 639 | | drive->i.iec.state++; |
| 640 | | } |
| 641 | | break; |
| 642 | | case 22: |
| 643 | | if (drive->i.iec.datain == 0) |
| 644 | | { |
| 645 | | drive->i.iec.state++; |
| 646 | | } |
| 647 | | break; |
| 648 | | case 23: |
| 649 | | if (!drive->i.iec.handshakein) |
| 650 | | { |
| 651 | | drive->i.iec.handshakeout = 1; |
| 652 | | if (drive->state == READING) |
| 653 | | drive->i.iec.state = 10; |
| 654 | | else |
| 655 | | drive->i.iec.state = 0; |
| 656 | | } |
| 657 | | break; |
| 658 | | |
| 659 | | case 30: /* end of command */ |
| 660 | | if (drive->i.iec.datain == 0) |
| 661 | | { |
| 662 | | drive->i.iec.state++; |
| 663 | | } |
| 664 | | break; |
| 665 | | case 31: |
| 666 | | if (drive->i.iec.handshakein) |
| 667 | | { |
| 668 | | drive->i.iec.state = 0; |
| 669 | | } |
| 670 | | break; |
| 671 | | |
| 672 | | case 40: /* simple write */ |
| 673 | | if (!drive->i.iec.handshakein) |
| 674 | | { |
| 675 | | drive->i.iec.state++; |
| 676 | | if ((drive->state == 0) || (drive->state == OPEN)) |
| 677 | | { |
| 678 | | DBG_LOG(machine, 1, "c1551", ("taken data %.2x\n", |
| 679 | | drive->i.iec.datain)); |
| 680 | | if (drive->cmdpos < sizeof (drive->cmdbuffer)) |
| 681 | | drive->cmdbuffer[drive->cmdpos++] = drive->i.iec.datain; |
| 682 | | } |
| 683 | | else if (drive->state == WRITING) |
| 684 | | { |
| 685 | | DBG_LOG(machine, 1, "c1551", ("written data %.2x\n", drive->i.iec.datain)); |
| 686 | | } |
| 687 | | drive->i.iec.handshakeout = 1; |
| 688 | | } |
| 689 | | break; |
| 690 | | case 41: |
| 691 | | if (drive->i.iec.datain == 0) |
| 692 | | { |
| 693 | | drive->i.iec.state++; |
| 694 | | } |
| 695 | | break; |
| 696 | | case 42: |
| 697 | | if (drive->i.iec.handshakein) |
| 698 | | { |
| 699 | | drive->i.iec.state = 10; |
| 700 | | } |
| 701 | | break; |
| 702 | | } |
| 703 | | |
| 704 | | if (oldstate != drive->i.iec.state) |
| 705 | | if (VERBOSE_LEVEL >= 1) logerror("state %d->%d %d\n", oldstate, drive->i.iec.state, drive->state); |
| 706 | | } |
| 707 | | |
| 708 | | static int vc1541_time_greater( running_machine *machine, CBM_Drive * drive, attotime threshold ) |
| 709 | | { |
| 710 | | return attotime_compare( |
| 711 | | attotime_sub(timer_get_time(machine), drive->i.serial.time), |
| 712 | | threshold) > 0; |
| 713 | | } |
| 714 | | |
| 715 | | void vc1541_state( running_machine *machine, CBM_Drive * drive ) |
| 716 | | { |
| 717 | | int oldstate = drive->i.serial.state; |
| 718 | | |
| 719 | | switch (drive->i.serial.state) |
| 720 | | { |
| 721 | | case 0: |
| 722 | | if (!cbm_serial.atn[0] && !cbm_serial.clock[0]) |
| 723 | | { |
| 724 | | drive->i.serial.data = 0; |
| 725 | | drive->i.serial.state = 2; |
| 726 | | break; |
| 727 | | } |
| 728 | | if (!cbm_serial.clock[0] && drive->i.serial.forme) |
| 729 | | { |
| 730 | | drive->i.serial.data = 0; |
| 731 | | drive->i.serial.state++; |
| 732 | | break; |
| 733 | | } |
| 734 | | break; |
| 735 | | case 1: |
| 736 | | if (!cbm_serial.atn[0]) |
| 737 | | { |
| 738 | | drive->i.serial.state++; |
| 739 | | break; |
| 740 | | } |
| 741 | | if (cbm_serial.clock[0]) |
| 742 | | { |
| 743 | | drive->i.serial.broadcast = 0; |
| 744 | | drive->i.serial.data = 1; |
| 745 | | drive->i.serial.state = 100; |
| 746 | | drive->i.serial.last = 0; |
| 747 | | drive->i.serial.value = 0; |
| 748 | | drive->i.serial.time = timer_get_time(machine); |
| 749 | | break; |
| 750 | | } |
| 751 | | break; |
| 752 | | case 2: |
| 753 | | if (cbm_serial.clock[0]) |
| 754 | | { |
| 755 | | drive->i.serial.broadcast = 1; |
| 756 | | drive->i.serial.data = 1; |
| 757 | | drive->i.serial.state = 100; |
| 758 | | drive->i.serial.last = 0; |
| 759 | | drive->i.serial.value = 0; |
| 760 | | drive->i.serial.time = timer_get_time(machine); |
| 761 | | break; |
| 762 | | } |
| 763 | | break; |
| 764 | | /* bits to byte fitting */ |
| 765 | | case 100: |
| 766 | | if (!cbm_serial.clock[0]) |
| 767 | | { |
| 768 | | drive->i.serial.state++; |
| 769 | | break; |
| 770 | | } |
| 771 | | break; |
| 772 | | case 102: |
| 773 | | case 104: |
| 774 | | case 106: |
| 775 | | case 108: |
| 776 | | case 110: |
| 777 | | case 112: |
| 778 | | case 114: |
| 779 | | if (!cbm_serial.clock[0]) |
| 780 | | drive->i.serial.state++; |
| 781 | | break; |
| 782 | | case 101: |
| 783 | | if (cbm_serial.clock[0]) |
| 784 | | { |
| 785 | | drive->i.serial.value |= cbm_serial.data[0] ? 1 : 0; |
| 786 | | drive->i.serial.state++; |
| 787 | | } |
| 788 | | break; |
| 789 | | case 103: |
| 790 | | if (cbm_serial.clock[0]) |
| 791 | | { |
| 792 | | drive->i.serial.value |= cbm_serial.data[0] ? 2 : 0; |
| 793 | | drive->i.serial.state++; |
| 794 | | } |
| 795 | | break; |
| 796 | | case 105: |
| 797 | | if (cbm_serial.clock[0]) |
| 798 | | { |
| 799 | | drive->i.serial.value |= cbm_serial.data[0] ? 4 : 0; |
| 800 | | drive->i.serial.state++; |
| 801 | | } |
| 802 | | break; |
| 803 | | case 107: |
| 804 | | if (cbm_serial.clock[0]) |
| 805 | | { |
| 806 | | drive->i.serial.value |= cbm_serial.data[0] ? 8 : 0; |
| 807 | | drive->i.serial.state++; |
| 808 | | } |
| 809 | | break; |
| 810 | | case 109: |
| 811 | | if (cbm_serial.clock[0]) |
| 812 | | { |
| 813 | | drive->i.serial.value |= cbm_serial.data[0] ? 0x10 : 0; |
| 814 | | drive->i.serial.state++; |
| 815 | | } |
| 816 | | break; |
| 817 | | case 111: |
| 818 | | if (cbm_serial.clock[0]) |
| 819 | | { |
| 820 | | drive->i.serial.value |= cbm_serial.data[0] ? 0x20 : 0; |
| 821 | | drive->i.serial.state++; |
| 822 | | } |
| 823 | | break; |
| 824 | | case 113: |
| 825 | | if (cbm_serial.clock[0]) |
| 826 | | { |
| 827 | | drive->i.serial.value |= cbm_serial.data[0] ? 0x40 : 0; |
| 828 | | drive->i.serial.state++; |
| 829 | | } |
| 830 | | break; |
| 831 | | case 115: |
| 832 | | if (cbm_serial.clock[0]) |
| 833 | | { |
| 834 | | drive->i.serial.value |= cbm_serial.data[0] ? 0x80 : 0; |
| 835 | | if (drive->i.serial.broadcast |
| 836 | | && (((drive->i.serial.value & 0xf0) == 0x20) |
| 837 | | || ((drive->i.serial.value & 0xf0) == 0x40))) |
| 838 | | { |
| 839 | | drive->i.serial.forme = (drive->i.serial.value & 0xf) |
| 840 | | == drive->i.serial.device; |
| 841 | | if (!drive->i.serial.forme) |
| 842 | | { |
| 843 | | drive->i.serial.state = 160; |
| 844 | | break; |
| 845 | | } |
| 846 | | } |
| 847 | | if (drive->i.serial.forme) |
| 848 | | { |
| 849 | | if (drive->cmdpos < sizeof (drive->cmdbuffer)) |
| 850 | | drive->cmdbuffer[drive->cmdpos++] = drive->i.serial.value; |
| 851 | | DBG_LOG(machine, 1, "serial read", ("%s %s %.2x\n", |
| 852 | | drive->i.serial.broadcast ? "broad" : "", |
| 853 | | drive->i.serial.last ? "last" : "", |
| 854 | | drive->i.serial.value)); |
| 855 | | } |
| 856 | | drive->i.serial.state++; |
| 857 | | } |
| 858 | | break; |
| 859 | | case 116: |
| 860 | | if (!cbm_serial.clock[0]) |
| 861 | | { |
| 862 | | if (drive->i.serial.last) |
| 863 | | drive->i.serial.state = 130; |
| 864 | | else |
| 865 | | drive->i.serial.state++; |
| 866 | | if (drive->i.serial.broadcast && |
| 867 | | ((drive->i.serial.value == 0x3f) || (drive->i.serial.value == 0x5f) |
| 868 | | || ((drive->i.serial.value & 0xf0) == 0x60))) |
| 869 | | { |
| 870 | | cbm_command(machine, drive); |
| 871 | | } |
| 872 | | drive->i.serial.time = timer_get_time(machine); |
| 873 | | drive->i.serial.data = 0; |
| 874 | | break; |
| 875 | | } |
| 876 | | break; |
| 877 | | case 117: |
| 878 | | if (drive->i.serial.forme && ((drive->i.serial.value & 0xf0) == 0x60) |
| 879 | | && drive->i.serial.broadcast && cbm_serial.atn[0]) |
| 880 | | { |
| 881 | | if (drive->state == READING) |
| 882 | | { |
| 883 | | drive->i.serial.state = 200; |
| 884 | | break; |
| 885 | | } |
| 886 | | else if (drive->state != WRITING) |
| 887 | | { |
| 888 | | drive->i.serial.state = 150; |
| 889 | | break; |
| 890 | | } |
| 891 | | } |
| 892 | | if (((drive->i.serial.value == 0x3f) |
| 893 | | || (drive->i.serial.value == 0x5f)) |
| 894 | | && drive->i.serial.broadcast && cbm_serial.atn[0]) |
| 895 | | { |
| 896 | | drive->i.serial.data = 1; |
| 897 | | drive->i.serial.state = 140; |
| 898 | | break; |
| 899 | | } |
| 900 | | if (cbm_serial.clock[0]) |
| 901 | | { |
| 902 | | drive->i.serial.time = timer_get_time(machine); |
| 903 | | drive->i.serial.broadcast = !cbm_serial.atn[0]; |
| 904 | | drive->i.serial.data = 1; |
| 905 | | drive->i.serial.value = 0; |
| 906 | | drive->i.serial.state++; |
| 907 | | break; |
| 908 | | } |
| 909 | | break; |
| 910 | | /* if computer lowers clk not in 200micros (last byte following) |
| 911 | | * negativ pulse on data by listener */ |
| 912 | | case 118: |
| 913 | | if (!cbm_serial.clock[0]) |
| 914 | | { |
| 915 | | drive->i.serial.value = 0; |
| 916 | | drive->i.serial.state = 101; |
| 917 | | drive->i.serial.data = 1; |
| 918 | | break; |
| 919 | | } |
| 920 | | if (vc1541_time_greater(machine, drive, ATTOTIME_IN_USEC(200))) |
| 921 | | { |
| 922 | | drive->i.serial.data = 0; |
| 923 | | drive->i.serial.last = 1; |
| 924 | | drive->i.serial.state++; |
| 925 | | drive->i.serial.time = timer_get_time(machine); |
| 926 | | break; |
| 927 | | } |
| 928 | | break; |
| 929 | | case 119: |
| 930 | | if (vc1541_time_greater(machine, drive, ATTOTIME_IN_USEC(60))) |
| 931 | | { |
| 932 | | drive->i.serial.value = 0; |
| 933 | | drive->i.serial.data = 1; |
| 934 | | drive->i.serial.state = 100; |
| 935 | | break; |
| 936 | | } |
| 937 | | break; |
| 938 | | |
| 939 | | case 130: /* last byte of talk */ |
| 940 | | if (vc1541_time_greater(machine, drive, ATTOTIME_IN_USEC(60))) |
| 941 | | { |
| 942 | | drive->i.serial.data = 1; |
| 943 | | drive->i.serial.state = 0; |
| 944 | | break; |
| 945 | | } |
| 946 | | break; |
| 947 | | |
| 948 | | case 131: |
| 949 | | if (cbm_serial.clock[0]) |
| 950 | | { |
| 951 | | drive->i.serial.state = 0; |
| 952 | | } |
| 953 | | break; |
| 954 | | |
| 955 | | case 140: /* end of talk */ |
| 956 | | if (cbm_serial.clock[0]) |
| 957 | | { |
| 958 | | drive->i.serial.state = 0; |
| 959 | | } |
| 960 | | break; |
| 961 | | |
| 962 | | case 150: /* file not found */ |
| 963 | | if (cbm_serial.atn[0]) |
| 964 | | { |
| 965 | | drive->i.serial.state++; |
| 966 | | drive->i.serial.time = timer_get_time(machine); |
| 967 | | break; |
| 968 | | } |
| 969 | | break; |
| 970 | | case 151: |
| 971 | | if (vc1541_time_greater(machine, drive, ATTOTIME_IN_USEC(1000))) |
| 972 | | { |
| 973 | | drive->i.serial.state++; |
| 974 | | drive->i.serial.clock = 0; |
| 975 | | drive->i.serial.time = timer_get_time(machine); |
| 976 | | break; |
| 977 | | } |
| 978 | | break; |
| 979 | | case 152: |
| 980 | | if (vc1541_time_greater(machine, drive, ATTOTIME_IN_USEC(50))) |
| 981 | | { |
| 982 | | drive->i.serial.state++; |
| 983 | | drive->i.serial.clock = 1; |
| 984 | | break; |
| 985 | | } |
| 986 | | break; |
| 987 | | case 153: |
| 988 | | if (cbm_serial.clock[0]) |
| 989 | | { |
| 990 | | drive->i.serial.state = 0; |
| 991 | | } |
| 992 | | break; |
| 993 | | |
| 994 | | case 160: /* not for me */ |
| 995 | | if (cbm_serial.atn[0]) |
| 996 | | { |
| 997 | | drive->i.serial.state = 0; |
| 998 | | drive->i.serial.time = timer_get_time(machine); |
| 999 | | break; |
| 1000 | | } |
| 1001 | | break; |
| 1002 | | |
| 1003 | | case 200: |
| 1004 | | if (cbm_serial.clock[0]) |
| 1005 | | { |
| 1006 | | drive->i.serial.state++; |
| 1007 | | drive->i.serial.clock = 0; |
| 1008 | | drive->i.serial.time = timer_get_time(machine); |
| 1009 | | break; |
| 1010 | | } |
| 1011 | | break; |
| 1012 | | case 201: |
| 1013 | | if (vc1541_time_greater(machine, drive, ATTOTIME_IN_USEC(80))) |
| 1014 | | { |
| 1015 | | drive->i.serial.clock = 1; |
| 1016 | | drive->i.serial.data = 1; |
| 1017 | | drive->i.serial.state = 300; |
| 1018 | | break; |
| 1019 | | } |
| 1020 | | break; |
| 1021 | | |
| 1022 | | case 300: |
| 1023 | | if (!cbm_serial.atn[0]) |
| 1024 | | { |
| 1025 | | drive->i.serial.state = 330; |
| 1026 | | drive->i.serial.data = 1; |
| 1027 | | drive->i.serial.clock = 1; |
| 1028 | | break; |
| 1029 | | } |
| 1030 | | if (cbm_serial.data[0]) |
| 1031 | | { |
| 1032 | | drive->i.serial.value = drive->buffer[drive->pos]; |
| 1033 | | drive->i.serial.clock = 0; |
| 1034 | | drive->i.serial.data = (drive->i.serial.value & 1) ? 1 : 0; |
| 1035 | | drive->i.serial.state++; |
| 1036 | | drive->i.serial.time = timer_get_time(machine); |
| 1037 | | break; |
| 1038 | | } |
| 1039 | | break; |
| 1040 | | case 301: |
| 1041 | | if (!cbm_serial.atn[0]) |
| 1042 | | { |
| 1043 | | drive->i.serial.state = 330; |
| 1044 | | drive->i.serial.data = 1; |
| 1045 | | drive->i.serial.clock = 1; |
| 1046 | | break; |
| 1047 | | } |
| 1048 | | if (vc1541_time_greater(machine, drive, ATTOTIME_IN_USEC(40))) |
| 1049 | | { |
| 1050 | | drive->i.serial.clock = 1; |
| 1051 | | drive->i.serial.state++; |
| 1052 | | drive->i.serial.time = timer_get_time(machine); |
| 1053 | | break; |
| 1054 | | } |
| 1055 | | break; |
| 1056 | | case 303: |
| 1057 | | case 305: |
| 1058 | | case 307: |
| 1059 | | case 309: |
| 1060 | | case 311: |
| 1061 | | case 313: |
| 1062 | | case 315: |
| 1063 | | if (!cbm_serial.atn[0]) |
| 1064 | | { |
| 1065 | | drive->i.serial.state = 330; |
| 1066 | | drive->i.serial.data = 1; |
| 1067 | | drive->i.serial.clock = 1; |
| 1068 | | break; |
| 1069 | | } |
| 1070 | | if (vc1541_time_greater(machine, drive, ATTOTIME_IN_USEC(20))) |
| 1071 | | { |
| 1072 | | drive->i.serial.clock = 1; |
| 1073 | | drive->i.serial.state++; |
| 1074 | | drive->i.serial.time = timer_get_time(machine); |
| 1075 | | break; |
| 1076 | | } |
| 1077 | | break; |
| 1078 | | case 302: |
| 1079 | | if (!cbm_serial.atn[0]) |
| 1080 | | { |
| 1081 | | drive->i.serial.state = 330; |
| 1082 | | drive->i.serial.data = 1; |
| 1083 | | drive->i.serial.clock = 1; |
| 1084 | | break; |
| 1085 | | } |
| 1086 | | if (vc1541_time_greater(machine, drive, ATTOTIME_IN_USEC(20))) |
| 1087 | | { |
| 1088 | | drive->i.serial.data = drive->i.serial.value & 2 ? 1 : 0; |
| 1089 | | drive->i.serial.clock = 0; |
| 1090 | | drive->i.serial.state++; |
| 1091 | | drive->i.serial.time = timer_get_time(machine); |
| 1092 | | break; |
| 1093 | | } |
| 1094 | | break; |
| 1095 | | case 304: |
| 1096 | | if (!cbm_serial.atn[0]) |
| 1097 | | { |
| 1098 | | drive->i.serial.state = 330; |
| 1099 | | drive->i.serial.data = 1; |
| 1100 | | drive->i.serial.clock = 1; |
| 1101 | | break; |
| 1102 | | } |
| 1103 | | if (vc1541_time_greater(machine, drive, ATTOTIME_IN_USEC(20))) |
| 1104 | | { |
| 1105 | | drive->i.serial.data = drive->i.serial.value & 4 ? 1 : 0; |
| 1106 | | drive->i.serial.clock = 0; |
| 1107 | | drive->i.serial.state++; |
| 1108 | | drive->i.serial.time = timer_get_time(machine); |
| 1109 | | break; |
| 1110 | | } |
| 1111 | | break; |
| 1112 | | case 306: |
| 1113 | | if (!cbm_serial.atn[0]) |
| 1114 | | { |
| 1115 | | drive->i.serial.state = 330; |
| 1116 | | drive->i.serial.data = 1; |
| 1117 | | drive->i.serial.clock = 1; |
| 1118 | | break; |
| 1119 | | } |
| 1120 | | if (vc1541_time_greater(machine, drive, ATTOTIME_IN_USEC(20))) |
| 1121 | | { |
| 1122 | | drive->i.serial.data = drive->i.serial.value & 8 ? 1 : 0; |
| 1123 | | drive->i.serial.clock = 0; |
| 1124 | | drive->i.serial.state++; |
| 1125 | | drive->i.serial.time = timer_get_time(machine); |
| 1126 | | break; |
| 1127 | | } |
| 1128 | | break; |
| 1129 | | case 308: |
| 1130 | | if (!cbm_serial.atn[0]) |
| 1131 | | { |
| 1132 | | drive->i.serial.state = 330; |
| 1133 | | drive->i.serial.data = 1; |
| 1134 | | drive->i.serial.clock = 1; |
| 1135 | | break; |
| 1136 | | } |
| 1137 | | if (vc1541_time_greater(machine, drive, ATTOTIME_IN_USEC(20))) |
| 1138 | | { |
| 1139 | | drive->i.serial.data = drive->i.serial.value & 0x10 ? 1 : 0; |
| 1140 | | drive->i.serial.clock = 0; |
| 1141 | | drive->i.serial.state++; |
| 1142 | | drive->i.serial.time = timer_get_time(machine); |
| 1143 | | break; |
| 1144 | | } |
| 1145 | | break; |
| 1146 | | case 310: |
| 1147 | | if (!cbm_serial.atn[0]) |
| 1148 | | { |
| 1149 | | drive->i.serial.state = 330; |
| 1150 | | drive->i.serial.data = 1; |
| 1151 | | drive->i.serial.clock = 1; |
| 1152 | | break; |
| 1153 | | } |
| 1154 | | if (vc1541_time_greater(machine, drive, ATTOTIME_IN_USEC(20))) |
| 1155 | | { |
| 1156 | | drive->i.serial.data = drive->i.serial.value & 0x20 ? 1 : 0; |
| 1157 | | drive->i.serial.clock = 0; |
| 1158 | | drive->i.serial.state++; |
| 1159 | | drive->i.serial.time = timer_get_time(machine); |
| 1160 | | break; |
| 1161 | | } |
| 1162 | | break; |
| 1163 | | case 312: |
| 1164 | | if (!cbm_serial.atn[0]) |
| 1165 | | { |
| 1166 | | drive->i.serial.state = 330; |
| 1167 | | drive->i.serial.data = 1; |
| 1168 | | drive->i.serial.clock = 1; |
| 1169 | | break; |
| 1170 | | } |
| 1171 | | if (vc1541_time_greater(machine, drive, ATTOTIME_IN_USEC(20))) |
| 1172 | | { |
| 1173 | | drive->i.serial.data = drive->i.serial.value & 0x40 ? 1 : 0; |
| 1174 | | drive->i.serial.clock = 0; |
| 1175 | | drive->i.serial.state++; |
| 1176 | | drive->i.serial.time = timer_get_time(machine); |
| 1177 | | break; |
| 1178 | | } |
| 1179 | | break; |
| 1180 | | case 314: |
| 1181 | | if (!cbm_serial.atn[0]) |
| 1182 | | { |
| 1183 | | drive->i.serial.state = 330; |
| 1184 | | drive->i.serial.data = 1; |
| 1185 | | drive->i.serial.clock = 1; |
| 1186 | | break; |
| 1187 | | } |
| 1188 | | if (vc1541_time_greater(machine, drive, ATTOTIME_IN_USEC(20))) |
| 1189 | | { |
| 1190 | | drive->i.serial.data = drive->i.serial.value & 0x80 ? 1 : 0; |
| 1191 | | drive->i.serial.clock = 0; |
| 1192 | | drive->i.serial.state++; |
| 1193 | | drive->i.serial.time = timer_get_time(machine); |
| 1194 | | break; |
| 1195 | | } |
| 1196 | | break; |
| 1197 | | case 316: |
| 1198 | | if (!cbm_serial.atn[0]) |
| 1199 | | { |
| 1200 | | drive->i.serial.state = 330; |
| 1201 | | drive->i.serial.data = 1; |
| 1202 | | drive->i.serial.clock = 1; |
| 1203 | | break; |
| 1204 | | } |
| 1205 | | if (vc1541_time_greater(machine, drive, ATTOTIME_IN_USEC(20))) |
| 1206 | | { |
| 1207 | | DBG_LOG(machine, 1, "vc1541", ("%.2x written\n", drive->i.serial.value)); |
| 1208 | | drive->i.serial.data = 1; |
| 1209 | | drive->i.serial.clock = 0; |
| 1210 | | drive->i.serial.state++; |
| 1211 | | drive->i.serial.time = timer_get_time(machine); |
| 1212 | | break; |
| 1213 | | } |
| 1214 | | break; |
| 1215 | | case 317: |
| 1216 | | if (!cbm_serial.atn[0]) |
| 1217 | | { |
| 1218 | | drive->i.serial.state = 330; |
| 1219 | | drive->i.serial.data = 1; |
| 1220 | | drive->i.serial.clock = 1; |
| 1221 | | break; |
| 1222 | | } |
| 1223 | | if (!cbm_serial.data[0]) |
| 1224 | | { |
| 1225 | | drive->i.serial.state++; |
| 1226 | | drive->i.serial.time = timer_get_time(machine); |
| 1227 | | break; |
| 1228 | | } |
| 1229 | | break; |
| 1230 | | case 318: |
| 1231 | | if (!cbm_serial.atn[0]) |
| 1232 | | { |
| 1233 | | drive->i.serial.state = 330; |
| 1234 | | drive->i.serial.data = 1; |
| 1235 | | drive->i.serial.clock = 1; |
| 1236 | | break; |
| 1237 | | } |
| 1238 | | if (drive->pos + 1 == drive->size) |
| 1239 | | { |
| 1240 | | drive->i.serial.clock = 1; |
| 1241 | | drive->i.serial.state = 0; |
| 1242 | | break; |
| 1243 | | } |
| 1244 | | if (drive->pos + 2 == drive->size) |
| 1245 | | { |
| 1246 | | drive->pos++; |
| 1247 | | drive->i.serial.state = 320; |
| 1248 | | break; |
| 1249 | | } |
| 1250 | | if (vc1541_time_greater(machine, drive, ATTOTIME_IN_USEC(100))) |
| 1251 | | { |
| 1252 | | drive->pos++; |
| 1253 | | drive->i.serial.clock = 1; |
| 1254 | | drive->i.serial.state = 300; |
| 1255 | | break; |
| 1256 | | } |
| 1257 | | break; |
| 1258 | | case 320: |
| 1259 | | if (!cbm_serial.atn[0]) |
| 1260 | | { |
| 1261 | | drive->i.serial.state = 330; |
| 1262 | | drive->i.serial.data = 1; |
| 1263 | | drive->i.serial.clock = 1; |
| 1264 | | break; |
| 1265 | | } |
| 1266 | | if (vc1541_time_greater(machine, drive, ATTOTIME_IN_USEC(100))) |
| 1267 | | { |
| 1268 | | drive->i.serial.clock = 1; |
| 1269 | | drive->i.serial.state++; |
| 1270 | | break; |
| 1271 | | } |
| 1272 | | break; |
| 1273 | | case 321: |
| 1274 | | if (!cbm_serial.atn[0]) |
| 1275 | | { |
| 1276 | | drive->i.serial.state = 330; |
| 1277 | | drive->i.serial.data = 1; |
| 1278 | | drive->i.serial.clock = 1; |
| 1279 | | break; |
| 1280 | | } |
| 1281 | | if (cbm_serial.data[0]) |
| 1282 | | { |
| 1283 | | drive->i.serial.state++; |
| 1284 | | } |
| 1285 | | break; |
| 1286 | | case 322: |
| 1287 | | if (!cbm_serial.atn[0]) |
| 1288 | | { |
| 1289 | | drive->i.serial.state = 330; |
| 1290 | | drive->i.serial.data = 1; |
| 1291 | | drive->i.serial.clock = 1; |
| 1292 | | break; |
| 1293 | | } |
| 1294 | | if (!cbm_serial.data[0]) |
| 1295 | | { |
| 1296 | | drive->i.serial.state++; |
| 1297 | | } |
| 1298 | | break; |
| 1299 | | case 323: |
| 1300 | | if (!cbm_serial.atn[0]) |
| 1301 | | { |
| 1302 | | drive->i.serial.state = 330; |
| 1303 | | drive->i.serial.data = 1; |
| 1304 | | drive->i.serial.clock = 1; |
| 1305 | | break; |
| 1306 | | } |
| 1307 | | if (cbm_serial.data[0]) |
| 1308 | | { |
| 1309 | | drive->i.serial.state = 300; |
| 1310 | | } |
| 1311 | | break; |
| 1312 | | case 330: /* computer breaks receiving */ |
| 1313 | | drive->i.serial.state = 0; |
| 1314 | | break; |
| 1315 | | } |
| 1316 | | |
| 1317 | | if (oldstate != drive->i.serial.state) |
| 1318 | | if (VERBOSE_LEVEL >= 1) logerror("%d state %d->%d %d %s %s %s\n", |
| 1319 | | drive->i.serial.device, |
| 1320 | | oldstate, |
| 1321 | | drive->i.serial.state, drive->state, |
| 1322 | | cbm_serial.atn[0] ? "ATN" : "atn", |
| 1323 | | cbm_serial.clock[0] ? "CLOCK" : "clock", |
| 1324 | | cbm_serial.data[0] ? "DATA" : "data"); |
| 1325 | | } |
| 1326 | | |
| 1327 | | /* difference between vic20 and pet (first series) |
| 1328 | | pet lowers atn and wants a reaction on ndac */ |
| 1329 | | |
| 1330 | | void c2031_state( running_machine *machine, CBM_Drive *drive ) |
| 1331 | | { |
| 1332 | | const device_config *ieeebus = devtag_get_device(machine, "ieee_bus"); |
| 1333 | | int oldstate = drive->i.ieee.state; |
| 1334 | | int data; |
| 1335 | | |
| 1336 | | switch (drive->i.ieee.state) |
| 1337 | | { |
| 1338 | | case 0: |
| 1339 | | if (!cbm_ieee_dav_r(ieeebus, 0)) |
| 1340 | | { |
| 1341 | | drive->i.ieee.state = 10; |
| 1342 | | } |
| 1343 | | else if (!cbm_ieee_atn_r(ieeebus, 0)) |
| 1344 | | { |
| 1345 | | drive->i.ieee.state = 11; |
| 1346 | | cbm_ieee_ndac_w(ieeebus, 1, 0); |
| 1347 | | logerror("arsch\n"); |
| 1348 | | } |
| 1349 | | break; |
| 1350 | | case 1: |
| 1351 | | break; |
| 1352 | | case 10: |
| 1353 | | if (cbm_ieee_dav_r(ieeebus, 0)) |
| 1354 | | { |
| 1355 | | drive->i.ieee.state++; |
| 1356 | | cbm_ieee_nrfd_w(ieeebus, 1, 1); |
| 1357 | | cbm_ieee_ndac_w(ieeebus, 1, 0); |
| 1358 | | } |
| 1359 | | break; |
| 1360 | | case 11: |
| 1361 | | if (!cbm_ieee_dav_r(ieeebus, 0)) |
| 1362 | | { |
| 1363 | | cbm_ieee_nrfd_w(ieeebus, 1, 0); |
| 1364 | | data = cbm_ieee_data_r(ieeebus, 0) ^ 0xff; |
| 1365 | | cbm_ieee_ndac_w(ieeebus, 1, 1); |
| 1366 | | logerror("byte received %.2x\n",data); |
| 1367 | | if (!cbm_ieee_atn_r(ieeebus, 0) && ((data & 0x0f) == drive->i.ieee.device)) |
| 1368 | | { |
| 1369 | | if ((data & 0xf0) == 0x40) |
| 1370 | | drive->i.ieee.state = 30; |
| 1371 | | else |
| 1372 | | drive->i.ieee.state = 20; |
| 1373 | | if (drive->cmdpos < sizeof (drive->cmdbuffer)) |
| 1374 | | drive->cmdbuffer[drive->cmdpos++] = data; |
| 1375 | | } |
| 1376 | | else if ((data&0xf) == 0xf) |
| 1377 | | { |
| 1378 | | drive->i.ieee.state--; |
| 1379 | | } |
| 1380 | | else |
| 1381 | | { |
| 1382 | | drive->i.ieee.state++; |
| 1383 | | } |
| 1384 | | } |
| 1385 | | break; |
| 1386 | | /* wait until atn is released */ |
| 1387 | | case 12: |
| 1388 | | if (cbm_ieee_atn_r(ieeebus, 0)) |
| 1389 | | { |
| 1390 | | drive->i.ieee.state++; |
| 1391 | | cbm_ieee_nrfd_w(ieeebus, 1, 0); |
| 1392 | | } |
| 1393 | | break; |
| 1394 | | case 13: |
| 1395 | | if (!cbm_ieee_atn_r(ieeebus, 0)) |
| 1396 | | { |
| 1397 | | drive->i.ieee.state = 10; |
| 1398 | | /* cbm_ieee_nrfd_w(ieeebus, 1, 0); */ |
| 1399 | | } |
| 1400 | | break; |
| 1401 | | |
| 1402 | | /* receiving rest of command */ |
| 1403 | | case 20: |
| 1404 | | if (cbm_ieee_dav_r(ieeebus, 0)) |
| 1405 | | { |
| 1406 | | drive->i.ieee.state++; |
| 1407 | | cbm_ieee_nrfd_w(ieeebus, 1, 1); |
| 1408 | | cbm_ieee_ndac_w(ieeebus, 1, 0); |
| 1409 | | } |
| 1410 | | break; |
| 1411 | | case 21: |
| 1412 | | if (!cbm_ieee_dav_r(ieeebus, 0)) |
| 1413 | | { |
| 1414 | | cbm_ieee_nrfd_w(ieeebus, 1, 0); |
| 1415 | | data = cbm_ieee_data_r(ieeebus, 0) ^ 0xff; |
| 1416 | | logerror("byte received %.2x\n",data); |
| 1417 | | if (drive->cmdpos < sizeof (drive->cmdbuffer)) |
| 1418 | | drive->cmdbuffer[drive->cmdpos++] = data; |
| 1419 | | if (!cbm_ieee_atn_r(ieeebus, 0) && ((data & 0xf) == 0xf)) |
| 1420 | | { |
| 1421 | | cbm_command(machine, drive); |
| 1422 | | drive->i.ieee.state = 10; |
| 1423 | | } |
| 1424 | | else |
| 1425 | | drive->i.ieee.state = 20; |
| 1426 | | |
| 1427 | | cbm_ieee_ndac_w(ieeebus, 1, 1); |
| 1428 | | } |
| 1429 | | break; |
| 1430 | | |
| 1431 | | /* read command */ |
| 1432 | | case 30: |
| 1433 | | if (cbm_ieee_dav_r(ieeebus, 0)) |
| 1434 | | { |
| 1435 | | drive->i.ieee.state++; |
| 1436 | | cbm_ieee_nrfd_w(ieeebus, 1, 1); |
| 1437 | | cbm_ieee_ndac_w(ieeebus, 1, 0); |
| 1438 | | } |
| 1439 | | break; |
| 1440 | | case 31: |
| 1441 | | if (!cbm_ieee_dav_r(ieeebus, 0)) |
| 1442 | | { |
| 1443 | | cbm_ieee_nrfd_w(ieeebus, 1, 0); |
| 1444 | | data = cbm_ieee_data_r(ieeebus, 0) ^ 0xff; |
| 1445 | | logerror("byte received %.2x\n", data); |
| 1446 | | if (drive->cmdpos < sizeof (drive->cmdbuffer)) |
| 1447 | | drive->cmdbuffer[drive->cmdpos++] = data; |
| 1448 | | cbm_command(machine, drive); |
| 1449 | | if (drive->state == READING) |
| 1450 | | drive->i.ieee.state++; |
| 1451 | | else |
| 1452 | | drive->i.ieee.state = 10; |
| 1453 | | cbm_ieee_ndac_w(ieeebus, 1, 1); |
| 1454 | | } |
| 1455 | | break; |
| 1456 | | case 32: |
| 1457 | | if (cbm_ieee_dav_r(ieeebus, 0)) |
| 1458 | | { |
| 1459 | | cbm_ieee_nrfd_w(ieeebus, 1, 1); |
| 1460 | | drive->i.ieee.state = 40; |
| 1461 | | } |
| 1462 | | break; |
| 1463 | | case 40: |
| 1464 | | if (!cbm_ieee_ndac_r(ieeebus, 0)) |
| 1465 | | { |
| 1466 | | cbm_ieee_data_w(ieeebus, 1, drive->buffer[drive->pos++] ^ 0xff); |
| 1467 | | if (drive->pos >= drive->size) |
| 1468 | | cbm_ieee_eoi_w(ieeebus, 1, 0); |
| 1469 | | cbm_ieee_dav_w(ieeebus, 1, 0); |
| 1470 | | drive->i.ieee.state++; |
| 1471 | | } |
| 1472 | | break; |
| 1473 | | case 41: |
| 1474 | | if (!cbm_ieee_nrfd_r(ieeebus, 0)) |
| 1475 | | { |
| 1476 | | drive->i.ieee.state++; |
| 1477 | | } |
| 1478 | | break; |
| 1479 | | case 42: |
| 1480 | | if (cbm_ieee_ndac_r(ieeebus, 0)) |
| 1481 | | { |
| 1482 | | if (cbm_ieee_eoi_r(ieeebus, 0)) |
| 1483 | | drive->i.ieee.state = 40; |
| 1484 | | |
| 1485 | | else |
| 1486 | | { |
| 1487 | | cbm_ieee_data_w(ieeebus, 1, 0xff); |
| 1488 | | cbm_ieee_ndac_w(ieeebus, 1, 0); |
| 1489 | | cbm_ieee_nrfd_w(ieeebus, 1, 0); |
| 1490 | | cbm_ieee_eoi_w(ieeebus, 1, 1); |
| 1491 | | drive->i.ieee.state = 10; |
| 1492 | | } |
| 1493 | | cbm_ieee_dav_w(ieeebus, 1, 1); |
| 1494 | | } |
| 1495 | | break; |
| 1496 | | } |
| 1497 | | |
| 1498 | | if (oldstate != drive->i.ieee.state) |
| 1499 | | if (VERBOSE_LEVEL >= 1) logerror("%d state %d->%d %d\n", |
| 1500 | | drive->i.ieee.device, |
| 1501 | | oldstate, |
| 1502 | | drive->i.ieee.state, drive->state |
| 1503 | | ); |
| 1504 | | } |
| 1505 | | |
| 1506 | | |
| 1507 | | /************************************** |
| 1508 | | |
| 1509 | | C1551 handlers |
| 1510 | | |
| 1511 | | **************************************/ |
| 1512 | | |
| 1513 | | |
| 1514 | | static void c1551_write_data( running_machine *machine, CBM_Drive * drive, int data ) |
| 1515 | | { |
| 1516 | | drive->i.iec.datain = data; |
| 1517 | | c1551_state (machine, drive); |
| 1518 | | } |
| 1519 | | |
| 1520 | | static int c1551_read_data( running_machine *machine, CBM_Drive * drive ) |
| 1521 | | { |
| 1522 | | c1551_state (machine, drive); |
| 1523 | | return drive->i.iec.dataout; |
| 1524 | | } |
| 1525 | | |
| 1526 | | static void c1551_write_handshake( running_machine *machine, CBM_Drive * drive, int data ) |
| 1527 | | { |
| 1528 | | drive->i.iec.handshakein = data&0x40?1:0; |
| 1529 | | c1551_state (machine, drive); |
| 1530 | | } |
| 1531 | | |
| 1532 | | static int c1551_read_handshake( running_machine *machine, CBM_Drive * drive ) |
| 1533 | | { |
| 1534 | | c1551_state (machine, drive); |
| 1535 | | return drive->i.iec.handshakeout?0x80:0; |
| 1536 | | } |
| 1537 | | |
| 1538 | | static int c1551_read_status( running_machine *machine, CBM_Drive * drive ) |
| 1539 | | { |
| 1540 | | c1551_state (machine, drive); |
| 1541 | | return drive->i.iec.status; |
| 1542 | | } |
| 1543 | | |
| 1544 | | |
| 1545 | | WRITE8_DEVICE_HANDLER( c1551_0_write_data ) |
| 1546 | | { |
| 1547 | | c1551_write_data(device->machine, cbm_drive, data); |
| 1548 | | } |
| 1549 | | |
| 1550 | | READ8_DEVICE_HANDLER( c1551_0_read_data ) |
| 1551 | | { |
| 1552 | | return c1551_read_data(device->machine, cbm_drive); |
| 1553 | | } |
| 1554 | | |
| 1555 | | WRITE8_DEVICE_HANDLER( c1551_0_write_handshake ) |
| 1556 | | { |
| 1557 | | c1551_write_handshake(device->machine, cbm_drive, data); |
| 1558 | | } |
| 1559 | | |
| 1560 | | READ8_DEVICE_HANDLER( c1551_0_read_handshake ) |
| 1561 | | { |
| 1562 | | return c1551_read_handshake(device->machine, cbm_drive); |
| 1563 | | } |
| 1564 | | |
| 1565 | | READ8_DEVICE_HANDLER( c1551_0_read_status ) |
| 1566 | | { |
| 1567 | | return c1551_read_status(device->machine, cbm_drive); |
| 1568 | | } |
| 1569 | | |
| 1570 | | WRITE8_DEVICE_HANDLER( c1551_1_write_data ) |
| 1571 | | { |
| 1572 | | c1551_write_data(device->machine, cbm_drive + 1, data); |
| 1573 | | } |
| 1574 | | |
| 1575 | | READ8_DEVICE_HANDLER( c1551_1_read_data ) |
| 1576 | | { |
| 1577 | | return c1551_read_data(device->machine, cbm_drive + 1); |
| 1578 | | } |
| 1579 | | |
| 1580 | | WRITE8_DEVICE_HANDLER( c1551_1_write_handshake ) |
| 1581 | | { |
| 1582 | | c1551_write_handshake(device->machine, cbm_drive + 1, data); |
| 1583 | | } |
| 1584 | | |
| 1585 | | READ8_DEVICE_HANDLER( c1551_1_read_handshake ) |
| 1586 | | { |
| 1587 | | return c1551_read_handshake(device->machine, cbm_drive + 1); |
| 1588 | | } |
| 1589 | | |
| 1590 | | READ8_DEVICE_HANDLER( c1551_1_read_status ) |
| 1591 | | { |
| 1592 | | return c1551_read_status(device->machine, cbm_drive + 1); |
| 1593 | | } |
| 1594 | | |
| 1595 | | |
| 1596 | | /************************************** |
| 1597 | | |
| 1598 | | VC1541 Serial Bus Device Interface |
| 1599 | | |
| 1600 | | **************************************/ |
| 1601 | | |
| 1602 | | static UINT8 vc1541_atn_read( running_machine *machine, CBM_Drive * drive ) |
| 1603 | | { |
| 1604 | | vc1541_state(machine, drive); |
| 1605 | | return drive->i.serial.atn; |
| 1606 | | } |
| 1607 | | |
| 1608 | | static UINT8 vc1541_data_read( running_machine *machine, CBM_Drive * drive ) |
| 1609 | | { |
| 1610 | | vc1541_state(machine, drive); |
| 1611 | | return drive->i.serial.data; |
| 1612 | | } |
| 1613 | | |
| 1614 | | static UINT8 vc1541_clock_read( running_machine *machine, CBM_Drive * drive ) |
| 1615 | | { |
| 1616 | | vc1541_state(machine, drive); |
| 1617 | | return drive->i.serial.clock; |
| 1618 | | } |
| 1619 | | |
| 1620 | | static void vc1541_data_write( running_machine *machine, CBM_Drive * drive, int level ) |
| 1621 | | { |
| 1622 | | vc1541_state(machine, drive); |
| 1623 | | } |
| 1624 | | |
| 1625 | | static void vc1541_clock_write( running_machine *machine, CBM_Drive * drive, int level ) |
| 1626 | | { |
| 1627 | | vc1541_state(machine, drive); |
| 1628 | | } |
| 1629 | | |
| 1630 | | static void vc1541_atn_write( running_machine *machine, CBM_Drive * drive, int level ) |
| 1631 | | { |
| 1632 | | vc1541_state(machine, drive); |
| 1633 | | } |
| 1634 | | |
| 1635 | | static void drive_reset_write( CBM_Drive * drive, int level ) |
| 1636 | | { |
| 1637 | | if (level == 0) |
| 1638 | | { |
| 1639 | | drive->i.serial.data = |
| 1640 | | drive->i.serial.clock = |
| 1641 | | drive->i.serial.atn = 1; |
| 1642 | | drive->i.serial.state = 0; |
| 1643 | | } |
| 1644 | | } |
| 1645 | | |
| 1646 | | static READ8_DEVICE_HANDLER( sim_drive_atn_read ) |
| 1647 | | { |
| 1648 | | int i; |
| 1649 | | |
| 1650 | | cbm_serial.atn[0] = cbm_serial.atn[1]; |
| 1651 | | for (i = 0; i < cbm_serial.count; i++) |
| 1652 | | cbm_serial.atn[0] &= cbm_serial.atn[i + 2] = |
| 1653 | | vc1541_atn_read(device->machine, cbm_serial.drives[i]); |
| 1654 | | return cbm_serial.atn[0]; |
| 1655 | | } |
| 1656 | | |
| 1657 | | static READ8_DEVICE_HANDLER( sim_drive_clock_read ) |
| 1658 | | { |
| 1659 | | int i; |
| 1660 | | |
| 1661 | | cbm_serial.clock[0] = cbm_serial.clock[1]; |
| 1662 | | for (i = 0; i < cbm_serial.count; i++) |
| 1663 | | cbm_serial.clock[0] &= cbm_serial.clock[i + 2] = |
| 1664 | | vc1541_clock_read(device->machine, cbm_serial.drives[i]); |
| 1665 | | return cbm_serial.clock[0]; |
| 1666 | | } |
| 1667 | | |
| 1668 | | static READ8_DEVICE_HANDLER( sim_drive_data_read ) |
| 1669 | | { |
| 1670 | | int i; |
| 1671 | | |
| 1672 | | cbm_serial.data[0] = cbm_serial.data[1]; |
| 1673 | | for (i = 0; i < cbm_serial.count; i++) |
| 1674 | | cbm_serial.data[0] &= cbm_serial.data[i + 2] = |
| 1675 | | vc1541_data_read(device->machine, cbm_serial.drives[i]); |
| 1676 | | return cbm_serial.data[0]; |
| 1677 | | } |
| 1678 | | |
| 1679 | | static READ8_DEVICE_HANDLER( sim_drive_request_read ) |
| 1680 | | { |
| 1681 | | /* in c16 not connected */ |
| 1682 | | return 1; |
| 1683 | | } |
| 1684 | | |
| 1685 | | static WRITE8_DEVICE_HANDLER( sim_drive_atn_write ) |
| 1686 | | { |
| 1687 | | int i; |
| 1688 | | |
| 1689 | | cbm_serial.atn[0] = |
| 1690 | | cbm_serial.atn[1] = data; |
| 1691 | | /* update line */ |
| 1692 | | for (i = 0; i < cbm_serial.count; i++) |
| 1693 | | cbm_serial.atn[0] &= cbm_serial.atn[i + 2]; |
| 1694 | | /* inform drives */ |
| 1695 | | for (i = 0; i < cbm_serial.count; i++) |
| 1696 | | vc1541_atn_write(device->machine, cbm_serial.drives[i], cbm_serial.atn[0]); |
| 1697 | | } |
| 1698 | | |
| 1699 | | static WRITE8_DEVICE_HANDLER( sim_drive_clock_write ) |
| 1700 | | { |
| 1701 | | int i; |
| 1702 | | |
| 1703 | | cbm_serial.clock[0] = |
| 1704 | | cbm_serial.clock[1] = data; |
| 1705 | | /* update line */ |
| 1706 | | for (i = 0; i < cbm_serial.count; i++) |
| 1707 | | cbm_serial.clock[0] &= cbm_serial.clock[i + 2]; |
| 1708 | | /* inform drives */ |
| 1709 | | for (i = 0; i < cbm_serial.count; i++) |
| 1710 | | vc1541_clock_write(device->machine, cbm_serial.drives[i], cbm_serial.clock[0]); |
| 1711 | | } |
| 1712 | | |
| 1713 | | static WRITE8_DEVICE_HANDLER( sim_drive_data_write ) |
| 1714 | | { |
| 1715 | | int i; |
| 1716 | | |
| 1717 | | cbm_serial.data[0] = |
| 1718 | | cbm_serial.data[1] = data; |
| 1719 | | /* update line */ |
| 1720 | | for (i = 0; i < cbm_serial.count; i++) |
| 1721 | | cbm_serial.data[0] &= cbm_serial.data[i + 2]; |
| 1722 | | /* inform drives */ |
| 1723 | | for (i = 0; i < cbm_serial.count; i++) |
| 1724 | | vc1541_data_write(device->machine, cbm_serial.drives[i], cbm_serial.data[0]); |
| 1725 | | } |
| 1726 | | |
| 1727 | | static WRITE8_DEVICE_HANDLER( sim_drive_request_write ) |
| 1728 | | { |
| 1729 | | } |
| 1730 | | |
| 1731 | | static WRITE8_DEVICE_HANDLER( sim_drive_reset_write ) |
| 1732 | | { |
| 1733 | | int i; |
| 1734 | | |
| 1735 | | for (i = 0; i < cbm_serial.count; i++) |
| 1736 | | drive_reset_write(cbm_serial.drives[i], data); |
| 1737 | | /* init bus signals */ |
| 1738 | | } |
| 1739 | | |
| 1740 | | static const cbm_serial_bus_interface cbm_sim_drive_interface = |
| 1741 | | { |
| 1742 | | DEVCB_HANDLER(sim_drive_atn_read), |
| 1743 | | DEVCB_HANDLER(sim_drive_clock_read), |
| 1744 | | DEVCB_HANDLER(sim_drive_data_read), |
| 1745 | | DEVCB_HANDLER(sim_drive_request_read), |
| 1746 | | DEVCB_HANDLER(sim_drive_atn_write), |
| 1747 | | DEVCB_HANDLER(sim_drive_clock_write), |
| 1748 | | DEVCB_HANDLER(sim_drive_data_write), |
| 1749 | | DEVCB_HANDLER(sim_drive_request_write), |
| 1750 | | |
| 1751 | | DEVCB_HANDLER(sim_drive_reset_write) |
| 1752 | | }; |
| 1753 | | |
| 1754 | | |
| 1755 | | MACHINE_DRIVER_START( simulated_drive ) |
| 1756 | | MDRV_CBM_SERBUS_ADD("serial_bus", cbm_sim_drive_interface) |
| 1757 | | MACHINE_DRIVER_END |
| 1758 | | |
| 1759 | | |
| 1760 | | |
| 1761 | | /*********************************************** |
| 1762 | | |
| 1763 | | Drive handling |
| 1764 | | |
| 1765 | | ***********************************************/ |
| 1766 | | |
| 1767 | | CBM_Drive cbm_drive[2]; |
| 1768 | | |
| 1769 | | CBM_Serial cbm_serial; |
| 1770 | | |
| 1771 | | /* must be called before other functions */ |
| 1772 | | static void cbm_drive_open( void ) |
| 1773 | | { |
| 1774 | | int i; |
| 1775 | | |
| 1776 | | memset(cbm_drive, 0, sizeof(cbm_drive)); |
| 1777 | | memset(&cbm_serial, 0, sizeof(cbm_serial)); |
| 1778 | | |
| 1779 | | cbm_drive_open_helper(); |
| 1780 | | |
| 1781 | | cbm_serial.count = 0; |
| 1782 | | for (i = 0; i < ARRAY_LENGTH(cbm_serial.atn); i++) |
| 1783 | | |
| 1784 | | { |
| 1785 | | cbm_serial.atn[i] = |
| 1786 | | cbm_serial.data[i] = |
| 1787 | | cbm_serial.clock[i] = 1; |
| 1788 | | } |
| 1789 | | } |
| 1790 | | |
| 1791 | | static void cbm_drive_close( void ) |
| 1792 | | { |
| 1793 | | int i; |
| 1794 | | |
| 1795 | | cbm_serial.count = 0; |
| 1796 | | for (i = 0; i < ARRAY_LENGTH(cbm_drive); i++) |
| 1797 | | { |
| 1798 | | cbm_drive[i].interface = 0; |
| 1799 | | |
| 1800 | | if( cbm_drive[i].buffer ) |
| 1801 | | { |
| 1802 | | free(cbm_drive[i].buffer); |
| 1803 | | cbm_drive[i].buffer = NULL; |
| 1804 | | } |
| 1805 | | |
| 1806 | | if (cbm_drive[i].drive == D64_IMAGE) |
| 1807 | | cbm_drive[i].image = NULL; |
| 1808 | | cbm_drive[i].drive = 0; |
| 1809 | | } |
| 1810 | | } |
| 1811 | | |
| 1812 | | |
| 1813 | | |
| 1814 | | static void cbm_drive_config( CBM_Drive * drive, int interface, int serialnr ) |
| 1815 | | { |
| 1816 | | int i; |
| 1817 | | |
| 1818 | | if (interface == SERIAL) |
| 1819 | | drive->i.serial.device = serialnr; |
| 1820 | | |
| 1821 | | if (interface == IEEE) |
| 1822 | | drive->i.ieee.device = serialnr; |
| 1823 | | |
| 1824 | | if (drive->interface == interface) |
| 1825 | | return; |
| 1826 | | |
| 1827 | | if (drive->interface == SERIAL) |
| 1828 | | { |
| 1829 | | for (i = 0; (i < cbm_serial.count) && (cbm_serial.drives[i] != drive); i++); |
| 1830 | | for (; i + 1 < cbm_serial.count; i++) |
| 1831 | | cbm_serial.drives[i] = cbm_serial.drives[i + 1]; |
| 1832 | | cbm_serial.count--; |
| 1833 | | } |
| 1834 | | |
| 1835 | | drive->interface = interface; |
| 1836 | | |
| 1837 | | if (drive->interface == IEC) |
| 1838 | | { |
| 1839 | | drive->i.iec.handshakein = |
| 1840 | | drive->i.iec.handshakeout = 0; |
| 1841 | | drive->i.iec.status = 0; |
| 1842 | | drive->i.iec.dataout = drive->i.iec.datain = 0xff; |
| 1843 | | drive->i.iec.state = 0; |
| 1844 | | } |
| 1845 | | else if (drive->interface == SERIAL) |
| 1846 | | { |
| 1847 | | cbm_serial.drives[cbm_serial.count++] = drive; |
| 1848 | | drive_reset_write(drive, 0); |
| 1849 | | } |
| 1850 | | } |
| 1851 | | |
| 1852 | | void cbm_drive_0_config( int interface, int serialnr ) |
| 1853 | | { |
| 1854 | | cbm_drive_config(cbm_drive, interface, serialnr); |
| 1855 | | } |
| 1856 | | |
| 1857 | | void cbm_drive_1_config( int interface, int serialnr ) |
| 1858 | | { |
| 1859 | | cbm_drive_config(cbm_drive + 1, interface, serialnr); |
| 1860 | | } |
| 1861 | | |
| 1862 | | |
| 1863 | | /************************************** |
| 1864 | | |
| 1865 | | Floppy device configurations |
| 1866 | | |
| 1867 | | **************************************/ |
| 1868 | | |
| 1869 | | |
| 1870 | | static DEVICE_START( cbm_drive ) |
| 1871 | | { |
| 1872 | | int id = image_index_in_device(device); |
| 1873 | | if (id == 0) |
| 1874 | | cbm_drive_open(); /* boy these C64 drivers are butt ugly */ |
| 1875 | | } |
| 1876 | | |
| 1877 | | static DEVICE_STOP( cbm_drive ) |
| 1878 | | { |
| 1879 | | int id = image_index_in_device(device); |
| 1880 | | if (id == 0) |
| 1881 | | cbm_drive_close(); /* boy these C64 drivers are butt ugly */ |
| 1882 | | } |
| 1883 | | |
| 1884 | | |
| 1885 | | |
| 1886 | | /* open an d64 image */ |
| 1887 | | static DEVICE_IMAGE_LOAD( cbm_drive ) |
| 1888 | | { |
| 1889 | | int id = image_index_in_device(image); |
| 1890 | | |
| 1891 | | cbm_drive[id].drive = 0; |
| 1892 | | cbm_drive[id].image = NULL; |
| 1893 | | |
| 1894 | | cbm_drive[id].image = image_ptr(image); |
| 1895 | | if (!cbm_drive[id].image) |
| 1896 | | return INIT_FAIL; |
| 1897 | | |
| 1898 | | cbm_drive[id].drive = D64_IMAGE; |
| 1899 | | return 0; |
| 1900 | | } |
| 1901 | | |
| 1902 | | static DEVICE_IMAGE_UNLOAD( cbm_drive ) |
| 1903 | | { |
| 1904 | | int id = image_index_in_device(image); |
| 1905 | | |
| 1906 | | cbm_drive[id].drive = 0; |
| 1907 | | cbm_drive[id].image = NULL; |
| 1908 | | } |
| 1909 | | |
| 1910 | | |
| 1911 | | void cbmfloppy_device_getinfo(const mess_device_class *devclass, UINT32 state, union devinfo *info) |
| 1912 | | { |
| 1913 | | switch(state) |
| 1914 | | { |
| 1915 | | /* --- the following bits of info are returned as 64-bit signed integers --- */ |
| 1916 | | case MESS_DEVINFO_INT_TYPE: info->i = IO_FLOPPY; break; |
| 1917 | | case MESS_DEVINFO_INT_READABLE: info->i = 1; break; |
| 1918 | | case MESS_DEVINFO_INT_WRITEABLE: info->i = 0; break; |
| 1919 | | case MESS_DEVINFO_INT_CREATABLE: info->i = 0; break; |
| 1920 | | case MESS_DEVINFO_INT_COUNT: info->i = 2; break; |
| 1921 | | |
| 1922 | | /* --- the following bits of info are returned as pointers to data or functions --- */ |
| 1923 | | case MESS_DEVINFO_PTR_START: info->start = DEVICE_START_NAME(cbm_drive); break; |
| 1924 | | case MESS_DEVINFO_PTR_STOP: info->stop = DEVICE_STOP_NAME(cbm_drive); break; |
| 1925 | | case MESS_DEVINFO_PTR_LOAD: info->load = DEVICE_IMAGE_LOAD_NAME(cbm_drive); break; |
| 1926 | | case MESS_DEVINFO_PTR_UNLOAD: info->unload = DEVICE_IMAGE_UNLOAD_NAME(cbm_drive); break; |
| 1927 | | |
| 1928 | | /* --- the following bits of info are returned as NULL-terminated strings --- */ |
| 1929 | | case MESS_DEVINFO_STR_FILE_EXTENSIONS: strcpy(info->s = device_temp_str(), "d64"); break; |
| 1930 | | } |
| 1931 | | } |
src/mess/drivers/pet.c
| r6732 | r6733 | |
| 393 | 393 | |
| 394 | 394 | /* devices config */ |
| 395 | 395 | #include "includes/cbm.h" |
| 396 | | #include "includes/cbmdrive.h" |
| 397 | 396 | #include "includes/cbmieeeb.h" |
| 398 | 397 | |
| 399 | 398 | /************************************* |
| r6732 | r6733 | |
| 1120 | 1119 | ROM_LOAD("skand.gen.ub3", 0x0000, 0x1000, CRC(da1cd630) SHA1(35f472114ff001259bdbae073ae041b0759e32cb) ) // Actual label was "901640-01 SKAND.GEN." |
| 1121 | 1120 | ROM_END |
| 1122 | 1121 | |
| 1123 | | |
| 1124 | | |
| 1125 | | |
| 1126 | | /************************************* |
| 1127 | | * |
| 1128 | | * System configuration(s) |
| 1129 | | * |
| 1130 | | *************************************/ |
| 1131 | | |
| 1132 | | static SYSTEM_CONFIG_START( pet ) |
| 1133 | | CONFIG_DEVICE(cbmfloppy_device_getinfo) |
| 1134 | | SYSTEM_CONFIG_END |
| 1135 | | |
| 1136 | 1122 | /*************************************************************************** |
| 1137 | 1123 | |
| 1138 | 1124 | Game driver(s) |
| r6732 | r6733 | |
| 1141 | 1127 | |
| 1142 | 1128 | /* YEAR NAME PARENT COMPAT MACHINE INPUT INIT CONFIG COMPANY FULLNAME */ |
| 1143 | 1129 | |
| 1144 | | COMP(1977, pet2001, 0, 0, pet2001, pet, pet2001, pet, "Commodore Business Machines Co.", "PET 2001", GAME_NO_SOUND) |
| 1145 | | COMP(1979, pet2001n, pet2001, 0, pet, pet, pet, pet, "Commodore Business Machines Co.", "PET 2001-N", GAME_NO_SOUND) |
| 1146 | | COMP(1979, pet2001b, pet2001, 0, petb, petb, pet, pet, "Commodore Business Machines Co.", "PET 2001-B", GAME_NO_SOUND) |
| 1147 | | COMP(1979, cbm30, pet2001, 0, pet, pet, pet, pet, "Commodore Business Machines Co.", "CBM 30xx", GAME_NO_SOUND) |
| 1148 | | COMP(1979, cbm30b, pet2001, 0, petb, petb, pet, pet, "Commodore Business Machines Co.", "CBM 30xx (Business keyboard)", GAME_NO_SOUND) |
| 1149 | | COMP(1979, cbm30nor, pet2001, 0, petb, petb, pet, pet, "Commodore Business Machines Co.", "CBM 30xx (Norway, Business keyboard)", GAME_NO_SOUND) |
| 1130 | COMP(1977, pet2001, 0, 0, pet2001, pet, pet2001, 0, "Commodore Business Machines Co.", "PET 2001", GAME_NO_SOUND) |
| 1131 | COMP(1979, pet2001n, pet2001, 0, pet, pet, pet, 0, "Commodore Business Machines Co.", "PET 2001-N", GAME_NO_SOUND) |
| 1132 | COMP(1979, pet2001b, pet2001, 0, petb, petb, pet, 0, "Commodore Business Machines Co.", "PET 2001-B", GAME_NO_SOUND) |
| 1133 | COMP(1979, cbm30, pet2001, 0, pet, pet, pet, 0, "Commodore Business Machines Co.", "CBM 30xx", GAME_NO_SOUND) |
| 1134 | COMP(1979, cbm30b, pet2001, 0, petb, petb, pet, 0, "Commodore Business Machines Co.", "CBM 30xx (Business keyboard)", GAME_NO_SOUND) |
| 1135 | COMP(1979, cbm30nor, pet2001, 0, petb, petb, pet, 0, "Commodore Business Machines Co.", "CBM 30xx (Norway, Business keyboard)", GAME_NO_SOUND) |
| 1150 | 1136 | |
| 1151 | 1137 | /* So called, THIN-40 */ |
| 1152 | | COMP(1980, pet40on, pet2001, 0, pet, pet, pet, pet, "Commodore Business Machines Co.", "PET 40xx (Basic 4, no CRTC, Normal keyboard)", GAME_NO_SOUND) |
| 1153 | | COMP(1980, pet40ob, pet2001, 0, petb, petb, pet, pet, "Commodore Business Machines Co.", "PET 40xx (Basic 4, no CRTC, Business keyboard)", GAME_NO_SOUND) |
| 1154 | | COMP(1980, cbm40o, pet2001, 0, pet, pet, pet, pet, "Commodore Business Machines Co.", "CBM 40xx (Basic 4, no CRTC, Normal keyboard)", GAME_NO_SOUND) |
| 1155 | | COMP(1980, cbm40ob, pet2001, 0, petb, petb, pet, pet, "Commodore Business Machines Co.", "CBM 40xx (Basic 4, no CRTC, Business keyboard)", GAME_NO_SOUND) |
| 1138 | COMP(1980, pet40on, pet2001, 0, pet, pet, pet, 0, "Commodore Business Machines Co.", "PET 40xx (Basic 4, no CRTC, Normal keyboard)", GAME_NO_SOUND) |
| 1139 | COMP(1980, pet40ob, pet2001, 0, petb, petb, pet, 0, "Commodore Business Machines Co.", "PET 40xx (Basic 4, no CRTC, Business keyboard)", GAME_NO_SOUND) |
| 1140 | COMP(1980, cbm40o, pet2001, 0, pet, pet, pet, 0, "Commodore Business Machines Co.", "CBM 40xx (Basic 4, no CRTC, Normal keyboard)", GAME_NO_SOUND) |
| 1141 | COMP(1980, cbm40ob, pet2001, 0, petb, petb, pet, 0, "Commodore Business Machines Co.", "CBM 40xx (Basic 4, no CRTC, Business keyboard)", GAME_NO_SOUND) |
| 1156 | 1142 | |
| 1157 | | COMP(1981, pet80, 0, 0, pet80, cbm8096, pet80, pet, "Commodore Business Machines Co.", "PET 80xx (Basic 4, CRTC 60Hz, 80 columns)", GAME_NO_SOUND) |
| 1158 | | COMP(1981, cbm80, pet80, 0, pet80pal, cbm8096, pet80, pet, "Commodore Business Machines Co.", "CBM 80xx (Basic 4, CRTC 50Hz, 80 columns)", GAME_NO_SOUND) |
| 1159 | | COMP(1981, cbm80ger, pet80, 0, pet80pal, cbm8096, pet80, pet, "Commodore Business Machines Co.", "CBM 80xx (Germany, Basic 4, CRTC 50Hz, 80 columns)", GAME_NO_SOUND) |
| 1160 | | COMP(1981, cbm80hun, pet80, 0, pet80pal, cbm8096, pet80, pet, "Commodore Business Machines Co.", "CBM 80xx (Hungary, Basic 4, CRTC 50Hz, 80 columns)", GAME_NO_SOUND) |
| 1161 | | COMP(1981, cbm80swe, pet80, 0, pet80pal, cbm8096, pet80, pet, "Commodore Business Machines Co.", "CBM 80xx (Sweden, Basic 4, CRTC 50Hz, 80 columns)", GAME_NO_SOUND) |
| 1143 | COMP(1981, pet80, 0, 0, pet80, cbm8096, pet80, 0, "Commodore Business Machines Co.", "PET 80xx (Basic 4, CRTC 60Hz, 80 columns)", GAME_NO_SOUND) |
| 1144 | COMP(1981, cbm80, pet80, 0, pet80pal, cbm8096, pet80, 0, "Commodore Business Machines Co.", "CBM 80xx (Basic 4, CRTC 50Hz, 80 columns)", GAME_NO_SOUND) |
| 1145 | COMP(1981, cbm80ger, pet80, 0, pet80pal, cbm8096, pet80, 0, "Commodore Business Machines Co.", "CBM 80xx (Germany, Basic 4, CRTC 50Hz, 80 columns)", GAME_NO_SOUND) |
| 1146 | COMP(1981, cbm80hun, pet80, 0, pet80pal, cbm8096, pet80, 0, "Commodore Business Machines Co.", "CBM 80xx (Hungary, Basic 4, CRTC 50Hz, 80 columns)", GAME_NO_SOUND) |
| 1147 | COMP(1981, cbm80swe, pet80, 0, pet80pal, cbm8096, pet80, 0, "Commodore Business Machines Co.", "CBM 80xx (Sweden, Basic 4, CRTC 50Hz, 80 columns)", GAME_NO_SOUND) |
| 1162 | 1148 | |
| 1163 | 1149 | /* So called, FAT-40 */ |
| 1164 | | COMP(1981, pet40b, pet80, 0, pet80, cbm8096, pet80, pet, "Commodore Business Machines Co.", "PET 40xx (Basic 4, CRTC 60Hz, 80 columns)", GAME_NO_SOUND) |
| 1165 | | COMP(1981, pet40n, pet2001, 0, pet40, pet, pet, pet, "Commodore Business Machines Co.", "PET 40xx (Basic 4, CRTC 60Hz, 40 columns)", GAME_NO_SOUND) |
| 1166 | | COMP(1981, cbm40b, pet80, 0, pet80pal, cbm8096, pet80, pet, "Commodore Business Machines Co.", "CBM 40xx (Basic 4, CRTC 50Hz, 80 columns)", GAME_NO_SOUND) |
| 1167 | | COMP(1981, cbm40n, pet2001, 0, pet40pal, pet, pet, pet, "Commodore Business Machines Co.", "CBM 40xx (Basic 4, CRTC 50Hz, 40 columns)", GAME_NO_SOUND) |
| 1150 | COMP(1981, pet40b, pet80, 0, pet80, cbm8096, pet80, 0, "Commodore Business Machines Co.", "PET 40xx (Basic 4, CRTC 60Hz, 80 columns)", GAME_NO_SOUND) |
| 1151 | COMP(1981, pet40n, pet2001, 0, pet40, pet, pet, 0, "Commodore Business Machines Co.", "PET 40xx (Basic 4, CRTC 60Hz, 40 columns)", GAME_NO_SOUND) |
| 1152 | COMP(1981, cbm40b, pet80, 0, pet80pal, cbm8096, pet80, 0, "Commodore Business Machines Co.", "CBM 40xx (Basic 4, CRTC 50Hz, 80 columns)", GAME_NO_SOUND) |
| 1153 | COMP(1981, cbm40n, pet2001, 0, pet40pal, pet, pet, 0, "Commodore Business Machines Co.", "CBM 40xx (Basic 4, CRTC 50Hz, 40 columns)", GAME_NO_SOUND) |
| 1168 | 1154 | |
| 1169 | | COMP(1981, superpet, 0, 0, superpet, superpet, superpet, pet, "Commodore Business Machines Co.", "SuperPET (CRTC 50Hz)", GAME_NO_SOUND | GAME_NOT_WORKING) |
| 1170 | | COMP(1981, sp9000, superpet, 0, superpet, superpet, superpet, pet, "Commodore Business Machines Co.", "CBM SP9000 / MicroMainFrame 9000 (CRTC 50Hz)", GAME_NO_SOUND | GAME_NOT_WORKING) |
| 1171 | | COMP(198?, mmf9000s, superpet, 0, superpet, superpet, superpet, pet, "Commodore Business Machines Co.", "MicroMainFrame 9000 (Sweden, CRTC 50Hz)", GAME_NO_SOUND | GAME_NOT_WORKING) |
| 1155 | COMP(1981, superpet, 0, 0, superpet, superpet, superpet, 0, "Commodore Business Machines Co.", "SuperPET (CRTC 50Hz)", GAME_NO_SOUND | GAME_NOT_WORKING) |
| 1156 | COMP(1981, sp9000, superpet, 0, superpet, superpet, superpet, 0, "Commodore Business Machines Co.", "CBM SP9000 / MicroMainFrame 9000 (CRTC 50Hz)", GAME_NO_SOUND | GAME_NOT_WORKING) |
| 1157 | COMP(198?, mmf9000s, superpet, 0, superpet, superpet, superpet, 0, "Commodore Business Machines Co.", "MicroMainFrame 9000 (Sweden, CRTC 50Hz)", GAME_NO_SOUND | GAME_NOT_WORKING) |
| 1172 | 1158 | |
| 1173 | | COMP(1984, cbm8296, pet80, 0, pet80pal, cbm8096, pet80, pet, "Commodore Business Machines Co.", "CBM 8296 (Basic 4, CRTC 50Hz, 80 columns)", GAME_NO_SOUND) |
| 1174 | | COMP(1984, cbm8296d, pet80, 0, pet80pal, cbm8096, pet80, pet, "Commodore Business Machines Co.", "CBM 8296D", GAME_NO_SOUND) |
| 1159 | COMP(1984, cbm8296, pet80, 0, pet80pal, cbm8096, pet80, 0, "Commodore Business Machines Co.", "CBM 8296 (Basic 4, CRTC 50Hz, 80 columns)", GAME_NO_SOUND) |
| 1160 | COMP(1984, cbm8296d, pet80, 0, pet80pal, cbm8096, pet80, 0, "Commodore Business Machines Co.", "CBM 8296D", GAME_NO_SOUND) |