src/emu/imagedev/cassette.c
| r14940 | r14941 | |
| 104 | 104 | |
| 105 | 105 | if (is_motor_on()) |
| 106 | 106 | { |
| 107 | | double new_position = m_position + (cur_time - m_position_time); |
| 107 | double new_position = m_position + (cur_time - m_position_time)*m_speed*m_direction; |
| 108 | 108 | |
| 109 | 109 | switch(m_state & CASSETTE_MASK_UISTATE) { |
| 110 | 110 | case CASSETTE_RECORD: |
| 111 | | cassette_put_sample(m_cassette, 0, m_position, new_position - m_position, m_value); |
| 111 | cassette_put_sample(m_cassette, m_channel, m_position, new_position - m_position, m_value); |
| 112 | 112 | break; |
| 113 | 113 | |
| 114 | 114 | case CASSETTE_PLAY: |
| 115 | 115 | if ( m_cassette ) |
| 116 | 116 | { |
| 117 | | cassette_get_sample(m_cassette, 0, new_position, 0.0, &m_value); |
| 117 | cassette_get_sample(m_cassette, m_channel, new_position, 0.0, &m_value); |
| 118 | 118 | /* See if reached end of tape */ |
| 119 | 119 | double length = get_length(); |
| 120 | 120 | if (new_position > length) |
| r14940 | r14941 | |
| 122 | 122 | m_state = (cassette_state)(( m_state & ~CASSETTE_MASK_UISTATE ) | CASSETTE_STOPPED); |
| 123 | 123 | new_position = length; |
| 124 | 124 | } |
| 125 | else if (new_position < 0) |
| 126 | { |
| 127 | m_state = (cassette_state)(( m_state & ~CASSETTE_MASK_UISTATE ) | CASSETTE_STOPPED); |
| 128 | new_position = 0; |
| 129 | } |
| 125 | 130 | } |
| 126 | 131 | break; |
| 127 | 132 | } |
| r14940 | r14941 | |
| 182 | 187 | double position = m_position; |
| 183 | 188 | |
| 184 | 189 | if (is_motor_on()) |
| 185 | | position += device().machine().time().as_double() - m_position_time; |
| 190 | position += (device().machine().time().as_double() - m_position_time)*m_speed*m_direction; |
| 186 | 191 | return position; |
| 187 | 192 | } |
| 188 | 193 | |
| r14940 | r14941 | |
| 196 | 201 | return ((double) info.sample_count) / info.sample_frequency; |
| 197 | 202 | } |
| 198 | 203 | |
| 204 | void cassette_image_device::set_channel(int channel) |
| 205 | { |
| 206 | m_channel = channel; |
| 207 | } |
| 199 | 208 | |
| 209 | void cassette_image_device::set_speed(double speed) |
| 210 | { |
| 211 | m_speed = speed; |
| 212 | } |
| 200 | 213 | |
| 214 | void cassette_image_device::go_forward() |
| 215 | { |
| 216 | m_direction = 1; |
| 217 | } |
| 218 | |
| 219 | void cassette_image_device::go_reverse() |
| 220 | { |
| 221 | m_direction = -1; |
| 222 | } |
| 223 | |
| 224 | |
| 201 | 225 | void cassette_image_device::seek(double time, int origin) |
| 202 | 226 | { |
| 203 | 227 | double length; |
| r14940 | r14941 | |
| 300 | 324 | /* reset the position */ |
| 301 | 325 | m_position = 0.0; |
| 302 | 326 | m_position_time = device().machine().time().as_double(); |
| 327 | |
| 328 | /* default channel to 0, speed multiplier to 1 */ |
| 329 | m_channel = 0; |
| 330 | m_speed = 1; |
| 331 | m_direction = 1; |
| 303 | 332 | |
| 304 | 333 | return IMAGE_INIT_PASS; |
| 305 | 334 | |
src/lib/formats/adam_cas.c
| r0 | r14941 | |
| 1 | |
| 2 | #include "cassimg.h"
|
| 3 | #include "adam_cas.h"
|
| 4 | |
| 5 | // This code will reproduce the timing of an adam tape played back on a standard tape deck with a 1 7/8ips speed.
|
| 6 | #define CASS_AMP 0x1fffffff
|
| 7 | #define SPEED_MULTIPLIER 20.0/1.875
|
| 8 | #define COL_ADAM_PERIOD 0.00007*SPEED_MULTIPLIER
|
| 9 | #define COL_ADAM_PERIOD1 0.000031*SPEED_MULTIPLIER
|
| 10 | #define COL_ADAM_PERIOD2 0.000039*SPEED_MULTIPLIER
|
| 11 | #define TYPE_HE 0
|
| 12 | #define TYPE_GW 1
|
| 13 | |
| 14 | /***************************************************************
|
| 15 | Coleco Adam Digital Data Pack format:
|
| 16 | The packs are the same shape as a standard audio cassette, but with different alignment and capstan holes
|
| 17 | The tape only has one side and has two widely separated mono data tracks (second track readable on an audio
|
| 18 | cassette deck by flipping the tape over and reversing the recorded signal).
|
| 19 | |
| 20 | Header format:
|
| 21 | 2 byte header id: 0x48 0x45 (central directory HE type) or 0x47 0x57 (GW type)
|
| 22 | 2 byte block number
|
| 23 | 2 byte NOT block number
|
| 24 | 1 byte number of blocks (0x80)
|
| 25 | 1 byte sum of the above (checksum)
|
| 26 | |
| 27 | |
| 28 | track format:
|
| 29 | leading zeros: ~2753
|
| 30 | |
| 31 | block format:
|
| 32 | sync byte 0x16
|
| 33 | header
|
| 34 | pad zero bytes ~21
|
| 35 | sync byte 0x16
|
| 36 | data(1k)
|
| 37 | pad zero bytes ~21
|
| 38 | sync byte 0x16
|
| 39 | 2 byte checksum-16
|
| 40 | pad zero bytes ~2
|
| 41 | sync bytes 0xaa ~922
|
| 42 | pad zero bytes ~2
|
| 43 | |
| 44 | Data is phase encoded, with 70us bit cells with a transition at 31us for a 1 and no transition for a 0
|
| 45 | |
| 46 | ****************************************************************/
|
| 47 | |
| 48 | |
| 49 | static casserr_t coladam_ddp_identify ( cassette_image *cass, struct CassetteOptions *opts )
|
| 50 | {
|
| 51 | opts -> bits_per_sample = 16;
|
| 52 | opts -> channels = 2;
|
| 53 | opts -> sample_frequency = 44100;
|
| 54 | return CASSETTE_ERROR_SUCCESS;
|
| 55 | }
|
| 56 | |
| 57 | |
| 58 | // Store byte of data
|
| 59 | casserr_t coladam_put_byte(cassette_image *cass, int channel, double *time_index, int byte, int *prev_sign)
|
| 60 | {
|
| 61 | casserr_t err;
|
| 62 | for (int i = 0; i < 8; i++)
|
| 63 | {
|
| 64 | if(byte & 0x80)
|
| 65 | {
|
| 66 | err = cassette_put_sample( cass, channel, *time_index, COL_ADAM_PERIOD1, -CASS_AMP*(*prev_sign) );
|
| 67 | (*time_index) += COL_ADAM_PERIOD1;
|
| 68 | err = cassette_put_sample( cass, channel, *time_index, COL_ADAM_PERIOD2, CASS_AMP*(*prev_sign) );
|
| 69 | (*time_index) += COL_ADAM_PERIOD2;
|
| 70 | }
|
| 71 | else
|
| 72 | {
|
| 73 | err = cassette_put_sample( cass, channel, *time_index, COL_ADAM_PERIOD, -CASS_AMP*(*prev_sign) );
|
| 74 | (*prev_sign) *=-1;
|
| 75 | (*time_index) += COL_ADAM_PERIOD;
|
| 76 | }
|
| 77 | byte <<= 1;
|
| 78 | }
|
| 79 | return err;
|
| 80 | }
|
| 81 | |
| 82 | casserr_t coladam_put_block(cassette_image *cass, int channel, double *time_index, int *prev_sign, int block_index, UINT8 *buffer, int layout_type)
|
| 83 | {
|
| 84 | int i, checksum_16=0;
|
| 85 | UINT8 header[] = { 0x16, 0x48, 0x45, 0x00, block_index, 0xff, (0xff - block_index), 0x00, 0x80, 0xf4 };
|
| 86 | casserr_t err;
|
| 87 | if (layout_type == TYPE_GW)
|
| 88 | {
|
| 89 | header[1] = 0x47;
|
| 90 | header[2] = 0x57;
|
| 91 | header[9] = 0xe3;
|
| 92 | }
|
| 93 | |
| 94 | for (i = 0; i < 10; i++) // header
|
| 95 | {
|
| 96 | err = coladam_put_byte(cass, channel, time_index, header[i], prev_sign);
|
| 97 | }
|
| 98 | for (i = 0; i < 21; i++) // leading zero bytes
|
| 99 | {
|
| 100 | err = coladam_put_byte(cass, channel, time_index, 0x00, prev_sign);
|
| 101 | }
|
| 102 | err = coladam_put_byte(cass, channel, time_index, 0x16, prev_sign); // data start
|
| 103 | for ( i = 0; i < 0x400; i++ )
|
| 104 | {
|
| 105 | err = coladam_put_byte(cass, channel, time_index, buffer[i], prev_sign);
|
| 106 | checksum_16 += buffer[i];
|
| 107 | }
|
| 108 | for (i = 0; i < 21; i++) // trailing padding zeros
|
| 109 | {
|
| 110 | err = coladam_put_byte(cass, channel, time_index, 0x00, prev_sign);
|
| 111 | }
|
| 112 | err = coladam_put_byte(cass, channel, time_index, 0x16, prev_sign);
|
| 113 | err = coladam_put_byte(cass, channel, time_index, (checksum_16 & 0xff00) >> 8, prev_sign); // write checksum
|
| 114 | err = coladam_put_byte(cass, channel, time_index, (checksum_16 & 0xff), prev_sign);
|
| 115 | for (i = 0; i < 922; i++) // sync bytes
|
| 116 | {
|
| 117 | err = coladam_put_byte(cass, channel, time_index, 0xaa, prev_sign);
|
| 118 | }
|
| 119 | err = coladam_put_byte(cass, channel, time_index, 0x00, prev_sign);
|
| 120 | err = coladam_put_byte(cass, channel, time_index, 0x00, prev_sign);
|
| 121 | return err;
|
| 122 | }
|
| 123 |
|
| 124 | |
| 125 | static casserr_t coladam_ddp_load( cassette_image *cass )
|
| 126 | {
|
| 127 | double time = 0.;
|
| 128 | int i, block, prev_sign=-1;
|
| 129 | UINT8 buffer[0x400];
|
| 130 | casserr_t err;
|
| 131 | |
| 132 | // It would appear that data packs that originally had the type GW data layout and headers work fine when converted to type
|
| 133 | // HE. Thus we set all tapes to type HE.
|
| 134 |
|
| 135 | int layout_type = TYPE_HE;
|
| 136 |
|
| 137 | // Track 0
|
| 138 | for ( i = 0; i < 2753; i++ ) // leading zero bytes
|
| 139 | {
|
| 140 | err = coladam_put_byte(cass, 0, &time, 0x00, &prev_sign);
|
| 141 | }
|
| 142 | |
| 143 | for (block = 0; block < 128; block++)
|
| 144 | {
|
| 145 | cassette_image_read( cass, buffer, 0x20000+0x400*block, 0x400 );
|
| 146 | err = coladam_put_block(cass, 0, &time, &prev_sign, block, buffer, layout_type);
|
| 147 | }
|
| 148 | for (block = 128; block < 131; block++)
|
| 149 | {
|
| 150 | cassette_image_read( cass, buffer, 0x3f400+0x400*(block-128), 0x400 );
|
| 151 | err = coladam_put_block(cass, 0, &time, &prev_sign, block, buffer, layout_type);
|
| 152 | }
|
| 153 | |
| 154 | // Track 1
|
| 155 | time = 0.;
|
| 156 | for ( i = 0; i < 2753; i++ ) // leading zero bytes
|
| 157 | {
|
| 158 | err = coladam_put_byte(cass, 1, &time, 0x00, &prev_sign);
|
| 159 | }
|
| 160 | if (layout_type == TYPE_HE)
|
| 161 | {
|
| 162 | for (block = 0; block < 64; block++)
|
| 163 | {
|
| 164 | cassette_image_read( cass, buffer, 0x10000+0x400*block, 0x400 );
|
| 165 | err = coladam_put_block(cass, 1, &time, &prev_sign, block, buffer, layout_type);
|
| 166 | }
|
| 167 | for (block = 64; block < 128; block++)
|
| 168 | {
|
| 169 | cassette_image_read( cass, buffer, 0x00000+0x400*(block-64), 0x400 );
|
| 170 | err = coladam_put_block(cass, 1, &time, &prev_sign, block, buffer, layout_type);
|
| 171 | }
|
| 172 | for (block = 128; block < 131; block++)
|
| 173 | {
|
| 174 | cassette_image_read( cass, buffer, 0x0f400+0x400*(block-128), 0x400 );
|
| 175 | err = coladam_put_block(cass, 1, &time, &prev_sign, block, buffer, layout_type);
|
| 176 | }
|
| 177 | }
|
| 178 | else
|
| 179 | {
|
| 180 | time = 0;
|
| 181 | for ( i = 0; i < 2753; i++ ) // leading zero bytes
|
| 182 | {
|
| 183 | err = coladam_put_byte(cass, 1, &time, 0x00, &prev_sign);
|
| 184 | }
|
| 185 | for (block = 0; block < 128; block++)
|
| 186 | {
|
| 187 | cassette_image_read( cass, buffer, 0x400*block, 0x400 );
|
| 188 | err = coladam_put_block(cass, 1, &time, &prev_sign, block, buffer, layout_type);
|
| 189 | }
|
| 190 | for (block = 128; block < 131; block++)
|
| 191 | {
|
| 192 | cassette_image_read( cass, buffer, 0x1f400+0x400*(block-128), 0x400 );
|
| 193 | err = coladam_put_block(cass, 1, &time, &prev_sign, block, buffer, layout_type);
|
| 194 | }
|
| 195 | }
|
| 196 |
|
| 197 | if (err)
|
| 198 | return err;
|
| 199 |
|
| 200 | return CASSETTE_ERROR_SUCCESS;
|
| 201 | }
|
| 202 | |
| 203 | |
| 204 | |
| 205 | static const struct CassetteFormat coladam_ddp =
|
| 206 | { "ddp", coladam_ddp_identify, coladam_ddp_load, NULL /* no save */ };
|
| 207 | |
| 208 | CASSETTE_FORMATLIST_START(coleco_adam_cassette_formats)
|
| 209 | CASSETTE_FORMAT(coladam_ddp)
|
| 210 | CASSETTE_FORMATLIST_END
|
src/mess/drivers/adam.c
| r14940 | r14941 | |
| 193 | 193 | #include "cpu/z80/z80.h" |
| 194 | 194 | #include "cpu/m6800/m6800.h" |
| 195 | 195 | #include "formats/basicdsk.h" |
| 196 | #include "formats/adam_cas.h" |
| 196 | 197 | #include "imagedev/cartslot.h" |
| 197 | 198 | #include "imagedev/cassette.h" |
| 198 | 199 | #include "imagedev/flopdrv.h" |
| r14940 | r14941 | |
| 762 | 763 | |
| 763 | 764 | */ |
| 764 | 765 | |
| 765 | | // speed select |
| 766 | | // cassette_set_speed(m_ddp0, BIT(data, 0) ? 80 : 20); |
| 767 | | // cassette_set_speed(m_ddp1, BIT(data, 0) ? 80 : 20); |
| 766 | if(m_ddp0->exists()) |
| 767 | { |
| 768 | m_ddp0->set_speed(BIT(data, 0) ? (double) 80/1.875 : 20/1.875); // speed select |
| 769 | if(!(data & 0x08)) m_ddp0->go_forward(); |
| 770 | if(!(data & 0x10)) m_ddp0->go_reverse(); |
| 771 | m_ddp0->change_state(BIT(data, 1) ? CASSETTE_MOTOR_DISABLED : CASSETTE_MOTOR_ENABLED, CASSETTE_MASK_MOTOR); // motor control |
| 772 | } |
| 773 | |
| 774 | if(m_ddp1->exists()) |
| 775 | { |
| 776 | m_ddp1->set_speed(BIT(data, 0) ? (double) 80/1.875 : 20/1.875); // speed select |
| 777 | if(!(data & 0x08)) m_ddp1->go_forward(); |
| 778 | if(!(data & 0x10)) m_ddp1->go_reverse(); |
| 779 | m_ddp1->change_state(BIT(data, 2) ? CASSETTE_MOTOR_DISABLED : CASSETTE_MOTOR_ENABLED, CASSETTE_MASK_MOTOR); // motor control |
| 780 | } |
| 768 | 781 | |
| 769 | | // motor stop 0 |
| 770 | | m_ddp0->set_state(BIT(data, 1) ? CASSETTE_MOTOR_DISABLED : CASSETTE_MOTOR_ENABLED); |
| 771 | | |
| 772 | | // motor stop 1 |
| 773 | | m_ddp1->set_state(BIT(data, 2) ? CASSETTE_MOTOR_DISABLED : CASSETTE_MOTOR_ENABLED); |
| 774 | | |
| 775 | 782 | // data write 0 |
| 776 | 783 | m_wr0 = BIT(data, 6); |
| 777 | 784 | |
| r14940 | r14941 | |
| 797 | 804 | 4 |
| 798 | 805 | |
| 799 | 806 | */ |
| 807 | |
| 808 | UINT8 data = 0; |
| 809 | |
| 810 | if (m_reset) |
| 811 | data |= M6801_MODE_6; |
| 812 | else |
| 813 | data |= m_ddp1->exists() << 1; // Cassette in place 1 |
| 800 | 814 | |
| 801 | | UINT8 data = M6801_MODE_6; |
| 802 | | |
| 803 | | if (!m_reset) |
| 804 | | { |
| 805 | | // cassette in place 1 |
| 806 | | data &= ~0x01; |
| 807 | | //data |= dynamic_cast<device_image_interface *>(&m_ddp1)->exists() << 1; |
| 808 | | } |
| 809 | | |
| 810 | 815 | // NET RXD |
| 811 | 816 | data |= m_rxd << 3; |
| 812 | 817 | |
| r14940 | r14941 | |
| 832 | 837 | |
| 833 | 838 | */ |
| 834 | 839 | |
| 835 | | // track |
| 836 | | m_track = !BIT(data, 2); |
| 840 | if(m_ddp0->exists()) |
| 841 | { |
| 842 | m_ddp0->set_channel(!BIT(data, 2)); // Track select |
| 843 | if (!m_wr0) m_ddp0->output(BIT(data, 0) ? 1.0 : -1.0); // write data |
| 844 | } |
| 845 | |
| 846 | if(m_ddp1->exists()) |
| 847 | { |
| 848 | m_ddp1->set_channel(!BIT(data, 2)); |
| 849 | if (!m_wr1) m_ddp1->output(BIT(data, 0) ? 1.0 : -1.0); |
| 850 | } |
| 837 | 851 | |
| 838 | | // write data |
| 839 | | if (!m_wr0) m_ddp0->output(BIT(data, 0) ? 1.0 : -1.0); |
| 840 | | if (!m_wr1) m_ddp1->output(BIT(data, 0) ? 1.0 : -1.0); |
| 841 | | |
| 842 | 852 | // NET TXD |
| 843 | 853 | adamnet_txd_w(ADAMNET_DDP, BIT(data, 4)); |
| 844 | 854 | } |
| 845 | 855 | |
| 846 | | |
| 847 | 856 | //------------------------------------------------- |
| 848 | 857 | // ddp6801_p4_r - |
| 849 | 858 | //------------------------------------------------- |
| r14940 | r14941 | |
| 867 | 876 | |
| 868 | 877 | UINT8 data = 0; |
| 869 | 878 | |
| 870 | | // motion sense 0 |
| 871 | | data |= ((m_ddp0->get_state() & CASSETTE_MASK_UISTATE) != CASSETTE_STOPPED) << 3; |
| 872 | | |
| 873 | | // motion sense 1 |
| 874 | | data |= ((m_ddp1->get_state() & CASSETTE_MASK_UISTATE) != CASSETTE_STOPPED) << 4; |
| 875 | | |
| 876 | | // cassette in place 0 |
| 877 | | // data |= dynamic_cast<device_image_interface *>(&m_ddp0)->exists() << 5; |
| 878 | | |
| 879 | | // read data 0 |
| 879 | // drive 0 |
| 880 | if(m_ddp0->exists()) |
| 881 | { |
| 882 | data |= ((m_ddp0->get_state() & CASSETTE_MASK_UISTATE) != CASSETTE_STOPPED) << 3; // motion sense |
| 883 | data |= 1 << 5; // cassette in place |
| 884 | data |= (m_ddp0->input() < 0) << 7; // read data |
| 885 | } |
| 886 | |
| 887 | // drive 1 |
| 888 | if(m_ddp1->exists()) |
| 889 | { |
| 890 | data |= ((m_ddp1->get_state() & CASSETTE_MASK_UISTATE) != CASSETTE_STOPPED) << 4; // motion sense |
| 891 | data |= (m_ddp1->input() < 0) << 7; // read data |
| 892 | } |
| 893 | |
| 894 | // read data 0 (always 1) |
| 880 | 895 | data |= 0x40; |
| 881 | | |
| 882 | | // read data 1 |
| 883 | | data |= ((m_ddp0->input() < 0) || (m_ddp1->input() < 0)) << 7; |
| 884 | | |
| 896 | |
| 885 | 897 | return data; |
| 886 | 898 | } |
| 887 | 899 | |
| r14940 | r14941 | |
| 1514 | 1526 | // cassette_interface adam_cassette_interface |
| 1515 | 1527 | //------------------------------------------------- |
| 1516 | 1528 | |
| 1529 | static const struct CassetteOptions adam_cassette_options = |
| 1530 | { |
| 1531 | 2, /* channels */ |
| 1532 | 16, /* bits per sample */ |
| 1533 | 44100 /* sample frequency */ |
| 1534 | }; |
| 1535 | |
| 1517 | 1536 | static const cassette_interface adam_cassette_interface = |
| 1518 | 1537 | { |
| 1519 | | cassette_default_formats, |
| 1538 | coleco_adam_cassette_formats, |
| 1539 | &adam_cassette_options, |
| 1540 | (cassette_state)(CASSETTE_PLAY | CASSETTE_MOTOR_DISABLED | CASSETTE_SPEAKER_MUTED), |
| 1520 | 1541 | NULL, |
| 1521 | | (cassette_state)(CASSETTE_STOPPED | CASSETTE_MOTOR_ENABLED | CASSETTE_SPEAKER_MUTED), |
| 1522 | | NULL, |
| 1523 | 1542 | NULL |
| 1524 | 1543 | }; |
| 1525 | 1544 | |
| r14940 | r14941 | |
| 1681 | 1700 | MCFG_CPU_ADD(M6801_DDP_TAG, M6801, XTAL_4MHz) |
| 1682 | 1701 | MCFG_CPU_PROGRAM_MAP(ddp6801_mem) |
| 1683 | 1702 | MCFG_CPU_IO_MAP(ddp6801_io) |
| 1684 | | MCFG_DEVICE_DISABLE() |
| 1685 | 1703 | |
| 1686 | 1704 | MCFG_CPU_ADD(M6801_PRN_TAG, M6801, XTAL_4MHz) |
| 1687 | 1705 | MCFG_CPU_PROGRAM_MAP(printer6801_mem) |