Previous 15994 Revisions Next

r3286 Thursday 18th September, 2008 at 16:54:03 UTC by Wilbert Pol
[TRS80] Added proper cassette emulation support.
[docs]messnew.txt
[src/mess/drivers]trs80.c
[src/mess/includes]trs80.h
[src/mess/machine]trs80.c

src/mess/includes/trs80.h
r3285r3286
1818
1919extern UINT8 trs80_port_ff;
2020
21DEVICE_IMAGE_LOAD( trs80_cas );
22DEVICE_IMAGE_UNLOAD( trs80_cas );
2321DEVICE_IMAGE_LOAD( trs80_floppy );
2422QUICKLOAD_LOAD( trs80_cmd );
2523
src/mess/machine/trs80.c
r3285r3286
1818
1919/* Devices */
2020#include "devices/basicdsk.h"
21#include "devices/cassette.h"
2122#include "devices/flopdrv.h"
2223
2324
r3285r3286
4950#endif
5051static UINT8 irq_mask = 0;
5152
52static UINT8 *cas_buff = NULL;
53static UINT32 cas_size = 0;
54
55/* current tape file handles */
56static mame_file *tape_put_file = NULL;
57static mame_file *tape_get_file = NULL;
58
59/* tape buffer for the first eight bytes at write (to extract a filename) */
60static UINT8 tape_buffer[8];
61
62static int tape_count = 0;      /* file offset within tape file */
63static int put_bit_count = 0;   /* number of sync and data bits that were written */
64static int get_bit_count = 0;   /* number of sync and data bits to read */
65static int tape_bits = 0;      /* sync and data bits mask */
66static int tape_time = 0;      /* time in cycles for the next bit at read */
67static int in_sync = 0;       /* flag if writing to tape detected the sync header A5 already */
68static int put_cycles = 0;      /* cycle count at last output port change */
69static int get_cycles = 0;      /* cycle count at last input port read */
70
71static void tape_put_byte(UINT8 value);
72static void tape_get_open(running_machine *machine);
73static void tape_put_close(running_machine *machine);
74
7553#define FW TRS80_FONT_W
7654#define FH TRS80_FONT_H
7755
56static double old_cassette_val;
57static UINT8 cassette_data;
58static emu_timer *cassette_data_timer;
7859
79static TIMER_CALLBACK(cas_copy_callback)
60static TIMER_CALLBACK( cassette_data_callback )
8061{
81   UINT16 entry = 0, block_ofs = 0, block_len = 0;
82   unsigned offs = 0;
62   double new_val = cassette_input(device_list_find_by_tag( machine->config->devicelist, CASSETTE, "cassette" ));
8363
84   while( cas_size > 3 )
64   /* Check for HI-LO transition */
65   if ( old_cassette_val > -0.2 && new_val < -0.2 )
8566   {
86      UINT8 data = cas_buff[offs++];
87
88      switch( data )
89      {
90      case 0x3c:         /* CAS file header */
91         block_len = cas_buff[offs++];
92         /* on CMD files size=zero means size 256 */
93         if( block_len == 0 )
94            block_len += 256;
95         block_ofs = cas_buff[offs++];
96         block_ofs += 256 * cas_buff[offs++];
97         cas_size -= 4;
98         LOG(("cas_copy_callback block ($%02X) %d at $%04X\n", data, block_len, block_ofs));
99         while( block_len && cas_size )
100         {
101            program_write_byte(block_ofs, cas_buff[offs]);
102            offs++;
103            block_ofs++;
104            block_len--;
105            cas_size--;
106         }
107         /* skip the CHKSUM byte */
108         offs++;
109         break;
110      case 0x78:
111         entry = cas_buff[offs++];
112         entry += 256 * cas_buff[offs++];
113         LOG(("cas_copy_callback entry ($%02X) at $%04X\n", data, entry));
114         cas_size -= 3;
115         break;
116      default:
117         cas_size--;
118      }
67      cassette_data |= 0x80;
11968   }
120   cas_size = 0;
121   activecpu_set_reg(Z80_PC, entry);
69   old_cassette_val = new_val;
12270}
12371
124DEVICE_IMAGE_LOAD( trs80_cas )
125{
126   cas_size = image_length(image);
127   cas_buff = image_ptr(image);
128   if (!cas_buff)
129      return INIT_FAIL;
13072
131   if (cas_buff[1] == 0x55)
132   {
133      LOG(("trs80_cas_init: loading %s size %d\n", image_filename(image), cas_size));
134   }
135   else
136   {
137      cas_buff = NULL;
138      cas_size = 0;
139      logerror("trs80_cas_init: CAS file is not in SYSTEM format\n");
140      return 1;
141   }
142   return 0;
143}
144
145DEVICE_IMAGE_UNLOAD( trs80_cas )
146{
147   cas_buff = NULL;
148   cas_size = 0;
149}
150
15173QUICKLOAD_LOAD( trs80_cmd )
15274{
15375   UINT16 entry = 0, block_ofs = 0, block_len = 0;
r3285r3286
282204
283205static void trs80_fdc_callback(running_machine *machine, wd17xx_state_t event, void *param);
284206
207
285208MACHINE_RESET( trs80 )
286209{
287   if (cas_size)
288   {
289      LOG(("trs80_init_machine: schedule cas_copy_callback (%d)\n", cas_size));
290      timer_set(ATTOTIME_IN_MSEC(500), NULL, 0, cas_copy_callback);
291   }
210   cassette_data = 0x00;
211   cassette_data_timer = timer_alloc( cassette_data_callback, NULL );
212   timer_adjust_periodic( cassette_data_timer, attotime_zero, 0, ATTOTIME_IN_HZ(11025) );
292213}
293214
215
294216DRIVER_INIT( trs80 )
295217{
296218   UINT8 *FNT = memory_region(machine, "gfx1");
r3285r3286
354276{
355277}
356278
279
357280DRIVER_INIT( ht108064 )
358281{
359282   UINT8 *FNT = memory_region(machine, "gfx1");
r3285r3286
363286   }
364287}
365288
289
366290MACHINE_START( trs80 )
367291{
368292   wd17xx_init(machine, WD_TYPE_179X,trs80_fdc_callback, NULL);
369   add_exit_callback(machine, tape_put_close);
370293}
371294
372/*************************************
373 *
374 *            Tape emulation.
375 *
376 *************************************/
377295
378static void tape_put_byte(UINT8 value)
379{
380   if (tape_count < 8)
381   {
382      tape_buffer[tape_count++] = value;
383      if (tape_count == 8)
384      {
385         /* BASIC tape ? */
386         if (tape_buffer[1] == 0xd3)
387         {
388            char filename[12+1];
389            UINT8 zeroes[256] = {0,};
390
391            sprintf(filename, "basic%c.cas", tape_buffer[4]);
392            mame_fopen(SEARCHPATH_IMAGE, filename, OPEN_FLAG_READ | OPEN_FLAG_WRITE, &tape_put_file);
393            mame_fwrite(tape_put_file, zeroes, 256);
394            mame_fwrite(tape_put_file, tape_buffer, 8);
395         }
396         else
397         /* SYSTEM tape ? */
398         if (tape_buffer[1] == 0x55)
399         {
400            char filename[12+1];
401            UINT8 zeroes[256] = {0,};
402
403            sprintf(filename, "%-6.6s.cas", tape_buffer+2);
404            mame_fopen(SEARCHPATH_IMAGE, filename, OPEN_FLAG_READ | OPEN_FLAG_WRITE, &tape_put_file);
405            mame_fwrite(tape_put_file, zeroes, 256);
406            mame_fwrite(tape_put_file, tape_buffer, 8);
407         }
408      }
409   }
410   else
411   {
412      if (tape_put_file)
413         mame_fwrite(tape_put_file, &value, 1);
414   }
415}
416
417static void tape_put_close(running_machine *machine)
418{
419   /* file open ? */
420   if (tape_put_file)
421   {
422      if (put_bit_count)
423      {
424         UINT8   value;
425         while (put_bit_count < 16)
426         {
427               tape_bits <<= 1;
428               put_bit_count++;
429         }
430         value = 0;
431         if (tape_bits & 0x8000) value |= 0x80;
432         if (tape_bits & 0x2000) value |= 0x40;
433         if (tape_bits & 0x0800) value |= 0x20;
434         if (tape_bits & 0x0200) value |= 0x10;
435         if (tape_bits & 0x0080) value |= 0x08;
436         if (tape_bits & 0x0020) value |= 0x04;
437         if (tape_bits & 0x0008) value |= 0x02;
438         if (tape_bits & 0x0002) value |= 0x01;
439         tape_put_byte(value);
440      }
441      mame_fclose(tape_put_file);
442   }
443   tape_count = 0;
444   tape_put_file = 0;
445}
446
447static void tape_get_byte(running_machine *machine)
448{
449   int    count;
450   UINT8   value;
451   if (tape_get_file)
452   {
453      count = mame_fread(tape_get_file, &value, 1);
454      if (count == 0)
455      {
456            value = 0;
457            mame_fclose(tape_get_file);
458            tape_get_file = 0;
459      }
460      tape_bits |= 0xaaaa;
461      if (value & 0x80) tape_bits ^= 0x4000;
462      if (value & 0x40) tape_bits ^= 0x1000;
463      if (value & 0x20) tape_bits ^= 0x0400;
464      if (value & 0x10) tape_bits ^= 0x0100;
465      if (value & 0x08) tape_bits ^= 0x0040;
466      if (value & 0x04) tape_bits ^= 0x0010;
467      if (value & 0x02) tape_bits ^= 0x0004;
468      if (value & 0x01) tape_bits ^= 0x0001;
469      get_bit_count = 16;
470      tape_count++;
471   }
472}
473
474static void tape_get_open(running_machine *machine)
475{
476   /* TODO: remove this */
477   unsigned char *RAM = memory_region(machine, "main");
478
479   if (!tape_get_file)
480   {
481      char filename[12+1];
482
483      sprintf(filename, "%-6.6s.cas", RAM + 0x41e8);
484      logerror("filename %s\n", filename);
485      mame_fopen(SEARCHPATH_IMAGE, filename, OPEN_FLAG_READ, &tape_get_file);
486      tape_count = 0;
487   }
488}
489
490296/*************************************
491297 *
492298 *            Port handlers.
493299 *
494300 *************************************/
495301
302
496303 READ8_HANDLER( trs80_port_xx_r )
497304{
498305   return 0;
499306}
500307
308
501309WRITE8_HANDLER( trs80_port_ff_w )
502310{
503   int changes = trs80_port_ff ^ data;
311   static const double levels[4] = { 0.0, -1.0, 0.0, 1.0 };
312   const device_config *cass = device_list_find_by_tag( machine->config->devicelist, CASSETTE, "cassette" );
504313
505   /* tape output changed ? */
506   if( changes & 0x03 )
507   {
508      /* virtual tape ? */
509      if( input_port_read(machine, "CONFIG") & 0x20 )
510      {
511         int now_cycles = activecpu_gettotalcycles();
512         int diff = now_cycles - put_cycles;
513         UINT8 value;
514         /* overrun since last write ? */
515         if (diff > 4000)
516         {
517            /* reset tape output */
518            tape_put_close(machine);
519            put_bit_count = tape_bits = in_sync = 0;
520         }
521         else
522         /* just wrote the interesting value ? */
523         if( (data & 0x03) == 0x01 )
524         {
525            /* change within time for a 1 bit ? */
526            if( diff < 2000 )
527            {
528               tape_bits = (tape_bits << 1) | 1;
529               /* in sync already ? */
530               if( in_sync )
531               {
532                  /* count 1 bit */
533                  put_bit_count += 1;
534               }
535               else
536               {
537                  /* try to find sync header A5 */
538                  if( tape_bits == 0xcc33 )
539                  {
540                     in_sync = 1;
541                     put_bit_count = 16;
542                  }
543               }
544            }
545            else   /* no change indicates a 0 bit */
546            {
547               /* shift twice */
548               tape_bits <<= 2;
549               /* in sync already ? */
550               if( in_sync )
551                  put_bit_count += 2;
552            }
314   cassette_change_state( cass, ( data & 0x04 ) ? CASSETTE_MOTOR_ENABLED : CASSETTE_MOTOR_DISABLED, CASSETTE_MASK_MOTOR );
553315
554            /* collected 8 sync plus 8 data bits ? */
555            if( put_bit_count >= 16 )
556            {
557               /* extract data bits to value */
558               value = 0;
559               if (tape_bits & 0x8000) value |= 0x80;
560               if (tape_bits & 0x2000) value |= 0x40;
561               if (tape_bits & 0x0800) value |= 0x20;
562               if (tape_bits & 0x0200) value |= 0x10;
563               if (tape_bits & 0x0080) value |= 0x08;
564               if (tape_bits & 0x0020) value |= 0x04;
565               if (tape_bits & 0x0008) value |= 0x02;
566               if (tape_bits & 0x0002) value |= 0x01;
567               put_bit_count -= 16;
568               tape_bits = 0;
569               tape_put_byte(value);
570            }
571         }
572         /* remember the cycle count of this write */
573         put_cycles = now_cycles;
574      }
575      else
576      {
577         switch( data & 0x03 )
578         {
579         case 0: /* 0.46 volts */
580            speaker_level_w(0,1);
581            break;
582         case 1:
583         case 3: /* 0.00 volts */
584            speaker_level_w(0,0);
585            break;
586         case 2: /* 0.85 volts */
587            speaker_level_w(0,2);
588            break;
589         }
590      }
591   }
316   cassette_output( cass, levels[data & 0x03]);
592317
318   cassette_data &= ~0x80;
593319   trs80_port_ff = data;
594320}
595321
322
596323 READ8_HANDLER( trs80_port_ff_r )
597324{
598   int now_cycles = activecpu_gettotalcycles();
599   /* virtual tape ? */
600   if( input_port_read(machine, "CONFIG") & 0x20 )
601   {
602      int diff = now_cycles - get_cycles;
603      /* overrun since last read ? */
604      if (diff >= 4000)
605      {
606         if (tape_get_file)
607         {
608            mame_fclose(tape_get_file);
609            tape_get_file = 0;
610         }
611         get_bit_count = tape_bits = tape_time = 0;
612      }
613      else /* check what he will get for input */
614      {
615         /* count down cycles */
616         tape_time -= diff;
617         /* time for the next sync or data bit ? */
618         if (tape_time <= 0)
619         {
620            /* approx. time for a bit */
621            tape_time += 1570;
622            /* need to read get new data ? */
623            if (--get_bit_count <= 0)
624            {
625               tape_get_open(machine);
626               tape_get_byte(machine);
627            }
628            /* shift next sync or data bit to bit 16 */
629            tape_bits <<= 1;
630            /* if bit is set, set trs80_port_ff bit 4
631               which is then read as bit 7 */
632            if (tape_bits & 0x10000)
633               trs80_port_ff |= 0x80;
634         }
635      }
636      /* remember the cycle count of this read */
637      get_cycles = now_cycles;
638   }
639   return (trs80_port_ff << 3) & 0xc0;
325   return cassette_data | 0x7F;
640326}
641327
642328/*************************************
src/mess/drivers/trs80.c
r3285r3286
8787
8888/* Devices */
8989#include "devices/basicdsk.h"
90#include "devices/cassette.h"
9091
9192
9293#define FW   TRS80_FONT_W
r3285r3286
402403
403404   /* devices */
404405   MDRV_QUICKLOAD_ADD(trs80_cmd, "cmd", 0.5)
406
407   MDRV_CASSETTE_ADD( "cassette", default_cassette_config )
405408MACHINE_DRIVER_END
406409
407410
r3285r3286
524527ROM_END
525528
526529
527static void trs80_cassette_getinfo(const mess_device_class *devclass, UINT32 state, union devinfo *info)
528{
529   /* cassette */
530   switch(state)
531   {
532      /* --- the following bits of info are returned as 64-bit signed integers --- */
533      case MESS_DEVINFO_INT_TYPE:                     info->i = IO_CASSETTE; break;
534      case MESS_DEVINFO_INT_READABLE:                  info->i = 1; break;
535      case MESS_DEVINFO_INT_WRITEABLE:                  info->i = 0; break;
536      case MESS_DEVINFO_INT_CREATABLE:                  info->i = 0; break;
537      case MESS_DEVINFO_INT_COUNT:                     info->i = 1; break;
538
539      /* --- the following bits of info are returned as pointers to data or functions --- */
540      case MESS_DEVINFO_PTR_LOAD:                     info->load = DEVICE_IMAGE_LOAD_NAME(trs80_cas); break;
541      case MESS_DEVINFO_PTR_UNLOAD:                  info->unload = DEVICE_IMAGE_UNLOAD_NAME(trs80_cas); break;
542
543      /* --- the following bits of info are returned as NULL-terminated strings --- */
544      case MESS_DEVINFO_STR_FILE_EXTENSIONS:            strcpy(info->s = device_temp_str(), "cas"); break;
545   }
546}
547
548static SYSTEM_CONFIG_START(trs80)
549   CONFIG_DEVICE(trs80_cassette_getinfo)
550SYSTEM_CONFIG_END
551
552
553530static void trs8012_floppy_getinfo(const mess_device_class *devclass, UINT32 state, union devinfo *info)
554531{
555532   /* floppy */
r3285r3286
569546}
570547
571548static SYSTEM_CONFIG_START(trs8012)
572   CONFIG_IMPORT_FROM(trs80)
573549   CONFIG_DEVICE(trs8012_floppy_getinfo)
574550SYSTEM_CONFIG_END
575551
576552
577553/*    YEAR  NAME      PARENT  COMPAT  MACHINE   INPUT  INIT  CONFIG   COMPANY  FULLNAME */
578COMP( 1977, trs80,    0,        0,      level1,   trs80, trs80,    trs80,   "Tandy Radio Shack",  "TRS-80 Model I (Level I Basic)" , 0)
554COMP( 1977, trs80,    0,        0,      level1,   trs80, trs80,    0,      "Tandy Radio Shack",  "TRS-80 Model I (Level I Basic)" , 0)
579555COMP( 1978, trs80l2,  trs80,    0,      model1,   trs80, trs80,    trs8012,   "Tandy Radio Shack",  "TRS-80 Model I (Level II Basic)" , 0)
580556COMP( 1980, sys80,    trs80,    0,      model1,   trs80, trs80,    trs8012,   "EACA Computers Ltd.","System-80" , 0)
581557COMP( 1981, lnw80,    trs80,    0,      model1,   trs80, lnw80,    trs8012,   "LNW Research","LNW-80", 0 )
docs/messnew.txt
r3285r3286
109109
110110- [TMC2000] Fixed quickloading. [Curt Coder]
111111
112- [TRS80] Added proper cassette emulation support.  [Wilbert Pol]
113
112114- [VIC20] Added support for tape emulation using MESS core functions
113115  (loading and saving, both .wav and .tap formats) [Fabio Priuli]
114116

Previous 15994 Revisions Next


© 1998-2018 The MESS Team