Previous 15994 Revisions Next

r8682 Sunday 1st August, 2010 at 17:28:34 UTC by Justin Kerk
Fix svn:eol-style
[hash]rx78.xml
[src/mess/devices]ti99_peb.c ti99_peb.h
[src/mess/drivers]prestige.c
[src/mess/machine]a2cffa.c a2cffa.h
[src/mess/tools/imgtool/modules]cybikoxt.c

hash/rx78.xml
r8681r8682
1<?xml version="1.0"?>
2<!DOCTYPE softwarelist SYSTEM "softwarelist.dtd">
3<softwarelist name="rx78" description="Gundam RX-78 cartridges">
4   <software name="bs-basic">
5      <description>BS-BASIC</description>
6      <year>1983</year>
7      <publisher>Bandai</publisher>
8      <part name="cart" interface="rx78_cart">
9         <dataarea name="rom" size="16384">
10            <rom name="bs-basic.bin" size="16384" crc="e52b383f" sha1="6ebbff7eb718822cad3c1216882df5d9f2d3a03f" offset="0" />
11         </dataarea>
12      </part>
13   </software>
14</softwarelist>
1<?xml version="1.0"?>
2<!DOCTYPE softwarelist SYSTEM "softwarelist.dtd">
3<softwarelist name="rx78" description="Gundam RX-78 cartridges">
4   <software name="bs-basic">
5      <description>BS-BASIC</description>
6      <year>1983</year>
7      <publisher>Bandai</publisher>
8      <part name="cart" interface="rx78_cart">
9         <dataarea name="rom" size="16384">
10            <rom name="bs-basic.bin" size="16384" crc="e52b383f" sha1="6ebbff7eb718822cad3c1216882df5d9f2d3a03f" offset="0" />
11         </dataarea>
12      </part>
13   </software>
14</softwarelist>
src/mess/devices/ti99_peb.c
r8681r8682
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    The third-party myarc geneve and snug sgcpu computers are actually cards
25    to be inserted into a PEB: they have a PC keyboard connector, and replace
26    the original ti-99 console completely.
27 
28    Each expansion card is assigned to one of 16 CRU address ranges.
29    I appended the names of known TI peripherals that use each port (I appended
30    '???' when I don't know what the peripheral is :-) ).
31    * 0x1000-0x10FE "For test equipment use on production line"
32    * 0x1100-0x11FE disk controller
33    * 0x1200-0x12FE modem???
34    * 0x1300-0x13FE RS232 1&2, PIO 1
35    * 0x1400-0x14FE unassigned
36    * 0x1500-0x15FE RS232 3&4, PIO 2
37    * 0x1600-0x16FE unassigned
38    * 0x1700-0x17FE hex-bus (prototypes)
39    * 0x1800-0x18FE thermal printer (early peripheral)
40    * 0x1900-0x19FE EPROM programmer??? (Mezzanine board in July 1981's TI99/7
41        prototype)
42    * 0x1A00-0x1AFE unassigned
43    * 0x1B00-0x1BFE TI GPL debugger card
44    * 0x1C00-0x1CFE Video Controller Card (Possibly the weirdest device.  This
45        card is connected to the video output of the computer, to a VCR, and a
46        video monitor.  It can control the VCR, connect the display to either
47        VCR output or computer video output, and it can read or save binary
48        data to video tape.  I think it can act as a genlock interface (i.e.
49        TMS9918 transparent background shows the video signal), too, but I am
50        not sure about this.)
51    * 0x1D00-0x1DFE IEEE 488 Controller Card ('intelligent' parallel bus,
52        schematics on ftp.whtech.com)
53    * 0x1E00-0x1EFE unassigned
54    * 0x1F00-0x1FFE P-code card (part of a complete development system)
55 
56    The ti-99/8 implements 16 extra ports:
57    * 0x2000-0x26ff and 0x2800-0x2fff: reserved for future expansion?
58    * 0x2700-0x27ff: internal DSR
59 
60    The snug sgcpu 99/4p implements 12 extra ports:
61    * 0x0400-0x0eff: free
62    * 0x0f00-0x0fff: internal DSR
63 
64    Known mappings for 3rd party cards:
65    * Horizon RAMdisk: any ports from 0 to 7 (port 0 is most common).
66    * Myarc 128k/512k (RAM and DSR ROM): port 0 (0x1000-0x11FE)
67    * Corcomp 512k (RAM and DSR ROM): port unknown
68    * Super AMS 128k/512k: port 14 (0x1E00-0x1EFE)
69    * Foundation 128k/512k: port 14 (0x1E00-0x1EFE)
70    * Gram Karte: any port (0-15)
71    * EVPC (video card): 0x1400-0x14FE
72    * HSGPL (GROM replacement): 0x1B00-0x1BFE
73 
74    Of course, these devices additionally need some support routines, and
75    possibly memory-mapped I/O registers.  To do so, memory range 0x4000-5FFF
76    is shared by all cards.  The system enables each card as needed by writing
77    a 1 to the first CRU bit: when this happens the card can safely enable its
78    ROM, RAM, memory-mapped registers, etc.  Provided the ROM uses the proper
79    ROM header, the system will recognize and call peripheral I/O functions,
80    interrupt service routines, and startup routines.  (All these routines are
81    generally called DSR = Device Service Routine.)
82 
83    Also, the cards can trigger level-1 ("INTA") interrupts.  A LOAD interrupt
84    is present on the side port of the ti-99/4(a), too, but it was never used
85    by TI, AFAIK.  Also, an interrupt line called "INTB" is found on several
86    cards built by TI, but it is not connected: I am quite unsure whether it
87    was intended to be connected to the LOAD line, to the INT2 line of TMS9985,
88    or it was only to be used with the ti-99/4(a) development system running on
89    a TI990/10.  This is not the only unused feature: cards built by TI support
90    sensing of an interrupt status register and 19-bit addressing, even though
91    ti-99/4(A) does not take advantage of these features.  TI documentation
92    tells that some of these features are "defined by the Personal Computer PCC
93    at Texas Instrument", which is not very explicit (What on earth does "PCC"
94    stand for?).  Maybe it refers to the ti-99/4(a) development system running
95    on a TI990/10, or to the ti-99/7 and ti-99/8 prototypes.
96 
97    Note that I use 8-bit RAM handlers.  Obviously, using 16-bit handlers would
98    be equivalent and faster on a ti-99/4(a), but we need to interface the
99    extension cards not only to the ti-99/4(a), but to the geneve and ti-99/8
100    emulators as well.
101 
102    June 2010: Reimplemented using device structure (MZ) (obsoletes 99_peb.c)
103*/
104 
105#include "emu.h"
106#include "ti99_peb.h"
107 
108enum width_t {
109   width_8bit = 0,
110   width_16bit
111};
112/* expansion card structure for the snug sgcpu 99/4p system, which supports
113dynamical 16-bit accesses (TI did not design this!) */
114typedef struct ti99_4p_peb_card_handlers_t
115{
116   cru_read_handler cru_read;      /* card CRU read handler */
117   cru_write_handler cru_write;   /* card CRU handler */
118 
119   width_t width;
120   union
121   {
122      struct
123      {
124         read8_space_func mem_read;      /* card mem read handler (8 bits) */
125         write8_space_func mem_write;   /* card mem write handler (8 bits) */
126      } width_8bit;
127      struct
128      {
129         read16_space_func mem_read;   /* card mem read handler (16 bits) */
130         write16_space_func mem_write;   /* card mem write handler (16 bits) */
131      } width_16bit;
132   } w;
133} ti99_4p_peb_card_handlers_t;
134 
135typedef struct _ti99_peb_state
136{
137   /* TRUE if we are using the snug sgcpu 99/4p 16-bit extensions */
138   int has_16bit_peb;
139 
140   /* handlers for each of 28 slots */
141   ti99_4p_peb_card_handlers_t ti99_4p_expansion_ports[28];
142 
143   /* handlers for each of 16 slots + 16 extra slots for ti-99/8 */
144   ti99_peb_card_handlers_t expansion_ports[16+16];
145 
146   /* index of the currently active card (-1 if none) */
147   int active_card;
148 
149   /* index of the currently active card, overridden by the mapper */
150   int active_card_tmp;
151 
152   /* Mapper override. */
153   int mapper_override;
154 
155   // ila: inta status register (not actually used on ti-99/4(a), but nevertheless
156   // present)
157   int ila;
158 
159   // ilb: intb status register (completely pointless on ti-99/4(a), as neither
160   // INTB nor SENILB are connected; OTOH, INTB can trigger interrupts on a Geneve,
161   // and snug sgcpu 99/4p can sense ILB)
162   int ilb;
163 
164   /* only used by the snug sgcpu 99/4p */
165   int senila, senilb;
166 
167   /* hack to simulate TMS9900 byte write */
168   int tmp_buffer;
169 
170   /* inta/intb handlers */
171   void (*inta_callback)(running_machine *machine, int state);
172   void (*intb_callback)(running_machine *machine, int state);
173 
174   const address_space *space;
175 
176} ti99_peb_state;
177 
178INLINE ti99_peb_state *get_safe_token(running_device *device)
179{
180   assert(device != NULL);
181   assert(downcast<legacy_device_base *>(device)->token() != NULL);
182   return (ti99_peb_state *)downcast<legacy_device_base *>(device)->token();
183}
184 
185INLINE const ti99_peb_config *get_config(running_device *device)
186{
187   assert(device != NULL);
188   assert(device->type() == PBOX);
189   return (const ti99_peb_config *) downcast<const legacy_device_config_base &>(device->baseconfig()).inline_config();
190}
191 
192/*
193    Sets the handlers for one expansion port (normal 8-bit card)
194 
195    cru_base: CRU base address (any of 0x1000, 0x1100, 0x1200, ..., 0x1F00)
196        (snug sgcpu 99/4p accepts 0x0400, ..., 0x1F00, ti-99/8 accepts 0x1000,
197        ..., 0x2F00)
198    handler: handler structure for the given card
199*/
200void ti99_peb_set_card_handlers(running_device *box, int cru_base, const ti99_peb_card_handlers_t *handler)
201{
202   int port;
203   ti99_peb_state *peb = get_safe_token(box);
204 
205   if (cru_base & 0xff)
206      return;
207 
208   if (peb->has_16bit_peb)
209   {
210      port = (cru_base - 0x0400) >> 8;
211 
212      if ((port>=0) && (port<28))
213      {
214         peb->ti99_4p_expansion_ports[port].cru_read = handler->cru_read;
215         peb->ti99_4p_expansion_ports[port].cru_write = handler->cru_write;
216         peb->ti99_4p_expansion_ports[port].width = width_8bit;
217         peb->ti99_4p_expansion_ports[port].w.width_8bit.mem_read = handler->mem_read;
218         peb->ti99_4p_expansion_ports[port].w.width_8bit.mem_write = handler->mem_write;
219      }
220   }
221   else
222   {
223      port = (cru_base - 0x1000) >> 8;
224 
225      if ((port>=0) && (port</*16*/32))
226      {
227         peb->expansion_ports[port] = *handler;
228      }
229   }
230}
231 
232/*
233    Sets the handlers for one expansion port (special 16-bit card for snug
234    sgcpu 99/4p)
235 
236    cru_base: CRU base address (any of 0x1000, 0x1100, 0x1200, ..., 0x1F00)
237        (snug sgcpu 99/4p accepts 0x0400, ..., 0x1F00, ti-99/8 accepts 0x1000,
238        ..., 0x2F00)
239    handler: handler structure for the given card
240*/
241void ti99_peb_set_16bit_card_handlers(running_device *box, int cru_base, const ti99_peb_16bit_card_handlers_t *handler)
242{
243   int port;
244   ti99_peb_state *peb = get_safe_token(box);
245 
246   if (cru_base & 0xff)
247      return;
248 
249   if (peb->has_16bit_peb)
250   {
251      port = (cru_base - 0x0400) >> 8;
252 
253      if ((port>=0) && (port<28))
254      {
255         peb->ti99_4p_expansion_ports[port].cru_read = handler->cru_read;
256         peb->ti99_4p_expansion_ports[port].cru_write = handler->cru_write;
257         peb->ti99_4p_expansion_ports[port].width = width_16bit;
258         peb->ti99_4p_expansion_ports[port].w.width_16bit.mem_read = handler->mem_read;
259         peb->ti99_4p_expansion_ports[port].w.width_16bit.mem_write = handler->mem_write;
260      }
261   }
262}
263 
264/*
265    Update ila status register and assert or clear INTA interrupt line
266    accordingly.
267 
268    bit: bit number ([0,7] for original INTA register, [8,15] are extra
269        "virtual" bits for devices that assert the INTA line without setting a
270        bit of the ILA register)
271    state: 1 to assert bit, 0 to clear
272*/
273void ti99_peb_set_ila_bit(running_device *box, int bit, int state)
274{
275   ti99_peb_state *peb = get_safe_token(box);
276   if (state)
277   {
278      peb->ila |= 1 << bit;
279      if (peb->inta_callback)
280         (*peb->inta_callback)(box->machine, 1);
281   }
282   else
283   {
284      peb->ila &= ~(1 << bit);
285      if ((!peb->ila) && peb->inta_callback)
286         (*peb->inta_callback)(box->machine, 0);
287   }
288}
289 
290/*
291    Update ilb status register and assert or clear INTB interrupt line
292    accordingly.
293 
294    bit: bit number ([0,7] for original INTAB register, [8,15] are extra
295        "virtual" bits for devices that assert the INTB line without setting a
296        bit of the ILB register)
297    state: 1 to assert bit, 0 to clear
298*/
299void ti99_peb_set_ilb_bit(running_device *box, int bit, int state)
300{
301   ti99_peb_state *peb = get_safe_token(box);
302 
303   if (state)
304   {
305      peb->ilb |= 1 << bit;
306      if (peb->intb_callback)
307         (*peb->intb_callback)(box->machine, 1);
308   }
309   else
310   {
311      peb->ilb &= ~(1 << bit);
312      if ((!peb->ilb) && peb->intb_callback)
313         (*peb->intb_callback)(box->machine, 0);
314   }
315}
316 
317 
318/*
319    Read CRU in range >1000->1ffe (>800->fff) (ti-99/4(a))
320*/
321READ8_DEVICE_HANDLER( ti99_4x_peb_cru_r )
322{
323   int port;
324   cru_read_handler handler;
325   int reply;
326   ti99_peb_state *peb = get_safe_token(device);
327 
328   port = (offset & 0x00f0) >> 4;
329   handler = peb->expansion_ports[port].cru_read;
330 
331   reply = (handler) ? (*handler)(device->machine, offset & 0xf) : 0;
332 
333   return reply;
334}
335 
336/*
337    Write CRU in range >1000->1ffe (>800->fff) (ti-99/4(a))
338*/
339WRITE8_DEVICE_HANDLER( ti99_4x_peb_cru_w )
340{
341   int port;
342   cru_write_handler handler;
343   ti99_peb_state *peb = get_safe_token(device);
344 
345   port = (offset & 0x0780) >> 7;
346   handler = peb->expansion_ports[port].cru_write;
347 
348   if (handler)
349      (*handler)(device->machine, offset & 0x7f, data);
350 
351   /* expansion card enable? */
352   if ((offset & 0x7f) == 0)
353   {
354      if (data & 1)
355      {
356         /* enable */
357         peb->active_card = port;
358      }
359      else
360      {
361         if (port == peb->active_card)   /* geez... who cares? */
362         {
363            peb->active_card = -1;         /* no port selected */
364         }
365      }
366   }
367}
368 
369/*
370    Read mem in range >4000->5ffe (ti-99/4(a))
371*/
372READ16_DEVICE_HANDLER( ti99_4x_peb_r )
373{
374   int reply = 0;
375   read8_space_func handler;
376   ti99_peb_state *peb = get_safe_token(device);
377 
378   cpu_adjust_icount(device->machine->firstcpu,-4);
379 
380   if (peb->active_card != -1)
381   {
382      handler = peb->expansion_ports[peb->active_card].mem_read;
383      if (handler)
384      {
385         reply = (*handler)(peb->space, (offset << 1) + 1);
386         reply |= ((unsigned) (*handler)(peb->space, offset << 1)) << 8;
387      }
388   }
389//  printf("[%04x:%04x] = %04x\n", (active_card<<8)+0x1000, (offset<<1)+0x4000, reply);
390 
391   return peb->tmp_buffer = reply;
392}
393 
394/*
395    Write mem in range >4000->5ffe (ti-99/4(a))
396*/
397WRITE16_DEVICE_HANDLER( ti99_4x_peb_w )
398{
399   write8_space_func handler;
400   ti99_peb_state *peb = get_safe_token(device);
401 
402   cpu_adjust_icount(device->machine->firstcpu,-4);
403 
404   /* simulate byte write */
405   data = (peb->tmp_buffer & ~mem_mask) | (data & mem_mask);
406 
407   if (peb->active_card != -1)
408   {
409      handler = peb->expansion_ports[peb->active_card].mem_write;
410      if (handler)
411      {
412         (*handler)(peb->space, (offset << 1) + 1, data & 0xff);
413         (*handler)(peb->space, offset << 1, (data >> 8) & 0xff);
414      }
415   }
416}
417 
418 
419/*
420    Read CRU in range >1000->1ffe (>800->fff) (Geneve)
421*/
422READ8_DEVICE_HANDLER( geneve_peb_cru_r )
423{
424   int port;
425   cru_read_handler handler;
426   int reply;
427   ti99_peb_state *peb = get_safe_token(device);
428 
429   port = (offset & 0x00f0) >> 4;
430   handler = peb->expansion_ports[port].cru_read;
431 
432   reply = (handler) ? (*handler)(device->machine, offset & 0xf) : 0;
433 
434   return reply;
435}
436 
437/*
438    Write CRU in range >1000->1ffe (>800->fff) (Geneve)
439*/
440WRITE8_DEVICE_HANDLER( geneve_peb_cru_w )
441{
442   int port;
443   cru_write_handler handler;
444   ti99_peb_state *peb = get_safe_token(device);
445 
446   port = (offset & 0x0780) >> 7;
447   handler = peb->expansion_ports[port].cru_write;
448 
449   if (handler)
450      (*handler)(device->machine, offset & 0x7f, data);
451 
452   /* expansion card enable? */
453   if ((offset & 0x7f) == 0)
454   {
455      if (data & 1)
456      {
457         /* enable */
458         peb->active_card = port;
459      }
460      else
461      {
462         if (port == peb->active_card)   /* geez... who cares? */
463         {
464            peb->active_card = -1;         /* no port selected */
465         }
466      }
467   }
468}
469 
470/*
471    Read mem in range >4000->5fff (Geneve)
472*/
473READ8_DEVICE_HANDLER( geneve_peb_r )
474{
475   int reply = 0;
476   read8_space_func handler;
477   ti99_peb_state *peb = get_safe_token(device);
478 
479   cpu_adjust_icount(device->machine->firstcpu,-8);
480 
481   if (peb->active_card != -1)
482   {
483      handler = peb->expansion_ports[peb->active_card].mem_read;
484      if (handler)
485         reply = (*handler)(peb->space, offset);
486   }
487 
488   return reply;
489}
490 
491/*
492    Write mem in range >4000->5fff (Geneve)
493*/
494WRITE8_DEVICE_HANDLER( geneve_peb_w )
495{
496   write8_space_func handler;
497   ti99_peb_state *peb = get_safe_token(device);
498 
499   cpu_adjust_icount(device->machine->firstcpu,-8);
500 
501   if (peb->active_card != -1)
502   {
503      handler = peb->expansion_ports[peb->active_card].mem_write;
504      if (handler)
505         (*handler)(peb->space, offset, data);
506   }
507}
508 
509/*
510    Read CRU in range >1000->2ffe (>0800->17ff) (ti-99/8)
511*/
512READ8_DEVICE_HANDLER( ti99_8_peb_cru_r )
513{
514   int port;
515   cru_read_handler handler;
516   int reply;
517   ti99_peb_state *peb = get_safe_token(device);
518 
519   port = (offset & 0x01f0) >> 4;
520   handler = peb->expansion_ports[port].cru_read;
521 
522   reply = (handler) ? (*handler)(device->machine, offset & 0xf) : 0;
523 
524   return reply;
525}
526 
527/*
528    Write CRU in range >1000->2ffe (>0800->17ff) (ti-99/8)
529*/
530WRITE8_DEVICE_HANDLER( ti99_8_peb_cru_w )
531{
532   int port;
533   cru_write_handler handler;
534   ti99_peb_state *peb = get_safe_token(device);
535 
536   port = (offset & 0x0f80) >> 7;
537   handler = peb->expansion_ports[port].cru_write;
538 
539   if (handler)
540      (*handler)(device->machine, offset & 0x7f, data);
541 
542   /* expansion card enable? */
543   if ((offset & 0x7f) == 0)
544   {
545      if (data & 1)
546      {
547         /* enable */
548         peb->active_card = port;
549      }
550      else
551      {
552         if (port == peb->active_card)   /* geez... who cares? */
553         {
554            peb->active_card = -1;         /* no port selected */
555         }
556      }
557   }
558}
559 
560/*
561    Read mem in range >4000->5fff (ti-99/8)
562*/
563READ8_DEVICE_HANDLER( ti99_8_peb_r )
564{
565   int reply = 0;
566   read8_space_func handler;
567   ti99_peb_state *peb = get_safe_token(device);
568 
569   cpu_adjust_icount(device->machine->firstcpu,-4);
570 
571   if (peb->active_card != -1)
572   {
573      handler = peb->expansion_ports[peb->active_card].mem_read;
574      if (handler)
575         reply = (*handler)(peb->space, offset);
576   }
577 
578   return reply;
579}
580 
581/*
582    Write mem in range >4000->5fff (ti-99/8)
583*/
584WRITE8_DEVICE_HANDLER( ti99_8_peb_w )
585{
586   write8_space_func handler;
587   ti99_peb_state *peb = get_safe_token(device);
588 
589   cpu_adjust_icount(device->machine->firstcpu,-4);
590 
591   if (peb->active_card != -1)
592   {
593      handler = peb->expansion_ports[peb->active_card].mem_write;
594      if (handler)
595         (*handler)(peb->space, offset, data);
596   }
597}
598 
599/*
600    Read CRU in range >0400->1ffe (>200->fff) (snug sgcpu 99/4p)
601*/
602READ8_DEVICE_HANDLER( ti99_4p_peb_cru_r )
603{
604   int port;
605   cru_read_handler handler;
606   int reply;
607   ti99_peb_state *peb = get_safe_token(device);
608 
609   port = offset >> 4;
610   handler = peb->ti99_4p_expansion_ports[port].cru_read;
611 
612   reply = (handler) ? (*handler)(device->machine, offset & 0xf) : 0;
613 
614   return reply;
615}
616 
617/*
618    Write CRU in range >0400->1ffe (>200->fff) (snug sgcpu 99/4p)
619*/
620WRITE8_DEVICE_HANDLER( ti99_4p_peb_cru_w )
621{
622   int port;
623   cru_write_handler handler;
624   ti99_peb_state *peb = get_safe_token(device);
625 
626   int cru_address = (offset + 0x200)<<1;
627 
628   port = offset >> 7;
629   handler = peb->ti99_4p_expansion_ports[port].cru_write;
630 
631   if (handler)
632      (*handler)(device->machine, offset & 0x7f, data);
633 
634   /* expansion card enable? */
635   if ((cru_address & 0xfe) == 0)
636   {
637      if (data & 1)
638      {
639         /* enable */
640         if (cru_address == 0x1e00)
641         {
642            // The internal mapper has precedence over the external bus.
643            // It may be turned on although there is another device currently turned on
644            peb->active_card_tmp = peb->active_card;
645            peb->mapper_override = TRUE;
646         }
647         peb->active_card = port;
648      }
649      else
650      {
651         if ((cru_address == 0x1e00) && peb->mapper_override)
652         {
653            peb->active_card = peb->active_card_tmp;
654            peb->mapper_override = FALSE;
655         }
656         else
657         {
658            if (port == peb->active_card)   /* geez... who cares? */
659            {
660               peb->active_card = -1;         /* no port selected */
661            }
662         }
663      }
664   }
665}
666 
667/*
668    Read mem in range >4000->5ffe (snug sgcpu 99/4p)
669*/
670READ16_DEVICE_HANDLER( ti99_4p_peb_r )
671{
672   int reply = 0;
673   read8_space_func handler;
674   read16_space_func handler16;
675   ti99_peb_state *peb = get_safe_token(device);
676 
677   if (peb->active_card == -1)
678      cpu_adjust_icount(device->machine->firstcpu,-4);   /* ??? */
679   else
680   {
681      if (peb->ti99_4p_expansion_ports[peb->active_card].width == width_8bit)
682      {
683         cpu_adjust_icount(device->machine->firstcpu,-4);
684 
685         handler = peb->ti99_4p_expansion_ports[peb->active_card].w.width_8bit.mem_read;
686         if (handler)
687         {
688            reply = (*handler)(peb->space, (offset << 1) + 1);
689            reply |= ((unsigned) (*handler)(peb->space, offset << 1)) << 8;
690         }
691      }
692      else
693      {
694         cpu_adjust_icount(device->machine->firstcpu,-1);   /* ??? */
695 
696         handler16 = peb->ti99_4p_expansion_ports[peb->active_card].w.width_16bit.mem_read;
697         if (handler16)
698            reply = (*handler16)(peb->space, offset, /*mem_mask*/0xffff);
699      }
700   }
701 
702   if (peb->senila || peb->senilb)
703   {
704      if ((peb->active_card != -1) || (peb->senila && peb->senilb))
705         /* ah, the smell of burnt silicon... */
706         logerror("<Scrrrrr>: your computer has just burnt (maybe).\n");
707 
708      if (peb->senila)
709         reply = (peb->ila & 0xff) | (peb->ila << 8);
710      else if (peb->senilb)
711         reply = (peb->ilb & 0xff) | (peb->ilb << 8);
712   }
713 
714//  printf("[%04x:%04x] = %04x\n", (active_card<<8)+0x400, (offset<<1)+0x4000, reply);
715   return peb->tmp_buffer = reply;
716}
717 
718/*
719    Write mem in range >4000->5ffe (snug sgcpu 99/4p)
720*/
721WRITE16_DEVICE_HANDLER( ti99_4p_peb_w )
722{
723   write8_space_func handler;
724   write16_space_func handler16;
725   ti99_peb_state *peb = get_safe_token(device);
726 
727   if (peb->active_card == -1)
728      cpu_adjust_icount(device->machine->firstcpu,-4);   /* ??? */
729   else
730   {
731      /* simulate byte write */
732      data = (peb->tmp_buffer & ~mem_mask) | (data & mem_mask);
733 
734      if (peb->ti99_4p_expansion_ports[peb->active_card].width == width_8bit)
735      {
736         cpu_adjust_icount(device->machine->firstcpu,-4);
737 
738         handler = peb->ti99_4p_expansion_ports[peb->active_card].w.width_8bit.mem_write;
739         if (handler)
740         {
741            (*handler)(peb->space, (offset << 1) + 1, data & 0xff);
742            (*handler)(peb->space, offset << 1, (data >> 8) & 0xff);
743         }
744      }
745      else
746      {
747         cpu_adjust_icount(device->machine->firstcpu,-1);   /* ??? */
748 
749         handler16 = peb->ti99_4p_expansion_ports[peb->active_card].w.width_16bit.mem_write;
750         if (handler16)
751            (*handler16)(peb->space, offset, data, /*mem_mask*/0xffff);
752      }
753   }
754}
755 
756/*
757    Set the state of the SENILA line (snug sgcpu 99/4p)
758*/
759void ti99_4p_peb_set_senila(running_device *box, int state)
760{
761   ti99_peb_state *peb = get_safe_token(box);
762   peb->senila = (state != 0);
763}
764 
765/*
766    Set the state of the SENILB line (snug sgcpu 99/4p)
767*/
768void ti99_4p_peb_set_senilb(running_device *box, int state)
769{
770   ti99_peb_state *peb = get_safe_token(box);
771   peb->senilb = (state != 0);
772}
773 
774 
775/***************************************************************************
776    DEVICE FUNCTIONS
777***************************************************************************/
778 
779static DEVICE_START( ti99_peb )
780{
781}
782 
783static DEVICE_STOP( ti99_peb )
784{
785}
786 
787static DEVICE_RESET( ti99_peb )
788{
789   ti99_peb_state *peb = get_safe_token(device);
790 
791   peb->has_16bit_peb = get_config(device)->mode16;
792   peb->inta_callback = get_config(device)->inta_callback;
793   peb->intb_callback = get_config(device)->intb_callback;
794 
795   peb->active_card = -1;
796   peb->active_card_tmp = -1;
797 
798   peb->mapper_override = FALSE; // for ti99_4p
799 
800   peb->ila = 0;
801   peb->ilb = 0;
802 
803   peb->space = cputag_get_address_space(device->machine, "maincpu", ADDRESS_SPACE_PROGRAM);
804 
805   // Remove all card handlers; must be reinstalled
806   memset(peb->expansion_ports, 0, sizeof(peb->expansion_ports));
807   memset(peb->ti99_4p_expansion_ports, 0, sizeof(peb->ti99_4p_expansion_ports));
808}
809 
810static const char DEVTEMPLATE_SOURCE[] = __FILE__;
811 
812#define DEVTEMPLATE_ID(p,s)             p##ti99_peb##s
813#define DEVTEMPLATE_FEATURES            DT_HAS_START | DT_HAS_STOP | DT_HAS_RESET | DT_HAS_INLINE_CONFIG
814#define DEVTEMPLATE_NAME                "TI99 Peripheral Expansion System"
815#define DEVTEMPLATE_FAMILY              "External devices"
816#include "devtempl.h"
817 
818DEFINE_LEGACY_DEVICE( PBOX, ti99_peb );
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    The third-party myarc geneve and snug sgcpu computers are actually cards
25    to be inserted into a PEB: they have a PC keyboard connector, and replace
26    the original ti-99 console completely.
27
28    Each expansion card is assigned to one of 16 CRU address ranges.
29    I appended the names of known TI peripherals that use each port (I appended
30    '???' when I don't know what the peripheral is :-) ).
31    * 0x1000-0x10FE "For test equipment use on production line"
32    * 0x1100-0x11FE disk controller
33    * 0x1200-0x12FE modem???
34    * 0x1300-0x13FE RS232 1&2, PIO 1
35    * 0x1400-0x14FE unassigned
36    * 0x1500-0x15FE RS232 3&4, PIO 2
37    * 0x1600-0x16FE unassigned
38    * 0x1700-0x17FE hex-bus (prototypes)
39    * 0x1800-0x18FE thermal printer (early peripheral)
40    * 0x1900-0x19FE EPROM programmer??? (Mezzanine board in July 1981's TI99/7
41        prototype)
42    * 0x1A00-0x1AFE unassigned
43    * 0x1B00-0x1BFE TI GPL debugger card
44    * 0x1C00-0x1CFE Video Controller Card (Possibly the weirdest device.  This
45        card is connected to the video output of the computer, to a VCR, and a
46        video monitor.  It can control the VCR, connect the display to either
47        VCR output or computer video output, and it can read or save binary
48        data to video tape.  I think it can act as a genlock interface (i.e.
49        TMS9918 transparent background shows the video signal), too, but I am
50        not sure about this.)
51    * 0x1D00-0x1DFE IEEE 488 Controller Card ('intelligent' parallel bus,
52        schematics on ftp.whtech.com)
53    * 0x1E00-0x1EFE unassigned
54    * 0x1F00-0x1FFE P-code card (part of a complete development system)
55
56    The ti-99/8 implements 16 extra ports:
57    * 0x2000-0x26ff and 0x2800-0x2fff: reserved for future expansion?
58    * 0x2700-0x27ff: internal DSR
59
60    The snug sgcpu 99/4p implements 12 extra ports:
61    * 0x0400-0x0eff: free
62    * 0x0f00-0x0fff: internal DSR
63
64    Known mappings for 3rd party cards:
65    * Horizon RAMdisk: any ports from 0 to 7 (port 0 is most common).
66    * Myarc 128k/512k (RAM and DSR ROM): port 0 (0x1000-0x11FE)
67    * Corcomp 512k (RAM and DSR ROM): port unknown
68    * Super AMS 128k/512k: port 14 (0x1E00-0x1EFE)
69    * Foundation 128k/512k: port 14 (0x1E00-0x1EFE)
70    * Gram Karte: any port (0-15)
71    * EVPC (video card): 0x1400-0x14FE
72    * HSGPL (GROM replacement): 0x1B00-0x1BFE
73
74    Of course, these devices additionally need some support routines, and
75    possibly memory-mapped I/O registers.  To do so, memory range 0x4000-5FFF
76    is shared by all cards.  The system enables each card as needed by writing
77    a 1 to the first CRU bit: when this happens the card can safely enable its
78    ROM, RAM, memory-mapped registers, etc.  Provided the ROM uses the proper
79    ROM header, the system will recognize and call peripheral I/O functions,
80    interrupt service routines, and startup routines.  (All these routines are
81    generally called DSR = Device Service Routine.)
82
83    Also, the cards can trigger level-1 ("INTA") interrupts.  A LOAD interrupt
84    is present on the side port of the ti-99/4(a), too, but it was never used
85    by TI, AFAIK.  Also, an interrupt line called "INTB" is found on several
86    cards built by TI, but it is not connected: I am quite unsure whether it
87    was intended to be connected to the LOAD line, to the INT2 line of TMS9985,
88    or it was only to be used with the ti-99/4(a) development system running on
89    a TI990/10.  This is not the only unused feature: cards built by TI support
90    sensing of an interrupt status register and 19-bit addressing, even though
91    ti-99/4(A) does not take advantage of these features.  TI documentation
92    tells that some of these features are "defined by the Personal Computer PCC
93    at Texas Instrument", which is not very explicit (What on earth does "PCC"
94    stand for?).  Maybe it refers to the ti-99/4(a) development system running
95    on a TI990/10, or to the ti-99/7 and ti-99/8 prototypes.
96
97    Note that I use 8-bit RAM handlers.  Obviously, using 16-bit handlers would
98    be equivalent and faster on a ti-99/4(a), but we need to interface the
99    extension cards not only to the ti-99/4(a), but to the geneve and ti-99/8
100    emulators as well.
101
102    June 2010: Reimplemented using device structure (MZ) (obsoletes 99_peb.c)
103*/
104
105#include "emu.h"
106#include "ti99_peb.h"
107
108enum width_t {
109   width_8bit = 0,
110   width_16bit
111};
112/* expansion card structure for the snug sgcpu 99/4p system, which supports
113dynamical 16-bit accesses (TI did not design this!) */
114typedef struct ti99_4p_peb_card_handlers_t
115{
116   cru_read_handler cru_read;      /* card CRU read handler */
117   cru_write_handler cru_write;   /* card CRU handler */
118
119   width_t width;
120   union
121   {
122      struct
123      {
124         read8_space_func mem_read;      /* card mem read handler (8 bits) */
125         write8_space_func mem_write;   /* card mem write handler (8 bits) */
126      } width_8bit;
127      struct
128      {
129         read16_space_func mem_read;   /* card mem read handler (16 bits) */
130         write16_space_func mem_write;   /* card mem write handler (16 bits) */
131      } width_16bit;
132   } w;
133} ti99_4p_peb_card_handlers_t;
134
135typedef struct _ti99_peb_state
136{
137   /* TRUE if we are using the snug sgcpu 99/4p 16-bit extensions */
138   int has_16bit_peb;
139
140   /* handlers for each of 28 slots */
141   ti99_4p_peb_card_handlers_t ti99_4p_expansion_ports[28];
142
143   /* handlers for each of 16 slots + 16 extra slots for ti-99/8 */
144   ti99_peb_card_handlers_t expansion_ports[16+16];
145
146   /* index of the currently active card (-1 if none) */
147   int active_card;
148
149   /* index of the currently active card, overridden by the mapper */
150   int active_card_tmp;
151
152   /* Mapper override. */
153   int mapper_override;
154
155   // ila: inta status register (not actually used on ti-99/4(a), but nevertheless
156   // present)
157   int ila;
158
159   // ilb: intb status register (completely pointless on ti-99/4(a), as neither
160   // INTB nor SENILB are connected; OTOH, INTB can trigger interrupts on a Geneve,
161   // and snug sgcpu 99/4p can sense ILB)
162   int ilb;
163
164   /* only used by the snug sgcpu 99/4p */
165   int senila, senilb;
166
167   /* hack to simulate TMS9900 byte write */
168   int tmp_buffer;
169
170   /* inta/intb handlers */
171   void (*inta_callback)(running_machine *machine, int state);
172   void (*intb_callback)(running_machine *machine, int state);
173
174   const address_space *space;
175
176} ti99_peb_state;
177
178INLINE ti99_peb_state *get_safe_token(running_device *device)
179{
180   assert(device != NULL);
181   assert(downcast<legacy_device_base *>(device)->token() != NULL);
182   return (ti99_peb_state *)downcast<legacy_device_base *>(device)->token();
183}
184
185INLINE const ti99_peb_config *get_config(running_device *device)
186{
187   assert(device != NULL);
188   assert(device->type() == PBOX);
189   return (const ti99_peb_config *) downcast<const legacy_device_config_base &>(device->baseconfig()).inline_config();
190}
191
192/*
193    Sets the handlers for one expansion port (normal 8-bit card)
194
195    cru_base: CRU base address (any of 0x1000, 0x1100, 0x1200, ..., 0x1F00)
196        (snug sgcpu 99/4p accepts 0x0400, ..., 0x1F00, ti-99/8 accepts 0x1000,
197        ..., 0x2F00)
198    handler: handler structure for the given card
199*/
200void ti99_peb_set_card_handlers(running_device *box, int cru_base, const ti99_peb_card_handlers_t *handler)
201{
202   int port;
203   ti99_peb_state *peb = get_safe_token(box);
204
205   if (cru_base & 0xff)
206      return;
207
208   if (peb->has_16bit_peb)
209   {
210      port = (cru_base - 0x0400) >> 8;
211
212      if ((port>=0) && (port<28))
213      {
214         peb->ti99_4p_expansion_ports[port].cru_read = handler->cru_read;
215         peb->ti99_4p_expansion_ports[port].cru_write = handler->cru_write;
216         peb->ti99_4p_expansion_ports[port].width = width_8bit;
217         peb->ti99_4p_expansion_ports[port].w.width_8bit.mem_read = handler->mem_read;
218         peb->ti99_4p_expansion_ports[port].w.width_8bit.mem_write = handler->mem_write;
219      }
220   }
221   else
222   {
223      port = (cru_base - 0x1000) >> 8;
224
225      if ((port>=0) && (port</*16*/32))
226      {
227         peb->expansion_ports[port] = *handler;
228      }
229   }
230}
231
232/*
233    Sets the handlers for one expansion port (special 16-bit card for snug
234    sgcpu 99/4p)
235
236    cru_base: CRU base address (any of 0x1000, 0x1100, 0x1200, ..., 0x1F00)
237        (snug sgcpu 99/4p accepts 0x0400, ..., 0x1F00, ti-99/8 accepts 0x1000,
238        ..., 0x2F00)
239    handler: handler structure for the given card
240*/
241void ti99_peb_set_16bit_card_handlers(running_device *box, int cru_base, const ti99_peb_16bit_card_handlers_t *handler)
242{
243   int port;
244   ti99_peb_state *peb = get_safe_token(box);
245
246   if (cru_base & 0xff)
247      return;
248
249   if (peb->has_16bit_peb)
250   {
251      port = (cru_base - 0x0400) >> 8;
252
253      if ((port>=0) && (port<28))
254      {
255         peb->ti99_4p_expansion_ports[port].cru_read = handler->cru_read;
256         peb->ti99_4p_expansion_ports[port].cru_write = handler->cru_write;
257         peb->ti99_4p_expansion_ports[port].width = width_16bit;
258         peb->ti99_4p_expansion_ports[port].w.width_16bit.mem_read = handler->mem_read;
259         peb->ti99_4p_expansion_ports[port].w.width_16bit.mem_write = handler->mem_write;
260      }
261   }
262}
263
264/*
265    Update ila status register and assert or clear INTA interrupt line
266    accordingly.
267
268    bit: bit number ([0,7] for original INTA register, [8,15] are extra
269        "virtual" bits for devices that assert the INTA line without setting a
270        bit of the ILA register)
271    state: 1 to assert bit, 0 to clear
272*/
273void ti99_peb_set_ila_bit(running_device *box, int bit, int state)
274{
275   ti99_peb_state *peb = get_safe_token(box);
276   if (state)
277   {
278      peb->ila |= 1 << bit;
279      if (peb->inta_callback)
280         (*peb->inta_callback)(box->machine, 1);
281   }
282   else
283   {
284      peb->ila &= ~(1 << bit);
285      if ((!peb->ila) && peb->inta_callback)
286         (*peb->inta_callback)(box->machine, 0);
287   }
288}
289
290/*
291    Update ilb status register and assert or clear INTB interrupt line
292    accordingly.
293
294    bit: bit number ([0,7] for original INTAB register, [8,15] are extra
295        "virtual" bits for devices that assert the INTB line without setting a
296        bit of the ILB register)
297    state: 1 to assert bit, 0 to clear
298*/
299void ti99_peb_set_ilb_bit(running_device *box, int bit, int state)
300{
301   ti99_peb_state *peb = get_safe_token(box);
302
303   if (state)
304   {
305      peb->ilb |= 1 << bit;
306      if (peb->intb_callback)
307         (*peb->intb_callback)(box->machine, 1);
308   }
309   else
310   {
311      peb->ilb &= ~(1 << bit);
312      if ((!peb->ilb) && peb->intb_callback)
313         (*peb->intb_callback)(box->machine, 0);
314   }
315}
316
317
318/*
319    Read CRU in range >1000->1ffe (>800->fff) (ti-99/4(a))
320*/
321READ8_DEVICE_HANDLER( ti99_4x_peb_cru_r )
322{
323   int port;
324   cru_read_handler handler;
325   int reply;
326   ti99_peb_state *peb = get_safe_token(device);
327
328   port = (offset & 0x00f0) >> 4;
329   handler = peb->expansion_ports[port].cru_read;
330
331   reply = (handler) ? (*handler)(device->machine, offset & 0xf) : 0;
332
333   return reply;
334}
335
336/*
337    Write CRU in range >1000->1ffe (>800->fff) (ti-99/4(a))
338*/
339WRITE8_DEVICE_HANDLER( ti99_4x_peb_cru_w )
340{
341   int port;
342   cru_write_handler handler;
343   ti99_peb_state *peb = get_safe_token(device);
344
345   port = (offset & 0x0780) >> 7;
346   handler = peb->expansion_ports[port].cru_write;
347
348   if (handler)
349      (*handler)(device->machine, offset & 0x7f, data);
350
351   /* expansion card enable? */
352   if ((offset & 0x7f) == 0)
353   {
354      if (data & 1)
355      {
356         /* enable */
357         peb->active_card = port;
358      }
359      else
360      {
361         if (port == peb->active_card)   /* geez... who cares? */
362         {
363            peb->active_card = -1;         /* no port selected */
364         }
365      }
366   }
367}
368
369/*
370    Read mem in range >4000->5ffe (ti-99/4(a))
371*/
372READ16_DEVICE_HANDLER( ti99_4x_peb_r )
373{
374   int reply = 0;
375   read8_space_func handler;
376   ti99_peb_state *peb = get_safe_token(device);
377
378   cpu_adjust_icount(device->machine->firstcpu,-4);
379
380   if (peb->active_card != -1)
381   {
382      handler = peb->expansion_ports[peb->active_card].mem_read;
383      if (handler)
384      {
385         reply = (*handler)(peb->space, (offset << 1) + 1);
386         reply |= ((unsigned) (*handler)(peb->space, offset << 1)) << 8;
387      }
388   }
389//  printf("[%04x:%04x] = %04x\n", (active_card<<8)+0x1000, (offset<<1)+0x4000, reply);
390
391   return peb->tmp_buffer = reply;
392}
393
394/*
395    Write mem in range >4000->5ffe (ti-99/4(a))
396*/
397WRITE16_DEVICE_HANDLER( ti99_4x_peb_w )
398{
399   write8_space_func handler;
400   ti99_peb_state *peb = get_safe_token(device);
401
402   cpu_adjust_icount(device->machine->firstcpu,-4);
403
404   /* simulate byte write */
405   data = (peb->tmp_buffer & ~mem_mask) | (data & mem_mask);
406
407   if (peb->active_card != -1)
408   {
409      handler = peb->expansion_ports[peb->active_card].mem_write;
410      if (handler)
411      {
412         (*handler)(peb->space, (offset << 1) + 1, data & 0xff);
413         (*handler)(peb->space, offset << 1, (data >> 8) & 0xff);
414      }
415   }
416}
417
418
419/*
420    Read CRU in range >1000->1ffe (>800->fff) (Geneve)
421*/
422READ8_DEVICE_HANDLER( geneve_peb_cru_r )
423{
424   int port;
425   cru_read_handler handler;
426   int reply;
427   ti99_peb_state *peb = get_safe_token(device);
428
429   port = (offset & 0x00f0) >> 4;
430   handler = peb->expansion_ports[port].cru_read;
431
432   reply = (handler) ? (*handler)(device->machine, offset & 0xf) : 0;
433
434   return reply;
435}
436
437/*
438    Write CRU in range >1000->1ffe (>800->fff) (Geneve)
439*/
440WRITE8_DEVICE_HANDLER( geneve_peb_cru_w )
441{
442   int port;
443   cru_write_handler handler;
444   ti99_peb_state *peb = get_safe_token(device);
445
446   port = (offset & 0x0780) >> 7;
447   handler = peb->expansion_ports[port].cru_write;
448
449   if (handler)
450      (*handler)(device->machine, offset & 0x7f, data);
451
452   /* expansion card enable? */
453   if ((offset & 0x7f) == 0)
454   {
455      if (data & 1)
456      {
457         /* enable */
458         peb->active_card = port;
459      }
460      else
461      {
462         if (port == peb->active_card)   /* geez... who cares? */
463         {
464            peb->active_card = -1;         /* no port selected */
465         }
466      }
467   }
468}
469
470/*
471    Read mem in range >4000->5fff (Geneve)
472*/
473READ8_DEVICE_HANDLER( geneve_peb_r )
474{
475   int reply = 0;
476   read8_space_func handler;
477   ti99_peb_state *peb = get_safe_token(device);
478
479   cpu_adjust_icount(device->machine->firstcpu,-8);
480
481   if (peb->active_card != -1)
482   {
483      handler = peb->expansion_ports[peb->active_card].mem_read;
484      if (handler)
485         reply = (*handler)(peb->space, offset);
486   }
487
488   return reply;
489}
490
491/*
492    Write mem in range >4000->5fff (Geneve)
493*/
494WRITE8_DEVICE_HANDLER( geneve_peb_w )
495{
496   write8_space_func handler;
497   ti99_peb_state *peb = get_safe_token(device);
498
499   cpu_adjust_icount(device->machine->firstcpu,-8);
500
501   if (peb->active_card != -1)
502   {
503      handler = peb->expansion_ports[peb->active_card].mem_write;
504      if (handler)
505         (*handler)(peb->space, offset, data);
506   }
507}
508
509/*
510    Read CRU in range >1000->2ffe (>0800->17ff) (ti-99/8)
511*/
512READ8_DEVICE_HANDLER( ti99_8_peb_cru_r )
513{
514   int port;
515   cru_read_handler handler;
516   int reply;
517   ti99_peb_state *peb = get_safe_token(device);
518
519   port = (offset & 0x01f0) >> 4;
520   handler = peb->expansion_ports[port].cru_read;
521
522   reply = (handler) ? (*handler)(device->machine, offset & 0xf) : 0;
523
524   return reply;
525}
526
527/*
528    Write CRU in range >1000->2ffe (>0800->17ff) (ti-99/8)
529*/
530WRITE8_DEVICE_HANDLER( ti99_8_peb_cru_w )
531{
532   int port;
533   cru_write_handler handler;
534   ti99_peb_state *peb = get_safe_token(device);
535
536   port = (offset & 0x0f80) >> 7;
537   handler = peb->expansion_ports[port].cru_write;
538
539   if (handler)
540      (*handler)(device->machine, offset & 0x7f, data);
541
542   /* expansion card enable? */
543   if ((offset & 0x7f) == 0)
544   {
545      if (data & 1)
546      {
547         /* enable */
548         peb->active_card = port;
549      }
550      else
551      {
552         if (port == peb->active_card)   /* geez... who cares? */
553         {
554            peb->active_card = -1;         /* no port selected */
555         }
556      }
557   }
558}
559
560/*
561    Read mem in range >4000->5fff (ti-99/8)
562*/
563READ8_DEVICE_HANDLER( ti99_8_peb_r )
564{
565   int reply = 0;
566   read8_space_func handler;
567   ti99_peb_state *peb = get_safe_token(device);
568
569   cpu_adjust_icount(device->machine->firstcpu,-4);
570
571   if (peb->active_card != -1)
572   {
573      handler = peb->expansion_ports[peb->active_card].mem_read;
574      if (handler)
575         reply = (*handler)(peb->space, offset);
576   }
577
578   return reply;
579}
580
581/*
582    Write mem in range >4000->5fff (ti-99/8)
583*/
584WRITE8_DEVICE_HANDLER( ti99_8_peb_w )
585{
586   write8_space_func handler;
587   ti99_peb_state *peb = get_safe_token(device);
588
589   cpu_adjust_icount(device->machine->firstcpu,-4);
590
591   if (peb->active_card != -1)
592   {
593      handler = peb->expansion_ports[peb->active_card].mem_write;
594      if (handler)
595         (*handler)(peb->space, offset, data);
596   }
597}
598
599/*
600    Read CRU in range >0400->1ffe (>200->fff) (snug sgcpu 99/4p)
601*/
602READ8_DEVICE_HANDLER( ti99_4p_peb_cru_r )
603{
604   int port;
605   cru_read_handler handler;
606   int reply;
607   ti99_peb_state *peb = get_safe_token(device);
608
609   port = offset >> 4;
610   handler = peb->ti99_4p_expansion_ports[port].cru_read;
611
612   reply = (handler) ? (*handler)(device->machine, offset & 0xf) : 0;
613
614   return reply;
615}
616
617/*
618    Write CRU in range >0400->1ffe (>200->fff) (snug sgcpu 99/4p)
619*/
620WRITE8_DEVICE_HANDLER( ti99_4p_peb_cru_w )
621{
622   int port;
623   cru_write_handler handler;
624   ti99_peb_state *peb = get_safe_token(device);
625
626   int cru_address = (offset + 0x200)<<1;
627
628   port = offset >> 7;
629   handler = peb->ti99_4p_expansion_ports[port].cru_write;
630
631   if (handler)
632      (*handler)(device->machine, offset & 0x7f, data);
633
634   /* expansion card enable? */
635   if ((cru_address & 0xfe) == 0)
636   {
637      if (data & 1)
638      {
639         /* enable */
640         if (cru_address == 0x1e00)
641         {
642            // The internal mapper has precedence over the external bus.
643            // It may be turned on although there is another device currently turned on
644            peb->active_card_tmp = peb->active_card;
645            peb->mapper_override = TRUE;
646         }
647         peb->active_card = port;
648      }
649      else
650      {
651         if ((cru_address == 0x1e00) && peb->mapper_override)
652         {
653            peb->active_card = peb->active_card_tmp;
654            peb->mapper_override = FALSE;
655         }
656         else
657         {
658            if (port == peb->active_card)   /* geez... who cares? */
659            {
660               peb->active_card = -1;         /* no port selected */
661            }
662         }
663      }
664   }
665}
666
667/*
668    Read mem in range >4000->5ffe (snug sgcpu 99/4p)
669*/
670READ16_DEVICE_HANDLER( ti99_4p_peb_r )
671{
672   int reply = 0;
673   read8_space_func handler;
674   read16_space_func handler16;
675   ti99_peb_state *peb = get_safe_token(device);
676
677   if (peb->active_card == -1)
678      cpu_adjust_icount(device->machine->firstcpu,-4);   /* ??? */
679   else
680   {
681      if (peb->ti99_4p_expansion_ports[peb->active_card].width == width_8bit)
682      {
683         cpu_adjust_icount(device->machine->firstcpu,-4);
684
685         handler = peb->ti99_4p_expansion_ports[peb->active_card].w.width_8bit.mem_read;
686         if (handler)
687         {
688            reply = (*handler)(peb->space, (offset << 1) + 1);
689            reply |= ((unsigned) (*handler)(peb->space, offset << 1)) << 8;
690         }
691      }
692      else
693      {
694         cpu_adjust_icount(device->machine->firstcpu,-1);   /* ??? */
695
696         handler16 = peb->ti99_4p_expansion_ports[peb->active_card].w.width_16bit.mem_read;
697         if (handler16)
698            reply = (*handler16)(peb->space, offset, /*mem_mask*/0xffff);
699      }
700   }
701
702   if (peb->senila || peb->senilb)
703   {
704      if ((peb->active_card != -1) || (peb->senila && peb->senilb))
705         /* ah, the smell of burnt silicon... */
706         logerror("<Scrrrrr>: your computer has just burnt (maybe).\n");
707
708      if (peb->senila)
709         reply = (peb->ila & 0xff) | (peb->ila << 8);
710      else if (peb->senilb)
711         reply = (peb->ilb & 0xff) | (peb->ilb << 8);
712   }
713
714//  printf("[%04x:%04x] = %04x\n", (active_card<<8)+0x400, (offset<<1)+0x4000, reply);
715   return peb->tmp_buffer = reply;
716}
717
718/*
719    Write mem in range >4000->5ffe (snug sgcpu 99/4p)
720*/
721WRITE16_DEVICE_HANDLER( ti99_4p_peb_w )
722{
723   write8_space_func handler;
724   write16_space_func handler16;
725   ti99_peb_state *peb = get_safe_token(device);
726
727   if (peb->active_card == -1)
728      cpu_adjust_icount(device->machine->firstcpu,-4);   /* ??? */
729   else
730   {
731      /* simulate byte write */
732      data = (peb->tmp_buffer & ~mem_mask) | (data & mem_mask);
733
734      if (peb->ti99_4p_expansion_ports[peb->active_card].width == width_8bit)
735      {
736         cpu_adjust_icount(device->machine->firstcpu,-4);
737
738         handler = peb->ti99_4p_expansion_ports[peb->active_card].w.width_8bit.mem_write;
739         if (handler)
740         {
741            (*handler)(peb->space, (offset << 1) + 1, data & 0xff);
742            (*handler)(peb->space, offset << 1, (data >> 8) & 0xff);
743         }
744      }
745      else
746      {
747         cpu_adjust_icount(device->machine->firstcpu,-1);   /* ??? */
748
749         handler16 = peb->ti99_4p_expansion_ports[peb->active_card].w.width_16bit.mem_write;
750         if (handler16)
751            (*handler16)(peb->space, offset, data, /*mem_mask*/0xffff);
752      }
753   }
754}
755
756/*
757    Set the state of the SENILA line (snug sgcpu 99/4p)
758*/
759void ti99_4p_peb_set_senila(running_device *box, int state)
760{
761   ti99_peb_state *peb = get_safe_token(box);
762   peb->senila = (state != 0);
763}
764
765/*
766    Set the state of the SENILB line (snug sgcpu 99/4p)
767*/
768void ti99_4p_peb_set_senilb(running_device *box, int state)
769{
770   ti99_peb_state *peb = get_safe_token(box);
771   peb->senilb = (state != 0);
772}
773
774
775/***************************************************************************
776    DEVICE FUNCTIONS
777***************************************************************************/
778
779static DEVICE_START( ti99_peb )
780{
781}
782
783static DEVICE_STOP( ti99_peb )
784{
785}
786
787static DEVICE_RESET( ti99_peb )
788{
789   ti99_peb_state *peb = get_safe_token(device);
790
791   peb->has_16bit_peb = get_config(device)->mode16;
792   peb->inta_callback = get_config(device)->inta_callback;
793   peb->intb_callback = get_config(device)->intb_callback;
794
795   peb->active_card = -1;
796   peb->active_card_tmp = -1;
797
798   peb->mapper_override = FALSE; // for ti99_4p
799
800   peb->ila = 0;
801   peb->ilb = 0;
802
803   peb->space = cputag_get_address_space(device->machine, "maincpu", ADDRESS_SPACE_PROGRAM);
804
805   // Remove all card handlers; must be reinstalled
806   memset(peb->expansion_ports, 0, sizeof(peb->expansion_ports));
807   memset(peb->ti99_4p_expansion_ports, 0, sizeof(peb->ti99_4p_expansion_ports));
808}
809
810static const char DEVTEMPLATE_SOURCE[] = __FILE__;
811
812#define DEVTEMPLATE_ID(p,s)             p##ti99_peb##s
813#define DEVTEMPLATE_FEATURES            DT_HAS_START | DT_HAS_STOP | DT_HAS_RESET | DT_HAS_INLINE_CONFIG
814#define DEVTEMPLATE_NAME                "TI99 Peripheral Expansion System"
815#define DEVTEMPLATE_FAMILY              "External devices"
816#include "devtempl.h"
817
818DEFINE_LEGACY_DEVICE( PBOX, ti99_peb );
src/mess/devices/ti99_peb.h
r8681r8682
1/*
2    header file for machine/99_peb.c
3*/
4 
5/*
6    mode16: TRUE if we are using the snug sgcpu 99/4p 16-bit extensions
7    inta_callback: callback called when the state of INTA changes (may be NULL)
8    intb_callback: callback called when the state of INTB changes (may be NULL)
9*/
10typedef struct _ti99_peb_config ti99_peb_config;
11struct _ti99_peb_config
12{
13   int      mode16;
14   void   (*inta_callback)(running_machine *machine, int state);
15   void   (*intb_callback)(running_machine *machine, int state);
16 
17};
18 
19/*
20    prototype for CRU handlers in expansion system
21*/
22typedef int (*cru_read_handler)(running_machine *machine, int offset);
23typedef void (*cru_write_handler)(running_machine *machine, int offset, int data);
24 
25/*
26    Descriptor for TI peripheral expansion cards (8-bit bus)
27*/
28typedef struct ti99_peb_card_handlers_t
29{
30   cru_read_handler cru_read;      /* card CRU read handler */
31   cru_write_handler cru_write;   /* card CRU handler */
32 
33   read8_space_func mem_read;      /* card mem read handler (8 bits) */
34   write8_space_func mem_write;   /* card mem write handler (8 bits) */
35} ti99_peb_card_handlers_t;
36 
37/*
38    Descriptor for 16-bit peripheral expansion cards designed for the snug
39    sgcpu 99/4p system.  (These cards were not designed by TI, TI always
40    regarded the ti-99 as an 8-bit system.)
41*/
42typedef struct ti99_peb_16bit_card_handlers_t
43{
44   cru_read_handler cru_read;      /* card CRU read handler */
45   cru_write_handler cru_write;   /* card CRU handler */
46 
47   read16_space_func mem_read;      /* card mem read handler (16 bits) */
48   write16_space_func mem_write;      /* card mem write handler (16 bits) */
49} ti99_peb_16bit_card_handlers_t;
50 
51/* masks for ila and ilb */
52enum
53{
54   /* bits from actual ILA register */
55   inta_rs232_1_bit = 7-0,
56   inta_rs232_2_bit = 7-1,
57   inta_rs232_3_bit = 7-4,
58   inta_rs232_4_bit = 7-5,
59 
60   /* extra "virtual" bits for devices that assert the INTA line without
61    setting a bit of the ILA register */
62   inta_ide_bit     = 8,
63   inta_ide_clk_bit = 9,
64 
65   /* bits from actual ILB register */
66   intb_fdc_bit     = 7-0,
67   intb_ieee488_bit = 7-1
68};
69 
70void ti99_peb_set_card_handlers(running_device *box, int cru_base, const ti99_peb_card_handlers_t *handler);
71void ti99_peb_set_16bit_card_handlers(running_device *box, int cru_base, const ti99_peb_16bit_card_handlers_t *handler);
72void ti99_peb_set_ila_bit(running_device *box, int bit, int state);
73void ti99_peb_set_ilb_bit(running_device *box, int bit, int state);
74 
75READ8_DEVICE_HANDLER( ti99_4x_peb_cru_r );
76WRITE8_DEVICE_HANDLER( ti99_4x_peb_cru_w );
77READ16_DEVICE_HANDLER( ti99_4x_peb_r );
78WRITE16_DEVICE_HANDLER( ti99_4x_peb_w );
79 
80READ8_DEVICE_HANDLER( geneve_peb_cru_r );
81WRITE8_DEVICE_HANDLER( geneve_peb_cru_w );
82READ8_DEVICE_HANDLER( geneve_peb_r );
83WRITE8_DEVICE_HANDLER( geneve_peb_w );
84 
85READ8_DEVICE_HANDLER( ti99_8_peb_cru_r );
86WRITE8_DEVICE_HANDLER( ti99_8_peb_cru_w );
87READ8_DEVICE_HANDLER( ti99_8_peb_r );
88WRITE8_DEVICE_HANDLER( ti99_8_peb_w );
89 
90READ8_DEVICE_HANDLER( ti99_4p_peb_cru_r );
91WRITE8_DEVICE_HANDLER( ti99_4p_peb_cru_w );
92READ16_DEVICE_HANDLER( ti99_4p_peb_r );
93WRITE16_DEVICE_HANDLER( ti99_4p_peb_w );
94 
95void ti99_4p_peb_set_senila(running_device *box, int state);
96void ti99_4p_peb_set_senilb(running_device *box, int state);
97 
98/* device interface */
99DECLARE_LEGACY_DEVICE( PBOX, ti99_peb );
100 
101#define MDRV_PBOX_ADD(_tag, _mode16, _inta, _intb)         \
102   MDRV_DEVICE_ADD(_tag, PBOX, 0)                     \
103   MDRV_DEVICE_CONFIG_DATA32(ti99_peb_config, mode16, _mode16)   \
104   MDRV_DEVICE_CONFIG_DATAPTR(ti99_peb_config, inta_callback, _inta)   \
105   MDRV_DEVICE_CONFIG_DATAPTR(ti99_peb_config, intb_callback, _intb)
106 
107 
1/*
2    header file for machine/99_peb.c
3*/
4
5/*
6    mode16: TRUE if we are using the snug sgcpu 99/4p 16-bit extensions
7    inta_callback: callback called when the state of INTA changes (may be NULL)
8    intb_callback: callback called when the state of INTB changes (may be NULL)
9*/
10typedef struct _ti99_peb_config ti99_peb_config;
11struct _ti99_peb_config
12{
13   int      mode16;
14   void   (*inta_callback)(running_machine *machine, int state);
15   void   (*intb_callback)(running_machine *machine, int state);
16
17};
18
19/*
20    prototype for CRU handlers in expansion system
21*/
22typedef int (*cru_read_handler)(running_machine *machine, int offset);
23typedef void (*cru_write_handler)(running_machine *machine, int offset, int data);
24
25/*
26    Descriptor for TI peripheral expansion cards (8-bit bus)
27*/
28typedef struct ti99_peb_card_handlers_t
29{
30   cru_read_handler cru_read;      /* card CRU read handler */
31   cru_write_handler cru_write;   /* card CRU handler */
32
33   read8_space_func mem_read;      /* card mem read handler (8 bits) */
34   write8_space_func mem_write;   /* card mem write handler (8 bits) */
35} ti99_peb_card_handlers_t;
36
37/*
38    Descriptor for 16-bit peripheral expansion cards designed for the snug
39    sgcpu 99/4p system.  (These cards were not designed by TI, TI always
40    regarded the ti-99 as an 8-bit system.)
41*/
42typedef struct ti99_peb_16bit_card_handlers_t
43{
44   cru_read_handler cru_read;      /* card CRU read handler */
45   cru_write_handler cru_write;   /* card CRU handler */
46
47   read16_space_func mem_read;      /* card mem read handler (16 bits) */
48   write16_space_func mem_write;      /* card mem write handler (16 bits) */
49} ti99_peb_16bit_card_handlers_t;
50
51/* masks for ila and ilb */
52enum
53{
54   /* bits from actual ILA register */
55   inta_rs232_1_bit = 7-0,
56   inta_rs232_2_bit = 7-1,
57   inta_rs232_3_bit = 7-4,
58   inta_rs232_4_bit = 7-5,
59
60   /* extra "virtual" bits for devices that assert the INTA line without
61    setting a bit of the ILA register */
62   inta_ide_bit     = 8,
63   inta_ide_clk_bit = 9,
64
65   /* bits from actual ILB register */
66   intb_fdc_bit     = 7-0,
67   intb_ieee488_bit = 7-1
68};
69
70void ti99_peb_set_card_handlers(running_device *box, int cru_base, const ti99_peb_card_handlers_t *handler);
71void ti99_peb_set_16bit_card_handlers(running_device *box, int cru_base, const ti99_peb_16bit_card_handlers_t *handler);
72void ti99_peb_set_ila_bit(running_device *box, int bit, int state);
73void ti99_peb_set_ilb_bit(running_device *box, int bit, int state);
74
75READ8_DEVICE_HANDLER( ti99_4x_peb_cru_r );
76WRITE8_DEVICE_HANDLER( ti99_4x_peb_cru_w );
77READ16_DEVICE_HANDLER( ti99_4x_peb_r );
78WRITE16_DEVICE_HANDLER( ti99_4x_peb_w );
79
80READ8_DEVICE_HANDLER( geneve_peb_cru_r );
81WRITE8_DEVICE_HANDLER( geneve_peb_cru_w );
82READ8_DEVICE_HANDLER( geneve_peb_r );
83WRITE8_DEVICE_HANDLER( geneve_peb_w );
84
85READ8_DEVICE_HANDLER( ti99_8_peb_cru_r );
86WRITE8_DEVICE_HANDLER( ti99_8_peb_cru_w );
87READ8_DEVICE_HANDLER( ti99_8_peb_r );
88WRITE8_DEVICE_HANDLER( ti99_8_peb_w );
89
90READ8_DEVICE_HANDLER( ti99_4p_peb_cru_r );
91WRITE8_DEVICE_HANDLER( ti99_4p_peb_cru_w );
92READ16_DEVICE_HANDLER( ti99_4p_peb_r );
93WRITE16_DEVICE_HANDLER( ti99_4p_peb_w );
94
95void ti99_4p_peb_set_senila(running_device *box, int state);
96void ti99_4p_peb_set_senilb(running_device *box, int state);
97
98/* device interface */
99DECLARE_LEGACY_DEVICE( PBOX, ti99_peb );
100
101#define MDRV_PBOX_ADD(_tag, _mode16, _inta, _intb)         \
102   MDRV_DEVICE_ADD(_tag, PBOX, 0)                     \
103   MDRV_DEVICE_CONFIG_DATA32(ti99_peb_config, mode16, _mode16)   \
104   MDRV_DEVICE_CONFIG_DATAPTR(ti99_peb_config, inta_callback, _inta)   \
105   MDRV_DEVICE_CONFIG_DATAPTR(ti99_peb_config, intb_callback, _intb)
106
107
src/mess/tools/imgtool/modules/cybikoxt.c
r8681r8682
1/*
2 
3    Cybiko Xtreme File System
4 
5    (c) 2010 Tim Schuerewegen
6 
7*/
8 
9#include "imgtool.h"
10 
11#include <zlib.h>
12 
13typedef struct _cybiko_file_system cybiko_file_system;
14struct _cybiko_file_system
15{
16   imgtool_stream *stream;
17   UINT32 page_count, page_size, block_count_boot, block_count_file;
18   UINT16 write_count;
19};
20 
21typedef struct _cybiko_iter cybiko_iter;
22struct _cybiko_iter
23{
24   UINT16 block;
25};
26 
27typedef struct _cfs_file cfs_file;
28struct _cfs_file
29{
30   char name[64]; // name of the file
31   UINT32 date;   // date/time of the file (seconds since 1900/01/01)
32   UINT32 size;   // size of the file
33   UINT32 blocks; // number of blocks occupied by the file
34};
35 
36enum
37{
38   BLOCK_TYPE_INVALID,
39   BLOCK_TYPE_BOOT,
40   BLOCK_TYPE_FILE
41};
42 
43#define   MAX_PAGE_SIZE (264 * 2)
44 
45#define INVALID_FILE_ID  0xFFFF
46 
47#define BLOCK_USED(x)      (x[0] & 0x80)
48#define BLOCK_FILE_ID(x)   buffer_read_16_be( x + 2)
49#define BLOCK_PART_ID(x)   buffer_read_16_be( x + 4)
50#define BLOCK_FILENAME(x)  (char*)(x + 7)
51 
52#define FILE_HEADER_SIZE  0x48
53 
54// 2208988800 is the number of seconds between 1900/01/01 and 1970/01/01
55 
56static time_t time_crack( UINT32 cfs_time)
57{
58   return (time_t)(cfs_time - 2208988800UL);
59}
60 
61static UINT32 time_setup( time_t ansi_time)
62{
63   return (UINT32)(ansi_time + 2208988800UL);
64}
65 
66static UINT32 buffer_read_32_be( UINT8 *buffer)
67{
68   return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | (buffer[3] << 0);
69}
70 
71static UINT16 buffer_read_16_be( UINT8 *buffer)
72{
73   return (buffer[0] << 8) | (buffer[1] << 0);
74}
75 
76static void buffer_write_32_be( UINT8 *buffer, UINT32 data)
77{
78   buffer[0] = (data >> 24) & 0xFF;
79   buffer[1] = (data >> 16) & 0xFF;
80   buffer[2] = (data >>  8) & 0xFF;
81   buffer[3] = (data >>  0) & 0xFF;
82}
83 
84static void buffer_write_16_be( UINT8 *buffer, UINT16 data)
85{
86   buffer[0] = (data >> 8) & 0xFF;
87   buffer[1] = (data >> 0) & 0xFF;
88}
89 
90// page = crc (2) + data (x)
91 
92static UINT16 page_buffer_calc_checksum( UINT8 *data, UINT32 size)
93{
94   int i;
95   UINT32 val = 0;
96   for (i = 0; i < size; i++)
97   {
98      val = (val ^ data[i] ^ i) << 1;
99      val = val | ((val >> 16) & 0x0001);
100   }
101   return val;
102}
103 
104static int page_buffer_verify( UINT8 *buffer, UINT32 size, int block_type)
105{
106   // checksum
107   if (block_type == BLOCK_TYPE_FILE)
108   {
109      UINT32 checksum_page, checksum_calc;
110      checksum_calc = page_buffer_calc_checksum( buffer + 2, size - 2);
111      checksum_page = buffer_read_16_be( buffer + 0);
112      if (checksum_calc != checksum_page) return FALSE;
113   }
114   // ok
115   return TRUE;
116}
117 
118static int cfs_block_to_page( cybiko_file_system *cfs, int block_type, UINT32 block, UINT32 *page)
119{
120   switch (block_type)
121   {
122      case BLOCK_TYPE_BOOT : if (page) *page = block; return TRUE;
123      case BLOCK_TYPE_FILE : if (page) *page = block + cfs->block_count_boot; return TRUE;
124      default              : return FALSE;
125   }
126}
127 
128static int cfs_page_to_block( cybiko_file_system *cfs, UINT32 page, int *block_type, UINT32 *block)
129{
130   UINT32 tmp = page;
131   // boot block
132   if (tmp < cfs->block_count_boot)
133   {
134      if (block_type) *block_type = BLOCK_TYPE_BOOT;
135      if (block) *block = tmp;
136      return TRUE;
137   }
138   tmp -= cfs->block_count_boot;
139   // file block
140   if (tmp < cfs->block_count_file)
141   {
142      if (block_type) *block_type = BLOCK_TYPE_FILE;
143      if (block) *block = tmp;
144      return TRUE;
145   }
146   tmp -= cfs->block_count_file;
147   // error
148   return FALSE;
149}
150 
151static int cfs_page_read( cybiko_file_system *cfs, UINT8 *buffer, UINT32 page)
152{
153   if (page >= cfs->page_count) return FALSE;
154   stream_seek( cfs->stream, page * cfs->page_size, SEEK_SET);
155   stream_read( cfs->stream, buffer, cfs->page_size);
156   return TRUE;
157}
158 
159static int cfs_page_write( cybiko_file_system *cfs, UINT8 *buffer, UINT32 page)
160{
161   if (page >= cfs->page_count) return FALSE;
162   stream_seek( cfs->stream, page * cfs->page_size, SEEK_SET);
163   stream_write( cfs->stream, buffer, cfs->page_size);
164   return TRUE;
165}
166 
167static int cfs_block_read( cybiko_file_system *cfs, UINT8 *buffer, int block_type, UINT32 block)
168{
169   UINT8 buffer_page[MAX_PAGE_SIZE];
170   UINT32 page;
171   if (!cfs_block_to_page( cfs, block_type, block, &page)) return FALSE;
172   if (!cfs_page_read( cfs, buffer_page, page)) return FALSE;
173   memcpy( buffer, buffer_page + 2, cfs->page_size - 2);
174   return TRUE;
175}
176 
177static int cfs_block_write( cybiko_file_system *cfs, UINT8 *buffer, int block_type, UINT32 block)
178{
179   UINT8 buffer_page[MAX_PAGE_SIZE];
180   UINT32 page;
181   UINT16 checksum;
182   memcpy( buffer_page + 2, buffer, cfs->page_size - 2);
183   if (block_type == BLOCK_TYPE_BOOT)
184   {
185      checksum = 0xFFFF;
186   }
187   else
188   {
189      checksum = page_buffer_calc_checksum( buffer_page + 2, cfs->page_size - 2);
190   }
191   buffer_write_16_be( buffer_page + 0, checksum);
192   if (!cfs_block_to_page( cfs, block_type, block, &page)) return FALSE;
193   if (!cfs_page_write( cfs, buffer_page, page)) return FALSE;
194   return TRUE;
195}
196 
197static int cfs_file_delete( cybiko_file_system *cfs, UINT16 file_id)
198{
199   UINT8 buffer[MAX_PAGE_SIZE];
200   int i;
201   for (i=0;i<cfs->block_count_file;i++)
202   {
203      if (!cfs_block_read( cfs, buffer, BLOCK_TYPE_FILE, i)) return FALSE;
204      if (BLOCK_USED(buffer) && (BLOCK_FILE_ID(buffer) == file_id))
205      {
206         buffer[0] &= ~0x80;
207         if (!cfs_block_write( cfs, buffer, BLOCK_TYPE_FILE, i)) return FALSE;
208      }
209   }
210   return TRUE;
211}
212 
213static int cfs_file_info( cybiko_file_system *cfs, UINT16 file_id, cfs_file *file)
214{
215   UINT8 buffer[MAX_PAGE_SIZE];
216   int i;
217   file->blocks = file->size = 0;
218   for (i=0;i<cfs->block_count_file;i++)
219   {
220      if (!cfs_block_read( cfs, buffer, BLOCK_TYPE_FILE, i)) return FALSE;
221      if (BLOCK_USED(buffer) && (BLOCK_FILE_ID(buffer) == file_id))
222      {
223         if (BLOCK_PART_ID(buffer) == 0)
224         {
225            strcpy( file->name, BLOCK_FILENAME(buffer));
226            file->date = buffer_read_32_be( buffer + 6 + FILE_HEADER_SIZE - 4);
227         }
228         file->size += buffer[1];
229         file->blocks++;
230      }
231   }
232   return (file->blocks > 0) ? TRUE : FALSE;
233}
234 
235static int cfs_file_find( cybiko_file_system *cfs, const char *filename, UINT16 *file_id)
236{
237   UINT8 buffer[MAX_PAGE_SIZE];
238   int i;
239   for (i=0;i<cfs->block_count_file;i++)
240   {
241      if (!cfs_block_read( cfs, buffer, BLOCK_TYPE_FILE, i)) return FALSE;
242      if (BLOCK_USED(buffer) && (BLOCK_PART_ID(buffer) == 0) && (strcmp( filename, BLOCK_FILENAME(buffer)) == 0))
243      {
244         *file_id = i;
245         return TRUE;
246      }
247   }
248   return FALSE;
249}
250 
251static int cfs_verify( cybiko_file_system *cfs)
252{
253   UINT8 buffer[MAX_PAGE_SIZE];
254   int i, block_type;
255   for (i=0;i<cfs->page_count;i++)
256   {
257      if (!cfs_page_read( cfs, buffer, i)) return FALSE;
258      if (!cfs_page_to_block( cfs, i, &block_type, NULL)) return FALSE;
259      if (!page_buffer_verify( buffer, cfs->page_size, block_type)) return FALSE;
260   }
261   return TRUE;
262}
263 
264static int cfs_init( cybiko_file_system *cfs, imgtool_stream *stream)
265{
266   cfs->stream = stream;
267   cfs->page_count = 2005;
268   cfs->page_size = 258;
269   cfs->block_count_boot = 5;
270   cfs->block_count_file = cfs->page_count - cfs->block_count_boot;
271   cfs->write_count = 0;
272   return TRUE;
273}
274 
275static int cfs_format( cybiko_file_system *cfs)
276{
277   UINT8 buffer[MAX_PAGE_SIZE];
278   int i;
279   // boot blocks
280   memset( buffer, 0xFF, sizeof( buffer));
281   for (i=0;i<cfs->block_count_boot;i++)
282   {
283      if (!cfs_block_write( cfs, buffer, BLOCK_TYPE_BOOT, i)) return FALSE;
284   }
285   // file blocks
286   memset( buffer, 0xFF, sizeof( buffer));
287   buffer[0] &= ~0x80;
288   for (i=0;i<cfs->block_count_file;i++)
289   {
290      if (!cfs_block_write( cfs, buffer, BLOCK_TYPE_FILE, i)) return FALSE;
291   }
292   // padding
293   buffer[0] = 0xFF;
294   for (i=0;i<0x1B56;i++)
295   {
296      stream_write( cfs->stream, buffer, 1);
297   }
298   // ok
299   return TRUE;
300}
301 
302static UINT16 cfs_calc_free_blocks( cybiko_file_system *cfs)
303{
304   UINT8 buffer[MAX_PAGE_SIZE];
305   int i;
306   UINT16 blocks = 0;
307   for (i=0;i<cfs->block_count_file;i++)
308   {
309      if (!cfs_block_read( cfs, buffer, BLOCK_TYPE_FILE, i)) return 0;
310      if (!BLOCK_USED(buffer)) blocks++;
311   }
312   return blocks;
313}
314 
315static UINT32 cfs_calc_free_space( cybiko_file_system *cfs, UINT16 blocks)
316{
317   UINT32 free_space;
318   free_space = blocks * ((cfs->page_size - 2) - 6);
319   if (free_space > 0) free_space -= FILE_HEADER_SIZE;
320   return free_space;
321}
322 
323static imgtoolerr_t cybiko_image_open( imgtool_image *image, imgtool_stream *stream)
324{
325   cybiko_file_system *cfs = (cybiko_file_system*)imgtool_image_extra_bytes( image);
326   // init
327   if (!cfs_init( cfs, stream)) return IMGTOOLERR_CORRUPTIMAGE;
328   // verify
329   if (!cfs_verify( cfs)) return IMGTOOLERR_CORRUPTIMAGE;
330   // ok
331   return IMGTOOLERR_SUCCESS;
332}
333 
334static void cybiko_image_close( imgtool_image *image)
335{
336   cybiko_file_system *cfs = (cybiko_file_system*)imgtool_image_extra_bytes( image);
337   stream_close( cfs->stream);
338}
339 
340static imgtoolerr_t cybiko_image_create( imgtool_image *image, imgtool_stream *stream, option_resolution *opts)
341{
342   cybiko_file_system *cfs = (cybiko_file_system*)imgtool_image_extra_bytes( image);
343   // init
344   if (!cfs_init( cfs, stream)) return IMGTOOLERR_CORRUPTIMAGE;
345   // format
346   if (!cfs_format( cfs)) return IMGTOOLERR_CORRUPTIMAGE;
347   // ok
348   return IMGTOOLERR_SUCCESS;
349}
350 
351static imgtoolerr_t cybiko_image_begin_enum( imgtool_directory *enumeration, const char *path)
352{
353   cybiko_iter *iter = (cybiko_iter*)imgtool_directory_extrabytes( enumeration);
354   iter->block = 0;
355   return IMGTOOLERR_SUCCESS;
356}
357 
358static imgtoolerr_t cybiko_image_next_enum( imgtool_directory *enumeration, imgtool_dirent *ent)
359{
360   imgtool_image *image = imgtool_directory_image( enumeration);
361   cybiko_file_system *cfs = (cybiko_file_system*)imgtool_image_extra_bytes( image);
362   cybiko_iter *iter = (cybiko_iter*)imgtool_directory_extrabytes( enumeration);
363   UINT8 buffer[MAX_PAGE_SIZE];
364   UINT16 file_id = INVALID_FILE_ID;
365   cfs_file file;
366   // find next file
367   while (iter->block < cfs->block_count_file)
368   {
369      if (!cfs_block_read( cfs, buffer, BLOCK_TYPE_FILE, iter->block++)) return IMGTOOLERR_READERROR;
370      if (BLOCK_USED(buffer) && (BLOCK_PART_ID(buffer) == 0))
371      {
372         file_id = BLOCK_FILE_ID(buffer);
373         break;
374      }
375   }
376   // get file information
377   if ((file_id != INVALID_FILE_ID) && cfs_file_info( cfs, file_id, &file))
378   {
379      strcpy( ent->filename, file.name);
380      ent->filesize = file.size;
381      ent->lastmodified_time = time_crack( file.date);
382      ent->filesize = file.size;
383   }
384   else
385   {
386      ent->eof = 1;
387   }
388   // ok
389   return IMGTOOLERR_SUCCESS;
390}
391 
392static void cybiko_image_close_enum( imgtool_directory *enumeration)
393{
394   // nothing
395}
396 
397static imgtoolerr_t cybiko_image_free_space( imgtool_partition *partition, UINT64 *size)
398{
399   imgtool_image *image = imgtool_partition_image( partition);
400   cybiko_file_system *cfs = (cybiko_file_system*)imgtool_image_extra_bytes( image);
401   if (size) *size = cfs_calc_free_space( cfs, cfs_calc_free_blocks( cfs));
402   return IMGTOOLERR_SUCCESS;
403}
404 
405static imgtoolerr_t cybiko_image_read_file( imgtool_partition *partition, const char *filename, const char *fork, imgtool_stream *destf)
406{
407   imgtool_image *image = imgtool_partition_image( partition);
408   cybiko_file_system *cfs = (cybiko_file_system*)imgtool_image_extra_bytes( image);
409   UINT8 buffer[MAX_PAGE_SIZE];
410   UINT16 file_id, part_id = 0, old_part_id;
411   int i;
412   // check filename
413   if (strlen( filename) > 58) return IMGTOOLERR_BADFILENAME;
414   // find file
415   if (!cfs_file_find( cfs, filename, &file_id)) return IMGTOOLERR_FILENOTFOUND;
416   // read file
417   do
418   {
419      old_part_id = part_id;
420      for (i=0;i<cfs->block_count_file;i++)
421      {
422         if (!cfs_block_read( cfs, buffer, BLOCK_TYPE_FILE, i)) return IMGTOOLERR_READERROR;
423         if (BLOCK_USED(buffer) && (BLOCK_FILE_ID(buffer) == file_id) && (BLOCK_PART_ID(buffer) == part_id))
424         {
425            stream_write( destf, buffer + 6 + ((part_id == 0) ? FILE_HEADER_SIZE : 0), buffer[1]);
426            part_id++;
427         }
428      }
429   } while (old_part_id != part_id);
430   // ok
431   return IMGTOOLERR_SUCCESS;
432}
433 
434static imgtoolerr_t cybiko_image_write_file( imgtool_partition *partition, const char *filename, const char *fork, imgtool_stream *sourcef, option_resolution *opts)
435{
436   imgtool_image *image = imgtool_partition_image( partition);
437   cybiko_file_system *cfs = (cybiko_file_system*)imgtool_image_extra_bytes( image);
438   UINT8 buffer[MAX_PAGE_SIZE];
439   UINT16 file_id, part_id = 0, free_blocks;
440   UINT64 bytes_left;
441   cfs_file file;
442   int i;
443   // check filename
444   if (strlen( filename) > 58) return IMGTOOLERR_BADFILENAME;
445   // find file
446   if (!cfs_file_find( cfs, filename, &file_id)) file_id = INVALID_FILE_ID;
447   // check free space
448   free_blocks = cfs_calc_free_blocks( cfs);
449   if (file_id != INVALID_FILE_ID)
450   {
451      if (!cfs_file_info( cfs, file_id, &file)) return IMGTOOLERR_UNEXPECTED;
452      free_blocks += file.blocks;
453   }
454   if (cfs_calc_free_space( cfs, free_blocks) < stream_size( sourcef)) return IMGTOOLERR_NOSPACE;
455   // delete file
456   if (file_id != INVALID_FILE_ID)
457   {
458      if (!cfs_file_delete( cfs, file_id)) return IMGTOOLERR_UNEXPECTED;
459   }
460   // create/write destination file
461   bytes_left = stream_size( sourcef);
462   i = 0;
463   while (i < cfs->block_count_file)
464   {
465      if (!cfs_block_read( cfs, buffer, BLOCK_TYPE_FILE, i)) return IMGTOOLERR_READERROR;
466      if (!BLOCK_USED(buffer))
467      {
468         if (part_id == 0) file_id = i;
469         memset( buffer, 0xFF, cfs->page_size - 0x02);
470         buffer[0] = 0x80;
471         buffer[1] = (cfs->page_size - 2) - 6 - ((part_id == 0) ? FILE_HEADER_SIZE : 0);
472         if (bytes_left < buffer[1]) buffer[1] = bytes_left;
473         buffer_write_16_be( buffer + 2, file_id);
474         buffer_write_16_be( buffer + 4, part_id);
475         if (part_id == 0)
476         {
477            buffer[6] = 0x20;
478            strcpy( BLOCK_FILENAME(buffer), filename);
479            buffer_write_32_be( buffer + 6 + FILE_HEADER_SIZE - 4, time_setup( time( NULL)));
480            stream_read( sourcef, buffer + 6 + FILE_HEADER_SIZE, buffer[1]);
481         }
482         else
483         {
484            stream_read( sourcef, buffer + 6, buffer[1]);
485         }
486         if (!cfs_block_write( cfs, buffer, BLOCK_TYPE_FILE, i)) return IMGTOOLERR_WRITEERROR;
487         bytes_left -= buffer[1];
488         if (bytes_left == 0) break;
489         part_id++;
490      }
491      i++;
492   }
493   // ok
494   return IMGTOOLERR_SUCCESS;
495}
496 
497static imgtoolerr_t cybiko_image_delete_file( imgtool_partition *partition, const char *filename)
498{
499   imgtool_image *image = imgtool_partition_image( partition);
500   cybiko_file_system *cfs = (cybiko_file_system*)imgtool_image_extra_bytes( image);
501   UINT16 file_id;
502   // check filename
503   if (strlen( filename) > 58) return IMGTOOLERR_BADFILENAME;
504   // find file
505   if (!cfs_file_find( cfs, filename, &file_id)) return IMGTOOLERR_FILENOTFOUND;
506   // delete file
507   if (!cfs_file_delete( cfs, file_id)) return IMGTOOLERR_UNEXPECTED;
508   // ok
509   return IMGTOOLERR_SUCCESS;
510}
511 
512void cybikoxt_get_info( const imgtool_class *imgclass, UINT32 state, union imgtoolinfo *info)
513{
514   switch (state)
515   {
516      // --- the following bits of info are returned as 64-bit signed integers ---
517      case IMGTOOLINFO_INT_IMAGE_EXTRA_BYTES          : info->i = sizeof( cybiko_file_system); break;
518      case IMGTOOLINFO_INT_DIRECTORY_EXTRA_BYTES      : info->i = sizeof( cybiko_iter); break;
519//      case IMGTOOLINFO_INT_SUPPORTS_CREATION_TIME     : info->i = 1; break;
520      case IMGTOOLINFO_INT_SUPPORTS_LASTMODIFIED_TIME : info->i = 1; break;
521//      case IMGTOOLINFO_INT_BLOCK_SIZE                 : info->i = 264; break;
522      // --- the following bits of info are returned as pointers to data or functions ---
523      case IMGTOOLINFO_PTR_OPEN        : info->open        = cybiko_image_open; break;
524      case IMGTOOLINFO_PTR_CREATE      : info->create      = cybiko_image_create; break;
525      case IMGTOOLINFO_PTR_CLOSE       : info->close       = cybiko_image_close; break;
526      case IMGTOOLINFO_PTR_BEGIN_ENUM  : info->begin_enum  = cybiko_image_begin_enum; break;
527      case IMGTOOLINFO_PTR_NEXT_ENUM   : info->next_enum   = cybiko_image_next_enum; break;
528      case IMGTOOLINFO_PTR_CLOSE_ENUM  : info->close_enum  = cybiko_image_close_enum; break;
529      case IMGTOOLINFO_PTR_FREE_SPACE  : info->free_space  = cybiko_image_free_space; break;
530      case IMGTOOLINFO_PTR_READ_FILE   : info->read_file   = cybiko_image_read_file; break;
531      case IMGTOOLINFO_PTR_WRITE_FILE  : info->write_file  = cybiko_image_write_file; break;
532      case IMGTOOLINFO_PTR_DELETE_FILE : info->delete_file = cybiko_image_delete_file; break;
533      // --- the following bits of info are returned as NULL-terminated strings ---
534      case IMGTOOLINFO_STR_NAME            : strcpy( info->s = imgtool_temp_str(), "cybikoxt"); break;
535      case IMGTOOLINFO_STR_DESCRIPTION     : strcpy( info->s = imgtool_temp_str(), "Cybiko Xtreme File System"); break;
536      case IMGTOOLINFO_STR_FILE            : strcpy( info->s = imgtool_temp_str(), __FILE__); break;
537      case IMGTOOLINFO_STR_FILE_EXTENSIONS : strcpy( info->s = imgtool_temp_str(), "bin,nv"); break;
538      case IMGTOOLINFO_STR_EOLN            : strcpy( info->s = imgtool_temp_str(), "\r\n"); break;
539   }
540}
1/*
2
3    Cybiko Xtreme File System
4
5    (c) 2010 Tim Schuerewegen
6
7*/
8
9#include "imgtool.h"
10
11#include <zlib.h>
12
13typedef struct _cybiko_file_system cybiko_file_system;
14struct _cybiko_file_system
15{
16   imgtool_stream *stream;
17   UINT32 page_count, page_size, block_count_boot, block_count_file;
18   UINT16 write_count;
19};
20
21typedef struct _cybiko_iter cybiko_iter;
22struct _cybiko_iter
23{
24   UINT16 block;
25};
26
27typedef struct _cfs_file cfs_file;
28struct _cfs_file
29{
30   char name[64]; // name of the file
31   UINT32 date;   // date/time of the file (seconds since 1900/01/01)
32   UINT32 size;   // size of the file
33   UINT32 blocks; // number of blocks occupied by the file
34};
35
36enum
37{
38   BLOCK_TYPE_INVALID,
39   BLOCK_TYPE_BOOT,
40   BLOCK_TYPE_FILE
41};
42
43#define   MAX_PAGE_SIZE (264 * 2)
44
45#define INVALID_FILE_ID  0xFFFF
46
47#define BLOCK_USED(x)      (x[0] & 0x80)
48#define BLOCK_FILE_ID(x)   buffer_read_16_be( x + 2)
49#define BLOCK_PART_ID(x)   buffer_read_16_be( x + 4)
50#define BLOCK_FILENAME(x)  (char*)(x + 7)
51
52#define FILE_HEADER_SIZE  0x48
53
54// 2208988800 is the number of seconds between 1900/01/01 and 1970/01/01
55
56static time_t time_crack( UINT32 cfs_time)
57{
58   return (time_t)(cfs_time - 2208988800UL);
59}
60
61static UINT32 time_setup( time_t ansi_time)
62{
63   return (UINT32)(ansi_time + 2208988800UL);
64}
65
66static UINT32 buffer_read_32_be( UINT8 *buffer)
67{
68   return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | (buffer[3] << 0);
69}
70
71static UINT16 buffer_read_16_be( UINT8 *buffer)
72{
73   return (buffer[0] << 8) | (buffer[1] << 0);
74}
75
76static void buffer_write_32_be( UINT8 *buffer, UINT32 data)
77{
78   buffer[0] = (data >> 24) & 0xFF;
79   buffer[1] = (data >> 16) & 0xFF;
80   buffer[2] = (data >>  8) & 0xFF;
81   buffer[3] = (data >>  0) & 0xFF;
82}
83
84static void buffer_write_16_be( UINT8 *buffer, UINT16 data)
85{
86   buffer[0] = (data >> 8) & 0xFF;
87   buffer[1] = (data >> 0) & 0xFF;
88}
89
90// page = crc (2) + data (x)
91
92static UINT16 page_buffer_calc_checksum( UINT8 *data, UINT32 size)
93{
94   int i;
95   UINT32 val = 0;
96   for (i = 0; i < size; i++)
97   {
98      val = (val ^ data[i] ^ i) << 1;
99      val = val | ((val >> 16) & 0x0001);
100   }
101   return val;
102}
103
104static int page_buffer_verify( UINT8 *buffer, UINT32 size, int block_type)
105{
106   // checksum
107   if (block_type == BLOCK_TYPE_FILE)
108   {
109      UINT32 checksum_page, checksum_calc;
110      checksum_calc = page_buffer_calc_checksum( buffer + 2, size - 2);
111      checksum_page = buffer_read_16_be( buffer + 0);
112      if (checksum_calc != checksum_page) return FALSE;
113   }
114   // ok
115   return TRUE;
116}
117
118static int cfs_block_to_page( cybiko_file_system *cfs, int block_type, UINT32 block, UINT32 *page)
119{
120   switch (block_type)
121   {
122      case BLOCK_TYPE_BOOT : if (page) *page = block; return TRUE;
123      case BLOCK_TYPE_FILE : if (page) *page = block + cfs->block_count_boot; return TRUE;
124      default              : return FALSE;
125   }
126}
127
128static int cfs_page_to_block( cybiko_file_system *cfs, UINT32 page, int *block_type, UINT32 *block)
129{
130   UINT32 tmp = page;
131   // boot block
132   if (tmp < cfs->block_count_boot)
133   {
134      if (block_type) *block_type = BLOCK_TYPE_BOOT;
135      if (block) *block = tmp;
136      return TRUE;
137   }
138   tmp -= cfs->block_count_boot;
139   // file block
140   if (tmp < cfs->block_count_file)
141   {
142      if (block_type) *block_type = BLOCK_TYPE_FILE;
143      if (block) *block = tmp;
144      return TRUE;
145   }
146   tmp -= cfs->block_count_file;
147   // error
148   return FALSE;
149}
150
151static int cfs_page_read( cybiko_file_system *cfs, UINT8 *buffer, UINT32 page)
152{
153   if (page >= cfs->page_count) return FALSE;
154   stream_seek( cfs->stream, page * cfs->page_size, SEEK_SET);
155   stream_read( cfs->stream, buffer, cfs->page_size);
156   return TRUE;
157}
158
159static int cfs_page_write( cybiko_file_system *cfs, UINT8 *buffer, UINT32 page)
160{
161   if (page >= cfs->page_count) return FALSE;
162   stream_seek( cfs->stream, page * cfs->page_size, SEEK_SET);
163   stream_write( cfs->stream, buffer, cfs->page_size);
164   return TRUE;
165}
166
167static int cfs_block_read( cybiko_file_system *cfs, UINT8 *buffer, int block_type, UINT32 block)
168{
169   UINT8 buffer_page[MAX_PAGE_SIZE];
170   UINT32 page;
171   if (!cfs_block_to_page( cfs, block_type, block, &page)) return FALSE;
172   if (!cfs_page_read( cfs, buffer_page, page)) return FALSE;
173   memcpy( buffer, buffer_page + 2, cfs->page_size - 2);
174   return TRUE;
175}
176
177static int cfs_block_write( cybiko_file_system *cfs, UINT8 *buffer, int block_type, UINT32 block)
178{
179   UINT8 buffer_page[MAX_PAGE_SIZE];
180   UINT32 page;
181   UINT16 checksum;
182   memcpy( buffer_page + 2, buffer, cfs->page_size - 2);
183   if (block_type == BLOCK_TYPE_BOOT)
184   {
185      checksum = 0xFFFF;
186   }
187   else
188   {
189      checksum = page_buffer_calc_checksum( buffer_page + 2, cfs->page_size - 2);
190   }
191   buffer_write_16_be( buffer_page + 0, checksum);
192   if (!cfs_block_to_page( cfs, block_type, block, &page)) return FALSE;
193   if (!cfs_page_write( cfs, buffer_page, page)) return FALSE;
194   return TRUE;
195}
196
197static int cfs_file_delete( cybiko_file_system *cfs, UINT16 file_id)
198{
199   UINT8 buffer[MAX_PAGE_SIZE];
200   int i;
201   for (i=0;i<cfs->block_count_file;i++)
202   {
203      if (!cfs_block_read( cfs, buffer, BLOCK_TYPE_FILE, i)) return FALSE;
204      if (BLOCK_USED(buffer) && (BLOCK_FILE_ID(buffer) == file_id))
205      {
206         buffer[0] &= ~0x80;
207         if (!cfs_block_write( cfs, buffer, BLOCK_TYPE_FILE, i)) return FALSE;
208      }
209   }
210   return TRUE;
211}
212
213static int cfs_file_info( cybiko_file_system *cfs, UINT16 file_id, cfs_file *file)
214{
215   UINT8 buffer[MAX_PAGE_SIZE];
216   int i;
217   file->blocks = file->size = 0;
218   for (i=0;i<cfs->block_count_file;i++)
219   {
220      if (!cfs_block_read( cfs, buffer, BLOCK_TYPE_FILE, i)) return FALSE;
221      if (BLOCK_USED(buffer) && (BLOCK_FILE_ID(buffer) == file_id))
222      {
223         if (BLOCK_PART_ID(buffer) == 0)
224         {
225            strcpy( file->name, BLOCK_FILENAME(buffer));
226            file->date = buffer_read_32_be( buffer + 6 + FILE_HEADER_SIZE - 4);
227         }
228         file->size += buffer[1];
229         file->blocks++;
230      }
231   }
232   return (file->blocks > 0) ? TRUE : FALSE;
233}
234
235static int cfs_file_find( cybiko_file_system *cfs, const char *filename, UINT16 *file_id)
236{
237   UINT8 buffer[MAX_PAGE_SIZE];
238   int i;
239   for (i=0;i<cfs->block_count_file;i++)
240   {
241      if (!cfs_block_read( cfs, buffer, BLOCK_TYPE_FILE, i)) return FALSE;
242      if (BLOCK_USED(buffer) && (BLOCK_PART_ID(buffer) == 0) && (strcmp( filename, BLOCK_FILENAME(buffer)) == 0))
243      {
244         *file_id = i;
245         return TRUE;
246      }
247   }
248   return FALSE;
249}
250
251static int cfs_verify( cybiko_file_system *cfs)
252{
253   UINT8 buffer[MAX_PAGE_SIZE];
254   int i, block_type;
255   for (i=0;i<cfs->page_count;i++)
256   {
257      if (!cfs_page_read( cfs, buffer, i)) return FALSE;
258      if (!cfs_page_to_block( cfs, i, &block_type, NULL)) return FALSE;
259      if (!page_buffer_verify( buffer, cfs->page_size, block_type)) return FALSE;
260   }
261   return TRUE;
262}
263
264static int cfs_init( cybiko_file_system *cfs, imgtool_stream *stream)
265{
266   cfs->stream = stream;
267   cfs->page_count = 2005;
268   cfs->page_size = 258;
269   cfs->block_count_boot = 5;
270   cfs->block_count_file = cfs->page_count - cfs->block_count_boot;
271   cfs->write_count = 0;
272   return TRUE;
273}
274
275static int cfs_format( cybiko_file_system *cfs)
276{
277   UINT8 buffer[MAX_PAGE_SIZE];
278   int i;
279   // boot blocks
280   memset( buffer, 0xFF, sizeof( buffer));
281   for (i=0;i<cfs->block_count_boot;i++)
282   {
283      if (!cfs_block_write( cfs, buffer, BLOCK_TYPE_BOOT, i)) return FALSE;
284   }
285   // file blocks
286   memset( buffer, 0xFF, sizeof( buffer));
287   buffer[0] &= ~0x80;
288   for (i=0;i<cfs->block_count_file;i++)
289   {
290      if (!cfs_block_write( cfs, buffer, BLOCK_TYPE_FILE, i)) return FALSE;
291   }
292   // padding
293   buffer[0] = 0xFF;
294   for (i=0;i<0x1B56;i++)
295   {
296      stream_write( cfs->stream, buffer, 1);
297   }
298   // ok
299   return TRUE;
300}
301
302static UINT16 cfs_calc_free_blocks( cybiko_file_system *cfs)
303{
304   UINT8 buffer[MAX_PAGE_SIZE];
305   int i;
306   UINT16 blocks = 0;
307   for (i=0;i<cfs->block_count_file;i++)
308   {
309      if (!cfs_block_read( cfs, buffer, BLOCK_TYPE_FILE, i)) return 0;
310      if (!BLOCK_USED(buffer)) blocks++;
311   }
312   return blocks;
313}
314
315static UINT32 cfs_calc_free_space( cybiko_file_system *cfs, UINT16 blocks)
316{
317   UINT32 free_space;
318   free_space = blocks * ((cfs->page_size - 2) - 6);
319   if (free_space > 0) free_space -= FILE_HEADER_SIZE;
320   return free_space;
321}
322
323static imgtoolerr_t cybiko_image_open( imgtool_image *image, imgtool_stream *stream)
324{
325   cybiko_file_system *cfs = (cybiko_file_system*)imgtool_image_extra_bytes( image);
326   // init
327   if (!cfs_init( cfs, stream)) return IMGTOOLERR_CORRUPTIMAGE;
328   // verify
329   if (!cfs_verify( cfs)) return IMGTOOLERR_CORRUPTIMAGE;
330   // ok
331   return IMGTOOLERR_SUCCESS;
332}
333
334static void cybiko_image_close( imgtool_image *image)
335{
336   cybiko_file_system *cfs = (cybiko_file_system*)imgtool_image_extra_bytes( image);
337   stream_close( cfs->stream);
338}
339
340static imgtoolerr_t cybiko_image_create( imgtool_image *image, imgtool_stream *stream, option_resolution *opts)
341{
342   cybiko_file_system *cfs = (cybiko_file_system*)imgtool_image_extra_bytes( image);
343   // init
344   if (!cfs_init( cfs, stream)) return IMGTOOLERR_CORRUPTIMAGE;
345   // format
346   if (!cfs_format( cfs)) return IMGTOOLERR_CORRUPTIMAGE;
347   // ok
348   return IMGTOOLERR_SUCCESS;
349}
350
351static imgtoolerr_t cybiko_image_begin_enum( imgtool_directory *enumeration, const char *path)
352{
353   cybiko_iter *iter = (cybiko_iter*)imgtool_directory_extrabytes( enumeration);
354   iter->block = 0;
355   return IMGTOOLERR_SUCCESS;
356}
357
358static imgtoolerr_t cybiko_image_next_enum( imgtool_directory *enumeration, imgtool_dirent *ent)
359{
360   imgtool_image *image = imgtool_directory_image( enumeration);
361   cybiko_file_system *cfs = (cybiko_file_system*)imgtool_image_extra_bytes( image);
362   cybiko_iter *iter = (cybiko_iter*)imgtool_directory_extrabytes( enumeration);
363   UINT8 buffer[MAX_PAGE_SIZE];
364   UINT16 file_id = INVALID_FILE_ID;
365   cfs_file file;
366   // find next file
367   while (iter->block < cfs->block_count_file)
368   {
369      if (!cfs_block_read( cfs, buffer, BLOCK_TYPE_FILE, iter->block++)) return IMGTOOLERR_READERROR;
370      if (BLOCK_USED(buffer) && (BLOCK_PART_ID(buffer) == 0))
371      {
372         file_id = BLOCK_FILE_ID(buffer);
373         break;
374      }
375   }
376   // get file information
377   if ((file_id != INVALID_FILE_ID) && cfs_file_info( cfs, file_id, &file))
378   {
379      strcpy( ent->filename, file.name);
380      ent->filesize = file.size;
381      ent->lastmodified_time = time_crack( file.date);
382      ent->filesize = file.size;
383   }
384   else
385   {
386      ent->eof = 1;
387   }
388   // ok
389   return IMGTOOLERR_SUCCESS;
390}
391
392static void cybiko_image_close_enum( imgtool_directory *enumeration)
393{
394   // nothing
395}
396
397static imgtoolerr_t cybiko_image_free_space( imgtool_partition *partition, UINT64 *size)
398{
399   imgtool_image *image = imgtool_partition_image( partition);
400   cybiko_file_system *cfs = (cybiko_file_system*)imgtool_image_extra_bytes( image);
401   if (size) *size = cfs_calc_free_space( cfs, cfs_calc_free_blocks( cfs));
402   return IMGTOOLERR_SUCCESS;
403}
404
405static imgtoolerr_t cybiko_image_read_file( imgtool_partition *partition, const char *filename, const char *fork, imgtool_stream *destf)
406{
407   imgtool_image *image = imgtool_partition_image( partition);
408   cybiko_file_system *cfs = (cybiko_file_system*)imgtool_image_extra_bytes( image);
409   UINT8 buffer[MAX_PAGE_SIZE];
410   UINT16 file_id, part_id = 0, old_part_id;
411   int i;
412   // check filename
413   if (strlen( filename) > 58) return IMGTOOLERR_BADFILENAME;
414   // find file
415   if (!cfs_file_find( cfs, filename, &file_id)) return IMGTOOLERR_FILENOTFOUND;
416   // read file
417   do
418   {
419      old_part_id = part_id;
420      for (i=0;i<cfs->block_count_file;i++)
421      {
422         if (!cfs_block_read( cfs, buffer, BLOCK_TYPE_FILE, i)) return IMGTOOLERR_READERROR;
423         if (BLOCK_USED(buffer) && (BLOCK_FILE_ID(buffer) == file_id) && (BLOCK_PART_ID(buffer) == part_id))
424         {
425            stream_write( destf, buffer + 6 + ((part_id == 0) ? FILE_HEADER_SIZE : 0), buffer[1]);
426            part_id++;
427         }
428      }
429   } while (old_part_id != part_id);
430   // ok
431   return IMGTOOLERR_SUCCESS;
432}
433
434static imgtoolerr_t cybiko_image_write_file( imgtool_partition *partition, const char *filename, const char *fork, imgtool_stream *sourcef, option_resolution *opts)
435{
436   imgtool_image *image = imgtool_partition_image( partition);
437   cybiko_file_system *cfs = (cybiko_file_system*)imgtool_image_extra_bytes( image);
438   UINT8 buffer[MAX_PAGE_SIZE];
439   UINT16 file_id, part_id = 0, free_blocks;
440   UINT64 bytes_left;
441   cfs_file file;
442   int i;
443   // check filename
444   if (strlen( filename) > 58) return IMGTOOLERR_BADFILENAME;
445   // find file
446   if (!cfs_file_find( cfs, filename, &file_id)) file_id = INVALID_FILE_ID;
447   // check free space
448   free_blocks = cfs_calc_free_blocks( cfs);
449   if (file_id != INVALID_FILE_ID)
450   {
451      if (!cfs_file_info( cfs, file_id, &file)) return IMGTOOLERR_UNEXPECTED;
452      free_blocks += file.blocks;
453   }
454   if (cfs_calc_free_space( cfs, free_blocks) < stream_size( sourcef)) return IMGTOOLERR_NOSPACE;
455   // delete file
456   if (file_id != INVALID_FILE_ID)
457   {
458      if (!cfs_file_delete( cfs, file_id)) return IMGTOOLERR_UNEXPECTED;
459   }
460   // create/write destination file
461   bytes_left = stream_size( sourcef);
462   i = 0;
463   while (i < cfs->block_count_file)
464   {
465      if (!cfs_block_read( cfs, buffer, BLOCK_TYPE_FILE, i)) return IMGTOOLERR_READERROR;
466      if (!BLOCK_USED(buffer))
467      {
468         if (part_id == 0) file_id = i;
469         memset( buffer, 0xFF, cfs->page_size - 0x02);
470         buffer[0] = 0x80;
471         buffer[1] = (cfs->page_size - 2) - 6 - ((part_id == 0) ? FILE_HEADER_SIZE : 0);
472         if (bytes_left < buffer[1]) buffer[1] = bytes_left;
473         buffer_write_16_be( buffer + 2, file_id);
474         buffer_write_16_be( buffer + 4, part_id);
475         if (part_id == 0)
476         {
477            buffer[6] = 0x20;
478            strcpy( BLOCK_FILENAME(buffer), filename);
479            buffer_write_32_be( buffer + 6 + FILE_HEADER_SIZE - 4, time_setup( time( NULL)));
480            stream_read( sourcef, buffer + 6 + FILE_HEADER_SIZE, buffer[1]);
481         }
482         else
483         {
484            stream_read( sourcef, buffer + 6, buffer[1]);
485         }
486         if (!cfs_block_write( cfs, buffer, BLOCK_TYPE_FILE, i)) return IMGTOOLERR_WRITEERROR;
487         bytes_left -= buffer[1];
488         if (bytes_left == 0) break;
489         part_id++;
490      }
491      i++;
492   }
493   // ok
494   return IMGTOOLERR_SUCCESS;
495}
496
497static imgtoolerr_t cybiko_image_delete_file( imgtool_partition *partition, const char *filename)
498{
499   imgtool_image *image = imgtool_partition_image( partition);
500   cybiko_file_system *cfs = (cybiko_file_system*)imgtool_image_extra_bytes( image);
501   UINT16 file_id;
502   // check filename
503   if (strlen( filename) > 58) return IMGTOOLERR_BADFILENAME;
504   // find file
505   if (!cfs_file_find( cfs, filename, &file_id)) return IMGTOOLERR_FILENOTFOUND;
506   // delete file
507   if (!cfs_file_delete( cfs, file_id)) return IMGTOOLERR_UNEXPECTED;
508   // ok
509   return IMGTOOLERR_SUCCESS;
510}
511
512void cybikoxt_get_info( const imgtool_class *imgclass, UINT32 state, union imgtoolinfo *info)
513{
514   switch (state)
515   {
516      // --- the following bits of info are returned as 64-bit signed integers ---
517      case IMGTOOLINFO_INT_IMAGE_EXTRA_BYTES          : info->i = sizeof( cybiko_file_system); break;
518      case IMGTOOLINFO_INT_DIRECTORY_EXTRA_BYTES      : info->i = sizeof( cybiko_iter); break;
519//      case IMGTOOLINFO_INT_SUPPORTS_CREATION_TIME     : info->i = 1; break;
520      case IMGTOOLINFO_INT_SUPPORTS_LASTMODIFIED_TIME : info->i = 1; break;
521//      case IMGTOOLINFO_INT_BLOCK_SIZE                 : info->i = 264; break;
522      // --- the following bits of info are returned as pointers to data or functions ---
523      case IMGTOOLINFO_PTR_OPEN        : info->open        = cybiko_image_open; break;
524      case IMGTOOLINFO_PTR_CREATE      : info->create      = cybiko_image_create; break;
525      case IMGTOOLINFO_PTR_CLOSE       : info->close       = cybiko_image_close; break;
526      case IMGTOOLINFO_PTR_BEGIN_ENUM  : info->begin_enum  = cybiko_image_begin_enum; break;
527      case IMGTOOLINFO_PTR_NEXT_ENUM   : info->next_enum   = cybiko_image_next_enum; break;
528      case IMGTOOLINFO_PTR_CLOSE_ENUM  : info->close_enum  = cybiko_image_close_enum; break;
529      case IMGTOOLINFO_PTR_FREE_SPACE  : info->free_space  = cybiko_image_free_space; break;
530      case IMGTOOLINFO_PTR_READ_FILE   : info->read_file   = cybiko_image_read_file; break;
531      case IMGTOOLINFO_PTR_WRITE_FILE  : info->write_file  = cybiko_image_write_file; break;
532      case IMGTOOLINFO_PTR_DELETE_FILE : info->delete_file = cybiko_image_delete_file; break;
533      // --- the following bits of info are returned as NULL-terminated strings ---
534      case IMGTOOLINFO_STR_NAME            : strcpy( info->s = imgtool_temp_str(), "cybikoxt"); break;
535      case IMGTOOLINFO_STR_DESCRIPTION     : strcpy( info->s = imgtool_temp_str(), "Cybiko Xtreme File System"); break;
536      case IMGTOOLINFO_STR_FILE            : strcpy( info->s = imgtool_temp_str(), __FILE__); break;
537      case IMGTOOLINFO_STR_FILE_EXTENSIONS : strcpy( info->s = imgtool_temp_str(), "bin,nv"); break;
538      case IMGTOOLINFO_STR_EOLN            : strcpy( info->s = imgtool_temp_str(), "\r\n"); break;
539   }
540}
src/mess/machine/a2cffa.c
r8681r8682
1/*********************************************************************
2 
3    a2cffa.c
4 
5    Implementation of Rich Dreher's IDE/CompactFlash card
6    for the Apple II.
7 
8    http://www.dreher.net/
9 
10*********************************************************************/
11 
12#include "a2cffa.h"
13#include "includes/apple2.h"
14#include "machine/idectrl.h"
15 
16 
17/***************************************************************************
18    PARAMETERS
19***************************************************************************/
20 
21#define LOG_A2CFFA   1
22 
23 
24/***************************************************************************
25    TYPE DEFINITIONS
26***************************************************************************/
27 
28typedef struct _a2cffa_token a2cffa_token;
29struct _a2cffa_token
30{
31   UINT8 *ROM;      // card ROM
32   UINT16 lastdata;   // last data from IDE
33};
34 
35 
36/***************************************************************************
37    INLINE FUNCTIONS
38***************************************************************************/
39 
40INLINE a2cffa_token *get_token(running_device *device)
41{
42   assert(device != NULL);
43   assert(device->type() == A2CFFA);
44   return (a2cffa_token *)downcast<legacy_device_base *>(device)->token();
45}
46 
47 
48 
49/***************************************************************************
50    FUNCTION PROTOTYPES
51***************************************************************************/
52 
53/*-------------------------------------------------
54    DEVICE_START(a2cffa) - device start
55    function
56-------------------------------------------------*/
57 
58static DEVICE_START(a2cffa)
59{
60}
61 
62 
63 
64/*-------------------------------------------------
65    DEVICE_RESET(a2cffa) - device reset
66    function
67-------------------------------------------------*/
68 
69static DEVICE_RESET(a2cffa)
70{
71   a2cffa_token *token = get_token(device);
72 
73   // find card ROM
74   token->ROM = (UINT8 *)memory_region(device->machine, "cffa");
75}
76 
77 
78 
79/*-------------------------------------------------
80    a2cffa_r - device read function
81-------------------------------------------------*/
82 
83READ8_DEVICE_HANDLER(a2cffa_r)
84{
85   a2cffa_token *token = get_token(device);
86 
87   if (offset == 0)
88   {
89      return token->lastdata>>8;
90   }
91   else if (offset == 8)
92   {
93      token->lastdata = ide_controller_r(device->machine->m_devicelist.find("ide"), 0x1f0+offset-8, 2);
94      return token->lastdata & 0xff;
95   }
96   else if (offset > 8)
97   {
98      return ide_controller_r(device->machine->m_devicelist.find("ide"), 0x1f0+offset-8, 1);
99   }
100 
101   return 0xff;
102}
103 
104 
105 
106/*-------------------------------------------------
107    a2cffa_w - device write function
108-------------------------------------------------*/
109 
110WRITE8_DEVICE_HANDLER(a2cffa_w)
111{
112   a2cffa_token *token = get_token(device);
113 
114   if (offset == 0)
115   {
116      token->lastdata &= 0x00ff;
117      token->lastdata |= data<<8;
118   }
119   else if (offset == 8)
120   {
121      token->lastdata &= 0xff00;
122      token->lastdata |= data;
123      ide_controller_w(device->machine->m_devicelist.find("ide"), 0x1f0+offset-8, 2, token->lastdata);
124   }
125   else if (offset > 8)
126   {
127      ide_controller_w(device->machine->m_devicelist.find("ide"), 0x1f0+offset-8, 1, data);
128   }
129}
130 
131 
132/* slot ext. ROM (C800) read function */
133READ8_DEVICE_HANDLER(a2cffa_c800_r)
134{
135   a2cffa_token *token = get_token(device);
136 
137   return token->ROM[offset+0x800];
138}
139 
140/* slot ext. ROM (C800) write function */
141WRITE8_DEVICE_HANDLER(a2cffa_c800_w)
142{
143}
144 
145/* slot ROM (CN00) read function */
146READ8_DEVICE_HANDLER(a2cffa_cnxx_r)
147{
148   a2cffa_token *token = get_token(device);
149 
150   return token->ROM[offset+0x700];   // this needs to be = to the slot #, we assume 7 for now
151}
152 
153/* slot ROM (CN00) write function */
154WRITE8_DEVICE_HANDLER(a2cffa_cnxx_w)
155{
156}
157 
158 
159/*-------------------------------------------------
160    DEVICE_GET_INFO(a2cffa) - device get info
161    function
162-------------------------------------------------*/
163 
164DEVICE_GET_INFO(a2cffa)
165{
166   switch (state)
167   {
168      /* --- the following bits of info are returned as 64-bit signed integers --- */
169      case DEVINFO_INT_TOKEN_BYTES:               info->i = sizeof(a2cffa_token);      break;
170      case DEVINFO_INT_INLINE_CONFIG_BYTES:         info->i = 0;                        break;
171 
172      /* --- the following bits of info are returned as pointers to data or functions --- */
173      case DEVINFO_FCT_START:                     info->start = DEVICE_START_NAME(a2cffa);   break;
174      case DEVINFO_FCT_STOP:                     /* Nothing */                        break;
175      case DEVINFO_FCT_RESET:                     info->reset = DEVICE_RESET_NAME(a2cffa);   break;
176 
177      /* --- the following bits of info are returned as NULL-terminated strings --- */
178      case DEVINFO_STR_NAME:                     strcpy(info->s, "Apple II CFFA Card (www.dreher.net)");         break;
179      case DEVINFO_STR_FAMILY:                  strcpy(info->s, "Apple II CFFA Card (www.dreher.net)");         break;
180      case DEVINFO_STR_VERSION:                  strcpy(info->s, "1.0");                     break;
181      case DEVINFO_STR_SOURCE_FILE:               strcpy(info->s, __FILE__);                     break;
182   }
183}
184 
185DEFINE_LEGACY_DEVICE(A2CFFA, a2cffa);
1/*********************************************************************
2
3    a2cffa.c
4
5    Implementation of Rich Dreher's IDE/CompactFlash card
6    for the Apple II.
7
8    http://www.dreher.net/
9
10*********************************************************************/
11
12#include "a2cffa.h"
13#include "includes/apple2.h"
14#include "machine/idectrl.h"
15
16
17/***************************************************************************
18    PARAMETERS
19***************************************************************************/
20
21#define LOG_A2CFFA   1
22
23
24/***************************************************************************
25    TYPE DEFINITIONS
26***************************************************************************/
27
28typedef struct _a2cffa_token a2cffa_token;
29struct _a2cffa_token
30{
31   UINT8 *ROM;      // card ROM
32   UINT16 lastdata;   // last data from IDE
33};
34
35
36/***************************************************************************
37    INLINE FUNCTIONS
38***************************************************************************/
39
40INLINE a2cffa_token *get_token(running_device *device)
41{
42   assert(device != NULL);
43   assert(device->type() == A2CFFA);
44   return (a2cffa_token *)downcast<legacy_device_base *>(device)->token();
45}
46
47
48
49/***************************************************************************
50    FUNCTION PROTOTYPES
51***************************************************************************/
52
53/*-------------------------------------------------
54    DEVICE_START(a2cffa) - device start
55    function
56-------------------------------------------------*/
57
58static DEVICE_START(a2cffa)
59{
60}
61
62
63
64/*-------------------------------------------------
65    DEVICE_RESET(a2cffa) - device reset
66    function
67-------------------------------------------------*/
68
69static DEVICE_RESET(a2cffa)
70{
71   a2cffa_token *token = get_token(device);
72
73   // find card ROM
74   token->ROM = (UINT8 *)memory_region(device->machine, "cffa");
75}
76
77
78
79/*-------------------------------------------------
80    a2cffa_r - device read function
81-------------------------------------------------*/
82
83READ8_DEVICE_HANDLER(a2cffa_r)
84{
85   a2cffa_token *token = get_token(device);
86
87   if (offset == 0)
88   {
89      return token->lastdata>>8;
90   }
91   else if (offset == 8)
92   {
93      token->lastdata = ide_controller_r(device->machine->m_devicelist.find("ide"), 0x1f0+offset-8, 2);
94      return token->lastdata & 0xff;
95   }
96   else if (offset > 8)
97   {
98      return ide_controller_r(device->machine->m_devicelist.find("ide"), 0x1f0+offset-8, 1);
99   }
100
101   return 0xff;
102}
103
104
105
106/*-------------------------------------------------
107    a2cffa_w - device write function
108-------------------------------------------------*/
109
110WRITE8_DEVICE_HANDLER(a2cffa_w)
111{
112   a2cffa_token *token = get_token(device);
113
114   if (offset == 0)
115   {
116      token->lastdata &= 0x00ff;
117      token->lastdata |= data<<8;
118   }
119   else if (offset == 8)
120   {
121      token->lastdata &= 0xff00;
122      token->lastdata |= data;
123      ide_controller_w(device->machine->m_devicelist.find("ide"), 0x1f0+offset-8, 2, token->lastdata);
124   }
125   else if (offset > 8)
126   {
127      ide_controller_w(device->machine->m_devicelist.find("ide"), 0x1f0+offset-8, 1, data);
128   }
129}
130
131
132/* slot ext. ROM (C800) read function */
133READ8_DEVICE_HANDLER(a2cffa_c800_r)
134{
135   a2cffa_token *token = get_token(device);
136
137   return token->ROM[offset+0x800];
138}
139
140/* slot ext. ROM (C800) write function */
141WRITE8_DEVICE_HANDLER(a2cffa_c800_w)
142{
143}
144
145/* slot ROM (CN00) read function */
146READ8_DEVICE_HANDLER(a2cffa_cnxx_r)
147{
148   a2cffa_token *token = get_token(device);
149
150   return token->ROM[offset+0x700];   // this needs to be = to the slot #, we assume 7 for now
151}
152
153/* slot ROM (CN00) write function */
154WRITE8_DEVICE_HANDLER(a2cffa_cnxx_w)
155{
156}
157
158
159/*-------------------------------------------------
160    DEVICE_GET_INFO(a2cffa) - device get info
161    function
162-------------------------------------------------*/
163
164DEVICE_GET_INFO(a2cffa)
165{
166   switch (state)
167   {
168      /* --- the following bits of info are returned as 64-bit signed integers --- */
169      case DEVINFO_INT_TOKEN_BYTES:               info->i = sizeof(a2cffa_token);      break;
170      case DEVINFO_INT_INLINE_CONFIG_BYTES:         info->i = 0;                        break;
171
172      /* --- the following bits of info are returned as pointers to data or functions --- */
173      case DEVINFO_FCT_START:                     info->start = DEVICE_START_NAME(a2cffa);   break;
174      case DEVINFO_FCT_STOP:                     /* Nothing */                        break;
175      case DEVINFO_FCT_RESET:                     info->reset = DEVICE_RESET_NAME(a2cffa);   break;
176
177      /* --- the following bits of info are returned as NULL-terminated strings --- */
178      case DEVINFO_STR_NAME:                     strcpy(info->s, "Apple II CFFA Card (www.dreher.net)");         break;
179      case DEVINFO_STR_FAMILY:                  strcpy(info->s, "Apple II CFFA Card (www.dreher.net)");         break;
180      case DEVINFO_STR_VERSION:                  strcpy(info->s, "1.0");                     break;
181      case DEVINFO_STR_SOURCE_FILE:               strcpy(info->s, __FILE__);                     break;
182   }
183}
184
185DEFINE_LEGACY_DEVICE(A2CFFA, a2cffa);
src/mess/machine/a2cffa.h
r8681r8682
1/*********************************************************************
2 
3    a2cffa.h
4 
5    Implementation of Rich Dreher's IDE/CompactFlash board for
6    the Apple II
7 
8*********************************************************************/
9 
10#ifndef __A2CFFA__
11#define __A2CFFA__
12 
13#include "emu.h"
14 
15 
16/***************************************************************************
17    CONSTANTS
18***************************************************************************/
19 
20DECLARE_LEGACY_DEVICE(A2CFFA, a2cffa);
21 
22#define MDRV_A2CFFA_ADD(_tag)   \
23   MDRV_DEVICE_ADD((_tag), A2CFFA, 0)
24 
25 
26/***************************************************************************
27    FUNCTION PROTOTYPES
28***************************************************************************/
29/* slot read function */
30READ8_DEVICE_HANDLER(a2cffa_r);
31 
32/* slot write function */
33WRITE8_DEVICE_HANDLER(a2cffa_w);
34 
35/* slot ext. ROM (C800) read function */
36READ8_DEVICE_HANDLER(a2cffa_c800_r);
37 
38/* slot ext. ROM (C800) write function */
39WRITE8_DEVICE_HANDLER(a2cffa_c800_w);
40 
41/* slot ROM (CN00) read function */
42READ8_DEVICE_HANDLER(a2cffa_cnxx_r);
43 
44/* slot ROM (CN00) write function */
45WRITE8_DEVICE_HANDLER(a2cffa_cnxx_w);
46 
47#endif /* __A2SCSI__ */
48 
1/*********************************************************************
2
3    a2cffa.h
4
5    Implementation of Rich Dreher's IDE/CompactFlash board for
6    the Apple II
7
8*********************************************************************/
9
10#ifndef __A2CFFA__
11#define __A2CFFA__
12
13#include "emu.h"
14
15
16/***************************************************************************
17    CONSTANTS
18***************************************************************************/
19
20DECLARE_LEGACY_DEVICE(A2CFFA, a2cffa);
21
22#define MDRV_A2CFFA_ADD(_tag)   \
23   MDRV_DEVICE_ADD((_tag), A2CFFA, 0)
24
25
26/***************************************************************************
27    FUNCTION PROTOTYPES
28***************************************************************************/
29/* slot read function */
30READ8_DEVICE_HANDLER(a2cffa_r);
31
32/* slot write function */
33WRITE8_DEVICE_HANDLER(a2cffa_w);
34
35/* slot ext. ROM (C800) read function */
36READ8_DEVICE_HANDLER(a2cffa_c800_r);
37
38/* slot ext. ROM (C800) write function */
39WRITE8_DEVICE_HANDLER(a2cffa_c800_w);
40
41/* slot ROM (CN00) read function */
42READ8_DEVICE_HANDLER(a2cffa_cnxx_r);
43
44/* slot ROM (CN00) write function */
45WRITE8_DEVICE_HANDLER(a2cffa_cnxx_w);
46
47#endif /* __A2SCSI__ */
48
src/mess/drivers/prestige.c
r8681r8682
1/*
2 
3VTech PreComputer Prestige Elite
4 
5PCB Layout
6----------
7 
8|-------------------------------------------|
9|   |-------CN1-------|     CN2             |
10|                                           |
11|                                       CN3 |
12|                                           |
13|CN10                                       |
14|CN9            RAM                         --|
15|CN8                                          |
16|                                             |
17|                       Z80         ROM       |
18|               04010                     CN4 |
19|CN7                                          |
20|CN6                                          |
21|                       |------CN5------|   --|
22|-------------------------------------------|
23 
24Notes:
25    All IC's shown.
26 
27    ROM     - VTech LH5S8R14, labeled "1998 27-6020-02" (dumped as 1Mx8)
28    Z80     - Z80 family SOC?
29    RAM     - LG Semicon GM76C256CLLFW55 32Kx8 Static RAM
30    04010   - ?
31    CN1     - Centronics connector
32    CN2     - mouse connector
33    CN3     - LCD ribbon cable
34    CN4     - expansion connector
35    CN5     - keyboard ribbon cable
36    CN6     - speaker wire
37    CN7     - volume wire
38    CN8     - ? wire
39    CN9     - power wire
40    CN10    - NVRAM battery wire
41*/
42 
43/*
44   
45   Undumped cartridges:
46   
47   80-1410   Super Science
48   80-1533   Famous Things & Places
49   80-0989   Bible Knowledge
50   80-1001   Fantasy Trivia
51   80-1002   General Knowledge II
52   80-1003   Sports History
53   80-2314   Familiar Faces
54   80-2315   Historical Happenings
55   80-2333   Arts, Entertainment & More
56   80-2334   Customs & Cultures
57   80-1531   32K RAM Memory Expansion Cartridge
58   80-12051  Space Scholar
59   80-12053  Frenzy of Facts
60   80-12052  Spreadsheet Success
61 
62*/
63 
64/*
65 
66   TODO:
67 
68   - identify unknown chips
69   - boot animation won't play
70   - keyboard
71   - mouse
72   - sound
73   - cartridges
74 
75*/
76 
77#include "emu.h"
78#include "cpu/z80/z80.h"
79#include "devices/messram.h"
80#include "devices/cartslot.h"
81 
82static UINT8 bank[6];
83 
84static READ8_HANDLER( bankswitch_r )
85{
86   return bank[offset];
87}
88 
89static WRITE8_HANDLER( bankswitch_w )
90{
91   const address_space *program = cputag_get_address_space(space->machine, "maincpu", ADDRESS_SPACE_PROGRAM);
92 
93   switch (offset)
94   {
95   case 0:
96      memory_set_bank(space->machine, "bank1", data & 0x3f);
97      break;
98 
99   case 1:
100      memory_set_bank(space->machine, "bank2", data & 0x3f);
101      break;
102 
103   case 2:
104      if (bank[5] == 0x0c)
105      {
106         memory_set_bank(space->machine, "bank3", 0x40 + BIT(data, 7));
107      }
108      else
109      {
110         memory_set_bank(space->machine, "bank3", data & 0x3f);
111      }
112      break;
113 
114   case 3:
115      memory_set_bank(space->machine, "bank4", data & 0x03);
116      break;
117 
118   case 4:
119      memory_set_bank(space->machine, "bank5", data & 0x03);
120      break;
121 
122   case 5:
123      if (data == 0x0c)
124      {
125         memory_install_readwrite_bank(program, 0x8000, 0xbfff, 0, 0, "bank3");
126      }
127      else
128      {
129         memory_unmap_write(program, 0x8000, 0xbfff, 0, 0);
130      }
131   }
132 
133   bank[offset] = data;
134}
135 
136static ADDRESS_MAP_START(prestige_mem, ADDRESS_SPACE_PROGRAM, 8)
137   AM_RANGE(0x0000, 0x3fff) AM_ROMBANK("bank1")
138   AM_RANGE(0x4000, 0x7fff) AM_ROMBANK("bank2")
139   AM_RANGE(0x8000, 0xbfff) AM_ROMBANK("bank3")
140   AM_RANGE(0xc000, 0xdfff) AM_RAMBANK("bank4")
141   AM_RANGE(0xe000, 0xffff) AM_RAMBANK("bank5")
142ADDRESS_MAP_END
143 
144static ADDRESS_MAP_START( prestige_io , ADDRESS_SPACE_IO, 8)
145   ADDRESS_MAP_UNMAP_HIGH
146   ADDRESS_MAP_GLOBAL_MASK(0xff)
147   AM_RANGE(0x50, 0x55) AM_READWRITE(bankswitch_r, bankswitch_w)
148ADDRESS_MAP_END
149 
150/* Input ports */
151INPUT_PORTS_START( prestige )
152INPUT_PORTS_END
153 
154 
155static MACHINE_START(prestige)
156{
157   UINT8 *ram = messram_get_ptr(machine->device("messram"));
158 
159   memory_configure_bank(machine, "bank1", 0, 64, memory_region(machine, "maincpu"), 0x4000);
160   memory_configure_bank(machine, "bank2", 0, 64, memory_region(machine, "maincpu"), 0x4000);
161   memory_configure_bank(machine, "bank3", 0, 64, memory_region(machine, "maincpu"), 0x4000);
162   memory_configure_bank(machine, "bank3", 64, 2, ram + 0x8000, 0x4000);
163   memory_configure_bank(machine, "bank4", 0, 4, ram, 0x2000);
164   memory_configure_bank(machine, "bank5", 0, 4, ram, 0x2000);
165 
166   memory_set_bank(machine, "bank1", 0);
167   memory_set_bank(machine, "bank2", 0);
168   memory_set_bank(machine, "bank3", 0);
169   memory_set_bank(machine, "bank4", 0);
170   memory_set_bank(machine, "bank5", 0);
171}
172 
173static PALETTE_INIT( prestige )
174{
175   palette_set_color(machine, 0, MAKE_RGB(39, 108, 51));
176   palette_set_color(machine, 1, MAKE_RGB(16, 37, 84));
177}
178 
179static VIDEO_START( prestige )
180{
181}
182 
183static VIDEO_UPDATE( prestige )
184{
185   const address_space *program = cputag_get_address_space(screen->machine, "maincpu", ADDRESS_SPACE_PROGRAM);
186   UINT16 addr = 0xe000;
187 
188   for (int y = 0; y < 100; y++)
189   {
190      for (int sx = 0; sx < 30; sx++)
191      {
192         UINT8 data = memory_read_byte(program, addr);
193 
194         for (int x = 0; x < 8; x++)
195         {
196            *BITMAP_ADDR16(bitmap, y, (sx * 8) + x) = BIT(data, 7);
197 
198            data <<= 1;
199         }
200 
201         addr++;
202      }
203   }
204 
205    return 0;
206}
207 
208static DEVICE_IMAGE_LOAD( prestige_cart )
209{
210   return IMAGE_INIT_FAIL;
211}
212 
213static MACHINE_DRIVER_START( prestige )
214    /* basic machine hardware */
215    MDRV_CPU_ADD("maincpu",Z80, XTAL_4MHz)
216    MDRV_CPU_PROGRAM_MAP(prestige_mem)
217    MDRV_CPU_IO_MAP(prestige_io)
218 
219    MDRV_MACHINE_START(prestige)
220 
221    /* video hardware */
222    MDRV_SCREEN_ADD("screen", LCD)
223    MDRV_SCREEN_REFRESH_RATE(50)
224    MDRV_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) /* not accurate */
225    MDRV_SCREEN_FORMAT(BITMAP_FORMAT_INDEXED16)
226   MDRV_SCREEN_SIZE( 240, 100 )
227   MDRV_SCREEN_VISIBLE_AREA( 0, 240-1, 0, 100-1 )
228   MDRV_DEFAULT_LAYOUT( layout_lcd )
229 
230    MDRV_PALETTE_LENGTH(2)
231    MDRV_PALETTE_INIT(prestige)
232 
233    MDRV_VIDEO_START(prestige)
234    MDRV_VIDEO_UPDATE(prestige)
235 
236   /* cartridge */
237   MDRV_CARTSLOT_ADD("cart")
238   MDRV_CARTSLOT_EXTENSION_LIST("bin")
239   MDRV_CARTSLOT_INTERFACE("prestige_cart")
240   MDRV_CARTSLOT_LOAD(prestige_cart)
241 
242   /* internal ram */
243   MDRV_RAM_ADD("messram")
244   MDRV_RAM_DEFAULT_SIZE("32K")
245   MDRV_RAM_EXTRA_OPTIONS("64K")
246MACHINE_DRIVER_END
247 
248/* ROM definition */
249ROM_START( prestige )
250    ROM_REGION( 0x100000, "maincpu", 0 )
251   ROM_LOAD( "27-6020-02.u2", 0x00000, 0x100000, CRC(6bb6db14) SHA1(5d51fc3fd799e7f01ee99c453f9005fb07747b1e) )
252ROM_END
253 
254/* Driver */
255 
256/*    YEAR  NAME    PARENT  COMPAT   MACHINE    INPUT    INIT    COMPANY   FULLNAME       FLAGS */
257COMP( 1998, prestige,  0,       0,   prestige,   prestige,    0,  "VTech",   "PC Prestige Elite",      GAME_NOT_WORKING | GAME_NO_SOUND)
1/*
2
3VTech PreComputer Prestige Elite
4
5PCB Layout
6----------
7
8|-------------------------------------------|
9|   |-------CN1-------|     CN2             |
10|                                           |
11|                                       CN3 |
12|                                           |
13|CN10                                       |
14|CN9            RAM                         --|
15|CN8                                          |
16|                                             |
17|                       Z80         ROM       |
18|               04010                     CN4 |
19|CN7                                          |
20|CN6                                          |
21|                       |------CN5------|   --|
22|-------------------------------------------|
23
24Notes:
25    All IC's shown.
26
27    ROM     - VTech LH5S8R14, labeled "1998 27-6020-02" (dumped as 1Mx8)
28    Z80     - Z80 family SOC?
29    RAM     - LG Semicon GM76C256CLLFW55 32Kx8 Static RAM
30    04010   - ?
31    CN1     - Centronics connector
32    CN2     - mouse connector
33    CN3     - LCD ribbon cable
34    CN4     - expansion connector
35    CN5     - keyboard ribbon cable
36    CN6     - speaker wire
37    CN7     - volume wire
38    CN8     - ? wire
39    CN9     - power wire
40    CN10    - NVRAM battery wire
41*/
42
43/*
44   
45   Undumped cartridges:
46 
47   80-1410   Super Science
48   80-1533   Famous Things & Places
49   80-0989   Bible Knowledge
50   80-1001   Fantasy Trivia
51   80-1002   General Knowledge II
52   80-1003   Sports History
53   80-2314   Familiar Faces
54   80-2315   Historical Happenings
55   80-2333   Arts, Entertainment & More
56   80-2334   Customs & Cultures
57   80-1531   32K RAM Memory Expansion Cartridge
58   80-12051  Space Scholar
59   80-12053  Frenzy of Facts
60   80-12052  Spreadsheet Success
61
62*/
63
64/*
65
66   TODO:
67
68   - identify unknown chips
69   - boot animation won't play
70   - keyboard
71   - mouse
72   - sound
73   - cartridges
74
75*/
76
77#include "emu.h"
78#include "cpu/z80/z80.h"
79#include "devices/messram.h"
80#include "devices/cartslot.h"
81
82static UINT8 bank[6];
83
84static READ8_HANDLER( bankswitch_r )
85{
86   return bank[offset];
87}
88
89static WRITE8_HANDLER( bankswitch_w )
90{
91   const address_space *program = cputag_get_address_space(space->machine, "maincpu", ADDRESS_SPACE_PROGRAM);
92
93   switch (offset)
94   {
95   case 0:
96      memory_set_bank(space->machine, "bank1", data & 0x3f);
97      break;
98
99   case 1:
100      memory_set_bank(space->machine, "bank2", data & 0x3f);
101      break;
102
103   case 2:
104      if (bank[5] == 0x0c)
105      {
106         memory_set_bank(space->machine, "bank3", 0x40 + BIT(data, 7));
107      }
108      else
109      {
110         memory_set_bank(space->machine, "bank3", data & 0x3f);
111      }
112      break;
113
114   case 3:
115      memory_set_bank(space->machine, "bank4", data & 0x03);
116      break;
117
118   case 4:
119      memory_set_bank(space->machine, "bank5", data & 0x03);
120      break;
121
122   case 5:
123      if (data == 0x0c)
124      {
125         memory_install_readwrite_bank(program, 0x8000, 0xbfff, 0, 0, "bank3");
126      }
127      else
128      {
129         memory_unmap_write(program, 0x8000, 0xbfff, 0, 0);
130      }
131   }
132
133   bank[offset] = data;
134}
135
136static ADDRESS_MAP_START(prestige_mem, ADDRESS_SPACE_PROGRAM, 8)
137   AM_RANGE(0x0000, 0x3fff) AM_ROMBANK("bank1")
138   AM_RANGE(0x4000, 0x7fff) AM_ROMBANK("bank2")
139   AM_RANGE(0x8000, 0xbfff) AM_ROMBANK("bank3")
140   AM_RANGE(0xc000, 0xdfff) AM_RAMBANK("bank4")
141   AM_RANGE(0xe000, 0xffff) AM_RAMBANK("bank5")
142ADDRESS_MAP_END
143
144static ADDRESS_MAP_START( prestige_io , ADDRESS_SPACE_IO, 8)
145   ADDRESS_MAP_UNMAP_HIGH
146   ADDRESS_MAP_GLOBAL_MASK(0xff)
147   AM_RANGE(0x50, 0x55) AM_READWRITE(bankswitch_r, bankswitch_w)
148ADDRESS_MAP_END
149
150/* Input ports */
151INPUT_PORTS_START( prestige )
152INPUT_PORTS_END
153
154
155static MACHINE_START(prestige)
156{
157   UINT8 *ram = messram_get_ptr(machine->device("messram"));
158
159   memory_configure_bank(machine, "bank1", 0, 64, memory_region(machine, "maincpu"), 0x4000);
160   memory_configure_bank(machine, "bank2", 0, 64, memory_region(machine, "maincpu"), 0x4000);
161   memory_configure_bank(machine, "bank3", 0, 64, memory_region(machine, "maincpu"), 0x4000);
162   memory_configure_bank(machine, "bank3", 64, 2, ram + 0x8000, 0x4000);
163   memory_configure_bank(machine, "bank4", 0, 4, ram, 0x2000);
164   memory_configure_bank(machine, "bank5", 0, 4, ram, 0x2000);
165
166   memory_set_bank(machine, "bank1", 0);
167   memory_set_bank(machine, "bank2", 0);
168   memory_set_bank(machine, "bank3", 0);
169   memory_set_bank(machine, "bank4", 0);
170   memory_set_bank(machine, "bank5", 0);
171}
172
173static PALETTE_INIT( prestige )
174{
175   palette_set_color(machine, 0, MAKE_RGB(39, 108, 51));
176   palette_set_color(machine, 1, MAKE_RGB(16, 37, 84));
177}
178
179static VIDEO_START( prestige )
180{
181}
182
183static VIDEO_UPDATE( prestige )
184{
185   const address_space *program = cputag_get_address_space(screen->machine, "maincpu", ADDRESS_SPACE_PROGRAM);
186   UINT16 addr = 0xe000;
187
188   for (int y = 0; y < 100; y++)
189   {
190      for (int sx = 0; sx < 30; sx++)
191      {
192         UINT8 data = memory_read_byte(program, addr);
193
194         for (int x = 0; x < 8; x++)
195         {
196            *BITMAP_ADDR16(bitmap, y, (sx * 8) + x) = BIT(data, 7);
197
198            data <<= 1;
199         }
200
201         addr++;
202      }
203   }
204
205    return 0;
206}
207
208static DEVICE_IMAGE_LOAD( prestige_cart )
209{
210   return IMAGE_INIT_FAIL;
211}
212
213static MACHINE_DRIVER_START( prestige )
214    /* basic machine hardware */
215    MDRV_CPU_ADD("maincpu",Z80, XTAL_4MHz)
216    MDRV_CPU_PROGRAM_MAP(prestige_mem)
217    MDRV_CPU_IO_MAP(prestige_io)
218
219    MDRV_MACHINE_START(prestige)
220
221    /* video hardware */
222    MDRV_SCREEN_ADD("screen", LCD)
223    MDRV_SCREEN_REFRESH_RATE(50)
224    MDRV_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) /* not accurate */
225    MDRV_SCREEN_FORMAT(BITMAP_FORMAT_INDEXED16)
226   MDRV_SCREEN_SIZE( 240, 100 )
227   MDRV_SCREEN_VISIBLE_AREA( 0, 240-1, 0, 100-1 )
228   MDRV_DEFAULT_LAYOUT( layout_lcd )
229
230    MDRV_PALETTE_LENGTH(2)
231    MDRV_PALETTE_INIT(prestige)
232
233    MDRV_VIDEO_START(prestige)
234    MDRV_VIDEO_UPDATE(prestige)
235
236   /* cartridge */
237   MDRV_CARTSLOT_ADD("cart")
238   MDRV_CARTSLOT_EXTENSION_LIST("bin")
239   MDRV_CARTSLOT_INTERFACE("prestige_cart")
240   MDRV_CARTSLOT_LOAD(prestige_cart)
241
242   /* internal ram */
243   MDRV_RAM_ADD("messram")
244   MDRV_RAM_DEFAULT_SIZE("32K")
245   MDRV_RAM_EXTRA_OPTIONS("64K")
246MACHINE_DRIVER_END
247
248/* ROM definition */
249ROM_START( prestige )
250    ROM_REGION( 0x100000, "maincpu", 0 )
251   ROM_LOAD( "27-6020-02.u2", 0x00000, 0x100000, CRC(6bb6db14) SHA1(5d51fc3fd799e7f01ee99c453f9005fb07747b1e) )
252ROM_END
253
254/* Driver */
255
256/*    YEAR  NAME    PARENT  COMPAT   MACHINE    INPUT    INIT    COMPANY   FULLNAME       FLAGS */
257COMP( 1998, prestige,  0,       0,   prestige,   prestige,    0,  "VTech",   "PC Prestige Elite",      GAME_NOT_WORKING | GAME_NO_SOUND)

Previous 15994 Revisions Next


© 1998-2018 The MESS Team