Previous 15994 Revisions Next

r14941 Monday 16th April, 2012 at 12:26:53 UTC by Curt Coder
[ADAM] Improved the cassette emulation:
- added ddp tape image support
- edited cassette.c to allow speed / direction / channel selection
- changed cassimg.c so multichannel tapes work [huygens]
[src/emu/imagedev]cassette.c cassette.h
[src/lib]lib.mak
[src/lib/formats]adam_cas.c* adam_cas.h* cassimg.c
[src/mess/drivers]adam.c
[src/mess/tools/castool]main.c

src/emu/imagedev/cassette.c
r14940r14941
104104
105105   if (is_motor_on())
106106   {
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;
108108
109109      switch(m_state & CASSETTE_MASK_UISTATE) {
110110      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);
112112         break;
113113
114114      case CASSETTE_PLAY:
115115         if ( m_cassette )
116116         {
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);
118118            /* See if reached end of tape */
119119            double length = get_length();
120120            if (new_position > length)
r14940r14941
122122               m_state = (cassette_state)(( m_state & ~CASSETTE_MASK_UISTATE ) | CASSETTE_STOPPED);
123123               new_position = length;
124124            }
125            else if (new_position < 0)
126            {
127               m_state = (cassette_state)(( m_state & ~CASSETTE_MASK_UISTATE ) | CASSETTE_STOPPED);
128               new_position = 0;
129            }
125130         }
126131         break;
127132      }
r14940r14941
182187   double position = m_position;
183188
184189   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;
186191   return position;
187192}
188193
r14940r14941
196201   return ((double) info.sample_count) / info.sample_frequency;
197202}
198203
204void cassette_image_device::set_channel(int channel)
205{
206   m_channel = channel;
207}
199208
209void cassette_image_device::set_speed(double speed)
210{
211   m_speed = speed;
212}
200213
214void cassette_image_device::go_forward()
215{
216   m_direction = 1;
217}
218
219void cassette_image_device::go_reverse()
220{
221   m_direction = -1;
222}
223
224
201225void cassette_image_device::seek(double time, int origin)
202226{
203227   double length;
r14940r14941
300324   /* reset the position */
301325   m_position = 0.0;
302326   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;
303332
304333   return IMAGE_INIT_PASS;
305334
src/emu/imagedev/cassette.h
r14940r14941
9292   cassette_image *get_image() { return m_cassette; }
9393   double get_position();
9494   double get_length();
95   void set_speed(double speed);
96   void set_channel(int channel);
97   void go_forward();
98   void go_reverse();
9599   void seek(double time, int origin);
96100
97101protected:
r14940r14941
107111   double         m_position;
108112   double         m_position_time;
109113   INT32         m_value;
114   int            m_channel;
115   double         m_speed; // speed multiplier for tape speeds other than standard 1.875ips (used in adam driver)
116   int            m_direction; // direction select
110117   char         m_extension_list[256];
111118};
112119
src/lib/formats/adam_cas.c
r0r14941
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/***************************************************************
15Coleco Adam Digital Data Pack format:
16The packs are the same shape as a standard audio cassette, but with different alignment and capstan holes
17The tape only has one side and has two widely separated mono data tracks (second track readable on an audio
18cassette deck by flipping the tape over and reversing the recorded signal).
19 
20Header format:
212 byte header id: 0x48 0x45 (central directory HE type) or 0x47 0x57 (GW type)
222 byte block number
232 byte NOT block number
241 byte number of blocks (0x80)
251 byte sum of the above (checksum)
26 
27 
28track format:
29leading zeros: ~2753
30 
31block format:
32sync byte 0x16
33header
34pad zero bytes ~21
35sync byte 0x16
36data(1k)
37pad zero bytes ~21
38sync byte 0x16
392 byte checksum-16
40pad zero bytes ~2
41sync bytes 0xaa ~922
42pad zero bytes ~2
43 
44Data 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 
49static 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
59casserr_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 
82casserr_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 
125static 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 
205static const struct CassetteFormat coladam_ddp =
206{ "ddp", coladam_ddp_identify, coladam_ddp_load, NULL /* no save */ };
207 
208CASSETTE_FORMATLIST_START(coleco_adam_cassette_formats)
209   CASSETTE_FORMAT(coladam_ddp)
210CASSETTE_FORMATLIST_END
src/lib/formats/adam_cas.h
r0r14941
1/*********************************************************************
2 
3    adam_cas.h
4 
5    Format code for Coleco Adam .ddp casette files.
6 
7*********************************************************************/
8 
9#ifndef __ADAM_CAS_H
10#define __ADAM_CAS_H
11 
12#include "cassimg.h"
13 
14CASSETTE_FORMATLIST_EXTERN(coleco_adam_cassette_formats);
15 
16#endif
17 
src/lib/formats/cassimg.c
r14940r14941
479479
480480      /* and write out the result */
481481      dest_ptr = (UINT8*)samples;
482      dest_ptr += waveform_bytes_per_sample(waveform_flags) * sample_index;
482      dest_ptr += waveform_bytes_per_sample(waveform_flags) * sample_index * cassette->channels;
483483      switch(waveform_bytes_per_sample(waveform_flags))
484484      {
485485         case 1:
src/lib/lib.mak
r14940r14941
9494   $(LIBOBJ)/formats/basicdsk.o   \
9595   $(LIBOBJ)/formats/a26_cas.o      \
9696   $(LIBOBJ)/formats/ace_tap.o      \
97   $(LIBOBJ)/formats/adam_cas.o   \
9798   $(LIBOBJ)/formats/ami_dsk.o      \
9899   $(LIBOBJ)/formats/ap2_dsk.o      \
99100   $(LIBOBJ)/formats/apf_apt.o      \
src/mess/tools/castool/main.c
r14940r14941
2727#include "formats/gtp_cas.h"
2828#include "formats/hect_tap.h"
2929#include "formats/ace_tap.h"
30#include "formats/adam_cas.h"
3031#include "formats/kc_cas.h"
3132#include "formats/kim1_cas.h"
3233#include "formats/lviv_lvt.h"
r14940r14941
5556
5657const struct SupportedCassetteFormats formats[] = {
5758   {"a26", a26_cassette_formats               ,"Atari 2600"},
59   {"ddp", coleco_adam_cassette_formats       ,"Coleco Adam"},
5860   {"apf", apf_cassette_formats               ,"APF Imagination Machine"},
5961   {"cbm", cbm_cassette_formats               ,"Commodore"},
6062   {"cgenie", cgenie_cassette_formats         ,"Colour Genie"},
src/mess/drivers/adam.c
r14940r14941
193193#include "cpu/z80/z80.h"
194194#include "cpu/m6800/m6800.h"
195195#include "formats/basicdsk.h"
196#include "formats/adam_cas.h"
196197#include "imagedev/cartslot.h"
197198#include "imagedev/cassette.h"
198199#include "imagedev/flopdrv.h"
r14940r14941
762763
763764    */
764765
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   }
768781
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
775782   // data write 0
776783   m_wr0 = BIT(data, 6);
777784
r14940r14941
797804        4
798805
799806    */
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
800814
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
810815   // NET RXD
811816   data |= m_rxd << 3;
812817
r14940r14941
832837
833838    */
834839
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   }
837851
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
842852   // NET TXD
843853   adamnet_txd_w(ADAMNET_DDP, BIT(data, 4));
844854}
845855
846
847856//-------------------------------------------------
848857//  ddp6801_p4_r -
849858//-------------------------------------------------
r14940r14941
867876
868877   UINT8 data = 0;
869878
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)
880895   data |= 0x40;
881
882   // read data 1
883   data |= ((m_ddp0->input() < 0) || (m_ddp1->input() < 0)) << 7;
884
896     
885897   return data;
886898}
887899
r14940r14941
15141526//  cassette_interface adam_cassette_interface
15151527//-------------------------------------------------
15161528
1529static const struct CassetteOptions adam_cassette_options =
1530{
1531   2,      /* channels */
1532   16,      /* bits per sample */
1533   44100   /* sample frequency */
1534};
1535
15171536static const cassette_interface adam_cassette_interface =
15181537{
1519   cassette_default_formats,
1538   coleco_adam_cassette_formats,
1539   &adam_cassette_options,
1540   (cassette_state)(CASSETTE_PLAY | CASSETTE_MOTOR_DISABLED | CASSETTE_SPEAKER_MUTED),
15201541   NULL,
1521   (cassette_state)(CASSETTE_STOPPED | CASSETTE_MOTOR_ENABLED | CASSETTE_SPEAKER_MUTED),
1522   NULL,
15231542   NULL
15241543};
15251544
r14940r14941
16811700   MCFG_CPU_ADD(M6801_DDP_TAG, M6801, XTAL_4MHz)
16821701   MCFG_CPU_PROGRAM_MAP(ddp6801_mem)
16831702   MCFG_CPU_IO_MAP(ddp6801_io)
1684   MCFG_DEVICE_DISABLE()
16851703
16861704   MCFG_CPU_ADD(M6801_PRN_TAG, M6801, XTAL_4MHz)
16871705   MCFG_CPU_PROGRAM_MAP(printer6801_mem)

Previous 15994 Revisions Next


© 1998-2018 The MESS Team