Previous 15994 Revisions Next

r9485 Sunday 31st October, 2010 at 16:20:16 UTC by Michael Zapf
TI-99 family architecture refactoring. All components have been
rewritten as devices. For the sake of keeping things together I put all
those files in a new subfolder.
[src/mess/machine/ti99]bwg.c* bwg.h* crubus.c* crubus.h* datamux.c* datamux.h* evpc.c* evpc.h* genboard.c* genboard.h* grom.c* grom.h* gromport.c* gromport.h* handset.c* handset.h* hfdc.c* hfdc.h* hsgpl.c* hsgpl.h* mapper8.c* mapper8.h* mecmouse.c* mecmouse.h* myarcmem.c* myarcmem.h* p_code.c* p_code.h* peribox.c* peribox.h* samsmem.c* samsmem.h* sgcpu.c* sgcpu.h* spchsyn.c* spchsyn.h* speech8.c* speech8.h* ti32kmem.c* ti32kmem.h* ti99defs.h* ti_fdc.c* ti_fdc.h* ti_rs232.c* ti_rs232.h* tiboard.c* tiboard.h* tn_ide.c* tn_ide.h* tn_usbsm.c* tn_usbsm.h* videowrp.c* videowrp.h*

src/mess/machine/ti99/crubus.c
r0r9485
1/*
2   TI-99 CRU Bus       
3*/
4
5#include "emu.h"
6#include "crubus.h"
7
8#define MAXCRU 20
9
10typedef struct _crubus_dev
11{
12   /* The device. */
13   running_device       *device;
14
15   /* Read access. */
16   cru_read_function   cru_read;
17
18   /* Write access. */
19   cru_write_function   cru_write;
20
21   /* Address bits involved. The CRU makes use of the address bus. */
22   UINT16         address_mask;
23
24   /* Value of the address bits which are involved for selecting for read. */
25   UINT16         select;
26
27} crubus_dev;
28
29typedef struct _crubus_state
30{
31   crubus_dev         component[MAXCRU];
32   /* Management function */
33   int devindex;
34
35} crubus_state;
36
37INLINE crubus_state *get_safe_token(running_device *device)
38{
39   assert(device != NULL);
40   return (crubus_state *)downcast<legacy_device_base *>(device)->token();
41}
42
43void cru_mount_device(running_device *device, running_device *crudev, UINT16 address_mask, UINT16 address_bits, cru_read_function cruread, cru_write_function cruwrite)
44{
45   crubus_state *crubus = get_safe_token(device);
46   int index = crubus->devindex++;
47//   logerror("register cru device %lx\n", (long unsigned int)crudev);
48   if (index < MAXCRU)
49   {
50      if (crubus->component[index].device == NULL)
51      {
52         crubus->component[index].device = crudev;
53         crubus->component[index].cru_read = cruread;
54         crubus->component[index].cru_write = cruwrite;
55         crubus->component[index].address_mask = address_mask;
56         crubus->component[index].select = address_bits;
57      }
58   }
59}
60
61/***************************************************************************
62    ACCESSOR FUNCTIONS
63***************************************************************************/
64
65READ8_DEVICE_HANDLER( ti99_crubus_r )
66{
67   crubus_state *crubus = get_safe_token(device);
68   UINT8 reply = 0;
69   
70   for (int i=0; i < MAXCRU; i++)
71   {
72      crubus_dev *crudev = &crubus->component[i];
73      if (crubus->component[i].device != NULL)
74      {
75         if (crudev->cru_read != NULL)
76         {
77            if (((offset<<4) & crudev->address_mask)==crudev->select)
78            {
79               // CRU read is implemented as an 8-bit read access.
80               // We shift the address for the sake of readability
81               // Each read access returns 8 consecutive CRU bits
82               // Shift 4 = addr*8*2
83               crudev->cru_read(crudev->device, offset<<4, &reply);
84            }
85         }
86      }
87   }
88//   printf("cru read %04x = %02x\n", offset<<4, reply);   
89
90   return reply;
91}
92
93WRITE8_DEVICE_HANDLER( ti99_crubus_w )
94{
95   crubus_state *crubus = get_safe_token(device);
96
97//   printf("cru write %04x = %02x\n", offset<<1, data);   
98   for (int i=0; i < MAXCRU; i++)
99   {
100      crubus_dev *crudev = &crubus->component[i];
101      if (crubus->component[i].device != NULL)
102      {
103         if (crudev->cru_write != NULL)
104         {
105            if (((offset<<1) & crudev->address_mask)==crudev->select)
106            {
107               // CRU write is implemented as a 1-bit access
108               crudev->cru_write(crudev->device, offset<<1, data);
109            }
110         }
111      }
112   }
113}
114
115/***************************************************************************
116    DEVICE FUNCTIONS
117***************************************************************************/
118
119static DEVICE_START( crubus )
120{
121   int i = 0;
122   int done=FALSE;
123   cruconf_device *cons = (cruconf_device*)device->baseconfig().static_config();
124   crubus_state *crubus = get_safe_token(device);
125   
126   logerror("start CRU bus\n");
127   
128   crubus->devindex = 0;
129
130   while (!done)
131   {
132      if (cons[i].name != NULL)
133      {
134         running_device *dev = device->machine->device(cons[i].name);
135         if (dev!=NULL)
136            cru_mount_device(device, dev, cons[i].address_mask, cons[i].select_pattern, cons[i].read, cons[i].write);
137         else
138            logerror("ti99_crubus: Device %s not found.\n", cons[i].name);
139      }
140      else done=TRUE;
141      i++;
142   }
143}
144
145static DEVICE_STOP( crubus )
146{
147   logerror("stop CRU bus\n");
148}
149
150static DEVICE_RESET( crubus )
151{
152   logerror("reset CRU bus\n");
153}
154
155static const char DEVTEMPLATE_SOURCE[] = __FILE__;
156
157#define DEVTEMPLATE_ID(p,s)             p##crubus##s
158#define DEVTEMPLATE_FEATURES            DT_HAS_START | DT_HAS_STOP | DT_HAS_RESET
159#define DEVTEMPLATE_NAME                "TI99 CRU bus system"
160#define DEVTEMPLATE_FAMILY              "Internal devices"
161#include "devtempl.h"
162
163DEFINE_LEGACY_DEVICE( CRUBUS, crubus );
src/mess/machine/ti99/grom.c
r0r9485
1/***************************************************************************
2
3    GROM emulation (aka TMC0430)
4
5    This is a preliminary implementation since it does not yet contain
6    internal timing; instead, it directly accesses the processor to
7    simulate wait states
8    When this will have become available, the file will be moved to the
9    general circuit collection (emu/machine)
10   
11          +----+--+----+
12      AD7 |1    G    16| Vss             
13      AD6 |2    R    15| GR
14      AD5 |3    O    14| Vdd
15      AD4 |4    M    13| GRC
16      AD3 |5         12| M
17      AD2 |6         11| MO
18      AD1 |7         10| GS*
19      AD0 |8          9| Vcc
20          +------------+
21
22    GR  = GROM Ready. Should be connected to processor's READY/HOLD*.
23    GRC = GROM clock. Typically in the range of 400-500 kHz.
24    M   = Direction. 1=read, 0=write
25    MO  = Mode. 1=address counter access, 0=data access
26    GS* = GROM select. 0=select, 1=deselect
27   
28    Every GROM has an internal ID which represents the high-order three
29    address bits. The address counter can be set to any value from 0
30    to 0xffff; the GROM will only react if selected and if the current
31    address counter's high-order bits match the ID of the chip.
32    Example: When the ID is 6, the GROM will react when the address
33    counter contains a value from 0xc000 to 0xdfff.
34   
35    Writable GROMs are called GRAMs. Although the TI-99 systems reserve a
36    port in the memory space, no one has ever seen a GRAM circuit in the wild.
37    However, third-party products like HSGPL or GRAM Kracker simulate GRAMs
38    using conventional RAM with some addressing circuitry, usually in a custom
39    chip.
40   
41    CHECK: Reading the address increases the counter only once. The first access
42    returns the MSB, the second (and all following accesses) return the LSB.
43   
44    Michael Zapf, August 2010
45   
46***************************************************************************/
47
48#include "emu.h"
49#include "grom.h"
50#include "datamux.h"
51
52/* ti99_grom_state: GROM state */
53struct _ti99grom_state
54{
55   /* Address pointer. */
56   // This value is always expected to be in the range 0x0000 - 0xffff, even
57   // when this GROM is not addressed.
58   UINT16 address;
59
60   /* GROM data buffer. */
61   UINT8 buffer;
62   
63   /* Internal flip-flop. Used when retrieving the address counter. */
64   UINT8 raddr_LSB;
65
66   /* Internal flip-flops. Used when writing the address counter.*/
67   UINT8 waddr_LSB;
68   
69   /* ID of this GROM. */
70   UINT8 ident;
71   
72   /* Pointer to the memory region contained in this GROM. */
73   UINT8 *memptr;
74   
75   /* GROM size. May be 0x1800 or 0x2000. */
76   // If the GROM has only 6 KiB, the remaining 2 KiB are filled with a
77   // specific byte pattern which is created by a logical OR of lower
78   // regions
79   int extended;
80
81   /* Determines whether this is a GRAM. */   
82   int writable;
83
84   /* Determines whether there is a rollover at the end of the address space. */   
85   int rollover;
86   
87   /* Ready callback. This line is usually connected to the READY pin of the CPU. */
88   devcb_resolved_write_line gromready;
89};
90typedef struct _ti99grom_state ti99grom_state;
91
92INLINE ti99grom_state *get_safe_token(running_device *device)
93{
94   assert(device != NULL);
95   assert(downcast<legacy_device_base *>(device)->token() != NULL);
96   return (ti99grom_state *)downcast<legacy_device_base *>(device)->token();
97}
98
99INLINE const ti99grom_config *get_config(running_device *device)
100{
101   assert(device != NULL);
102   assert(device->type() == GROM);
103   return (const ti99grom_config *) downcast<const legacy_device_config_base &>(device->baseconfig()).inline_config();
104}
105
106/*
107   Indicates whether this chip will react on the next read/write data
108   access. We do not have a tri-state handling on the read handlers, so this
109   serves to avoid the read access.
110*/
111int is_selected(running_device *chip)
112{
113   ti99grom_state *grom = get_safe_token(chip);
114   return (((grom->address >> 13)&0x07)==grom->ident);
115}
116
117/*
118   Reading from the chip. Represents an access with M=1, GS*=0. The MO bit is
119   defined by the offset (0 or 1). This is the enhanced read function with
120   Z state.
121*/
122READ8Z_DEVICE_HANDLER( ti99grom_rz )
123{
124   ti99grom_state *grom = get_safe_token(device);
125     
126   if (offset & 2)
127   {
128      if (((grom->address >> 13)&0x07)!=grom->ident)
129         return;
130
131      /* When reading, reset the hi/lo flag byte for writing. */
132      /* TODO: Verify this with a real machine. */
133      grom->waddr_LSB = FALSE;
134
135      /* Address reading is done in two steps; first, the high byte */
136      /* is transferred, then the low byte. */
137      if (grom->raddr_LSB)
138      {
139         /* second pass */
140         *value = grom->address & 0x00ff;
141         grom->raddr_LSB = FALSE;
142      }
143      else
144      {
145         /* first pass */
146         *value = (grom->address & 0xff00)>>8;
147         grom->raddr_LSB = TRUE;
148      }
149   }
150   else
151   {
152      if (((grom->address >> 13)&0x07)==grom->ident)
153      {
154         /* GROMs are buffered. Data is retrieved from a buffer, */
155         /* while the buffer is replaced with the next cell content. */
156         *value = grom->buffer;
157         
158         /* Get next value, put it in buffer. Note that the GROM */
159         /* wraps at 8K boundaries. */
160         UINT16 addr = grom->address-(grom->ident<<13);
161         
162         if (!grom->extended && ((grom->address&0x1fff)>=0x1800))
163            grom->buffer = grom->memptr[addr-0x1000] | grom->memptr[addr-0x0800];
164         else
165            grom->buffer = grom->memptr[addr];
166      }
167      /* Note that all GROMs update their address counter. */
168      if (grom->rollover)
169         grom->address = ((grom->address + 1) & 0x1FFF) | (grom->address & 0xE000);
170      else
171         grom->address = (grom->address + 1)&0xFFFF;
172
173      /* Reset the read and write address flipflops. */
174      grom->raddr_LSB = grom->waddr_LSB = FALSE;
175   }
176}
177
178/*
179   Reading from the chip. Represents an access with M=1, GS*=0. The MO bit is
180   defined by the offset (0 or 1).
181*/
182READ8_DEVICE_HANDLER( ti99grom_r )
183{
184   UINT8 reply;
185   ti99grom_rz(device, offset, &reply);
186   return reply;
187}
188
189
190/*
191   Writing to the chip. Represents an access with M=0, GS*=0. The MO bit is
192   defined by the offset (0 or 1).
193*/
194WRITE8_DEVICE_HANDLER( ti99grom_w )
195{
196   ti99grom_state *grom = get_safe_token(device);
197   if (offset & 2)
198   {
199      /* write GROM address */
200      /* see comments above */
201      grom->raddr_LSB = FALSE;
202
203      /* Implements the internal flipflop. */
204      /* The Editor/Assembler manuals says that the current address */
205      /* plus one is returned. This effect is properly emulated */
206      /* by using a read-ahead buffer. */
207      if (grom->waddr_LSB)
208      {
209         /* Accept low byte (2nd write) */
210         grom->address = (grom->address & 0xFF00) | data;
211         /* Setting the address causes a new prefetch */
212         if (is_selected(device))
213         {
214            grom->buffer = grom->memptr[grom->address-(grom->ident<<13)];
215         }     
216         grom->waddr_LSB = FALSE;
217      }
218      else
219      {
220         /* Accept high byte (1st write). Do not advance the address conter. */
221         grom->address = (data << 8) | (grom->address & 0xFF);
222         grom->waddr_LSB = TRUE;
223         return;
224      }
225   }
226   else
227   {
228      /* write GRAM data */
229      if ((((grom->address >> 13)&0x07)==grom->ident) && grom->writable)
230      {
231         UINT16 write_addr;
232         // We need to rewind by 1 because the read address has already advanced.
233         // However, do not change the address counter!
234         if (grom->rollover)
235            write_addr = ((grom->address + 0x1fff) & 0x1FFF) | (grom->address & 0xE000);
236         else
237            write_addr = (grom->address - 1) & 0xFFFF;
238         
239         // UINT16 addr = grom->address-(grom->ident<<13);
240         if (grom->extended || ((grom->address&0x1fff)<0x1800))
241            grom->memptr[write_addr-(grom->ident<<13)] = data;
242      }     
243      grom->raddr_LSB = grom->waddr_LSB = FALSE;
244   }
245
246   if (grom->rollover)
247      grom->address = ((grom->address + 1) & 0x1FFF) | (grom->address & 0xE000);
248   else
249      grom->address = (grom->address + 1) & 0xFFFF;
250}
251
252/***************************************************************************
253    DEVICE FUNCTIONS
254***************************************************************************/
255
256static DEVICE_START( ti99grom )
257{
258   ti99grom_state *grom = get_safe_token(device);
259   const ti99grom_config* gromconf = (const ti99grom_config*)get_config(device);
260
261   grom->writable = gromconf->writeable;
262   grom->ident = gromconf->ident;
263   
264   grom->extended = (gromconf->size==0x1800)? TRUE : FALSE;
265
266   grom->rollover = gromconf->rollover;
267
268   devcb_write_line ready = DEVCB_LINE(gromconf->ready);
269   devcb_resolve_write_line(&grom->gromready, &ready, device);
270   // Test
271   // devcb_call_write_line(&grom->gromready, ASSERT_LINE);
272}
273
274static DEVICE_STOP( ti99grom )
275{
276}
277
278static DEVICE_RESET( ti99grom )
279{
280   const ti99grom_config* gromconf = (const ti99grom_config*)get_config(device);
281   ti99grom_state *grom = get_safe_token(device);
282   grom->address = 0;
283   grom->raddr_LSB = FALSE;
284   grom->waddr_LSB = FALSE;
285   grom->buffer = 0;
286
287   /* Try to get the pointer to the memory contents from the parent */
288   if (gromconf->region==NULL)
289      grom->memptr = (*gromconf->get_memory)(device->owner());
290   else
291      grom->memptr = memory_region(device->machine, gromconf->region);
292
293   //  TODO: Check whether this may be 0 for console GROMs.
294   //   assert (grom->memptr!=NULL);
295
296   grom->memptr += gromconf->offset;
297
298   // TODO: If the GROM is a subdevice of another device, and a region
299   // is specified, we need to first determine the device tag and concatenate
300   // the GROM region behind this device tag; otherwise the region will not be
301   // found. May be done with an astring.
302}
303
304static const char DEVTEMPLATE_SOURCE[] = __FILE__;
305
306#define DEVTEMPLATE_ID(p,s)             p##ti99grom##s
307#define DEVTEMPLATE_FEATURES            DT_HAS_START | DT_HAS_STOP | DT_HAS_RESET | DT_HAS_INLINE_CONFIG
308#define DEVTEMPLATE_NAME                "tmc0430"
309#define DEVTEMPLATE_FAMILY              "TTL"
310#include "devtempl.h"
311
312DEFINE_LEGACY_DEVICE( GROM, ti99grom );
src/mess/machine/ti99/crubus.h
r0r9485
1#ifndef __CRUBUS__
2#define __CRUBUS__
3/*
4   TI-99 CRU Bus   
5   header file for crubus   
6*/
7
8typedef void (*cru_read_function)(device_t *device, offs_t offset, UINT8 *value);
9typedef void (*cru_write_function)(device_t *device, offs_t offset, UINT8 value);
10
11typedef struct _cruconf_device
12{
13   const char             *name;
14   UINT16               address_mask;
15   UINT16               select_pattern;
16   cru_read_function       read;
17   cru_write_function       write;
18} cruconf_device;
19
20READ8_DEVICE_HANDLER( ti99_crubus_r );
21WRITE8_DEVICE_HANDLER( ti99_crubus_w );
22
23/* device interface */
24DECLARE_LEGACY_DEVICE( CRUBUS, crubus );
25
26#define MDRV_CRUBUS_ADD(_tag, _devices)         \
27   MDRV_DEVICE_ADD(_tag, CRUBUS, 0) \
28   MDRV_DEVICE_CONFIG( _devices )
29   
30#endif
src/mess/machine/ti99/grom.h
r0r9485
1/***************************************************************************
2    GROM emulation
3
4    TI99/4x hardware supports GROMs.  GROMs are slow ROM devices, which are
5    interfaced via a 8-bit data bus, and include an internal address pointer
6    which is incremented after each read.  This implies that accesses are
7    faster when reading consecutive bytes, although the address pointer can be
8    read and written at any time.
9
10    They are generally used to store programs in GPL (Graphic Programming
11    Language: a proprietary, interpreted language - the interpreter takes most
12    of a TI99/4(a) CPU ROMs).  They can used to store large pieces of data,
13    too.
14
15    Both TI-99/4 and TI-99/4a include three GROMs, with some start-up code,
16    system routines and TI-Basic.  TI99/4 includes an additional Equation
17    Editor.  According to the preliminary schematics found on ftp.whtech.com,
18    TI-99/8 includes the three standard GROMs and 16 GROMs for the UCSD
19    p-system.  TI99/2 does not include GROMs at all, and was not designed to
20    support any, although it should be relatively easy to create an expansion
21    card with the GPL interpreter and a /4a cartridge port.
22
23The simple way:
24
25    Each GROM is logically 8kb long.
26
27    Communication with GROM is done with 4 memory-mapped locations.  You can read or write
28    a 16-bit address pointer, and read data from GROMs.  One register allows to write data, too,
29    which would support some GRAMs, but AFAIK TI never built such GRAMs (although docs from TI
30    do refer to this possibility).
31
32    Since address are 16-bit long, you can have up to 8 GROMs.  So, a cartridge may
33    include up to 5 GROMs.  (Actually, there is a way more GROMs can be used - see below...)
34
35    The address pointer is incremented after each GROM operation, but it will always remain
36    within the bounds of the currently selected GROM (e.g. after 0x3fff comes 0x2000).
37
38Some details:
39
40    Original TI-built GROM are 6kb long, but take 8kb in address space.  The extra 2kb can be
41    read, and follow the following formula:
42        GROM[0x1800+offset] = GROM[0x0800+offset] | GROM[0x1000+offset];
43    (sounds like address decoding is incomplete - we are lucky we don't burn any silicon when
44    doing so...)
45
46    Needless to say, some hackers simulated 8kb GRAMs and GROMs with normal RAM/PROM chips and
47    glue logic.
48
49GPL ports:
50
51    When accessing the GROMs registers, 8 address bits (cpu_addr & 0x03FC) may
52    be used as a port number, which permits the use of up to 256 independant
53    GROM ports, with 64kb of address space in each.  TI99/4(a) ROMs can take
54    advantage of the first 16 ports: it will look for GPL programs in every
55    GROM of the 16 first ports.  Additionally, while the other 240 ports cannot
56    contain standard GROMs with GPL code, they may still contain custom GROMs
57    with data.
58
59    Note, however, that the TI99/4(a) console does not decode the page number, so console GROMs
60    occupy the first 24kb of EVERY port, and cartridge GROMs occupy the next 40kb of EVERY port
61    (with the exception of one demonstration from TI that implements several distinct ports).
62    (Note that the TI99/8 console does have the required decoder.)  Fortunately, GROM drivers
63    have a relatively high impedance, and therefore extension cards can use TTL drivers to impose
64    another value on the data bus with no risk of burning the console GROMs.  This hack permits
65    the addition of additionnal GROMs in other ports, with the only side effect that whenever
66    the address pointer in port N is altered, the address pointer of console GROMs in port 0
67    is altered, too.  Overriding the system GROMs with custom code is possible, too (some hackers
68    have done so), but I would not recommended it, as connecting such a device to a TI99/8 might
69    burn some drivers.
70
71    The p-code card (-> UCSD Pascal system) contains 8 GROMs, all in port 16.  This port is not
72    in the range recognized by the TI ROMs (0-15), and therefore it is used by the p-code DSR ROMs
73    as custom data.  Additionally, some hackers used the extra ports to implement "GRAM" devices.
74
75
76***************************************************************************/
77
78#define READ8Z_DEVICE_HANDLER(name)      void name(ATTR_UNUSED device_t *device, ATTR_UNUSED offs_t offset, UINT8 *value)
79
80typedef struct _ti99grom_config
81{
82   int                  writeable;
83   int                ident;
84   const char             *region;
85   UINT8               *(*get_memory)(running_device *device);
86   offs_t               offset;
87   int                size;
88   int                rollover;   // some GRAM simulations do not implement rollover
89   write_line_device_func   ready;
90} ti99grom_config;
91
92typedef struct _grom_callback
93{
94   devcb_write_line ready;
95} grom_callback;
96
97WRITE8_DEVICE_HANDLER( ti99grom_w );
98READ8Z_DEVICE_HANDLER( ti99grom_rz );
99
100DECLARE_LEGACY_DEVICE( GROM, ti99grom );
101
102#define MDRV_GROM_ADD(_tag, _id, _region, _offset, _size, _ready)   \
103   MDRV_DEVICE_ADD(_tag, GROM, 0)   \
104   MDRV_DEVICE_CONFIG_DATA32(ti99grom_config, writeable, FALSE) \
105   MDRV_DEVICE_CONFIG_DATA32(ti99grom_config, ident, _id) \
106   MDRV_DEVICE_CONFIG_DATAPTR(ti99grom_config, region, _region) \
107   MDRV_DEVICE_CONFIG_DATA32(ti99grom_config, offset, _offset) \
108   MDRV_DEVICE_CONFIG_DATA32(ti99grom_config, size, _size) \
109   MDRV_DEVICE_CONFIG_DATA32(ti99grom_config, rollover, FALSE) \
110   MDRV_DEVICE_CONFIG_DATAPTR(ti99grom_config, ready, _ready)
111
112#define MDRV_GROM_ADD_P(_tag, _id, _memptr, _offset, _size, _ready)   \
113   MDRV_DEVICE_ADD(_tag, GROM, 0)   \
114   MDRV_DEVICE_CONFIG_DATA32(ti99grom_config, writeable, FALSE) \
115   MDRV_DEVICE_CONFIG_DATA32(ti99grom_config, ident, _id) \
116   MDRV_DEVICE_CONFIG_DATAPTR(ti99grom_config, get_memory, _memptr) \
117   MDRV_DEVICE_CONFIG_DATAPTR(ti99grom_config, region, NULL) \
118   MDRV_DEVICE_CONFIG_DATA32(ti99grom_config, offset, _offset) \
119   MDRV_DEVICE_CONFIG_DATA32(ti99grom_config, size, _size) \
120   MDRV_DEVICE_CONFIG_DATA32(ti99grom_config, rollover, FALSE) \
121   MDRV_DEVICE_CONFIG_DATAPTR(ti99grom_config, ready, _ready)
122   
123#define MDRV_GRAM_ADD(_tag, _id, _region, _offset, _size, _rollover, _ready)      \
124   MDRV_DEVICE_ADD(_tag, GROM, 0)                        \
125   MDRV_DEVICE_CONFIG_DATA32(ti99grom_config, writeable, TRUE)   \
126   MDRV_DEVICE_CONFIG_DATA32(ti99grom_config, ident, _id)      \
127   MDRV_DEVICE_CONFIG_DATAPTR(ti99grom_config, region, _region) \
128   MDRV_DEVICE_CONFIG_DATA32(ti99grom_config, offset, _offset)    \
129   MDRV_DEVICE_CONFIG_DATA32(ti99grom_config, size, _size)   \
130   MDRV_DEVICE_CONFIG_DATA32(ti99grom_config, rollover, _rollover) \
131   MDRV_DEVICE_CONFIG_DATAPTR(ti99grom_config, ready, _ready)
132
133
src/mess/machine/ti99/gromport.c
r0r9485
1/**********************************************************************
2
3    gromport.c
4
5*********************************************************************/
6
7#include "emu.h"
8#include "gromport.h"
9#include "devices/cartslot.h"
10#include "devices/multcart.h"
11#include "grom.h"
12
13typedef UINT8   (*read8z_device_func)  (ATTR_UNUSED device_t *device, ATTR_UNUSED offs_t offset, UINT8 *value);
14
15/* We set the number of slots to 8, although we may have up to 16. From a
16   logical point of view we could have 256, but the operating system only checks
17   the first 16 banks. */
18#define NUMBER_OF_CARTRIDGE_SLOTS 8
19
20typedef int assmfct(running_device *);
21
22DECLARE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_NONE, ti99_cartridge_pcb_none);
23DECLARE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_STD, ti99_cartridge_pcb_std);
24DECLARE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_PAGED, ti99_cartridge_pcb_paged);
25DECLARE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_MINIMEM, ti99_cartridge_pcb_minimem);
26DECLARE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_SUPER, ti99_cartridge_pcb_super);
27DECLARE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_MBX, ti99_cartridge_pcb_mbx);
28DECLARE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_PAGED379I, ti99_cartridge_pcb_paged379i);
29DECLARE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_PAGEDCRU, ti99_cartridge_pcb_pagedcru);
30DECLARE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_GRAMKRACKER, ti99_cartridge_pcb_gramkracker);
31
32DEFINE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_NONE, ti99_cartridge_pcb_none);
33DEFINE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_STD, ti99_cartridge_pcb_std);
34DEFINE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_PAGED, ti99_cartridge_pcb_paged);
35DEFINE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_MINIMEM, ti99_cartridge_pcb_minimem);
36DEFINE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_SUPER, ti99_cartridge_pcb_super);
37DEFINE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_MBX, ti99_cartridge_pcb_mbx);
38DEFINE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_PAGED379I, ti99_cartridge_pcb_paged379i);
39DEFINE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_PAGEDCRU, ti99_cartridge_pcb_pagedcru);
40DEFINE_LEGACY_CART_SLOT_DEVICE(TI99_CARTRIDGE_PCB_GRAMKRACKER, ti99_cartridge_pcb_gramkracker);
41
42/* Generic TI99 cartridge structure. */
43struct _cartridge_t
44{
45   // PCB device associated to this cartridge. If NULL, the slot is empty.
46   running_device *pcb;
47
48   // ROM page.
49   int rom_page;
50
51   // RAM page.
52   int ram_page;
53
54   // GROM buffer size.
55   int grom_size;
56   
57   // ROM buffer size. All banks have equal sizes.
58   int rom_size;
59   
60   // RAM buffer size. All banks have equal sizes.
61   int ram_size;
62
63   // GROM buffer.
64   UINT8 *grom_ptr;
65
66   // ROM buffer.
67   UINT8 *rom_ptr;
68
69   // ROM buffer for the second bank of paged cartridges.
70   UINT8 *rom2_ptr;
71
72   // RAM buffer. The persistence service is done by the cartridge system.
73   // The RAM space is a consecutive space; all banks are in one buffer.
74   UINT8 *ram_ptr;
75   
76   /* GK support. */
77   UINT16   grom_address;   
78   int      waddr_LSB;
79};
80typedef struct _cartridge_t cartridge_t;
81
82enum
83{
84   TI99CARTINFO_FCT_6000_R = DEVINFO_FCT_DEVICE_SPECIFIC,
85   TI99CARTINFO_FCT_6000_W,
86   TI99CARTINFO_FCT_CRU_R,
87   TI99CARTINFO_FCT_CRU_W,
88   TI99CART_FCT_ASSM,
89   TI99CART_FCT_DISASSM
90};
91
92typedef struct _ti99_multicart_state
93{
94   // Reserves space for all cartridges. This is also used in the legacy
95   // cartridge system, but only for slot 0.
96   cartridge_t cartridge[NUMBER_OF_CARTRIDGE_SLOTS];
97
98   // Determines which slot is currently active. This value is changed when
99   // there are accesses to other GROM base addresses.
100   int    active_slot;
101
102   // Used in order to enforce a special slot. This value is retrieved
103   // from the dipswitch setting. A value of -1 means automatic, that is,
104   // the grom base switch is used. Values 0 .. max refer to the
105   // respective slot.
106   int    fixed_slot;
107
108   // Holds the highest index of a cartridge being plugged in plus one.
109   // If we only have one cartridge inserted, we don't want to get a
110   // selection option, so we just mirror the memory contents.
111   int    next_free_slot;
112   
113   /* GK support. */
114   int      gk_slot;
115   int      gk_guest_slot;
116   
117   /* Legacy support. */
118   // Counts the number of slots which currently contain legacy format
119   // cartridge images.
120   int legacy_slots;
121
122   // Counts the number of slots which currently contain new format
123   // cartridge images.
124   int multi_slots;
125   
126   /* Used to cache the switch settings. */
127   UINT8 gk_switch[8];
128
129   /* Ready line */
130   devcb_resolved_write_line ready;
131   
132} ti99_multicart_state;
133
134#define AUTO -1
135
136/* Access to the pcb. Contained in the token of the pcb instance. */
137struct _ti99_pcb_t
138{
139   /* Read function for this cartridge. */
140   read8z_device_func read;
141
142   /* Write function for this cartridge. */
143   write8_device_func write;
144
145   /* Read function for this cartridge, CRU. */
146   read8z_device_func cruread;
147
148   /* Write function for this cartridge, CRU. */
149   write8_device_func cruwrite;
150
151   /* Link up to the cartridge structure which contains this pcb. */
152   cartridge_t *cartridge;
153
154   /* Function to assemble this cartridge. */
155   assmfct   *assemble;
156
157   /* Function to disassemble this cartridge. */
158   assmfct   *disassemble;
159   
160   /* Points to the (max 5) GROM devices. */
161   running_device *grom[5];
162};
163typedef struct _ti99_pcb_t ti99_pcb_t;
164
165INLINE ti99_multicart_state *get_safe_token(running_device *device)
166{
167   assert(device != NULL);
168   return (ti99_multicart_state *)downcast<legacy_device_base *>(device)->token();
169}
170
171INLINE const ti99_multicart_config *get_config(running_device *device)
172{
173   assert(device != NULL);
174   assert(device->type() == TI99_MULTICART);
175   return (const ti99_multicart_config *) downcast<const legacy_device_config_base &>(device->baseconfig()).inline_config();
176}
177
178INLINE ti99_pcb_t *get_safe_pcb_token(running_device *device)
179{
180   assert(device != NULL);
181   return (ti99_pcb_t *)downcast<legacy_device_base *>(device)->token();
182}
183
184static WRITE_LINE_DEVICE_HANDLER( cart_grom_ready )
185{
186   running_device *cartdev = device->owner()->owner();
187   ti99_multicart_state *cartslots = get_safe_token(cartdev);
188   devcb_call_write_line( &cartslots->ready, state );
189}
190
191/*
192   The console writes the values in this array to cache them.
193*/
194void set_gk_switches(running_device *cartsys, int number, int value)
195{
196   ti99_multicart_state *cartslots = get_safe_token(cartsys);
197   cartslots->gk_switch[number] = value;
198}
199
200static int get_gk_switch(running_device *cartsys, int number)
201{
202   ti99_multicart_state *cartslots = get_safe_token(cartsys);
203   return cartslots->gk_switch[number];
204}
205
206static int in_legacy_mode(running_device *device)
207{
208   ti99_multicart_state *cartslots = (ti99_multicart_state *)downcast<legacy_device_base *>(device)->token();
209   return ((cartslots->legacy_slots>0) && (cartslots->multi_slots==0));
210}
211
212/*
213    Activates a slot in the multi-cartridge extender.
214*/
215static void cartridge_slot_set(running_device *cartsys, UINT8 slotnumber)
216{
217   ti99_multicart_state *cartslots = get_safe_token(cartsys);
218//  if (cartslots->active_slot != slotnumber) printf("Setting cartslot to %d\n", slotnumber);
219   if (cartslots->fixed_slot==AUTO)
220      cartslots->active_slot = slotnumber;
221   else
222      cartslots->active_slot = cartslots->fixed_slot;
223}
224
225static int slot_is_empty(running_device *cartsys, int slotnumber)
226{
227   cartridge_t *cart;
228   ti99_multicart_state *cartslots = get_safe_token(cartsys);
229
230   cart = &cartslots->cartridge[slotnumber];
231
232   if ((cart->rom_size==0) && (cart->ram_size==0) && (cart->grom_size==0))
233      return TRUE;
234   return FALSE;
235}
236
237static void clear_slot(running_device *cartsys, int slotnumber)
238{
239   cartridge_t *cart;
240   ti99_multicart_state *cartslots = get_safe_token(cartsys);
241
242   cart = &cartslots->cartridge[slotnumber];
243
244   cart->rom_size = cart->ram_size = cart->grom_size = 0;
245   cart->rom_ptr = NULL;
246   cart->rom2_ptr = NULL;
247   cart->ram_ptr = NULL;
248}
249
250/*
251    Find the index of the cartridge name. We assume the format
252    <name><number>, i.e. the number is the longest string from the right
253    which can be interpreted as a number.
254*/
255static int get_index_from_tagname(running_device *image)
256{
257   const char *tag = image->tag();
258   int maxlen = strlen(tag);
259   int i;
260   for (i=maxlen-1; i >=0; i--)
261      if (tag[i] < 48 || tag[i] > 57) break;
262
263   return atoi(tag+i+1);
264}
265
266/*
267    Common routine to assemble cartridges from resources.
268*/
269static cartridge_t *assemble_common(running_device *cartslot)
270{
271   /* Pointer to the cartridge structure. */
272   cartridge_t *cartridge;
273   running_device *cartsys = cartslot->owner();
274   ti99_multicart_state *cartslots = get_safe_token(cartsys);
275   running_device *pcb = cartslot->subdevice("pcb");
276   ti99_pcb_t *pcb_def;
277   
278   void *socketcont;
279   int reslength;
280//   int i;
281
282   int slotnumber = get_index_from_tagname(cartslot)-1;
283   assert(slotnumber>=0 && slotnumber<NUMBER_OF_CARTRIDGE_SLOTS);
284
285   /* There is a cartridge in this slot, check the maximum slot number. */
286   if (cartslots->next_free_slot <= slotnumber)
287   {
288      cartslots->next_free_slot = slotnumber+1;
289   }
290   cartridge = &cartslots->cartridge[slotnumber];
291
292   // Get the socket which is retrieved by the multicart instance in
293   // the state of the cartslot instance.
294   socketcont = cartslot_get_socket(cartslot, "grom_socket");
295   reslength = cartslot_get_resource_length(cartslot, "grom_socket");
296   if (socketcont != NULL)
297   {
298      cartridge->grom_ptr = (UINT8 *)socketcont;
299//      printf("grom_socket = %lx\n", cartridge->grom_ptr);
300      cartridge->grom_size = reslength;
301   }
302
303   socketcont = cartslot_get_socket(cartslot, "rom_socket");
304   reslength = cartslot_get_resource_length(cartslot, "rom_socket");
305   if (socketcont != NULL)
306   {
307      cartridge->rom_ptr = (UINT8 *)socketcont;
308      cartridge->rom_size = reslength;
309//      printf("set rom ptr = %lx, romlength = %04x, data = %02x %02x\n", cartridge->rom_ptr, cartridge->rom_size, cartridge->rom_ptr[0], cartridge->rom_ptr[1]);
310   }
311
312   socketcont = cartslot_get_socket(cartslot, "rom2_socket");
313//  reslength = cartslot_get_resource_length(cartslot, "rom2_socket");  /* cannot differ from rom_socket */
314   if (socketcont != NULL)
315   {
316      cartridge->rom2_ptr = (UINT8 *)socketcont;
317   }
318
319   socketcont = cartslot_get_socket(cartslot, "ram_socket");
320   reslength = cartslot_get_resource_length(cartslot, "ram_socket");
321   if (socketcont != NULL)
322   {
323      cartridge->ram_ptr = (UINT8 *)socketcont;
324      cartridge->ram_size = reslength;
325   }
326
327   // Register the GROMs
328   pcb_def = (ti99_pcb_t *)downcast<legacy_device_base *>(pcb)->token();
329   for (int i=0; i < 5; i++) pcb_def->grom[i]= NULL;
330   if (cartridge->grom_size > 0)      pcb_def->grom[0] = pcb->subdevice("grom_3");
331   if (cartridge->grom_size > 0x2000) pcb_def->grom[1] = pcb->subdevice("grom_4");
332   if (cartridge->grom_size > 0x4000) pcb_def->grom[2] = pcb->subdevice("grom_5");
333   if (cartridge->grom_size > 0x6000) pcb_def->grom[3] = pcb->subdevice("grom_6");
334   if (cartridge->grom_size > 0x8000) pcb_def->grom[4] = pcb->subdevice("grom_7");
335   
336   return cartridge;
337}
338
339static void set_pointers(running_device *pcb, int index)
340{
341   running_device *cartsys = pcb->owner()->owner();
342   ti99_multicart_state *cartslots = get_safe_token(cartsys);
343   ti99_pcb_t *pcb_def = (ti99_pcb_t *)downcast<legacy_device_base *>(pcb)->token();
344
345   pcb_def->read = (read8z_device_func)downcast<const legacy_cart_slot_device_config_base *>(&pcb->baseconfig())->get_config_fct(TI99CARTINFO_FCT_6000_R);
346   pcb_def->write = (write8_device_func)downcast<const legacy_cart_slot_device_config_base *>(&pcb->baseconfig())->get_config_fct(TI99CARTINFO_FCT_6000_W);
347   pcb_def->cruread = (read8z_device_func)downcast<const legacy_cart_slot_device_config_base *>(&pcb->baseconfig())->get_config_fct(TI99CARTINFO_FCT_CRU_R);
348   pcb_def->cruwrite = (write8_device_func)downcast<const legacy_cart_slot_device_config_base *>(&pcb->baseconfig())->get_config_fct(TI99CARTINFO_FCT_CRU_W);
349
350    pcb_def->assemble = (assmfct *)downcast<const legacy_cart_slot_device_config_base *>(&pcb->baseconfig())->get_config_fct(TI99CART_FCT_ASSM);
351    pcb_def->disassemble = (assmfct *)downcast<const legacy_cart_slot_device_config_base *>(&pcb->baseconfig())->get_config_fct(TI99CART_FCT_DISASSM);
352
353   pcb_def->cartridge = &cartslots->cartridge[index];
354   pcb_def->cartridge->pcb = pcb;
355}
356
357/*****************************************************************************
358  Cartridge type: None
359    This PCB device is just a pseudo device; the legacy mode is handled
360    by dedicated functions.
361******************************************************************************/
362static DEVICE_START(ti99_pcb_none)
363{
364   /* device is ti99_cartslot:cartridge:pcb */
365   set_pointers(device, get_index_from_tagname(device->owner())-1);
366}
367
368/*****************************************************************************
369  Cartridge type: Standard
370    Most cartridges are built in this type. Every cartridge may contain
371    GROM between 0 and 40 KiB, and ROM with 8 KiB length, no banking.
372******************************************************************************/
373
374static DEVICE_START(ti99_pcb_std)
375{
376   /* device is ti99_cartslot:cartridge:pcb */
377   set_pointers(device, get_index_from_tagname(device->owner())-1);
378}
379
380/*
381    Read handler for the CPU address space of the cartridge
382    Images for this area are found in the rom_sockets.
383*/
384static READ8Z_DEVICE_HANDLER( read_cart_std )
385{
386   /* device is pcb, owner is cartslot (cartridge is only a part of the state of cartslot) */
387   ti99_pcb_t *pcb = get_safe_pcb_token(device);
388   cartridge_t *cartridge = pcb->cartridge;
389   if (cartridge->rom_ptr!=NULL)
390   {
391      // For TI-99/8 we should plan for 16K cartridges. However, none was produced. Well, just ignore this thought,
392      *value = (cartridge->rom_ptr)[offset & 0x1fff]; 
393//      printf("read cartridge rom space (length %04x) %04x = %02x\n", cartridge->rom_size, offset, *value);
394   }
395}
396
397static WRITE8_DEVICE_HANDLER( write_cart_std )
398{
399   logerror("Write access to cartridge ROM at address %04x ignored\n", offset);
400}
401
402/*
403    The standard cartridge assemble routine. We just call the common
404    function here.
405*/
406static int assemble_std(running_device *image)
407{
408   assemble_common(image);
409   return IMAGE_INIT_PASS;
410}
411
412/*
413    Removes pointers and restores the state before plugging in the
414    cartridge.
415    The pointer to the location after the last cartridge is adjusted.
416    As it seems, we can use the same function for the disassembling of all
417    cartridge types.
418*/
419static int disassemble_std(running_device *image)
420{
421   int slotnumber;
422   int i;
423//   cartridge_t *cart;
424   running_device *cartsys = image->owner();
425   ti99_multicart_state *cartslots = get_safe_token(cartsys);
426
427   slotnumber = get_index_from_tagname(image)-1;
428
429   /* Search the highest remaining cartridge. */
430   cartslots->next_free_slot = 0;
431   for (i=NUMBER_OF_CARTRIDGE_SLOTS-1; i >= 0; i--)
432   {
433      if (i != slotnumber)
434      {
435         if (!slot_is_empty(cartsys, i))
436         {
437            cartslots->next_free_slot = i+1;
438            break;
439         }
440      }
441   }
442
443   clear_slot(cartsys, slotnumber);
444
445   return IMAGE_INIT_PASS;
446}
447
448/*****************************************************************************
449  Cartridge type: Paged (Extended Basic)
450    This cartridge consists of GROM memory and 2 pages of standard ROM.
451    The page is set by writing any value to a location in
452    the address area, where an even word offset sets the page to 0 and an
453    odd word offset sets the page to 1 (e.g. 6000 = bank 0, and
454    6002 = bank 1).
455******************************************************************************/
456
457static DEVICE_START(ti99_pcb_paged)
458{
459   /* device is ti99_cartslot:cartridge:pcb */
460   set_pointers(device, get_index_from_tagname(device->owner())-1);
461}
462
463/*
464    Read handler for the CPU address space of the cartridge
465    Images for this area are found in the rom_sockets.
466*/
467static READ8Z_DEVICE_HANDLER( read_cart_paged )
468{
469   /* device is pcb, owner is cartslot */
470   ti99_pcb_t *pcb = get_safe_pcb_token(device);
471   cartridge_t *cartridge = pcb->cartridge;
472   UINT8 *rombank;
473
474   if (cartridge->rom_page==0)
475      rombank = (UINT8*)cartridge->rom_ptr;
476   else
477      rombank = (UINT8*)cartridge->rom2_ptr;
478
479   if (rombank==NULL)
480   {
481      /* TODO: Check for consistency with the GROM memory handling. */
482      *value = 0;
483   }
484   else
485   {
486      *value = rombank[offset & 0x1fff];
487   }
488}
489
490/*
491    Handle paging. Extended Basic switches between ROM banks by
492    using the value of the LSB of the address where any value
493    is written to.
494*/
495static WRITE8_DEVICE_HANDLER( write_cart_paged )
496{
497   ti99_pcb_t *pcb = get_safe_pcb_token(device);
498   cartridge_t *cartridge = pcb->cartridge;
499   cartridge->rom_page = (offset >> 1) & 1;
500}
501
502/*
503    We require paged modules to have at least those two rom banks.
504*/
505static int assemble_paged(running_device *image)
506{
507   cartridge_t *cart;
508
509   cart = assemble_common(image);
510   if (cart->rom_ptr==NULL)
511   {
512      logerror("Missing ROM for paged cartridge");
513      return IMAGE_INIT_FAIL;
514   }
515   if (cart->rom2_ptr==NULL)
516   {
517      logerror("Missing second ROM for paged cartridge");
518      return IMAGE_INIT_FAIL;
519   }
520
521   return IMAGE_INIT_PASS;
522}
523
524/*****************************************************************************
525  Cartridge type: Mini Memory
526    GROM: 6 KiB (occupies G>6000 to G>7800)
527    ROM: 4 KiB (romfile is actually 8 K long, second half with zeros, 0x6000-0x6fff)
528    persistent RAM: 4 KiB (0x7000-0x7fff)
529******************************************************************************/
530
531static DEVICE_START(ti99_pcb_minimem)
532{
533   set_pointers(device, get_index_from_tagname(device->owner())-1);
534}
535
536static READ8Z_DEVICE_HANDLER( read_cart_minimem )
537{
538   /* device is pcb, owner is cartslot */
539   ti99_pcb_t *pcb = get_safe_pcb_token(device);
540   cartridge_t *cartridge = pcb->cartridge;
541
542   if ((offset & 0xf000)==0x6000)
543   {
544      *value = (cartridge->rom_ptr==NULL)? 0 : (cartridge->rom_ptr)[offset & 0x0fff];
545   }
546   else
547   {
548      *value = (cartridge->ram_ptr==NULL)? 0 : (cartridge->ram_ptr)[offset & 0x0fff];
549   }
550}
551
552/*
553    Mini Memory cartridge write operation. RAM is located at 0x7000.
554*/
555static WRITE8_DEVICE_HANDLER( write_cart_minimem )
556{
557   ti99_pcb_t *pcb = get_safe_pcb_token(device);
558   cartridge_t *cartridge = pcb->cartridge;
559
560   if (offset < 0x7000)
561   {
562      logerror("Write access to cartridge ROM at address %04x ignored", offset);
563   }
564   else
565   {
566      if (cartridge->ram_ptr==NULL)
567      {
568         logerror("No cartridge RAM at address %04x", offset);
569         /* TODO: Check for consistency with the GROM memory handling. */
570      }
571      else
572      {
573         (cartridge->ram_ptr)[offset-0x7000] = data;
574      }
575   }
576}
577
578static int assemble_minimem(running_device *image)
579{
580   cartridge_t *cart;
581
582   cart = assemble_common(image);
583   if (cart->grom_size==0)
584   {
585      logerror("Missing GROM for Mini Memory");
586      // should not fail here because there may be variations of
587      // cartridges which do not use all parts
588//      return IMAGE_INIT_FAIL;
589   }
590   if (cart->rom_size==0)
591   {
592      logerror("Missing ROM for Mini Memory");
593//      return IMAGE_INIT_FAIL;
594   }
595   if (cart->ram_size==0)
596   {
597      logerror("Missing RAM for Mini Memory");
598//      return IMAGE_INIT_FAIL;
599   }
600
601   return IMAGE_INIT_PASS;
602}
603
604/*****************************************************************************
605  Cartridge type: SuperSpace II
606    SuperSpace cartridge type. SuperSpace is intended as a user-definable
607    blank cartridge containing buffered RAM
608    It has an Editor/Assembler GROM which helps the user to load
609    the user program into the cartridge. If the user program has a suitable
610    header, the console recognizes the cartridge as runnable, and
611    assigns a number in the selection screen.
612    Switching the RAM banks in this cartridge is achieved by setting
613    CRU bits (the system serial interface).
614
615    GROM: Editor/Assembler GROM
616    ROM: none
617    persistent RAM: 32 KiB (0x6000-0x7fff, 4 banks)
618    Switching the bank is done via CRU write
619******************************************************************************/
620
621static DEVICE_START(ti99_pcb_super)
622{
623   set_pointers(device, get_index_from_tagname(device->owner())-1);
624}
625
626/*
627    The CRU read handler. The CRU is a serial interface in the console.
628    Using the CRU we can switch the banks in the SuperSpace cartridge.
629*/
630static READ8Z_DEVICE_HANDLER( read_cart_cru )
631{
632   ti99_pcb_t *pcb = get_safe_pcb_token(device);
633   cartridge_t *cartridge = pcb->cartridge;
634   // offset is the bit number. The CRU base address is already divided  by 2.
635
636   // ram_page contains the bank number. We have a maximum of
637   // 4 banks; the Super Space II manual says:
638   //
639   // Banks are selected by writing a bit pattern to CRU address >0800:
640   //
641   // Bank #   Value
642   // 0        >02  = 0000 0010
643   // 1        >08  = 0000 1000
644   // 2        >20  = 0010 0000
645   // 3        >80  = 1000 0000
646   //
647   // With the bank number (0, 1, 2, or 3) in R0:
648   //
649   // BNKSW   LI    R12,>0800   Set CRU address
650   //         LI    R1,2        Load Shift Bit
651   //         SLA   R0,1        Align Bank Number
652   //         JEQ   BNKS1       Skip shift if Bank 0
653   //         SLA   R1,0        Align Shift Bit
654   // BNKS1   LDCR  R1,0        Switch Banks
655   //         SRL   R0,1        Restore Bank Number (optional)
656   //         RT
657   printf("Superspace: CRU accessed at %04x\n", offset);
658   if ((offset & 1) == 0 || offset > 7)
659      *value = 0;
660
661   // CRU addresses are only 1 bit wide. Bytes are transferred from LSB
662   // to MSB. That is, 8 bit are eight consecutive addresses. */
663   *value = (cartridge->ram_page == (offset-1)/2);
664}
665
666static WRITE8_DEVICE_HANDLER( write_cart_cru )
667{
668   ti99_pcb_t *pcb = get_safe_pcb_token(device);
669   cartridge_t *cartridge = pcb->cartridge;
670   // data is bit
671   // offset is address
672   printf("Superspace: CRU accessed at %04x\n", offset);
673   if (offset < 8)
674   {
675      if (data != 0)
676         cartridge->ram_page = (offset-1)/2;
677   }
678}
679
680/*
681    SuperSpace RAM read operation. RAM is located at 0x6000 to 0x7fff
682    as 4 banks of 8 KiB each
683*/
684static READ8Z_DEVICE_HANDLER( read_cart_super )
685{
686   /* device is pcb, owner is cartslot */
687   ti99_pcb_t *pcb = get_safe_pcb_token(device);
688   cartridge_t *cartridge = pcb->cartridge;
689   offs_t boffset;
690
691   if (cartridge->ram_ptr==NULL)
692   {
693      *value = 0;
694   }
695   else
696   {
697      boffset = cartridge->ram_page * 0x2000 + (offset & 0x1fff);
698      *value = (cartridge->ram_ptr)[boffset];
699   }
700}
701
702/*
703    SuperSpace RAM write operation. RAM is located at 0x6000 to 0x7fff
704    as 4 banks of 8 KiB each
705*/
706static WRITE8_DEVICE_HANDLER( write_cart_super )
707{
708   ti99_pcb_t *pcb = get_safe_pcb_token(device);
709   cartridge_t *cartridge = pcb->cartridge;
710   offs_t boffset;
711
712   if (cartridge->ram_ptr==NULL)
713   {
714      logerror("No cartridge RAM at address %04x", offset);
715   }
716   else
717   {
718      boffset = cartridge->ram_page * 0x2000 + (offset & 0x1fff);
719      (cartridge->ram_ptr)[boffset] = data;
720   }
721}
722
723static int assemble_super(running_device *image)
724{
725   cartridge_t *cart;
726
727   cart = assemble_common(image);
728   if (cart->ram_size==0)
729   {
730      logerror("Missing RAM for SuperSpace");
731      return IMAGE_INIT_FAIL;
732   }
733   return IMAGE_INIT_PASS;
734}
735
736/*****************************************************************************
737  Cartridge type: MBX
738    GROM: up to 40 KiB
739    ROM: up to 16 KiB (in up to 2 banks of 8KiB each)
740    RAM: 1022 B (0x6c00-0x6ffd, overrides ROM in that area)
741    ROM mapper: 6ffe
742
743    Note that some MBX cartridges assume the presence of the MBX system
744    (additional console) and will not run without it. The MBX hardware is
745    not emulated yet.
746******************************************************************************/
747
748static DEVICE_START(ti99_pcb_mbx)
749{
750   set_pointers(device, get_index_from_tagname(device->owner())-1);
751}
752
753static READ8Z_DEVICE_HANDLER( read_cart_mbx )
754{
755   /* device is pcb, owner is cartslot */
756   ti99_pcb_t *pcb = get_safe_pcb_token(device);
757   cartridge_t *cartridge = pcb->cartridge;
758
759   if ((offset & 0x1c00)==0x0c00)
760   {
761      // This is the RAM area which overrides any ROM. There is no
762      // known banking behavior for the RAM, so we must assume that
763      // there is only one bank.
764      if (cartridge->ram_ptr != NULL)
765         *value = (cartridge->ram_ptr)[offset & 0x03ff];
766   }
767   else
768   {
769      if (cartridge->rom_ptr != NULL)
770         *value = (cartridge->rom_ptr)[(offset & 0x1fff)+ cartridge->rom_page*0x2000];
771   }
772}
773
774/*
775    MBX write operation.
776*/
777static WRITE8_DEVICE_HANDLER( write_cart_mbx )
778{
779   ti99_pcb_t *pcb = get_safe_pcb_token(device);
780   cartridge_t *cartridge = pcb->cartridge;
781
782   if (offset == 0x6ffe)
783   {
784      cartridge->rom_page = data & 1;
785      return;
786   }
787
788   if ((offset & 0x1c00)==0x0c00)
789   {
790      if (cartridge->ram_ptr == NULL)   return;
791      cartridge->ram_ptr[offset - 0x6c00] = data;
792   }
793}
794
795
796static int assemble_mbx(running_device *image)
797{
798   assemble_common(image);
799   return IMAGE_INIT_PASS;
800}
801
802/*****************************************************************************
803  Cartridge type: paged379i
804    This cartridge consists of one 16 KiB, 32 KiB, 64 KiB, or 128 KiB EEPROM
805    which is organised in 2, 4, 8, or 16 pages of 8 KiB each. The complete
806    memory contents must be stored in one dump file.
807    The pages are selected by writing a value to some memory locations. Due to
808    using the inverted outputs of the LS379 latch, setting the inputs of the
809    latch to all 0 selects the highest bank, while setting to all 1 selects the
810    lowest. There are some cartridges (16 KiB) which are using this scheme, and
811    there are new hardware developments mainly relying on this scheme.
812
813    Writing to       selects page (16K/32K/64K/128K)
814    >6000            1 / 3 / 7 / 15
815    >6002            0 / 2 / 6 / 14
816    >6004            1 / 1 / 5 / 13
817    >6006            0 / 0 / 4 / 12
818    >6008            1 / 3 / 3 / 11
819    >600A            0 / 2 / 2 / 10
820    >600C            1 / 1 / 1 / 9
821    >600E            0 / 0 / 0 / 8
822    >6010            1 / 3 / 7 / 7
823    >6012            0 / 2 / 6 / 6
824    >6014            1 / 1 / 5 / 5
825    >6016            0 / 0 / 4 / 4
826    >6018            1 / 3 / 3 / 3
827    >601A            0 / 2 / 2 / 2
828    >601C            1 / 1 / 1 / 1
829    >601E            0 / 0 / 0 / 0
830
831******************************************************************************/
832
833static DEVICE_START(ti99_pcb_paged379i)
834{
835   /* device is ti99_cartslot:cartridge:pcb */
836   set_pointers(device, get_index_from_tagname(device->owner())-1);
837}
838
839/*
840    Read handler for the CPU address space of the cartridge
841    Images for this area are found in the rom_sockets.
842*/
843static READ8Z_DEVICE_HANDLER( read_cart_paged379i )
844{
845   /* device is pcb, owner is cartslot */
846   ti99_pcb_t *pcb = get_safe_pcb_token(device);
847   cartridge_t *cartridge = pcb->cartridge;
848
849   if (cartridge->rom_ptr!=NULL)
850   {
851      *value = (cartridge->rom_ptr)[cartridge->rom_page*0x2000 + (offset & 0x1fff)];
852   }
853}
854
855/*
856   Determines which bank to set, depending on the size of the ROM. This is
857   some magic code that actually represents different PCB versions.
858*/
859static void set_paged379i_bank(cartridge_t *cartridge, int rompage)
860{
861   int mask = 0;
862   if (cartridge->rom_size > 16384)
863   {
864      if (cartridge->rom_size > 32768)
865      {
866         if (cartridge->rom_size > 65536)
867            mask = 15;
868         else
869            mask = 7;
870      }
871      else
872         mask = 3;
873   }
874   else
875      mask = 1;
876
877   cartridge->rom_page = rompage & mask;
878}
879
880/*
881    Handle paging. We use a LS379 latch for storing the page number. On this
882    PCB, the inverted output of the latch is used, so the order of pages
883    is reversed. (No problem as long as the memory dump is kept exactly
884    in the way it is stored in the EPROM.)
885    The latch can store a value of 4 bits. We adjust the number of
886    significant bits by the size of the memory dump (16K, 32K, 64K).
887*/
888static WRITE8_DEVICE_HANDLER( write_cart_paged379i )
889{
890   ti99_pcb_t *pcb = get_safe_pcb_token(device);
891   cartridge_t *cartridge = pcb->cartridge;
892
893   // Bits: 011x xxxx xxxb bbbx
894   // x = don't care, bbbb = bank
895   set_paged379i_bank(cartridge, 15 - ((offset>>1) & 15));
896}
897
898/*
899    Paged379i modules have one EPROM dump.
900*/
901static int assemble_paged379i(running_device *image)
902{
903   cartridge_t *cart;
904
905   cart = assemble_common(image);
906   if (cart->rom_ptr==NULL)
907   {
908      logerror("Missing ROM for paged cartridge");
909      return IMAGE_INIT_FAIL;
910   }
911   set_paged379i_bank(cart, 15);
912   return IMAGE_INIT_PASS;
913}
914
915/*****************************************************************************
916  Cartridge type: pagedcru
917    This cartridge consists of one 16 KiB, 32 KiB, or 64 KiB EEPROM which is
918    organised in 2, 4, or 8 pages of 8 KiB each. We assume there is only one
919    dump file of the respective size.
920    The pages are selected by writing a value to the CRU. This scheme is
921    similar to the one used for the SuperSpace cartridge, with the exception
922    that we are using ROM only, and we can have up to 8 pages.
923
924    Bank     Value written to CRU>0800
925    0      >0002  = 0000 0000 0000 0010
926    1      >0008  = 0000 0000 0000 1000
927    2      >0020  = 0000 0000 0010 0000
928    3      >0080  = 0000 0000 1000 0000
929    4      >0200  = 0000 0010 0000 0000
930    5      >0800  = 0000 1000 0000 0000
931    6      >2000  = 0010 0000 0000 0000
932    7      >8000  = 1000 0000 0000 0000
933
934******************************************************************************/
935
936static DEVICE_START(ti99_pcb_pagedcru)
937{
938   /* device is ti99_cartslot:cartridge:pcb */
939   set_pointers(device, get_index_from_tagname(device->owner())-1);
940}
941
942/*
943    Read handler for the CPU address space of the cartridge
944    Images for this area are found in the rom_sockets.
945*/
946static READ8Z_DEVICE_HANDLER( read_cart_pagedcru )
947{
948   /* device is pcb, owner is cartslot */
949   ti99_pcb_t *pcb = get_safe_pcb_token(device);
950   cartridge_t *cartridge = pcb->cartridge;
951
952   if (cartridge->rom_ptr!=NULL)
953   {
954      *value = (cartridge->rom_ptr)[cartridge->rom_page*0x2000 + (offset & 0x1fff)];
955   }
956}
957
958/*
959    This type of cartridge does not support writing to the EPROM address
960    space.
961*/
962static WRITE8_DEVICE_HANDLER( write_cart_pagedcru )
963{
964   return;
965}
966
967/*
968    The CRU read handler. The CRU is a serial interface in the console.
969    Using the CRU we can switch the banks in the SuperSpace cartridge.
970    For documentation see the corresponding cru function above. Note we are
971    using rom_page here.
972*/
973static READ8Z_DEVICE_HANDLER( read_cart_cru_paged )
974{
975   ti99_pcb_t *pcb = get_safe_pcb_token(device);
976   cartridge_t *cartridge = pcb->cartridge;
977
978   int page = cartridge->rom_page;
979   if ((offset & 0xf800)==0x0800)
980   {
981      int bit = (offset & 0x001e)/2;
982      if (bit != 0)
983      {
984         page = page-(bit/2);  // 4 page flags per 8 bits
985      }     
986      *value = 1 << (page*2+1);
987   }
988}
989
990static WRITE8_DEVICE_HANDLER( write_cart_cru_paged )
991{
992   ti99_pcb_t *pcb = get_safe_pcb_token(device);
993   cartridge_t *cartridge = pcb->cartridge;
994
995   if ((offset & 0xf800)==0x0800)
996   {
997      int bit = (offset & 0x001e)/2;
998      if (data != 0 && bit > 0)
999      {
1000         cartridge->rom_page = (bit-1)/2;
1001      }
1002   }
1003}
1004
1005/*
1006    Pagedcru modules have one EPROM dump.
1007*/
1008static int assemble_pagedcru(running_device *image)
1009{
1010   cartridge_t *cart;
1011
1012   cart = assemble_common(image);
1013   if (cart->rom_ptr==NULL)
1014   {
1015      logerror("Missing ROM for pagedcru cartridge");
1016      return IMAGE_INIT_FAIL;
1017   }
1018   cart->rom_page = 0;
1019   return IMAGE_INIT_PASS;
1020}
1021
1022/*****************************************************************************
1023  Cartridge type: gramkracker
1024******************************************************************************/
1025
1026static DEVICE_START(ti99_pcb_gramkracker)
1027{
1028   /* device is ti99_cartslot:cartridge:pcb */
1029//  printf("DEVICE_START(ti99_pcb_pagedcru), tag of device=%s\n", device->tag());
1030   set_pointers(device, get_index_from_tagname(device->owner())-1);
1031}
1032
1033/*
1034    The GRAM Kracker contains one GROM and several buffered RAM chips
1035*/
1036static int assemble_gramkracker(running_device *image)
1037{
1038   cartridge_t *cart;
1039   int id,i;
1040
1041   running_device *cartsys = image->owner();
1042   ti99_multicart_state *cartslots = get_safe_token(cartsys);
1043
1044   cart = assemble_common(image);
1045
1046   if (cart->grom_ptr==NULL)
1047   {
1048      logerror("Missing loader GROM for GRAM Kracker system");
1049      return IMAGE_INIT_FAIL;
1050   }
1051
1052   if (cart->ram_size < 81920)
1053   {
1054      logerror("Missing or insufficient RAM for GRAM Kracker system");
1055      return IMAGE_INIT_FAIL;
1056   }
1057
1058   // Get slot number
1059   id = get_index_from_tagname(image);
1060   cartslots->gk_slot = id-1;
1061   cartslots->gk_guest_slot = -1;
1062   // The first cartridge that is still plugged in is the "guest" of the
1063   // GRAM Kracker
1064   for (i=0; i < NUMBER_OF_CARTRIDGE_SLOTS; i++)
1065   {
1066      if (!slot_is_empty(cartsys, i) && (i != cartslots->gk_slot))
1067      {
1068         cartslots->gk_guest_slot = i;
1069         break;
1070      }
1071   }
1072   return IMAGE_INIT_PASS;
1073}
1074
1075/*
1076    Unplugs the GRAM Kracker. The "guest" is still plugged in, but will be
1077    treated as normal.
1078*/
1079static int disassemble_gramkracker(running_device *cartslot)
1080{
1081   running_device *cartsys = cartslot->owner();
1082   ti99_multicart_state *cartslots = get_safe_token(cartsys);
1083
1084   int slotnumber = get_index_from_tagname(cartslot)-1;
1085   assert(slotnumber>=0 && slotnumber<NUMBER_OF_CARTRIDGE_SLOTS);
1086
1087   cartslots->gk_slot = -1;
1088   cartslots->gk_guest_slot = -1;
1089
1090   return disassemble_std(cartslot);
1091}
1092
1093
1094/*****************************************************************************
1095  Device metadata
1096******************************************************************************/
1097
1098/*
1099   Get the pointer to the GROM data from the cartridge. Called by the GROM.
1100*/
1101static UINT8 *get_grom_ptr(running_device *device)
1102{
1103   ti99_pcb_t *pcb = get_safe_pcb_token(device);
1104   return pcb->cartridge->grom_ptr;
1105}
1106
1107static MACHINE_CONFIG_FRAGMENT(ti99_cart_common)
1108   MDRV_GROM_ADD_P( "grom_3", 3, get_grom_ptr, 0x0000, 0x1800, cart_grom_ready )
1109   MDRV_GROM_ADD_P( "grom_4", 4, get_grom_ptr, 0x2000, 0x1800, cart_grom_ready )
1110   MDRV_GROM_ADD_P( "grom_5", 5, get_grom_ptr, 0x4000, 0x1800, cart_grom_ready )
1111   MDRV_GROM_ADD_P( "grom_6", 6, get_grom_ptr, 0x6000, 0x1800, cart_grom_ready )
1112   MDRV_GROM_ADD_P( "grom_7", 7, get_grom_ptr, 0x8000, 0x1800, cart_grom_ready )
1113MACHINE_CONFIG_END
1114
1115static DEVICE_GET_INFO(ti99_cart_common)
1116{
1117   switch(state)
1118   {
1119      /* --- the following bits of info are returned as 64-bit signed integers --- */
1120      case DEVINFO_INT_TOKEN_BYTES:
1121         info->i = sizeof(ti99_pcb_t);
1122         break;
1123      case DEVINFO_INT_INLINE_CONFIG_BYTES:
1124         info->i = 0;
1125         break;
1126         
1127      case DEVINFO_PTR_MACHINE_CONFIG:     
1128         info->machine_config = MACHINE_CONFIG_NAME(ti99_cart_common);
1129         break;
1130
1131      /* --- the following bits of info are returned as pointers to functions --- */
1132      case DEVINFO_FCT_START:
1133         info->start = DEVICE_START_NAME(ti99_pcb_std);
1134         break;
1135      case DEVINFO_FCT_STOP:
1136         /* Nothing */
1137         break;
1138      case DEVINFO_FCT_RESET:
1139         /* Nothing */
1140         break;
1141      case TI99CARTINFO_FCT_6000_R:
1142         info->f = (genf *) read_cart_std; break;
1143
1144      case TI99CARTINFO_FCT_6000_W:
1145         info->f = (genf *) write_cart_std; break;
1146
1147      case TI99CARTINFO_FCT_CRU_R:
1148         /* Nothing */
1149         break;
1150
1151      case TI99CARTINFO_FCT_CRU_W:
1152         /* Nothing */
1153         break;
1154
1155      case TI99CART_FCT_ASSM:
1156         info->f = (genf *) assemble_std;
1157         break;
1158
1159      case TI99CART_FCT_DISASSM:
1160         info->f = (genf *) disassemble_std;
1161         break;
1162
1163      /* --- the following bits of info are returned as NULL-terminated strings --- */
1164      case DEVINFO_STR_NAME:
1165         strcpy(info->s, "TI99 standard cartridge pcb");
1166         break;
1167      case DEVINFO_STR_FAMILY:
1168         strcpy(info->s, "TI99 cartridge pcb");
1169         break;
1170      case DEVINFO_STR_VERSION:
1171         strcpy(info->s, "1.0");
1172         break;
1173      case DEVINFO_STR_SOURCE_FILE:
1174         strcpy(info->s, __FILE__);
1175         break;
1176      case DEVINFO_STR_CREDITS:
1177         /* Nothing */
1178         break;
1179   }
1180}
1181
1182DEVICE_GET_INFO(ti99_cartridge_pcb_none)
1183{
1184   switch(state)
1185   {
1186      case DEVINFO_FCT_START:
1187         info->start = DEVICE_START_NAME(ti99_pcb_none);
1188         break;
1189
1190      case DEVINFO_STR_NAME:
1191         strcpy(info->s, "TI99 empty cartridge");
1192         break;
1193
1194      // Don't create GROMs
1195      case DEVINFO_PTR_MACHINE_CONFIG:     
1196         break;
1197         
1198      default:
1199         DEVICE_GET_INFO_CALL(ti99_cart_common);
1200         break;
1201   }
1202}
1203
1204DEVICE_GET_INFO(ti99_cartridge_pcb_std)
1205{
1206   DEVICE_GET_INFO_CALL(ti99_cart_common);
1207}
1208
1209DEVICE_GET_INFO(ti99_cartridge_pcb_paged)
1210{
1211   switch(state)
1212   {
1213      case DEVINFO_FCT_START:
1214         info->start = DEVICE_START_NAME(ti99_pcb_paged);
1215         break;
1216
1217      case TI99CART_FCT_ASSM:
1218         info->f = (genf *) assemble_paged;
1219         break;
1220
1221      case TI99CARTINFO_FCT_6000_R:
1222         info->f = (genf *) read_cart_paged;
1223         break;
1224
1225      case TI99CARTINFO_FCT_6000_W:
1226         info->f = (genf *) write_cart_paged;
1227         break;
1228
1229      case DEVINFO_STR_NAME:
1230         strcpy(info->s, "TI99 paged cartridge pcb");
1231         break;
1232
1233      default:
1234         DEVICE_GET_INFO_CALL(ti99_cart_common);
1235         break;
1236   }
1237}
1238
1239DEVICE_GET_INFO(ti99_cartridge_pcb_minimem)
1240{
1241   switch(state)
1242   {
1243      case DEVINFO_FCT_START:
1244         info->start = DEVICE_START_NAME(ti99_pcb_minimem);
1245         break;
1246
1247      case TI99CART_FCT_ASSM:
1248         info->f = (genf *) assemble_minimem;
1249         break;
1250      case TI99CARTINFO_FCT_6000_R:
1251         info->f = (genf *) read_cart_minimem;
1252         break;
1253      case TI99CARTINFO_FCT_6000_W:
1254         info->f = (genf *) write_cart_minimem;
1255         break;
1256         
1257      case DEVINFO_STR_NAME:
1258         strcpy(info->s, "TI99 MiniMemory cartridge pcb");
1259         break;
1260
1261      default:
1262         DEVICE_GET_INFO_CALL(ti99_cart_common);
1263         break;
1264   }
1265}
1266
1267DEVICE_GET_INFO(ti99_cartridge_pcb_super)
1268{
1269   switch(state)
1270   {
1271      case DEVINFO_FCT_START:
1272         info->start = DEVICE_START_NAME(ti99_pcb_super);
1273         break;
1274
1275      case TI99CART_FCT_ASSM:
1276         info->f = (genf *) assemble_super;
1277         break;
1278      case TI99CARTINFO_FCT_6000_R:
1279         info->f = (genf *) read_cart_super;
1280         break;
1281      case TI99CARTINFO_FCT_6000_W:
1282         info->f = (genf *) write_cart_super;
1283         break;
1284      case TI99CARTINFO_FCT_CRU_R:
1285         info->f = (genf *) read_cart_cru;
1286         break;
1287      case TI99CARTINFO_FCT_CRU_W:
1288         info->f = (genf *) write_cart_cru;
1289         break;
1290
1291      // Don't create GROMs
1292      case DEVINFO_PTR_MACHINE_CONFIG:     
1293         break;
1294
1295      case DEVINFO_STR_NAME:
1296         strcpy(info->s, "TI99 SuperSpace cartridge pcb");
1297         break;
1298
1299      default:
1300         DEVICE_GET_INFO_CALL(ti99_cart_common);
1301         break;
1302   }
1303}
1304
1305DEVICE_GET_INFO(ti99_cartridge_pcb_mbx)
1306{
1307   switch(state)
1308   {
1309      case DEVINFO_FCT_START:
1310         info->start = DEVICE_START_NAME(ti99_pcb_mbx);
1311         break;
1312
1313      case TI99CART_FCT_ASSM:
1314         info->f = (genf *) assemble_mbx;
1315         break;
1316      case TI99CARTINFO_FCT_6000_R:
1317         info->f = (genf *) read_cart_mbx;
1318         break;
1319      case TI99CARTINFO_FCT_6000_W:
1320         info->f = (genf *) write_cart_mbx;
1321         break;
1322
1323      case DEVINFO_STR_NAME:
1324         strcpy(info->s, "TI99 MBX cartridge pcb");
1325         break;
1326
1327      default:
1328         DEVICE_GET_INFO_CALL(ti99_cart_common);
1329         break;
1330   }
1331}
1332
1333DEVICE_GET_INFO(ti99_cartridge_pcb_paged379i)
1334{
1335   switch(state)
1336   {
1337      case DEVINFO_FCT_START:
1338         info->start = DEVICE_START_NAME(ti99_pcb_paged379i);
1339         break;
1340
1341      case TI99CART_FCT_ASSM:
1342         info->f = (genf *) assemble_paged379i; break;
1343
1344      case TI99CARTINFO_FCT_6000_R:
1345         info->f = (genf *) read_cart_paged379i;
1346         break;
1347
1348      case TI99CARTINFO_FCT_6000_W:
1349         info->f = (genf *) write_cart_paged379i;
1350         break;
1351
1352      case DEVINFO_STR_NAME:
1353         strcpy(info->s, "TI99 paged379i cartridge pcb");
1354         break;
1355
1356      default:
1357         DEVICE_GET_INFO_CALL(ti99_cart_common);
1358         break;
1359   }
1360}
1361
1362DEVICE_GET_INFO(ti99_cartridge_pcb_pagedcru)
1363{
1364   switch(state)
1365   {
1366      case DEVINFO_FCT_START:
1367         info->start = DEVICE_START_NAME(ti99_pcb_pagedcru);
1368         break;
1369
1370      case TI99CART_FCT_ASSM:
1371         info->f = (genf *) assemble_pagedcru;
1372         break;
1373
1374      case TI99CARTINFO_FCT_6000_R:
1375         info->f = (genf *) read_cart_pagedcru;
1376         break;
1377
1378      case TI99CARTINFO_FCT_6000_W:
1379         info->f = (genf *) write_cart_pagedcru;
1380         break;
1381
1382      case TI99CARTINFO_FCT_CRU_R:
1383         info->f = (genf *) read_cart_cru_paged;
1384         break;
1385      case TI99CARTINFO_FCT_CRU_W:
1386         info->f = (genf *) write_cart_cru_paged;
1387         break;
1388
1389      case DEVINFO_STR_NAME:
1390         strcpy(info->s, "TI99 pagedcru cartridge pcb");
1391         break;
1392
1393      default:
1394         DEVICE_GET_INFO_CALL(ti99_cart_common);
1395         break;
1396   }
1397}
1398
1399DEVICE_GET_INFO(ti99_cartridge_pcb_gramkracker)
1400{
1401   switch(state)
1402   {
1403      case DEVINFO_FCT_START:
1404         info->start = DEVICE_START_NAME(ti99_pcb_gramkracker);
1405         break;
1406
1407      case TI99CART_FCT_ASSM:
1408         info->f = (genf *) assemble_gramkracker;
1409         break;
1410
1411      case TI99CART_FCT_DISASSM:
1412         info->f = (genf *) disassemble_gramkracker;
1413         break;
1414
1415      case DEVINFO_STR_NAME:
1416         strcpy(info->s, "TI99 GRAM Kracker system");
1417         break;
1418
1419      default:
1420         DEVICE_GET_INFO_CALL(ti99_cart_common);
1421         break;
1422   }
1423}
1424
1425/*****************************************************************************
1426  The cartridge handling of the multi-cartridge system.
1427  Every cartridge contains a PCB device. The memory handlers delegate the calls
1428  to the respective handlers of the cartridges.
1429******************************************************************************/
1430/*
1431    Initialize a cartridge. Each cartridge contains a PCB device.
1432*/
1433static DEVICE_START( ti99_cartridge )
1434{
1435   cartslot_t *cart = (cartslot_t *)downcast<legacy_device_base *>(device)->token();
1436
1437   /* find the PCB device */
1438   cart->pcb_device = device->subdevice(TAG_PCB);
1439}
1440
1441/*
1442    Load the cartridge image files. Apart from reading, we set pointers
1443    to the image files so that during runtime we do not need search
1444    operations.
1445*/
1446static DEVICE_IMAGE_LOAD( ti99_cartridge )
1447{
1448   running_device *pcbdev = cartslot_get_pcb(&image.device());
1449//   running_device *cartsys = image.device().owner();
1450//   ti99_multicart_state *cartslots = get_safe_token(cartsys);
1451
1452   int result;
1453
1454   if (pcbdev != NULL)
1455   {
1456      /* If we are here, we have a multicart. */
1457      ti99_pcb_t *pcb = (ti99_pcb_t *)downcast<legacy_device_base *>(pcbdev)->token();
1458      cartslot_t *cart = (cartslot_t *)downcast<legacy_device_base *>(&image.device())->token();
1459
1460      /* try opening this as a multicart */
1461      // This line requires that cartslot_t be included in cartslot.h,
1462      // otherwise one cannot make use of multicart handling within such a
1463      // custom LOAD function.
1464      multicart_open_error me = multicart_open(image.filename(), image.device().machine->gamedrv->name, MULTICART_FLAGS_LOAD_RESOURCES, &cart->mc);
1465
1466      // Now that we have loaded the image files, let the PCB put them all
1467      // together. This means we put the images in a structure which allows
1468      // for a quick access by the memory handlers. Every PCB defines an
1469      // own assembly method.
1470      if (me == MCERR_NONE)
1471         result = pcb->assemble(image);
1472      else
1473         fatalerror("Error loading multicart: %s", multicart_error_text(me));
1474   }
1475   else
1476   {
1477      fatalerror("Error loading multicart: no pcb found.");
1478   }
1479   return result;
1480}
1481
1482/*
1483    This is called when the cartridge is unplugged (or the emulator is
1484    stopped).
1485*/
1486static DEVICE_IMAGE_UNLOAD( ti99_cartridge )
1487{
1488   running_device *pcbdev;
1489//   ti99_multicart_state *cartslots = (ti99_multicart_state *)downcast<legacy_device_base *>(image.device().owner())->token();
1490
1491   if (downcast<legacy_device_base *>(&image.device())->token() == NULL)
1492   {
1493      // This means something went wrong during the pcb
1494      // identification (e.g. one of the cartridge files was not
1495      // found). We do not need to (and cannot) unload the cartridge.
1496      return;
1497   }
1498   pcbdev = cartslot_get_pcb(image);
1499
1500   if (pcbdev != NULL)
1501   {
1502      ti99_pcb_t *pcb = (ti99_pcb_t *)downcast<legacy_device_base *>(pcbdev)->token();
1503      cartslot_t *cart = (cartslot_t *)downcast<legacy_device_base *>(&image.device())->token();
1504
1505      if (cart->mc != NULL)
1506      {
1507         /* Remove pointers and de-big-endianize RAM contents. */
1508         pcb->disassemble(image);
1509
1510         // Close the multicart; all RAM resources will be
1511         // written to disk
1512         multicart_close(cart->mc);
1513         cart->mc = NULL;
1514
1515      }
1516   }
1517}
1518
1519/*****************************************************************************
1520  The overall multi-cartridge slot system. It contains instances of
1521  cartridges which contain PCB devices. The memory handlers delegate the calls
1522  to the respective handlers of the cartridges.
1523
1524  Note that the term "multi-cartridge system" and "multicart" are not the same:
1525  A "multicart" may contain multiple resources, organized on a PCB. The multi-
1526  cart system may thus host multiple multicarts.
1527
1528  Actually, the name of the device should be changed (however, the device name
1529  length is limited)
1530******************************************************************************/
1531
1532static READ8Z_DEVICE_HANDLER( ti99_cart_gk_rz );
1533static WRITE8_DEVICE_HANDLER( ti99_cart_gk_w );
1534static void cartridge_gram_kracker_writeg(running_device *cartsys, int offset, UINT8 data);
1535static void cartridge_gram_kracker_readg(running_device *device, UINT8 *value);
1536static READ8Z_DEVICE_HANDLER( ti99_cart_cru_gk_rz );
1537static WRITE8_DEVICE_HANDLER( ti99_cart_cru_gk_w );
1538
1539/*
1540    Instantiation of a multicart system for the TI family.
1541*/
1542static DEVICE_START(ti99_multicart)
1543{
1544   int i;
1545   ti99_multicart_state *cartslots = (ti99_multicart_state *)downcast<legacy_device_base *>(device)->token();
1546   const ti99_multicart_config* cartconf = (const ti99_multicart_config*)get_config(device);
1547
1548   cartslots->active_slot = 0;
1549   cartslots->next_free_slot = 0;
1550
1551   for (i=0; i < NUMBER_OF_CARTRIDGE_SLOTS; i++)
1552   {
1553      cartslots->cartridge[i].pcb = NULL;
1554      clear_slot(device, i);
1555   }
1556   
1557   devcb_write_line ready = DEVCB_LINE(cartconf->ready);
1558
1559   devcb_resolve_write_line(&cartslots->ready, &ready, device);
1560   
1561   // The cartslot system is initialized now. The cartridges themselves
1562   // need to check whether their parts are available.
1563}
1564
1565static DEVICE_STOP(ti99_multicart)
1566{
1567//  printf("DEVICE_STOP(ti99_multicart)\n");
1568}
1569
1570static DEVICE_RESET(ti99_multicart)
1571{
1572   // Consider to propagate RESET to cartridges.
1573   // However, schematics do not reveal any pin for resetting a cartridge;
1574   // the reset line is an input used when plugging in a cartridge.
1575
1576   ti99_multicart_state *cartslots = (ti99_multicart_state *)downcast<legacy_device_base *>(device)->token();
1577   int slotnumber = input_port_read(device->machine, "CARTSLOT");
1578   cartslots->fixed_slot = slotnumber-1; /* auto = -1 */
1579}
1580
1581/*
1582    Accesses the ROM regions of the cartridge for reading.
1583*/
1584READ8Z_DEVICE_HANDLER( gromportr_rz )
1585{
1586   ti99_multicart_state *cartslots = (ti99_multicart_state *) downcast<legacy_device_base *>(device)->token();
1587   int slot = cartslots->active_slot;
1588   cartridge_t *cart;
1589
1590   // Handle GRAM Kracker
1591   // We could also consider to use a flag, but input_port_read uses
1592   // a hashtable, so this should not be too slow
1593   if ((cartslots->gk_slot != -1) && (input_port_read(device->machine, "CARTSLOT")==CART_GK))
1594   {
1595      ti99_cart_gk_rz(device, offset, value);
1596      return;
1597   }
1598   
1599   /* Sanity check. Higher slots are always empty. */
1600   if (slot >= NUMBER_OF_CARTRIDGE_SLOTS)
1601      return;
1602
1603   // Same as above (GROM read)
1604   if (cartslots->fixed_slot==AUTO && cartslots->next_free_slot==1)
1605      slot=0;
1606
1607   cart = &cartslots->cartridge[slot];
1608
1609   if (!slot_is_empty(device, slot))
1610   {
1611//      printf("try it on slot %d\n", slot);
1612      ti99_pcb_t *pcbdef = (ti99_pcb_t *)downcast<legacy_device_base *>(cart->pcb)->token();
1613      (*pcbdef->read)(cart->pcb, offset, value);
1614   }
1615}
1616
1617/*
1618    Accesses the ROM regions of the cartridge for writing.
1619*/
1620WRITE8_DEVICE_HANDLER( gromportr_w )
1621{
1622   ti99_multicart_state *cartslots = (ti99_multicart_state *) downcast<legacy_device_base *>(device)->token();
1623   int slot = cartslots->active_slot;
1624   cartridge_t *cart;
1625
1626   // Handle GRAM Kracker
1627   if ((cartslots->gk_slot != -1) && (input_port_read(device->machine, "CARTSLOT")==CART_GK))
1628      ti99_cart_gk_w(device, offset, data);
1629
1630   /* Sanity check. Higher slots are always empty. */
1631   if (slot >= NUMBER_OF_CARTRIDGE_SLOTS)
1632      return;
1633
1634   /* Same as above (READ16). */
1635   if (cartslots->fixed_slot==AUTO && cartslots->next_free_slot==1)
1636      slot=0;
1637
1638   cart = &cartslots->cartridge[slot];
1639
1640   if (!slot_is_empty(device, slot))
1641   {
1642      ti99_pcb_t *pcbdef = (ti99_pcb_t *)downcast<legacy_device_base *>(cart->pcb)->token();
1643      (*pcbdef->write)(cart->pcb, offset, data);
1644   }
1645}
1646
1647/*
1648    Set the address pointer value or write to GRAM (if available).
1649*/
1650WRITE8_DEVICE_HANDLER(gromportg_w)
1651{
1652   int slot;
1653   cartridge_t *cartridge;
1654   ti99_multicart_state *cartslots = (ti99_multicart_state *)downcast<legacy_device_base *>(device)->token();
1655
1656   // Set the cart slot.
1657   // 1001 1wbb bbbb bbr0
1658
1659   cartridge_slot_set(device, (UINT8)((offset>>2) & 0x00ff));
1660   slot = cartslots->active_slot;
1661
1662   // The selection mechanism of the console checks the different GROM address
1663   // bases, and when it finds different data, it concludes that there is
1664   // indeed a multi-cartridge facility. Empty   slots return 0 at all
1665   // addresses.
1666   // Unfortunately, TI's cartridge selection mechanism has an undesirable
1667   // side-effect which we work around in this implementation.
1668   // When we have only one cartridge we would like to get only the option to
1669   // select this cartridge and not an option to switch to the next one (which
1670   // would immediately cycle back to cartridge 1). However, the console
1671   // routines always show the switch option when any two slots have different
1672   // content, and this is the case with only one cartridge (slot 2 will then
1673   // be filled with zeros).
1674   // So if next_free_slot==1, we have one cartridge in slot 0.
1675   // In that case we trick the OS to believe that the addressed
1676   // cartridge appears at all locations which causes it to assume a
1677   // standard single cartslot.
1678
1679   if (cartslots->fixed_slot==AUTO && cartslots->next_free_slot==1)
1680      slot=0;
1681
1682   // Handle the GRAM Kracker
1683   if ((cartslots->gk_slot != -1) && (input_port_read(device->machine, "CARTSLOT")==CART_GK))
1684   {
1685      cartridge_gram_kracker_writeg(device, offset, data);
1686      return;
1687   }
1688
1689   if (slot < NUMBER_OF_CARTRIDGE_SLOTS)
1690   {
1691      cartridge = &cartslots->cartridge[slot];
1692      // Send the request to all mounted GROMs
1693      if (cartridge->pcb!=NULL)
1694      {
1695         for (int i=0; i < 5; i++)
1696         {
1697            ti99_pcb_t *pcbdef = (ti99_pcb_t *)downcast<legacy_device_base *>(cartridge->pcb)->token();
1698            if (pcbdef->grom[i]!=NULL)
1699               ti99grom_w(pcbdef->grom[i], offset, data);
1700         }
1701      }
1702   }
1703}
1704
1705/*
1706    GROM access. Nota bene: We only react to the request if there is a GROM
1707    at the selected bank with the currently selected ID. If not, just do
1708    nothing; do not return a value.
1709    (We must not return a value since all GROMs are connected in parallel, so
1710    returning a 0, for instance, will spoil the processing of other GROMs.)
1711*/
1712READ8Z_DEVICE_HANDLER(gromportg_rz)
1713{
1714   int slot;
1715   cartridge_t *cartridge;
1716   ti99_multicart_state *cartslots = (ti99_multicart_state *)downcast<legacy_device_base *>(device)->token();
1717
1718   // Set the cart slot. Note that the port must be adjusted for 16-bit
1719   // systems, i.e. it should be shifted left by 1.
1720   // 1001 1wbb bbbb bbr0
1721
1722   cartridge_slot_set(device, (UINT8)((offset>>2) & 0x00ff));
1723   
1724   // Handle the GRAM Kracker
1725   // BTW, the GK does not have a readable address counter, but the console
1726   // GROMs will keep our addess counter up to date. That is
1727   // exactly what happens in the real machine.
1728   if ((cartslots->gk_slot != -1) && (input_port_read(device->machine, "CARTSLOT")==CART_GK))
1729   {
1730      if ((offset & 0x0002)==0) cartridge_gram_kracker_readg(device, value);
1731      return;
1732   }
1733
1734   slot = cartslots->active_slot;
1735   
1736   // This fixes a minor issue: The selection mechanism of the console
1737   // concludes that there are multiple cartridges plugged in when it
1738   // checks the different GROM bases and finds different data. Empty
1739   // slots should return 0 at all addresses, but when we have only
1740   // one cartridge, this entails that the second cartridge is
1741   // different (all zeros), and so we get a meaningless selection
1742   // option between cartridge 1 and 1 and 1 ...
1743   //
1744   // So if next_free_slot==1, we have one cartridge in slot 0.
1745   // In that case we trick the OS to believe that the addressed
1746   // cartridge appears at all locations which causes it to assume a
1747   // standard single cartslot.
1748   
1749   if (cartslots->fixed_slot==AUTO && cartslots->next_free_slot==1)
1750      slot=0;
1751   
1752   if (slot < NUMBER_OF_CARTRIDGE_SLOTS)
1753   {
1754      // Select the cartridge which the multicart system is currently pointing at
1755      cartridge = &cartslots->cartridge[slot];
1756      // Send the request to all mounted GROMs on this PCB
1757      if (cartridge->pcb!=NULL)
1758      {
1759         for (int i=0; i < 5; i++)
1760         {
1761            ti99_pcb_t *pcbdef = (ti99_pcb_t *)downcast<legacy_device_base *>(cartridge->pcb)->token();
1762            if (pcbdef->grom[i]!=NULL)
1763               ti99grom_rz(pcbdef->grom[i], offset, value);
1764         }
1765      }
1766   }
1767}
1768
1769/*
1770    CRU interface to cartridges, used only by SuperSpace and Pagedcru
1771    style cartridges.
1772    The SuperSpace has a CRU-based memory mapper. It is accessed via the
1773    cartridge slot on CRU base >0800.
1774*/
1775READ8Z_DEVICE_HANDLER( gromportc_rz )
1776{
1777   ti99_multicart_state *cartslots = (ti99_multicart_state *) downcast<legacy_device_base *>(device)->token();
1778   cartridge_t *cart;
1779
1780   int slot = cartslots->active_slot;
1781
1782   // Handle GRAM Kracker
1783   if ((cartslots->gk_slot != -1) && (input_port_read(device->machine, "CARTSLOT")==CART_GK))
1784   {
1785      ti99_cart_cru_gk_rz(device, offset, value);
1786      return;
1787   }
1788   
1789   /* Sanity check. Higher slots are always empty. */
1790   if (slot >= NUMBER_OF_CARTRIDGE_SLOTS)
1791      return;
1792
1793   /* Same as above (READ16). */
1794   if (cartslots->fixed_slot==AUTO && cartslots->next_free_slot==1)
1795      slot=0;
1796
1797   cart = &cartslots->cartridge[slot];
1798
1799   if (!slot_is_empty(device, slot))
1800   {
1801      ti99_pcb_t *pcbdef = (ti99_pcb_t *)downcast<legacy_device_base *>(cart->pcb)->token();;
1802      if (pcbdef->cruread != NULL)
1803         (*pcbdef->cruread)(cart->pcb, offset, value);
1804   }
1805}
1806
1807/*
1808    Write cartridge mapper CRU interface (SuperSpace, Pagedcru)
1809*/
1810WRITE8_DEVICE_HANDLER( gromportc_w )
1811{
1812   ti99_multicart_state *cartslots = (ti99_multicart_state *) downcast<legacy_device_base *>(device)->token();
1813   cartridge_t *cart;
1814
1815   int slot = cartslots->active_slot;
1816
1817   // Handle GRAM Kracker
1818   if ((cartslots->gk_slot != -1) && (input_port_read(device->machine, "CARTSLOT")==CART_GK))
1819   {
1820      ti99_cart_cru_gk_w(device, offset, data);
1821      return;
1822   }
1823   
1824   /* Sanity check. Higher slots are always empty. */
1825   if (slot >= NUMBER_OF_CARTRIDGE_SLOTS)
1826      return;
1827
1828   /* Same as above (READ16). */
1829   if (cartslots->fixed_slot==AUTO && cartslots->next_free_slot==1)
1830      slot=0;
1831
1832   cart = &cartslots->cartridge[slot];
1833
1834   if (!slot_is_empty(device, slot))
1835   {
1836      ti99_pcb_t *pcbdef = (ti99_pcb_t *)downcast<legacy_device_base *>(cart->pcb)->token();;
1837      if (pcbdef->cruwrite != NULL)
1838         (*pcbdef->cruwrite)(cart->pcb, offset, data);
1839   }
1840}
1841
1842/*****************************************************************************
1843   GramKracker support
1844   The 80 KiB of the GK are allocated as follows
1845   00000 - 01fff: GRAM 0
1846   02000 - 03fff: GRAM 1  (alternatively, the loader GROM appears here)
1847   04000 - 05fff: GRAM 2
1848   06000 - 0ffff: GRAM 3-7 (alternatively, the guest GROMs appear here)
1849   10000 - 11fff: RAM 1
1850   12000 - 13fff: RAM 2
1851   
1852   The GK emulates GROMs, but without a readable address counter. Thus it
1853   relies on the console GROMs being still in place (compare with the HSGPL).
1854   Also, the GK does not implement a GROM buffer.
1855******************************************************************************/
1856
1857/*
1858    Reads from the GRAM space of the GRAM Kracker.
1859*/
1860static void cartridge_gram_kracker_readg(running_device *cartsys, UINT8 *value)
1861{
1862   // gk_slot is the slot where the GK module is plugged in
1863   // gk_guest_slot is the slot where the cartridge is plugged in
1864
1865   cartridge_t *gromkrackerbox, *gkguestcart;
1866   ti99_multicart_state *cartslots = get_safe_token(cartsys);
1867
1868   // Not null, since this is only called when there is really a GK module
1869   gromkrackerbox = &cartslots->cartridge[cartslots->gk_slot];
1870
1871   if ((gromkrackerbox->grom_address & 0xe000) == 0x0000)
1872   {
1873      // GRAM 0. Only return a value if switch 2 is in GRAM0 position.
1874      if (get_gk_switch(cartsys, 2)==GK_GRAM0)
1875         *value = (gromkrackerbox->ram_ptr)[gromkrackerbox->grom_address];
1876   }
1877   
1878   if ((gromkrackerbox->grom_address & 0xe000) == 0x2000)
1879   {
1880      // If the loader is turned on, return loader contents.
1881      if (get_gk_switch(cartsys, 5)==GK_LDON)
1882      {
1883         // The only ROM contained in the GK box is the loader
1884         *value = gromkrackerbox->grom_ptr[gromkrackerbox->grom_address & 0x1fff];
1885      }
1886      else
1887      {
1888         // Loader off
1889         // GRAM 1. Only return a value if switch 3 is in GRAM12 position.
1890         if (get_gk_switch(cartsys, 3)==GK_GRAM12)
1891            *value = (gromkrackerbox->ram_ptr)[gromkrackerbox->grom_address];
1892      }
1893   }
1894
1895   if ((gromkrackerbox->grom_address & 0xe000) == 0x4000)
1896   {
1897      // GRAM 2. Only return a value if switch 3 is in GRAM12 position.
1898      if (get_gk_switch(cartsys, 3)==GK_GRAM12)
1899         *value = (gromkrackerbox->ram_ptr)[gromkrackerbox->grom_address];
1900   }
1901
1902   if (((gromkrackerbox->grom_address & 0xe000) == 0x6000) ||
1903      ((gromkrackerbox->grom_address & 0x8000) == 0x8000))
1904   {
1905      // Cartridge space
1906      // When a cartridge is installed, it overrides the GK contents
1907      // but only if it has GROMs     
1908      int cartwithgrom = FALSE;
1909      gkguestcart = &cartslots->cartridge[cartslots->gk_guest_slot];
1910
1911      // Send the request to all mounted GROMs
1912      if (gkguestcart->pcb!=NULL)
1913      {
1914         for (int i=0; i < 5; i++)
1915         {
1916            ti99_pcb_t *pcbdef = (ti99_pcb_t *)downcast<legacy_device_base *>(gkguestcart->pcb)->token();
1917            if (pcbdef->grom[i]!=NULL)
1918            {
1919               ti99grom_rz(pcbdef->grom[i], 0x9800, value);
1920               cartwithgrom = TRUE;
1921            }
1922         }
1923      }
1924      if (!cartwithgrom && get_gk_switch(cartsys, 1)==GK_NORMAL)
1925      {
1926         *value = (gromkrackerbox->ram_ptr)[gromkrackerbox->grom_address];         
1927      }
1928   }
1929
1930   // The GK GROM emulation does not wrap at 8K boundaries.
1931   gromkrackerbox->grom_address = (gromkrackerbox->grom_address+1) & 0xffff;
1932
1933   /* Reset the write address flipflop. */
1934   gromkrackerbox->waddr_LSB = FALSE;
1935}
1936
1937/*
1938    Writes to the GRAM space of the GRAM Kracker.
1939*/
1940static void cartridge_gram_kracker_writeg(running_device *cartsys, int offset, UINT8 data)
1941{
1942   // gk_slot is the slot where the GK module is plugged in
1943   // gk_guest_slot is the slot where the cartridge is plugged in
1944   cartridge_t *gromkrackerbox;
1945   ti99_multicart_state *cartslots = get_safe_token(cartsys);
1946
1947   // This is only called when there is really a GK module
1948   gromkrackerbox = &cartslots->cartridge[cartslots->gk_slot];
1949
1950   if ((offset & 0x0002)==0x0002)
1951   {
1952      // Set address     
1953      if (gromkrackerbox->waddr_LSB)
1954      {
1955         /* Accept low byte (2nd write) */
1956         gromkrackerbox->grom_address = (gromkrackerbox->grom_address & 0xff00) | data;
1957         gromkrackerbox->waddr_LSB = FALSE;
1958      }
1959      else
1960      {
1961         /* Accept high byte (1st write) */
1962         gromkrackerbox->grom_address = ((data<<8) & 0xff00) | (gromkrackerbox->grom_address & 0x00ff);
1963         gromkrackerbox->waddr_LSB = TRUE;
1964      }
1965   }
1966   else
1967   {
1968      if (get_gk_switch(cartsys, 4) != GK_WP)
1969      {
1970         // Write protection off
1971         if (   (((gromkrackerbox->grom_address & 0xe000)==0x0000) && get_gk_switch(cartsys, 2)==GK_GRAM0)
1972            || (((gromkrackerbox->grom_address & 0xe000)==0x2000) && get_gk_switch(cartsys, 3)==GK_GRAM12 && (get_gk_switch(cartsys, 5)==GK_LDOFF))
1973            || (((gromkrackerbox->grom_address & 0xe000)==0x4000) && get_gk_switch(cartsys, 3)==GK_GRAM12)
1974            || (((gromkrackerbox->grom_address & 0xe000)==0x6000) && get_gk_switch(cartsys, 1)==GK_NORMAL && (cartslots->gk_guest_slot==-1))
1975            || (((gromkrackerbox->grom_address & 0x8000)==0x8000) && get_gk_switch(cartsys, 1)==GK_NORMAL && (cartslots->gk_guest_slot==-1)))
1976         {
1977            (gromkrackerbox->ram_ptr)[gromkrackerbox->grom_address] = data;
1978         }
1979      }
1980      // The GK GROM emulation does not wrap at 8K boundaries.
1981      gromkrackerbox->grom_address = (gromkrackerbox->grom_address+1) & 0xffff;
1982     
1983      /* Reset the write address flipflop. */
1984      gromkrackerbox->waddr_LSB = FALSE;
1985   }
1986}
1987
1988/*
1989    Reads from the RAM space of the GRAM Kracker.
1990*/
1991static READ8Z_DEVICE_HANDLER( ti99_cart_gk_rz )
1992{
1993   // gk_slot is the slot where the GK module is plugged in
1994   // gk_guest_slot is the slot where the cartridge is plugged in
1995   cartridge_t *gromkrackerbox, *gkguestcart;
1996   ti99_multicart_state *cartslots = (ti99_multicart_state *)downcast<legacy_device_base *>(device)->token();
1997
1998   gromkrackerbox = &cartslots->cartridge[cartslots->gk_slot];
1999
2000   if (cartslots->gk_guest_slot != -1)
2001   {
2002      gkguestcart = &cartslots->cartridge[cartslots->gk_guest_slot];
2003      // Legacy mode is not supported with the GK
2004      if (in_legacy_mode(device))
2005      {
2006         return;
2007      }
2008      //      printf("accessing cartridge in slot %d\n", slot);
2009      ti99_pcb_t *pcbdef = (ti99_pcb_t *)downcast<legacy_device_base *>(gkguestcart->pcb)->token();
2010      //      printf("address=%lx, offset=%lx\n", pcbdef, offset);
2011      (*pcbdef->read)(gkguestcart->pcb, offset, value);
2012      return;
2013   }
2014   else
2015   {
2016      if (get_gk_switch(device, 1)==GK_OFF) return;
2017      if (get_gk_switch(device, 4)==GK_BANK1)
2018      {
2019         *value = (gromkrackerbox->ram_ptr)[offset+0x10000];
2020      }
2021      else
2022      {
2023         if (get_gk_switch(device, 4)==GK_BANK2)
2024         {
2025            *value = (gromkrackerbox->ram_ptr)[offset+0x12000];
2026         }
2027         else
2028         {
2029            // Write protection on; auto-bank
2030            if (gromkrackerbox->ram_page==0)
2031            {
2032               *value = (gromkrackerbox->ram_ptr)[offset+0x10000];
2033            }
2034            else
2035            {
2036               *value = (gromkrackerbox->ram_ptr)[offset+0x12000];
2037            }
2038         }
2039      }
2040   }
2041}
2042
2043/*
2044    Writes to the RAM space of the GRAM Kracker.
2045*/
2046static WRITE8_DEVICE_HANDLER( ti99_cart_gk_w )
2047{
2048   // gk_slot is the slot where the GK module is plugged in
2049   // gk_guest_slot is the slot where the cartridge is plugged in
2050   cartridge_t *gromkrackerbox, *gkguestcart;
2051   ti99_multicart_state *cartslots = (ti99_multicart_state *)downcast<legacy_device_base *>(device)->token();
2052
2053   gromkrackerbox = &cartslots->cartridge[cartslots->gk_slot];
2054
2055   if (cartslots->gk_guest_slot != -1)
2056   {
2057      gkguestcart = &cartslots->cartridge[cartslots->gk_guest_slot];
2058      // Legacy mode is not supported with the GK
2059      if (in_legacy_mode(device))
2060      {
2061         return;
2062      }
2063
2064      ti99_pcb_t *pcbdef = (ti99_pcb_t *)downcast<legacy_device_base *>(gkguestcart->pcb)->token();
2065         (*pcbdef->write)(gkguestcart->pcb, offset, data);
2066   }
2067   else
2068   {
2069      if (get_gk_switch(device, 1)==GK_OFF)
2070         return;
2071
2072      if (get_gk_switch(device, 4)==GK_BANK1)
2073      {
2074         (gromkrackerbox->ram_ptr)[offset + 0x10000] = data;
2075      }
2076      else
2077      {
2078         if (get_gk_switch(device, 4)==GK_BANK2)
2079         {
2080            (gromkrackerbox->ram_ptr)[offset + 0x12000] = data;
2081         }
2082         else
2083         {
2084            // Write protection on
2085            // This is handled like in Extended Basic
2086            gromkrackerbox->ram_page = (offset & 2)>>1;
2087         }
2088      }
2089   }
2090}
2091
2092/*
2093    Read cartridge mapper CRU interface (Guest in GRAM Kracker)
2094*/
2095static READ8Z_DEVICE_HANDLER( ti99_cart_cru_gk_rz )
2096{
2097   ti99_multicart_state *cartslots = (ti99_multicart_state *)downcast<legacy_device_base *>(device)->token();
2098   cartridge_t *gkguestcart;
2099
2100   if (cartslots->gk_guest_slot != -1)
2101   {
2102      gkguestcart = &cartslots->cartridge[cartslots->gk_guest_slot];
2103      ti99_pcb_t *pcbdef = (ti99_pcb_t *)downcast<legacy_device_base *>(gkguestcart->pcb)->token();
2104      if (pcbdef->cruread != NULL)
2105         (*pcbdef->cruread)(gkguestcart->pcb, offset, value);
2106   }
2107}
2108
2109/*
2110    Write cartridge mapper CRU interface (Guest in GRAM Kracker)
2111*/
2112static WRITE8_DEVICE_HANDLER( ti99_cart_cru_gk_w )
2113{
2114   ti99_multicart_state *cartslots = (ti99_multicart_state *)downcast<legacy_device_base *>(device)->token();
2115   cartridge_t *gkguestcart;
2116
2117   if (cartslots->gk_guest_slot != -1)
2118   {
2119      gkguestcart = &cartslots->cartridge[cartslots->gk_guest_slot];
2120      ti99_pcb_t *pcbdef = (ti99_pcb_t *)downcast<legacy_device_base *>(gkguestcart->pcb)->token();
2121      if (pcbdef->cruwrite != NULL)
2122         (*pcbdef->cruwrite)(gkguestcart->pcb, offset, data);
2123   }
2124}
2125
2126/*****************************************************************************/
2127#define TI99_CARTRIDGE_SLOT(p)  MDRV_CARTSLOT_ADD(p) \
2128   MDRV_CARTSLOT_EXTENSION_LIST("rpk,bin") \
2129   MDRV_CARTSLOT_PCBTYPE(0, "none", TI99_CARTRIDGE_PCB_NONE) \
2130   MDRV_CARTSLOT_PCBTYPE(1, "standard", TI99_CARTRIDGE_PCB_STD) \
2131   MDRV_CARTSLOT_PCBTYPE(2, "paged", TI99_CARTRIDGE_PCB_PAGED) \
2132   MDRV_CARTSLOT_PCBTYPE(3, "minimem", TI99_CARTRIDGE_PCB_MINIMEM) \
2133   MDRV_CARTSLOT_PCBTYPE(4, "super", TI99_CARTRIDGE_PCB_SUPER) \
2134   MDRV_CARTSLOT_PCBTYPE(5, "mbx", TI99_CARTRIDGE_PCB_MBX) \
2135   MDRV_CARTSLOT_PCBTYPE(6, "paged379i", TI99_CARTRIDGE_PCB_PAGED379I) \
2136   MDRV_CARTSLOT_PCBTYPE(7, "pagedcru", TI99_CARTRIDGE_PCB_PAGEDCRU) \
2137   MDRV_CARTSLOT_PCBTYPE(8, "gramkracker", TI99_CARTRIDGE_PCB_GRAMKRACKER) \
2138   MDRV_CARTSLOT_START(ti99_cartridge) \
2139   MDRV_CARTSLOT_LOAD(ti99_cartridge) \
2140   MDRV_CARTSLOT_UNLOAD(ti99_cartridge)
2141
2142static MACHINE_CONFIG_FRAGMENT(ti99_multicart)
2143   TI99_CARTRIDGE_SLOT("cartridge1")
2144   TI99_CARTRIDGE_SLOT("cartridge2")
2145   TI99_CARTRIDGE_SLOT("cartridge3")
2146   TI99_CARTRIDGE_SLOT("cartridge4")
2147MACHINE_CONFIG_END
2148
2149static const char DEVTEMPLATE_SOURCE[] = __FILE__;
2150
2151#define DEVTEMPLATE_ID(p,s)             p##ti99_multicart##s
2152#define DEVTEMPLATE_FEATURES            DT_HAS_START | DT_HAS_STOP | DT_HAS_RESET | DT_HAS_INLINE_CONFIG | DT_HAS_MACHINE_CONFIG
2153#define DEVTEMPLATE_NAME                "TI99 Multi-Cartridge Extender"
2154#define DEVTEMPLATE_FAMILY              "Multi-cartridge system"
2155#include "devtempl.h"
2156
2157DEFINE_LEGACY_CART_SLOT_DEVICE(TI99_MULTICART, ti99_multicart);
src/mess/machine/ti99/hsgpl.c
r0r9485
1/*
2    SNUG HSGPL card emulation.
3    Raphael Nabet, 2003.
4   
5    Rewritten as device
6    Michael Zapf, October 2010
7*/
8
9#include "emu.h"
10#include "emuopts.h"
11#include "peribox.h"
12#include "hsgpl.h"
13#include "machine/at29040a.h"
14#include "ti99defs.h"
15
16/*
17    Supports 16 banks of 8 GROMs (8kbytes each) with 16 associated banks of
18    32kbytes (8kbytes*4) of module ROM, 2 banks of 8 GRAMs with 2 associated
19    banks of 32 kbytes of RAM, and 512kbytes of DSR.  Roms are implemented with
20    512kbyte EEPROMs (1 for DSR, 2 for GROMs, 1 for cartridge ROM).  RAM is
21    implemented with 128kbyte SRAMs (1 for GRAM, 1 for cartridge RAM - only the
22    first 64kbytes of the cartridge RAM chip is used).
23
24    CRU bits:
25       Name    Equates Meaning
26    >0 DEN     DSRENA  DSR Enable
27    >1 GRMENA  GRMENA  Enable GRAM instead of GROM in banks 0 and 1
28    >2 BNKINH* BNKENA  Disable banking
29    >3 PG0     PG0
30    >4 PG1     PG1
31    >5 PG2     PG2     Paging-Bits for DSR-area
32    >6 PG3     PG3
33    >7 PG4     PG4
34    >8 PG5     PG5
35    >9 CRDENA  CRDENA  Activate memory areas of HSGPL (i.e. enable HSGPL GROM and ROM6 ports)
36    >A WRIENA  WRIENA  write enable for RAM and GRAM (and flash GROM!)
37    >B SCENA   SCARTE  Activate SuperCart-banking
38    >C LEDENA  LEDENA  turn LED on
39    >D -       -       free
40    >E MBXENA  MBXENA  Activate MBX-Banking
41    >F RAMENA  RAMENA  Enable RAM6000 instead of ROM6000 in banks 0 and 1
42
43
44    Direct access ports for all memory areas (the original manual gives
45    >9880->989C and >9C80->9C9C for ROM6000, but this is incorrect):
46
47    Module bank Read    Write   Read ROM6000        Write ROM6000
48                GROM    GROM
49    0           >9800   >9C00   >9860 Offset >0000  >9C60 Offset >0000
50    1           >9804   >9C04   >9860 Offset >8000  >9C60 Offset >8000
51    2           >9808   >9C08   >9864 Offset >0000  >9C64 Offset >0000
52    3           >980C   >9C0C   >9864 Offset >8000  >9C64 Offset >8000
53    4           >9810   >9C10   >9868 Offset >0000  >9C68 Offset >0000
54    5           >9814   >9C14   >9868 Offset >8000  >9C68 Offset >8000
55    6           >9818   >9C18   >986C Offset >0000  >9C6C Offset >0000
56    7           >981C   >9C1C   >986C Offset >8000  >9C6C Offset >8000
57    8           >9820   >9C20   >9870 Offset >0000  >9C70 Offset >0000
58    9           >9824   >9C24   >9870 Offset >8000  >9C70 Offset >8000
59    10          >9828   >9C28   >9874 Offset >0000  >9C74 Offset >0000
60    11          >982C   >9C2C   >9874 Offset >8000  >9C74 Offset >8000
61    12          >9830   >9C30   >9878 Offset >0000  >9C78 Offset >0000
62    13          >9834   >9C34   >9878 Offset >8000  >9C78 Offset >8000
63    14          >9838   >9C38   >987C Offset >0000  >9C7C Offset >0000
64    15          >983C   >9C3C   >987C Offset >8000  >9C7C Offset >8000
65
66    Module bank Read    Write   Read RAM6000        Write RAM6000
67                GRAM    GRAM
68    16 (Ram)    >9880   >9C80   >98C0 Offset >0000  >9CC0 Offset >0000
69    17 (Ram)    >9884   >9C84   >98C0 Offset >8000  >9CC0 Offset >8000
70
71    DSR bank    Read    Write
72    0 - 7       >9840   >9C40
73    8 - 15      >9844   >9C44
74    16 - 23     >9848   >9C48
75    24 - 31     >984C   >9C4C
76    32 - 39     >9850   >9C50
77    40 - 47     >9854   >9C54
78    48 - 55     >9858   >9C58
79    56 - 63     >985C   >9C5C
80
81    Note: Writing only works for areas set up as RAM.  To write to the
82        FEEPROMs, you must used the algorithm specified by their respective
83        manufacturer.
84       
85    FIXME: Crashes when a cartridge is plugged in
86*/
87
88#define CRU_BASE 0x1B00
89
90#define RAMSIZE       0x020000
91#define GRAMSIZE       0x020000
92#define FEEPROM_SIZE   0x80000
93#define FLROMSIZE    4*(FEEPROM_SIZE+2) + 1
94
95#define NVVERSION 0
96
97typedef ti99_pebcard_config hsgpl_config;
98
99typedef struct _hsgpl_state
100{
101   running_device   *dsr, *rom6, *groma, *gromb;
102   UINT8   *ram6;
103   UINT8   *gram;
104   UINT8   *flashrom;
105   
106   int    current_grom_port;
107   
108   int      dsr_enabled;
109   int      gram_enabled;
110   int      bank_enabled;
111   int      dsr_page;
112   int      card_enabled;
113   int      write_enabled;
114   int      supercart_enabled;
115   int      led_on;
116   int      mbx_enabled;
117   int      ram_enabled;
118   
119   int      flash_mode;
120   
121   int      current_bank;
122   
123   /* GROM emulation */
124   int      raddr_LSB, waddr_LSB;
125   int      grom_address;
126   
127} hsgpl_state;
128
129INLINE hsgpl_state *get_safe_token(running_device *device)
130{
131   assert(device != NULL);
132   return (hsgpl_state *)downcast<legacy_device_base *>(device)->token();
133}
134
135/*
136    Write hsgpl CRU interface
137*/
138static WRITE8_DEVICE_HANDLER( cru_w )
139{
140   hsgpl_state *card = get_safe_token(device);
141
142   if ((offset & 0xff00)==CRU_BASE)
143   {
144      int bit = (offset >> 1) & 0x0f;
145      switch (bit)
146      {
147      case 0:
148         card->dsr_enabled = data;
149         logerror("hsgpl: Set dsr_enabled=%x\n", data);
150         break;
151      case 1:
152         card->gram_enabled = data;
153         logerror("hsgpl: Set gram_enabled=%x\n", data);
154         break;
155      case 2:
156         card->bank_enabled = data;
157         logerror("hsgpl: Set bank_enabled=%x\n", data);
158         break;
159      case 3:
160      case 4:
161      case 5:
162      case 6:
163      case 7:
164      case 8:
165         if (data)
166            card->dsr_page |= (1 << (bit-3));
167         else
168            card->dsr_page &= ~(1 << (bit-3));
169         logerror("hsgpl: Set dsr_page=%d\n", card->dsr_page);
170         break;
171      case 9:
172         card->card_enabled = data;
173         logerror("hsgpl: Set card_enabled=%x\n", data);
174         break;
175      case 10:
176         card->write_enabled = data;
177         logerror("hsgpl: Set write_enabled=%x\n", data);
178         break;
179      case 11:
180         card->supercart_enabled = data;
181         logerror("hsgpl: Set supercart_enabled=%x\n", data);
182         break;
183      case 12:
184         card->led_on = data;
185         logerror("hsgpl: Set led_on=%x\n", data);
186         break;
187      case 13:
188         break;
189      case 14:
190         card->mbx_enabled = data;
191         logerror("hsgpl: Set mbx_enabled=%x\n", data);
192         break;
193      case 15:
194         card->ram_enabled = data;
195         logerror("hsgpl: Set ram_enabled=%x\n", data);
196         break;
197      }
198   }
199}
200
201/*
202    GROM read. This is somewhat different to the original TI GROMs, so we
203    partly reimplement it here. Anyway, the card does not use GROMs but makes
204    use of a special decoder chip (MACH) which emulates the GROM functions.
205*/
206static READ8Z_DEVICE_HANDLER ( hsgpl_grom_rz )
207{
208   int port;
209   hsgpl_state *card = get_safe_token(device);
210
211   //activecpu_adjust_icount(-4);
212
213   // 1001 10bb bbbb bba0
214   port = card->current_grom_port = (offset & 0x3fc) >> 2;
215
216   if (offset & 2)
217   {   // Read GPL address. This must be available even when the rest
218      // of the card is offline (card_enabled=0).
219      card->waddr_LSB = FALSE;
220
221      if (card->raddr_LSB)
222      {
223         *value = ((card->grom_address + 1) & 0xff);
224         card->raddr_LSB = FALSE;
225      }
226      else
227      {
228         *value = ((card->grom_address + 1) >> 8) & 0xff;
229         card->raddr_LSB = TRUE;
230      }
231   }
232   else
233   {   /* read GPL data */
234      if (card->card_enabled)
235      {
236         if ((port < 2) && (card->gram_enabled))
237         {
238            *value = card->gram[card->grom_address + 0x10000*port];
239         }
240         else
241         {
242            if (port < 8)
243            {
244               if (!card->flash_mode)
245               {
246                  *value = at29c040a_r(card->groma, card->grom_address + 0x10000*port);
247               }
248            }
249            else
250            {
251               if (port < 16)
252               {
253                  *value = at29c040a_r(card->gromb, card->grom_address + 0x10000*(port-8));
254               }
255               else
256               {
257                  if (port < 24)
258                  {
259                     *value = at29c040a_r(card->dsr, card->grom_address + 0x10000*(port-16));
260                  }
261                  else
262                  {
263                     if (port < 32)
264                     {
265                        /* The HSGPL manual says 32-47, but this is incorrect */
266                        *value = at29c040a_r(card->rom6, card->grom_address + 0x10000*(port-24));
267                     }
268                     else
269                     {
270                        if (port==32 || port==33)
271                        {
272                           *value = card->gram[card->grom_address + 0x10000*(port-32)];
273                        }
274                        else
275                        {
276                           if (port==48 || port==49)
277                           {
278                              *value = card->ram6[card->grom_address];
279                           }
280                           else
281                           {
282                              logerror("hsgpl: Attempt to read from undefined port 0x%0x; ignored.\n", port);
283                           }
284                        }
285                     }
286                  }
287               }
288            }
289         }
290      }
291      // The address auto-increment should be done even when the card is
292      // offline     
293      card->grom_address++;
294      card->raddr_LSB = card->waddr_LSB = FALSE;
295   }
296}
297
298/*
299    GROM write
300*/
301static WRITE8_DEVICE_HANDLER ( hsgpl_grom_w )
302{
303   int port;
304   hsgpl_state *card = get_safe_token(device);
305
306   //activecpu_adjust_icount(-4);
307
308   // 1001 11bb bbbb bba0
309   port = card->current_grom_port = (offset & 0x3fc) >> 2;
310
311   if (offset & 2)
312   {   // Write GPL address. This must be available even when the rest
313      // of the card is offline (card_enabled=0).
314      card->raddr_LSB = FALSE;
315
316      if (card->waddr_LSB)
317      {
318         card->grom_address = (card->grom_address & 0xFF00) | data;
319         card->waddr_LSB = FALSE;
320      }
321      else
322      {
323         card->grom_address = (data << 8) | (card->grom_address & 0xFF);
324         card->waddr_LSB = TRUE;
325      }
326   }
327   else
328   {   
329      if (card->card_enabled)
330      {
331         /* write GPL data */
332         if (card->write_enabled)
333         {
334            if ((port < 2) && (card->gram_enabled))
335            {
336               card->gram[card->grom_address + 0x10000*port] = data;
337            }
338            else
339            {
340               if (port < 8)
341               {
342                  at29c040a_w(card->groma, card->grom_address + 0x10000*port, data);
343               }
344               else
345               {
346                  if (port < 16)
347                  {
348                     at29c040a_w(card->gromb, card->grom_address + 0x10000*(port-8), data);
349                  }
350                  else
351                  {
352                     if (port < 24)
353                     {
354                        at29c040a_w(card->dsr, card->grom_address + 0x10000*(port-16), data);
355                     }
356                     else
357                     {
358                        if (port < 32)
359                        {
360                           /* The HSGPL manual says 32-47, but this is incorrect */
361                           at29c040a_w(card->rom6, card->grom_address + 0x10000*(port-24), data);
362                        }
363                        else
364                        {
365                           if (port==32 || port==33)
366                           {
367                              card->gram[card->grom_address + 0x10000*(port-32)] = data;
368                           }
369                           else
370                           {
371                              if (port==48 || port==49)
372                              {
373                                 card->ram6[card->grom_address] = data;
374                              }
375                              else
376                              {
377                                 logerror("hsgpl: Attempt to write to undefined port; ignored.\n");
378                              }
379                           }
380                        }
381                     }
382                  }
383               }
384            }
385         }
386      }
387      // The address auto-increment should be done even when the card is
388      // offline
389      card->grom_address++;
390      card->raddr_LSB = card->waddr_LSB = FALSE;
391   }
392}
393
394static READ8Z_DEVICE_HANDLER ( hsgpl_dsrspace_rz )
395{
396   hsgpl_state *card = get_safe_token(device);
397   if (card->dsr_enabled)
398   {
399      *value = at29c040a_r(card->dsr, (offset-0x4000) + 0x2000 * card->dsr_page);
400//      logerror("hsgpl: read dsr %04x[%02x] -> %02x\n", offset, card->dsr_page, *value);
401   }
402}
403   
404static READ8Z_DEVICE_HANDLER ( hsgpl_cartspace_rz )
405{
406   hsgpl_state *card = get_safe_token(device);
407
408   if (!card->card_enabled || card->flash_mode)
409   {
410//      logerror("hsgpl cart read ignored (enable=%02x)\n", card->card_enabled);       
411      return;
412   }
413
414   int port = card->current_grom_port;
415
416   if ((port < 2) && (card->ram_enabled))
417   {
418      *value = card->ram6[(offset-0x6000) + 0x2000*card->current_bank + 0x8000*port];
419//      logerror("hsgpl cart ram read %04x -> %02x\n", offset, *value);
420      return;
421   }
422
423   if (port < 16)
424   {
425      *value = at29c040a_r(card->rom6, (offset-0x6000) + 0x2000*card->current_bank + 0x8000*port);
426//      logerror("hsgpl cart read %04x -> %02x\n", offset, *value);
427   }
428   else
429   {
430      if (port==32 || port==33)
431      {
432         *value = card->ram6[(offset-0x6000) + 0x2000*card->current_bank + 0x8000*(port-32)];
433      }
434      else
435      {
436         logerror("unknown 0x6000 port\n");
437      }
438   }
439}
440
441static WRITE8_DEVICE_HANDLER ( hsgpl_cartspace_w )
442{
443   hsgpl_state *card = get_safe_token(device);
444   
445   if (!card->card_enabled || card->flash_mode)
446   {
447      logerror("hsgpl cart write ignored: card_enabled=%02x\n", card->card_enabled);       
448      return;
449   }
450   
451   int port = card->current_grom_port;
452//   logerror("hsgpl cart write %04x -> %02x\n", offset, data);       
453
454   if (card->bank_enabled)
455   {
456      card->current_bank = (offset>>1) & 3;
457//      logerror("hsgpl cart select bank %02x\n", card->current_bank);       
458      return;      /* right??? */
459   }
460
461   if ((card->mbx_enabled) && (offset==0x6ffe))
462   {   /* MBX: mapper at 0x6ffe */
463      card->current_bank = data & 0x03;
464      return;
465   }
466
467   // MBX: RAM in 0x6c00-0x6ffd (it is unclear whether the MBX RAM area is
468   // enabled/disabled by the wriena bit).  I guess RAM is unpaged, but it is
469   // not implemented
470   if ((card->write_enabled) || ((card->mbx_enabled) && ((offset & 0xfc00)==0x6c00)))
471   {
472      if ((port < 2) && (card->ram_enabled))
473      {
474         card->ram6[(offset-0x6000) + 0x2000*card->current_bank + 0x8000*port ] = data;
475      }
476      else
477      {   // keep in mind that these lines are also reached for port < 2
478         // and !ram_enabled
479         if (port < 16)
480         {
481         // feeprom is normally written to using GPL ports, and I don't know
482         // writing through >6000 page is enabled
483/*
484         at29c040a_w(feeprom_rom6, 1 + 2*offset + 0x2000*hsgpl.cur_bank + 0x8000*port, data);
485         at29c040a_w(feeprom_rom6, 2*offset + 0x2000*hsgpl.cur_bank + 0x8000*port, data >> 8);
486*/
487         }
488         else
489         {
490            if (port==32 || port==33)
491            {
492               card->ram6[(offset-0x6000) + 0x2000*card->current_bank + 0x8000*(port-32)] = data;
493            }
494            else
495            {
496               logerror("unknown 0x6000 port\n");
497            }
498         }
499      }
500   }
501}
502
503/*
504    Memory read
505*/
506static READ8Z_DEVICE_HANDLER ( data_rz )
507{
508   if ((offset & 0xe000)==0x4000)
509   {
510      hsgpl_dsrspace_rz(device, offset, value);
511   }
512   
513   if ((offset & 0xe000)==0x6000)
514   {
515      hsgpl_cartspace_rz(device, offset, value);
516   }
517   
518   // 1001 1wbb bbbb bba0
519   if ((offset & 0xfc01)==0x9800)
520   {
521      hsgpl_grom_rz(device, offset, value);
522   }
523}
524
525/*
526    Memory write
527*/
528static WRITE8_DEVICE_HANDLER ( data_w )
529{
530   if ((offset & 0xe000)==0x6000)
531   {
532      hsgpl_cartspace_w(device, offset, data);
533   }
534   
535   // 1001 1wbb bbbb bba0
536   if ((offset & 0xfc01)==0x9c00)
537   {
538      hsgpl_grom_w(device, offset, data);
539   }
540}
541
542static ti99_peb_card hsgpl_card =
543{
544   data_rz,
545   data_w,
546   NULL,
547   cru_w,   
548   NULL, NULL,   NULL, NULL   
549};
550
551static DEVICE_START( hsgpl )
552{
553   logerror("HSGPL start\n");
554   hsgpl_state *card = get_safe_token(device);
555   card->dsr = device->subdevice("u9_dsr");
556   card->rom6 = device->subdevice("u6_rom6");
557   card->groma = device->subdevice("u4_grom");
558   card->gromb = device->subdevice("u1_grom");
559
560   /* We need this for the NVRAM; at this point we cannot query the settings yet. */
561   card->flashrom = (UINT8*)malloc(FLROMSIZE);
562}
563
564static DEVICE_STOP( hsgpl )
565{
566   hsgpl_state *card = get_safe_token(device);
567   logerror("hsgpl: stop\n");
568   free(card->flashrom);
569   if (card->ram6)
570   {
571      free(card->ram6);
572      free(card->gram);
573   }
574}
575
576static DEVICE_RESET( hsgpl )
577{
578   logerror("hsgpl: reset\n");
579   hsgpl_state *card = get_safe_token(device);
580   
581   /* If the card is selected in the menu, register the card */
582   if (input_port_read(device->machine, "EXTCARD") & (EXT_HSGPL_ON | EXT_HSGPL_FLASH))
583   {
584      running_device *peb = device->owner();   
585      int success = mount_card(peb, device, &hsgpl_card, get_pebcard_config(device)->slot);
586      if (!success)
587      {
588         logerror("hsgpl: Failed to mount.\n");
589         return;
590      }
591
592      card->grom_address = 0;
593      card->raddr_LSB = 0;
594      card->waddr_LSB = 0;
595      card->current_grom_port = 0;
596      card->current_bank = 0;
597
598      card->dsr_enabled = FALSE;
599      card->gram_enabled = FALSE;
600      card->bank_enabled = TRUE;      // important, assumed to be enabled by default
601      card->dsr_page = 0;
602      card->card_enabled = TRUE;      // important, assumed to be enabled by default
603      card->write_enabled = FALSE;
604      card->supercart_enabled = FALSE;
605      card->led_on = FALSE;
606      card->mbx_enabled = FALSE;
607      card->ram_enabled = FALSE;
608
609      card->flash_mode = (input_port_read(device->machine, "EXTCARD") & EXT_HSGPL_FLASH);
610      if (card->flash_mode) logerror("hsgpl: flash mode\n");
611      else logerror("hsgpl: full mode\n");
612     
613      if (card->ram6==NULL)
614      {
615         card->ram6 = (UINT8*)malloc(RAMSIZE);
616         card->gram = (UINT8*)malloc(GRAMSIZE);
617      }
618   }
619}
620
621static DEVICE_NVRAM( hsgpl )
622{
623   // Called between START and RESET
624   hsgpl_state *card = get_safe_token(device);
625   astring *hsname = astring_assemble_3(astring_alloc(), device->machine->gamedrv->name, PATH_SEPARATOR, "hsgpl.nv");
626   file_error filerr;
627   mame_file *nvfile;
628
629   if (read_or_write==0)
630   {
631      logerror("hsgpl: device nvram load %s\n", astring_c(hsname));
632     
633      filerr = mame_fopen(SEARCHPATH_NVRAM, astring_c(hsname), OPEN_FLAG_READ, &nvfile);
634      if (filerr != FILERR_NONE)
635      {
636         logerror("hsgpl: Could not restore NVRAM\n");
637         return;
638      }
639
640      if (mame_fread(nvfile, card->flashrom, FLROMSIZE) != FLROMSIZE)
641      {
642         logerror("hsgpl: Error loading NVRAM; unexpected EOF\n");
643         mame_fclose(nvfile);
644         return;
645      }
646         
647      if (card->flashrom[0] != NVVERSION)
648      {
649         logerror("hsgpl: Wrong NVRAM image version: %d\n", card->flashrom[0]);
650         mame_fclose(nvfile);
651         return;
652      }
653      mame_fclose(nvfile);
654   }
655   else
656   {
657      logerror("hsgpl: device nvram save %s\n", astring_c(hsname));
658      // Check dirty flags
659      if (at29c040a_is_dirty(card->dsr) ||
660         at29c040a_is_dirty(card->rom6) ||
661         at29c040a_is_dirty(card->groma) ||
662         at29c040a_is_dirty(card->gromb))
663      {
664         card->flashrom[0] = NVVERSION;
665         filerr = mame_fopen(SEARCHPATH_NVRAM, astring_c(hsname), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS, &nvfile);
666         
667         if (filerr != FILERR_NONE)
668         {
669            logerror("hsgpl: Could not save NVRAM\n");
670         }
671         else
672         {
673            if (mame_fwrite(nvfile, card->flashrom, FLROMSIZE) != FLROMSIZE)
674            {
675               logerror("hsgpl: Error while saving contents of NVRAM.\n");
676            }
677         }
678         mame_fclose(nvfile);
679         return;
680      }
681      else
682      {
683         logerror("hsgpl: No changes on card, leaving nvram file unchanged.\n");
684      }
685   }
686}
687
688/*
689   Get the pointer to the memory data from the HSGPL card. Called by the FEEPROM.
690*/
691static UINT8 *get_mem_ptr(running_device *device)
692{
693   hsgpl_state *card = get_safe_token(device);
694   return card->flashrom;
695}
696
697MACHINE_CONFIG_FRAGMENT( hsgpl )
698   MDRV_AT29C040_ADD_P( "u9_dsr",  get_mem_ptr, 0x000001)
699   MDRV_AT29C040_ADD_P( "u4_grom", get_mem_ptr, 0x080003)
700   MDRV_AT29C040_ADD_P( "u1_grom", get_mem_ptr, 0x100005)
701   MDRV_AT29C040_ADD_P( "u6_rom6", get_mem_ptr, 0x180007)
702MACHINE_CONFIG_END
703
704static const char DEVTEMPLATE_SOURCE[] = __FILE__;
705
706#define DEVTEMPLATE_ID(p,s)             p##hsgpl##s
707#define DEVTEMPLATE_FEATURES            DT_HAS_START | DT_HAS_STOP | DT_HAS_RESET | DT_HAS_INLINE_CONFIG | DT_HAS_MACHINE_CONFIG | DT_HAS_NVRAM
708#define DEVTEMPLATE_NAME                "SNUG High-Speed GPL card"
709#define DEVTEMPLATE_FAMILY              "Peripheral expansion"
710#include "devtempl.h"
711
712DEFINE_LEGACY_NVRAM_DEVICE( HSGPL, hsgpl );
src/mess/machine/ti99/gromport.h
r0r9485
1/*********************************************************************
2
3    gromport.h
4
5    TI99 family cartridge management
6
7*********************************************************************/
8
9#ifndef __TI99CART_H__
10#define __TI99CART_H__
11
12#include "devices/cartslot.h"
13#include "ti99defs.h"
14
15typedef struct _ti99_multicart_config
16{
17   write_line_device_func   ready;
18   
19} ti99_multicart_config;
20
21typedef struct _gromport_callback
22{
23   devcb_write_line ready;
24} gromport_callback;
25
26void set_gk_switches(running_device *cartsys, int number, int value);
27
28/* GROM part */
29WRITE8_DEVICE_HANDLER( gromportg_w );
30READ8Z_DEVICE_HANDLER( gromportg_rz );
31
32/* ROM part */
33WRITE8_DEVICE_HANDLER( gromportr_w );
34READ8Z_DEVICE_HANDLER( gromportr_rz );
35
36/* CRU part */
37WRITE8_DEVICE_HANDLER( gromportc_w );
38READ8Z_DEVICE_HANDLER( gromportc_rz );
39
40DECLARE_LEGACY_CART_SLOT_DEVICE(TI99_MULTICART, ti99_multicart);
41
42#define MDRV_TI99_GROMPORT_ADD(_tag, _ready) \
43   MDRV_DEVICE_ADD(_tag, TI99_MULTICART, 0) \
44   MDRV_DEVICE_CONFIG_DATAPTR(ti99_multicart_config, ready, _ready)
45
46#endif /* __TI99CART_H__ */
src/mess/machine/ti99/genboard.c
r0r9485
1/***************************************************************************
2   Geneve 9640 system board
3     
4   Michael Zapf, October 2010
5***************************************************************************/
6
7#include "emu.h"
8#include "genboard.h"
9#include "video/v9938.h"
10#include "videowrp.h"
11#include "sound/sn76496.h"
12#include "machine/mm58274c.h"
13#include "peribox.h"
14#include "includes/geneve.h"
15
16#define KEYQUEUESIZE 256
17#define MAXKEYMSGLENGTH 10
18#define KEYAUTOREPEATDELAY 30
19#define KEYAUTOREPEATRATE 6
20
21#define SRAM_SIZE 64*1024
22#define DRAM_SIZE 512*1024
23
24typedef struct _genboard_state
25{
26   /* Mouse support */
27   int      last_mx;
28   int      last_my;
29   
30   /* Joystick support */
31   int    joySel;
32
33   /* Keyboard support */
34   UINT8    keyQueue[KEYQUEUESIZE];
35   int    keyQueueHead;
36   int    keyQueueLen;
37   int    keyInBuf;
38   int    keyReset;
39   UINT32    keyStateSave[4];
40   int    keyNumLockState;
41   int    keyCtrlState;
42   int    keyAltState;
43   int    keyRealShiftState;
44   int    keyFakeShiftState;
45   int    keyFakeUnshiftState;
46   int    keyAutoRepeatKey;
47   int    keyAutoRepeatTimer;
48   
49   /* Mode flags */
50   int      palvideo;         // bit 5 +
51   int      capslock;         // bit 7 +
52   int      keyboard_clock;      // bit 8 +
53   int      keep_keybuf;      // bit 9 keyclear -
54   int      zero_wait;         // bit 15
55   
56   /* GROM simulation */
57   int      grom_address;
58   int      gromraddr_LSB;
59   int      gromwaddr_LSB;
60   
61   /* Memory */
62   UINT8   *sram;
63   UINT8   *dram;
64   UINT8   *eprom;
65   
66   /* Mapper */
67   int    geneve_mode;          // +
68   int      direct_mode;          // mapmode -
69   int      cartridge_size_8K;     // +
70   int      cartridge_secondpage;   // +
71   int      cartridge6_writable;    // protect -
72   int      cartridge7_writable;    // protect -
73   int      map[8];
74   
75   int      line_count;
76   
77   /* Devices */
78   running_device    *cpu;
79   running_device    *video;
80   running_device  *tms9901;
81   running_device    *clock;
82   running_device    *peribox;
83   running_device    *sound;
84
85} genboard_state;
86
87static const UINT8 keyboard_mf1_code[0xe] =
88{
89   /* extended keys that are equivalent to non-extended keys */
90   0x1c,   /* keypad enter */
91   0x1d,   /* right control */
92   0x38,   /* alt gr */
93   /* extra codes are 0x5b for Left Windows, 0x5c for Right Windows, 0x5d
94   for Menu, 0x5e for power, 0x5f for sleep, 0x63 for wake, but I doubt
95   any Geneve program would take advantage of these. */
96   
97   /* extended key that is equivalent to a non-extended key
98   with shift off */
99   0x35,   /* pad slash */
100   
101   /* extended keys that are equivalent to non-extended keys
102   with numlock off */
103   0x47,   /* home */
104   0x48,   /* up */
105   0x49,   /* page up */
106   0x4b,   /* left */
107   0x4d,   /* right */
108   0x4f,   /* end */
109   0x50,   /* down */
110   0x51,   /* page down */
111   0x52,   /* insert */
112   0x53   /* delete */
113};
114
115static void poll_keyboard(running_device *device);
116static void poll_mouse(running_device *device);
117static void read_key_if_possible(genboard_state *board);
118static UINT8 get_recent_key(running_device *device);
119
120static const char *keynames[] = { "KEY0", "KEY1", "KEY2", "KEY3", "KEY4", "KEY5", "KEY6", "KEY7" };
121
122INLINE genboard_state *get_safe_token(running_device *device)
123{
124   assert(device != NULL);
125   assert(downcast<legacy_device_base *>(device)->token() != NULL);
126   return (genboard_state *)downcast<legacy_device_base *>(device)->token();
127}
128
129/*
130    scanline interrupt
131*/
132INTERRUPT_GEN( geneve_hblank_interrupt )
133{
134   running_device *dev = device->machine->device("geneve_board");
135   genboard_state *board = get_safe_token(dev);
136   v9938_interrupt(device->machine, 0);
137   board->line_count++;
138   if (board->line_count == 262)
139   {
140      board->line_count = 0;
141      poll_keyboard(dev);
142      poll_mouse(dev);
143   }
144}
145
146/****************************************************************************
147   GROM simulation. The Geneve board simulated GROM circuits within its gate
148   array.
149*****************************************************************************/
150
151/*
152   Simulates GROM. The real Geneve does not use GROMs but simulates them
153   within the gate array. Unlike with real GROMs, no address wrapping occurs,
154   and the complete 64K space is available.
155*/
156static READ8_DEVICE_HANDLER( read_grom )
157{
158   genboard_state *board = get_safe_token(device);
159   UINT8 reply;
160   if (offset & 0x0002)
161   {
162      // GROM address handling   
163      board->gromwaddr_LSB = FALSE;
164     
165      if (board->gromraddr_LSB)
166      {
167         reply = board->grom_address & 0xff;
168         board->gromraddr_LSB = FALSE;
169      }
170      else
171      {
172         reply = (board->grom_address >> 8) & 0xff;
173         board->gromraddr_LSB = TRUE;
174      }
175   }
176   else
177   {
178      // GROM data handling
179      // GROMs are stored in pages 38..3f
180      int page = 0x38;
181      reply = board->dram[page*0x2000 + board->grom_address];
182      board->grom_address = (board->grom_address + 1) & 0xffff;
183      board->gromraddr_LSB = board->gromwaddr_LSB = FALSE;
184   }
185   return reply;
186}
187
188/*
189   Simulates GROM. The real Geneve does not use GROMs but simulates them
190   within the gate array.
191*/
192static WRITE8_DEVICE_HANDLER( write_grom )
193{
194   genboard_state *board = get_safe_token(device);
195   if (offset & 0x0002)
196   {
197      // set address
198      board->gromraddr_LSB = FALSE;
199      if (board->gromwaddr_LSB)
200      {
201         board->grom_address = (board->grom_address & 0xff00) | data;
202         board->grom_address = (board->grom_address + 1) & 0xffff;
203         board->gromwaddr_LSB = FALSE;
204      }
205      else
206      {
207         board->grom_address = (board->grom_address & 0x00ff) | ((UINT16)data<<8);
208         board->gromwaddr_LSB = TRUE;
209      }         
210   }
211   else
212   {   // write GPL data
213      // TODO: Check whether available in the real hardware.
214      board->grom_address = (board->grom_address + 1) & 0xffff;
215      board->gromraddr_LSB = board->gromwaddr_LSB = FALSE;
216      logerror("Geneve: GROM write ignored\n");
217   }
218}
219
220/****************************************************************************
221   Mapper
222*****************************************************************************/
223
224READ8_DEVICE_HANDLER( geneve_r )
225{
226   genboard_state *board = get_safe_token(device);
227   UINT8 value = 0;
228   int page;
229
230   // Premature access. The CPU reads the start vector before RESET.
231   if (board->peribox==NULL) return 0;
232   
233   if (!board->zero_wait)
234      cpu_adjust_icount(board->cpu, -4);
235
236   UINT32   physaddr;
237   
238   if (board->geneve_mode)
239   {
240      // TODO: shortcut offset & 0xffc0 = 0xf100
241      if ((offset & 0xfff5)==0xf100)
242      {
243         // video
244         // ++++ ++++ ++++ -+-+
245         // 1111 0001 0000 0000
246         // 1111 0001 0000 0010
247         // 1111 0001 0000 1000
248         // 1111 0001 0000 1010
249         gen_v9938_rz(board->video, offset, &value);
250         return value;
251      }
252      if ((offset & 0xfff8)==0xf110)
253      {
254         // mapper
255         value = board->map[offset & 0x0007];
256         return value;
257      }
258      if (offset == 0xf118)
259      {
260         // key
261         value = get_recent_key(device);
262         return value;
263      }
264      if ((offset & 0xfff0)==0xf130)
265      {
266         // clock
267         value = mm58274c_r(board->clock, offset & 0x00f);
268         return value;
269      }
270   }
271   else // TI mode
272   {
273      if ((offset & 0xfff8)==0x8000)
274      {
275         // mapper
276         value = board->map[offset & 0x0007];
277         return value;
278      }
279      if (offset == 0x8008)
280      {
281         // key
282         value = get_recent_key(device);
283         return value;
284      }
285      if ((offset & 0xfff0)==0x8010)
286      {
287         // clock
288         value = mm58274c_r(board->clock, offset & 0x00f);
289         return value;
290      }
291      if ((offset & 0xfc01)==0x8800)
292      {
293         // video
294         // ++++ ++-- ---- ---+
295         // 1000 1000 0000 00x0
296         gen_v9938_rz(board->video, offset, &value);
297         return value;
298      }
299      if ((offset & 0xfc01)==0x9000)
300      {
301         // speech
302         // ++++ ++-- ---- ---+
303         // 1001 0000 0000 0000
304         // 0x17000 represents the proper AMA/B/C setting; will be masked away currently
305         ti99_peb_data_rz(board->peribox, offset | 0x17000, &value);
306         return value;
307      }
308      if ((offset & 0xfc01)==0x9800)
309      {
310         // grom simulation
311         // ++++ ++-- ---- ---+
312         // 1001 1000 0000 00x0
313         value = read_grom(device, offset);
314         return value;
315      }
316   }
317   
318   page = (offset & 0xe000) >> 13;
319
320   if (board->direct_mode)
321   {
322      physaddr = 0x1e0000; // points to boot eprom
323   }
324   else
325   { // mf_mapmode=0 (bit 11)
326      if (!board->geneve_mode && page==3)
327      {
328         // Cartridge paging in TI mode
329         // See also cartridge type "paged" in gromport.h
330         // value 0x36 = 0 0110 110x xxxx xxxx xxxx (page 1)
331         // value 0x37 = 0 0110 111x xxxx xxxx xxxx (page 2)
332         // Only use this if there are 2*8 KiB cartridge ROM
333         if (!board->cartridge_size_8K && board->cartridge_secondpage) physaddr = 0x06e000;
334         else physaddr = 0x06c000;
335      }
336      else
337      {
338         physaddr = (board->map[page] << 13);
339      }
340   }
341   
342   physaddr |= (offset & 0x1fff);
343   
344   if ((physaddr & 0x180000)==0x000000)
345   {
346      // DRAM. One wait state.
347      cpu_adjust_icount(board->cpu, -4);
348      value = board->dram[physaddr & 0x07ffff];
349      return value;
350   }
351   if ((physaddr & 0x180000)==0x080000)
352   {
353      // Memex in PEB
354      // 0 1aaa xxxx xxxx xxxx xxxx 
355      ti99_peb_data_rz(board->peribox, physaddr, &value);
356      return value;
357   }
358   if ((physaddr & 0x180000)==0x100000)
359   {
360      // 1 0aaa xxxx xxxx xxxx xxxx p-box address block
361      // Cards in PEB (aaa = AMC, AMB, AMA)
362      ti99_peb_data_rz(board->peribox, physaddr, &value);
363      return value;
364   }
365   if ((physaddr & 0x1f0000)==0x1d0000)
366   {
367      // 1 1101 xxxx xxxx xxxx xxxx on-board sram (64K)
368      value = board->sram[physaddr & 0x00ffff];
369      return value;
370   }
371   if ((physaddr & 0x1e0000)==0x1e0000)
372   {
373      // 1 111. ..xx xxxx xxxx xxxx on-board eprom (16K)
374      // mirrored for f0, f2, f4, ...; f1, f3, f5, ...
375      value = board->eprom[physaddr & 0x003fff];
376      return value;
377   }   
378
379   return 0;   
380}
381/*
382Geneve mode:
383f100 / fff5: v9938_r
384f110 / fff8: mapper_r
385f118 / ffff: key_r
386f130 / fff0: clock_r
387
388TI mode:
3898000 / fff8: mapper_r
3908008 / ffff: key_r
3918010 / fff0: clock_r
3928800 / fffd: v9938_r
3939000 / ffc0: speech_r
3949800 / ffc0: grom_r
395
396*/
397
398WRITE8_DEVICE_HANDLER( geneve_w )
399{
400   genboard_state *board = get_safe_token(device);
401   UINT32   physaddr;
402   int page;
403
404   if (board->peribox==NULL) return;
405     
406   if (!board->zero_wait)
407      cpu_adjust_icount(board->cpu, -4);
408   
409   if (board->geneve_mode)
410   {
411      if ((offset & 0xfff1)==0xf100)
412      {
413         // video
414         // ++++ ++++ ++++ ---+
415         // 1111 0001 0000 .cc0
416         gen_v9938_w(board->video, offset, data);
417         return;
418      }
419      if ((offset & 0xfff8)==0xf110)
420      {
421         // mapper
422         board->map[offset & 0x0007] = data;
423         return;
424      }
425      if ((offset & 0xfff1)==0xf120)
426      {
427         // sound
428         // ++++ ++++ ++++ ---+
429         sn76496_w(board->sound, 0, data);
430         return;
431      }
432      if ((offset & 0xfff0)==0xf130)
433      {
434         // clock
435         // ++++ ++++ ++++ ----
436         mm58274c_w(board->clock, offset & 0x00f, data);
437         return;
438      }
439   }
440   else
441   {
442      // TI mode
443      if ((offset & 0xfff8)==0x8000)
444      {
445         // mapper
446         board->map[offset & 0x0007] = data;
447         return;
448      }
449      // No key write at 8008
450      if ((offset & 0xfff0)==0x8010)
451      {
452         // clock
453         mm58274c_w(board->clock, offset & 0x00f, data);
454         return;
455      }
456      if ((offset & 0xfc01)==0x8400)
457      {
458         // sound
459         // ++++ ++-- ---- ---+
460         // 1000 0100 0000 0000
461         sn76496_w(board->sound, 0, data);
462         return;
463      }
464      if ((offset & 0xfc01)==0x8c00)
465      {
466         // video
467         // ++++ ++-- ---- ---+
468         // 1000 1100 0000 00c0
469         gen_v9938_w(board->video, offset, data);
470         return;
471      }
472      if ((offset & 0xfc01)==0x9400)
473      {
474         // speech
475         // ++++ ++-- ---- ---+
476         // 1001 0100 0000 0000
477         ti99_peb_data_w(board->peribox, offset | 0x17000, data);
478         return;
479      }
480      if ((offset & 0xfc01)==0x9c00)
481      {
482         // grom simulation
483         // ++++ ++-- ---- ---+
484         // 1001 1100 0000 00c0
485         write_grom(device, offset, data);
486         return;
487      }
488   }
489
490   page = (offset & 0xe000) >> 13;
491   if (board->direct_mode)
492   {
493      physaddr = 0x1e0000; // points to boot eprom
494   }
495   else
496   {
497      if (!board->geneve_mode && page==3)
498      {
499         if (!board->cartridge_size_8K)
500         {
501            // Writing to 0x6000 selects page 1,
502            // writing to 0x6002 selects page 2
503            board->cartridge_secondpage = ((offset & 0x0002)!=0);
504            return;
505         }
506         else
507         {
508            // writing into cartridge rom space (no bankswitching)
509            if ((((offset & 0x1000)==0x0000) && !board->cartridge6_writable)
510               || (((offset & 0x1000)==0x1000) && !board->cartridge7_writable))
511            {
512               logerror("Geneve: Writing to protected cartridge space %04x ignored\n", offset);
513               return;
514            }
515            else
516               // TODO: Check whether secondpage is really ignored
517               physaddr = 0x06c000;
518         }
519      }
520      else
521         physaddr = (board->map[page] << 13);
522   }
523
524   physaddr |= offset & 0x1fff;
525   
526   if ((physaddr & 0x180000)==0x000000)
527   {
528      // DRAM write. One wait state.
529      cpu_adjust_icount(board->cpu, -4);
530      board->dram[physaddr & 0x07ffff] = data;
531      return;
532   }
533   if ((physaddr & 0x180000)==0x080000)
534   {
535      // Memex in PEB
536      ti99_peb_data_w(board->peribox, physaddr, data);
537      return;
538   }
539   if ((physaddr & 0x180000)==0x100000)
540   {
541      // Classic cards in PEB
542      ti99_peb_data_w(board->peribox, physaddr, data);
543      return;
544   }     
545   if ((physaddr & 0x1f0000)==0x1d0000)
546   {
547      // SRAM write
548      board->sram[physaddr & 0x00ffff] = data;
549      return;
550   }
551   // Ignore EPROM write
552}
553
554/*
555Geneve mode:
556f100 / fff1: v9938_w
557f110 / fff8: mapper_w
558f120 / fff0: sound_w
559f130 / fff0: clock_w
560
561TI mode:
5628000 / fff8: mapper_w
5638010 / fff0: clock_w
5648400 / fc00: sound_w
5658c00 / fff9: v9938_w
5669400 / fc00: speech_w
5679c00 / fffd: grom_w
568
569
570Address: (max 2 MB)
571b bbbb bbbc cccc cccc cccc
572
5730 0... .... .... .... .... on-board dram 512 KiB
574
5750 1... .... .... .... .... p-box optional memex 512 KiB
5761 00.. .... .... .... .... p-box AMA=0 (256 KiB)
5771 010. .... .... .... .... p-box AMA=1 AMB=0 (128 KiB)
5781 0110 .... .... .... .... p-box AMA=1 AMB=1 AMC=0 (64 KiB)
579
5801 0111 00.. .... .... .... p-box address block 0xxx, 2xxx
5811 0111 010. .... .... .... p-box address block 4xxx (DSR)
5821 0111 011. .... .... .... p-box address block 6xxx
5831 0111 100. .... .... .... p-box address block 8xxx
5841 0111 101. .... .... .... p-box address block axxx
5851 0111 11.. .... .... .... p-box address block cxxx, exxx
586
5871 1101 .... .... .... .... on-board sram (64K)
5881 111. ..0. .... .... .... on-board boot1
5891 111. ..1. .... .... .... on-board boot2
590
591
592*/
593
594/****************************************************************************
595   CRU handling
596*****************************************************************************/
597
598#define CRU_CONTROL_BASE 0x1ee0
599
600WRITE8_DEVICE_HANDLER ( geneve_cru_w )
601{
602   genboard_state *board = get_safe_token(device);
603
604   int addroff = (offset + 0x0800) << 1;
605   int rising_edge = FALSE;
606   int falling_edge = FALSE;
607     
608   if ((addroff & 0x1fe0) == CRU_CONTROL_BASE)
609   {
610      int bit = (addroff & 0x0001e)>>1;
611      switch (bit)
612      {
613      case 5:
614         board->palvideo = data;
615         break;
616      case 7:
617         board->capslock = data;
618         break;
619      case 8:
620         rising_edge = (!board->keyboard_clock && data);
621         board->keyboard_clock = data;
622         if (rising_edge)
623            read_key_if_possible(board);           
624         break;
625      case 9:
626         rising_edge = (!board->keep_keybuf && data);
627         falling_edge = (board->keep_keybuf && !data);
628         board->keep_keybuf = data;
629
630         if (rising_edge)
631            read_key_if_possible(board);
632         else
633         {
634            if (falling_edge)
635            {
636               if (board->keyQueueLen != 0)
637               {
638                  board->keyQueueHead = (board->keyQueueHead + 1) % KEYQUEUESIZE;
639                  board->keyQueueLen--;
640               }
641               /* clear keyboard interrupt */
642               tms9901_set_single_int(board->tms9901, 8, 0);
643               board->keyInBuf = 0;
644            }
645         }           
646         break;
647      case 10:
648         board->geneve_mode = data;
649         break;
650      case 11:
651         board->direct_mode = data;
652         break;
653      case 12:
654         board->cartridge_size_8K = data;
655         break;
656      case 13:
657         board->cartridge6_writable = data;
658         break;
659      case 14:
660         board->cartridge7_writable = data;
661         break;
662      case 15:
663         board->zero_wait = data;
664         break;
665      default:
666         logerror("geneve: set CRU address %04x=%02x ignored\n", addroff, data);
667         break;
668      }
669   }
670   else
671      ti99_peb_cru_w(board->peribox, addroff, data);
672}
673
674
675READ8_DEVICE_HANDLER ( geneve_cru_r )
676{
677   UINT8 value = 0;
678   genboard_state *board = get_safe_token(device);
679   int addroff = (offset + 0x0100) << 4;
680
681   // TMS9995-internal CRU locations (1ee0-1efe) are handled within the 99xxcore
682   // implementation (read_single_cru), so we don't arrive here
683   ti99_peb_cru_rz(board->peribox, addroff, &value);
684   return value;
685}
686
687/****************************************************************************
688   Keyboard support
689*****************************************************************************/
690
691UINT8 get_recent_key(running_device *device)
692{
693   genboard_state *board = get_safe_token(device);
694   if (board->keyInBuf)
695      return board->keyQueue[board->keyQueueHead];
696   else
697      return 0;
698}
699
700static void read_key_if_possible(genboard_state *board)
701{
702   // if keyboard reset is not asserted, and key clock is enabled, and key
703   // buffer clear is disabled, and key queue is not empty. */
704   if ((!board->keyReset) && (board->keyboard_clock) && (board->keep_keybuf) && (board->keyQueueLen != 0))
705   {
706      tms9901_set_single_int(board->tms9901, 8, 1);
707      board->keyInBuf = 1;
708   }
709}
710
711INLINE void post_in_keyQueue(genboard_state *board, int keycode)
712{
713   board->keyQueue[(board->keyQueueHead + board->keyQueueLen) % KEYQUEUESIZE] = keycode;
714   board->keyQueueLen++;
715}
716
717static void poll_keyboard(running_device *device)
718{
719   genboard_state *board = get_safe_token(device);
720
721   UINT32 keystate;
722   UINT32 key_transitions;
723   int i, j;
724   int keycode;
725   int pressed;
726
727   if (board->keyReset)
728      return;
729
730   /* Poll keyboard */
731   for (i = 0; (i < 4) && (board->keyQueueLen <= (KEYQUEUESIZE-MAXKEYMSGLENGTH)); i++)
732   {
733      keystate = input_port_read(device->machine, keynames[2*i]) | (input_port_read(device->machine, keynames[2*i + 1]) << 16);
734      key_transitions = keystate ^ board->keyStateSave[i];
735      if (key_transitions)
736      {
737         for (j = 0; (j < 32) && (board->keyQueueLen <= (KEYQUEUESIZE-MAXKEYMSGLENGTH)); j++)
738         {
739            if ((key_transitions >> j) & 1)
740            {
741               keycode = (i << 5) | j;
742               pressed = ((keystate >> j) & 1);
743               if (pressed)
744                  board->keyStateSave[i] |= (1 << j);
745               else
746                  board->keyStateSave[i] &= ~ (1 << j);
747
748               /* Update auto-repeat */
749               if (pressed)
750               {
751                  board->keyAutoRepeatKey = keycode;
752                  board->keyAutoRepeatTimer = KEYAUTOREPEATDELAY+1;
753               }
754               else /*if (keycode == board->keyAutoRepeatKey)*/
755                  board->keyAutoRepeatKey = 0;
756
757               // Release Fake Shift/Unshift if another key is pressed
758               // We do so if a key is released, though it is actually
759               // required only if it is a modifier key
760               /*if (pressed)*/
761               //{
762               if (board->keyFakeShiftState)
763               {
764                  /* Fake shift release */
765                  post_in_keyQueue(board, 0xe0);
766                  post_in_keyQueue(board, 0xaa);
767                  board->keyFakeShiftState = 0;
768               }
769               if (board->keyFakeUnshiftState)
770               {
771                  /* Fake shift press */
772                  post_in_keyQueue(board, 0xe0);
773                  post_in_keyQueue(board, 0x2a);
774                  board->keyFakeUnshiftState = 0;
775               }
776               //}
777
778               /* update shift and numlock state */
779               if ((keycode == 0x2a) || (keycode == 0x36))
780                  board->keyRealShiftState = board->keyRealShiftState + (pressed ? +1 : -1);
781               if ((keycode == 0x1d) || (keycode == 0x61))
782                  board->keyCtrlState = board->keyCtrlState + (pressed ? +1 : -1);
783               if ((keycode == 0x38) || (keycode == 0x62))
784                  board->keyAltState = board->keyAltState + (pressed ? +1 : -1);
785               if ((keycode == 0x45) && pressed)
786                  board->keyNumLockState = ! board->keyNumLockState;
787
788               if ((keycode >= 0x60) && (keycode < 0x6e))
789               {   /* simpler extended keys */
790                  /* these keys are emulated */
791
792                  if ((keycode >= 0x63) && pressed)
793                  {
794                     /* Handle shift state */
795                     if (keycode == 0x63)
796                     {   /* non-shifted key */
797                        if (board->keyRealShiftState)
798                           /* Fake shift unpress */
799                           board->keyFakeUnshiftState = 1;
800                     }
801                     else /*if (keycode >= 0x64)*/
802                     {   /* non-numlock mode key */
803                        if (board->keyNumLockState & ! board->keyRealShiftState)
804                           /* Fake shift press if numlock is active */
805                           board->keyFakeShiftState = 1;
806                        else if ((! board->keyNumLockState) & board->keyRealShiftState)
807                           /* Fake shift unpress if shift is down */
808                           board->keyFakeUnshiftState = 1;
809                     }
810
811                     if (board->keyFakeShiftState)
812                     {
813                        post_in_keyQueue(board, 0xe0);
814                        post_in_keyQueue(board, 0x2a);
815                     }
816
817                     if (board->keyFakeUnshiftState)
818                     {
819                        post_in_keyQueue(board, 0xe0);
820                        post_in_keyQueue(board, 0xaa);
821                     }
822                  }
823
824                  keycode = keyboard_mf1_code[keycode-0x60];
825                  if (! pressed)
826                     keycode |= 0x80;
827                  post_in_keyQueue(board, 0xe0);
828                  post_in_keyQueue(board, keycode);
829               }
830               else if (keycode == 0x6e)
831               {   /* emulate Print Screen / System Request (F13) key */
832                  /* this is a bit complex, as Alt+PrtScr -> SysRq */
833                  /* Additionally, Ctrl+PrtScr involves no fake shift press */
834                  if (board->keyAltState)
835                  {
836                     /* SysRq */
837                     keycode = 0x54;
838                     if (! pressed)
839                        keycode |= 0x80;
840                     post_in_keyQueue(board, keycode);
841                  }
842                  else
843                  {
844                     /* Handle shift state */
845                     if (pressed && (! board->keyRealShiftState) && (! board->keyCtrlState))
846                     {   /* Fake shift press */
847                        post_in_keyQueue(board, 0xe0);
848                        post_in_keyQueue(board, 0x2a);
849                        board->keyFakeShiftState = 1;
850                     }
851
852                     keycode = 0x37;
853                     if (! pressed)
854                        keycode |= 0x80;
855                     post_in_keyQueue(board, 0xe0);
856                     post_in_keyQueue(board, keycode);
857                  }
858               }
859               else if (keycode == 0x6f)
860               {   // emulate pause (F15) key
861                  // this is a bit complex, as Pause -> Ctrl+NumLock and
862                  // Ctrl+Pause -> Ctrl+ScrLock.  Furthermore, there is no
863                  // repeat or release.
864                  if (pressed)
865                  {
866                     if (board->keyCtrlState)
867                     {
868                        post_in_keyQueue(board, 0xe0);
869                        post_in_keyQueue(board, 0x46);
870                        post_in_keyQueue(board, 0xe0);
871                        post_in_keyQueue(board, 0xc6);
872                     }
873                     else
874                     {
875                        post_in_keyQueue(board, 0xe1);
876                        post_in_keyQueue(board, 0x1d);
877                        post_in_keyQueue(board, 0x45);
878                        post_in_keyQueue(board, 0xe1);
879                        post_in_keyQueue(board, 0x9d);
880                        post_in_keyQueue(board, 0xc5);
881                     }
882                  }
883               }
884               else
885               {
886                  if (! pressed)
887                     keycode |= 0x80;
888                  post_in_keyQueue(board, keycode);
889               }
890               read_key_if_possible(board);
891            }
892         }
893      }
894   }
895
896   /* Handle auto-repeat */
897   if ((board->keyQueueLen <= (KEYQUEUESIZE-MAXKEYMSGLENGTH)) && board->keyAutoRepeatKey && (--board->keyAutoRepeatTimer == 0))
898   {
899      if ((board->keyAutoRepeatKey >= 0x60) && (board->keyAutoRepeatKey < 0x6e))
900      {
901         post_in_keyQueue(board, 0xe0);
902         post_in_keyQueue(board, keyboard_mf1_code[board->keyAutoRepeatKey-0x60]);
903      }
904      else if (board->keyAutoRepeatKey == 0x6e)
905      {
906         if (board->keyAltState)
907            post_in_keyQueue(board, 0x54);
908         else
909         {
910            post_in_keyQueue(board, 0xe0);
911            post_in_keyQueue(board, 0x37);
912         }
913      }
914      else if (board->keyAutoRepeatKey == 0x6f)
915         ;
916      else
917      {
918         post_in_keyQueue(board, board->keyAutoRepeatKey);
919      }
920      read_key_if_possible(board);
921      board->keyAutoRepeatTimer = KEYAUTOREPEATRATE;
922   }
923}
924
925/****************************************************************************
926   Mouse support
927****************************************************************************/
928
929static void poll_mouse(running_device *device)
930{
931   genboard_state *board = get_safe_token(device);
932
933   int new_mx, new_my;
934   int delta_x, delta_y, buttons;
935
936   buttons = input_port_read(device->machine, "MOUSE0");
937   new_mx = input_port_read(device->machine, "MOUSEX");
938   new_my = input_port_read(device->machine, "MOUSEY");
939
940   /* compute x delta */
941   delta_x = new_mx - board->last_mx;
942
943   /* check for wrap */
944   if (delta_x > 0x80)
945      delta_x = 0x100-delta_x;
946   if  (delta_x < -0x80)
947      delta_x = -0x100-delta_x;
948
949   board->last_mx = new_mx;
950
951   /* compute y delta */
952   delta_y = new_my - board->last_my;
953
954   /* check for wrap */
955   if (delta_y > 0x80)
956      delta_y = 0x100-delta_y;
957   if  (delta_y < -0x80)
958      delta_y = -0x100-delta_y;
959
960   board->last_my = new_my;
961
962   video_update_mouse(board->video, delta_x, delta_y, buttons & 3);
963}
964
965/****************************************************************************
966   TMS9901 and attached devices handling
967****************************************************************************/
968
969/*
970    Called by the 9901 core whenever the state of INTREQ and IC0-3 changes
971*/
972static TMS9901_INT_CALLBACK( tms9901_interrupt_callback )
973{
974   /* INTREQ is connected to INT1 (IC0-3 are not connected) */
975   cputag_set_input_line(device->machine, "maincpu", 0, intreq? ASSERT_LINE : CLEAR_LINE);
976}
977
978/*
979    Read pins INT3*-INT7* of Geneve 9901.
980
981    signification:
982     (bit 1: INT1 status)
983     (bit 2: INT2 status)
984     bit 3-7: joystick status
985*/
986static READ8_DEVICE_HANDLER( R9901_0 )
987{
988   running_device *dev = device->machine->device("geneve_board");
989   genboard_state *board = get_safe_token(dev);
990   int answer;
991   answer = input_port_read(device->machine, "JOY") >> (board->joySel * 8);
992   return answer;
993}
994
995/*
996    Read pins INT8*-INT15* of Geneve 9901.
997
998    signification:
999     (bit 0: keyboard interrupt)
1000     bit 1: unused
1001     bit 2: mouse right button
1002     (bit 3: clock interrupt)
1003     (bit 4: INTB from PE-bus)
1004     bit 5 & 7: used as output
1005     bit 6: unused
1006*/
1007static READ8_DEVICE_HANDLER( R9901_1 )
1008{
1009   int answer;
1010   answer = (input_port_read(device->machine, "MOUSE0") & 4) ^ 4;
1011   return answer;
1012}
1013
1014/*
1015    Read pins P0-P7 of Geneve 9901.
1016*/
1017static READ8_DEVICE_HANDLER( R9901_2 )
1018{
1019   return 0;
1020}
1021
1022/*
1023    Read pins P8-P15 of Geneve 9901.
1024    bit 4: mouse right button
1025*/
1026static READ8_DEVICE_HANDLER( R9901_3 )
1027{
1028   int answer = 0;
1029
1030   if (! (input_port_read(device->machine, "MOUSE0") & 4))
1031      answer |= 0x10;
1032
1033   return answer;
1034}
1035
1036/*
1037    Write PE bus reset line
1038*/
1039static WRITE8_DEVICE_HANDLER( W9901_PE_bus_reset )
1040{
1041}
1042
1043/*
1044    Write VDP reset line
1045*/
1046static WRITE8_DEVICE_HANDLER( W9901_VDP_reset )
1047{
1048}
1049
1050/*
1051    Write joystick select line
1052*/
1053static WRITE8_DEVICE_HANDLER( W9901_joySel )
1054{
1055   running_device *dev = device->machine->device("geneve_board");
1056   genboard_state *board = get_safe_token(dev);
1057   board->joySel = data;
1058}
1059
1060static WRITE8_DEVICE_HANDLER( W9901_keyboardReset )
1061{
1062   running_device *dev = device->machine->device("geneve_board");
1063   genboard_state *board = get_safe_token(dev);
1064
1065   board->keyReset = !data;
1066
1067   if (board->keyReset)
1068   {
1069      /* reset -> clear keyboard key queue, but not geneve key buffer */
1070      board->keyQueueLen = board->keyInBuf ? 1 : 0;
1071      memset(board->keyStateSave, 0, sizeof(board->keyStateSave));
1072      board->keyNumLockState = 0;
1073      board->keyCtrlState = 0;
1074      board->keyAltState = 0;
1075      board->keyRealShiftState = 0;
1076      board->keyFakeShiftState = 0;
1077      board->keyFakeUnshiftState = 0;
1078      board->keyAutoRepeatKey = 0;
1079   }
1080   /*else
1081        poll_keyboard(space->machine);*/
1082}
1083
1084/*
1085    Write external mem cycles (0=long, 1=short)
1086*/
1087static WRITE8_DEVICE_HANDLER( W9901_ext_mem_wait_states )
1088{
1089}
1090
1091/*
1092    Write vdp wait cycles (1=add 15 cycles, 0=add none)
1093*/
1094static WRITE8_DEVICE_HANDLER( W9901_VDP_wait_states )
1095{
1096}
1097
1098/* tms9901 setup */
1099const tms9901_interface tms9901_wiring_geneve =
1100{
1101   TMS9901_INT1 | TMS9901_INT2 | TMS9901_INT8 | TMS9901_INTB | TMS9901_INTC,   /* only input pins whose state is always known */
1102
1103   {   /* read handlers */
1104      R9901_0,               // INTA, VDPint, Joystick
1105      R9901_1,               // Keyb, Mouse, Clock, INTB
1106      R9901_2,               // -
1107      R9901_3                  // Mouse right button
1108   },
1109
1110   {   /* write handlers */
1111      W9901_PE_bus_reset,           
1112      W9901_VDP_reset,           
1113      W9901_joySel,             
1114      NULL,                   
1115      NULL,                   
1116      NULL,                   
1117      W9901_keyboardReset,         
1118      W9901_ext_mem_wait_states,       
1119      NULL,                   
1120      W9901_VDP_wait_states,         
1121      NULL,                   
1122      NULL,                   
1123      NULL,                   
1124      NULL,                   
1125      NULL,                   
1126      NULL                 
1127   },
1128
1129   /* interrupt handler */
1130   tms9901_interrupt_callback,
1131
1132   /* clock rate = 3MHz */
1133   3000000.
1134};
1135
1136/*
1137    inta is connected to both tms9901 IRQ1 line and to tms9995 INT4/EC line.
1138*/
1139WRITE_LINE_DEVICE_HANDLER( board_inta )
1140{
1141   tms9901_set_single_int(device->machine->device("tms9901"), 1, state);
1142   cputag_set_input_line(device->machine, "maincpu", 1, state ? ASSERT_LINE : CLEAR_LINE);
1143}
1144
1145/*
1146    intb is connected to tms9901 IRQ12 line.
1147*/
1148WRITE_LINE_DEVICE_HANDLER( board_intb )
1149{
1150   tms9901_set_single_int(device->machine->device("tms9901"), 12, state);
1151
1152}
1153
1154WRITE_LINE_DEVICE_HANDLER( board_ready )
1155{
1156   logerror("READY line set ... not yet connected, level=%02x\n", state);
1157}
1158
1159/*
1160    set the state of int2 (called by the v9938 core)
1161*/
1162void tms9901_gen_set_int2(running_machine *machine, int state)
1163{
1164   tms9901_set_single_int(machine->device("tms9901"), 2, state);
1165}
1166
1167/***************************************************************************
1168    DEVICE LIFECYCLE FUNCTIONS
1169***************************************************************************/
1170
1171static const mm58274c_interface geneve_mm58274c_interface =
1172{
1173   1,   /*  mode 24*/
1174   0   /*  first day of week */
1175};
1176
1177static MACHINE_CONFIG_FRAGMENT( genboard )
1178   MDRV_MM58274C_ADD("mm58274c", geneve_mm58274c_interface)
1179MACHINE_CONFIG_END
1180   
1181static DEVICE_START( genboard )
1182{
1183   logerror("Starting Geneve board\n");
1184   genboard_state *board = get_safe_token(device);
1185   board->video = device->siblingdevice("video");
1186   board->tms9901 = device->siblingdevice("tms9901");
1187   board->peribox = device->siblingdevice("peribox");
1188   board->cpu = device->siblingdevice("maincpu");
1189   board->sound = device->siblingdevice("soundgen");
1190   
1191   board->clock = device->subdevice("mm58274c");
1192
1193   board->sram = (UINT8*)malloc(SRAM_SIZE);
1194   board->dram = (UINT8*)malloc(DRAM_SIZE);
1195   board->eprom = memory_region(device->machine, "maincpu");
1196   assert(board->video && board->tms9901);
1197   assert(board->peribox && board->cpu);
1198   assert(board->sound && board->clock);
1199   assert(board->eprom);
1200   board->geneve_mode = 0;
1201   board->direct_mode = 1;
1202   
1203   memset(board->sram, 0x00, SRAM_SIZE);
1204   memset(board->dram, 0x00, DRAM_SIZE);
1205}
1206
1207static DEVICE_STOP( genboard )
1208{
1209   logerror("Stopping Geneve board\n");
1210   genboard_state *board = get_safe_token(device);
1211   free(board->sram);
1212   free(board->dram);
1213}
1214
1215static DEVICE_RESET( genboard )
1216{
1217   genboard_state *board = get_safe_token(device);
1218   logerror("Resetting Geneve board\n");
1219   board->joySel = 0;
1220   board->keyQueueHead = board->keyQueueLen = 0;
1221   memset(board->keyStateSave, 0, sizeof(board->keyStateSave));
1222   board->keyNumLockState = 0;
1223   board->keyCtrlState = 0;
1224   board->keyAltState = 0;
1225   board->keyRealShiftState = 0;
1226   board->keyFakeShiftState = 0;
1227   board->keyFakeUnshiftState = 0;
1228   board->keyAutoRepeatKey = 0;
1229   board->keyInBuf = 0;
1230   board->keyReset = 1;
1231   board->last_mx = 0;
1232   board->last_my = 0;
1233   board->line_count = 0;
1234   
1235   board->palvideo = 0;
1236   board->capslock = 0;
1237   board->keyboard_clock = 0;
1238   board->keep_keybuf = 0;
1239   board->zero_wait = 1;
1240   
1241   board->geneve_mode = 0;
1242   board->direct_mode = 1;
1243   board->cartridge_size_8K = 0;
1244   board->cartridge_secondpage = 0;
1245   board->cartridge6_writable = 0;
1246   board->cartridge7_writable = 0;
1247   for (int i=0; i < 8; i++) board->map[i] = 0;
1248   
1249   if (input_port_read(device->machine, "BOOTROM")==0)
1250   {
1251      board->eprom = memory_region(device->machine, "maincpu") + offset_altrom_geneve;
1252   }
1253}
1254
1255static const char DEVTEMPLATE_SOURCE[] = __FILE__;
1256
1257#define DEVTEMPLATE_ID(p,s)             p##genboard##s
1258#define DEVTEMPLATE_FEATURES            DT_HAS_START | DT_HAS_STOP | DT_HAS_RESET | DT_HAS_MACHINE_CONFIG
1259#define DEVTEMPLATE_NAME                "Geneve system board"
1260#define DEVTEMPLATE_FAMILY              "Internal component"
1261#include "devtempl.h"
1262
1263DEFINE_LEGACY_DEVICE( GENBOARD, genboard );
src/mess/machine/ti99/sgcpu.c
r0r9485
1/***************************************************************************
2   
3   SGCPU board
4   including decoder/mapper
5   
6   This component implements the address decoder and mapper logic from the
7   SGCPU expansion card (inofficially called TI-99/4P).
8     
9   Michael Zapf, October 2010
10   
11   TODO: Check for wait states
12***************************************************************************/
13
14#include "emu.h"
15#include "peribox.h"
16#include "sgcpu.h"
17#include "videowrp.h"
18#include "sound/sn76496.h"
19#include "devices/cassette.h"
20
21typedef struct _sgcpu_state
22{
23   /* Pointer to ROM0 */
24   UINT16 *rom0;
25
26   /* Pointer to DSR ROM */
27   UINT16 *dsr;
28
29   /* Pointer to ROM6, first bank */
30   UINT16 *rom6a;
31
32   /* Pointer to ROM6, second bank */
33   UINT16 *rom6b;
34
35   /* AMS RAM (1 Mib) */
36   UINT16 *ram;
37   
38   /* Scratch pad ram (1 KiB) */
39   UINT16 *scratchpad;
40   
41   /* True if SGCPU DSR is enabled */
42   int internal_dsr;
43
44   /* True if SGCPU rom6 is enabled */
45   int internal_rom6;
46
47   /* Offset to the ROM6 bank. */
48   int rom6_bank;
49
50   /* TRUE when mapper is active */
51   int map_mode;
52
53   /* TRUE when mapper registers are accessible */
54   int access_mapper;
55
56   UINT8   lowbyte;
57   UINT8   highbyte;
58   UINT8   latch;
59     
60   /* Mapper registers */
61   UINT8 mapper[16];
62   
63   running_device *cpu;
64   running_device *soundchip;
65   running_device *video;
66   running_device *cassette;
67   running_device *peribox;
68   
69   int keyCol;
70   int alphaLockLine;
71   
72} sgcpu_state;
73
74
75INLINE sgcpu_state *get_safe_token(running_device *device)
76{
77   assert(device != NULL);
78   assert(downcast<legacy_device_base *>(device)->token() != NULL);
79   return (sgcpu_state *)downcast<legacy_device_base *>(device)->token();
80}
81
82
83/***************************************************************************
84   AMS Memory implementation
85***************************************************************************/
86
87#define MAP_CRU_BASE 0x0f00
88#define SAMS_CRU_BASE 0x1e00
89
90/*
91   CRU write (there is no read here)
92*/
93WRITE8_DEVICE_HANDLER( sgcpu_cru_w )
94{
95   sgcpu_state *sgcpu = get_safe_token(device);
96   int addroff = (offset + 0x0400)<<1;
97
98   if ((addroff & 0xff00)==MAP_CRU_BASE)
99   {
100      if ((addroff & 0x000e)==0) sgcpu->internal_dsr = data;
101      if ((addroff & 0x000e)==2) sgcpu->internal_rom6 = data;
102      if ((addroff & 0x000e)==4)
103      {
104         ti99_peb_senila(sgcpu->peribox, data);
105      }
106      if ((addroff & 0x000e)==6)
107      {
108         ti99_peb_senilb(sgcpu->peribox, data);
109      }
110      // TODO: more CRU bits? 8=Fast timing / a=KBENA
111      return;
112   }
113   if ((addroff & 0xff00)==SAMS_CRU_BASE)
114   {
115      if ((addroff & 0x000e)==0) sgcpu->access_mapper = data;
116      if ((addroff & 0x000e)==2) sgcpu->map_mode = data;
117      return;
118   }
119
120   // No match - pass to peribox
121   ti99_peb_cru_w(sgcpu->peribox, addroff, data);
122}
123
124READ8_DEVICE_HANDLER( sgcpu_cru_r )
125{
126   sgcpu_state *sgcpu = get_safe_token(device);
127   UINT8 value = 0;
128   int addroff = (offset + 0x0080)<<4;
129
130   ti99_peb_cru_rz(sgcpu->peribox, addroff, &value);
131   return value;
132}
133
134/*
135    Memory read. The SAMS card has two address areas: The memory is at locations
136   0x2000-0x3fff and 0xa000-0xffff, and the mapper area is at 0x4000-0x401e
137   (only even addresses).
138*/
139static READ16_DEVICE_HANDLER( sgcpu_samsmem_r )
140{
141   sgcpu_state *sgcpu = get_safe_token(device);
142   UINT32 address = 0;
143   int addroff = offset << 1;
144
145   // select memory expansion
146   if (sgcpu->map_mode)
147      address = (sgcpu->mapper[(addroff>>12) & 0x000f] << 12) + (addroff & 0x0fff);
148   else // transparent mode
149      address = addroff;
150   
151   return sgcpu->ram[address>>1];       
152}
153
154/*
155   Memory write
156*/
157static WRITE16_DEVICE_HANDLER( sgcpu_samsmem_w )
158{
159   sgcpu_state *sgcpu = get_safe_token(device);
160   UINT32 address = 0;
161   int addroff = offset << 1;
162   
163   // select memory expansion
164   if (sgcpu->map_mode)
165      address = (sgcpu->mapper[(addroff>>12) & 0x000f] << 12) + (addroff & 0x0fff);
166   else // transparent mode
167      address = addroff;
168   
169   COMBINE_DATA(&sgcpu->ram[address>>1]);
170}
171
172/***************************************************************************
173    Internal datamux; similar to TI-99/4A
174***************************************************************************/
175
176static READ16_DEVICE_HANDLER( sgcpu_datamux_r )
177{
178   sgcpu_state *sgcpu = get_safe_token(device);
179
180   UINT8 hbyte = 0;
181   UINT16 addroff = (offset << 1);
182
183   ti99_peb_data_rz(sgcpu->peribox, addroff+1, &sgcpu->latch);
184   sgcpu->lowbyte = sgcpu->latch;
185     
186   // Takes three cycles
187   cpu_adjust_icount(sgcpu->cpu, -3);
188
189   ti99_peb_data_rz(sgcpu->peribox, addroff, &hbyte);
190   sgcpu->highbyte = hbyte;
191   
192   // Takes three cycles
193   cpu_adjust_icount(sgcpu->cpu, -3);
194
195   // use the latch and the currently read byte and put it on the 16bit bus
196//   printf("read  address = %04x, value = %04x, memmask = %4x\n", addroff,  (hbyte<<8) | sgcpu->latch, mem_mask);
197   return (hbyte<<8) | sgcpu->latch ;
198}
199
200/*
201    Write access.
202    TODO: use the 16-bit expansion in the box for suitable cards
203*/
204static WRITE16_DEVICE_HANDLER( sgcpu_datamux_w )
205{
206   sgcpu_state *sgcpu = get_safe_token(device);
207   UINT16 addroff = (offset << 1);         
208//   printf("write address = %04x, value = %04x, memmask = %4x\n", addroff, data, mem_mask);
209   
210   // read more about the datamux in datamux.c
211   
212   // byte-only transfer, high byte
213   // we use the previously read low byte to complete
214   if (mem_mask == 0xff00)
215      data = data | sgcpu->lowbyte;
216   
217   // byte-only transfer, low byte   
218   // we use the previously read high byte to complete   
219   if (mem_mask == 0x00ff)
220      data = data | (sgcpu->highbyte << 8);
221
222   // Write to the PEB
223   ti99_peb_data_w(sgcpu->peribox, addroff+1, data & 0xff);
224
225   // Takes three cycles
226   cpu_adjust_icount(sgcpu->cpu,-3);
227   
228   // Write to the PEB
229   ti99_peb_data_w(sgcpu->peribox, addroff, (data>>8) & 0xff);
230   
231   // Takes three cycles
232   cpu_adjust_icount(sgcpu->cpu,-3);
233}
234
235/*
236    Read access.
237*/
238READ16_DEVICE_HANDLER( sgcpu_r )
239{
240   sgcpu_state *sgcpu = get_safe_token(device);
241   if (sgcpu->cpu == NULL) return 0;
242
243   int addroff = offset << 1;
244   UINT16 zone = addroff & 0xe000;
245   UINT16 value = 0;
246   
247   if (zone==0x0000)
248   {
249      // ROM0
250      value = sgcpu->rom0[(addroff & 0x1fff)>>1];
251      return value;
252   }
253   if (zone==0x2000 || zone==0xa000 || zone==0xc000 || zone==0xe000)
254   {
255      value = sgcpu_samsmem_r(device, offset, mem_mask);
256      return value;
257   }
258   
259   if (zone==0x4000)
260   {
261      if (sgcpu->internal_dsr)
262      {
263         value = sgcpu->dsr[(addroff & 0x1fff)>>1];     
264         return value;
265      }
266      else
267      {
268         if (sgcpu->access_mapper && ((addroff & 0xffe0)==0x4000))
269         {
270            value = sgcpu->mapper[offset & 0x000f]<<8;
271            return value;
272         }
273      }
274   }
275   
276   if (zone==0x6000 && sgcpu->internal_rom6)
277   {
278      if (sgcpu->rom6_bank==0)
279         value = sgcpu->rom6a[(addroff & 0x1fff)>>1];
280      else
281         value = sgcpu->rom6b[(addroff & 0x1fff)>>1];
282
283      return value;
284   }
285
286   // Scratch pad RAM and sound
287   // speech is in peribox
288   // groms are in hsgpl in peribox
289   if (zone==0x8000)
290   {
291      if ((addroff & 0xfff0)==0x8400)
292      {
293         value = 0;
294         return value;
295      }
296      if ((addroff & 0xfc00)==0x8000)
297      {
298         value = sgcpu->scratchpad[(addroff & 0x03ff)>>1];
299         return value;
300      }
301      // Video: 8800, 8802
302      if ((addroff & 0xfffd)==0x8800)
303      {
304         value = ti_v9938_r16(sgcpu->video, offset, mem_mask);
305         return value;
306      }
307   }
308   
309   // If we are here, check the peribox via the datamux
310   // catch-all for unmapped zones
311   value = sgcpu_datamux_r(device, offset, mem_mask);
312   return value;
313}
314
315/*
316    Write access.
317*/
318WRITE16_DEVICE_HANDLER( sgcpu_w )
319{
320   sgcpu_state *sgcpu = get_safe_token(device);
321   if (sgcpu->cpu == NULL) return;
322
323//   cpu_adjust_icount(sgcpu->cpu, -4);
324   
325   int addroff = offset << 1;
326   UINT16 zone = addroff & 0xe000;
327   
328   if (zone==0x0000)
329   {
330      // ROM0
331      logerror("SGCPU: ignoring ROM write access at %04x\n", addroff);
332      return;
333   }
334
335   if (zone==0x2000 || zone==0xa000 || zone==0xc000 || zone==0xe000)
336   {
337      sgcpu_samsmem_w(device, offset, data, mem_mask);
338      return;
339   }
340   
341   if (zone==0x4000)
342   {
343      if (sgcpu->internal_dsr)
344      {
345         logerror("SGCPU: ignoring DSR write access at %04x\n", addroff);
346         return;
347      }
348      else
349      {
350         if (sgcpu->access_mapper && ((addroff & 0xffe0)==0x4000))
351         {
352            COMBINE_DATA(&sgcpu->mapper[offset & 0x000f]);
353            return;
354         }
355      }
356   }
357
358   if (zone==0x6000 && sgcpu->internal_rom6)
359   {
360      sgcpu->rom6_bank = offset & 0x0001;
361      return;
362   }
363
364   // Scratch pad RAM and sound
365   // speech is in peribox
366   // groms are in hsgpl in peribox
367   if (zone==0x8000)
368   {
369      if ((addroff & 0xfff0)==0x8400)
370      {
371         sn76496_w(sgcpu->soundchip, 0, (data >> 8) & 0xff);
372         return;
373      }
374      if ((addroff & 0xfc00)==0x8000)
375      {
376         COMBINE_DATA(&sgcpu->scratchpad[(addroff & 0x03ff)>>1]);
377         return;
378      }
379      // Video: 8C00, 8C02
380      if ((addroff & 0xfffd)==0x8c00)
381      {
382         ti_v9938_w16(sgcpu->video, offset, data, mem_mask);
383         return;
384      }
385   }
386   
387   // If we are here, check the peribox via the datamux
388   // catch-all for unmapped zones
389   sgcpu_datamux_w(device, offset, data, mem_mask);
390}
391
392/***************************************************************************
393   Control lines
394****************************************************************************/
395/*
396   Handles the EXTINT line. This one is directly connected to the 9901.
397*/
398WRITE_LINE_DEVICE_HANDLER( card_extint )
399{
400   tms9901_set_single_int(device->machine->device("tms9901"), 1, state);
401}
402
403WRITE_LINE_DEVICE_HANDLER( card_notconnected )
404{
405   logerror("Not connected line set ... sorry\n");
406}
407
408WRITE_LINE_DEVICE_HANDLER( card_ready )
409{
410   logerror("READY line set ... not yet connected, level=%02x\n", state);
411}
412
413/*
414    set the state of int2 (called by the v9938)
415*/
416void tms9901_sg_set_int2(running_machine *machine, int state)
417{
418   tms9901_set_single_int(machine->device("tms9901"), 2, state);
419}
420
421/***************************************************************************
422   Keyboard/tape control
423****************************************************************************/
424static const char *keynames[] = { "KEY0", "KEY1", "KEY2", "KEY3" };
425
426/*
427    Called by the 9901 core whenever the state of INTREQ and IC0-3 changes
428*/
429static TMS9901_INT_CALLBACK( tms9901_interrupt_callback )
430{
431   if (intreq)
432   {
433      // On TI99, TMS9900 IC0-3 lines are not connected to TMS9901,
434      // but hard-wired to force level 1 interrupts
435      cputag_set_input_line_and_vector(device->machine, "maincpu", 0, ASSERT_LINE, 1);
436   }
437   else
438   {
439      cputag_set_input_line(device->machine, "maincpu", 0, CLEAR_LINE);
440   }
441}
442
443
444/*
445    Read pins INT3*-INT7* of TI99's 9901.
446
447    signification:
448     (bit 1: INT1 status)
449     (bit 2: INT2 status)
450     bit 3-7: keyboard status bits 0 to 4
451*/
452static READ8_DEVICE_HANDLER( sgcpu_R9901_0 )
453{
454   running_device *dev = device->machine->device("sgcpu_board");
455   sgcpu_state *sgcpu = get_safe_token(dev);
456   int answer;
457
458   answer = ((input_port_read(device->machine, keynames[sgcpu->keyCol >> 1]) >> ((sgcpu->keyCol & 1) * 8)) << 3) & 0xF8;
459   
460   if (sgcpu->alphaLockLine == FALSE)
461      answer &= ~(input_port_read(device->machine, "ALPHA") << 3);
462   
463   return answer;
464}
465
466/*
467    Read pins INT8*-INT15* of TI99's 9901.
468     bit 0-2: keyboard status bits 5 to 7
469     bit 3: tape input mirror
470     bit 5-7: weird, not emulated
471*/
472static READ8_DEVICE_HANDLER( sgcpu_R9901_1 )
473{
474   running_device *dev = device->machine->device("sgcpu_board");
475   sgcpu_state *sgcpu = get_safe_token(dev);
476   int answer;
477
478   if (sgcpu->keyCol == 7)
479      answer = 0x07;
480   else
481   {
482      answer = ((input_port_read(device->machine, keynames[sgcpu->keyCol >> 1]) >> ((sgcpu->keyCol & 1) * 8)) >> 5) & 0x07;
483   }
484   return answer;
485}
486
487
488/*
489    Read pins P8-P15 of TI99's 9901.
490     bit 26: high
491     bit 27: tape input
492*/
493static READ8_DEVICE_HANDLER( sgcpu_R9901_3 )
494{
495   running_device *dev = device->machine->device("sgcpu_board");
496   sgcpu_state *sgcpu = get_safe_token(dev);
497   int answer = 4;   /* on systems without handset, the pin is pulled up to avoid spurious interrupts */
498   if (cassette_input(sgcpu->cassette) > 0)
499      answer |= 8;
500   return answer;
501}
502
503/*
504    WRITE key column select (P2-P4)
505*/
506static WRITE8_DEVICE_HANDLER( sgcpu_KeyC )
507{
508   running_device *dev = device->machine->device("sgcpu_board");
509   sgcpu_state *sgcpu = get_safe_token(dev);
510   if (data)
511      sgcpu->keyCol |= 1 << (offset-2);
512   else
513      sgcpu->keyCol &= ~(1 << (offset-2));
514}
515
516/*
517    WRITE alpha lock line - TI99/4a only (P5)
518*/
519static WRITE8_DEVICE_HANDLER( sgcpu_AlphaW )
520{
521   running_device *dev = device->machine->device("sgcpu_board");
522   sgcpu_state *sgcpu = get_safe_token(dev);
523   sgcpu->alphaLockLine = data;
524}
525
526/*
527    command CS1 (only) tape unit motor (P6)
528*/
529static WRITE8_DEVICE_HANDLER( sgcpu_CS_motor )
530{
531   running_device *dev = device->machine->device("sgcpu_board");
532   sgcpu_state *sgcpu = get_safe_token(dev);
533   cassette_change_state(sgcpu->cassette, data ? CASSETTE_MOTOR_ENABLED : CASSETTE_MOTOR_DISABLED, CASSETTE_MASK_MOTOR);
534}
535
536/*
537    audio gate (P8)
538
539    Set to 1 before using tape: this enables the mixing of tape input sound
540    with computer sound.
541
542    We do not really need to emulate this as the tape recorder generates sound
543    on its own.
544*/
545static WRITE8_DEVICE_HANDLER( sgcpu_audio_gate )
546{
547}
548
549/*
550    tape output (P9)
551    I think polarity is correct, but don't take my word for it.
552*/
553static WRITE8_DEVICE_HANDLER( sgcpu_CS_output )
554{
555   running_device *dev = device->machine->device("sgcpu_board");
556   sgcpu_state *sgcpu = get_safe_token(dev);
557   cassette_output(sgcpu->cassette, data ? +1 : -1);
558}
559
560/* TMS9901 setup. The callback functions pass a reference to the TMS9901 as device. */
561const tms9901_interface tms9901_wiring_ti99_4p =
562{
563   TMS9901_INT1 | TMS9901_INT2 | TMS9901_INTC,   /* only input pins whose state is always known */
564
565   {   /* read handlers */
566      sgcpu_R9901_0,
567      sgcpu_R9901_1,
568      NULL,
569      sgcpu_R9901_3
570   },
571
572   {   /* write handlers */
573      NULL,
574      NULL,
575      sgcpu_KeyC,
576      sgcpu_KeyC,
577      sgcpu_KeyC,
578      sgcpu_AlphaW,
579      sgcpu_CS_motor,
580      NULL,
581      sgcpu_audio_gate,
582      sgcpu_CS_output,
583      NULL,
584      NULL,
585      NULL,
586      NULL,
587      NULL,
588      NULL
589   },
590
591   /* interrupt handler */
592   tms9901_interrupt_callback,
593
594   /* clock rate = 3MHz */
595   3000000.
596};
597
598
599/***************************************************************************
600    DEVICE LIFECYCLE FUNCTIONS
601***************************************************************************/
602
603static DEVICE_START( sgcpu )
604{
605//   // printf("Starting mapper\n");
606   sgcpu_state *sgcpu = get_safe_token(device);
607   sgcpu->cpu = device->machine->device("maincpu");
608   sgcpu->peribox = device->machine->device("peribox");
609   sgcpu->soundchip = device->machine->device("soundgen");
610   sgcpu->video = device->machine->device("video");
611   sgcpu->cassette = device->machine->device("cassette");
612   
613   assert(sgcpu->cpu && sgcpu->peribox && sgcpu->soundchip && sgcpu->video && sgcpu->cassette);
614   
615   sgcpu->ram = (UINT16*)malloc(0x080000);
616   sgcpu->scratchpad = (UINT16*)malloc(0x0400);
617   
618   UINT16 *rom = (UINT16*)memory_region(device->machine, "maincpu");
619   sgcpu->rom0  = rom + 0x2000;
620   sgcpu->dsr   = rom + 0x6000;   
621   sgcpu->rom6a = rom + 0x3000;   
622   sgcpu->rom6b = rom + 0x7000;   
623}
624
625static DEVICE_STOP( sgcpu )
626{
627   // printf("Stopping SGCPU\n");
628   sgcpu_state *sgcpu = get_safe_token(device);
629   free(sgcpu->ram);
630   free(sgcpu->scratchpad);
631}
632
633static DEVICE_RESET( sgcpu )
634{
635   logerror("Resetting SGCPU\n");
636}
637
638static const char DEVTEMPLATE_SOURCE[] = __FILE__;
639
640#define DEVTEMPLATE_ID(p,s)             p##sgcpu##s
641#define DEVTEMPLATE_FEATURES            DT_HAS_START | DT_HAS_STOP | DT_HAS_RESET
642#define DEVTEMPLATE_NAME                "SGCPU Board"
643#define DEVTEMPLATE_FAMILY              "Peripheral Expansion"
644#include "devtempl.h"
645
646DEFINE_LEGACY_DEVICE( SGCPU, sgcpu );
src/mess/machine/ti99/hsgpl.h
r0r9485
1/*
2    SNUG HSGPL card emulation.
3    Raphael Nabet, 2003.
4   
5    Rewritten as device
6    Michael Zapf, 2010
7*/
8
9/* device interface */
10#ifndef __HSGPL__
11#define __HSGPL__
12
13DECLARE_LEGACY_NVRAM_DEVICE( HSGPL, hsgpl );
14#endif
15
src/mess/machine/ti99/genboard.h
r0r9485
1#ifndef __GENBOARD__
2#define __GENBOARD__
3
4#include "machine/tms9901.h"
5
6READ8_DEVICE_HANDLER( geneve_r );
7WRITE8_DEVICE_HANDLER( geneve_w );
8READ8_DEVICE_HANDLER( geneve_cru_r );
9WRITE8_DEVICE_HANDLER( geneve_cru_w );
10
11extern const tms9901_interface tms9901_wiring_geneve;
12void tms9901_gen_set_int2(running_machine *machine, int state);
13
14/* device interface */
15DECLARE_LEGACY_DEVICE( GENBOARD, genboard );
16
17WRITE_LINE_DEVICE_HANDLER( board_inta );
18WRITE_LINE_DEVICE_HANDLER( board_intb );
19WRITE_LINE_DEVICE_HANDLER( board_ready );
20
21#define MDRV_GENEVE_BOARD_ADD(_tag )         \
22   MDRV_DEVICE_ADD(_tag, GENBOARD, 0)
23   
24#endif
src/mess/machine/ti99/sgcpu.h
r0r9485
1#ifndef __SGCPU__
2#define __SGCPU__
3
4#include "machine/tms9901.h"
5
6void tms9901_sg_set_int2(running_machine *machine, int state);
7
8READ16_DEVICE_HANDLER( sgcpu_r );
9WRITE16_DEVICE_HANDLER( sgcpu_w );
10
11READ8_DEVICE_HANDLER( sgcpu_cru_r );
12WRITE8_DEVICE_HANDLER( sgcpu_cru_w );
13
14WRITE_LINE_DEVICE_HANDLER( card_extint );
15WRITE_LINE_DEVICE_HANDLER( card_notconnected );
16WRITE_LINE_DEVICE_HANDLER( card_ready );
17
18/* device interface */
19DECLARE_LEGACY_DEVICE( SGCPU, sgcpu );
20
21#define MDRV_SGCPUB_ADD(_tag )         \
22   MDRV_DEVICE_ADD(_tag, SGCPU, 0)
23
24extern const tms9901_interface tms9901_wiring_ti99_4p;
25   
26#endif
src/mess/machine/ti99/ti_fdc.c
r0r9485
1/*
2   TI Standard Floppy Disk Controller
3   September 2010
4   
5   Michael Zapf
6*/
7#include "emu.h"
8#include "peribox.h"
9#include "ti_fdc.h"
10#include "machine/wd17xx.h"
11#include "formats/ti99_dsk.h"
12#include "devices/flopdrv.h"
13
14#define CRU_BASE 0x1100
15
16#define fdc_IRQ 1
17#define fdc_DRQ 2
18
19#define fdc_region "fdc_region"
20
21typedef ti99_pebcard_config ti99_fdc_config;
22
23typedef struct _ti99_fdc_state
24{
25   /* Holds the status of the DRQ and IRQ lines. */
26   int               DRQ_IRQ_status;
27   
28   /* When TRUE, card is accessible. Indicated by a LED. */
29   int               selected;
30
31   /* When TRUE, keeps DVENA high. */
32   int               strobe_motor;
33
34   /* Signal DVENA. When TRUE, makes some drive turning. */
35   int               DVENA;
36
37   /* When TRUE the CPU is halted while DRQ/IRQ are true. */
38   int               hold;
39   
40   /* Indicates which drive has been selected. Values are 0, 1, 2, and 4. */
41   // 000 = no drive
42   // 001 = drive 1
43   // 010 = drive 2
44   // 100 = drive 3
45   int               DSEL;
46
47   /* Signal SIDSEL. 0 or 1, indicates the selected head. */
48   int               SIDSEL;
49
50   /* count 4.23s from rising edge of motor_on */
51   emu_timer          *motor_on_timer;
52   
53   /* Link to the FDC1771 controller on the board. */
54   running_device       *controller;
55
56   /* DSR ROM */
57   UINT8            *rom;
58
59   /* Callback lines to the main system. */
60   ti99_peb_connect   lines;
61   
62} ti99_fdc_state;
63
64/* Those defines are required because the WD17xx DEVICE_START implementation
65assumes that the floppy devices are either at root level or at the parent
66level. Our floppy devices, however, are at the grandparent level as seen from
67the controller. */
68
69#define PFLOPPY_0 "peribox:floppy0"
70#define PFLOPPY_1 "peribox:floppy1"
71#define PFLOPPY_2 "peribox:floppy2"
72
73INLINE ti99_fdc_state *get_safe_token(running_device *device)
74{
75   assert(device != NULL);
76   return (ti99_fdc_state *)downcast<legacy_device_base *>(device)->token();
77}
78
79/*
80    Call this when the state of DSKhold or DRQ/IRQ or DVENA change
81
82    Emulation is faulty because the CPU is actually stopped in the midst of
83    instruction, at the end of the memory access
84   
85   TODO: This has to be replaced by the proper READY handling that is already
86   prepared here. (Requires READY handling by the CPU.)
87*/
88static void fdc_handle_hold(running_device *device)
89{
90   ti99_fdc_state *card = get_safe_token(device);
91   line_state state;
92   
93   if (card->hold && (!card->DRQ_IRQ_status) && card->DVENA)
94      state = ASSERT_LINE;
95   else
96      state = CLEAR_LINE;
97   
98   // TODO: use READY
99   cputag_set_input_line(device->machine, "maincpu", INPUT_LINE_HALT, state);
100}
101
102/*
103    Resets the drive geometry. This is required because the heuristic of
104    the default implementation sets the drive geometry to the geometry
105    of the medium.
106*/
107static void set_geometry(running_device *drive, floppy_type_t type)
108{
109   if (drive!=NULL)
110      floppy_drive_set_geometry(drive, type);
111   else
112      logerror("ti99/FDC: Drive not found\n");
113}
114
115static void set_all_geometries(running_device *device, floppy_type_t type)
116{
117   set_geometry(device->machine->device(PFLOPPY_0), type);
118   set_geometry(device->machine->device(PFLOPPY_1), type);
119   set_geometry(device->machine->device(PFLOPPY_2), type);
120}
121
122
123/*************************************************************************/
124
125/*
126    The CRU read handler.
127    bit 0: HLD pin
128    bit 1-3: drive n active
129    bit 4: 0: motor strobe on
130    bit 5: always 0
131    bit 6: always 1
132    bit 7: selected side
133*/
134static READ8Z_DEVICE_HANDLER( cru_r )
135{
136   ti99_fdc_state *card = get_safe_token(device);
137
138   if ((offset & 0xff00)==CRU_BASE)
139   {
140      int addr = offset & 0x07;
141      UINT8 reply = 0;
142      if (addr == 0)
143      {
144         // deliver bits 0-7
145         // TODO: HLD pin
146         // The DVENA state is returned inverted
147         if (card->DVENA) reply |= ((card->DSEL)<<1);
148         else reply |= 0x10;
149         reply |= 0x40;
150         if (card->SIDSEL) reply |= 0x80;
151      }
152      *value = reply;
153      printf("fdc read cru %04x = %02x\n", offset, reply);
154   }
155}
156
157static WRITE8_DEVICE_HANDLER( cru_w )
158{
159   ti99_fdc_state *card = get_safe_token(device);
160   int drive, drivebit;
161
162   if ((offset & 0xff00)==CRU_BASE)
163   {
164      printf("fdc write cru %04x = %02x\n", offset, data);
165
166      int bit = (offset >> 1) & 0x07;
167      switch (bit)
168      {
169      case 0:
170         /* (De)select the card. Indicated by a LED on the board. */
171         card->selected = data;
172         break;
173      case 1:
174         /* Activate motor */
175         if (data && !card->strobe_motor)
176         {   /* on rising edge, set motor_running for 4.23s */
177            card->DVENA = TRUE;
178            fdc_handle_hold(device);
179            timer_adjust_oneshot(card->motor_on_timer, ATTOTIME_IN_MSEC(4230), 0);
180         }
181         card->strobe_motor = data;
182         break;
183         
184      case 2:
185         /* Set disk ready/hold (bit 2) */
186         // 0: ignore IRQ and DRQ
187         // 1: TMS9900 is stopped until IRQ or DRQ are set
188         // OR the motor stops rotating - rotates for 4.23s after write
189         // to CRU bit 1
190         // This is not emulated and could cause the TI99 to lock up
191         card->hold = data;
192         fdc_handle_hold(device);
193         break;
194
195      case 3:
196         /* Load disk heads (HLT pin) (bit 3). Not implemented. */
197         break;
198
199      case 4:
200      case 5:
201      case 6:
202         /* Select drive X (bits 4-6) */
203         drive = bit-4;               /* drive # (0-2) */
204         drivebit = 1<<drive;
205         
206         if (data)
207         {
208            if (!(card->DSEL & drivebit))         /* select drive */
209            {
210               if (card->DSEL != 0)
211                  logerror("ti_fdc: Multiple drives selected, %02x\n", card->DSEL); 
212               card->DSEL |= drivebit;
213               wd17xx_set_drive(card->controller, drive);
214               /*wd17xx_set_side(DSKside);*/
215            }
216         }
217         else
218            card->DSEL &= ~drivebit;
219         break;
220         
221      case 7:
222         /* Select side of disk (bit 7) */
223         card->SIDSEL = data;
224         wd17xx_set_side(card->controller, data);
225         break;
226      }   
227   }
228}
229
230/*
231    Read a byte from the ROM or from the controller
232*/
233static READ8Z_DEVICE_HANDLER( data_r )
234{
235   ti99_fdc_state *card = get_safe_token(device);
236
237   if (card->selected)
238   {
239      if ((offset & 0xe000)==0x4000)
240      {
241         // only use the even addresses from 1ff0 to 1ff6.
242         // Note that data is inverted.
243         // 0101 1111 1111 0xx0
244         UINT8 reply = 0;
245
246         if ((offset & 0x1ff9)==0x1ff0)
247            reply = wd17xx_r(card->controller, (offset >> 1)&0x03) ^ 0xff;
248         else
249            reply = card->rom[offset & 0x1fff];
250
251         *value = reply;
252         printf("fdc read %04x = %02x, %c\n", offset, *value, (char)*value);
253      }
254   }
255}
256
257/*
258    Write a byte to the controller.
259*/
260static WRITE8_DEVICE_HANDLER( data_w )
261{
262   ti99_fdc_state *card = get_safe_token(device);
263   if (card->selected)
264   {
265      if ((offset & 0xe000)==0x4000)
266      {
267         printf("fdc write %04x = %02x\n", offset, data);
268         // only use the even addresses from 1ff8 to 1ffe.
269         // Note that data is inverted.
270         // 0101 1111 1111 1xx0
271         if ((offset & 0x1ff9)==0x1ff8)
272            wd17xx_w(card->controller, (offset >> 1)&0x03, data ^ 0xff);
273      }
274   }
275}
276
277/*
278    Callback, called from the controller chip whenever DRQ/IRQ state change
279*/
280static WRITE_LINE_DEVICE_HANDLER( ti_fdc_intrq_w )
281{
282   running_device *carddev = device->owner();
283   ti99_fdc_state *card = get_safe_token(carddev);
284
285   if (state)
286   {
287      card->DRQ_IRQ_status |= fdc_IRQ;
288      // Note that INTB is actually not used in the TI-99 family. But the
289      // controller asserts the line nevertheless
290      devcb_call_write_line(&card->lines.intb, TRUE);
291   }
292   else
293   {
294      card->DRQ_IRQ_status &= ~fdc_IRQ;
295      devcb_call_write_line(&card->lines.intb, FALSE);
296   }
297   fdc_handle_hold(carddev);
298}
299
300static WRITE_LINE_DEVICE_HANDLER( ti_fdc_drq_w )
301{
302   running_device *carddev = device->owner();
303   ti99_fdc_state *card = get_safe_token(carddev);
304
305   if (state)
306      card->DRQ_IRQ_status |= fdc_DRQ;
307   else
308      card->DRQ_IRQ_status &= ~fdc_DRQ;
309
310   fdc_handle_hold(carddev);
311}
312
313/*
314    callback called at the end of DVENA pulse
315*/
316static TIMER_CALLBACK(motor_on_timer_callback)
317{
318   running_device *device = (running_device *)ptr;
319   ti99_fdc_state *card = get_safe_token(device);
320   card->DVENA = 0;
321   fdc_handle_hold(device);
322}
323
324const wd17xx_interface ti_wd17xx_interface =
325{
326   DEVCB_NULL,
327   DEVCB_LINE(ti_fdc_intrq_w),
328   DEVCB_LINE(ti_fdc_drq_w),
329   { PFLOPPY_0, PFLOPPY_1, PFLOPPY_2, NULL }
330};
331
332static ti99_peb_card fdc_card =
333{
334   data_r,
335   data_w,
336   cru_r,
337   cru_w,
338   
339   NULL, NULL,   NULL, NULL   
340};
341
342static DEVICE_START( ti99_fdc )
343{
344   ti99_fdc_state *card = (ti99_fdc_state*)downcast<legacy_device_base *>(device)->token();
345   
346   /* Resolve the callbacks to the PEB */
347   peb_callback_if *topeb = (peb_callback_if *)device->baseconfig().static_config();
348   devcb_resolve_write_line(&card->lines.ready, &topeb->ready, device);
349
350   card->motor_on_timer = timer_alloc(device->machine, motor_on_timer_callback, (void *)device);
351
352   astring *region = new astring();
353   astring_assemble_3(region, device->tag(), ":", fdc_region);   
354   card->rom = memory_region(device->machine, astring_c(region));
355   card->controller = device->subdevice("fd1771");
356}
357
358static DEVICE_STOP( ti99_fdc )
359{
360   logerror("ti99_fdc: stop\n");
361}
362
363static DEVICE_RESET( ti99_fdc )
364{
365   ti99_fdc_state *card = (ti99_fdc_state*)downcast<legacy_device_base *>(device)->token();
366
367   /* If the card is selected in the menu, register the card */
368   if (input_port_read(device->machine, "DISKCTRL") == DISK_TIFDC)
369   {
370      running_device *peb = device->owner();   
371      int success = mount_card(peb, device, &fdc_card, get_pebcard_config(device)->slot);
372      if (!success) return;
373
374      card->DSEL = 0;
375      card->SIDSEL = 0;
376      card->DVENA = 0;
377      card->strobe_motor = 0;
378
379      ti99_set_80_track_drives(FALSE);
380
381      floppy_type_t type = FLOPPY_STANDARD_5_25_DSDD_40;
382      set_all_geometries(device, type);
383   }
384   // TODO: Check that:    floppy_mon_w(w->drive, CLEAR_LINE);
385}
386
387#if 0
388static WRITE_LINE_DEVICE_HANDLER( ti99_fdc_ready )
389{
390   // Caution: The device pointer passed to this function is the calling
391   // device. That is, if we want *this* device, we need to take the owner.
392   ti99_fdc_state *card = (ti99_fdc_state*)downcast<legacy_device_base *>(device->owner())->token();
393   devcb_call_write_line( &card->lines.ready, state );
394}
395#endif
396
397MACHINE_CONFIG_FRAGMENT( ti99_fdc )
398   MDRV_WD1771_ADD("fd1771", ti_wd17xx_interface )
399MACHINE_CONFIG_END
400
401ROM_START( ti99_fdc )
402   ROM_REGION(0x2000, fdc_region, 0)
403   ROM_LOAD_OPTIONAL("disk.bin", 0x0000, 0x2000, CRC(8f7df93f) SHA1(ed91d48c1eaa8ca37d5055bcf67127ea51c4cad5)) /* TI disk DSR ROM */
404ROM_END
405
406static const char DEVTEMPLATE_SOURCE[] = __FILE__;
407
408#define DEVTEMPLATE_ID(p,s)             p##ti99_fdc##s
409#define DEVTEMPLATE_FEATURES            DT_HAS_START | DT_HAS_STOP | DT_HAS_RESET | DT_HAS_ROM_REGION | DT_HAS_INLINE_CONFIG | DT_HAS_MACHINE_CONFIG
410#define DEVTEMPLATE_NAME                "TI Floppy Disk Controller Card"
411#define DEVTEMPLATE_FAMILY              "Peripheral expansion"
412#include "devtempl.h"
413
414DEFINE_LEGACY_DEVICE( TIFDC, ti99_fdc );
415
src/mess/machine/ti99/p_code.c
r0r9485
1/*
2    TI-99 P-Code Card emulation.
3    Michael Zapf, July 2009
4
5    The P-Code card is part of the UCSD p-System support for the TI-99
6    computer family. This system is a comprehensive development system for
7    creating, running, and debugging programs written in UCSD Pascal.
8
9    The complete system consists of
10    - P-Code card, plugged into the Peripheral Expansion Box (PEB)
11    - Software on disk:
12      + PHD5063: UCSD p-System Compiler
13      + PHD5064: UCSD p-System Assembler/Linker
14      + PHD5065: UCSD p-System Editor/Filer (2 disks)
15
16    The card has a switch on the circuit board extending outside the PEB
17    which allows to turn off the card without removing it. Unlike other
18    expansion cards for the TI system, the P-Code card immediately takes
19    over control after the system is turned on.
20
21    When the p-System is booted, the screen turns cyan and remains empty.
22    There are two beeps, a pause for about 15 seconds, another three beeps,
23    and then a welcome text is displayed with a one-line menu at the screen
24    top. (Delay times seem unrealistically short; the manual says
25    30-60 seconds. To be checked.)
26    Many of the functions require one of the disks be inserted in one
27    of the disk drives. You can leave the p-System by waiting for the menu
28    to appear, and typing H (halt). This returns you to the Master Title
29    Screen, and the card is inactive until the system is reset.
30
31    The P-Code card contains the P-Code interpreter which is somewhat
32    comparable to today's Java virtual machine. Programs written for the
33    p-System are interchangeable between different platforms.
34
35    On the P-Code card we find 12 KiB of ROM, visible in the DSR memory area
36    (>4000 to >5FFF). The first 4 KiB (>4000->4FFF) are from the 4732 ROM,
37    the second and third 4 KiB (>5000->5FFF) are from a 4764 ROM, switched
38    by setting the CRU bit 4 to 1 on the CRU base >1F00.
39
40    CRU base >1F00
41        Bit 0: Activate card
42        Bit 4: Select bank 2 of the 4764 ROM (0 = bank 1)
43        Bit 7: May be connected to an indicator LED which is by default
44               wired to bit 0 (on the PCB)
45
46    The lines are used in a slightly uncommon way: the three bits of the
47    CRU bit address are A8, A13, and A14 (A15=LSB). Hence, bit 4 is at
48    address >1F80, and bit 7 is at address >1F86. These bits are purely
49    write-only.
50
51    Moreover, the card contains 48 KiB of GROM memory, occupying the address
52    space from G>0000 to G>FFFF in portions of 6KiB at every 8KiB boundary.
53
54    Another specialty of the card is that the GROM contents are accessed via
55    another GROM base address than what is used in the console:
56    - >5BFC = read GROM data
57    - >5BFE = read GROM address
58    - >5FFC = write GROM data
59    - >5FFE = write GROM address
60
61    This makes the GROM memory "private" to the card; together with the
62    rest of the ROM space the ports become invisible when the card is
63    deactivated.
64
65    Emulation information:
66
67    The P-Code card switch is mapped to a DIP switch in the configuration
68    menu. If the switch is turned on, the system assumes that ROM dumps are
69    present called "pcode_r0.bin" (4 KiB), "pcode_r1.bin" (8KiB),
70    "pcode_g0.bin" (64 KiB). The switch is turned off by default. Check the
71    switch position if the Master Title Screen does not appear as expected.
72   
73   September 2010: Rewritten as device
74*/
75#include "emu.h"
76#include "peribox.h"
77#include "p_code.h"
78#include "grom.h"
79
80#define GROMBASE 0x5bfc
81#define PCODE_CRU_BASE 0x1f00
82
83#define pcode_region "pcode_region"
84#define grom_offset 0x3000
85
86typedef ti99_pebcard_config ti99_pcoden_config;
87
88typedef struct _ti99_pcoden_state
89{
90   int selected;
91
92   int bank_select; // 0 or 1
93   
94   // Pointer to the pcode ROM data. We have three sections of the ROM code:
95   // 4K from one chip, 2 banks with 4K each from the second chip.
96   UINT8 *rom0;
97   UINT8 *rom1;
98   UINT8 *rom2;
99   UINT8 *grom;
100     
101   running_device *gromdev[8];
102
103   ti99_peb_connect      lines;
104   
105} ti99_pcoden_state;
106
107INLINE ti99_pcoden_state *get_safe_token(running_device *device)
108{
109   assert(device != NULL);
110   return (ti99_pcoden_state *)downcast<legacy_device_base *>(device)->token();
111}
112
113/*************************************************************************/
114
115/*
116    The CRU write handler. The CRU is a serial interface in the console.
117    Using the CRU we can switch the banks in the p-code card
118    Bit 0 = activate card
119    Bit 4 = select second bank of high ROM.
120    Note that the CRU address is created from address lines A8, A13, and A14
121    so bit 0 is at 0x1f00, but bit 4 is at 0x1f80 (bit 7 would be 0x1f86
122    but it is not used)
123*/
124static WRITE8_DEVICE_HANDLER( cru_w )
125{
126   ti99_pcoden_state *card = get_safe_token(device);
127
128   if ((offset & 0xff00)==PCODE_CRU_BASE)
129   {
130      int addr = offset & 0x00ff;
131     
132      if (addr==0)
133         card->selected = data;
134     
135      if (addr==0x80) // Bit 4 is on address line 8
136         card->bank_select = data;
137   }
138}
139
140/*
141    Read a byte in pcode DSR space
142*/
143static READ8Z_DEVICE_HANDLER( data_r )
144{
145   ti99_pcoden_state *card = get_safe_token(device);
146
147   if (card->selected)
148   {
149      if ((offset & 0xe000)==0x4000)
150      {
151         if ((offset & 0xfffd)==GROMBASE)
152         {
153            for (int i=0; i < 8; i++)
154               ti99grom_rz(card->gromdev[i], offset, value);
155            return;
156         }
157         
158         if (offset < 0x5000)
159         {
160            /* Accesses ROM 4732 (4K) */
161            *value = card->rom0[offset-0x4000];
162         }
163         else
164            // Accesses ROM 4764 (2*4K)
165         // We have two banks here which are activated according
166         // to the setting of CRU bit 4
167         *value = (card->bank_select==0)? card->rom1[offset-0x5000] : card->rom2[offset-0x5000];
168      }
169   }
170}
171
172/*
173    Write a byte in P-Code ROM space. This is only useful for setting the
174    GROM address.
175*/
176static WRITE8_DEVICE_HANDLER( data_w )
177{
178   ti99_pcoden_state *card = get_safe_token(device);
179   if (card->selected)
180   {
181      if ((offset & 0xfffd)==(GROMBASE|0x0400))
182      {
183         for (int i=0; i < 8; i++)
184            ti99grom_w(card->gromdev[i], offset, data);
185      }
186   }
187}
188
189static ti99_peb_card pcode_ncard =
190{
191   data_r,
192   data_w,
193   NULL,
194   cru_w,
195   
196   NULL, NULL,   NULL, NULL   
197};
198
199static DEVICE_START( ti99_pcoden )
200{
201   ti99_pcoden_state *pcode = (ti99_pcoden_state*)downcast<legacy_device_base *>(device)->token();
202   
203   /* Resolve the callbacks to the PEB */
204   peb_callback_if *topeb = (peb_callback_if *)device->baseconfig().static_config();
205   devcb_resolve_write_line(&pcode->lines.ready, &topeb->ready, device);
206}
207
208static DEVICE_STOP( ti99_pcoden )
209{
210   logerror("ti99_pcode: stop\n");
211}
212
213static DEVICE_RESET( ti99_pcoden )
214{
215   logerror("ti99_pcode: reset\n");
216   ti99_pcoden_state *pcode = (ti99_pcoden_state*)downcast<legacy_device_base *>(device)->token();
217
218   /* If the card is selected in the menu, register the card */
219   if (input_port_read(device->machine, "EXTCARD") & EXT_PCODE)
220   {
221      running_device *peb = device->owner();   
222      int success = mount_card(peb, device, &pcode_ncard, get_pebcard_config(device)->slot);
223      if (!success) return;
224     
225      astring *region = new astring();
226      astring_assemble_3(region, device->tag(), ":", pcode_region);   
227     
228      pcode->rom0 = memory_region(device->machine, astring_c(region));
229      pcode->rom1 = pcode->rom0 + 0x1000;
230      pcode->rom2 = pcode->rom0 + 0x2000;
231      pcode->grom = pcode->rom0 + 0x3000;
232      pcode->bank_select = 0;   
233      pcode->selected = 0;
234   
235      astring *gromname = new astring();
236      for (int i=0; i < 8; i++)
237      {
238         astring_printf(gromname, "grom_%d", i);
239         pcode->gromdev[i] = device->subdevice(astring_c(gromname));
240      }
241   }
242}
243
244static WRITE_LINE_DEVICE_HANDLER( pcode_ready )
245{
246   // Caution: The device pointer passed to this function is the calling
247   // device. That is, if we want *this* device, we need to take the owner.
248   ti99_pcoden_state *pcode = (ti99_pcoden_state*)downcast<legacy_device_base *>(device->owner())->token();
249   devcb_call_write_line( &pcode->lines.ready, state );
250}
251
252/*
253   Get the pointer to the GROM data from the P-Code card. Called by the GROM.
254*/
255static UINT8 *get_grom_ptr(running_device *device)
256{
257   ti99_pcoden_state *pcode = (ti99_pcoden_state*)downcast<legacy_device_base *>(device)->token();
258   return pcode->grom;
259}
260
261MACHINE_CONFIG_FRAGMENT( ti99_pcoden )
262   MDRV_GROM_ADD_P( "grom_0", 0, get_grom_ptr, 0x0000, 0x1800, pcode_ready )
263   MDRV_GROM_ADD_P( "grom_1", 1, get_grom_ptr, 0x2000, 0x1800, pcode_ready )
264   MDRV_GROM_ADD_P( "grom_2", 2, get_grom_ptr, 0x4000, 0x1800, pcode_ready )
265   MDRV_GROM_ADD_P( "grom_3", 3, get_grom_ptr, 0x6000, 0x1800, pcode_ready )
266   MDRV_GROM_ADD_P( "grom_4", 4, get_grom_ptr, 0x8000, 0x1800, pcode_ready )
267   MDRV_GROM_ADD_P( "grom_5", 5, get_grom_ptr, 0xa000, 0x1800, pcode_ready )
268   MDRV_GROM_ADD_P( "grom_6", 6, get_grom_ptr, 0xc000, 0x1800, pcode_ready )
269   MDRV_GROM_ADD_P( "grom_7", 7, get_grom_ptr, 0xe000, 0x1800, pcode_ready )
270MACHINE_CONFIG_END
271
272ROM_START( ti99_pcoden )
273   ROM_REGION(0x13000, pcode_region, 0)
274   ROM_LOAD_OPTIONAL("pcode_r0.bin", 0x0000, 0x1000, CRC(3881d5b0) SHA1(a60e0468bb15ff72f97cf6e80979ca8c11ed0426)) /* TI P-Code card rom4732 */
275   ROM_LOAD_OPTIONAL("pcode_r1.bin", 0x1000, 0x2000, CRC(46a06b8b) SHA1(24e2608179921aef312cdee6f455e3f46deb30d0)) /* TI P-Code card rom4764 */
276   ROM_LOAD_OPTIONAL("pcode_g0.bin", 0x3000, 0x10000, CRC(541b3860) SHA1(7be77c216737334ae997753a6a85136f117affb7)) /* TI P-Code card groms */
277ROM_END
278
279static const char DEVTEMPLATE_SOURCE[] = __FILE__;
280
281#define DEVTEMPLATE_ID(p,s)             p##ti99_pcoden##s
282#define DEVTEMPLATE_FEATURES            DT_HAS_START | DT_HAS_STOP | DT_HAS_RESET | DT_HAS_ROM_REGION | DT_HAS_INLINE_CONFIG | DT_HAS_MACHINE_CONFIG
283#define DEVTEMPLATE_NAME                "TI99 P-Code Card"
284#define DEVTEMPLATE_FAMILY              "Peripheral expansion"
285#include "devtempl.h"
286
287DEFINE_LEGACY_DEVICE(PCODEN, ti99_pcoden);
src/mess/machine/ti99/tn_usbsm.c
r0r9485
1/*
2    Thierry Nouspikel's USB-SmartMedia card emulation
3
4    This card features three USB ports (two host and one device) and a
5    SmartMedia interface.  The original prototype was designed by Thierry
6    Nouspikel, and its description was published in 2003; a small series of
7    approximately 100 printed-circuit boards was ordered shortly afterwards
8    by various TI users.
9
10    The specs have been published in <http://www.nouspikel.com/ti99/usb.html>.
11
12    The USB interface uses a Philips ISP1161A USB controller that supports
13    USB 2.0 full-speed (12 Mbit/s) and low-speed (1.5 Mbit/s) I/O (high speed
14    (480 Mbits/sec) is not supported, but it is hardly a problem since TI99 is
15    too slow to take advantage from high speed).  The SmartMedia interface uses
16    a few TTL buffers.  The card also includes an 8MByte StrataFlash FEEPROM
17    and 1MByte of SRAM for DSR use.
18
19    The card has a 8-bit->16-bit demultiplexer that can be set-up to assume
20    either that the LSByte of a word is accessed first or that the MSByte of a word
21    is accessed first.  The former is true with ti-99/4(a), the latter with the
22    tms9995 CPU used by Geneve and ti-99/8.
23   
24    TODO:
25    * Test SmartMedia support
26    * Implement USB controller and assorted USB devices
27    * Save DSR FEEPROM to disk
28
29    Raphael Nabet, 2004.
30
31    Rewritten as device
32    Michael Zapf, September 2010
33*/
34#include "emu.h"
35#include "peribox.h"
36#include "tn_usbsm.h"
37#include "cpu/tms9900/tms9900.h"
38#include "machine/strata.h"
39#include "machine/smartmed.h"
40
41#define CRU_BASE 0x1600
42
43typedef ti99_pebcard_config tn_usbsm_config;
44
45typedef struct _tn_usbsm_state
46{
47   running_device *smartmedia;
48
49   int    selected;
50   int      feeprom_page;
51   int      sram_page;
52   int      cru_register;
53   int      tms9995_mode;
54
55   UINT8   input_latch;
56   
57   UINT8   output_latch;
58   UINT16   *ram;
59   
60   /* Callback lines to the main system. */
61   ti99_peb_connect   lines;
62   
63} tn_usbsm_state;
64
65enum
66{
67   cru_reg_io_regs_enable = 0x02,
68   cru_reg_int_enable = 0x04,
69   cru_reg_sm_enable = 0x08,
70   cru_reg_feeprom_write_enable = 0x10
71};
72
73INLINE tn_usbsm_state *get_safe_token(running_device *device)
74{
75   assert(device != NULL);
76   return (tn_usbsm_state *)downcast<legacy_device_base *>(device)->token();
77}
78
79/*
80    demultiplexed read in USB-SmartMedia DSR space
81*/
82static UINT16 usbsm_mem_16_r(running_device *device, offs_t offset)
83{
84   UINT16 reply = 0;
85   tn_usbsm_state *card = get_safe_token(device);
86
87   if (offset < 0x2800)
88   {   /* 0x4000-0x4fff range */
89      if ((card->cru_register & cru_reg_io_regs_enable) && (offset >= 0x27f8))
90      {   /* SmartMedia interface */
91         if (offset == 0)
92            reply = smartmedia_data_r(card->smartmedia) << 8;
93      }
94      else
95      {   /* FEEPROM */
96         if (!(card->cru_register & cru_reg_feeprom_write_enable))
97            reply = strataflash_16_r(0, offset);
98      }
99   }
100   else
101   {   /* 0x5000-0x5fff range */
102      if ((card->cru_register & cru_reg_io_regs_enable) && (offset >= 0x2ff8))
103      {   /* USB controller */
104      }
105      else
106      {   /* SRAM */
107         reply = card->ram[card->sram_page*0x800+(offset-0x2800)];
108      }
109   }
110   return reply;
111}
112
113/*
114    demultiplexed write in USB-SmartMedia DSR space
115*/
116static void usbsm_mem_16_w(running_device *device, offs_t offset, UINT16 data)
117{
118   tn_usbsm_state *card = get_safe_token(device);
119
120   if (offset < 0x2800)
121   {   /* 0x4000-0x4fff range */
122      if ((card->cru_register & cru_reg_io_regs_enable) && (offset >= 0x27f8))
123      {   /* SmartMedia interface */
124         switch (offset & 3)
125         {
126         case 0:
127            smartmedia_data_w(card->smartmedia, data >> 8);
128            break;
129         case 1:
130            smartmedia_address_w(card->smartmedia, data >> 8);
131            break;
132         case 2:
133            smartmedia_command_w(card->smartmedia, data >> 8);
134            break;
135         case 3:
136            /* bogus, don't use(?) */
137            break;
138         }
139      }
140      else
141      {   /* FEEPROM */
142         if (card->cru_register & cru_reg_feeprom_write_enable)
143            strataflash_16_w(0, offset, data);
144      }
145   }
146   else
147   {   /* 0x5000-0x5fff range */
148      if ((card->cru_register & cru_reg_io_regs_enable) && (offset >= 0x2ff8))
149      {   /* USB controller */
150      }
151      else
152      {   /* SRAM */
153         card->ram[card->sram_page*0x800+(offset-0x2800)] = data;
154      }
155   }
156}
157
158/*
159    CRU read
160*/
161static READ8Z_DEVICE_HANDLER( cru_rz )
162{
163   tn_usbsm_state *card = get_safe_token(device);
164
165   if ((offset & 0xff00)==CRU_BASE)
166   {
167      UINT8 reply = 0;
168      running_device *smartmedia = card->smartmedia;
169      offset &= 3;
170     
171      if (offset == 0)
172      {
173         // bit
174         // 0   >1x00   0: USB Host controller requests interrupt.
175         // 1   >1x02   0: USB Device controller requests interrupt.
176         // 2   >1x04   1: USB Host controller suspended.
177         // 3   >1x06   1: USB Device controller suspended.
178         // 4   >1x08   0: Strata FEEPROM is busy.
179         //             1: Strata FEEPROM is ready.
180         // 5   >1x0A   0: SmartMedia card is busy.
181         //             1: SmartMedia card absent or ready.
182         // 6   >1x0C   0: No SmartMedia card present.
183         //             1: A card is in the connector.
184         // 7   >1x0E   0: SmartMedia card is protected.
185         //             1: Card absent or not protected.
186         
187         reply = 0x33;
188         if (!smartmedia_present(smartmedia))
189            reply |= 0xc0;
190         else if (!smartmedia_protected(smartmedia))
191            reply |= 0x80;
192      }
193      *value = reply;
194   }
195}
196
197/*
198   CRU write
199*/
200static WRITE8_DEVICE_HANDLER( cru_w )
201{
202   tn_usbsm_state *card = get_safe_token(device);
203
204   if ((offset & 0xff00)==CRU_BASE)
205   {
206      int bit = (offset >> 1) & 0x1f;
207
208      switch (bit)
209      {
210      case 0:
211         card->selected = data;
212         break;
213         
214      case 1:         /* enable I/O registers */
215      case 2:         /* enable interrupts */
216      case 3:         /* enable SmartMedia card */
217      case 4:         /* enable FEEPROM writes (and disable reads) */
218         if (data)
219            card->cru_register |= 1 << bit;
220         else
221            card->cru_register &= ~ (1 << bit);
222         break;
223      case 5:         /* FEEPROM page */
224      case 6:
225      case 7:
226      case 8:
227      case 9:
228      case 10:
229      case 11:
230      case 12:
231      case 13:
232      case 14:
233      case 15:
234         if (data)
235            card->feeprom_page |= 1 << (bit-5);
236         else
237            card->feeprom_page &= ~ (1 << (bit-5));
238         break;
239         
240      case 16:      /* SRAM page */
241      case 17:
242      case 18:
243      case 19:
244      case 20:
245      case 21:
246      case 22:
247      case 23:
248         if (data)
249            card->sram_page |= 1 << (bit-16);
250         else
251            card->sram_page &= ~ (1 << (bit-16));
252         break;
253      }
254   }
255}
256
257/*
258    Memory read
259*/
260static READ8Z_DEVICE_HANDLER( data_rz )
261{
262   tn_usbsm_state *card = get_safe_token(device);
263
264   if (((offset & 0xe000)==0x4000) && card->selected)
265   {
266      if (card->tms9995_mode ? (!(offset & 1)) : (offset & 1))
267      {   /* first read triggers 16-bit read cycle */
268         card->input_latch = usbsm_mem_16_r(device, offset >> 1);
269      }
270     
271      /* return latched input */
272      *value = (offset & 1) ? card->input_latch : (card->input_latch >> 8);
273   }
274}
275
276/*
277   Memory write. The controller is 16 bit, so we need to demultiplex again.
278*/
279static WRITE8_DEVICE_HANDLER( data_w )
280{
281   tn_usbsm_state *card = get_safe_token(device);
282
283   if (((offset & 0xe000)==0x4000) && card->selected)
284   {
285      /* latch write */
286      if (offset & 1)
287         card->output_latch = (card->output_latch & 0xff00) | data;
288      else
289         card->output_latch = (card->output_latch & 0x00ff) | (data << 8);
290     
291      if ((card->tms9995_mode)? (offset & 1) : (!(offset & 1)))
292      {   /* second write triggers 16-bit write cycle */
293         usbsm_mem_16_w(device, offset >> 1, card->output_latch);
294      }     
295   }
296}
297
298/**************************************************************************/
299
300static ti99_peb_card tn_usbsm_card =
301{
302   data_rz, data_w,            // memory access read/write
303   cru_rz, cru_w,               // CRU access
304   NULL, NULL,                  // SENILA/B access
305   NULL, NULL                  // 16 bit access (none here)
306};
307
308static DEVICE_START( tn_usbsm )
309{
310   tn_usbsm_state *card = (tn_usbsm_state*)downcast<legacy_device_base *>(device)->token();
311   card->ram = auto_alloc_array(device->machine, UINT16, 0x100000/2);
312   card->smartmedia = device->subdevice("smartmedia");
313   strataflash_init(device->machine, 0);
314}
315
316static DEVICE_STOP( tn_usbsm )
317{
318}
319
320static DEVICE_RESET( tn_usbsm )
321{
322   tn_usbsm_state *card = (tn_usbsm_state*)downcast<legacy_device_base *>(device)->token();
323   /* Register the card */
324   running_device *peb = device->owner();
325   
326   if (input_port_read(device->machine, "HDCTRL") & HD_USB)
327   {
328      int success = mount_card(peb, device, &tn_usbsm_card, get_pebcard_config(device)->slot);
329      if (!success) return;
330     
331      card->feeprom_page = 0;
332      card->sram_page = 0;
333      card->cru_register = 0;
334      card->tms9995_mode = (device->type()==TMS9995);
335   }
336}
337
338MACHINE_CONFIG_FRAGMENT( tn_usbsm )
339   MDRV_SMARTMEDIA_ADD( "smartmedia" )
340MACHINE_CONFIG_END
341
342static const char DEVTEMPLATE_SOURCE[] = __FILE__;
343
344#define DEVTEMPLATE_ID(p,s)             p##tn_usbsm##s
345#define DEVTEMPLATE_FEATURES            DT_HAS_START | DT_HAS_STOP | DT_HAS_RESET | DT_HAS_INLINE_CONFIG | DT_HAS_MACHINE_CONFIG
346#define DEVTEMPLATE_NAME                "Nouspikel USB/Smartmedia card"
347#define DEVTEMPLATE_FAMILY              "Peripheral expansion"
348#include "devtempl.h"
349
350DEFINE_LEGACY_DEVICE( USBSMART, tn_usbsm );
351
src/mess/machine/ti99/ti32kmem.c
r0r9485
1/*
2    TI-99 32 KiB Memory Expansion Card
3*/
4#include "emu.h"
5#include "peribox.h"
6#include "ti32kmem.h"
7
8typedef ti99_pebcard_config ti99_mem32k_config;
9
10typedef struct _ti99_mem32k_state
11{
12   UINT8 *memory;
13   
14} ti99_mem32k_state;
15
16INLINE ti99_mem32k_state *get_safe_token(running_device *device)
17{
18   assert(device != NULL);
19   return (ti99_mem32k_state *)downcast<legacy_device_base *>(device)->token();
20}
21
22/*
23    Memory read
24*/
25static READ8Z_DEVICE_HANDLER( mem32k_rz )
26{
27   ti99_mem32k_state *card = get_safe_token(device);
28
29   if (((offset & 0xe000)==0x2000) || ((offset & 0xe000)==0xa000) || ((offset & 0xc000)==0xc000))
30   {
31      if (offset < 0xa000)
32         *value = card->memory[offset-0x2000];
33      else
34         *value = card->memory[offset-0x8000];
35   }
36}
37
38/*
39   Memory write
40*/
41static WRITE8_DEVICE_HANDLER( mem32k_w )
42{
43   ti99_mem32k_state *card = get_safe_token(device);
44
45   if (((offset & 0xe000)==0x2000) || ((offset & 0xe000)==0xa000) || ((offset & 0xc000)==0xc000))
46   {
47      if (offset < 0xa000)
48         card->memory[offset-0x2000] = data;
49      else
50         card->memory[offset-0x8000] = data;
51   }
52}
53
54/**************************************************************************/
55
56static ti99_peb_card ti32k_card =
57{
58   mem32k_rz, mem32k_w,         // memory access read/write
59   NULL, NULL,                  // CRU access (none here)
60   NULL, NULL,                  // SENILA/B access (none here)
61   NULL, NULL                  // 16 bit access (none here)
62};
63
64static DEVICE_START( ti99_mem32k )
65{
66   ti99_mem32k_state *card = (ti99_mem32k_state*)downcast<legacy_device_base *>(device)->token();
67   card->memory = NULL;
68}
69
70static DEVICE_STOP( ti99_mem32k )
71{
72   ti99_mem32k_state *card = (ti99_mem32k_state*)downcast<legacy_device_base *>(device)->token();
73   if (card->memory) free(card->memory);
74}
75
76static DEVICE_RESET( ti99_mem32k )
77{
78   ti99_mem32k_state *card = (ti99_mem32k_state*)downcast<legacy_device_base *>(device)->token();
79   /* Register the card */
80   running_device *peb = device->owner();
81   
82   if (input_port_read(device->machine, "RAM")==RAM_TI32_EXT)
83   {
84      int success = mount_card(peb, device, &ti32k_card, get_pebcard_config(device)->slot);
85      if (!success) return;
86
87      if (card->memory==NULL) card->memory = (UINT8*)malloc(32768);
88   }
89}
90
91static const char DEVTEMPLATE_SOURCE[] = __FILE__;
92
93#define DEVTEMPLATE_ID(p,s)             p##ti99_mem32k##s
94#define DEVTEMPLATE_FEATURES            DT_HAS_START | DT_HAS_STOP | DT_HAS_RESET | DT_HAS_INLINE_CONFIG
95#define DEVTEMPLATE_NAME                "TI99 32KiB Memory Expansion Card"
96#define DEVTEMPLATE_FAMILY              "Peripheral expansion"
97#include "devtempl.h"
98
99DEFINE_LEGACY_DEVICE( TI32KMEM, ti99_mem32k );
100
src/mess/machine/ti99/ti_fdc.h
r0r9485
1/*
2    TI-99 Standard Floppy Disk Controller Card
3   Based on WD1771
4   Single Density, Double-sided
5    Michael Zapf, September 2010
6*/
7
8/* device interface */
9#ifndef __TIFDC__
10#define __TIFDC__
11
12DECLARE_LEGACY_DEVICE( TIFDC, ti99_fdc );
13#endif
src/mess/machine/ti99/evpc.c
r0r9485
1/*
2   SNUG Enhanced Video Processor Card (evpc)
3    based on v9938 (may also be equipped with v9958)
4    Can be used with TI-99/4A as an add-on card; internal VDP must be removed
5
6    The SGCPU ("TI-99/4P") only runs with EVPC.
7   Michael Zapf   
8   Rewritten as device
9   October 2010
10*/
11#include "emu.h"
12#include "peribox.h"
13#include "evpc.h"
14#include "emuopts.h"
15
16#define evpc_region "evpc_region"
17
18#define EVPC_CRU_BASE 0x1400
19
20typedef ti99_pebcard_config ti99_evpc_config;
21
22typedef struct _evpc_palette
23{
24   UINT8       read_index, write_index, mask;
25   int       read;
26   int       state;
27   struct { UINT8 red, green, blue; } color[0x100];
28   //int dirty;
29} evpc_palette;
30
31typedef struct _ti99_evpc_state
32{
33   int                selected;
34   UINT8                *dsrrom;
35   int                RAMEN;
36   int                dsr_page;
37   UINT8                *novram;   /* NOVRAM area */
38   evpc_palette         palette;
39   ti99_peb_connect      lines;
40   
41} ti99_evpc_state;
42
43INLINE ti99_evpc_state *get_safe_token(running_device *device)
44{
45   assert(device != NULL);
46   return (ti99_evpc_state *)downcast<legacy_device_base *>(device)->token();
47}
48
49static int get_evpc_switch(running_device *device, int number)
50{
51   switch (number)
52   {
53   case 0:
54      return input_port_read(device->machine, "EVPC-SW1");
55   case 1:
56      return input_port_read(device->machine, "EVPC-SW3");
57   case 2:
58      return input_port_read(device->machine, "EVPC-SW4");
59   case 3:
60      return input_port_read(device->machine, "EVPC-SW8");
61   default:
62      logerror("evpc: Invalid switch index %02x\n", number);
63      return 0;
64   }
65}
66
67/*************************************************************************/
68
69/*
70    The CRU read handler. The CRU is a serial interface in the console.
71
72    Read EVPC CRU interface (dip switches)
73    0: Video timing (PAL/NTSC)
74    1: -
75    2: charset
76    3: RAM shift
77    4: -
78    5: -
79    6: -
80    7: DIP or NOVRAM
81    Logic is inverted
82*/
83static READ8Z_DEVICE_HANDLER( cru_rz )
84{
85   if ((offset & 0xff00)==EVPC_CRU_BASE)
86   {
87      int bit = (offset >> 1) & 0x0f;
88      if (bit == 0)
89         *value = ~(get_evpc_switch(device, 0) | (get_evpc_switch(device, 1)<<2) | (get_evpc_switch(device, 2)<<3) | (get_evpc_switch(device, 3)<<7));
90   }
91}
92
93/*
94    The CRU write handler. The CRU is a serial interface in the console.
95*/
96static WRITE8_DEVICE_HANDLER( cru_w )
97{
98   ti99_evpc_state *card = get_safe_token(device);
99
100   if ((offset & 0xff00)==EVPC_CRU_BASE)
101   {
102      int bit = (offset >> 1) & 0x0f;
103      switch (bit)
104      {
105      case 0:
106         card->selected = data;
107         break;
108         
109      case 1:
110         if (data)
111            card->dsr_page |= 1;
112         else
113            card->dsr_page &= ~1;
114         break;
115         
116      case 2:
117         break;
118         
119      case 3:
120         card->RAMEN = data;
121         break;
122         
123      case 4:
124         if (data)
125            card->dsr_page |= 4;
126         else
127            card->dsr_page &= ~4;
128         break;
129         
130      case 5:
131         if (data)
132            card->dsr_page |= 2;
133         else
134            card->dsr_page &= ~2;
135         break;
136         
137      case 6:
138         break;
139         
140      case 7:
141         break;
142      }
143   }
144}
145
146/*
147    Read a byte in evpc DSR space
148    0x4000 - 0x5eff   DSR (paged)
149    0x5f00 - 0x5fef   NOVRAM
150    0x5ff0 - 0x5fff   Palette
151*/
152static READ8Z_DEVICE_HANDLER( data_rz )
153{
154   ti99_evpc_state *card = get_safe_token(device);
155
156   if (card->selected)
157   {
158      if (card->dsrrom==NULL)
159      {
160         logerror("evpc: no dsrrom\n");
161         return;
162      }
163         
164      if ((offset & 0xe000)==0x4000)
165      {
166         if ((offset & 0x1ff0)==0x1ff0)
167         {
168            /* PALETTE */
169            switch (offset & 0x000f)
170            {
171            case 0:
172               /* Palette Read Address Register */
173               *value = card->palette.write_index;
174               break;
175               
176            case 2:
177               /* Palette Read Color Value */
178               if (card->palette.read)
179               {
180                  switch (card->palette.state)
181                  {
182                  case 0:
183                     *value = card->palette.color[card->palette.read_index].red;
184                     break;
185                  case 1:
186                     *value = card->palette.color[card->palette.read_index].green;
187                     break;
188                  case 2:
189                     *value = card->palette.color[card->palette.read_index].blue;
190                     break;
191                  }
192                  card->palette.state++;
193                  if (card->palette.state == 3)
194                  {
195                     card->palette.state = 0;
196                     card->palette.read_index++;
197                  }
198               }
199               break;
200               
201            case 4:
202               /* Palette Read Pixel Mask */
203               *value = card->palette.mask;
204               break;
205            case 6:
206               /* Palette Read Address Register for Color Value */
207               if (card->palette.read)
208                  *value = 0;
209               else
210                  *value = 3;
211               break;
212            }
213         }
214         else
215         {
216            if ((offset & 0x1f00)==0x1f00)
217            {
218               /* NOVRAM */
219               if (card->RAMEN)
220               {
221                  *value = card->novram[offset & 0x00ff];
222               }
223               else
224               {
225                  *value = card->dsrrom[(offset&0x1fff) + card->dsr_page*0x2000];
226               }
227            }
228            else
229            {
230               *value = card->dsrrom[(offset&0x1fff) + card->dsr_page*0x2000];
231            }
232         }
233      }
234   }
235}
236
237/*
238    Write a byte in evpc DSR space
239    0x4000 - 0x5eff   DSR (paged)
240    0x5f00 - 0x5fef   NOVRAM
241    0x5ff0 - 0x5fff   Palette
242*/
243static WRITE8_DEVICE_HANDLER( data_w )
244{
245   ti99_evpc_state *card = get_safe_token(device);
246   if (card->selected)
247   {
248      if ((offset & 0xe000)==0x4000)
249      {
250         if ((offset & 0x1ff0)==0x1ff0)
251         {
252            /* PALETTE */
253            logerror("palette write, offset=%d\n, data=%d", offset-0x5ff0, data);
254            switch (offset & 0x000f)
255            {
256            case 8:
257               /* Palette Write Address Register */
258               logerror("EVPC palette address write (for write access)\n");
259               card->palette.write_index = data;
260               card->palette.state = 0;
261               card->palette.read = 0;
262               break;
263               
264            case 10:
265               /* Palette Write Color Value */
266               logerror("EVPC palette color write\n");
267               if (!card->palette.read)
268               {
269                  switch (card->palette.state)
270                  {
271                  case 0:
272                     card->palette.color[card->palette.write_index].red = data;
273                     break;
274                  case 1:
275                     card->palette.color[card->palette.write_index].green = data;
276                     break;
277                  case 2:
278                     card->palette.color[card->palette.write_index].blue = data;
279                     break;
280                  }
281                  card->palette.state++;
282                  if (card->palette.state == 3)
283                  {
284                     card->palette.state = 0;
285                     card->palette.write_index++;
286                  }
287                  //evpc_palette.dirty = 1;
288               }
289               break;
290               
291            case 12:
292               /* Palette Write Pixel Mask */
293               logerror("EVPC palette mask write\n");
294               card->palette.mask = data;
295               break;
296               
297            case 14:
298               /* Palette Write Address Register for Color Value */
299               logerror("EVPC palette address write (for read access)\n");
300               card->palette.read_index = data;
301               card->palette.state = 0;
302               card->palette.read = 1;
303               break;
304            }
305         }
306         else
307         {
308            if ((offset & 0x1f00)==0x1f00)
309            {
310               if (card->RAMEN)
311               {
312                  // NOVRAM
313                  card->novram[offset & 0x00ff] = data;
314               }
315            }
316         }
317      }
318   }
319}
320
321static ti99_peb_card evpc_card =
322{
323   data_rz,
324   data_w,
325   cru_rz,
326   cru_w,
327   
328   NULL, NULL,   NULL, NULL   
329};
330
331static DEVICE_START( ti99_evpc )
332{
333   ti99_evpc_state *card = get_safe_token(device);
334   card->novram = (UINT8*)malloc(256); // need that already now for NVRAM handling
335   
336   /* Resolve the callbacks to the PEB */
337   peb_callback_if *topeb = (peb_callback_if *)device->baseconfig().static_config();
338   devcb_resolve_write_line(&card->lines.ready, &topeb->ready, device);
339}
340
341static DEVICE_STOP( ti99_evpc )
342{
343   logerror("ti99_evpc: stop\n");
344   ti99_evpc_state *card = get_safe_token(device);
345   free(card->novram);
346}
347
348static DEVICE_RESET( ti99_evpc )
349{
350   logerror("ti99_evpc: reset\n");
351   ti99_evpc_state *card = get_safe_token(device);
352   astring *region = new astring();
353
354   /* If the card is selected in the menu, register the card */
355   running_device *peb = device->owner();   
356   int success = mount_card(peb, device, &evpc_card, get_pebcard_config(device)->slot);
357   if (!success)
358   {
359      logerror("evpc: Could not mount card.\n");
360      return;
361   }
362   card->RAMEN = 0;
363   card->dsr_page = 0;
364   
365   astring_assemble_3(region, device->tag(), ":", evpc_region);   
366   
367   card->dsrrom = memory_region(device->machine, astring_c(region));
368}
369
370static DEVICE_NVRAM( ti99_evpc )
371{
372   // Called between START and RESET
373   ti99_evpc_state *card = get_safe_token(device);
374   astring *hsname = astring_assemble_3(astring_alloc(), device->machine->gamedrv->name, PATH_SEPARATOR, "evpc.nv");
375   file_error filerr;
376   mame_file *nvfile;
377
378   if (read_or_write==0)
379   {
380      logerror("evpc: device nvram load %s\n", astring_c(hsname));
381     
382      filerr = mame_fopen(SEARCHPATH_NVRAM, astring_c(hsname), OPEN_FLAG_READ, &nvfile);
383      if (filerr == FILERR_NONE)
384      {
385         if (mame_fread(nvfile, card->novram, 256) != 256)
386            logerror("evpc: NOVRAM load error\n");
387         mame_fclose(nvfile);
388      }
389   }
390   else
391   {
392      logerror("evpc: device nvram save %s\n", astring_c(hsname));
393      filerr = mame_fopen(SEARCHPATH_NVRAM, astring_c(hsname), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS, &nvfile);
394     
395      if (filerr == FILERR_NONE)
396      {
397         if (mame_fwrite(nvfile, card->novram, 256) != 256)
398            logerror("evpc: NOVRAM save error\n");
399         mame_fclose(nvfile);
400      }
401   }
402}
403
404MACHINE_CONFIG_FRAGMENT( ti99_evpc )
405MACHINE_CONFIG_END
406
407ROM_START( ti99_evpc )
408   ROM_REGION(0x10000, evpc_region, 0)
409   ROM_LOAD_OPTIONAL("evpcdsr.bin", 0, 0x10000, CRC(a062b75d) SHA1(6e8060f86e3bb9c36f244d88825e3fe237bfe9a9)) /* evpc DSR ROM */
410ROM_END
411
412static const char DEVTEMPLATE_SOURCE[] = __FILE__;
413
414#define DEVTEMPLATE_ID(p,s)             p##ti99_evpc##s
415#define DEVTEMPLATE_FEATURES            DT_HAS_START | DT_HAS_STOP | DT_HAS_RESET | DT_HAS_ROM_REGION | DT_HAS_INLINE_CONFIG | DT_HAS_MACHINE_CONFIG | DT_HAS_NVRAM
416#define DEVTEMPLATE_NAME                "SNUG Enhanced Video Processor Card"
417#define DEVTEMPLATE_FAMILY              "Peripheral expansion"
418#include "devtempl.h"
419
420DEFINE_LEGACY_NVRAM_DEVICE(EVPC, ti99_evpc);
src/mess/machine/ti99/p_code.h
r0r9485
1/*
2    TI-99 P-Code Card emulation.
3    Michael Zapf, July 2009
4   
5   Revised July 2010
6*/
7
8#ifndef __PCODEN__
9#define __PCODEN__
10
11DECLARE_LEGACY_DEVICE( PCODEN, ti99_pcoden );
12#endif
src/mess/machine/ti99/videowrp.c
r0r9485
1/*
2    TI-99/4(A) and /8 Video subsystem
3   This device actually wraps the naked video chip implementation
4
5    EVPC (Enhanced Video Processor Card) from SNUG
6    based on v9938 (may also be equipped with v9958)
7    Can be used with TI-99/4A as an add-on card; internal VDP must be removed
8
9    The SGCPU ("TI-99/4P") only runs with EVPC.
10
11    Michael Zapf, October 2010
12*/
13
14#include "emu.h"
15#include "videowrp.h"
16
17typedef struct _ti99_video_state
18{
19   address_space    *space;
20   running_device   *cpu;
21   int            chip;
22} ti99_video_state;
23
24INLINE ti99_video_state *get_safe_token(running_device *device)
25{
26   assert(device != NULL);
27   return (ti99_video_state *)downcast<legacy_device_base *>(device)->token();
28}
29
30INLINE const ti99_video_config *get_config(running_device *device)
31{
32   assert(device != NULL);
33   assert(device->type() == TIVIDEO);
34   return (const ti99_video_config *) downcast<const legacy_device_config_base &>(device->baseconfig()).inline_config();
35}
36
37
38/*****************************************************************************/
39
40/*
41    Memory read (TI-99/4(A))
42*/
43READ16_DEVICE_HANDLER( ti_tms991x_r16 )
44{
45   ti99_video_state *video = get_safe_token(device);
46//   cpu_adjust_icount(video->cpu, -4);
47
48   if (offset & 1)
49   {   /* read VDP status */
50      return ((int) TMS9928A_register_r(video->space, 0)) << 8;
51   }
52   else
53   {   /* read VDP RAM */
54      return ((int) TMS9928A_vram_r(video->space, 0)) << 8;
55   }
56}
57
58/*
59    Memory read (TI-99/8). Makes use of the Z memory handler.
60*/
61READ8Z_DEVICE_HANDLER( ti8_tms991x_rz )
62{
63   ti99_video_state *video = get_safe_token(device);
64//   cpu_adjust_icount(video->cpu, -4);
65
66   if (offset & 2)
67   {   /* read VDP status */
68      *value = TMS9928A_register_r(video->space, 0);
69   }
70   else
71   {   /* read VDP RAM */
72      *value = TMS9928A_vram_r(video->space, 0);
73   }
74}
75
76/*
77   Memory read (EVPC)
78*/
79READ16_DEVICE_HANDLER( ti_v9938_r16 )
80{
81   ti99_video_state *video = get_safe_token(device);
82//   cpu_adjust_icount(video->cpu, -4);
83
84   if (offset & 1)
85   {   /* read VDP status */
86      return ((int) v9938_0_status_r(video->space, 0)) << 8;
87   }
88   else
89   {   /* read VDP RAM */
90      return ((int) v9938_0_vram_r(video->space, 0)) << 8;
91   }
92}
93
94/*
95   Memory write
96*/
97WRITE16_DEVICE_HANDLER( ti_tms991x_w16 )
98{
99   ti99_video_state *video = get_safe_token(device);
100//   cpu_adjust_icount(video->cpu, -4);
101
102   if (offset & 1)
103   {   /* write VDP address */
104      TMS9928A_register_w(video->space, 0, (data >> 8) & 0xff);
105   }
106   else
107   {   /* write VDP data */
108      TMS9928A_vram_w(video->space, 0, (data >> 8) & 0xff);
109   }
110}
111
112/*
113   Memory write (TI-99/8)
114*/
115WRITE8_DEVICE_HANDLER( ti8_tms991x_w )
116{
117   ti99_video_state *video = get_safe_token(device);
118//   cpu_adjust_icount(video->cpu, -4);
119
120   if (offset & 2)
121   {   /* write VDP address */
122      TMS9928A_register_w(video->space, 0, data);
123   }
124   else
125   {   /* write VDP data */
126      TMS9928A_vram_w(video->space, 0, data);
127   }
128}
129
130/*
131   Memory write (EVPC)
132*/
133WRITE16_DEVICE_HANDLER ( ti_v9938_w16 )
134{
135   ti99_video_state *video = get_safe_token(device);
136//   cpu_adjust_icount(video->cpu, -4);
137
138   switch (offset & 3)
139   {
140   case 0:
141      /* write VDP data */
142      v9938_0_vram_w(video->space, 0, (data >> 8) & 0xff);
143      break;
144   case 1:
145      /* write VDP address */
146      v9938_0_command_w(video->space, 0, (data >> 8) & 0xff);
147      break;
148   case 2:
149      /* write VDP palette */
150      v9938_0_palette_w(video->space, 0, (data >> 8) & 0xff);
151      break;
152   case 3:
153      /* write VDP register pointer (indirect access) */
154      v9938_0_register_w(video->space, 0, (data >> 8) & 0xff);
155      break;
156   }
157}
158
159/*
160   Video write (Geneve)
161*/
162WRITE8_DEVICE_HANDLER ( gen_v9938_w )
163{
164   ti99_video_state *video = get_safe_token(device);
165//   cpu_adjust_icount(video->cpu, -4);
166
167   switch (offset & 6)
168   {
169   case 0:
170      /* write VDP data */
171      v9938_0_vram_w(video->space, 0, data);
172      break;
173   case 2:
174      /* write VDP address */
175      v9938_0_command_w(video->space, 0, data);
176      break;
177   case 4:
178      /* write VDP palette */
179      v9938_0_palette_w(video->space, 0, data);
180      break;
181   case 6:
182      /* write VDP register pointer (indirect access) */
183      v9938_0_register_w(video->space, 0, data);
184      break;
185   }
186}
187
188/*
189    Video read (Geneve).
190*/
191READ8Z_DEVICE_HANDLER( gen_v9938_rz )
192{
193   ti99_video_state *video = get_safe_token(device);
194//   cpu_adjust_icount(video->cpu, -4);
195     
196   if (offset & 2)
197   {   /* read VDP status */
198      *value = v9938_0_status_r(video->space, 0);
199   }
200   else
201   {   /* read VDP RAM */
202      *value = v9938_0_vram_r(video->space, 0);
203   }
204}
205
206READ16_DEVICE_HANDLER ( ti_video_rnop )
207{
208   ti99_video_state *video = get_safe_token(device);
209   cpu_adjust_icount(video->cpu, -4);
210   return 0;
211}
212
213WRITE16_DEVICE_HANDLER ( ti_video_wnop )
214{
215   ti99_video_state *video = get_safe_token(device);
216   cpu_adjust_icount(video->cpu, -4);
217}
218/**************************************************************************/
219// Interfacing to mouse attached to v9938
220
221void video_update_mouse( running_device *device, int delta_x, int delta_y, int buttons)
222{
223   ti99_video_state *video = get_safe_token(device);
224   // TODO: V9938 to be devicified
225   if (video->chip==TI_V9938)
226      v9938_update_mouse_state(0, delta_x, delta_y, buttons & 3);
227}
228
229
230/**************************************************************************/
231
232static DEVICE_START( ti99_video )
233{
234   ti99_video_state *video = get_safe_token(device);
235   const ti99_video_config* conf = (const ti99_video_config*)get_config(device);
236   
237   video->cpu = device->machine->device("maincpu");
238   video->space = cputag_get_address_space(device->machine, "maincpu", ADDRESS_SPACE_PROGRAM);
239
240   if (conf->chip==TI_TMS991X)
241   {
242      TMS9928A_configure(conf->tmsparam);
243   }
244   else
245   {
246      running_machine *machine = device->machine;
247      VIDEO_START_CALL(generic_bitmapped);
248      v9938_init(machine, 0, *machine->primary_screen, machine->generic.tmpbitmap,
249         MODEL_V9938, 0x20000, conf->callback);   /* v38 with 128 kb of video RAM */     
250   }
251}
252
253static DEVICE_STOP( ti99_video )
254{
255}
256
257static DEVICE_RESET( ti99_video )
258{
259   const ti99_video_config* conf = (const ti99_video_config*)get_config(device);
260   if (conf->chip==TI_TMS991X)
261   {
262      TMS9928A_reset();
263   }
264   else
265   {
266      v9938_reset(0);
267   }
268}
269
270static const char DEVTEMPLATE_SOURCE[] = __FILE__;
271
272#define DEVTEMPLATE_ID(p,s)             p##ti99_video##s
273#define DEVTEMPLATE_FEATURES            DT_HAS_START | DT_HAS_STOP | DT_HAS_RESET | DT_HAS_INLINE_CONFIG
274#define DEVTEMPLATE_NAME                "TI-99/x Video subsystem"
275#define DEVTEMPLATE_FAMILY              "Internal device"
276#include "devtempl.h"
277
278DEFINE_LEGACY_DEVICE( TIVIDEO, ti99_video );
279
src/mess/machine/ti99/tn_usbsm.h
r0r9485
1/*
2    Nouspikel USB / SmartMedia interface card
3    Michael Zapf, September 2010
4*/
5
6#ifndef __USBSMART__
7#define __USBSMART__
8
9DECLARE_LEGACY_DEVICE( USBSMART, tn_usbsm );
10#endif
src/mess/machine/ti99/speech8.c
r0r9485
1/*
2    TI-99/8 Speech synthesizer subsystem
3   
4   The TI-99/8 contains a speech synthesizer inside the console, so we cannot
5   reuse the spchsyn implementation of the P-Box speech synthesizer.
6   
7    Note that this subsystem also contains the speech roms.
8*/
9#include "emu.h"
10#include "speech8.h"
11#include "sound/tms5220.h"
12#include "sound/wave.h"
13
14#define TMS5220_ADDRESS_MASK 0x3FFFFUL   /* 18-bit mask for tms5220 address */
15#define speech8_region "speech8_region"
16
17typedef struct _ti99_speech8_state
18{
19   running_device          *vsp;
20   UINT8                *speechrom_data;      /* pointer to speech ROM data */
21   int                load_pointer;         /* which 4-bit nibble will be affected by load address */
22   int                ROM_bits_count;            /* current bit position in ROM */
23   UINT32                speechROMaddr;            /* 18 bit pointer in ROM */
24   UINT32               speechROMlen;         /* length of data pointed by speechrom_data, from 0 to 2^18 */
25   
26} ti99_speech8_state;
27
28INLINE ti99_speech8_state *get_safe_token(running_device *device)
29{
30   assert(device != NULL);
31   return (ti99_speech8_state *)downcast<legacy_device_base *>(device)->token();
32}
33
34/*****************************************************************************/
35
36/*
37    Read 'count' bits serially from speech ROM
38*/
39static int ti99_spchroms_read(running_device *vspdev, int count)
40{
41   running_device *device = vspdev->owner();
42   ti99_speech8_state *spsys = get_safe_token(device);
43
44   int val;
45
46   if (spsys->load_pointer)
47   {   /* first read after load address is ignored */
48      spsys->load_pointer = 0;
49      count--;
50   }
51
52   if (spsys->speechROMaddr < spsys->speechROMlen)
53   {
54      if (count < spsys->ROM_bits_count)
55      {
56         spsys->ROM_bits_count -= count;
57         val = (spsys->speechrom_data[spsys->speechROMaddr] >> spsys->ROM_bits_count) & (0xFF >> (8 - count));
58      }
59      else
60      {
61         val = ((int)spsys->speechrom_data[spsys->speechROMaddr]) << 8;
62
63         spsys->speechROMaddr = (spsys->speechROMaddr + 1) & TMS5220_ADDRESS_MASK;
64
65         if (spsys->speechROMaddr < spsys->speechROMlen)
66            val |= spsys->speechrom_data[spsys->speechROMaddr];
67
68         spsys->ROM_bits_count += 8 - count;
69
70         val = (val >> spsys->ROM_bits_count) & (0xFF >> (8 - count));
71      }
72   }
73   else
74      val = 0;
75
76   return val;
77}
78
79/*
80    Write an address nibble to speech ROM
81*/
82static void ti99_spchroms_load_address(running_device *vspdev, int data)
83{
84   running_device *device = vspdev->owner();
85   ti99_speech8_state *spsys = get_safe_token(device);
86   // tms5220 data sheet says that if we load only one 4-bit nibble, it won't work.
87   // This code does not care about this.
88   spsys->speechROMaddr = ((spsys->speechROMaddr & ~(0xf << spsys->load_pointer))
89      | (((unsigned long) (data & 0xf)) << spsys->load_pointer) ) & TMS5220_ADDRESS_MASK;
90   spsys->load_pointer += 4;
91   spsys->ROM_bits_count = 8;
92}
93
94/*
95    Perform a read and branch command
96*/
97static void ti99_spchroms_read_and_branch(running_device *vspdev)
98{
99   running_device *device = vspdev->owner();
100   ti99_speech8_state *spsys = get_safe_token(device);
101   // tms5220 data sheet says that if more than one speech ROM (tms6100) is present,
102   // there is a bus contention.  This code does not care about this. */
103   if (spsys->speechROMaddr < spsys->speechROMlen-1)
104      spsys->speechROMaddr = (spsys->speechROMaddr & 0x3c000UL)
105         | (((((unsigned long) spsys->speechrom_data[spsys->speechROMaddr]) << 8)
106         | spsys->speechrom_data[spsys->speechROMaddr+1]) & 0x3fffUL);
107   else if (spsys->speechROMaddr == spsys->speechROMlen-1)
108      spsys->speechROMaddr = (spsys->speechROMaddr & 0x3c000UL)
109         | ((((unsigned long) spsys->speechrom_data[spsys->speechROMaddr]) << 8) & 0x3fffUL);
110   else
111      spsys->speechROMaddr = (spsys->speechROMaddr & 0x3c000UL);
112
113   spsys->ROM_bits_count = 8;
114}
115
116/*****************************************************************************/
117
118/*
119    Memory read
120*/
121READ8Z_DEVICE_HANDLER( ti998spch_rz )
122{
123   ti99_speech8_state *spsys = get_safe_token(device);
124   
125   if ((offset & 0xfc01)==0x9000)       
126   {
127      cpu_adjust_icount(device->machine->device("maincpu"),-(18+3));      /* this is just a minimum, it can be more */     
128      *value = tms5220_status_r(spsys->vsp, offset) & 0xff;
129   }
130}
131
132/*
133   Memory write
134*/
135WRITE8_DEVICE_HANDLER( ti998spch_w )
136{
137   ti99_speech8_state *spsys = get_safe_token(device);
138
139   if ((offset & 0xfc01)==0x9400)
140   {
141      cpu_adjust_icount(device->machine->device("maincpu"),-(54+3));      /* this is just an approx. minimum, it can be much more */
142     
143      /* RN: the stupid design of the tms5220 core means that ready is cleared */
144      /* when there are 15 bytes in FIFO.  It should be 16.  Of course, if */
145      /* it were the case, we would need to store the value on the bus, */
146      /* which would be more complex. */
147      if (!tms5220_readyq_r(spsys->vsp))
148      {
149         attotime time_to_ready = double_to_attotime(tms5220_time_to_ready(spsys->vsp));
150         int cycles_to_ready = device->machine->device<cpu_device>("maincpu")->attotime_to_cycles(time_to_ready);
151         logerror("time to ready: %f -> %d\n", attotime_to_double(time_to_ready), (int) cycles_to_ready);
152         
153         cpu_adjust_icount(device->machine->device("maincpu"),-cycles_to_ready);
154         timer_set(device->machine, attotime_zero, NULL, 0, NULL);
155      }     
156      tms5220_data_w(spsys->vsp, offset, data);
157   }
158}
159
160/**************************************************************************/
161
162static DEVICE_START( ti99_speech8 )
163{
164   ti99_speech8_state *spsys = (ti99_speech8_state*)downcast<legacy_device_base *>(device)->token();
165   /* Resolve the callbacks to the PEB */
166   spsys->vsp = device->subdevice("speechsyn");
167}
168
169static DEVICE_STOP( ti99_speech8 )
170{
171}
172
173static DEVICE_RESET( ti99_speech8 )
174{
175   ti99_speech8_state *spsys = (ti99_speech8_state*)downcast<legacy_device_base *>(device)->token();
176
177   astring *region = new astring();
178   astring_assemble_3(region, device->tag(), ":", speech8_region);   
179   
180   spsys->speechrom_data = memory_region(device->machine, astring_c(region));
181   spsys->speechROMlen = memory_region_length(device->machine, astring_c(region));
182   spsys->speechROMaddr = 0;
183   spsys->load_pointer = 0;
184   spsys->ROM_bits_count = 0;
185}
186
187static WRITE_LINE_DEVICE_HANDLER( speech8_ready )
188{
189//   ti99_speech8_state *spsys = (ti99_speech8_state*)downcast<legacy_device_base *>(device->owner())->token();
190   logerror("speech8: READY called by VSP\n");
191}
192
193/*
194    TMS5220 speech synthesizer
195    Note that in the real hardware, the predecessor TMC0285 was used.
196*/
197static const tms5220_interface ti99_4x_tms5200interface =
198{
199   DEVCB_NULL,               /* no IRQ callback */
200   DEVCB_LINE(speech8_ready),
201   ti99_spchroms_read,            /* speech ROM read handler */
202   ti99_spchroms_load_address,      /* speech ROM load address handler */
203   ti99_spchroms_read_and_branch   /* speech ROM read and branch handler */
204};
205
206MACHINE_CONFIG_FRAGMENT( ti99_speech8 )
207   MDRV_SOUND_ADD("speechsyn", TMS5220, 680000L)
208   MDRV_SOUND_CONFIG(ti99_4x_tms5200interface)
209   MDRV_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)
210MACHINE_CONFIG_END
211
212ROM_START( ti99_speech8 )
213   ROM_REGION(0x8000, speech8_region, 0)
214   ROM_LOAD_OPTIONAL("spchrom.bin", 0x0000, 0x8000, BAD_DUMP CRC(58b155f7) SHA1(382292295c00dff348d7e17c5ce4da12a1d87763)) /* system speech ROM */
215ROM_END
216
217static const char DEVTEMPLATE_SOURCE[] = __FILE__;
218
219#define DEVTEMPLATE_ID(p,s)             p##ti99_speech8##s
220#define DEVTEMPLATE_FEATURES            DT_HAS_START | DT_HAS_STOP | DT_HAS_RESET | DT_HAS_ROM_REGION | DT_HAS_MACHINE_CONFIG
221#define DEVTEMPLATE_NAME                "TI-99/8 Speech Synthesizer"
222#define DEVTEMPLATE_FAMILY              "Internal subsystem"
223#include "devtempl.h"
224
225DEFINE_LEGACY_DEVICE( TISPEECH8, ti99_speech8 );
226
src/mess/machine/ti99/ti32kmem.h
r0r9485
1/*
2    TI-99 32K memory expansion
3    Michael Zapf, September 2010
4*/
5
6#ifndef __TI32K__
7#define __TI32K__
8
9DECLARE_LEGACY_DEVICE( TI32KMEM, ti99_mem32k );
10#endif
src/mess/machine/ti99/tn_ide.c
r0r9485
1/*
2    Thierry Nouspikel's IDE card emulation
3
4    This card is just a prototype.  It has been designed by Thierry Nouspikel,
5    and its description was published in 2001.  The card have been revised in
6    2004.
7
8    The specs have been published in <http://www.nouspikel.com/ti99/ide.html>.
9
10    The IDE interface is quite simple, since it only implements PIO transfer.
11    The card includes a clock chip to timestamp files, and an SRAM for the DSR.
12    It should be possible to use a battery backed DSR SRAM, but since the clock
13    chip includes 4kb of battery-backed RAM, a bootstrap loader can be saved in
14    the clock SRAM in order to load the DSR from the HD when the computer
15    starts.
16
17    Raphael Nabet, 2002-2004.
18
19    Rewritten as device
20    Michael Zapf, September 2010
21   
22    FIXME: idecont assumes that there is only one drive that is called
23    "harddisk" at the root level
24*/
25#include "emu.h"
26#include "peribox.h"
27#include "machine/idectrl.h"
28#include "machine/rtc65271.h"
29#include "machine/idectrl.h"
30#include "cpu/tms9900/tms9900.h"
31#include "tn_ide.h"
32
33#define CRU_BASE 0x1000
34
35typedef ti99_pebcard_config tn_ide_config;
36
37enum
38{   /* 0xff for 2 mbytes, 0x3f for 512kbytes, 0x03 for 32 kbytes */
39   page_mask = /*0xff*/0x3f
40};
41
42enum
43{
44   cru_reg_page_switching = 0x04,
45   cru_reg_page_0 = 0x08,
46   /*cru_reg_rambo = 0x10,*/   /* not emulated */
47   cru_reg_wp = 0x20,
48   cru_reg_int_en = 0x40,
49   cru_reg_reset = 0x80
50};
51
52typedef struct _tn_ide_state
53{
54   int    selected;
55
56   running_device      *rtc;
57   running_device      *ide;
58
59   int      ide_irq;
60   int      clk_irq;
61   int    sram_enable;
62   int    sram_enable_dip;
63   int    cru_register;
64   int      cur_page;
65   
66   int      tms9995_mode;
67   
68   UINT8    input_latch;
69   UINT8    output_latch;
70   
71   UINT8   *ram;
72   
73   /* Callback lines to the main system. */
74   ti99_peb_connect   lines;
75   
76} tn_ide_state;
77
78INLINE tn_ide_state *get_safe_token(running_device *device)
79{
80   assert(device != NULL);
81   return (tn_ide_state *)downcast<legacy_device_base *>(device)->token();
82}
83
84
85/*
86    CRU read
87*/
88static READ8Z_DEVICE_HANDLER( cru_rz )
89{
90   tn_ide_state *card = get_safe_token(device);
91   UINT8 reply;
92   if ((offset & 0xff00)==CRU_BASE)
93   {
94      int bit = (offset >> 4) & 7;
95     
96      if (bit==0)
97      {
98         reply = card->cru_register & 0x30;
99         reply |= 8;   /* IDE bus IORDY always set */
100         if (!card->clk_irq)
101            reply |= 4;
102         if (card->sram_enable_dip)
103            reply |= 2;
104         if (!card->ide_irq)
105            reply |= 1;
106      }
107      *value = reply;
108   }
109}
110
111/*
112   CRU write
113*/
114static WRITE8_DEVICE_HANDLER( cru_w )
115{
116   tn_ide_state *card = get_safe_token(device);
117
118   if ((offset & 0xff00)==CRU_BASE)
119   {
120      int bit = (offset >>1) & 7;
121      switch (bit)
122      {
123      case 0:         /* turn card on: handled by core */
124         card->selected = data;
125         
126      case 1:         /* enable SRAM or registers in 0x4000-0x40ff */
127         card->sram_enable = data;
128         break;
129         
130      case 2:         /* enable SRAM page switching */
131      case 3:         /* force SRAM page 0 */
132      case 4:         /* enable SRAM in 0x6000-0x7000 ("RAMBO" mode) */
133      case 5:         /* write-protect RAM */
134      case 6:         /* irq and reset enable */
135      case 7:         /* reset drive */
136         if (data)
137            card->cru_register |= 1 << bit;
138         else
139            card->cru_register &= ~(1 << bit);
140         
141         if (bit == 6)
142            devcb_call_write_line(&card->lines.inta, (card->cru_register & cru_reg_int_en) && card->ide_irq);
143         
144         if ((bit == 6) || (bit == 7))
145            if ((card->cru_register & cru_reg_int_en) && !(card->cru_register & cru_reg_reset))
146               card->ide->reset();
147         break;
148      }
149   }
150}
151
152/*
153    Memory read
154*/
155static READ8Z_DEVICE_HANDLER( data_rz )
156{
157   tn_ide_state *card = get_safe_token(device);
158   UINT8 reply = 0;
159
160   if (((offset & 0xe000)==0x4000) && card->selected)
161   {
162      int addr = offset & 0x1fff;
163   
164      if ((addr <= 0xff) && (card->sram_enable == card->sram_enable_dip))
165      {   /* registers */
166         switch ((addr >> 5) & 0x3)
167         {
168         case 0:      /* RTC RAM */
169            if (addr & 0x80)
170               /* RTC RAM page register */
171               reply = rtc65271_xram_r(card->rtc, (addr & 0x1f) | 0x20);
172            else
173               /* RTC RAM read */
174               reply = rtc65271_xram_r(card->rtc, addr);
175            break;
176         case 1:      /* RTC registers */
177            if (addr & 0x10)
178               /* register data */
179               reply = rtc65271_rtc_r(card->rtc, 1);
180            else
181               /* register select */
182               reply = rtc65271_rtc_r(card->rtc, 0);
183            break;
184         case 2:      /* IDE registers set 1 (CS1Fx) */
185            if (card->tms9995_mode ? (!(addr & 1)) : (addr & 1))
186            {   /* first read triggers 16-bit read cycle */
187               card->input_latch = (! (addr & 0x10)) ? ide_bus_r(card->ide, 0, (addr >> 1) & 0x7) : 0;
188            }
189           
190            /* return latched input */
191            /*reply = (addr & 1) ? input_latch : (input_latch >> 8);*/
192            /* return latched input - bytes are swapped in 2004 IDE card */
193            reply = (addr & 1) ? (card->input_latch >> 8) : card->input_latch;
194            break;
195         case 3:      /* IDE registers set 2 (CS3Fx) */
196            if (card->tms9995_mode ? (!(addr & 1)) : (addr & 1))
197            {   /* first read triggers 16-bit read cycle */
198               card->input_latch = (! (addr & 0x10)) ? ide_bus_r(card->ide, 1, (addr >> 1) & 0x7) : 0;
199            }
200           
201            /* return latched input */
202            /*reply = (addr & 1) ? input_latch : (input_latch >> 8);*/
203            /* return latched input - bytes are swapped in 2004 IDE card */
204            reply = (addr & 1) ? (card->input_latch >> 8) : card->input_latch;
205            break;
206         }
207      }
208      else
209      {   /* sram */
210         if ((card->cru_register & cru_reg_page_0) || (addr >= 0x1000))
211            reply = card->ram[addr+0x2000 * card->cur_page];
212         else
213            reply = card->ram[addr];
214      }
215      *value = reply;
216   }
217}
218
219/*
220   Memory write. The controller is 16 bit, so we need to demultiplex again.
221*/
222static WRITE8_DEVICE_HANDLER( data_w )
223{
224   tn_ide_state *card = get_safe_token(device);
225
226   if (((offset & 0xe000)==0x4000) && card->selected)
227   {
228      if (card->cru_register & cru_reg_page_switching)
229      {
230         card->cur_page = (offset >> 1) & page_mask;
231      }
232     
233      int addr = offset & 0x1fff;
234     
235      if ((addr <= 0xff) && (card->sram_enable == card->sram_enable_dip))
236      {   /* registers */
237         switch ((addr >> 5) & 0x3)
238         {
239         case 0:      /* RTC RAM */
240            if (addr & 0x80)
241               /* RTC RAM page register */
242               rtc65271_xram_w(card->rtc, (addr & 0x1f) | 0x20, data);
243            else
244               /* RTC RAM write */
245               rtc65271_xram_w(card->rtc, addr, data);
246            break;
247         case 1:      /* RTC registers */
248            if (addr & 0x10)
249               /* register data */
250               rtc65271_rtc_w(card->rtc, 1, data);
251            else
252               /* register select */
253               rtc65271_rtc_w(card->rtc, 0, data);
254            break;
255         case 2:      /* IDE registers set 1 (CS1Fx) */
256/*   
257            if (addr & 1)
258               card->output_latch = (card->output_latch & 0xff00) | data;
259            else
260               card->output_latch = (card->output_latch & 0x00ff) | (data << 8);
261*/
262            /* latch write - bytes are swapped in 2004 IDE card */
263            if (addr & 1)
264               card->output_latch = (card->output_latch & 0x00ff) | (data << 8);
265            else
266               card->output_latch = (card->output_latch & 0xff00) | data;
267           
268            if (card->tms9995_mode ? (addr & 1) : (!(addr & 1)))
269            {   /* second write triggers 16-bit write cycle */
270               ide_bus_w(card->ide, 0, (addr >> 1) & 0x7, card->output_latch);
271            }
272            break;
273         case 3:      /* IDE registers set 2 (CS3Fx) */
274/*
275            if (addr & 1)
276               card->output_latch = (card->output_latch & 0xff00) | data;
277            else
278               card->output_latch = (card->output_latch & 0x00ff) | (data << 8);
279*/
280            /* latch write - bytes are swapped in 2004 IDE card */
281            if (addr & 1)
282               card->output_latch = (card->output_latch & 0x00ff) | (data << 8);
283            else
284               card->output_latch = (card->output_latch & 0xff00) | data;
285           
286            if (card->tms9995_mode ? (addr & 1) : (!(addr & 1)))
287            {   /* second write triggers 16-bit write cycle */
288               ide_bus_w(card->ide, 1, (addr >> 1) & 0x7, card->output_latch);
289            }
290            break;
291         }
292      }
293      else
294      {   /* sram */
295         if (! (card->cru_register & cru_reg_wp))
296         {
297            if ((card->cru_register & cru_reg_page_0) || (addr >= 0x1000))
298               card->ram[addr+0x2000 * card->cur_page] = data;
299            else
300               card->ram[addr] = data;
301         }
302      }
303   }
304}
305
306/**************************************************************************/
307
308static ti99_peb_card tn_ide_card =
309{
310   data_rz, data_w,            // memory access read/write
311   cru_rz, cru_w,               // CRU access
312   NULL, NULL,                  // SENILA/B access
313   NULL, NULL                  // 16 bit access (none here)
314};
315
316/*
317    ti99_ide_interrupt()
318    IDE interrupt callback
319*/
320static void ide_interrupt_callback(running_device *device, int state)
321{
322   tn_ide_state *card = get_safe_token(device->owner());
323   card->ide_irq = state;
324   if (card->cru_register & cru_reg_int_en)
325      devcb_call_write_line(&card->lines.inta, state);
326}
327
328/*
329    clk_interrupt_callback()
330    clock interrupt callback
331*/
332static void clock_interrupt_callback(running_device *device, int state)
333{
334   tn_ide_state *card = get_safe_token(device->owner());
335   card->clk_irq = state;
336   devcb_call_write_line(&card->lines.inta, state);
337}
338
339
340static DEVICE_START( tn_ide )
341{
342   tn_ide_state *card = get_safe_token(device);
343   card->rtc = device->subdevice("ide_rtc");
344   card->ide = device->subdevice("ide");
345   
346   peb_callback_if *topeb = (peb_callback_if *)device->baseconfig().static_config();
347   devcb_resolve_write_line(&card->lines.inta, &topeb->inta, device);
348
349   card->ram = auto_alloc_array(device->machine, UINT8, 0x080000);
350   card->sram_enable_dip = 0;
351}
352
353static DEVICE_STOP( tn_ide )
354{
355}
356
357static DEVICE_RESET( tn_ide )
358{
359   tn_ide_state *card = get_safe_token(device);
360   running_device *peb = device->owner();
361   
362   if (input_port_read(device->machine, "HDCTRL") & HD_IDE)
363   {
364      int success = mount_card(peb, device, &tn_ide_card, get_pebcard_config(device)->slot);
365      if (!success) return;
366     
367      card->cur_page = 0;
368      card->sram_enable = 0;
369      card->cru_register = 0;
370      card->tms9995_mode =  (device->type()==TMS9995);
371   }
372}
373
374MACHINE_CONFIG_FRAGMENT( tn_ide )
375   MDRV_RTC65271_ADD( "ide_rtc", clock_interrupt_callback )
376   MDRV_IDE_CONTROLLER_ADD( "ide", ide_interrupt_callback )
377MACHINE_CONFIG_END
378
379static const char DEVTEMPLATE_SOURCE[] = __FILE__;
380
381#define DEVTEMPLATE_ID(p,s)             p##tn_ide##s
382#define DEVTEMPLATE_FEATURES            DT_HAS_START | DT_HAS_STOP | DT_HAS_RESET | DT_HAS_INLINE_CONFIG | DT_HAS_MACHINE_CONFIG
383#define DEVTEMPLATE_NAME                "Nouspikel IDE controller card"
384#define DEVTEMPLATE_FAMILY              "Peripheral expansion"
385#include "devtempl.h"
386
387DEFINE_LEGACY_DEVICE( TNIDE, tn_ide );
388
src/mess/machine/ti99/evpc.h
r0r9485
1/*
2    SNUG Enhanced Video Processor Card (evpc)
3
4   Michael Zapf   
5   Rewritten as device
6   October 2010
7*/
8/* device interface */
9#ifndef __EVPC__
10#define __EVPC__
11
12DECLARE_LEGACY_NVRAM_DEVICE( EVPC, ti99_evpc );
13#endif
src/mess/machine/ti99/samsmem.c
r0r9485
1/*
2    TI-99 SuperAMS Memory Expansion Card. Uses a 74LS612 memory mapper.
3   
4   TODO: Test this device with some emulated program!
5*/
6#include "emu.h"
7#include "peribox.h"
8#include "samsmem.h"
9
10typedef ti99_pebcard_config ti99_samsmem_config;
11
12typedef struct _ti99_samsmem_state
13{
14   UINT8    mapper[16];
15   int    map_mode;   
16   int      access_mapper;
17   UINT8    *memory;
18   
19} ti99_samsmem_state;
20
21INLINE ti99_samsmem_state *get_safe_token(running_device *device)
22{
23   assert(device != NULL);
24   return (ti99_samsmem_state *)downcast<legacy_device_base *>(device)->token();
25}
26
27#define SAMS_CRU_BASE 0x1e00
28
29/*
30   CRU write (there is no read here)
31*/
32static WRITE8_DEVICE_HANDLER( samsmem_cru_w )
33{
34   ti99_samsmem_state *card = get_safe_token(device);
35   if ((offset & 0xff00)==SAMS_CRU_BASE)
36   {
37      if ((offset & 0x000e)==0) card->access_mapper = data;
38      if ((offset & 0x000e)==2) card->map_mode = data;
39   }
40}
41
42/*
43    Memory read. The SAMS card has two address areas: The memory is at locations
44   0x2000-0x3fff and 0xa000-0xffff, and the mapper area is at 0x4000-0x401e
45   (only even addresses).
46*/
47static READ8Z_DEVICE_HANDLER( samsmem_rz )
48{
49   ti99_samsmem_state *card = get_safe_token(device);
50   UINT32 address = 0;
51
52   if (card->access_mapper && ((offset & 0xe000)==0x4000))
53   {
54      // select the mapper circuit
55      *value = card->mapper[(offset>>1)&0x000f];
56   }
57     
58   if (((offset & 0xe000)==0x2000) || ((offset & 0xe000)==0xa000) || ((offset & 0xc000)==0xc000))
59   {
60      // select memory expansion
61      if (card->map_mode)
62         address = (card->mapper[offset>>12] << 12) + (offset & 0x0fff);
63      else // transparent mode
64         address = offset;
65      *value = card->memory[address];       
66   }   
67}
68
69/*
70   Memory write
71*/
72static WRITE8_DEVICE_HANDLER( samsmem_w )
73{
74   ti99_samsmem_state *card = get_safe_token(device);
75   UINT32 address = 0;
76
77   if (card->access_mapper && ((offset & 0xe000)==0x4000))
78   {
79      // select the mapper circuit
80      card->mapper[(offset>>1)&0x000f] = data;
81   }
82   if (((offset & 0xe000)==0x2000) || ((offset & 0xe000)==0xa000) || ((offset & 0xc000)==0xc000))
83   {
84      // select memory expansion
85      if (card->map_mode)
86         address = (card->mapper[offset>>12] << 12) + (offset & 0x0fff);
87      else // transparent mode
88         address = offset;
89      card->memory[address] = data;
90   }   
91}
92
93/**************************************************************************/
94
95static ti99_peb_card samsmem_card =
96{
97   samsmem_rz, samsmem_w,         // memory access read/write
98   NULL, samsmem_cru_w,         // CRU access (no read here)
99   NULL, NULL,                  // SENILA/B access (none here)
100   NULL, NULL                  // 16 bit access (none here)
101};
102
103static DEVICE_START( ti99_samsmem )
104{
105   ti99_samsmem_state *card = (ti99_samsmem_state*)downcast<legacy_device_base *>(device)->token();
106   card->memory=NULL;
107}
108
109static DEVICE_STOP( ti99_samsmem )
110{
111   ti99_samsmem_state *card = (ti99_samsmem_state*)downcast<legacy_device_base *>(device)->token();
112   if (card->memory) free(card->memory);
113}
114
115static DEVICE_RESET( ti99_samsmem )
116{
117   ti99_samsmem_state *card = (ti99_samsmem_state*)downcast<legacy_device_base *>(device)->token();
118   /* Register the card */
119   running_device *peb = device->owner();
120   
121   if (input_port_read(device->machine, "RAM")==RAM_SUPERAMS1024)
122   {
123      int success = mount_card(peb, device, &samsmem_card, get_pebcard_config(device)->slot);
124      if (!success) return;
125
126      if (card->memory==NULL)
127      {
128         // Allocate 1 MiB (check whether we want to allocate this on demand)
129         card->memory = (UINT8*)malloc(0x100000);
130      }
131      card->map_mode = FALSE;
132      card->access_mapper = FALSE;
133      for (int i=0; i < 16; i++) card->mapper[i]=0;
134   }
135}
136
137static const char DEVTEMPLATE_SOURCE[] = __FILE__;
138
139#define DEVTEMPLATE_ID(p,s)             p##ti99_samsmem##s
140#define DEVTEMPLATE_FEATURES            DT_HAS_START | DT_HAS_STOP | DT_HAS_RESET | DT_HAS_INLINE_CONFIG
141#define DEVTEMPLATE_NAME                "TI99 SuperAMS Memory Expansion Card"
142#define DEVTEMPLATE_FAMILY              "Peripheral expansion"
143#include "devtempl.h"
144
145DEFINE_LEGACY_DEVICE( SAMSMEM, ti99_samsmem );
146
src/mess/machine/ti99/datamux.c
r0r9485
1/***************************************************************************
2   
3   TI-99/4(A) databus multiplexer circuit
4   
5   The DMUX is used to convert the 16-bit databus of the TMS9900 into
6   an 8-bit databus. The processor writes a 16 bit word which is split
7   by this circuit into two bytes that are sent serially over the 8-bit bus.
8   In the opposite direction, one 16-bit read request from the CPU is
9   translated into two 8-bit read requests (odd address / even address) from
10   this datamux. Its 8-bit latch (LS373) holds the first byte, while the
11   datamux puts the CPU on hold, gets the second byte, and routes that second
12   byte to the D0-D7 lines, while the latch now puts the first byte on D8-D15.
13   Since we get two memory accesses each time, there are twice as many
14   wait states than for a direct 16-bit access (order LSB, MSB).
15   
16   In addition, since the TMS 9900 also supports byte operations, every write
17   operation is automatically preceded by a read operation, so this adds even
18   more delays.
19
20   Within the TI-99/4(A) console, only the internal ROM and the small internal
21   RAM ("scratch pad RAM") are directly connected to the 16-bit bus. All other
22   devices (video, audio, speech, GROM, and the complete P-Box system are
23   connected to the datamux.
24   
25   The TMS9995 which is used in the Geneve has an internal multiplex, and
26   the byte order is reversed: MSB, LSB
27   
28   ROM = 4K * 16 bit (8 KiB) system ROM (kind of BIOS, plus the GPL interpreter)
29   RAM = 128 * 16 bit (256 byte) system RAM ("scratch pad")
30
31   Many users (me too) used to solder a 16K * 16 bit (32 KiB) SRAM circuit into
32   the console, before the datamux, decoded to 0x2000-0x3fff and 0xa000-0xffff.
33   (This expansion was also called 0-waitstate, since it could be accessed
34   with the full databus width, and the datamux did not create waitstates.)   
35   
36   +---+                                                   +-------+
37   |   |===##========##== D0-D7 ==========##===============|TMS9918| Video
38   |   |   ||        ||                   ||               +-------+ 
39   | T |   +-----+  +-----+      LS245  +----+   
40   | M |   | ROM |  | RAM |             +----+
41   | S |   +-----+  +-----+               || |                     :
42   |   |---||-||-----||-||----------------||-|---------------------:
43   | 9 |   ||        ||    A0 - A14       || |                A0   : Sound
44   | 9 |---||--------||-------------------||-|----------+    -A15  : GROM
45   | 0 |   ||        ||      LS373  +-+   || | +----A15-+----------: Cartridges
46   | 0 |   ||        ||   ##========|<|===## | |                   : Speech
47   |   |   ||        ||   ||  +-+   +-+   || | |                   : Expansion
48   |   |===## D8-D15 ##===##==|>|=====|===##=|=|=========== D0-D7 =: cards
49   +---+                      +-+     |      | |                   : 
50     ^                     LS244|     |      | |                     
51     |                          |     +--+---+-++                   
52     |                       +--------| DMUX |                   
53     +--- READY -------------------------+------+
54
55        Databus width
56       :------------- 16 bit ---------------|---------- 8 bit -----:
57   
58   A0=MSB; A15=LSB
59   D0=MSB; D15=LSB
60   
61   We integrate the 16 bit memory expansion in this datamux component
62   (pretending that the memory expansion was soldered on top of the datamux)
63***************************************************************************/
64
65#include "emu.h"
66#include "peribox.h"
67#include "datamux.h"
68
69#define MAXDEV 10
70
71typedef struct _attached_device
72{
73   /* The device. */
74   running_device    *device;
75   
76   /* Address bits involved */
77   UINT16         address_mask;
78
79   /* Value of the address bits which are involved for selecting for read. */
80   UINT16         select;
81
82   /* Value of the address bits which are involved for selecting for write. */
83   UINT16         write_select;
84   
85   /* Read access. */
86   databus_read_function read_byte;
87   
88   /* Write access. */
89   databus_write_function write_byte;
90
91   /* Setting which determined if this device is mounted or not. */
92   const char   *setting;
93   
94   /* Bits which must be set in the setting. */
95   UINT8      set;
96   
97   /* Bits which must not be set in the setting. */
98   UINT8      unset;
99} attached_device;
100
101typedef struct _datamux_state
102{
103   /* All devices that are attached to the 8-bit bus. */
104   attached_device component[MAXDEV];
105   
106   /* Latch which stores the first byte */
107   UINT8 latch;
108   
109   // Intermediate storage which holds the low byte of the previous read cycle.
110   // In reality, the TMS9900 adds the low byte to the 16 bit memory word
111   // from the previous read-before-write cycle, but this is not yet handled
112   // by the TMS9900 emulation. TODO: rewrite TMS9900
113   UINT8 lowbyte;
114   UINT8 highbyte;
115   
116   /* Memory expansion (internal, 16 bit). */
117   UINT16 *ram16b;
118   
119   /* Use the memory expansion? */
120   int use32k;
121   
122   /* Management function */
123   int devindex;
124} datamux_state;
125
126
127INLINE datamux_state *get_safe_token(running_device *device)
128{
129   assert(device != NULL);
130   assert(downcast<legacy_device_base *>(device)->token() != NULL);
131   return (datamux_state *)downcast<legacy_device_base *>(device)->token();
132}
133
134static void dmux_mount_device(running_device *dmuxdev, running_device *busdevice, UINT16 address_mask, UINT16 address_bits, UINT16 write_sel, databus_read_function read, databus_write_function write)
135{
136   datamux_state *dmux = get_safe_token(dmuxdev);
137   int index = dmux->devindex++;
138   if (index < MAXDEV)
139   {
140      if (dmux->component[index].device == NULL)
141      {
142         dmux->component[index].device = busdevice;
143         dmux->component[index].address_mask = address_mask;
144         dmux->component[index].select = address_bits;
145         dmux->component[index].write_select = write_sel;
146         dmux->component[index].read_byte = read;
147         dmux->component[index].write_byte = write;   
148         // printf("registering the device at position %d\n", index);
149      }
150   }
151   else
152   {
153      logerror("ti99_dmux: Tried to mount too many devices to the DMUX. (Just a bug.)\n");
154   }
155}
156/*
157static void dmux_unmount_device(running_device *dmuxdev, running_device *busdevice)
158{
159   datamux_state *dmux = get_safe_token(dmuxdev);
160   for (int index = 0; index < MAXDEV; index++)
161   {
162      if (dmux->component[index].device == busdevice)
163      {
164         dmux->component[index].device = NULL;
165         return;
166      }     
167   }
168   printf("Failed to uninstall device from dmux\n");
169}
170*/
171/***************************************************************************
172    DEVICE ACCESSOR FUNCTIONS
173***************************************************************************/
174
175/*
176    Read access. We are using two loops because the delay between both
177    accesses must not occur within the loop. So we have one access on the bus,
178    a delay, and then the second access (each one with possibly many attached
179    devices)
180*/
181READ16_DEVICE_HANDLER( ti99_dmux_r )
182{
183   UINT8 hbyte = 0;
184   datamux_state *dmux = get_safe_token(device);
185   UINT16 addr = (offset << 1);
186
187   // Looks ugly, but this is close to the real thing. If the 16bit
188   // memory expansion is installed in the console, and the access hits its
189   // space, just respond to the memory access and don't bother the
190   // datamux in any way. In particular, do not make the datamux insert wait
191   // states.
192   if (dmux->use32k)
193   {
194      UINT16 base = 0;
195      if ((addr & 0xe000)==0x2000) base = 0x1000;
196      if (((addr & 0xe000)==0xa000) || ((addr & 0xc000)==0xc000)) base = 0x4000;
197
198      if (base != 0)
199      {
200         UINT16 reply = dmux->ram16b[offset-base];
201         // Store the prefetch
202         dmux->lowbyte = reply & 0x00ff;
203         dmux->highbyte = (reply & 0xff00)>>8;
204         return reply;
205      }
206   }
207     
208   for (int i=0; i < MAXDEV; i++)
209   {
210      attached_device *adev = &dmux->component[i];
211      if (dmux->component[i].device != NULL)
212      {
213         if (adev->read_byte != NULL)
214         {
215            if (((addr+1) & adev->address_mask)==adev->select)
216            {
217               // put on the latch
218               adev->read_byte(adev->device, addr+1, &dmux->latch);
219               dmux->lowbyte = dmux->latch;
220            }
221         }
222         // hope we don't have two devices answering...
223         // consider something like a logical OR and maybe some artificial smoke
224      }
225   }   
226   
227   // Takes three cycles
228   cpu_adjust_icount(device->machine->device("maincpu"),-3);
229
230   for (int i=0; i < MAXDEV; i++)
231   {
232      attached_device *adev = &dmux->component[i];
233      if (dmux->component[i].device != NULL)
234      {
235         if (adev->read_byte != NULL)
236         {
237            if ((addr & adev->address_mask)==adev->select)
238            {
239               adev->read_byte(adev->device, addr, &hbyte);
240               dmux->highbyte = hbyte;
241            }
242         }
243      }
244   }   
245
246   // Takes three cycles
247   cpu_adjust_icount(device->machine->device("maincpu"),-3);
248
249   // use the latch and the currently read byte and put it on the 16bit bus
250   return (hbyte<<8) | dmux->latch ;
251}
252
253/*
254    Write access.
255*/
256WRITE16_DEVICE_HANDLER( ti99_dmux_w )
257{
258   datamux_state *dmux = get_safe_token(device);
259   UINT16 addr = (offset << 1);         
260   
261   // The handling of byte writing is done in MESS using mem_mask.
262   // If the mem_mask is ff00, the CPU is about to write the high byte. This
263   // is not the true story, since the real CPU never writes half a word.
264   // In reality, the TMS9900 performs a read-before-write, stores the word
265   // internally, and replaces the high or low byte when it is about to write
266   // a byte to an even or odd address, respectively. Then it writes the
267   // complete new word.
268   // Example: Memory locations 0x6000 contains the word 0x1234 (BE). If we
269   // write a 0x56 to 0x6000, the CPU first reads 0x6000, stores the 0x1234,
270   // replaces the first byte with 0x56, and then writes 0x5634 to 0x6000.
271
272   // Until the TMS9900 emulation is corrected in this way, we are using
273   // the DMUX in place of the internal buffer.
274   
275//   printf("write addr=%04x memmask=%04x value=%04x\n", addr, mem_mask, data);
276   if (mem_mask == 0xff00)
277      data = data | dmux->lowbyte;
278   
279   if (mem_mask == 0x00ff)
280      data = data | (dmux->highbyte << 8);
281
282   // Handle the internal 32K expansion
283   if (dmux->use32k)
284   {
285      if (addr>=0x2000 && addr<0x4000)
286      {
287         dmux->ram16b[offset-0x1000] = data; // index 0000 - 0fff
288         return;
289      }
290      if (addr>=0xa000)
291      {
292         dmux->ram16b[offset-0x4000] = data; // index 1000 - 4fff
293         return;
294      }
295   }
296   
297   for (int i=0; i < MAXDEV; i++)
298   {
299      attached_device *adev = &dmux->component[i];
300      if (dmux->component[i].device != NULL)
301      {
302         if (adev->write_byte != NULL)
303         {
304            if (((addr+1) & adev->address_mask)==(adev->select|adev->write_select))
305            {
306               // write the byte from the lower 8 lines
307               adev->write_byte(adev->device, addr+1, data & 0xff);
308            }
309         }
310      }
311   }
312
313   // Takes three cycles
314   cpu_adjust_icount(device->machine->device("maincpu"),-3);
315
316   for (int i=0; i < MAXDEV; i++)
317   {
318      attached_device *adev = &dmux->component[i];
319      if (dmux->component[i].device != NULL)
320      {
321         if (adev->write_byte != NULL)
322         {
323            if ((addr & adev->address_mask)==(adev->select|adev->write_select))
324            {
325               // write the byte from the upper 8 lines
326               adev->write_byte(adev->device, addr, (data>>8) & 0xff);
327            }
328         }
329      }
330   }   
331
332   // Takes three cycles
333   cpu_adjust_icount(device->machine->device("maincpu"),-3);
334}
335
336/* CRU space is not involved in the dmux. */
337
338/***************************************************************************
339    DEVICE LIFECYCLE FUNCTIONS
340***************************************************************************/
341
342static DEVICE_START( datamux )
343{
344   datamux_state *dmux = get_safe_token(device);
345   dmux->ram16b = NULL;
346}
347
348static DEVICE_STOP( datamux )
349{
350   datamux_state *dmux = get_safe_token(device);
351   if (dmux->ram16b) free(dmux->ram16b);
352}
353
354static DEVICE_RESET( datamux )
355{
356   datamux_state *dmux = get_safe_token(device);
357   dmux->use32k = (input_port_read(device->machine, "RAM")==RAM_TI32_INT)? TRUE : FALSE;
358
359   dmux->devindex = 0;
360   int i = 0;
361   int done=FALSE;
362
363   for (int index = 0; index < MAXDEV; index++)
364   {
365      dmux->component[index].device = NULL;     
366   }
367
368   if (dmux->ram16b==NULL) dmux->ram16b = (UINT16*)malloc(32768);
369   bus_device *cons = (bus_device*)device->baseconfig().static_config();
370   while (!done)
371   {
372      if (cons[i].name != NULL)
373      {
374         running_device *dev = device->machine->device(cons[i].name);
375         if (dev!=NULL)
376         {
377            UINT32 set = 0;
378            if (cons[i].setting!=NULL)
379               set = input_port_read(device->machine, cons[i].setting);
380           
381            if (((set & cons[i].set)==cons[i].set)&&((set & cons[i].unset)==0))
382            {
383               dmux_mount_device(device, dev, cons[i].address_mask, cons[i].select_pattern, cons[i].write_select, cons[i].read, cons[i].write);
384               logerror("ti99_datamux: Device %s mounted at index %d.\n", cons[i].name, i);
385            }
386            else
387            {
388               logerror("ti99_datamux: Device %s not mounted due to configuration setting %s.\n", cons[i].name, cons[i].setting);
389            }
390         }
391         else
392            logerror("ti99_datamux: Device %s not found.\n", cons[i].name);
393      }
394      else done=TRUE;
395      i++;
396   }
397}
398
399static const char DEVTEMPLATE_SOURCE[] = __FILE__;
400
401#define DEVTEMPLATE_ID(p,s)             p##datamux##s
402#define DEVTEMPLATE_FEATURES            DT_HAS_START | DT_HAS_STOP | DT_HAS_RESET
403#define DEVTEMPLATE_NAME                "TI-99 Databus 16/8 Multiplexer"
404#define DEVTEMPLATE_FAMILY              "Internal devices"
405#include "devtempl.h"
406
407DEFINE_LEGACY_DEVICE( DMUX, datamux );
src/mess/machine/ti99/videowrp.h
r0r9485
1/*
2    TI-99/4(A) and /8 Video subsystem
3   This device actually wraps the naked video chip implementation
4    Michael Zapf, October 2010
5*/
6
7#ifndef __TIVIDEO__
8#define __TIVIDEO__
9
10#include "video/tms9928a.h"
11#include "video/v9938.h"
12
13#define READ8Z_DEVICE_HANDLER(name)      void name(ATTR_UNUSED device_t *device, ATTR_UNUSED offs_t offset, UINT8 *value)
14
15#define TI_TMS991X 1
16#define TI_V9938 2
17
18typedef struct _ti99_video_config
19{
20   TMS9928a_interface         *tmsparam;
21   int                     chip;
22   void                   (*callback)(running_machine *, int);
23   
24} ti99_video_config;
25
26READ16_DEVICE_HANDLER( ti_tms991x_r16 );
27READ8Z_DEVICE_HANDLER( ti8_tms991x_rz );
28WRITE16_DEVICE_HANDLER( ti_tms991x_w16 );
29WRITE8_DEVICE_HANDLER( ti8_tms991x_w );
30READ16_DEVICE_HANDLER( ti_video_rnop );
31WRITE16_DEVICE_HANDLER( ti_video_wnop );
32READ16_DEVICE_HANDLER( ti_v9938_r16 );
33WRITE16_DEVICE_HANDLER( ti_v9938_w16 );
34READ8Z_DEVICE_HANDLER( gen_v9938_rz );
35WRITE8_DEVICE_HANDLER( gen_v9938_w );
36
37void video_update_mouse( running_device *device, int delta_x, int delta_y, int buttons);
38
39DECLARE_LEGACY_DEVICE( TIVIDEO, ti99_video );
40
41#define MDRV_TI_TMS991x_ADD(_tag, _chip, _rate, _screen, _blank, _tmsparam)      \
42   MDRV_DEVICE_ADD(_tag, TIVIDEO, 0)                        \
43   MDRV_DEVICE_CONFIG_DATAPTR(ti99_video_config, tmsparam, _tmsparam)   \
44   MDRV_DEVICE_CONFIG_DATA32(ti99_video_config, chip, TI_TMS991X)      \
45   MDRV_FRAGMENT_ADD(_chip)                              \
46   MDRV_SCREEN_MODIFY(_screen)                              \
47   MDRV_SCREEN_REFRESH_RATE(_rate)                           \
48   MDRV_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(_blank))
49   
50#define MDRV_TI_V9938_ADD(_tag, _rate, _screen, _blank, _x, _y, _int)      \
51   MDRV_DEVICE_ADD(_tag, TIVIDEO, 0)                        \
52   MDRV_DEVICE_CONFIG_DATAPTR(ti99_video_config, tmsparam, NULL)   \
53   MDRV_DEVICE_CONFIG_DATAPTR(ti99_video_config, callback, _int)   \
54   MDRV_DEVICE_CONFIG_DATA32(ti99_video_config, chip, TI_V9938)      \
55   MDRV_SCREEN_ADD(_screen, RASTER)   \
56   MDRV_SCREEN_REFRESH_RATE(_rate)                           \
57   MDRV_SCREEN_FORMAT(BITMAP_FORMAT_INDEXED16)   \
58   MDRV_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(_blank))   \
59   MDRV_SCREEN_SIZE(_x, _y)   \
60   MDRV_SCREEN_VISIBLE_AREA(0, _x - 1, 0, _y - 1)   \
61   MDRV_PALETTE_LENGTH(512)   \
62   MDRV_PALETTE_INIT(v9938)   \
63   MDRV_VIDEO_UPDATE(generic_bitmapped)
64   
65#endif /* __TIVIDEO__ */
66
src/mess/machine/ti99/speech8.h
r0r9485
1/*
2    TI-99/8 Speech Synthesizer
3    Michael Zapf, October 2010
4*/
5
6#ifndef __TISPEECH8__
7#define __TISPEECH8__
8
9#include "ti99defs.h"
10
11READ8Z_DEVICE_HANDLER( ti998spch_rz );
12WRITE8_DEVICE_HANDLER( ti998spch_w );
13
14DECLARE_LEGACY_DEVICE( TISPEECH8, ti99_speech8 );
15
16#define MDRV_TISPEECH_ADD(_tag)      \
17   MDRV_DEVICE_ADD(_tag, TISPEECH8, 0)   
18#endif
src/mess/machine/ti99/hfdc.c
r0r9485
1/*
2   Myarc Hard and Floppy Disk Controller
3   Michael Zapf
4*/
5#include "emu.h"
6#include "peribox.h"
7#include "ti_fdc.h"
8#include "machine/wd17xx.h"
9#include "formats/ti99_dsk.h"
10#include "devices/flopdrv.h"
11#include "devices/ti99_hd.h"
12#include "machine/mm58274c.h"
13#include "hfdc.h"
14
15#define CRU_BASE 0x1100
16
17#define hfdc_region "hfdc_region"
18
19#define HFDC_MAX_FLOPPY 4
20#define HFDC_MAX_HARD 4
21
22#define TAPE_ADDR    0x0fc0
23#define HDC_R_ADDR    0x0fd0
24#define HDC_W_ADDR    0x0fd2
25#define CLK_ADDR    0x0fe0
26#define RAM_ADDR    0x1000
27
28typedef ti99_pebcard_config ti99_hfdc_config;
29
30typedef struct _ti99_hfdc_state
31{
32   /* When TRUE, card is accessible. Indicated by a LED. */
33   int               selected;
34
35   /* When TRUE, triggers motor monoflop. */
36   int               strobe_motor;
37
38   /* Clock divider bit 0. Unused in this emulation. */
39   int             CD0;
40   
41   /* Clock divider bit 1. Unused in this emulation. */
42   int               CD1;
43   
44   /* count 4.23s from rising edge of motor_on */
45   emu_timer          *motor_on_timer;
46   
47   /* Link to the HDC9234 controller on the board. */
48   running_device       *controller;
49
50   /* Link to the clock chip on the board. */
51   running_device       *clock;
52     
53   /* Determines whether we have access to the CRU bits. */
54   int             cru_select;
55   
56   /* IRQ state */
57   int             irq;
58   
59   /* DMA in Progress state */
60   int             dip;
61     
62   /* Output 1 latch */
63   UINT8             output1_latch;
64
65   /* Output 2 latch */
66   UINT8             output2_latch;
67   
68   /* Connected floppy drives. */
69   running_device       *floppy_unit[HFDC_MAX_FLOPPY];
70   
71   /* Connected harddisk drives. */
72   running_device       *harddisk_unit[HFDC_MAX_HARD];
73
74   /* DMA address latch */
75   UINT32             dma_address;
76   
77   /* DSR ROM */
78   UINT8            *rom;
79   
80   /* ROM banks. */
81   int             rom_offset;
82
83   /* HFDC RAM */
84   UINT8             *ram;
85   
86   /* RAM banks */   
87   int             ram_offset[4];
88   
89   /* Callback lines to the main system. */
90   ti99_peb_connect   lines;
91   
92} ti99_hfdc_state;
93
94INLINE ti99_hfdc_state *get_safe_token(running_device *device)
95{
96   assert(device != NULL);
97   return (ti99_hfdc_state *)downcast<legacy_device_base *>(device)->token();
98}
99
100/*
101    Resets the drive geometry. This is required because the heuristic of
102    the default implementation sets the drive geometry to the geometry
103    of the medium.
104*/
105static void set_geometry(running_device *drive, floppy_type_t type)
106{
107   if (drive!=NULL)
108      floppy_drive_set_geometry(drive, type);
109   else
110      logerror("ti99/HFDC: Drive not found\n");
111}
112
113static void set_all_geometries(running_device *device, floppy_type_t type)
114{
115   set_geometry(device->siblingdevice(FLOPPY_0), type);
116   set_geometry(device->siblingdevice(FLOPPY_1), type);
117   set_geometry(device->siblingdevice(FLOPPY_2), type);
118}
119
120/*************************************************************************/
121
122/*
123    Read disk CRU interface
124    HFDC manual p. 44
125
126    CRU Select=0
127    xx00          Disk controller interrupt
128    xx02          Motor status
129    xx04          DMA in progress
130
131    Note that the cru line settings on the board do not match the
132    description in the manual. 02 and 04 swap their positions (checked with
133    board and schematics). Similarly, the dip switches
134    for the drive configurations are not correctly enumerated in the manual.
135
136    CRU Select=1
137    xx00          Switch 4 status \_ drive 2 config
138    xx02          Switch 3 status /
139    xx04          Switch 2 status \_ drive 1 config
140    xx06          Switch 1 status /
141    xx08          Switch 8 status \_ drive 4 config
142    xx0A          Switch 7 status /
143    xx0C          Switch 6 status \_ drive 3 config
144    xx0E          Switch 5 status /
145
146    config: 00 = 9/16/18 sectors, 40 tracks, 16 msec
147        10 = 9/16/18 sectors, 40 tracks, 8 msec
148        01 = 9/16/18 sectors, 80 tracks, 2 msec
149        11 = 36 sectors, 80 tracks, 2 msec
150*/
151static READ8Z_DEVICE_HANDLER( cru_r )
152{
153   ti99_hfdc_state *card = get_safe_token(device);
154   UINT8 reply;
155   
156   if ((offset & 0xff00)==CRU_BASE)
157   {
158      if ((offset & 0x00ff)==0)  /* CRU bits 0-7 */
159      {
160         /* CRU bits */
161         if (card->cru_select)
162         {
163            /* DIP switches.  Logic levels are inverted (on->0, off->1).  CRU
164            bit order is the reverse of DIP-switch order, too (dip 1 -> bit 7,
165            dip 8 -> bit 0).
166           
167            MZ: 00 should not be used since there is a bug in the
168            DSR of the HFDC which causes problems with SD disks
169            (controller tries DD and then fails to fall back to SD) */           
170            reply = ~(input_port_read(device->machine, "HFDCDIP"));
171         }
172         else
173         {
174            reply = 0;
175           
176            if (card->irq)          reply |= 0x01;
177            if (card->dip)         reply |= 0x02;
178            if (card->strobe_motor)   reply |= 0x04;
179         }
180         *value = reply;
181      }
182      else /* CRU bits 8+ */
183         *value = 0;
184   }
185}
186
187/*
188    Write disk CRU interface
189    HFDC manual p. 43
190
191    CRU rel. address    Definition                      Active
192    00                  Device Service Routine Select   HIGH
193    02                  Reset to controller chip        LOW
194    04                  Floppy Motor on / CD0           HIGH
195    06                  ROM page select 0 / CD1
196    08                  ROM page select 1 / CRU input select
197    12/4/6/8/A          RAM page select at 0x5400
198    1C/E/0/2/4          RAM page select at 0x5800
199    26/8/A/C/E          RAM page select at 0x5C00
200
201    RAM bank select: bank 0..31; 12 = LSB (accordingly for other two areas)
202    ROM bank select: bank 0..3; 06 = MSB, 07 = LSB
203    Bit number = (CRU_rel_address - base_address)/2
204    CD0 and CD1 are Clock Divider selections for the Floppy Data Separator (FDC9216)
205*/
206static WRITE8_DEVICE_HANDLER( cru_w )
207{
208   ti99_hfdc_state *card = get_safe_token(device);
209
210   if ((offset & 0xff00)==CRU_BASE)
211   {
212      int bit = (offset >> 1) & 0x1f;
213
214      if (bit >= 9 && bit < 24)
215      {
216         if (data)
217            // we leave index 0 unchanged; modify indexes 1-3
218            card->ram_offset[(bit-4)/5] |= 0x0400 << ((bit-9)%5);
219         else
220            card->ram_offset[(bit-4)/5] &= ~(0x0400 << ((bit-9)%5));
221
222         return;
223      }
224
225      switch (bit)
226      {
227      case 0:
228         card->selected = data;
229         break;
230
231      case 1:
232         if (!data) smc92x4_reset(card->controller);  // active low
233         break;
234
235      case 2:
236         card->CD0 = data;
237         if (data && !card->strobe_motor)
238         {
239            timer_adjust_oneshot(card->motor_on_timer, ATTOTIME_IN_MSEC(4230), 0);
240         }
241         card->strobe_motor = data;
242         break;
243
244      case 3:
245         card->CD1 = data;
246         if (data) card->rom_offset |= 0x2000;
247         else card->rom_offset &= ~0x2000;
248         break;
249
250      case 4:
251         card->cru_select = data;
252         if (data) card->rom_offset |= 0x1000;
253         else card->rom_offset &= ~0x1000;
254         break;
255
256      default:
257          logerror("ti99/HFDC: Attempt to set undefined CRU bit %d\n", bit);
258      }
259   }
260}
261
262/*
263    read a byte in disk DSR space
264    HFDC manual, p. 44
265    Memory map as seen by the 99/4A PEB
266
267    0x4000 - 0x4fbf one of four possible ROM pages
268    0x4fc0 - 0x4fcf tape select
269    0x4fd0 - 0x4fdf disk controller select
270    0x4fe0 - 0x4fff time chip select
271
272    0x5000 - 0x53ff static RAM page 0x10
273    0x5400 - 0x57ff static RAM page any of 32 pages
274    0x5800 - 0x5bff static RAM page any of 32 pages
275    0x5c00 - 0x5fff static RAM page any of 32 pages
276*/
277
278static READ8Z_DEVICE_HANDLER( data_r )
279{
280   ti99_hfdc_state *card = get_safe_token(device);
281
282   if (card->selected && (offset & 0xe000)==0x4000)
283   {
284      /* DSR region */
285      if ((offset & 0x1000)==0x0000)
286      {
287         if ((offset & 0x0fc0)==0x0fc0)
288         {
289            // Tape: 4fc0...4fcf
290            if ((offset & 0x1ff0)==TAPE_ADDR)
291            {
292               logerror("ti99/HFDC: Tape support not available (access to address %04x)\n", offset);
293               return;
294            }
295           
296            // HDC9234: 4fd0..4fdf / read: 4fd0,4 (mirror 8,c)
297            // read: 0100 1111 1101 xx00
298            if ((offset & 0x1ff3)==HDC_R_ADDR)
299            {
300               *value = smc92x4_r(card->controller, (offset>>2)&1);
301               return;
302            }
303           
304            if ((offset & 0x1fe1)==CLK_ADDR)
305            {
306               *value = mm58274c_r(card->clock, (offset & 0x001e) >> 1);
307               return;
308            }
309         }
310         else
311         {
312            // ROM
313            *value = card->rom[card->rom_offset + (offset & 0x0fff)];
314            return;
315         }
316      }
317     
318      // RAM: 0101 xxxx xxxx xxxx
319      if ((offset & 0x1000)==RAM_ADDR)
320      {
321         // 0101 00xx xxxx xxxx  static 0x08
322         // 0101 01xx xxxx xxxx  bank 1
323         // 0101 10xx xxxx xxxx  bank 2
324         // 0101 11xx xxxx xxxx  bank 3
325         int bank = (offset & 0x0c00) >> 10;
326         *value = card->ram[card->ram_offset[bank] + (offset & 0x03ff)];
327      }
328   }
329}
330
331/*
332    Write a byte to the controller.
333*/
334static WRITE8_DEVICE_HANDLER( data_w )
335{
336   ti99_hfdc_state *card = get_safe_token(device);
337   if (card->selected && (offset & 0xe000)==0x4000)
338   {     
339      // Tape: 4fc0...4fcf
340      if ((offset & 0x1ff0)==TAPE_ADDR)
341      {
342         logerror("ti99/HFDC: Tape support not available (access to address %04x)\n", offset);
343         return;
344      }
345     
346      // HDC9234: 4fd0..4fdf / write: 4fd2,6 (mirror a,e)
347      // write: 0100 1111 1101 xx10
348      if ((offset & 0x1ff3)==HDC_W_ADDR)
349      {
350         smc92x4_w(card->controller, (offset>>2)&1, data);
351         return;
352      }
353     
354      if ((offset & 0x1fe1)==CLK_ADDR)
355      {
356         mm58274c_w(card->clock, (offset & 0x001e) >> 1, data);
357         return;
358      }
359     
360      // RAM: 0101 xxxx xxxx xxxx
361      if ((offset & 0x1000)==RAM_ADDR)
362      {
363         // 0101 00xx xxxx xxxx  static 0x08
364         // 0101 01xx xxxx xxxx  bank 1
365         // 0101 10xx xxxx xxxx  bank 2
366         // 0101 11xx xxxx xxxx  bank 3
367         int bank = (offset & 0x0c00) >> 10;
368         card->ram[card->ram_offset[bank] + (offset & 0x03ff)] = data;
369      }
370   }
371}
372
373/*
374    Called whenever the state of the sms9234 interrupt pin changes.
375*/
376static WRITE_LINE_DEVICE_HANDLER( intrq_w )
377{
378   // Note that the callback functions deliver the calling device, which is
379   // the controller in this case.
380   ti99_hfdc_state *card = get_safe_token(device->owner());
381   card->irq = state;
382
383   /* Set INTA */
384   if (state)
385   {
386      devcb_call_write_line(&card->lines.inta, ASSERT_LINE);
387   }
388   else
389   {
390      devcb_call_write_line(&card->lines.inta, CLEAR_LINE);
391   }
392}
393
394/*
395    Called whenever the state of the sms9234 DMA in progress changes.
396*/
397static WRITE_LINE_DEVICE_HANDLER( dip_w )
398{
399   ti99_hfdc_state *card = get_safe_token(device->owner());
400   card->dip = state;
401}
402
403// device ok
404static WRITE8_DEVICE_HANDLER( auxbus_out )
405{
406   ti99_hfdc_state *card = get_safe_token(device->owner());
407   switch (offset)
408   {
409   case INPUT_STATUS:
410      logerror("ti99/HFDC: Invalid operation: S0=S1=0, but tried to write (expected: read drive status)\n");
411      break;
412     
413   case OUTPUT_DMA_ADDR:
414      /* Value is dma address byte. Shift previous contents to the left. */
415      card->dma_address = ((card->dma_address << 8) + (data&0xff))&0xffffff;
416      break;
417
418   case OUTPUT_OUTPUT1:
419      /* value is output1 */
420      card->output1_latch = data;
421      break;
422
423   case OUTPUT_OUTPUT2:
424      /* value is output2 */
425      card->output2_latch = data;
426      break;
427   }
428}
429
430static int line_to_index(UINT8 line, int max)
431{
432   // Calculate the binary logarithm of the given 2-multiple
433   int index = 0;
434   while (index < max)
435   {
436      if ((line & 0x01)!=0)
437         break;
438      else
439      {
440         line = line >> 1;
441         index++;
442      }
443   }
444   if (index==max) return -1;
445   return index;
446}
447
448/*
449    Select the HFDC floppy disk unit
450    This function implements the selection logic on the PCB (outside the
451    controller chip)
452    (Callback function)
453*/
454
455static running_device *current_floppy(running_device *controller)
456{
457   int disk_unit = -1;
458   ti99_hfdc_state *card = (ti99_hfdc_state*)downcast<legacy_device_base *>(controller->owner())->token();
459
460   disk_unit = line_to_index(card->output1_latch & 0x0f, HFDC_MAX_FLOPPY);
461
462   if (disk_unit<0)
463   {
464      logerror("No unit selected\n");
465      return NULL;
466   }
467
468   return card->floppy_unit[disk_unit];
469}
470
471/*
472   Select the HFDC hard disk unit
473   This function implements the selection logic on the PCB (outside the
474   controller chip)
475   The HDC9234 allows up to four drives to be selected by the select lines.
476   This is not enough for controlling four floppy drives and three hard
477   drives, so the user programmable outputs are used to select the floppy
478   drives. This selection happens completely outside of the controller,
479   so we must implement it here.
480*/
481
482static running_device *current_harddisk(running_device *controller)
483{
484   ti99_hfdc_state *card = (ti99_hfdc_state*)downcast<legacy_device_base *>(controller->owner())->token();
485
486   int disk_unit = -1;
487   disk_unit = line_to_index((card->output1_latch>>4)&0x0f, HFDC_MAX_HARD);
488
489   /* The HFDC does not use disk_unit=0. The first HD has index 1. */
490
491   if (disk_unit>=0)
492      return card->harddisk_unit[disk_unit];
493   else
494      return NULL;
495}
496
497static READ_LINE_DEVICE_HANDLER( auxbus_in )
498{
499   ti99_hfdc_state *card = get_safe_token(device->owner());
500   running_device *drive;
501   UINT8 reply = 0;
502
503   if (card->output1_latch==0)
504   {
505      return 0; /* is that the correct default value? */
506   }
507
508   /* If a floppy is selected, we have one line set among the four programmable outputs. */
509   if ((card->output1_latch & 0x0f)!=0)
510   {
511      drive = current_floppy(device);
512
513      /* Get floppy status. */
514      if (floppy_drive_get_flag_state(drive, FLOPPY_DRIVE_INDEX) == FLOPPY_DRIVE_INDEX)
515         reply |= DS_INDEX;
516      if (floppy_tk00_r(drive) == CLEAR_LINE)
517         reply |= DS_TRK00;
518      if (floppy_wpt_r(drive) == CLEAR_LINE)
519         reply |= DS_WRPROT;
520
521      /* if (image_exists(disk_img)) */
522
523      reply |= DS_READY;  /* Floppies don't have a READY line; line is pulled up */
524      reply |= DS_SKCOM;  /* Same here. */
525   }
526   else /* one of the first four lines must be selected */
527   {
528      UINT8 state;
529      drive = current_harddisk(device);
530      state = ti99_mfm_harddisk_status(drive);
531      if (state & MFMHD_TRACK00)       reply |= DS_TRK00;
532      if (state & MFMHD_SEEKCOMP)      reply |= DS_SKCOM;
533      if (state & MFMHD_WRFAULT)      reply |= DS_WRFAULT;
534      if (state & MFMHD_INDEX)      reply |= DS_INDEX;
535      if (state & MFMHD_READY)      reply |= DS_READY;
536   }
537
538   return reply;
539}
540
541/*
542    Read a byte from buffer in DMA mode
543*/
544static UINT8 hfdc_dma_read_callback(running_device *device)
545{
546   ti99_hfdc_state *card = get_safe_token(device->owner());
547   UINT8 value = card->ram[card->dma_address & 0x7fff];
548   card->dma_address++;
549   return value;
550}
551
552/*
553    Write a byte to buffer in DMA mode
554*/
555static void hfdc_dma_write_callback(running_device *device, UINT8 data)
556{
557   ti99_hfdc_state *card = get_safe_token(device->owner());
558   card->ram[card->dma_address & 0x7fff] = data;
559   card->dma_address++;
560}
561
562/*
563    callback called at the end of the motor movement
564*/
565static TIMER_CALLBACK(motor_on_timer_callback)
566{
567   // currently no activity here
568}
569
570/*
571    Preliminary MFM harddisk interface.
572*/
573static void hfdc_harddisk_get_next_id(running_device *controller, int head, chrn_id_hd *id)
574{
575   running_device *harddisk = current_harddisk(controller);
576   if (harddisk != NULL)
577      ti99_mfm_harddisk_get_next_id(harddisk, head, id);
578}
579
580static void hfdc_harddisk_seek(running_device *controller, int direction)
581{
582   running_device *harddisk = current_harddisk(controller);
583   if (harddisk != NULL)
584      ti99_mfm_harddisk_seek(harddisk, direction);
585}
586
587static void hfdc_harddisk_read_sector(running_device *controller, int cylinder, int head, int sector, UINT8 **buf, int *sector_length)
588{
589   running_device *harddisk = current_harddisk(controller);
590   if (harddisk != NULL)
591      ti99_mfm_harddisk_read_sector(harddisk, cylinder, head, sector, buf, sector_length);
592}
593
594static void hfdc_harddisk_write_sector(running_device *controller, int cylinder, int head, int sector, UINT8 *buf, int sector_length)
595{
596   running_device *harddisk = current_harddisk(controller);
597   if (harddisk != NULL)
598      ti99_mfm_harddisk_write_sector(harddisk, cylinder, head, sector, buf, sector_length);
599}
600
601static void hfdc_harddisk_read_track(running_device *controller, int head, UINT8 **buffer, int *data_count)
602{
603   running_device *harddisk = current_harddisk(controller);
604   if (harddisk != NULL)
605      ti99_mfm_harddisk_read_track(harddisk, head, buffer, data_count);
606}
607
608static void hfdc_harddisk_write_track(running_device *controller, int head, UINT8 *buffer, int data_count)
609{
610   running_device *harddisk = current_harddisk(controller);
611   if (harddisk != NULL)
612      ti99_mfm_harddisk_write_track(harddisk, head, buffer, data_count);
613}
614
615const smc92x4_interface ti99_smc92x4_interface =
616{
617   FALSE,      /* do not use the full track layout */
618   DEVCB_LINE(intrq_w),
619   DEVCB_LINE(dip_w),
620   DEVCB_HANDLER(auxbus_out),
621   DEVCB_LINE(auxbus_in),
622
623   current_floppy,
624   hfdc_dma_read_callback,
625   hfdc_dma_write_callback,
626
627   /* Preliminary MFM harddisk interface. */
628   hfdc_harddisk_get_next_id,
629   hfdc_harddisk_seek,
630   hfdc_harddisk_read_sector,
631   hfdc_harddisk_write_sector,
632   hfdc_harddisk_read_track,
633   hfdc_harddisk_write_track
634};
635
636static ti99_peb_card hfdc_card =
637{
638   data_r,
639   data_w,
640   cru_r,
641   cru_w,
642   
643   NULL, NULL,   NULL, NULL   
644};
645
646static DEVICE_START( ti99_hfdc )
647{
648   ti99_hfdc_state *card = (ti99_hfdc_state*)downcast<legacy_device_base *>(device)->token();
649   
650   /* Resolve the callbacks to the PEB */
651   peb_callback_if *topeb = (peb_callback_if *)device->baseconfig().static_config();
652   devcb_resolve_write_line(&card->lines.inta, &topeb->inta, device);
653   // The HFDC does not use READY; it has on-board RAM for DMA
654   
655   card->motor_on_timer = timer_alloc(device->machine, motor_on_timer_callback, (void *)device);
656   card->ram = NULL;
657   card->ram_offset[0] = 0x2000; // static bank
658   card->controller = device->subdevice("smc92x4");
659   card->clock = device->subdevice("mm58274c");
660   astring *region = new astring();
661   astring_assemble_3(region, device->tag(), ":", hfdc_region);   
662   card->rom = memory_region(device->machine, astring_c(region));
663}
664
665static DEVICE_STOP( ti99_hfdc )
666{
667   ti99_hfdc_state *card = (ti99_hfdc_state*)downcast<legacy_device_base *>(device)->token();
668   if (card->ram) free(card->ram);
669}
670
671static DEVICE_RESET( ti99_hfdc )
672{
673   ti99_hfdc_state *card = (ti99_hfdc_state*)downcast<legacy_device_base *>(device)->token();
674   const char *flopname[] = {FLOPPY_0, FLOPPY_1, FLOPPY_2, FLOPPY_3};
675   const char *hardname[] = {MFMHD_0, MFMHD_1, MFMHD_2};
676
677   /* If the card is selected in the menu, register the card */
678   if (input_port_read(device->machine, "DISKCTRL") == DISK_HFDC)
679   {
680      running_device *peb = device->owner();   
681      int success = mount_card(peb, device, &hfdc_card, get_pebcard_config(device)->slot);
682      if (!success) return;
683           
684      // Allocate 32 KiB for on-board buffer memory
685      if (card->ram==NULL)
686      {
687         card->ram = (UINT8*)malloc(32768);
688//         memset(card->ram, 0, 32768);
689      }
690     
691      if (input_port_read(device->machine, "HFDCDIP")&0x55)
692         ti99_set_80_track_drives(TRUE);
693      else
694         ti99_set_80_track_drives(FALSE);
695     
696      smc92x4_set_timing(card->controller, input_port_read(device->machine, "DRVSPD"));
697     
698      // Connect floppy drives to controller. Note that *this* is the
699      // controller, not the controller chip. The pcb contains a select
700      // logic.
701      int i;
702      for (i = 0; i < 4; i++)
703      {
704         card->floppy_unit[i] = device->siblingdevice(flopname[i]);
705         
706         if (card->floppy_unit[i]!=NULL)
707         {
708            floppy_drive_set_controller(card->floppy_unit[i], device);
709            //          floppy_drive_set_index_pulse_callback(floppy_unit[i], smc92x4_index_pulse_callback);
710            floppy_drive_set_rpm(card->floppy_unit[i], 300.);
711         }
712         else
713         {
714            logerror("hfdc: Image %s is null\n", flopname[i]);
715         }
716      }
717     
718      /* In the HFDC ROM, WDSx selects drive x; drive 0 is not used */
719      for (i = 1; i < 4; i++)
720      {
721         card->harddisk_unit[i] = device->siblingdevice(hardname[i-1]);
722      }
723      card->harddisk_unit[0] = NULL;
724
725      floppy_type_t flop = FLOPPY_STANDARD_5_25_DSHD;
726      set_all_geometries(device, flop);
727
728      card->strobe_motor = 0;
729      card->ram_offset[1] = card->ram_offset[2] = card->ram_offset[3] = 0;
730      card->rom_offset = 0;
731   }
732   // TODO: Check how to make use of   floppy_mon_w(w->drive, CLEAR_LINE);
733}
734
735static const mm58274c_interface floppy_mm58274c_interface =
736{
737   1,   /*  mode 24*/
738   0   /*  first day of week */
739};
740
741MACHINE_CONFIG_FRAGMENT( ti99_hfdc )
742   MDRV_SMC92X4_ADD("smc92x4", ti99_smc92x4_interface )
743   MDRV_MM58274C_ADD("mm58274c", floppy_mm58274c_interface)
744MACHINE_CONFIG_END
745
746ROM_START( ti99_hfdc )
747   ROM_REGION(0x4000, hfdc_region, 0)
748   ROM_LOAD_OPTIONAL("hfdc.bin", 0x0000, 0x4000, CRC(66fbe0ed) SHA1(11df2ecef51de6f543e4eaf8b2529d3e65d0bd59)) /* HFDC disk DSR ROM */
749ROM_END
750
751static const char DEVTEMPLATE_SOURCE[] = __FILE__;
752
753#define DEVTEMPLATE_ID(p,s)             p##ti99_hfdc##s
754#define DEVTEMPLATE_FEATURES            DT_HAS_START | DT_HAS_STOP | DT_HAS_RESET | DT_HAS_ROM_REGION | DT_HAS_INLINE_CONFIG | DT_HAS_MACHINE_CONFIG
755#define DEVTEMPLATE_NAME                "Myarc Hard and Floppy Disk Controller Card"
756#define DEVTEMPLATE_FAMILY              "Peripheral expansion"
757#include "devtempl.h"
758
759DEFINE_LEGACY_DEVICE( HFDC, ti99_hfdc );
760
src/mess/machine/ti99/ti99defs.h
r0r9485
1/*
2    Common definitions for TI family
3*/
4
5#ifndef __TI99DEFS__
6#define __TI99DEFS__
7
8#define region_grom "cons_grom"
9#define READ8Z_DEVICE_HANDLER(name)      void name(ATTR_UNUSED device_t *device, ATTR_UNUSED offs_t offset, UINT8 *value)
10#define READ16Z_DEVICE_HANDLER(name)      void name(ATTR_UNUSED device_t *device, ATTR_UNUSED offs_t offset, UINT16 *value)
11
12enum
13{
14   RAM_NONE = 0,
15   RAM_TI32_INT,
16   RAM_TI32_EXT,
17   RAM_SUPERAMS1024,
18   RAM_FOUNDATION128,
19   RAM_FOUNDATION512,
20   RAM_MYARC128,
21   RAM_MYARC512,
22   RAM_99_4P,
23   RAM_99_8
24};
25
26enum
27{
28   DISK_NONE = 0,
29   DISK_TIFDC,
30   DISK_BWG,
31   DISK_HFDC
32};
33
34enum
35{
36   HD_NONE = 0,
37   HD_IDE,
38   HD_WHTECH,
39   HD_USB = 4
40};
41
42enum
43{
44   SERIAL_NONE = 0,
45   SERIAL_TI
46};
47
48enum
49{
50   EXT_NONE = 0,
51   EXT_HSGPL_FLASH = 1,
52   EXT_HSGPL_ON = 2,
53   EXT_PCODE = 4
54};
55
56enum
57{
58   HCI_NONE = 0,
59   HCI_MECMOUSE = 1,
60   HCI_IR = 4
61};
62
63enum
64{
65   CART_AUTO = 0,
66   CART_1,
67   CART_2,
68   CART_3,
69   CART_4,
70   CART_GK = 15
71};
72
73enum
74{
75   GK_OFF = 0,
76   GK_NORMAL = 1,
77   GK_GRAM0 = 0,
78   GK_OPSYS = 1,
79   GK_GRAM12 = 0,
80   GK_TIBASIC = 1,
81   GK_BANK1 = 0,
82   GK_WP = 1,
83   GK_BANK2 = 2,
84   GK_LDON = 0,
85   GK_LDOFF = 1
86};
87
88#endif
src/mess/machine/ti99/samsmem.h
r0r9485
1/*
2    TI-99 SuperAMS memory expansion
3    Michael Zapf, September 2010
4*/
5
6#ifndef __SAMSMEM__
7#define __SAMSMEM__
8
9DECLARE_LEGACY_DEVICE( SAMSMEM, ti99_samsmem );
10#endif
src/mess/machine/ti99/ti_rs232.c
r0r9485
1/*
2    TI-99 RS232 and Parallel interface card
3   Currently this emulation does not interact with the serial interface
4   on the host computer. Planned for a later release.
5   As most serial applications require a feedback from the receiver's side
6   the serial interface implementation will usually *not* work.
7   
8   TI99 RS232 card ('rs232')
9   TMS9902 ('rs232:tms9902_0')
10   TMS9902 ('rs232:tms9902_1')
11   TI99 RS232 attached serial device ('rs232:serdev0')
12   TI99 RS232 attached serial device ('rs232:serdev1')
13   TI99 PIO attached parallel device ('rs232:piodev')
14   
15*/
16#include "emu.h"
17#include "peribox.h"
18#include "machine/tms9902.h"
19#include "ti_rs232.h"
20
21#define CRU_BASE 0x1300
22#define SENILA_0_BIT 0x80
23#define SENILA_1_BIT 0x40
24
25#define ser_region "ser_region"
26
27// Second card: Change CRU base to 0x1500
28// #define CRU_BASE 0x1500
29
30typedef ti99_pebcard_config ti_rs232_config;
31
32typedef struct _ti_rs232_state
33{
34   running_device *uart0, *uart1, *serdev0, *serdev1, *piodev;
35
36   int    selected;
37   
38   // PIO flags
39   int pio_direction;      // a.k.a. PIOOC pio in output mode if 0
40   int pio_handshakeout;
41   int pio_handshakein;
42   int pio_spareout;
43   int pio_sparein;
44   int flag0;            // spare
45   int cts1;            // a.k.a. flag1
46   int cts2;            // a.k.a. flag2
47   int led;            // a.k.a. flag3
48   int pio_out_buffer;
49   int pio_in_buffer;
50   int pio_readable;
51   int pio_writable;
52   int pio_write;         // 1 if image is to be written to
53     
54   UINT8    *rom;
55   
56   /* Keeps the state of the SENILA line. */
57   UINT8   senila;
58   
59   /* Keeps the value put on the bus when SENILA becomes active. */
60   UINT8    ila;
61   
62   /* Callback lines to the main system. */
63   ti99_peb_connect   lines;
64   
65} ti_rs232_state;
66
67INLINE ti_rs232_state *get_safe_token(running_device *device)
68{
69   assert(device != NULL);
70   return (ti_rs232_state *)downcast<legacy_device_base *>(device)->token();
71}
72
73/**************************************************************************/
74/* Ports */
75
76static DEVICE_START( ti99_rs232_serdev )
77{
78}
79
80static DEVICE_START( ti99_piodev )
81{
82}
83
84/*
85    Find the index of the image name. We assume the format
86    <name><number>, i.e. the number is the longest string from the right
87    which can be interpreted as a number.
88*/
89static int get_index_from_tagname(running_device *image)
90{
91   const char *tag = image->tag();
92   int maxlen = strlen(tag);
93   int i;
94   for (i=maxlen-1; i >=0; i--)
95      if (tag[i] < 48 || tag[i] > 57) break;
96
97   return atoi(tag+i+1);
98}
99
100/*
101    Initialize rs232 unit and open image
102*/
103static DEVICE_IMAGE_LOAD( ti99_rs232_serdev )
104{
105   running_device *tms9902 = NULL;
106
107   // TODO: strcmp does not work this way (wrong constant or wrong function)
108   int devnumber = get_index_from_tagname(&image.device());
109   if (devnumber==0)
110   {
111      tms9902 = image.device().siblingdevice("tms9902_0");
112   }
113   else if (devnumber==1)
114   {
115      tms9902 = image.device().siblingdevice("tms9902_1");
116   }
117   else
118   {
119      logerror("ti99/rs232: Could not find device tag number\n");
120      return IMAGE_INIT_FAIL;
121   }
122   
123   if (image)
124   {
125      tms9902_set_cts(tms9902, 1);
126      tms9902_set_dsr(tms9902, 1);
127   }
128   else
129   {
130      tms9902_set_cts(tms9902, 0);
131      tms9902_set_dsr(tms9902, 0);
132   }
133
134   return IMAGE_INIT_PASS;
135}
136
137/*
138    Initialize pio unit and open image
139*/
140static DEVICE_IMAGE_LOAD( ti99_piodev )
141{
142   running_device *carddev = image.device().owner();
143   ti_rs232_state *card = get_safe_token(carddev);
144
145   /* tell whether the image is writable */
146   card->pio_readable = !image.has_been_created();
147   /* tell whether the image is writable */
148   card->pio_writable = image.is_writable();
149
150   if (card->pio_write && card->pio_writable)
151      card->pio_handshakein = 0;   /* receiver ready */
152   else
153      card->pio_handshakein = 1;
154
155   return IMAGE_INIT_PASS;
156}
157
158/*
159    close a pio image
160*/
161static DEVICE_IMAGE_UNLOAD( ti99_piodev )
162{
163   running_device *carddev = image.device().owner();
164   ti_rs232_state *card = get_safe_token(carddev);
165
166   card->pio_writable = 0;
167   card->pio_handshakein = 1;   /* receiver not ready */
168   card->pio_sparein = 0;
169}
170
171/****************************************************************************/
172
173/*
174    CRU read
175*/
176static READ8Z_DEVICE_HANDLER( cru_rz )
177{
178   ti_rs232_state *card = get_safe_token(device);
179
180   if ((offset & 0xff00)==CRU_BASE)
181   {
182      if ((offset & 0x00c0)==0x0000)
183      {
184         UINT8 reply = 0x00;
185         if (card->pio_direction)
186            reply |= 0x02;
187         if (card->pio_handshakein)
188            reply |= 0x04;
189         if (card->pio_sparein)
190            reply |= 0x08;
191         if (card->flag0)
192            reply |= 0x10;
193         if (card->cts1)
194            reply |= 0x20;
195         if (card->cts2)
196            reply |= 0x40;
197         if (card->led)
198            reply |= 0x80;         
199         *value = reply;
200         return;
201      }
202      if ((offset & 0x00c0)==0x0040)
203      {
204         *value = tms9902_cru_r(card->uart0, offset>>4);
205         return;
206      }
207      if ((offset & 0x00c0)==0x0080)
208      {
209         *value = tms9902_cru_r(card->uart1, offset>>1);
210         return;
211      }
212   }
213}
214
215/*
216   CRU write
217*/
218static WRITE8_DEVICE_HANDLER( cru_w )
219{
220   ti_rs232_state *card = get_safe_token(device);
221
222   if ((offset & 0xff00)==CRU_BASE)
223   {
224      if ((offset & 0x00c0)==0x0040)
225      {
226         tms9902_cru_w(card->uart0, offset>>1, data);
227         return;
228      }
229      if ((offset & 0x00c0)==0x0080)
230      {
231         tms9902_cru_w(card->uart1, offset, data);
232         return;
233      }
234
235      device_image_interface *image = dynamic_cast<device_image_interface *>(card->piodev);
236      int bit = (offset & 0x00ff)>>1;
237      switch (bit)
238      {
239      case 0:
240         card->selected = data;
241         break;
242         
243      case 1:
244         card->pio_direction = data;
245         break;
246         
247      case 2:
248         if (data != card->pio_handshakeout)
249         {
250            card->pio_handshakeout = data;
251            if (card->pio_write && card->pio_writable && (!card->pio_direction))
252            {   /* PIO in output mode */
253               if (!card->pio_handshakeout)
254               {   /* write data strobe */
255                  /* write data and acknowledge */
256                  UINT8 buf = card->pio_out_buffer;
257                  int ret = image->fwrite(&buf, 1);
258                  if (ret)
259                     card->pio_handshakein = 1;
260               }
261               else
262               {
263                  /* end strobe */
264                  /* we can write some data: set receiver ready */
265                  card->pio_handshakein = 0;
266               }
267            }
268            if ((!card->pio_write) && card->pio_readable /*&& pio_direction*/)
269            {   /* PIO in input mode */
270               if (!card->pio_handshakeout)
271               {   /* receiver ready */
272                  /* send data and strobe */
273                  UINT8 buf;
274                  if (image->fread(&buf, 1))
275                     card->pio_in_buffer = buf;
276                  card->pio_handshakein = 0;
277               }
278               else
279               {
280                  /* data acknowledge */
281                  /* we can send some data: set transmitter ready */
282                  card->pio_handshakein = 1;
283               }
284            }
285         }
286         break;
287         
288      case 3:
289         card->pio_spareout = data;
290         break;
291         
292      case 4:
293         card->flag0 = data;
294         break;
295         
296      case 5:
297         card->cts1 = data;
298         break;
299         
300      case 6:
301         card->cts2 = data;
302         break;
303         
304      case 7:
305         card->led = data;
306         break;
307      }
308      return;
309   }
310}
311
312/*
313    Memory read
314*/
315static READ8Z_DEVICE_HANDLER( data_rz )
316{
317   ti_rs232_state *card = get_safe_token(device);
318
319   if (card->senila)
320   {
321      logerror("ti99/rs232: Sensing ILA\n");
322      *value = card->ila;
323      // hope that the card rom was *not* selected, or we get two values
324      // on the address bus
325
326      // Not sure whether this is right. Unfortunately, this is difficult
327      // to verify since the system does not make use of it, although the
328      // lines are there.
329      card->ila = 0;
330   }
331   if (((offset & 0xe000)==0x4000) && card->selected)
332   {
333      if ((offset & 0x1000)==0x0000)
334      {
335         *value = card->rom[offset&0x0fff];
336      }
337      else
338      {
339         *value = card->pio_direction ? card->pio_in_buffer : card->pio_out_buffer;
340      }
341   }
342}
343
344/*
345   Memory write
346*/
347static WRITE8_DEVICE_HANDLER( data_w )
348{
349   ti_rs232_state *card = get_safe_token(device);
350
351   if (((offset & 0xe000)==0x4000) && card->selected)
352   {
353      if ((offset & 0x1001)==0x1000)
354      {
355         card->pio_out_buffer = data;
356      }
357   }
358}
359
360/**************************************************************************/
361
362/*
363    rs232 interrupt handler
364*/
365static TMS9902_INT_CALLBACK( int_callback_0 )
366{
367   running_device *carddev = device->owner();
368   ti_rs232_state *card = get_safe_token(carddev);
369   if (INT)
370      card->ila |= SENILA_0_BIT;
371   else
372      card->ila &= ~SENILA_0_BIT;
373     
374   devcb_call_write_line(&card->lines.inta, INT);
375}
376
377static TMS9902_INT_CALLBACK( int_callback_1 )
378{
379   running_device *carddev = device->owner();
380   ti_rs232_state *card = get_safe_token(carddev);
381   if (INT)
382      card->ila |= SENILA_1_BIT;
383   else
384      card->ila &= ~SENILA_1_BIT;
385   
386   devcb_call_write_line(&card->lines.inta, INT);
387}
388
389static TMS9902_XMIT_CALLBACK( xmit_callback_0 )
390{
391   UINT8 buf = data;
392   device_image_interface *rs232_fp = dynamic_cast<device_image_interface *>(device->siblingdevice("serdev0"));
393
394   if (rs232_fp)
395      rs232_fp->fwrite(&buf, 1);
396   else
397      logerror("ti99/rs232: serdev0 not found\n");
398}
399
400static TMS9902_XMIT_CALLBACK( xmit_callback_1 )
401{
402   UINT8 buf = data;
403   device_image_interface *rs232_fp = dynamic_cast<device_image_interface *>(device->siblingdevice("serdev1"));
404
405   if (rs232_fp)
406      rs232_fp->fwrite(&buf, 1);
407   else
408      logerror("ti99/rs232: serdev1 not found\n");
409}
410
411WRITE_LINE_DEVICE_HANDLER( senila )
412{
413   // put the value on the data bus. We store it in a state variable.
414   ti_rs232_state *card = (ti_rs232_state*)downcast<legacy_device_base *>(device)->token();
415   card->senila = state;
416}
417
418static const tms9902_interface tms9902_params_0 =
419{
420   3000000.,            /* clock rate (3MHz) */
421   int_callback_0,         /* called when interrupt pin state changes */
422   NULL,//rts_callback,            /* called when Request To Send pin state changes */
423   NULL,//brk_callback,            /* called when BReaK state changes */
424   xmit_callback_0         /* called when a character is transmitted */
425};
426
427static const tms9902_interface tms9902_params_1 =
428{
429   3000000.,            /* clock rate (3MHz) */
430   int_callback_1,         /* called when interrupt pin state changes */
431   NULL,//rts_callback,            /* called when Request To Send pin state changes */
432   NULL,//brk_callback,            /* called when BReaK state changes */
433   xmit_callback_1         /* called when a character is transmitted */
434};
435
436
437static ti99_peb_card tirs232_card =
438{
439   data_rz, data_w,            // memory access read/write
440   cru_rz, cru_w,               // CRU access
441   senila, NULL,               // SENILA/B access
442   NULL, NULL                  // 16 bit access (none here)
443};
444
445/*
446   Defines the serial serdev.
447*/
448DEVICE_GET_INFO( ti99_rs232_serdev )
449{
450   switch ( state )
451   {
452      case DEVINFO_INT_INLINE_CONFIG_BYTES:      info->i = 0;                        break;
453      case DEVINFO_INT_IMAGE_TYPE:               info->i = IO_SERIAL;                                      break;
454      case DEVINFO_INT_IMAGE_READABLE:            info->i = 1;                                               break;
455      case DEVINFO_INT_IMAGE_WRITEABLE:         info->i = 1;                                               break;
456      case DEVINFO_INT_IMAGE_CREATABLE:          info->i = 1;                                               break;
457
458      case DEVINFO_FCT_START:                      info->start = DEVICE_START_NAME( ti99_rs232_serdev );              break;
459//      case DEVINFO_FCT_RESET:                  info->reset = DEVICE_RESET_NAME( ti99_rs232_serdev );         break;
460      case DEVINFO_FCT_IMAGE_LOAD:              info->f = (genf *) DEVICE_IMAGE_LOAD_NAME( ti99_rs232_serdev );    break;
461      case DEVINFO_STR_NAME:                      strcpy( info->s, "TI99 RS232 attached serial device");                            break;
462      case DEVINFO_STR_FAMILY:                    strcpy(info->s, "Peripheral expansion");                            break;
463      case DEVINFO_STR_IMAGE_FILE_EXTENSIONS:       strcpy(info->s, "");                                           break;
464      case DEVINFO_STR_VERSION:                  strcpy(info->s, "1.0");                              break;
465      case DEVINFO_STR_SOURCE_FILE:               strcpy(info->s, __FILE__);                           break;
466      case DEVINFO_STR_CREDITS:                  strcpy(info->s, "Copyright the MESS Team");       break;
467   }
468}
469
470/*
471   Defines the PIO (parallel IO) serdev
472*/
473DEVICE_GET_INFO( ti99_piodev )
474{
475   switch ( state )
476   {
477      case DEVINFO_INT_INLINE_CONFIG_BYTES:      info->i = 0;                        break;
478      case DEVINFO_INT_IMAGE_TYPE:               info->i = IO_PARALLEL;                                      break;
479      case DEVINFO_INT_IMAGE_READABLE:            info->i = 1;                                               break;
480      case DEVINFO_INT_IMAGE_WRITEABLE:         info->i = 1;                                               break;
481      case DEVINFO_INT_IMAGE_CREATABLE:          info->i = 1;                                               break;
482
483      case DEVINFO_FCT_START:                      info->start = DEVICE_START_NAME( ti99_piodev );              break;
484      case DEVINFO_FCT_IMAGE_LOAD:              info->f = (genf *) DEVICE_IMAGE_LOAD_NAME( ti99_piodev );    break;
485      case DEVINFO_FCT_IMAGE_UNLOAD:              info->f = (genf *) DEVICE_IMAGE_UNLOAD_NAME(ti99_piodev );  break;
486      case DEVINFO_STR_NAME:                      strcpy( info->s, "TI99 PIO attached device");                            break;
487      case DEVINFO_STR_FAMILY:                    strcpy(info->s, "Peripheral expansion");                            break;
488      case DEVINFO_STR_IMAGE_FILE_EXTENSIONS:       strcpy(info->s, "");                                           break;
489      case DEVINFO_STR_VERSION:                  strcpy(info->s, "1.0");                              break;
490      case DEVINFO_STR_SOURCE_FILE:               strcpy(info->s, __FILE__);                           break;
491      case DEVINFO_STR_CREDITS:                  strcpy(info->s, "Copyright the MESS Team");       break;
492   }
493}
494
495DECLARE_LEGACY_IMAGE_DEVICE(TI99_RS232, ti99_rs232_serdev);
496DEFINE_LEGACY_IMAGE_DEVICE(TI99_RS232, ti99_rs232_serdev);
497DECLARE_LEGACY_IMAGE_DEVICE(TI99_PIO, ti99_piodev);
498DEFINE_LEGACY_IMAGE_DEVICE(TI99_PIO, ti99_piodev);
499
500static DEVICE_START( ti_rs232 )
501{
502   ti_rs232_state *card = (ti_rs232_state*)downcast<legacy_device_base *>(device)->token();
503   peb_callback_if *topeb = (peb_callback_if *)device->baseconfig().static_config();
504
505   astring *region = new astring();
506   astring_assemble_3(region, device->tag(), ":", ser_region);   
507   card->rom = memory_region(device->machine, astring_c(region));
508   devcb_resolve_write_line(&card->lines.inta, &topeb->inta, device);
509   // READY and INTB are not used
510   card->uart0 = device->subdevice("tms9902_0");
511   card->uart1 = device->subdevice("tms9902_1");
512   card->serdev0 = device->subdevice("serdev0");
513   card->serdev1 = device->subdevice("serdev1");
514   card->piodev = device->subdevice("piodev");
515}
516
517static DEVICE_STOP( ti_rs232 )
518{
519}
520
521static DEVICE_RESET( ti_rs232 )
522{
523   ti_rs232_state *card = (ti_rs232_state*)downcast<legacy_device_base *>(device)->token();
524   /* Register the card */
525   running_device *peb = device->owner();
526   
527   if (input_port_read(device->machine, "SERIAL")==SERIAL_TI)
528   {
529      int success = mount_card(peb, device, &tirs232_card, get_pebcard_config(device)->slot);
530      if (!success) return;
531
532      card->pio_direction = 0;
533      card->pio_handshakeout = 0;
534      card->pio_spareout = 0;
535      card->flag0 = 0;
536      card->cts1 = 0;
537      card->cts2 = 0;
538      card->led = 0;
539      card->pio_write = 1;
540   }
541}
542
543static MACHINE_CONFIG_FRAGMENT( ti_rs232 )
544   MDRV_TMS9902_ADD("tms9902_0", tms9902_params_0)
545   MDRV_TMS9902_ADD("tms9902_1", tms9902_params_1)
546   MDRV_DEVICE_ADD("serdev0", TI99_RS232, 0)
547   MDRV_DEVICE_ADD("serdev1", TI99_RS232, 0)
548   MDRV_DEVICE_ADD("piodev", TI99_PIO, 0)   
549MACHINE_CONFIG_END
550
551ROM_START( ti_rs232 )
552   ROM_REGION(0x1000, ser_region, 0)
553   ROM_LOAD_OPTIONAL("rs232.bin", 0x0000, 0x1000, CRC(eab382fb) SHA1(ee609a18a21f1a3ddab334e8798d5f2a0fcefa91)) /* TI rs232 DSR ROM */
554ROM_END
555
556static const char DEVTEMPLATE_SOURCE[] = __FILE__;
557
558#define DEVTEMPLATE_ID(p,s)             p##ti_rs232##s
559#define DEVTEMPLATE_FEATURES            DT_HAS_START | DT_HAS_STOP | DT_HAS_RESET | DT_HAS_INLINE_CONFIG | DT_HAS_ROM_REGION | DT_HAS_MACHINE_CONFIG
560#define DEVTEMPLATE_NAME                "TI99 RS232/PIO interface card"
561#define DEVTEMPLATE_FAMILY              "Peripheral expansion"
562#include "devtempl.h"
563
564DEFINE_LEGACY_DEVICE( TIRS232, ti_rs232 );
565
src/mess/machine/ti99/tn_ide.h
r0r9485
1/*
2    Nouspikel IDE controller card
3    Michael Zapf, September 2010
4*/
5
6#ifndef __TNIDE__
7#define __TNIDE__
8
9DECLARE_LEGACY_DEVICE( TNIDE, tn_ide );
10#endif
src/mess/machine/ti99/peribox.c
r0r9485
1/*
2    Peripheral expansion bus support.
3 
4    The ti-99/4, ti-99/4a, ti computer 99/8, myarc geneve, and snug sgcpu
5    99/4p systems all feature a bus connector that enables the connection of
6    extension cards.  (Although the hexbus is the preferred bus to add
7    additional peripherals to a ti-99/8, ti-99/8 is believed to be compatible
8    with the older PEB system.)  In the case of the TI consoles, this bus
9    connector is located on the right side of the console.
10 
11    While a few extension cards connect to the side bus connector of the
12    ti-99/4(a) console directly, most extension cards were designed to be
13    inserted in a PEB instead.  The PEB (Peripheral Expansion Box) is a big box
14    with an alimentation, a few bus drivers, and several card slots, that
15    connects to the ti-99/4(a) side port.  The reason for using a PEB is that
16    daisy-chaining many modules caused the system to be unreliable due to the
17    noise produced by the successive contacts.  (As a matter of fact, TI
18    initially released most of its extension cards as side bus units, but when
19    the design proved to be unreliable, the PEB was introduced.  The TI speech
20    synthesizer was the only TI extension that remained on the side bus after
21    the introduction of the PEB, probably because TI wanted the speech
22    synthesizer to be a cheap extension, and the PEB was not cheap.)
23 
24    June 2010: Reimplemented using device structure (MZ) (obsoletes 99_peb.c)
25 
26Slots:
27   
28          REAR
29     +8V  1||2   +8V
30     GND  3||4   READY
31     GND  5||6   RESET*
32     GND  7||8   SCLK
33 BOOTPG*  9||10  AUDIO
34 RDBENA* 11||12  PCBEN
35   HOLD* 13||14  IAQHDA
36 SENILA* 15||16  SENILB*
37  INTA*  17||18  INTB*
38     D7  19||20  GND   
39     D5  21||22  D6
40     D3  23||24  D4
41     D1  25||26  D2
42    GND  27||28  D0
43    A14  29||30  A15/CRUOUT
44    A12  31||32  A13
45    A10  33||34  A11
46     A8  35||36  A9
47     A6  37||38  A7   
48     A4  39||40  A5
49     A2  41||42  A3
50     A0  43||44  A1
51    AMB  45||46  AMA 
52    GND  47||48  AMC
53    GND  49||50  CLKOUT*
54CRUCLK*  51||52  DBIN
55    GND  53||54  WE*
56  CRUIN  55||56  MEMEN*
57   -16V  57||58  -16V
58   +16V  59||60  +16V
59         FRONT
60 
61        < from box to console
62        > from console into box
63 
64READYA  <    System ready (goes to READY, 10K pull-up to +5V) A low level puts the cpu on hold.
65RESET*  >    System reset (active low) 
66SCLK    nc   System clock (not connected in interface card) 
67LCP*    nc   CPU indicator 1=TI99 0=2nd generation (not connected in interface card) 
68BOOTPG* nc   ?
69AUDIO   <    Input audio (to AUDIOIN in console) 
70RDBENA* <    Active low: enable flex cable data bus drivers (1K pull-up) 
71PCBEN   H    PCB enable for burn-in (always High) 
72HOLD*   H    Active low CPU hold request (always High) 
73IAQHDA  nc   IAQ [or] HOLDA (logical or) 
74SENILA* H(>) Interrupt level A sense enable (always High) 
75SENILB* H(>) Interrupt level B sense enable (always High) 
76INTA*   <    Interrupt level A (active low, goes to EXTINT*) 
77INTB*   nc   Interrupt level B (not used) 
78LOAD*   nc   Unmaskable interrupt (not carried by interface cable/card) 
79D0-D7   <>   Data bus (D0 most significant) 
80A0-A15  >    Address bus (A0 most sig; A15 also used as CRUOUT)
81AMA/B/C H    Extra address bits (always high for TI-99/4x)
82CLKOUT* >    Inverted PHI3 clock, from TIM9904 clock generator
83CRUCLK* >    Inverted CRU clock, from TMS9900 CRUCLK pin
84DBIN    >    Active high = read memory. Drives the data bus buffers.
85WE*     >    Write Enable pulse (derived from TMS9900 WE* pin)
86CRUIN   <    CRU input bit to TMS9900
87MEMEN*  >    Memory access enable (active low) 
88 
89 
90The obscure SENILx lines:
91 
92With SENILA* going low, a value shall be put on the data bus, 
93representing the interrupt status bits. It can also be used to determine 
94the source of the interrupt: The RS232 card (in its standard configuration) 
95uses the data bus bits 0 and 1 for its two UARTs, while in the second 
96configuration, it uses bits 4 and 5. Still note that the TI-99/4x does not make 
97use of SENILA*.
98 
99SENILB* / INTB* was planned to be used with disk controllers. The PHP1240 disk
100controller puts the value of INTB* on D0 when SENILB* gets active (low) which
101reflects the INTRQ output pin of the WD1771. This signal is not used, however. 
102Instead, the disk controller combines DRQ and IRQ and makes use of a READY/HOLD
103control of the CPU.
104 
105Obviously, SENILA* and SENILB* should never be active at the same time, and 
106neither should any memory access to a card be active at the same time, for in 
107both cases, data bus lines may be set to different levels simultaneously. One
108possible application case is to turn off all cards in the box, lower SENILA*, 
109and then do a read access in the memory area of any card in the P-Box (e.g.
1100x4000-0x5fff). Another possiblity is that the currently active card simply
111does not respond to a certain memory access, and in this case the status bits
112can be read.
113 
114Also note that the SENILx lines access all cards in parallel, meaning that there
115must be an agreement which cards may use which bits on the data bus. The lines
116do not depend on the card being active at that time. 
117*/
118 
119#include "emu.h"
120#include "peribox.h"
121 
122/* Expansion cards */
123#include "p_code.h"
124#include "ti_fdc.h"
125#include "hfdc.h"
126#include "bwg.h"
127#include "ti_rs232.h"
128#include "tn_usbsm.h"
129#include "tn_ide.h"
130#include "hsgpl.h"
131#include "spchsyn.h"
132#include "evpc.h"
133 
134#include "devices/flopdrv.h"
135#include "devices/harddriv.h"
136#include "formats/ti99_dsk.h"
137#include "devices/ti99_hd.h"
138 
139static const floppy_config ti99_4_floppy_config =
140{
141   DEVCB_NULL,
142   DEVCB_NULL,
143   DEVCB_NULL,
144   DEVCB_NULL,
145   DEVCB_NULL,
146   FLOPPY_STANDARD_5_25_DSHD,
147   FLOPPY_OPTIONS_NAME(ti99),
148   NULL
149};
150 
151typedef struct _ti99_peb_slot
152{
153   running_device       *card;
154   ti99_peb_card       *intf;
155} ti99_peb_slot;
156 
157typedef struct _ti99_peb_state
158{
159   ti99_peb_slot         slot[MAXSLOTS];
160 
161   // The next three members are used to emulate the collective lines
162   // If any card goes L, L is propagated. We are using flags.
163   UINT32               inta_state;
164   UINT32               intb_state;
165   UINT32               ready_state;
166 
167   int                  highest;
168   
169   // Callback to the main system
170   ti99_peb_connect      lines;
171   
172} ti99_peb_state;
173 
174INLINE ti99_peb_state *get_safe_token(running_device *device)
175{
176   assert(device != NULL);
177   return (ti99_peb_state *)downcast<legacy_device_base *>(device)->token();
178}
179 
180INLINE const ti99_peb_config *get_config(running_device *device)
181{
182   assert(device != NULL);
183   assert(device->type() == PBOX4 || device->type() == PBOX4A || device->type() == PBOX8 || device->type() == PBOXEV || device->type() == PBOXSG || device->type() == PBOXGEN);
184   return (const ti99_peb_config *) downcast<const legacy_device_config_base &>(device->baseconfig()).inline_config();
185}
186 
187/* Callbacks */
188static WRITE_LINE_DEVICE_HANDLER( inta )
189{
190   int slot = get_pebcard_config(device)->slot;
191   ti99_peb_state *peb = (ti99_peb_state*)downcast<legacy_device_base *>(device->owner())->token();
192   if (state==TRUE)
193   {
194      // The flags are stored as inverted (inta_state=0 if all lines are H)
195      peb->inta_state &= ~(1 << slot);
196   }
197   else
198   {
199      // 1 means: The card set it to L
200      peb->inta_state |= (1 << slot);
201   }
202   // Call back the main system, setting the line to L if any PEB card set it to L
203   // This is the case when inta_state is not 0
204   devcb_call_write_line( &peb->lines.inta, (peb->inta_state == 0) );
205}
206 
207static WRITE_LINE_DEVICE_HANDLER( intb )
208{
209   int slot = get_pebcard_config(device)->slot;
210   ti99_peb_state *peb = (ti99_peb_state*)downcast<legacy_device_base *>(device->owner())->token();
211   if (state==TRUE)
212      peb->intb_state &= ~(1 << slot);
213   else
214      peb->intb_state |= (1 << slot);
215   devcb_call_write_line( &peb->lines.intb, (peb->intb_state == 0) );
216}
217 
218static WRITE_LINE_DEVICE_HANDLER( ready )
219{
220   int slot = get_pebcard_config(device)->slot;
221   ti99_peb_state *peb = (ti99_peb_state*)downcast<legacy_device_base *>(device->owner())->token();
222   if (state==TRUE)
223      peb->ready_state &= ~(1 << slot);
224   else
225      peb->ready_state |= (1 << slot);
226   devcb_call_write_line( &peb->lines.ready, (peb->ready_state == 0) );
227}
228 
229/*
230   Declares the callbacks above that are called from the cards. This instance
231   is passed to the cards with MDRV_PBOXCARD_ADD and must be handled as a
232   static_config.
233*/
234const peb_callback_if peb_callback = 
235{ 
236   DEVCB_LINE( inta ), 
237   DEVCB_LINE( intb ), 
238   DEVCB_LINE( ready ) 
239};
240 
241/*
242   Mount the PEB card. Although possible, this is not done by the box itself;
243   instead, the card must call this function on the box. The advantage is
244   that we can assign the same slot to different cards which are selected
245   by dip switches. Only the card which is selected will register itself; the
246   other cards are stillborn.
247   Returns TRUE when the card could be mounted.
248*/
249int mount_card(running_device *device, running_device *cardptr, ti99_peb_card *cardintf, int slotindex)
250{
251   ti99_peb_state *peb = get_safe_token(device);
252   if ((slotindex > 0) &&  (slotindex < MAXSLOTS))
253   {
254      if (peb->slot[slotindex].card == NULL)
255      {
256         peb->slot[slotindex].card = cardptr;
257         peb->slot[slotindex].intf = cardintf;
258         if (slotindex > peb->highest) peb->highest = slotindex;
259         logerror("ti99_peb: registering the card at slot index %d\n", slotindex);
260         return TRUE;
261      }
262      else
263      {
264         logerror("ti99_peb: Tried to mount a second card in slot %d\n", slotindex);
265      }
266   }
267   else
268      logerror("ti99_peb: Invalid slot number %d\n", slotindex); 
269   return FALSE;
270}
271 
272void unmount_card(running_device *device, int slotindex)
273{
274   ti99_peb_state *peb = get_safe_token(device);
275   peb->slot[slotindex].card = NULL;
276}
277 
278/***************************************************************************
279    Memory and CRU access
280***************************************************************************/
281 
282READ8Z_DEVICE_HANDLER( ti99_peb_data_rz )
283{
284   ti99_peb_state *peb = get_safe_token(device);
285   int i;
286   for (i=1; i <= peb->highest; i++)
287   {
288      if ((peb->slot[i].card != NULL) && (*peb->slot[i].intf->card_read_data))
289         (*peb->slot[i].intf->card_read_data)(peb->slot[i].card, offset, value);
290   }
291}
292 
293WRITE8_DEVICE_HANDLER( ti99_peb_data_w )
294{
295   ti99_peb_state *peb = get_safe_token(device);
296   int i;
297   for (i=1; i <= peb->highest; i++)
298   {
299      if ((peb->slot[i].card != NULL) && (*peb->slot[i].intf->card_write_data))
300         (*peb->slot[i].intf->card_write_data)(peb->slot[i].card, offset, data);
301   }
302}
303 
304READ8Z_DEVICE_HANDLER( ti99_peb_cru_rz )
305{
306   ti99_peb_state *peb = get_safe_token(device);
307   int i;
308   for (i=1; i <= peb->highest; i++)
309   {
310      if ((peb->slot[i].card != NULL) && (*peb->slot[i].intf->card_read_cru))
311         (*peb->slot[i].intf->card_read_cru)(peb->slot[i].card, offset, value);
312   }
313}
314 
315WRITE8_DEVICE_HANDLER( ti99_peb_cru_w )
316{
317   ti99_peb_state *peb = get_safe_token(device);
318   int i;
319   for (i=1; i <= peb->highest; i++)
320   {
321      if ((peb->slot[i].card != NULL) && (*peb->slot[i].intf->card_write_cru))
322         (*peb->slot[i].intf->card_write_cru)(peb->slot[i].card, offset, data);
323   }
324}
325 
326/*
327   For SGCPU
328*/
329READ16Z_DEVICE_HANDLER( ti99_peb_data16_rz )
330{
331   ti99_peb_state *peb = get_safe_token(device);
332   int i;
333   for (i=1; i <= peb->highest; i++)
334   {
335      if ((peb->slot[i].card != NULL) && (*peb->slot[i].intf->card_read_data16))
336         (*peb->slot[i].intf->card_read_data16)(peb->slot[i].card, offset, value);
337   }
338}
339 
340/*
341   For SGCPU
342*/
343WRITE16_DEVICE_HANDLER( ti99_peb_data16_w )
344{
345   ti99_peb_state *peb = get_safe_token(device);
346   int i;
347   for (i=1; i <= peb->highest; i++)
348   {
349      if ((peb->slot[i].card != NULL) && (*peb->slot[i].intf->card_write_data16))
350         (*peb->slot[i].intf->card_write_data16)(peb->slot[i].card, offset, data);
351   }
352}
353 
354/*
355   SENILx
356   TODO: Check whether device is the correct pointer (seems to be wrong here,
357   the device is usually the caller)
358*/
359WRITE_LINE_DEVICE_HANDLER( ti99_peb_senila )
360{
361   ti99_peb_state *peb = get_safe_token(device);
362   int i;
363   for (i=1; i <= peb->highest; i++)
364   {
365      if ((peb->slot[i].card != NULL) && (*peb->slot[i].intf->senila))
366         (*peb->slot[i].intf->senila)(peb->slot[i].card, state);
367   }
368}
369 
370WRITE_LINE_DEVICE_HANDLER( ti99_peb_senilb)
371{
372   ti99_peb_state *peb = get_safe_token(device);
373   int i;
374   for (i=1; i <= peb->highest; i++)
375   {
376      if ((peb->slot[i].card != NULL) && (*peb->slot[i].intf->senilb))
377         (*peb->slot[i].intf->senilb)(peb->slot[i].card, state);
378   }
379}
380 
381/***************************************************************************
382    DEVICE FUNCTIONS
383***************************************************************************/
384 
385static DEVICE_START( ti99_peb )
386{
387   ti99_peb_state *peb = get_safe_token(device);
388   const ti99_peb_config* pebconf = (const ti99_peb_config*)get_config(device);
389 
390   for (int slotindex=0; slotindex < MAXSLOTS; slotindex++)
391      unmount_card(device, slotindex);
392   
393   /* Resolve the callbacks to the console */
394   devcb_write_line inta = DEVCB_LINE(pebconf->inta);
395   devcb_write_line intb = DEVCB_LINE(pebconf->intb);
396   devcb_write_line ready = DEVCB_LINE(pebconf->ready);
397 
398   devcb_resolve_write_line(&peb->lines.ready, &ready, device);
399   devcb_resolve_write_line(&peb->lines.inta, &inta, device);
400   devcb_resolve_write_line(&peb->lines.intb, &intb, device);
401}
402 
403static DEVICE_STOP( ti99_peb )
404{
405   logerror("ti99_peb: stop\n");
406}
407 
408static DEVICE_RESET( ti99_peb )
409{
410   ti99_peb_state *peb = get_safe_token(device);
411   logerror("ti99_peb: reset\n");
412   peb->inta_state = 0;   
413   peb->intb_state = 0;   
414   peb->ready_state = 0;
415   peb->highest = 0;
416   for (int i=0; i < MAXSLOTS; i++) unmount_card(device, i);
417}
418 
419#define MDRV_PBOXCARD_ADD( _tag, _type, _slot ) \
420   MDRV_DEVICE_ADD(_tag, _type, 0) \
421   MDRV_DEVICE_CONFIG_DATA32( ti99_pebcard_config, slot, _slot ) \
422   MDRV_DEVICE_CONFIG( peb_callback )
423 
424/*
425   We're emulating a "super box" with more than 8 slots. The original
426   box had 8 slots, but that's a bit too limiting.
427   This may become organized differently in future versions; for now
428   we'll go this way.
429   
430   Slot 0 is the "Flex cable interface" / SGCPU / Geneve
431   We assign the same slot number for some cards that cannot be used
432   in parallel anyway. The config switch will determine which one to use.
433   Future works:   
434   // WHTech SCSI controller 
435   // MDRV_PBOXCARD_ADD("SCSI", 4, scsi_intf)
436 
437   // Horizon Ramdisk
438   // MDRV_PBOXCARD_ADD("HRD", 10, ramdisk_intf)
439*/ 
440 
441static MACHINE_CONFIG_FRAGMENT( ti99_peb )
442   MDRV_PBOXCARD_ADD( "mem_ti32k",    TI32KMEM, 1 ) 
443   MDRV_PBOXCARD_ADD( "mem_sams1m",    SAMSMEM,  1 )
444   MDRV_PBOXCARD_ADD( "mem_myarc512",    MYARCMEM, 1 )   
445   MDRV_PBOXCARD_ADD( "speech",       TISPEECH, 2 )   
446   MDRV_PBOXCARD_ADD( "usbsmart",       USBSMART, 3 )
447   MDRV_PBOXCARD_ADD( "ide",          TNIDE,      4 )
448   MDRV_PBOXCARD_ADD( "hsgpl",       HSGPL,    5 ) 
449   MDRV_PBOXCARD_ADD( "rs232_card",    TIRS232,  7 )
450   MDRV_PBOXCARD_ADD( "ti_fdc",       TIFDC,      8 )
451   MDRV_PBOXCARD_ADD( "hfdc",          HFDC,      8 )
452   MDRV_PBOXCARD_ADD( "bwg",          BWG,      8 )
453   
454   MDRV_FLOPPY_4_DRIVES_ADD(ti99_4_floppy_config)
455   MDRV_MFMHD_3_DRIVES_ADD()
456MACHINE_CONFIG_END
457 
458static MACHINE_CONFIG_FRAGMENT( ti994a_peb )
459   MDRV_PBOXCARD_ADD( "mem_ti32k",    TI32KMEM, 1 ) 
460   MDRV_PBOXCARD_ADD( "mem_sams1m",    SAMSMEM,  1 )
461   MDRV_PBOXCARD_ADD( "mem_myarc512",    MYARCMEM, 1 )   
462   MDRV_PBOXCARD_ADD( "speech",       TISPEECH, 2 )   
463   MDRV_PBOXCARD_ADD( "usbsmart",       USBSMART, 3 )
464   MDRV_PBOXCARD_ADD( "ide",          TNIDE,      4 )
465   MDRV_PBOXCARD_ADD( "hsgpl",       HSGPL,    5 ) 
466   MDRV_PBOXCARD_ADD( "p_code_card",    PCODEN,   6 )
467   MDRV_PBOXCARD_ADD( "rs232_card",    TIRS232,  7 )
468   MDRV_PBOXCARD_ADD( "ti_fdc",       TIFDC,      8 )
469   MDRV_PBOXCARD_ADD( "hfdc",          HFDC,      8 )
470   MDRV_PBOXCARD_ADD( "bwg",          BWG,      8 )
471   
472   MDRV_FLOPPY_4_DRIVES_ADD(ti99_4_floppy_config)
473   MDRV_MFMHD_3_DRIVES_ADD()
474MACHINE_CONFIG_END
475 
476static MACHINE_CONFIG_FRAGMENT( ti99ev_peb )
477   MDRV_PBOXCARD_ADD( "mem_ti32k",    TI32KMEM, 1 ) 
478   MDRV_PBOXCARD_ADD( "mem_sams1m",    SAMSMEM,  1 )
479   MDRV_PBOXCARD_ADD( "mem_myarc512",    MYARCMEM, 1 )   
480   MDRV_PBOXCARD_ADD( "speech",       TISPEECH, 2 )   
481   MDRV_PBOXCARD_ADD( "usbsmart",       USBSMART, 3 )
482   MDRV_PBOXCARD_ADD( "ide",          TNIDE,      4 )
483   MDRV_PBOXCARD_ADD( "hsgpl",       HSGPL,    5 ) 
484   MDRV_PBOXCARD_ADD( "p_code_card",    PCODEN,   6 )
485   MDRV_PBOXCARD_ADD( "rs232_card",    TIRS232,  7 )
486   MDRV_PBOXCARD_ADD( "ti_fdc",       TIFDC,      8 )
487   MDRV_PBOXCARD_ADD( "hfdc",          HFDC,      8 )
488   MDRV_PBOXCARD_ADD( "bwg",          BWG,      8 )
489   MDRV_PBOXCARD_ADD( "evpc",          EVPC,     9 )
490   
491   MDRV_FLOPPY_4_DRIVES_ADD(ti99_4_floppy_config)
492   MDRV_MFMHD_3_DRIVES_ADD()
493MACHINE_CONFIG_END
494 
495 
496static MACHINE_CONFIG_FRAGMENT( ti998_peb )
497   MDRV_PBOXCARD_ADD( "usbsmart",       USBSMART, 1 )
498   MDRV_PBOXCARD_ADD( "ide",          TNIDE,      2 )
499   MDRV_PBOXCARD_ADD( "rs232_card",    TIRS232,  3 )
500   MDRV_PBOXCARD_ADD( "ti_fdc",       TIFDC,      8 )
501   MDRV_PBOXCARD_ADD( "hfdc",          HFDC,      8 )
502   MDRV_PBOXCARD_ADD( "bwg",          BWG,      8 )
503   
504   MDRV_FLOPPY_4_DRIVES_ADD(ti99_4_floppy_config)
505   MDRV_MFMHD_3_DRIVES_ADD()
506MACHINE_CONFIG_END
507 
508static MACHINE_CONFIG_FRAGMENT( ti99sg_peb )
509   MDRV_PBOXCARD_ADD( "speech",       TISPEECH, 1 )   
510   MDRV_PBOXCARD_ADD( "usbsmart",       USBSMART, 2 )
511   MDRV_PBOXCARD_ADD( "ide",          TNIDE,      3 )
512   MDRV_PBOXCARD_ADD( "hsgpl",       HSGPL,    4 ) 
513   MDRV_PBOXCARD_ADD( "rs232_card",    TIRS232,  6 )
514   MDRV_PBOXCARD_ADD( "ti_fdc",       TIFDC,      7 )
515   MDRV_PBOXCARD_ADD( "hfdc",          HFDC,      7 )
516   MDRV_PBOXCARD_ADD( "bwg",          BWG,      7 )
517   MDRV_PBOXCARD_ADD( "evpc",          EVPC,     8 )
518       
519   MDRV_FLOPPY_4_DRIVES_ADD(ti99_4_floppy_config)
520   MDRV_MFMHD_3_DRIVES_ADD()
521MACHINE_CONFIG_END
522 
523static MACHINE_CONFIG_FRAGMENT( geneve_peb )
524   MDRV_PBOXCARD_ADD( "speech",       TISPEECH, 1 )   
525   MDRV_PBOXCARD_ADD( "usbsmart",       USBSMART, 2 )
526   MDRV_PBOXCARD_ADD( "ide",          TNIDE,      3 )
527   MDRV_PBOXCARD_ADD( "rs232_card",    TIRS232,  6 )
528   MDRV_PBOXCARD_ADD( "ti_fdc",       TIFDC,      7 )
529   MDRV_PBOXCARD_ADD( "hfdc",          HFDC,      7 )
530   MDRV_PBOXCARD_ADD( "bwg",          BWG,      7 )
531       
532   MDRV_FLOPPY_4_DRIVES_ADD(ti99_4_floppy_config)
533   MDRV_MFMHD_3_DRIVES_ADD()
534MACHINE_CONFIG_END
535 
536static const char DEVTEMPLATE_SOURCE[] = __FILE__;
537 
538#define DEVTEMPLATE_ID(p,s)             p##ti99_peb##s
539#define DEVTEMPLATE_FEATURES            DT_HAS_START | DT_HAS_STOP | DT_HAS_RESET | DT_HAS_MACHINE_CONFIG | DT_HAS_INLINE_CONFIG
540#define DEVTEMPLATE_NAME                "TI-99 Peripheral Expansion System (99/4)"
541#define DEVTEMPLATE_FAMILY              "External devices"
542#include "devtempl.h"
543 
544#define DEVTEMPLATE_DERIVED_ID(p,s)      p##ti994a_peb##s
545#define DEVTEMPLATE_DERIVED_FEATURES   DT_HAS_MACHINE_CONFIG
546#define DEVTEMPLATE_DERIVED_NAME      "TI-99 Peripheral Expansion System (99/4A)"
547#include "devtempl.h"
548 
549#define DEVTEMPLATE_DERIVED_ID(p,s)      p##ti998_peb##s
550#define DEVTEMPLATE_DERIVED_FEATURES   DT_HAS_MACHINE_CONFIG
551#define DEVTEMPLATE_DERIVED_NAME      "TI-99 Peripheral Expansion System (99/8)"
552#include "devtempl.h"
553 
554#define DEVTEMPLATE_DERIVED_ID(p,s)      p##ti99ev_peb##s
555#define DEVTEMPLATE_DERIVED_FEATURES   DT_HAS_MACHINE_CONFIG
556#define DEVTEMPLATE_DERIVED_NAME      "TI-99 Peripheral Expansion System (99/4a with EVPC)"
557#include "devtempl.h"
558 
559#define DEVTEMPLATE_DERIVED_ID(p,s)      p##ti99sg_peb##s
560#define DEVTEMPLATE_DERIVED_FEATURES   DT_HAS_MACHINE_CONFIG
561#define DEVTEMPLATE_DERIVED_NAME      "TI99 Peripheral Expansion System (SGCPU)"
562#include "devtempl.h"
563 
564#define DEVTEMPLATE_DERIVED_ID(p,s)      p##geneve_peb##s
565#define DEVTEMPLATE_DERIVED_FEATURES   DT_HAS_MACHINE_CONFIG
566#define DEVTEMPLATE_DERIVED_NAME      "TI99 Peripheral Expansion System (Geneve)"
567#include "devtempl.h"
568 
569DEFINE_LEGACY_DEVICE( PBOX4, ti99_peb );
570DEFINE_LEGACY_DEVICE( PBOX4A, ti994a_peb );
571DEFINE_LEGACY_DEVICE( PBOXEV, ti99ev_peb );
572DEFINE_LEGACY_DEVICE( PBOX8, ti998_peb );
573DEFINE_LEGACY_DEVICE( PBOXSG, ti99sg_peb );
574DEFINE_LEGACY_DEVICE( PBOXGEN, geneve_peb );
src/mess/machine/ti99/datamux.h
r0r9485
1#ifndef __DMUX__
2#define __DMUX__
3
4typedef void (*databus_read_function)(device_t *device, offs_t offset, UINT8 *value);
5typedef void (*databus_write_function)(device_t *device, offs_t offset, UINT8 value);
6
7/* device interface */
8DECLARE_LEGACY_DEVICE( DMUX, datamux );
9
10READ16_DEVICE_HANDLER(  ti99_dmux_r );
11WRITE16_DEVICE_HANDLER( ti99_dmux_w );
12
13typedef struct _bus_device
14{
15   const char             *name;
16   UINT16               address_mask;
17   UINT16               select_pattern;
18   UINT16               write_select;
19   databus_read_function    read;
20   databus_write_function    write;
21   const char             *setting;
22   UINT8               set;
23   UINT8               unset;
24} bus_device;
25
26#define MDRV_DMUX_ADD(_tag, _devices)         \
27   MDRV_DEVICE_ADD(_tag, DMUX, 0) \
28   MDRV_DEVICE_CONFIG( _devices )
29#endif
src/mess/machine/ti99/hfdc.h
r0r9485
1/*
2    Myarc Hard and Floppy Disk Controller
3   Based on SMC9234
4   High Density, Double-sided
5    Michael Zapf, September 2010
6*/
7
8/* device interface */
9#ifndef __HFDC__
10#define __HFDC__
11
12DECLARE_LEGACY_DEVICE( HFDC, ti99_hfdc );
13#endif
src/mess/machine/ti99/myarcmem.c
r0r9485
1/*
2    TI-99 Myarc memory expansion
3   
4   Note that the DSR part is still missing
5   TODO: Test this device with some emulated program!
6*/
7#include "emu.h"
8#include "peribox.h"
9#include "myarcmem.h"
10
11typedef ti99_pebcard_config ti99_myarcmem_config;
12
13typedef struct _ti99_myarcmem_state
14{
15   int    bank;   
16   UINT8    *memory;
17   
18} ti99_myarcmem_state;
19
20INLINE ti99_myarcmem_state *get_safe_token(running_device *device)
21{
22   assert(device != NULL);
23   return (ti99_myarcmem_state *)downcast<legacy_device_base *>(device)->token();
24}
25
26#define MYARCMEM_CRU_BASE1 0x1000
27#define MYARCMEM_CRU_BASE2 0x1900
28
29/*
30   CRU write (is there a read?)
31*/
32static WRITE8_DEVICE_HANDLER( myarcmem_cru_w )
33{
34   ti99_myarcmem_state *card = get_safe_token(device);
35   if (((offset & 0xff00)==MYARCMEM_CRU_BASE1)||((offset & 0xff00)==MYARCMEM_CRU_BASE2))
36   {
37      if ((offset & 0x001e)==0)
38      {
39         logerror("Activate Myarc memory expansion DSR ROM. Not available.\n");   
40      }
41      else
42      {
43         // offset / 2 = cru bit
44         // bit 1 = 1; bit 2 = 2; bit 3 = 4; bit 4 = 8
45         UINT8 mask = 1<<((offset>>1)-1);
46         if (data==0)
47            card->bank &= ~mask;
48         else
49         {
50            card->bank |= mask;
51         }
52      }     
53   }
54}
55
56/*
57    Memory read. The memory is at locations 0x2000-0x3fff and 0xa000-0xffff
58*/
59static READ8Z_DEVICE_HANDLER( myarcmem_rz )
60{
61   ti99_myarcmem_state *card = get_safe_token(device);
62   if (((offset & 0xe000)==0x2000) || ((offset & 0xe000)==0xa000) || ((offset & 0xc000)==0xc000))
63   {
64      if (offset < 0xa000)
65         *value = card->memory[offset-0x2000 + card->bank*32768];
66      else
67         *value = card->memory[offset-0x8000 + card->bank*32768];
68   }
69}
70
71/*
72   Memory write
73*/
74static WRITE8_DEVICE_HANDLER( myarcmem_w )
75{
76   ti99_myarcmem_state *card = get_safe_token(device);
77   if (((offset & 0xe000)==0x2000) || ((offset & 0xe000)==0xa000) || ((offset & 0xc000)==0xc000))
78   {
79      if (offset < 0xa000)
80         card->memory[offset-0x2000 + card->bank*32768] = data;
81      else
82         card->memory[offset-0x8000 + card->bank*32768] = data;
83   }
84}
85
86/**************************************************************************/
87
88static ti99_peb_card myarcmem_card =
89{
90   myarcmem_rz, myarcmem_w,         // memory access read/write
91   NULL, myarcmem_cru_w,         // CRU access (no read here)
92   NULL, NULL,                  // SENILA/B access (none here)
93   NULL, NULL                  // 16 bit access (none here)
94};
95
96static DEVICE_START( ti99_myarcmem )
97{
98   ti99_myarcmem_state *card = (ti99_myarcmem_state*)downcast<legacy_device_base *>(device)->token();
99   card->memory=NULL;
100}
101
102static DEVICE_STOP( ti99_myarcmem )
103{
104   ti99_myarcmem_state *card = (ti99_myarcmem_state*)downcast<legacy_device_base *>(device)->token();
105   if (card->memory) free(card->memory);
106}
107
108static DEVICE_RESET( ti99_myarcmem )
109{
110   ti99_myarcmem_state *card = (ti99_myarcmem_state*)downcast<legacy_device_base *>(device)->token();
111   /* Register the card */
112   running_device *peb = device->owner();
113   
114   if (input_port_read(device->machine, "RAM")==RAM_MYARC512)
115   {
116      int success = mount_card(peb, device, &myarcmem_card, get_pebcard_config(device)->slot);
117      if (!success) return;
118     
119      if (card->memory==NULL)
120      {
121         // Allocate 512 KiB
122         card->memory = (UINT8*)malloc(0x080000);
123      }
124      card->bank = 0;
125   }
126}
127
128static const char DEVTEMPLATE_SOURCE[] = __FILE__;
129
130#define DEVTEMPLATE_ID(p,s)             p##ti99_myarcmem##s
131#define DEVTEMPLATE_FEATURES            DT_HAS_START | DT_HAS_STOP | DT_HAS_RESET | DT_HAS_INLINE_CONFIG
132#define DEVTEMPLATE_NAME                "TI99 Myarc/Foundation Memory Expansion Card"
133#define DEVTEMPLATE_FAMILY              "Peripheral expansion"
134#include "devtempl.h"
135
136DEFINE_LEGACY_DEVICE( MYARCMEM, ti99_myarcmem );
137
src/mess/machine/ti99/mapper8.c
r0r9485
1/***************************************************************************
2   
3   TI-99/8 Address decoder and mapper
4   
5   This component implements the address decoder and mapper logic from the
6   TI-99/8 console.
7   
8   The TI-99/8 defines a "logical address map" with 64 KiB (according to the
9   16 address bits) and a "physical address map" with 16 MiB (according to the
10   24 address bits of the mapper). Note that the mapper only uses 16 outgoing
11   address lines and multiplexes the address bytes.   
12   
13   Note: The TI-99/8's internal codename was "Armadillo"
14   
15   Initial setting of mapper (as defined in the power-up routine, TI-99/4A mode)
16   
17   0   00ff0000 -> Unmapped; logical address 0000...0fff = ROM0
18   1   00ff0000 -> Unmapped; logical address 1000...1fff = ROM0
19   2   00000800 -> DRAM; 2000 = 000800, 2fff = 0017ff
20   3   00001800 -> DRAM; 3000 = 001800, 3fff = 0027ff
21   4   00ff4000 -> DSR space (internal / ioport)
22   5   00ff5000 -> DSR space (internal / ioport)
23   6   00ff6000 -> Cartridge space (6000..6fff)
24   7   00ff7000 -> Cartridge space (7000..7fff)
25   8   00ff0000 -> Unmapped; device ports (VDP) and SRAM
26   9   00ff0000 -> Unmapped; device ports (Speech, GROM)
27   A   00002800 -> DRAM; a000 = 002800, afff = 0037ff
28   B   00003800 -> DRAM; b000 = 003800, bfff = 0047ff
29   C   00004800 -> DRAM; c000 = 004800, cfff = 0057ff
30   D   00005800 -> DRAM; d000 = 005800, dfff = 0067ff
31   E   00006800 -> DRAM; e000 = 006800, efff = 0077ff
32   F   00007800 -> DRAM; f000 = 007800, ffff = 0087ff
33
34   Informations taken from
35   [1] ARMADILLO PRODUCT SPECIFICATIONS
36   [2] TI-99/8 Graphics Programming Language interpreter
37   
38   Michael Zapf, October 2010
39   
40***************************************************************************/
41
42#include "emu.h"
43#include "peribox.h"
44#include "mapper8.h"
45
46#define MAXLOGDEV 20
47#define MAXPHYSDEV 10
48
49#define SRAM_SIZE 2048
50
51#define DRAM_SIZE 65536
52
53#define MAPPER_CRU_BASE 0x2700
54
55#define MAP8_SRAM (void*)1
56#define MAP8_ROM0 (void*)2
57#define MAP8_ROM1 (void*)3
58#define MAP8_ROM1A (void*)4
59#define MAP8_DRAM (void*)5
60#define MAP8_INTS (void*)6
61
62typedef struct _log_addressed_device
63{
64   /* The device. */
65   running_device    *device;
66   
67   /* Mode. */
68   int            mode;
69
70   /* Stop. If true, stop the address decoder here and do not look for parallel devices. */
71   int            stop;
72   
73   /* Address bits involved */
74   UINT16         address_mask;
75
76   /* Value of the address bits which are involved for selecting for read. */
77   UINT16         select;
78
79   /* Value of the address bits which are involved for selecting for write. */
80   UINT16         write_select;
81   
82   /* Read access. */
83   mapper_read_function read_byte;
84   
85   /* Write access. */
86   mapper_write_function write_byte;
87
88} log_addressed_device;
89
90typedef struct _phys_addressed_device
91{
92   /* The device. */
93   running_device    *device;
94   
95   /* Stop. If true, stop the address decoder here and do not look for parallel devices. */
96   int            stop;
97
98   /* Address bits involved */
99   UINT32         address_mask;
100
101   /* Value of the address bits which are involved for selecting for read. */
102   UINT32         select;   
103
104   /* Read access. */
105   mapper_read_function read_byte;
106   
107   /* Write access. */
108   mapper_write_function write_byte;
109   
110} phys_addressed_device;
111
112typedef struct _mapper8_state
113{
114   /* All devices that are attached to the 16-bit address bus. */
115   log_addressed_device logcomp[MAXLOGDEV];
116   
117   /* All devices that are attached to the 24-bit mapped address bus. */
118   phys_addressed_device physcomp[MAXPHYSDEV];
119
120   /* The I/O port. */
121   running_device   *ioport;
122   
123   /* Select bit for the internal DSR. */
124   int   dsr_selected;
125   
126   /* 99/4A compatibility mode. Name is taken from the spec. If 1, 99/4A compatibility is active. */
127   int   CRUS;
128   
129   /* P-Code mode. Name is taken from the spec. If 0, P-Code libraries are available. */
130   // May be read as "Pascal and Text-to-speech GROM libraries ENable"
131   // Note: this is negative logic. GROMs are present only for PTGEN=0
132   int PTGEN;
133   
134   /* Address mapper registers. Each offset is selected by the first 4 bits
135      of the logical address. */
136   UINT32   pas_offset[16];
137   
138   /* SRAM area of the system. Directly connected to the address decoder. */
139   UINT8   *sram;
140   
141   /* DRAM area of the system. Connected to the mapped address bus. */
142   UINT8   *dram;
143
144   /* ROM area of the system. Directly connected to the address decoder. */
145   UINT8   *rom;
146   
147   /* Points to the next free slot in the list. */
148   int logindex, physindex;
149   
150} mapper8_state;
151
152
153INLINE mapper8_state *get_safe_token(running_device *device)
154{
155   assert(device != NULL);
156   assert(downcast<legacy_device_base *>(device)->token() != NULL);
157   return (mapper8_state *)downcast<legacy_device_base *>(device)->token();
158}
159
160static void mapper_mount_logical_device(running_device *mapperdev, running_device *busdevice, int mode, int stop, UINT16 address_mask, UINT16 address_bits, UINT16 write_sel, mapper_read_function read, mapper_write_function write)
161{
162   mapper8_state *mapper = get_safe_token(mapperdev);
163   int index = mapper->logindex++;
164   if (index < MAXLOGDEV)
165   {
166      if (mapper->logcomp[index].device == NULL)
167      {
168         mapper->logcomp[index].device = busdevice;
169         mapper->logcomp[index].mode = mode;
170         mapper->logcomp[index].stop = stop;
171         
172         mapper->logcomp[index].address_mask = address_mask;
173         mapper->logcomp[index].select = address_bits;
174         mapper->logcomp[index].write_select = write_sel;
175         mapper->logcomp[index].read_byte = read;
176         mapper->logcomp[index].write_byte = write;   
177         // printf("registering the device at logical position %d, device %lx\n", index, busdevice);
178      }
179   }
180   else
181   {
182      logerror("ti99_8_mapper: Tried to mount too many logical devices to the mapper. (Actually a bug.)\n");
183   }
184}
185
186static void mapper_mount_physical_device(running_device *mapperdev, running_device *busdevice, int stop, UINT32 address_mask, UINT32 address_bits, mapper_read_function read, mapper_write_function write)
187{
188   mapper8_state *mapper = get_safe_token(mapperdev);
189   int index = mapper->physindex++;
190   if (index < MAXPHYSDEV)
191   {
192      if (mapper->physcomp[index].device == NULL)
193      {
194         mapper->physcomp[index].device = busdevice;
195         mapper->physcomp[index].stop = stop;
196         mapper->physcomp[index].address_mask = address_mask;
197         mapper->physcomp[index].select = address_bits;
198         mapper->physcomp[index].read_byte = read;
199         mapper->physcomp[index].write_byte = write;   
200         // printf("registering the device at physical position %d, device %lx\n", index, busdevice);
201      }
202   }
203   else
204   {
205      logerror("ti99_8_mapper: Tried to mount too many phys devices to the mapper. (Actually a bug.)\n");
206   }
207}
208
209/***************************************************************************
210    DEVICE ACCESSOR FUNCTIONS
211***************************************************************************/
212
213static int check_logically_addressed_r( device_t *device, offs_t offset, UINT8 *value)
214{
215   mapper8_state *mapper = get_safe_token(device);
216   int found = FALSE;
217   // printf("ti99_8: read access %04x ... ", offset);
218   // Look for components responding to the logical address   
219   for (int i=0; i < MAXLOGDEV; i++)
220   {
221      log_addressed_device *adev = &mapper->logcomp[i];
222      if (adev->device != NULL)
223      {
224         // Check for the mode
225         if (adev->mode == mapper->CRUS || (mapper->CRUS==0 && adev->mode==1 && mapper->PTGEN==FALSE))
226         {         
227            if ((offset & adev->address_mask)==adev->select)
228            {
229               if (adev->device == MAP8_SRAM)
230               {
231                  *value = mapper->sram[offset & ~adev->address_mask];
232                  // printf("sram");
233                  found = TRUE;
234               }
235               else
236               {
237                  if (adev->device == MAP8_ROM0)
238                  {
239                     // Starts at 0000
240                     *value = mapper->rom[offset & ~adev->address_mask];
241                     // printf("rom0");
242                     found = TRUE;
243                  }
244                  else
245                  {               
246                     // device
247                     if (adev->read_byte != NULL)
248                     {
249                        // printf("device ");
250                        adev->read_byte(adev->device, offset, value);
251                        found = TRUE;
252                     }
253                  }
254               }
255            }
256         }
257      }
258      if (found && adev->stop) break;
259   }
260   return found;
261}
262
263static int check_logically_addressed_w( device_t *device, offs_t offset, UINT8 data)
264{
265   mapper8_state *mapper = get_safe_token(device);
266   int found = FALSE;
267
268   // printf("ti99_8: write access %04x ... ", offset);
269   for (int i=0; i < MAXLOGDEV; i++)
270   {
271      log_addressed_device *adev = &mapper->logcomp[i];
272      if (adev->device != NULL)
273      {
274         // Check for the mode
275         if (adev->mode == mapper->CRUS ||  (mapper->CRUS==0 && adev->mode==1 && mapper->PTGEN==FALSE))
276         {         
277            if ((offset & adev->address_mask)==(adev->select | adev->write_select))
278            {
279               if (adev->device == MAP8_SRAM)
280               {
281                  mapper->sram[offset & ~adev->address_mask] = data;
282                  // printf("sram");
283                  found = TRUE;
284               }
285               else
286               {
287                  if (adev->device == MAP8_ROM0)
288                  {
289                     // printf("rom0 (ignored)");
290                     found = TRUE;
291                  }
292                  else
293                  {                     
294                     if (adev->write_byte != NULL)
295                     {
296                        // printf("device ");
297                        adev->write_byte(adev->device, offset, data);
298                        found = TRUE;
299                     }
300                  }
301               }
302            }
303         }
304      }
305      if (found && adev->stop) break;
306   }
307   return found;
308}
309
310/*
311    Read access.
312*/
313READ8_DEVICE_HANDLER( ti99_mapper8_r )
314{
315   UINT8 value = 0;
316   mapper8_state *mapper = get_safe_token(device);
317   int found = FALSE;
318
319   if (mapper->sram==NULL)  // not initialized yet
320      return 0;
321   
322   found = check_logically_addressed_r(device, offset, &value);
323
324   if (!found)
325   {
326      // printf(" not logical ...");
327      // In that case, the address decoder could not find a suitable device.
328      // This means the logical address is transformed by the mapper.
329      UINT32   pas_address = mapper->pas_offset[(offset & 0xf000)>>12] + (offset & 0xfff);
330      // printf("%08x ", pas_address);
331     
332      // So now let's do the same as above with physical addresses
333      for (int i=0; i < MAXPHYSDEV; i++)
334      {
335         phys_addressed_device *adev = &mapper->physcomp[i];
336         if (adev->device != NULL)
337         {
338            if ((pas_address & adev->address_mask)==adev->select)
339            {
340               if (adev->device == MAP8_DRAM)
341               {
342                  value = mapper->dram[pas_address & ~adev->address_mask];
343                  found = TRUE;
344                  // printf("dram");
345               }
346               else
347               {
348                  if (adev->device == MAP8_ROM1)
349                  {
350                     // Starts at 2000 in the image, 8K
351                     value = mapper->rom[0x2000 + (pas_address & 0x1fff)];
352                     found = TRUE;
353                     // printf("rom1");
354                  }
355                  else
356                  {
357                     if (adev->device == MAP8_ROM1A)
358                     {
359                        // Starts at 6000 in the image, 8K
360                        value = mapper->rom[0x6000 + (pas_address & 0x1fff)];
361                        found = TRUE;
362                        // printf("rom1a");
363                     }
364                     else
365                     {                     
366                        if (adev->device == MAP8_INTS)
367                        {
368                           // Interrupt sense
369                           // printf("ti99_8: ILSENSE not implemented.\n");
370                           // printf("sense");
371                           found = TRUE;
372                        }
373                        else
374                        {
375                           // only one option left: cartridge port (aka grom port)
376                           if (adev->read_byte != NULL)
377                           {
378                              // printf("pdevice ");
379                              adev->read_byte(adev->device, pas_address, &value);
380                              found = TRUE;
381                           }
382                        }
383                     }
384                  }
385               }
386            }
387         }
388         if (found && adev->stop) break;
389      }
390         
391      if (!found)
392      {
393         // Still not found? Then we route the physical address to the I/O port
394         // which has the peribox attached
395         // printf("not mapped ... ioport");
396         if (mapper->ioport!=NULL)
397            ti99_peb_data_rz(mapper->ioport, pas_address, &value);
398         // printf("ti99_8: io read %04x = %02x\n", offset, value);
399      }     
400   }
401   // printf(" %02x\n", value);
402
403   return value;   
404}
405
406/*
407    Write access.
408*/
409WRITE8_DEVICE_HANDLER( ti99_mapper8_w )
410{
411   mapper8_state *mapper = get_safe_token(device);
412   int found = FALSE;
413   if (mapper->sram==NULL)
414      return;
415//   // printf("ti99_8: write %04x = %02x\n", offset, data);
416   
417   // Look for components responding to the logical address   
418   found = check_logically_addressed_w(device, offset, data);
419   
420   if (!found)
421   {
422      // printf(" not logical ...");
423      // In that case, the address decoder could not find a suitable device.
424      // This means the logical address is transformed by the mapper.
425      UINT32 pas_address = mapper->pas_offset[(offset & 0xf000)>>12] + (offset & 0xfff);
426
427      // So now let's do the same as above with physical addresses
428      for (int i=0; i < MAXPHYSDEV; i++)
429      {
430         phys_addressed_device *adev = &mapper->physcomp[i];
431         if (adev->device != NULL)
432         {
433            if ((pas_address & adev->address_mask)==adev->select)
434            {
435               if (adev->device == MAP8_DRAM)
436               {
437                  mapper->dram[pas_address & ~adev->address_mask] = data;
438                  // printf("dram base %08x", pas_address);
439                  found = TRUE;
440               }
441               else
442               {
443                  if (adev->device == MAP8_ROM1 || adev->device == MAP8_ROM1A)
444                  {
445                     // printf("rom1 (ignored)");
446                     found = TRUE;
447                  }
448                  else
449                  {                     
450                     if (adev->device == MAP8_INTS)
451                     {
452                        // Interrupt sense
453                        // printf("ilsense (ignored)");
454                        found = TRUE;
455                     }
456                     else
457                     {
458                        // only one option left: cartridge port (aka grom port)
459                        if (adev->write_byte != NULL)
460                        {
461                           // printf("pdevice ");
462                           adev->write_byte(adev->device, pas_address, data);
463                           found = TRUE;
464                        }
465                     }
466                  }
467               }
468            }
469         }
470         if (found && adev->stop) break;
471      }
472         
473      if (!found)
474      {
475         // Still not found? Then we route the physical address to the I/O port
476         // which has the peribox attached
477         // printf("not mapped ... ioport");
478         if (mapper->ioport!=NULL)
479            ti99_peb_data_w(mapper->ioport, pas_address, data);
480         // printf("ti99_8: io write %04x = %02x\n", offset, data);
481      }
482   }
483   // printf(" %02x\n", data);
484}
485
486/*
487   Reconfigure mapper. Writing to this address copies the values in the
488   SRAM into the mapper and vice versa.
489   Format:
490   0000 bbbl; bbb=bank, l=load
491*/
492WRITE8_DEVICE_HANDLER( ti99_mapreg_w )
493{
494   mapper8_state *mapper = get_safe_token(device);
495   
496   if ((data & 0xf0)==0)
497   {
498      int bankindx = (data & 0x0e)>>1;
499      if (data & 1)
500      {
501         // printf("mapper8: load from sram bank %02x", bankindx);
502         // Load from SRAM
503         for (int i=0; i < 16; i++)
504         {
505            int ptr = (bankindx << 6);
506            mapper->pas_offset[i] =
507               (mapper->sram[i*4 + ptr] << 24)
508               + (mapper->sram[i*4 + ptr+1] << 16)
509               + (mapper->sram[i*4 + ptr+2] << 8)
510               + (mapper->sram[i*4 + ptr+3]);
511//            // printf(" values (%04x) %02x %02x %02x %02x, ", i*4+ptr, mapper->sram[i*4 + ptr], mapper->sram[i*4 + ptr+1], mapper->sram[i*4 + ptr+2], mapper->sram[i*4 + ptr+3]);
512         }
513      }
514      else
515      {
516         // Store in SRAM
517         // printf("mapper8: copy to sram bank %02x", bankindx);
518         for (int i=0; i < 16; i++)
519         {
520            int ptr = (bankindx << 6);
521            mapper->sram[i*4 + ptr]    =  (mapper->pas_offset[i] >> 24)& 0xff;
522            mapper->sram[i*4 + ptr +1] =  (mapper->pas_offset[i] >> 16)& 0xff;
523            mapper->sram[i*4 + ptr +2] =  (mapper->pas_offset[i] >> 8)& 0xff;
524            mapper->sram[i*4 + ptr +3] =  (mapper->pas_offset[i])& 0xff;
525         }
526      }
527   }
528}
529
530/************************************************************************/
531
532/*
533   Internal DSR
534*/
535READ8Z_DEVICE_HANDLER( ti998dsr_rz )
536{
537   mapper8_state *mapper = get_safe_token(device);
538   if (mapper->dsr_selected)
539   {
540      //  Starts at 0x4000 in the image
541      *value = mapper->rom[0x4000 + (offset & 0x1fff)];
542   }
543   else
544   {
545      if (mapper->ioport!=NULL)
546         ti99_peb_data_rz(mapper->ioport, 0x4000 + (offset & 0x1fff), value);
547//      printf("ti99_8: io1 read %04x = %02x\n", offset, *value);
548   }
549}
550
551
552/*
553   CRU handling. We handle the internal device at CRU address 0x2700 via
554   this mapper component.
555*/
556WRITE8_DEVICE_HANDLER( mapper8c_w )
557{
558   mapper8_state *mapper = get_safe_token(device);
559   if ((offset & 0xff00)==MAPPER_CRU_BASE)
560   {
561      int addr = offset & 0x00ff;
562      if (addr==0)
563         mapper->dsr_selected = data;
564      if (addr==2)
565      {
566         // TODO
567         // printf("ti-99/8: Hardware reset via CRU\n");
568      }
569   }
570}
571
572WRITE8_DEVICE_HANDLER( mapper8_CRUS_w )
573{
574   mapper8_state *mapper = get_safe_token(device);
575   mapper->CRUS = data;
576   // printf("ti99_8: CRUS = %02x\n", data);
577}
578
579WRITE8_DEVICE_HANDLER( mapper8_PTGEN_w )
580{
581   mapper8_state *mapper = get_safe_token(device);
582   mapper->PTGEN = data;
583   // printf("ti99_8: PTGEN = %02x\n", data);
584}
585
586/***************************************************************************
587    DEVICE LIFECYCLE FUNCTIONS
588***************************************************************************/
589
590static DEVICE_START( mapper8 )
591{
592//   // printf("Starting mapper\n");
593   mapper8_state *mapper = get_safe_token(device);
594   mapper->sram = (UINT8*)malloc(SRAM_SIZE);
595   mapper->dram = (UINT8*)malloc(DRAM_SIZE);
596   mapper->rom = memory_region(device->machine, "maincpu");
597
598   int i = 0;
599   int done=FALSE;
600   
601   for (int index = 0; index < MAXLOGDEV; index++)
602   {
603      mapper->logcomp[index].device = NULL;     
604   }
605
606   for (int index = 0; index < MAXPHYSDEV; index++)
607   {
608      mapper->physcomp[index].device = NULL;     
609   }
610
611   // Need to connect the callbacks
612   mapper->ioport = device->siblingdevice("peribox");
613   assert(mapper->ioport != NULL);
614   
615   mapper8_dev_config *cons = (mapper8_dev_config*)device->baseconfig().static_config();
616
617   mapper->logindex = 0;
618   mapper->physindex = 0;
619   
620   const char *list[6] = { SRAMNAME, ROM0NAME, ROM1NAME, ROM1ANAME, DRAMNAME, INTSNAME };
621   while (!done)
622   {
623      void *dev = NULL;
624      if (cons[i].name==NULL)
625         done = TRUE;
626      else
627      {
628         for (int j=1; (j < 7) && (dev == NULL); j++)
629         {
630            // printf("%s, %s\n", cons[i].name, list[j-1]);
631            if (strcmp(cons[i].name, list[j-1])==0)
632               dev = (void *)j;
633         }
634         if (dev==NULL)
635            dev = device->machine->device(cons[i].name);
636         
637         if (dev!=NULL)
638         {
639            if (cons[i].mode != 3)
640            {
641               mapper_mount_logical_device(device, (running_device*)dev, cons[i].mode, cons[i].stop, (UINT16)cons[i].address_mask, (UINT16)cons[i].select_pattern, (UINT16)cons[i].write_select, cons[i].read, cons[i].write);               
642            }
643            else
644            {
645               mapper_mount_physical_device(device, (running_device*)dev, cons[i].stop, cons[i].address_mask, cons[i].select_pattern, cons[i].read, cons[i].write);               
646            }
647         }
648         else
649            logerror("mapper8: Device %s not found.\n", cons[i].name);
650         i++;
651      }
652   }
653   
654   mapper->dsr_selected = FALSE;
655   mapper->CRUS = TRUE;
656   mapper->PTGEN = TRUE;
657}
658
659static DEVICE_STOP( mapper8 )
660{
661   // printf("Stopping mapper\n");
662   mapper8_state *mapper = get_safe_token(device);   
663   free(mapper->sram);
664   free(mapper->dram);
665}
666
667static DEVICE_RESET( mapper8 )
668{
669   // printf("Resetting mapper\n");
670   mapper8_state *mapper = get_safe_token(device);
671
672   mapper->dsr_selected = FALSE;
673   mapper->CRUS = TRUE;
674   mapper->PTGEN = TRUE;
675}
676
677static const char DEVTEMPLATE_SOURCE[] = __FILE__;
678
679#define DEVTEMPLATE_ID(p,s)             p##mapper8##s
680#define DEVTEMPLATE_FEATURES            DT_HAS_START | DT_HAS_STOP | DT_HAS_RESET
681#define DEVTEMPLATE_NAME                "TI-99/8 Address Decoder and Mapper"
682#define DEVTEMPLATE_FAMILY              "Internal devices"
683#include "devtempl.h"
684
685DEFINE_LEGACY_DEVICE( MAPPER8, mapper8 );
src/mess/machine/ti99/ti_rs232.h
r0r9485
1/*
2    TI-99 Serial and parallel interface card
3    Michael Zapf, September 2010
4*/
5
6#ifndef __TIRS232__
7#define __TIRS232__
8
9DECLARE_LEGACY_DEVICE( TIRS232, ti_rs232 );
10#endif
src/mess/machine/ti99/peribox.h
r0r9485
1#ifndef __PBOX__
2#define __PBOX__
3/*
4    header file for ti99_peb
5*/
6#include "p_code.h"
7#include "ti32kmem.h"
8#include "samsmem.h"
9#include "myarcmem.h"
10#include "ti99defs.h"
11 
12/*
13    inta: callback called when the state of INTA changes (may be NULL)
14    intb: callback called when the state of INTB changes (may be NULL)
15    ready: callback called when the state of INTB changes (may be NULL)
16*/
17 
18typedef struct _ti99_peb_config
19{
20   write_line_device_func inta;
21   write_line_device_func intb;
22   write_line_device_func ready;
23} ti99_peb_config;
24 
25/*
26   Callback interface. The callback functions are in the console and are
27   accessed from the PEB.
28*/
29 
30#define MAXSLOTS 16
31 
32/*
33   This interface is used by the PEB to communicate with the expansion cards.
34   It actually forwards the accesses from the main system.
35*/
36typedef struct _ti99_peb_card_interface
37{
38   void          (*card_read_data)(running_device *card, offs_t offset, UINT8 *value); 
39   void         (*card_write_data)(running_device *card, offs_t offset, UINT8 value);
40 
41   void          (*card_read_cru)(running_device *card, offs_t offset, UINT8 *value); 
42   void         (*card_write_cru)(running_device *card, offs_t offset, UINT8 value);
43 
44   void         (*senila)(running_device *card, int value);
45   void          (*senilb)(running_device *card, int value);
46 
47   /* For SGCPU only ("expansion bus") */
48   void         (*card_read_data16)(running_device *card, offs_t offset, UINT16 *value);
49   void         (*card_write_data16)(running_device *card, offs_t offset, UINT16 value);   
50   
51} ti99_peb_card;
52 
53/*
54   Called from the expansion cards. These are the callbacks from the cards to 
55   the PEB (which forwards them to the main system).
56*/   
57typedef struct _peb_callback_if
58{
59   devcb_write_line    inta;
60   devcb_write_line    intb;
61   devcb_write_line    ready;
62   
63} peb_callback_if;
64 
65/*
66   Used to call back the main system. Also imported by the cards. 
67   This structure holds the resolved callbacks within the PEB and the cards.
68*/
69typedef struct _peb_connect
70{
71   devcb_resolved_write_line inta;
72   devcb_resolved_write_line intb;
73   devcb_resolved_write_line ready;
74 
75} ti99_peb_connect;
76 
77/*
78   Accessor functions from the console. Note that we make use of the enhanced
79   read handler.
80*/
81READ8Z_DEVICE_HANDLER( ti99_peb_data_rz );
82WRITE8_DEVICE_HANDLER( ti99_peb_data_w );
83 
84READ8Z_DEVICE_HANDLER( ti99_peb_cru_rz );
85WRITE8_DEVICE_HANDLER( ti99_peb_cru_w );
86 
87WRITE_LINE_DEVICE_HANDLER( ti99_peb_senila );
88WRITE_LINE_DEVICE_HANDLER( ti99_peb_senilb );
89 
90 
91/*
92   For SGCPU only. Actually the SGCPU uses an external cable to add the 
93   8 data lines that are not included in the PEB
94*/
95READ16Z_DEVICE_HANDLER( ti99_peb_data16_rz );
96WRITE16_DEVICE_HANDLER( ti99_peb_data16_w );
97 
98/*
99   Value passed to the cards
100*/
101typedef struct _ti99_pebcard_config
102{
103   int slot;
104} ti99_pebcard_config;
105 
106INLINE const ti99_pebcard_config *get_pebcard_config(running_device *device)
107{
108   assert(device != NULL);
109   return (const ti99_pebcard_config *) downcast<const legacy_device_config_base &>(device->baseconfig()).inline_config();
110}
111 
112/*
113   Management functions
114*/
115int mount_card(running_device *device, running_device *cardptr, ti99_peb_card *card, int slotindex);
116void unmount_card(running_device *device, int slotindex);
117 
118 
119/* device interface */
120DECLARE_LEGACY_DEVICE( PBOX4, ti99_peb );
121DECLARE_LEGACY_DEVICE( PBOX4A, ti994a_peb );
122DECLARE_LEGACY_DEVICE( PBOXEV, ti99ev_peb );
123DECLARE_LEGACY_DEVICE( PBOX8, ti998_peb );
124DECLARE_LEGACY_DEVICE( PBOXSG, ti99sg_peb );
125DECLARE_LEGACY_DEVICE( PBOXGEN, geneve_peb );
126 
127#define MDRV_PBOX4_ADD(_tag, _inta, _intb, _ready)         \
128   MDRV_DEVICE_ADD(_tag, PBOX4, 0)                     \
129   MDRV_DEVICE_CONFIG_DATAPTR(ti99_peb_config, inta, _inta)      \
130   MDRV_DEVICE_CONFIG_DATAPTR(ti99_peb_config, intb, _intb)      \
131   MDRV_DEVICE_CONFIG_DATAPTR(ti99_peb_config, ready, _ready)   
132 
133#define MDRV_PBOX4A_ADD(_tag, _inta, _intb, _ready)         \
134   MDRV_DEVICE_ADD(_tag, PBOX4A, 0)                     \
135   MDRV_DEVICE_CONFIG_DATAPTR(ti99_peb_config, inta, _inta)      \
136   MDRV_DEVICE_CONFIG_DATAPTR(ti99_peb_config, intb, _intb)      \
137   MDRV_DEVICE_CONFIG_DATAPTR(ti99_peb_config, ready, _ready)   
138 
139#define MDRV_PBOXEV_ADD(_tag, _inta, _intb, _ready)         \
140   MDRV_DEVICE_ADD(_tag, PBOXEV, 0)                     \
141   MDRV_DEVICE_CONFIG_DATAPTR(ti99_peb_config, inta, _inta)      \
142   MDRV_DEVICE_CONFIG_DATAPTR(ti99_peb_config, intb, _intb)      \
143   MDRV_DEVICE_CONFIG_DATAPTR(ti99_peb_config, ready, _ready)   
144   
145#define MDRV_PBOX8_ADD(_tag, _inta, _intb, _ready)         \
146   MDRV_DEVICE_ADD(_tag, PBOX8, 0)                     \
147   MDRV_DEVICE_CONFIG_DATAPTR(ti99_peb_config, inta, _inta)      \
148   MDRV_DEVICE_CONFIG_DATAPTR(ti99_peb_config, intb, _intb)      \
149   MDRV_DEVICE_CONFIG_DATAPTR(ti99_peb_config, ready, _ready)   
150 
151#define MDRV_PBOXSG_ADD(_tag, _inta, _intb, _ready)         \
152   MDRV_DEVICE_ADD(_tag, PBOXSG, 0)                     \
153   MDRV_DEVICE_CONFIG_DATAPTR(ti99_peb_config, inta, _inta)      \
154   MDRV_DEVICE_CONFIG_DATAPTR(ti99_peb_config, intb, _intb)      \
155   MDRV_DEVICE_CONFIG_DATAPTR(ti99_peb_config, ready, _ready)   
156 
157#define MDRV_PBOXGEN_ADD(_tag, _inta, _intb, _ready)         \
158   MDRV_DEVICE_ADD(_tag, PBOXGEN, 0)                     \
159   MDRV_DEVICE_CONFIG_DATAPTR(ti99_peb_config, inta, _inta)      \
160   MDRV_DEVICE_CONFIG_DATAPTR(ti99_peb_config, intb, _intb)      \
161   MDRV_DEVICE_CONFIG_DATAPTR(ti99_peb_config, ready, _ready)   
162   
163#endif /* __PBOX__ */
src/mess/machine/ti99/mecmouse.c
r0r9485
1/*
2    TI-99 Mechatronic mouse with adapter
3    Michael Zapf, October 2010
4   
5    The Mechatronic mouse is connected to the joystick port and occupies
6    both joystick select lines and the switch lines. From these five
7    lines, left/right/down are used for the motion (i.e. 3 motion steps
8    for positive and four for negative motion and one for rest),
9    the fire line is used for the secondary mouse button, and the up
10    line is used for the primary button.
11    The mouse motion is delivered by the same lines for both directions;
12    this requires swapping the axes. According to the source code of
13    the accompanying mouse driver, the readout of the current axis is
14    done by selecting joystick 1, then joystick 2. The axis swapping is
15    achieved by selecting stick 1 again. When selecting stick 2, the
16    second axis is seen on the input lines.
17    Interrupting this sequence will lead to swapped axes. This is
18    prevented by resetting the toggle when the mouse is deselected
19    (neither 1 nor 2 are selected).
20
21    The joystick lines are selected as follows:
22    TI-99/4:  Stick 1: P4=1, P3=0, P2=1 (5)
23    Stick 2: P4=1, P3=1, P2=0 (6)
24
25    TI-99/4A: Stick 1: P4=1, P3=1, P2=0 (6)
26    Stick 2: P4=1, P3=1, P2=1 (7)
27
28    TI-99/8:  Stick 1: P3=1, P2=1, P1=1, P0=0 (14)
29    Stick 2: P3=1, P2=1, P1=1, P0=1 (15)
30
31    Geneve: n/a, has own mouse handling via v9938
32
33    As we can only deliver at max 3 steps positive and 4 steps negative,
34    we split the delta so that subsequent queries add up to the actual
35    delta. That is, one delta of +10 yields a 3+3+3+1.
36
37    mecmouse_x holds the current delta to be counted down for x
38    (y accordingly)
39
40    mecmouse_x_buf is the current step count reported to CRU
41
42    Michael Zapf, 2008-01-22
43   
44    2010-10-22 Rewriten as device
45*/
46
47#include "emu.h"
48#include "mecmouse.h"
49
50typedef struct _ti99_mecmouse_state
51{
52   int select;
53   int read_y;
54   int x;
55   int y;
56   int x_buf;
57   int y_buf;
58   int last_mx;
59   int last_my;
60   
61} ti99_mecmouse_state;
62
63INLINE ti99_mecmouse_state *get_safe_token(running_device *device)
64{
65   assert(device != NULL);
66   return (ti99_mecmouse_state *)downcast<legacy_device_base *>(device)->token();
67}
68
69void mecmouse_select(running_device *device, int selnow, int stick1, int stick2)
70{
71   ti99_mecmouse_state *mouse = get_safe_token(device);
72
73   if (selnow == stick2) {
74      if (mouse->select == stick1) {
75         if (!mouse->read_y)
76         {
77            /* Sample x motion. */
78            if (mouse->x < -4)
79               mouse->x_buf = -4;
80            else if (mouse->x > 3)
81               mouse->x_buf = 3;
82            else
83               mouse->x_buf = mouse->x;
84            mouse->x -= mouse->x_buf;
85            mouse->x_buf = (mouse->x_buf-1) & 7;
86         }
87         else
88         {
89            /* Sample y motion. */
90            if (mouse->y < -4)
91               mouse->y_buf = -4;
92            else if (mouse->y > 3)
93               mouse->y_buf = 3;
94            else
95               mouse->y_buf = mouse->y;
96            mouse->y -= mouse->y_buf;
97            mouse->y_buf = (mouse->y_buf-1) & 7;
98         }
99      }
100      mouse->select = selnow;
101   }
102   else if (selnow == stick1)
103   {
104      if (mouse->select == stick2)
105      {
106         /* Swap the axes. */
107         mouse->read_y = !mouse->read_y;
108      }
109      mouse->select = selnow;
110   }
111   else
112   {
113      /* Reset the axis toggle when the mouse is deselected */
114      mouse->read_y = 0;
115   }
116}
117
118void mecmouse_poll(running_device *device)
119{
120   ti99_mecmouse_state *mouse = get_safe_token(device);
121
122   int new_mx, new_my;
123   int delta_x, delta_y;
124
125   new_mx = input_port_read(device->machine, "MOUSEX");
126   new_my = input_port_read(device->machine, "MOUSEY");
127
128   /* compute x delta */
129   delta_x = new_mx - mouse->last_mx;
130
131   /* check for wrap */
132   if (delta_x > 0x80)
133      delta_x = -0x100+delta_x;
134   if  (delta_x < -0x80)
135      delta_x = 0x100+delta_x;
136
137   /* Prevent unplausible values at startup. */
138   if (delta_x > 100 || delta_x<-100) delta_x = 0;
139
140   mouse->last_mx = new_mx;
141
142   /* compute y delta */
143   delta_y = new_my - mouse->last_my;
144
145   /* check for wrap */
146   if (delta_y > 0x80)
147      delta_y = -0x100+delta_y;
148   if  (delta_y < -0x80)
149      delta_y = 0x100+delta_y;
150
151   if (delta_y > 100 || delta_y<-100) delta_y = 0;
152
153   mouse->last_my = new_my;
154
155   /* update state */
156   mouse->x += delta_x;
157   mouse->y += delta_y;
158}
159
160int mecmouse_get_values(running_device *device)
161{
162   ti99_mecmouse_state *mouse = get_safe_token(device);
163   int answer;
164   int buttons = input_port_read(device->machine, "MOUSE0") & 3;
165   answer = (mouse->read_y ? mouse->y_buf : mouse->x_buf) << 4;
166
167   if ((buttons & 1)==0)
168      /* action button */
169      answer |= 0x08;
170   if ((buttons & 2)==0)
171      /* home button */
172      answer |= 0x80;
173   return answer;
174}
175
176/*
177   Variation for TI-99/8
178*/
179int mecmouse_get_values8(running_device *device, int mode)
180{
181   ti99_mecmouse_state *mouse = get_safe_token(device);
182   int answer;
183   int buttons = input_port_read(device->machine, "MOUSE0") & 3;
184
185   if (mode == 0)
186   {
187      answer = ((mouse->read_y ? mouse->y_buf : mouse->x_buf) << 7) & 0x80;
188      if ((buttons & 1)==0)
189         /* action button */
190         answer |= 0x40;
191   }
192   else
193   {
194      answer = ((mouse->read_y ? mouse->y_buf : mouse->x_buf) << 1) & 0x03;
195      if ((buttons & 2)==0)
196         /* home button */
197         answer |= 0x04;
198   }     
199   return answer;
200}
201
202/**************************************************************************/
203
204static DEVICE_START( ti99_mecmouse)
205{
206}
207
208static DEVICE_RESET( ti99_mecmouse )
209{
210   ti99_mecmouse_state *mouse = get_safe_token(device);
211   mouse->select = 0;
212   mouse->read_y = 0;
213   mouse->x = 0;
214   mouse->y = 0;
215   mouse->last_mx = 0;
216   mouse->last_my = 0;
217}
218
219static const char DEVTEMPLATE_SOURCE[] = __FILE__;
220
221#define DEVTEMPLATE_ID(p,s)             p##ti99_mecmouse##s
222#define DEVTEMPLATE_FEATURES            DT_HAS_START | DT_HAS_RESET
223#define DEVTEMPLATE_NAME                "Mechatronics mouse"
224#define DEVTEMPLATE_FAMILY              "Human-computer interface"
225#include "devtempl.h"
226
227DEFINE_LEGACY_DEVICE( MECMOUSE, ti99_mecmouse );
228
src/mess/machine/ti99/myarcmem.h
r0r9485
1/*
2    TI-99 Myarc and Foundation memory expansion
3    Michael Zapf, September 2010
4*/
5
6#ifndef __MYARCMEM__
7#define __MYARCMEM__
8
9DECLARE_LEGACY_DEVICE( MYARCMEM, ti99_myarcmem );
10#endif
src/mess/machine/ti99/bwg.c
r0r9485
1/*
2    SNUG BwG Disk Controller
3    Based on WD1773
4    Double Density, Double-sided
5
6    * Supports Double Density.
7    * As this card includes its own RAM, it does not need to allocate a portion
8      of VDP RAM to store I/O buffers.
9    * Includes a MM58274C RTC.
10    * Support an additional floppy drive, for a total of 4 floppies.
11
12    Reference:
13    * BwG Disketten-Controller: Beschreibung der DSR
14        <http://home.t-online.de/home/harald.glaab/snug/bwg.pdf>
15
16    Michael Zapf, September 2010
17   
18   FIXME: IO error 50, CALLs ok
19*/
20
21#include "emu.h"
22#include "peribox.h"
23#include "bwg.h"
24#include "machine/wd17xx.h"
25#include "formats/ti99_dsk.h"
26#include "devices/flopdrv.h"
27#include "machine/mm58274c.h"
28
29#define CRU_BASE 0x1100
30
31#define bwg_IRQ 1
32#define bwg_DRQ 2
33
34#define bwg_region "bwg_region"
35
36typedef ti99_pebcard_config ti99_bwg_config;
37
38typedef struct _ti99_bwg_state
39{
40   /* Holds the status of the DRQ and IRQ lines. */
41   int               DRQ_IRQ_status;
42   
43   /* When TRUE, card is accessible. Indicated by a LED. */
44   int               selected;
45
46   /* When TRUE, keeps DVENA high. */
47   int               strobe_motor;
48
49   /* Signal DVENA. When TRUE, makes some drive turning. */
50   int               DVENA;
51
52   /* When TRUE the CPU is halted while DRQ/IRQ are true. */
53   int               hold;
54   
55   /* Indicates which drive has been selected. Values are 0, 1, 2, and 4. */
56   // 000 = no drive
57   // 001 = drive 1
58   // 010 = drive 2
59   // 100 = drive 3
60   int               DSEL;
61
62   /* Signal SIDSEL. 0 or 1, indicates the selected head. */
63   int               SIDE;
64
65   /* ROM and RAM offset. */
66   int               rom_offset, ram_offset;
67   
68   /* Indicates whether the clock is mapped into the address space. */
69   int               rtc_enabled;
70   
71   /* count 4.23s from rising edge of motor_on */
72   emu_timer          *motor_on_timer;
73   
74   /* Link to the FDC1771 controller on the board. */
75   running_device       *controller;
76
77   /* Link to the real-time clock on the board. */
78   running_device       *clock;
79
80   /* DSR ROM */
81   UINT8            *rom;
82
83   /* On-board RAM */
84   UINT8            *ram;
85
86   /* DIP swiches */
87   UINT8            dip1, dip2, dip34;
88   
89   /* Callback lines to the main system. */
90   ti99_peb_connect   lines;
91   
92} ti99_bwg_state;
93
94INLINE ti99_bwg_state *get_safe_token(running_device *device)
95{
96   assert(device != NULL);
97   return (ti99_bwg_state *)downcast<legacy_device_base *>(device)->token();
98}
99
100/*
101    Call this when the state of DSKhold or DRQ/IRQ or DVENA change
102
103    Emulation is faulty because the CPU is actually stopped in the midst of
104    instruction, at the end of the memory access
105   
106   TODO: This has to be replaced by the proper READY handling that is already
107   prepared here. (Requires READY handling by the CPU.)
108*/
109static void bwg_handle_hold(running_device *device)
110{
111   ti99_bwg_state *card = get_safe_token(device);
112   line_state state;
113   
114   if (card->hold && (!card->DRQ_IRQ_status) && card->DVENA)
115      state = ASSERT_LINE;
116   else
117      state = CLEAR_LINE;
118   
119   // TODO: use READY
120   cputag_set_input_line(device->machine, "maincpu", INPUT_LINE_HALT, state);
121}
122
123/*
124    Resets the drive geometry. This is required because the heuristic of
125    the default implementation sets the drive geometry to the geometry
126    of the medium.
127*/
128static void set_geometry(running_device *drive, floppy_type_t type)
129{
130   if (drive!=NULL)
131      floppy_drive_set_geometry(drive, type);
132   else
133      logerror("ti99/BwG: Drive not found\n");
134}
135
136/* Those defines are required because the WD17xx DEVICE_START implementation
137assumes that the floppy devices are either at root level or at the parent
138level. Our floppy devices, however, are at the grandparent level as seen from
139the controller. */
140
141#define PFLOPPY_0 "peribox:floppy0"
142#define PFLOPPY_1 "peribox:floppy1"
143#define PFLOPPY_2 "peribox:floppy2"
144#define PFLOPPY_3 "peribox:floppy3"
145
146static void set_all_geometries(running_device *device, floppy_type_t type)
147{
148   set_geometry(device->machine->device(PFLOPPY_0), type);
149   set_geometry(device->machine->device(PFLOPPY_1), type);
150   set_geometry(device->machine->device(PFLOPPY_2), type);
151   set_geometry(device->machine->device(PFLOPPY_3), type);
152}
153
154
155/*************************************************************************/
156
157/*
158    Callback, called from the controller chip whenever DRQ/IRQ state change
159*/
160static WRITE_LINE_DEVICE_HANDLER( ti_bwg_intrq_w )
161{
162   running_device *carddev = device->owner();
163   ti99_bwg_state *card = get_safe_token(carddev);
164
165   if (state)
166   {
167      card->DRQ_IRQ_status |= bwg_IRQ;
168      // Note that INTB is actually not used in the TI-99 family. But the
169      // controller asserts the line nevertheless
170      devcb_call_write_line(&card->lines.intb, TRUE);
171   }
172   else
173   {
174      card->DRQ_IRQ_status &= ~bwg_IRQ;
175      devcb_call_write_line(&card->lines.intb, FALSE);
176   }
177   bwg_handle_hold(carddev);
178}
179
180static WRITE_LINE_DEVICE_HANDLER( ti_bwg_drq_w )
181{
182   running_device *carddev = device->owner();
183   ti99_bwg_state *card = get_safe_token(carddev);
184
185   if (state)
186      card->DRQ_IRQ_status |= bwg_DRQ;
187   else
188      card->DRQ_IRQ_status &= ~bwg_DRQ;
189
190   bwg_handle_hold(carddev);
191}
192
193/*
194    callback called at the end of DVENA pulse
195*/
196static TIMER_CALLBACK(motor_on_timer_callback)
197{
198   running_device *device = (running_device *)ptr;
199   ti99_bwg_state *card = get_safe_token(device);
200   card->DVENA = 0;
201   bwg_handle_hold(device);
202}
203
204#if 0
205static WRITE_LINE_DEVICE_HANDLER( ti99_bwg_ready )
206{
207   // Caution: The device pointer passed to this function is the calling
208   // device. That is, if we want *this* device, we need to take the owner.
209   ti99_bwg_state *card = (ti99_bwg_state*)downcast<legacy_device_base *>(device->owner())->token();
210   devcb_call_write_line( &card->lines.ready, state );
211}
212#endif
213
214/*
215    CRU read handler. *=inverted.
216    bit 0: DSK4 connected*
217   bit 1: DSK1 connected*
218   bit 2: DSK2 connected*
219   bit 3: DSK3 connected*
220   bit 4: Dip 1
221   bit 5: Dip 2
222   bit 6: Dip 3
223   bit 7: Dip 4
224*/
225static READ8Z_DEVICE_HANDLER( cru_r )
226{
227   ti99_bwg_state *card = get_safe_token(device);
228   UINT8 reply = 0;
229   
230   if ((offset & 0xff00)==CRU_BASE)
231   {
232      if ((offset & 0x00ff)==0)
233      {
234         // Assume that we have 4 drives connected
235         // If we want to do that properly, we need to check the actually
236         // available drives (not the images!). But why should we connect less?
237         reply = 0x00;
238         
239         // DIP switches. Note that a closed switch means 0
240         // xx01 1111   11 = nur dsk1; 10 = 1+2, 01=1/2/3, 00=1-4
241         if (card->dip1) reply |= 0x10;
242         if (card->dip2) reply |= 0x20;
243         reply |= (card->dip34 << 6);
244         *value = ~reply;
245      }
246      else
247         *value = 0;
248   }
249}
250
251static WRITE8_DEVICE_HANDLER( cru_w )
252{
253   ti99_bwg_state *card = get_safe_token(device);
254   int drive, drivebit;
255
256   if ((offset & 0xff00)==CRU_BASE)
257   {
258      int bit = (offset >> 1) & 0x0f;
259      switch (bit)
260      {
261      case 0:
262         /* (De)select the card. Indicated by a LED on the board. */
263         card->selected = data;
264         break;
265
266      case 1:
267         /* Activate motor */
268         if (data && !card->strobe_motor)
269         {   /* on rising edge, set motor_running for 4.23s */
270            card->DVENA = TRUE;
271            bwg_handle_hold(device);
272            timer_adjust_oneshot(card->motor_on_timer, ATTOTIME_IN_MSEC(4230), 0);
273         }
274         card->strobe_motor = data;
275         break;
276
277      case 2:
278         /* Set disk ready/hold (bit 2) */
279         // 0: ignore IRQ and DRQ
280         // 1: TMS9900 is stopped until IRQ or DRQ are set
281         // OR the motor stops rotating - rotates for 4.23s after write
282         // to CRU bit 1
283         // This is not emulated and could cause the TI99 to lock up
284         card->hold = data;
285         bwg_handle_hold(device);
286         break;
287
288      case 4:
289      case 5:
290      case 6:
291      case 8:
292         /* Select drive 0-2 (DSK1-DSK3) (bits 4-6) */
293         /* Select drive 3 (DSK4) (bit 8) */
294         drive = (bit == 8) ? 3 : (bit - 4);      /* drive # (0-3) */
295         drivebit = 1<<drive;
296         
297         if (data)
298         {
299            if (!(card->DSEL & drivebit))         /* select drive */
300            {
301               if (card->DSEL != 0)
302                  logerror("ti99/BwG: Multiple drives selected, %02x\n", card->DSEL); 
303               card->DSEL |= drivebit;
304               wd17xx_set_drive(card->controller, drive);
305            }
306         }
307         else
308            card->DSEL &= ~drivebit;
309         break;
310                 
311      case 7:
312         /* Select side of disk (bit 7) */
313         card->SIDE = data;
314         wd17xx_set_side(card->controller, card->SIDE);
315         break;
316
317      case 10:
318         /* double density enable (active low) */
319         wd17xx_dden_w(card->controller, data ? ASSERT_LINE : CLEAR_LINE);
320         break;
321
322      case 11:
323         /* EPROM A13 */
324         if (data)
325            card->rom_offset |= 0x2000;
326         else
327            card->rom_offset &= ~0x2000;
328         break;
329
330      case 13:
331         /* RAM A10 */
332         if (data)
333            card->ram_offset = 0x0400;
334         else
335            card->ram_offset = 0x0000;
336         break;
337         
338      case 14:
339         /* Override FDC with RTC (active high) */
340         card->rtc_enabled = data;
341         break;
342         
343      case 15:
344         /* EPROM A14 */
345         if (data)
346            card->rom_offset |= 0x4000;
347         else
348            card->rom_offset &= ~0x4000;
349         break;
350         
351      case 3:
352      case 9:
353      case 12:
354         /* Unused (bit 3, 9 & 12) */
355         break;
356      }
357   }
358}
359
360/*
361    Read a byte
362   4000 - 5bff: ROM (4 banks)
363   
364   rtc disabled:
365   5c00 - 5fef: RAM
366   5ff0 - 5fff: Controller (f0 = status, f2 = track, f4 = sector, f6 = data)
367
368   rtc enabled:
369   5c00 - 5fdf: RAM
370   5fe0 - 5fff: Clock (even addr)
371*/
372
373static READ8Z_DEVICE_HANDLER( data_r )
374{
375   ti99_bwg_state *card = get_safe_token(device);
376
377   if (card->selected)
378   {
379      if ((offset & 0xe000)==0x4000)
380      {
381         // 010x xxxx xxxx xxxx
382         if ((offset & 0x1c00)==0x1c00)
383         {
384            // ...1 11xx xxxx xxxx
385            if (card->rtc_enabled)
386            {
387               if ((offset & 0x03e1)==0x03e0)
388               {
389                  // .... ..11 111x xxx0
390                  *value = mm58274c_r(card->clock, (offset & 0x001e) >> 1);
391               }
392               else
393               {
394                  *value = card->ram[card->ram_offset + (offset&0x03ff)];
395               }
396            }
397            else
398            {
399               if ((offset & 0x03f9)==0x03f0)
400               {
401                  // .... ..11 1111 0xx0
402                  // Note that the value is inverted again on the board,
403                  // so we can drop the inversion
404                  *value = wd17xx_r(card->controller, (offset >> 1)&0x03);
405               }
406               else
407               {
408                  *value = card->ram[card->ram_offset + (offset&0x03ff)];
409               }
410            }
411         }
412         else
413         {
414            *value = card->rom[card->rom_offset + (offset & 0x1fff)];
415         }
416      }
417   }
418}
419
420/*
421    Write a byte
422   4000 - 5bff: ROM, ignore write (4 banks)
423   
424   rtc disabled:
425   5c00 - 5fef: RAM
426   5ff0 - 5fff: Controller (f8 = command, fa = track, fc = sector, fe = data)
427
428   rtc enabled:
429   5c00 - 5fdf: RAM
430   5fe0 - 5fff: Clock (even addr)   
431*/
432static WRITE8_DEVICE_HANDLER( data_w )
433{
434   ti99_bwg_state *card = get_safe_token(device);
435
436   if (card->selected)
437   {
438      if ((offset & 0xe000)==0x4000)
439      {
440         // 010x xxxx xxxx xxxx
441         if ((offset & 0x1c00)==0x1c00)
442         {
443            // ...1 11xx xxxx xxxx
444            if (card->rtc_enabled)
445            {
446               if ((offset & 0x03e1)==0x03e0)
447               {
448                  // .... ..11 111x xxx0
449                  mm58274c_w(card->clock, (offset & 0x001e) >> 1, data);
450               }
451               else
452               {
453                  card->ram[card->ram_offset + (offset&0x03ff)] = data;
454               }
455            }
456            else
457            {
458               if ((offset & 0x03f9)==0x03f8)
459               {
460                  // .... ..11 1111 1xx0
461                  // Note that the value is inverted again on the board,
462                  // so we can drop the inversion
463                  wd17xx_w(card->controller, (offset >> 1)&0x03, data);
464               }
465               else
466               {
467                  card->ram[card->ram_offset + (offset&0x03ff)] = data;
468               }
469            }
470         }
471      }
472   }
473}
474
475static DEVICE_START( ti99_bwg )
476{
477   ti99_bwg_state *card = (ti99_bwg_state*)downcast<legacy_device_base *>(device)->token();
478   
479   /* Resolve the callbacks to the PEB */
480   peb_callback_if *topeb = (peb_callback_if *)device->baseconfig().static_config();
481   devcb_resolve_write_line(&card->lines.ready, &topeb->ready, device);
482
483   card->motor_on_timer = timer_alloc(device->machine, motor_on_timer_callback, (void *)device);
484   card->controller = device->subdevice("wd1773");
485   card->clock = device->subdevice("mm58274c");
486   astring *region = new astring();
487   astring_assemble_3(region, device->tag(), ":", bwg_region);     
488   card->rom = memory_region(device->machine, astring_c(region));
489   card->ram = NULL;
490}
491
492static DEVICE_STOP( ti99_bwg )
493{
494   logerror("ti99_bwg: stop\n");
495   ti99_bwg_state *card = (ti99_bwg_state*)downcast<legacy_device_base *>(device)->token();
496   if (card->ram) free(card->ram);
497}
498
499static ti99_peb_card bwg_card =
500{
501   data_r,
502   data_w,
503   cru_r,
504   cru_w,   
505   NULL, NULL,   NULL, NULL   
506};
507
508static DEVICE_RESET( ti99_bwg )
509{
510   ti99_bwg_state *card = (ti99_bwg_state*)downcast<legacy_device_base *>(device)->token();
511
512   /* If the card is selected in the menu, register the card */
513   if (input_port_read(device->machine, "DISKCTRL") == DISK_BWG)
514   {
515      running_device *peb = device->owner();   
516      int success = mount_card(peb, device, &bwg_card, get_pebcard_config(device)->slot);
517      if (!success) return;
518           
519      // Allocate 2 KiB for on-board buffer memory (6116 chip)
520      if (card->ram==NULL)
521      {
522         card->ram = (UINT8*)malloc(2048);
523         memset(card->ram, 0, 2048);
524      }
525     
526      card->dip1 = input_port_read(device->machine, "BWGDIP1");
527      card->dip2 = input_port_read(device->machine, "BWGDIP2");
528      card->dip34 = input_port_read(device->machine, "BWGDIP34");
529
530      card->DSEL = 0;
531      card->SIDE = 0;
532      card->DVENA = 0;
533      card->strobe_motor = 0;
534           
535      ti99_set_80_track_drives(FALSE);
536
537      floppy_type_t flop = FLOPPY_STANDARD_5_25_DSDD_40;
538      set_all_geometries(device, flop);
539
540      card->strobe_motor = 0;
541      card->ram_offset = 0;
542      card->rom_offset = 0;
543      card->rtc_enabled = 0;
544     
545      wd17xx_dden_w(card->controller, CLEAR_LINE);   // Correct?   
546   }
547}
548
549const wd17xx_interface ti_wd17xx_interface =
550{
551   DEVCB_NULL,
552   DEVCB_LINE(ti_bwg_intrq_w),
553   DEVCB_LINE(ti_bwg_drq_w),
554   { PFLOPPY_0, PFLOPPY_1, PFLOPPY_2, PFLOPPY_3 }
555};
556
557static const mm58274c_interface floppy_mm58274c_interface =
558{
559   1,   /*  mode 24*/
560   0   /*  first day of week */
561};
562
563MACHINE_CONFIG_FRAGMENT( ti99_bwg )
564   MDRV_WD1773_ADD("wd1773", ti_wd17xx_interface )
565   MDRV_MM58274C_ADD("mm58274c", floppy_mm58274c_interface)
566MACHINE_CONFIG_END
567
568ROM_START( ti99_bwg )
569   ROM_REGION(0x8000, bwg_region, 0)
570   ROM_LOAD_OPTIONAL("bwg.bin", 0x0000, 0x8000, CRC(06f1ec89) SHA1(6ad77033ed268f986d9a5439e65f7d391c4b7651)) /* BwG disk DSR ROM */
571ROM_END
572
573static const char DEVTEMPLATE_SOURCE[] = __FILE__;
574
575#define DEVTEMPLATE_ID(p,s)             p##ti99_bwg##s
576#define DEVTEMPLATE_FEATURES            DT_HAS_START | DT_HAS_STOP | DT_HAS_RESET | DT_HAS_ROM_REGION | DT_HAS_INLINE_CONFIG | DT_HAS_MACHINE_CONFIG
577#define DEVTEMPLATE_NAME                "SNUG BwG Floppy Disk Controller Card"
578#define DEVTEMPLATE_FAMILY              "Peripheral expansion"
579#include "devtempl.h"
580
581DEFINE_LEGACY_DEVICE( BWG, ti99_bwg );
582
src/mess/machine/ti99/mapper8.h
r0r9485
1#ifndef __MAPPER8__
2#define __MAPPER8__
3
4typedef void (*mapper_read_function)(device_t *device, offs_t offset, UINT8 *value);
5typedef void (*mapper_write_function)(device_t *device, offs_t offset, UINT8 value);
6
7typedef struct _mapper8_dev_config
8{
9   const char             *name;
10   int                  mode;
11   int                  stop;
12   UINT32               address_mask;
13   UINT32               select_pattern;
14   UINT32               write_select;
15   mapper_read_function    read;
16   mapper_write_function    write;
17} mapper8_dev_config;
18
19#define SRAMNAME "SRAM"
20#define ROM0NAME "ROM0"
21#define ROM1NAME "ROM1"
22#define ROM1ANAME "ROM1A"
23#define INTSNAME "INTS"
24#define DRAMNAME "DRAM"
25
26READ8_DEVICE_HANDLER( ti99_mapper8_r );
27WRITE8_DEVICE_HANDLER( ti99_mapper8_w );
28WRITE8_DEVICE_HANDLER( ti99_mapreg_w );
29WRITE8_DEVICE_HANDLER( mapper8_CRUS_w );
30WRITE8_DEVICE_HANDLER( mapper8_PTGEN_w );
31READ8Z_DEVICE_HANDLER( ti998dsr_rz );
32WRITE8_DEVICE_HANDLER( mapper8c_w );
33
34/* device interface */
35DECLARE_LEGACY_DEVICE( MAPPER8, mapper8 );
36
37#define MDRV_MAPPER8_ADD(_tag, _devices)         \
38   MDRV_DEVICE_ADD(_tag, MAPPER8, 0) \
39   MDRV_DEVICE_CONFIG( _devices )
40
41#endif
src/mess/machine/ti99/mecmouse.h
r0r9485
1/*
2    TI-99 Mechatronic mouse with adapter
3    Michael Zapf, October 2010
4*/
5
6#ifndef __MECMOUSE__
7#define __MECMOUSE__
8
9void mecmouse_select(running_device *device, int selnow, int stick1, int stick2);
10void mecmouse_poll(running_device *device);
11int mecmouse_get_values(running_device *device);
12int mecmouse_get_values8(running_device *device, int mode);
13
14#define MDRV_MECMOUSE_ADD(_tag )   \
15   MDRV_DEVICE_ADD(_tag, MECMOUSE, 0)
16
17DECLARE_LEGACY_DEVICE( MECMOUSE, ti99_mecmouse );
18#endif
src/mess/machine/ti99/bwg.h
r0r9485
1/*
2    SNUG BwG Disk Controller
3   Based on WD1770
4   Double Density, Double-sided
5    Michael Zapf, September 2010
6*/
7
8/* device interface */
9#ifndef __BWG__
10#define __BWG__
11
12DECLARE_LEGACY_DEVICE( BWG, ti99_bwg );
13#endif
src/mess/machine/ti99/tiboard.c
r0r9485
1/***************************************************************************
2   TI-99/4(A) and TI-99/8 main board
3     
4   Michael Zapf, October 2010
5   TODO: Find out whether device can be determined more easily in CRU functions
6***************************************************************************/
7
8#include "emu.h"
9#include "tiboard.h"
10#include "gromport.h"
11#include "video/tms9928a.h"
12#include "handset.h"
13#include "mecmouse.h"
14#include "devices/cassette.h"
15#include "mapper8.h"
16
17typedef struct _tiboard_state
18{
19   /* Mode: Which console do we have? */
20   int            mode;
21   
22   /* Keyboard support */
23   int            keyCol;
24   int            alphaLockLine;
25   
26   /* Devices */
27   running_device    *cpu;
28   running_device    *video;
29   running_device  *tms9901;
30   running_device    *peribox;
31   running_device    *sound;
32
33   running_device    *handset;
34   running_device    *mecmouse;
35   running_device    *gromport;
36
37} tiboard_state;
38
39static const char *keynames[] = { "KEY0", "KEY1", "KEY2", "KEY3" };
40static const char *keynames8[] = {
41      "KEY0", "KEY1", "KEY2", "KEY3", "KEY4", "KEY5", "KEY6", "KEY7",
42      "KEY8", "KEY9", "KEY10", "KEY11", "KEY12", "KEY13", "KEY14", "KEY15"
43   };
44
45INLINE tiboard_state *get_safe_token(running_device *device)
46{
47   assert(device != NULL);
48   assert(downcast<legacy_device_base *>(device)->token() != NULL);
49   return (tiboard_state *)downcast<legacy_device_base *>(device)->token();
50}
51
52INLINE const tiboard_config *get_config(running_device *device)
53{
54   assert(device != NULL);
55   assert(device->type()==TIBOARD);
56   return (const tiboard_config *) downcast<const legacy_device_config_base &>(device->baseconfig()).inline_config();
57}
58
59/****************************************************************************
60   TMS9901 and attached devices handling
61****************************************************************************/
62/*
63    VBL interrupt  (mmm...  actually, it happens when the beam enters the lower
64    border, so it is not a genuine VBI, but who cares ?)
65*/
66INTERRUPT_GEN( ti99_vblank_interrupt )
67{
68   running_device *dev = device->machine->device("ti_board");
69   tiboard_state *board = get_safe_token(dev);
70
71   TMS9928A_interrupt(device->machine);   
72
73   if (board->handset != NULL)
74      ti99_handset_task(board->handset);
75   if (board->mecmouse != NULL)
76      mecmouse_poll(board->mecmouse);
77}
78
79/*
80    TI99/4x-specific tms9901 I/O handlers
81
82    See mess/machine/tms9901.c for generic tms9901 CRU handlers.
83
84    BTW, although TMS9900 is generally big-endian, it is little endian as far as CRU is
85    concerned. (i.e. bit 0 is the least significant)
86
87KNOWN PROBLEMS:
88    * a read or write to bits 16-31 causes TMS9901 to quit timer mode.  The problem is:
89      on a TI99/4A, any memory access causes a dummy CRU read.  Therefore, TMS9901 can quit
90      timer mode even though the program did not explicitely ask... and THIS is impossible
91      to emulate efficiently (we would have to check every memory operation).
92*/
93/*
94    TMS9901 interrupt handling on a TI99/4(a).
95
96    TI99/4(a) uses the following interrupts:
97    INT1: external interrupt (used by RS232 controller, for instance)
98    INT2: VDP interrupt
99    TMS9901 timer interrupt (overrides INT3)
100    INT12: handset interrupt (only on a TI-99/4 with the handset prototypes)
101
102    Three (occasionally four) interrupts are used by the system (INT1, INT2,
103    timer, and INT12 on a TI-99/4 with remote handset prototypes), out of 15/16
104    possible interrupts.  Keyboard pins can be used as interrupt pins, too, but
105    this is not emulated (it's a trick, anyway, and I don't know any program
106    which uses it).
107
108    When an interrupt line is set (and the corresponding bit in the interrupt mask is set),
109    a level 1 interrupt is requested from the TMS9900.  This interrupt request lasts as long as
110    the interrupt pin and the revelant bit in the interrupt mask are set.
111
112    TIMER interrupts are kind of an exception, since they are not associated with an external
113    interrupt pin, and I guess it takes a write to the 9901 CRU bit 3 ("SBO 3") to clear
114    the pending interrupt (or am I wrong once again ?).
115
116nota:
117    All interrupt routines notify (by software) the TMS9901 of interrupt
118    recognition (with a "SBO n").  However, unless I am missing something, this
119    has absolutely no consequence on the TMS9901 (except for the TIMER
120    interrupt routine), and interrupt routines would work fine without this
121    SBO instruction.  This is quite weird.  Maybe the interrupt recognition
122    notification is needed on TMS9985, or any other weird variant of TMS9900
123    (how about the TI-99 development system connected to a TI990/10?).
124*/
125
126/*
127    set the state of int2 (called by the tms9928 core)
128*/
129void tms9901_set_int2(running_machine *machine, int state)
130{
131   tms9901_set_single_int(machine->device("tms9901"), 2, state);
132}
133
134/*
135    Called by the 9901 core whenever the state of INTREQ and IC0-3 changes
136*/
137static TMS9901_INT_CALLBACK( tms9901_interrupt_callback )
138{
139   if (intreq)
140   {
141      // On TI99, TMS9900 IC0-3 lines are not connected to TMS9901,
142      // but hard-wired to force level 1 interrupts
143      cputag_set_input_line_and_vector(device->machine, "maincpu", 0, ASSERT_LINE, 1);   /* interrupt it, baby */
144   }
145   else
146   {
147      cputag_set_input_line(device->machine, "maincpu", 0, CLEAR_LINE);
148   }
149}
150
151/*
152    ti99_handset_set_ack()
153    Handler for tms9901 P0 pin (handset data acknowledge)
154*/
155static WRITE8_DEVICE_HANDLER( ti99_handset_set_ack )
156{
157   running_device *dev = device->machine->device("ti_board");
158   tiboard_state *board = get_safe_token(dev);
159
160   if (board->handset != NULL)
161      ti99_handset_set_acknowledge(board->handset, data);
162}
163
164/*
165    Read pins INT3*-INT7* of TI99's 9901.
166
167    signification:
168     (bit 1: INT1 status)
169     (bit 2: INT2 status)
170     bit 3-7: keyboard status bits 0 to 4
171*/
172static READ8_DEVICE_HANDLER( ti99_R9901_0 )
173{
174   int answer = 0;
175   running_device *dev = device->machine->device("ti_board");
176   tiboard_state *board = get_safe_token(dev);
177
178   if (board->keyCol == 7)
179   {
180      if (board->handset != NULL) answer = (ti99_handset_poll_bus(board->handset) << 3);
181      answer |= 0x80;
182   }
183   else
184   {
185      if ((board->mecmouse != NULL) && (board->keyCol == 6))
186      {
187         answer = mecmouse_get_values(board->mecmouse);
188      }
189      else
190         answer = ((input_port_read(device->machine, keynames[board->keyCol >> 1]) >> ((board->keyCol & 1) * 8)) << 3) & 0xF8;
191   }
192   return answer;
193}
194
195/*
196    Read pins INT3*-INT7* of TI99's 9901.
197
198    signification:
199     (bit 1: INT1 status)
200     (bit 2: INT2 status)
201     bit 3-7: keyboard status bits 0 to 4
202*/
203static READ8_DEVICE_HANDLER( ti99_R9901_0a )
204{
205   int answer;
206   running_device *dev = device->machine->device("ti_board");
207   tiboard_state *board = get_safe_token(dev);
208
209   if ((board->mecmouse != NULL) && (board->keyCol == 7))
210      answer = mecmouse_get_values(board->mecmouse);
211   else
212      answer = ((input_port_read(device->machine, keynames[board->keyCol >> 1]) >> ((board->keyCol & 1) * 8)) << 3) & 0xF8;
213   
214   if (board->alphaLockLine == FALSE)
215      answer &= ~(input_port_read(device->machine, "ALPHA") << 3);
216   
217   return answer;
218}
219
220
221/*
222    Read pins INT8*-INT15* of TI99's 9901.
223
224    signification:
225     bit 0-2: keyboard status bits 5 to 7
226     bit 3: tape input mirror
227     (bit 4: IR remote handset interrupt)
228     bit 5-7: weird, not emulated
229*/
230static READ8_DEVICE_HANDLER( ti99_R9901_1 )
231{
232   int answer;
233   running_device *dev = device->machine->device("ti_board");
234   tiboard_state *board = get_safe_token(dev);
235
236   if (board->keyCol == 7)
237      answer = 0x07;
238   else
239   {
240      answer = ((input_port_read(device->machine, keynames[board->keyCol >> 1]) >> ((board->keyCol & 1) * 8)) >> 5) & 0x07;
241   }
242
243   /* we don't take CS2 into account, as CS2 is a write-only unit */
244   //   if (cassette_input(device->machine->device("cassette1")) > 0)
245   //      answer |= 8;
246
247   return answer;
248}
249
250/*
251    Read pins P0-P7 of TI99's 9901.
252
253     bit 1: handset data clock pin
254*/
255static READ8_DEVICE_HANDLER( ti99_R9901_2 )
256{
257   running_device *dev = device->machine->device("ti_board");
258   tiboard_state *board = get_safe_token(dev);
259
260   if (board->handset != NULL)
261      if (ti99_handset_get_clock(board->handset)) return 2;
262   return 0;
263}
264
265/*
266    Read pins P8-P15 of TI99's 9901. (99/4)
267
268     bit 26: IR handset interrupt
269     bit 27: tape input
270*/
271static READ8_DEVICE_HANDLER( ti99_R9901_3 )
272{
273   int answer = 4;
274   running_device *dev = device->machine->device("ti_board");
275   tiboard_state *board = get_safe_token(dev);
276
277   /* on systems without handset, the pin is pulled up to avoid spurious interrupts */
278   if (board->handset != NULL)
279      if (ti99_handset_get_int(board->handset)) answer = 0;
280
281   /* we don't take CS2 into account, as CS2 is a write-only unit */
282   if (cassette_input(device->machine->device("cassette1")) > 0)
283      answer |= 8;
284
285   return answer;
286}
287
288/*
289    Read pins P8-P15 of TI99's 9901. (TI-99/8)
290
291     bit 26: high
292     bit 27: tape input
293*/
294static READ8_DEVICE_HANDLER( ti99_8_R9901_3 )
295{
296   int answer = 4;   /* on systems without handset, the pin is pulled up to avoid spurious interrupts */
297   if (cassette_input(device->machine->device("cassette")) > 0)
298      answer |= 8;
299   return answer;
300}
301
302/*
303    WRITE key column select (P2-P4), TI-99/4
304*/
305static WRITE8_DEVICE_HANDLER( ti99_KeyC )
306{
307   running_device *dev = device->machine->device("ti_board");
308   tiboard_state *board = get_safe_token(dev);
309
310   int index=5;
311   
312   if (board->mode==TI994A)
313      index=6;
314   
315   if (data)
316      board->keyCol |= 1 << (offset-2);
317   else
318      board->keyCol &= ~ (1 << (offset-2));
319
320   if (board->mecmouse != NULL)
321      mecmouse_select(board->mecmouse, board->keyCol, index , index+1);
322}
323
324/*
325    WRITE alpha lock line - TI99/4a only (P5)
326*/
327static WRITE8_DEVICE_HANDLER( ti99_AlphaW )
328{
329   running_device *dev = device->machine->device("ti_board");
330   tiboard_state *board = get_safe_token(dev);
331   board->alphaLockLine = data;
332}
333
334/*
335    command CS1 tape unit motor (P6)
336*/
337static WRITE8_DEVICE_HANDLER( ti99_CS1_motor )
338{
339   running_device *img = device->machine->device("cassette1");
340   cassette_change_state(img, data ? CASSETTE_MOTOR_ENABLED : CASSETTE_MOTOR_DISABLED, CASSETTE_MASK_MOTOR);
341}
342
343/*
344    command CS2 tape unit motor (P7)
345*/
346static WRITE8_DEVICE_HANDLER( ti99_CS2_motor )
347{
348   running_device *img = device->machine->device("cassette2");
349   cassette_change_state(img, data ? CASSETTE_MOTOR_ENABLED : CASSETTE_MOTOR_DISABLED, CASSETTE_MASK_MOTOR);
350}
351
352/*
353    command CS1 (only) tape unit motor (P6)
354*/
355static WRITE8_DEVICE_HANDLER( ti99_CS_motor )
356{
357   running_device *img = device->machine->device("cassette");
358   cassette_change_state(img, data ? CASSETTE_MOTOR_ENABLED : CASSETTE_MOTOR_DISABLED, CASSETTE_MASK_MOTOR);
359}
360
361/*
362    audio gate (P8)
363
364    Set to 1 before using tape: this enables the mixing of tape input sound
365    with computer sound.
366
367    We do not really need to emulate this as the tape recorder generates sound
368    on its own.
369*/
370static WRITE8_DEVICE_HANDLER( ti99_audio_gate )
371{
372}
373
374/*
375    tape output (P9)
376    I think polarity is correct, but don't take my word for it.
377*/
378static WRITE8_DEVICE_HANDLER( ti99_CS12_output )
379{
380   cassette_output(device->machine->device("cassette1"), data ? +1 : -1);
381   cassette_output(device->machine->device("cassette2"), data ? +1 : -1);
382}
383
384/*
385    tape output (P9)
386    I think polarity is correct, but don't take my word for it.
387*/
388static WRITE8_DEVICE_HANDLER( ti99_CS_output )
389{
390   cassette_output(device->machine->device("cassette"), data ? +1 : -1);
391}
392
393/*
394    WRITE key column select (P0-P3)
395*/
396static WRITE8_DEVICE_HANDLER( ti99_8_KeyC )
397{
398   running_device *dev = device->machine->device("ti_board");
399   tiboard_state *board = get_safe_token(dev);
400
401   if (data)
402      board->keyCol |= 1 << offset;
403   else
404      board->keyCol &= ~ (1 << offset);
405
406   if (board->mecmouse != NULL)
407      mecmouse_select(board->mecmouse, board->keyCol, 14, 15);
408}
409
410static WRITE8_DEVICE_HANDLER( ti99_8_CRUS )
411{
412   running_device *mapper = device->machine->device("mapper");
413   mapper8_CRUS_w(mapper, 0, data);
414}
415
416static WRITE8_DEVICE_HANDLER( ti99_8_PTGEN )
417{
418   running_device *mapper = device->machine->device("mapper");
419   mapper8_PTGEN_w(mapper, 0, data);
420}
421
422/*
423    Read pins INT3*-INT7* of TI99's 9901.
424
425    signification:
426     (bit 1: INT1 status)
427     (bit 2: INT2 status)
428     bits 3-4: unused?
429     bit 5: ???
430     bit 6-7: keyboard status bits 0 through 1
431*/
432static READ8_DEVICE_HANDLER( ti99_8_R9901_0 )
433{
434   int answer;
435   running_device *dev = device->machine->device("ti_board");
436   tiboard_state *board = get_safe_token(dev);
437
438   if (board->mecmouse != NULL && (board->keyCol == 15))
439   {
440      answer = mecmouse_get_values8(board->mecmouse, 0);
441   }
442   else
443   {
444      answer = (input_port_read(device->machine, keynames8[board->keyCol]) << 6) & 0xC0;
445   }
446
447   return answer;
448}
449
450
451/*
452    Read pins INT8*-INT15* of TI99's 9901.
453
454    signification:
455     bit 0-2: keyboard status bits 2 to 4
456     bit 3: tape input mirror
457     (bit 4: IR remote handset interrupt)
458     bit 5-7: weird, not emulated
459*/
460static READ8_DEVICE_HANDLER( ti99_8_R9901_1 )
461{
462   running_device *dev = device->machine->device("ti_board");
463   tiboard_state *board = get_safe_token(dev);
464   int answer;
465
466   if (board->mecmouse != NULL && (board->keyCol == 15))
467   {
468      answer = mecmouse_get_values8(board->mecmouse, 1);
469   }
470   else
471   {
472      answer = (input_port_read(device->machine, keynames8[board->keyCol]) >> 2) & 0x07;
473   }
474
475   return answer;
476}
477
478/*
479    Read pins P0-P7 of TI99's 9901.
480
481     bit 1: handset data clock pin
482*/
483static READ8_DEVICE_HANDLER( ti99_8_R9901_2 )
484{
485   return 0;
486}
487
488
489/* TMS9901 setup. The callback functions pass a reference to the TMS9901 as device. */
490const tms9901_interface tms9901_wiring_ti99_4 =
491{
492   TMS9901_INT1 | TMS9901_INT2 | TMS9901_INTC,   /* only input pins whose state is always known */
493
494   {   /* read handlers */
495      ti99_R9901_0,
496      ti99_R9901_1,
497      ti99_R9901_2,
498      ti99_R9901_3
499   },
500
501   {   /* write handlers */
502      ti99_handset_set_ack,
503      NULL,
504      ti99_KeyC,
505      ti99_KeyC,
506      ti99_KeyC,
507      NULL,
508      ti99_CS1_motor,
509      ti99_CS2_motor,
510      ti99_audio_gate,
511      ti99_CS12_output,
512      NULL,
513      NULL,
514      NULL,
515      NULL,
516      NULL,
517      NULL
518   },
519
520   /* interrupt handler */
521   tms9901_interrupt_callback,
522
523   /* clock rate = 3MHz */
524   3000000.
525};
526
527/* TMS9901 setup. The callback functions pass a reference to the TMS9901 as device. */
528const tms9901_interface tms9901_wiring_ti99_4a =
529{
530   TMS9901_INT1 | TMS9901_INT2 | TMS9901_INTC,   /* only input pins whose state is always known */
531
532   {   /* read handlers */
533      ti99_R9901_0a,
534      ti99_R9901_1,
535      ti99_R9901_2,
536      ti99_R9901_3
537   },
538
539   {   /* write handlers */
540      NULL,
541      NULL,
542      ti99_KeyC,
543      ti99_KeyC,
544      ti99_KeyC,
545      ti99_AlphaW,
546      ti99_CS1_motor,
547      ti99_CS2_motor,
548      ti99_audio_gate,
549      ti99_CS12_output,
550      NULL,
551      NULL,
552      NULL,
553      NULL,
554      NULL,
555      NULL
556   },
557
558   /* interrupt handler */
559   tms9901_interrupt_callback,
560
561   /* clock rate = 3MHz */
562   3000000.
563};
564
565const tms9901_interface tms9901_wiring_ti99_8 =
566{
567   TMS9901_INT1 | TMS9901_INT2 | TMS9901_INTC,   /* only input pins whose state is always known */
568
569   {   /* read handlers */
570      ti99_8_R9901_0,
571      ti99_8_R9901_1,
572      ti99_8_R9901_2,
573      ti99_8_R9901_3
574   },
575
576   {   /* write handlers */
577      ti99_8_KeyC,
578      ti99_8_KeyC,
579      ti99_8_KeyC,
580      ti99_8_KeyC,
581      ti99_8_CRUS,
582      ti99_8_PTGEN,
583      ti99_CS_motor,
584      NULL,
585      ti99_audio_gate,
586      ti99_CS_output,
587      NULL,
588      NULL,
589      NULL,
590      NULL,
591      NULL,
592      NULL
593   },
594
595   /* interrupt handler */
596   tms9901_interrupt_callback,
597
598   /* clock rate = 3.58MHz??? 2.68MHz??? */
599   /*3579545.*/2684658.75
600};
601
602/*
603   Handles the EXTINT line. This one is directly connected to the 9901.
604*/
605WRITE_LINE_DEVICE_HANDLER( console_extint )
606{
607   tms9901_set_single_int(device->machine->device("tms9901"), 1, state);
608}
609
610WRITE_LINE_DEVICE_HANDLER( console_notconnected )
611{
612   logerror("Not connected line set ... sorry\n");
613}
614
615WRITE_LINE_DEVICE_HANDLER( console_ready )
616{
617   logerror("READY line set ... not yet connected, level=%02x\n", state);
618}
619
620/***************************************************************************
621    DEVICE LIFECYCLE FUNCTIONS
622***************************************************************************/
623   
624static DEVICE_START( tiboard )
625{
626   tiboard_state *board = get_safe_token(device);
627   logerror("Starting TI-99 board\n");
628   board->tms9901 = device->siblingdevice("tms9901");
629   board->gromport = device->siblingdevice("gromport");
630}
631
632static DEVICE_STOP( tiboard )
633{
634   logerror("Stopping TI-99 board\n");
635}
636
637static DEVICE_RESET( tiboard )
638{
639   tiboard_state *board = get_safe_token(device);
640   const tiboard_config* conf = (const tiboard_config*)get_config(device);
641   board->mode = conf->mode;
642   
643   /* clear keyboard interface state (probably overkill, but can't harm) */
644   board->keyCol = 0;
645   board->alphaLockLine = 0;
646   board->handset = NULL;
647   board->mecmouse = NULL;
648
649   if (board->mode == TI994)
650   {
651      /* reset handset */
652      tms9901_set_single_int(board->tms9901, 12, 0);
653     
654      if (input_port_read(device->machine, "HCI") & HCI_IR)
655         board->handset = device->siblingdevice("handset");
656   }
657
658   if (input_port_read(device->machine, "HCI") & HCI_MECMOUSE)
659      board->mecmouse = device->siblingdevice("mecmouse");
660   
661   if (board->mode != TI998)
662   {
663      set_gk_switches(board->gromport, 1, input_port_read(device->machine, "GKSWITCH1")); 
664      set_gk_switches(board->gromport, 2, input_port_read(device->machine, "GKSWITCH2")); 
665      set_gk_switches(board->gromport, 3, input_port_read(device->machine, "GKSWITCH3")); 
666      set_gk_switches(board->gromport, 4, input_port_read(device->machine, "GKSWITCH4")); 
667      set_gk_switches(board->gromport, 5, input_port_read(device->machine, "GKSWITCH5"));
668   }   
669}
670
671static const char DEVTEMPLATE_SOURCE[] = __FILE__;
672
673#define DEVTEMPLATE_ID(p,s)             p##tiboard##s
674#define DEVTEMPLATE_FEATURES            DT_HAS_START | DT_HAS_STOP | DT_HAS_RESET | DT_HAS_INLINE_CONFIG
675#define DEVTEMPLATE_NAME                "TI-99 system board"
676#define DEVTEMPLATE_FAMILY              "Internal component"
677#include "devtempl.h"
678
679DEFINE_LEGACY_DEVICE( TIBOARD, tiboard );
src/mess/machine/ti99/handset.c
r0r9485
1/*
2    TI-99/4 Handset support (TI99/4 only)
3
4    The ti99/4 was intended to support some so-called "IR remote handsets".
5    This feature was canceled at the last minute (reportedly ten minutes before
6    the introductory press conference in June 1979), but the first thousands of
7    99/4 units had the required port, and the support code was seemingly not
8    deleted from ROMs until the introduction of the ti99/4a in 1981.  You could
9    connect up to 4 20-key keypads, and up to 4 joysticks with a maximum
10    resolution of 15 levels on each axis.
11
12    The keyboard DSR was able to couple two 20-key keypads together to emulate
13    a full 40-key keyboard.  Keyboard modes 0, 1 and 2 would select either the
14    console keyboard with its two wired remote controllers (i.e. joysticks), or
15    remote handsets 1 and 2 with their associated IR remote controllers (i.e.
16    joysticks), according to which was currently active.
17
18    Originally written by R. Nabet
19   
20    Michael Zapf   
21    2010-10-24 Rewriten as device
22*/
23
24#include "emu.h"
25#include "handset.h"
26#include "machine/tms9901.h"
27
28#define MAX_HANDSETS 4
29
30typedef struct _ti99_handset_state
31{
32   int       buf;
33   int       buflen;
34   int       clock;
35   int       ack;
36   UINT8       previous_joy[MAX_HANDSETS];
37   UINT8       previous_key[MAX_HANDSETS];
38
39   emu_timer      *timer;
40   running_device    *console9901;
41
42} ti99_handset_state;
43
44static const char *const joynames[2][4] =
45{
46   { "JOY0", "JOY2", "JOY4", "JOY6" },      // X axis
47   { "JOY1", "JOY3", "JOY5", "JOY7" }      // Y axis
48};
49
50static const char *const keynames[] = { "KP0", "KP1", "KP2", "KP3", "KP4" };
51
52INLINE ti99_handset_state *get_safe_token(running_device *device)
53{
54   assert(device != NULL);
55   return (ti99_handset_state *)downcast<legacy_device_base *>(device)->token();
56}
57
58INLINE const ti99_handset_config *get_config(running_device *device)
59{
60   assert(device != NULL);
61   assert(device->type() == HANDSET);
62   return (const ti99_handset_config *) downcast<const legacy_device_config_base &>(device->baseconfig()).inline_config();
63}
64
65/*****************************************************************************/
66
67/*
68    ti99_handset_poll_bus()
69
70    Poll the current state of the 4-bit data bus that goes from the I/R
71    receiver to the tms9901.
72*/
73int ti99_handset_poll_bus(running_device *device)
74{
75   ti99_handset_state *handset = get_safe_token(device);
76   return (handset->buf & 0xf);
77}
78
79int ti99_handset_get_clock(running_device *device)
80{
81   ti99_handset_state *handset = get_safe_token(device);
82   return handset->clock;   
83}
84
85int ti99_handset_get_int(running_device *device)
86{
87   ti99_handset_state *handset = get_safe_token(device);
88   return handset->buflen==3;   
89}
90
91/*
92    ti99_handset_ack_callback()
93
94    Handle data acknowledge sent by the ti-99/4 handset ISR (through tms9901
95    line P0).  This function is called by a delayed timer 30us after the state
96    of P0 is changed, because, in one occasion, the ISR asserts the line before
97    it reads the data, so we need to delay the acknowledge process.
98*/
99static TIMER_CALLBACK(ti99_handset_ack_callback)
100{
101   running_device *device = (running_device *)ptr;
102   ti99_handset_state *handset = get_safe_token(device);
103
104   handset->clock = !handset->clock;
105   handset->buf >>= 4;
106   handset->buflen--;
107   
108   tms9901_set_single_int(handset->console9901, 12, 0);
109
110   if (handset->buflen == 1)
111   {
112      // Unless I am missing something, the third and last nybble of the
113      // message is not acknowledged by the DSR in any way, and the first nybble
114      // of next message is not requested for either, so we need to decide on
115      // our own when we can post a new event.  Currently, we wait for 1000us
116      // after the DSR acknowledges the second nybble.
117      timer_adjust_oneshot(handset->timer, ATTOTIME_IN_USEC(1000), 0);
118   }
119
120   if (handset->buflen == 0)
121      /* See if we need to post a new event */
122      ti99_handset_task(device);
123}
124
125/*
126    ti99_handset_set_ack()
127    Handler for tms9901 P0 pin (handset data acknowledge)
128*/
129void ti99_handset_set_acknowledge(running_device *device, UINT8 data)
130{
131   ti99_handset_state *handset = get_safe_token(device);
132   if (handset->buflen && (data != handset->ack))
133   {
134      handset->ack = data;
135      if (data == handset->clock)
136         /* I don't know what the real delay is, but 30us apears to be enough */
137         timer_adjust_oneshot(handset->timer, ATTOTIME_IN_USEC(30), 0);
138   }
139}
140
141/*
142    ti99_handset_post_message()
143
144    Post a 12-bit message: trigger an interrupt on the tms9901, and store the
145    message in the I/R receiver buffer so that the handset ISR will read this
146    message.
147
148    message: 12-bit message to post (only the 12 LSBits are meaningful)
149*/
150static void ti99_handset_post_message(running_device *device, int message)
151{
152   ti99_handset_state *handset = get_safe_token(device);
153   /* post message and assert interrupt */
154   handset->clock = 1;
155   handset->buf = ~message;
156   handset->buflen = 3;
157   
158   tms9901_set_single_int(handset->console9901, 12, 1);
159}
160
161/*
162    ti99_handset_poll_keyboard()
163    Poll the current state of one given handset keypad.
164    num: number of the keypad to poll (0-3)
165    Returns TRUE if the handset state has changed and a message was posted.
166*/
167static int ti99_handset_poll_keyboard(running_device *device, int num)
168{
169   ti99_handset_state *handset = get_safe_token(device);
170   UINT32 key_buf;
171   UINT8 current_key;
172   int i;
173
174   /* read current key state */
175   key_buf = ( input_port_read(device->machine, keynames[num]) | (input_port_read(device->machine, keynames[num + 1]) << 16) ) >> (4*num);
176
177   // If a key was previously pressed, this key was not shift, and this key is
178   // still down, then don't change the current key press.
179   if (handset->previous_key[num] && (handset->previous_key[num] != 0x24)
180      && (key_buf & (1 << (handset->previous_key[num] & 0x1f))))
181   {
182      /* check the shift modifier state */
183      if (((handset->previous_key[num] & 0x20) != 0) == ((key_buf & 0x0008) != 0))
184         /* the shift modifier state has not changed */
185      return FALSE;
186      else
187      {
188         // The shift modifier state has changed: we need to update the
189         // keyboard state
190         if (key_buf & 0x0008)
191         {   /* shift has been pressed down */
192            handset->previous_key[num] = current_key = handset->previous_key[num] | 0x20;
193         }
194         else
195         {   /* shift has been pressed down */
196            handset->previous_key[num] = current_key = handset->previous_key[num] & ~0x20;
197         }
198         /* post message */
199         ti99_handset_post_message(device, (((unsigned) current_key) << 4) | (num << 1));
200
201         return TRUE;
202      }
203
204   }
205
206   current_key = 0;   /* default value if no key is down */
207   for (i=0; i<20; i++)
208   {
209      if (key_buf & (1 << i))
210      {
211         current_key = i + 1;
212         if (key_buf & 0x0008)
213            current_key |= 0x20;   /* set shift flag */
214
215         if (current_key != 0x24)
216            // If this is the shift key, any other key we may find will
217            // have higher priority; otherwise, we may exit the loop and keep
218            // the key we have just found.
219            break;
220      }
221   }
222
223   if (current_key != handset->previous_key[num])
224   {
225      handset->previous_key[num] = current_key;
226
227      /* post message */
228      ti99_handset_post_message(device, (((unsigned) current_key) << 4) | (num << 1));
229
230      return TRUE;
231   }
232   return FALSE;
233}
234
235/*
236    ti99_handset_poll_joystick()
237
238    Poll the current state of one given handset joystick.
239    num: number of the joystick to poll (0-3)
240    Returns TRUE if the handset state has changed and a message was posted.
241*/
242static int ti99_handset_poll_joystick(running_device *device, int num)
243{
244   ti99_handset_state *handset = get_safe_token(device);
245
246   UINT8 current_joy;
247   int current_joy_x, current_joy_y;
248   int message;
249
250   /* read joystick position */
251   current_joy_x = input_port_read(device->machine, joynames[0][num]);
252   current_joy_y = input_port_read(device->machine, joynames[1][num]);
253
254   /* compare with last saved position */
255   current_joy = current_joy_x | (current_joy_y << 4);
256   if (current_joy != handset->previous_joy[num])
257   {
258      /* save position */
259      handset->previous_joy[num] = current_joy;
260
261      /* transform position to signed quantity */
262      current_joy_x -= 7;
263      current_joy_y -= 7;
264
265      message = 0;
266
267      /* set sign */
268      // note that we set the sign if the joystick position is 0 to work
269      // around a bug in the ti99/4 ROMs
270      if (current_joy_x <= 0)
271      {
272         message |= 0x040;
273         current_joy_x = - current_joy_x;
274      }
275
276      if (current_joy_y <= 0)
277      {
278         message |= 0x400;
279         current_joy_y = - current_joy_y;
280      }
281
282      /* convert absolute values to Gray code and insert in message */
283      if (current_joy_x & 4)
284         current_joy_x ^= 3;
285      if (current_joy_x & 2)
286         current_joy_x ^= 1;
287      message |= current_joy_x << 3;
288
289      if (current_joy_y & 4)
290         current_joy_y ^= 3;
291      if (current_joy_y & 2)
292         current_joy_y ^= 1;
293      message |= current_joy_y << 7;
294
295      /* set joystick address */
296      message |= (num << 1) | 0x1;
297
298      /* post message */
299      ti99_handset_post_message(device, message);
300      return TRUE;
301   }
302   return FALSE;
303}
304
305/*
306    ti99_handset_task()
307    Manage handsets, posting an event if the state of any handset has changed.
308*/
309void ti99_handset_task(running_device *device)
310{
311   int i;
312   ti99_handset_state *handset = get_safe_token(device);
313   
314   if (handset->buflen == 0)
315   {   
316      /* poll every handset */
317      for (i=0; i < MAX_HANDSETS; i++)
318         if (ti99_handset_poll_joystick(device, i)) return;
319      for (i=0; i < MAX_HANDSETS; i++)
320         if (ti99_handset_poll_keyboard(device, i)) return;
321   }
322   else if (handset->buflen == 3)
323   {   /* update messages after they have been posted */
324      if (handset->buf & 1)
325      {   /* keyboard */
326         ti99_handset_poll_keyboard(device, (~(handset->buf >> 1)) & 0x3);
327      }
328      else
329      {   /* joystick */
330         ti99_handset_poll_joystick(device, (~(handset->buf >> 1)) & 0x3);
331      }
332   }
333}
334
335
336/**************************************************************************/
337
338static DEVICE_START( ti99_handset)
339{
340   ti99_handset_state *handset = get_safe_token(device);
341   handset->timer = timer_alloc(device->machine, ti99_handset_ack_callback, (void *)device);
342}
343
344static DEVICE_RESET( ti99_handset )
345{
346   const ti99_handset_config* conf = (const ti99_handset_config*)get_config(device);
347   ti99_handset_state *handset = get_safe_token(device);
348   handset->console9901 = device->machine->device(conf->sysintf);
349   handset->buf = 0;
350   handset->buflen = 0;
351   handset->clock = 0;
352   handset->ack = 0;
353}
354
355static const char DEVTEMPLATE_SOURCE[] = __FILE__;
356
357#define DEVTEMPLATE_ID(p,s)             p##ti99_handset##s
358#define DEVTEMPLATE_FEATURES            DT_HAS_START | DT_HAS_RESET | DT_HAS_INLINE_CONFIG
359#define DEVTEMPLATE_NAME                "TI-99/4 Handset"
360#define DEVTEMPLATE_FAMILY              "Human-Computer Interface"
361#include "devtempl.h"
362
363DEFINE_LEGACY_DEVICE( HANDSET, ti99_handset );
364
src/mess/machine/ti99/spchsyn.c
r0r9485
1/*
2    TI-99 Speech synthesizer
3   
4    We emulate the Speech Synthesizer plugged onto a P-Box adapter. The original
5    Speech Synthesizer device was provided as a box to be plugged into the
6    right side of the console. In order to be used with Geneve and SGCPU, the
7    speech synthesizer must be moved into the Peripheral Box.
8   
9    The Speech Synthesizer used for the TI was the TMS5200, aka TMC0285, a
10    predecessor of the TMS5220 which was used in other commercial products.
11   
12    Note that this adapter also contains the speech roms.
13*/
14#include "emu.h"
15#include "peribox.h"
16#include "spchsyn.h"
17#include "sound/tms5220.h"
18#include "sound/wave.h"
19
20#define TMS5220_ADDRESS_MASK 0x3FFFFUL   /* 18-bit mask for tms5220 address */
21#define speech_region "speech_region"
22
23typedef ti99_pebcard_config ti99_speech_config;
24
25typedef struct _ti99_speech_state
26{
27   running_device          *vsp;
28   UINT8                *speechrom_data;      /* pointer to speech ROM data */
29   int                load_pointer;         /* which 4-bit nibble will be affected by load address */
30   int                ROM_bits_count;            /* current bit position in ROM */
31   UINT32                speechROMaddr;            /* 18 bit pointer in ROM */
32   UINT32               speechROMlen;         /* length of data pointed by speechrom_data, from 0 to 2^18 */
33   ti99_peb_connect      lines;
34   
35} ti99_speech_state;
36
37INLINE ti99_speech_state *get_safe_token(running_device *device)
38{
39   assert(device != NULL);
40   return (ti99_speech_state *)downcast<legacy_device_base *>(device)->token();
41}
42
43/*****************************************************************************/
44
45/*
46    Read 'count' bits serially from speech ROM
47*/
48static int ti99_spchroms_read(running_device *vspdev, int count)
49{
50   running_device *device = vspdev->owner();
51   ti99_speech_state *adapter = get_safe_token(device);
52
53   int val;
54
55   if (adapter->load_pointer)
56   {   /* first read after load address is ignored */
57      adapter->load_pointer = 0;
58      count--;
59   }
60
61   if (adapter->speechROMaddr < adapter->speechROMlen)
62   {
63      if (count < adapter->ROM_bits_count)
64      {
65         adapter->ROM_bits_count -= count;
66         val = (adapter->speechrom_data[adapter->speechROMaddr] >> adapter->ROM_bits_count) & (0xFF >> (8 - count));
67      }
68      else
69      {
70         val = ((int)adapter->speechrom_data[adapter->speechROMaddr]) << 8;
71
72         adapter->speechROMaddr = (adapter->speechROMaddr + 1) & TMS5220_ADDRESS_MASK;
73
74         if (adapter->speechROMaddr < adapter->speechROMlen)
75            val |= adapter->speechrom_data[adapter->speechROMaddr];
76
77         adapter->ROM_bits_count += 8 - count;
78
79         val = (val >> adapter->ROM_bits_count) & (0xFF >> (8 - count));
80      }
81   }
82   else
83      val = 0;
84
85   return val;
86}
87
88/*
89    Write an address nibble to speech ROM
90*/
91static void ti99_spchroms_load_address(running_device *vspdev, int data)
92{
93   running_device *device = vspdev->owner();
94   ti99_speech_state *adapter = get_safe_token(device);
95   // tms5220 data sheet says that if we load only one 4-bit nibble, it won't work.
96   // This code does not care about this.
97   adapter->speechROMaddr = ((adapter->speechROMaddr & ~(0xf << adapter->load_pointer))
98      | (((unsigned long) (data & 0xf)) << adapter->load_pointer) ) & TMS5220_ADDRESS_MASK;
99   adapter->load_pointer += 4;
100   adapter->ROM_bits_count = 8;
101}
102
103/*
104    Perform a read and branch command
105*/
106static void ti99_spchroms_read_and_branch(running_device *vspdev)
107{
108   running_device *device = vspdev->owner();
109   ti99_speech_state *adapter = get_safe_token(device);
110   // tms5220 data sheet says that if more than one speech ROM (tms6100) is present,
111   // there is a bus contention.  This code does not care about this. */
112   if (adapter->speechROMaddr < adapter->speechROMlen-1)
113      adapter->speechROMaddr = (adapter->speechROMaddr & 0x3c000UL)
114         | (((((unsigned long) adapter->speechrom_data[adapter->speechROMaddr]) << 8)
115         | adapter->speechrom_data[adapter->speechROMaddr+1]) & 0x3fffUL);
116   else if (adapter->speechROMaddr == adapter->speechROMlen-1)
117      adapter->speechROMaddr = (adapter->speechROMaddr & 0x3c000UL)
118         | ((((unsigned long) adapter->speechrom_data[adapter->speechROMaddr]) << 8) & 0x3fffUL);
119   else
120      adapter->speechROMaddr = (adapter->speechROMaddr & 0x3c000UL);
121
122   adapter->ROM_bits_count = 8;
123}
124
125/*****************************************************************************/
126
127/*
128    Memory read
129*/
130static READ8Z_DEVICE_HANDLER( speech_rz )
131{
132   ti99_speech_state *adapter = get_safe_token(device);
133   
134   if ((offset & 0xfc01)==0x9000)       
135   {
136      cpu_adjust_icount(device->machine->device("maincpu"),-(18+3));      /* this is just a minimum, it can be more */     
137      *value = tms5220_status_r(adapter->vsp, offset) & 0xff;
138   }
139}
140
141/*
142   Memory write
143*/
144static WRITE8_DEVICE_HANDLER( speech_w )
145{
146   ti99_speech_state *adapter = get_safe_token(device);
147
148   if ((offset & 0xfc01)==0x9400)
149   {
150      cpu_adjust_icount(device->machine->device("maincpu"),-(54+3));      /* this is just an approx. minimum, it can be much more */
151     
152      /* RN: the stupid design of the tms5220 core means that ready is cleared */
153      /* when there are 15 bytes in FIFO.  It should be 16.  Of course, if */
154      /* it were the case, we would need to store the value on the bus, */
155      /* which would be more complex. */
156      if (!tms5220_readyq_r(adapter->vsp))
157      {
158         attotime time_to_ready = double_to_attotime(tms5220_time_to_ready(adapter->vsp));
159         int cycles_to_ready = device->machine->device<cpu_device>("maincpu")->attotime_to_cycles(time_to_ready);
160         logerror("time to ready: %f -> %d\n", attotime_to_double(time_to_ready), (int) cycles_to_ready);
161         
162         cpu_adjust_icount(device->machine->device("maincpu"),-cycles_to_ready);
163         timer_set(device->machine, attotime_zero, NULL, 0, NULL);
164      }     
165      tms5220_data_w(adapter->vsp, offset, data);
166   }
167}
168
169/**************************************************************************/
170
171static ti99_peb_card speech_adapter_card =
172{
173   speech_rz, speech_w,         // memory access read/write
174   NULL, NULL,                  // CRU access (none here)
175   NULL, NULL,                  // SENILA/B access (none here)
176   NULL, NULL                  // 16 bit access (none here)
177};
178
179static DEVICE_START( ti99_speech )
180{
181   ti99_speech_state *adapter = (ti99_speech_state*)downcast<legacy_device_base *>(device)->token();
182   /* Resolve the callbacks to the PEB */
183   peb_callback_if *topeb = (peb_callback_if *)device->baseconfig().static_config();
184   devcb_resolve_write_line(&adapter->lines.ready, &topeb->ready, device);
185   adapter->vsp = device->subdevice("speechsyn");
186}
187
188static DEVICE_STOP( ti99_speech )
189{
190}
191
192static DEVICE_RESET( ti99_speech )
193{
194   ti99_speech_state *adapter = (ti99_speech_state*)downcast<legacy_device_base *>(device)->token();
195   /* Register the adapter */
196   running_device *peb = device->owner();
197   
198   if (input_port_read(device->machine, "SPEECH"))
199   {
200      int success = mount_card(peb, device, &speech_adapter_card, get_pebcard_config(device)->slot);
201      if (!success)
202      {
203         logerror("speech: Could not mount the speech synthesizer\n");
204         return;
205      }
206     
207      astring *region = new astring();
208      astring_assemble_3(region, device->tag(), ":", speech_region);   
209     
210      adapter->speechrom_data = memory_region(device->machine, astring_c(region));
211      adapter->speechROMlen = memory_region_length(device->machine, astring_c(region));
212      adapter->speechROMaddr = 0;
213      adapter->load_pointer = 0;
214      adapter->ROM_bits_count = 0;
215   }
216}
217
218static WRITE_LINE_DEVICE_HANDLER( speech_ready )
219{
220   ti99_speech_state *adapter = (ti99_speech_state*)downcast<legacy_device_base *>(device->owner())->token();
221   logerror("speech: READY called by VSP\n");
222   devcb_call_write_line( &adapter->lines.ready, state );
223}
224
225/*
226    TMS5220 speech synthesizer
227    Note that in the real hardware, the predecessor TMC0285 was used.
228*/
229static const tms5220_interface ti99_4x_tms5200interface =
230{
231   DEVCB_NULL,               /* no IRQ callback */
232   DEVCB_LINE(speech_ready),
233   ti99_spchroms_read,            /* speech ROM read handler */
234   ti99_spchroms_load_address,      /* speech ROM load address handler */
235   ti99_spchroms_read_and_branch   /* speech ROM read and branch handler */
236};
237
238MACHINE_CONFIG_FRAGMENT( ti99_speech )
239   MDRV_SOUND_ADD("speechsyn", TMC0285, 680000L)
240   MDRV_SOUND_CONFIG(ti99_4x_tms5200interface)
241   MDRV_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)
242MACHINE_CONFIG_END
243
244ROM_START( ti99_speech )
245   ROM_REGION(0x8000, speech_region, 0)
246   ROM_LOAD_OPTIONAL("spchrom.bin", 0x0000, 0x8000, CRC(58b155f7) SHA1(382292295c00dff348d7e17c5ce4da12a1d87763)) /* system speech ROM */
247ROM_END
248
249static const char DEVTEMPLATE_SOURCE[] = __FILE__;
250
251#define DEVTEMPLATE_ID(p,s)             p##ti99_speech##s
252#define DEVTEMPLATE_FEATURES            DT_HAS_START | DT_HAS_STOP | DT_HAS_RESET | DT_HAS_INLINE_CONFIG | DT_HAS_ROM_REGION | DT_HAS_MACHINE_CONFIG
253#define DEVTEMPLATE_NAME                "TI-99 Speech Synthesizer"
254#define DEVTEMPLATE_FAMILY              "Peripheral expansion"
255#include "devtempl.h"
256
257DEFINE_LEGACY_DEVICE( TISPEECH, ti99_speech );
258
src/mess/machine/ti99/tiboard.h
r0r9485
1#ifndef __TIBOARD__
2#define __TIBOARD__
3
4#include "machine/tms9901.h"
5
6void tms9901_set_int2(running_machine *machine, int state);
7
8extern const tms9901_interface tms9901_wiring_ti99_4;
9extern const tms9901_interface tms9901_wiring_ti99_4a;
10extern const tms9901_interface tms9901_wiring_ti99_8;
11
12typedef struct _tiboard_config
13{
14   int mode;
15} tiboard_config;
16
17enum
18{
19   TI994 = 1,
20   TI994A,
21   TI998
22};
23
24/* device interface */
25DECLARE_LEGACY_DEVICE( TIBOARD, tiboard );
26
27WRITE_LINE_DEVICE_HANDLER( console_extint );
28WRITE_LINE_DEVICE_HANDLER( console_notconnected );
29WRITE_LINE_DEVICE_HANDLER( console_ready );
30
31INTERRUPT_GEN( ti99_vblank_interrupt );
32
33#define MDRV_TI994_BOARD_ADD(_tag )         \
34   MDRV_DEVICE_ADD(_tag, TIBOARD, 0) \
35   MDRV_DEVICE_CONFIG_DATA32( tiboard_config, mode, TI994)
36
37#define MDRV_TI994A_BOARD_ADD(_tag )         \
38   MDRV_DEVICE_ADD(_tag, TIBOARD, 0) \
39   MDRV_DEVICE_CONFIG_DATA32( tiboard_config, mode, TI994A)
40
41#define MDRV_TI998_BOARD_ADD(_tag )         \
42   MDRV_DEVICE_ADD(_tag, TIBOARD, 0)    \
43   MDRV_DEVICE_CONFIG_DATA32( tiboard_config, mode, TI998)
44
45#endif
src/mess/machine/ti99/handset.h
r0r9485
1/*
2    TI-99/4 handset
3    Michael Zapf, October 2010
4*/
5
6#ifndef __HANDSET__
7#define __HANDSET__
8
9typedef struct _ti99_handset_config
10{
11   const char             *sysintf;
12} ti99_handset_config;
13
14
15void ti99_handset_task(running_device *device);
16void ti99_handset_set_acknowledge(running_device *device, UINT8 data);
17int ti99_handset_poll_bus(running_device *device);
18int ti99_handset_get_clock(running_device *device);
19int ti99_handset_get_int(running_device *device);
20
21#define MDRV_HANDSET_ADD(_tag, _sysintf )   \
22   MDRV_DEVICE_ADD(_tag, HANDSET, 0) \
23   MDRV_DEVICE_CONFIG_DATAPTR(ti99_handset_config, sysintf, _sysintf)
24
25DECLARE_LEGACY_DEVICE( HANDSET, ti99_handset );
26#endif
src/mess/machine/ti99/spchsyn.h
r0r9485
1/*
2    TI-99 Speech Synthesizer
3    Michael Zapf, October 2010
4*/
5
6#ifndef __TISPEECH__
7#define __TISPEECH__
8
9DECLARE_LEGACY_DEVICE( TISPEECH, ti99_speech );
10#endif

Previous 15994 Revisions Next


© 1998-2018 The MESS Team