Previous 15994 Revisions Next

r2802 Monday 2nd June, 2008 at 08:23:01 UTC by Robbbert
[EXIDY] Committing WIP while I take a break.
[src/mess]mess.mak
[src/mess/drivers]exidy.c
[src/mess/machine]ay31015.c* ay31015.h*

src/mess/machine/ay31015.c
r0r2802
1/****************************************************************************
2 
3   ay31015.c by Robbbert, May 2008
4 
5   Code for the AY3-1015 UART
6 
7   This is cycle-accurate according to the specifications.
8 
9   It supports independent receive and transmit clocks,
10   and transmission and reception can occur simultaneously if desired.
11 
12   Note to any MESSDEVs who might happen to stray here:
13 
14   - If you find bugs, please fix them yourself.
15   - If you want to convert it to a DEVICE, please do so.
16 
17****************************************************************************/
18 
19/* It is not clear in the documentation as to which settings will reset the device.
20   To be safe, we will always reset whenever the control register changes.
21 
22   Also, it not clear exactly what happens under various error conditions.
23   What we do is:
24   1. During receive the stop bit processing is cut short, so we can better
25   synchronise the next byte.
26   2. If a framing error occurs, we do not signal DAV, but instead skip
27   the bad byte and start looking for the next.
28 
29   This device has only been tested successfully at 300 baud, with 8 bits,
30   2 stop bits and no parity.
31 
32   The bit order of the status and control registers is set up to suit the
33   Exidy driver. If you wish to use it for some other driver, use the BITSWAP8
34   macro in the driver.
35 
36Device Data:
37 
38* Common Controls:
39-- Pin 1 - Vcc - 5 volts
40-- Pin 2 - not used
41-- Pin 3 - Gnd - 0 volts
42-- Pin 21 - XR - External Reset - resets all registers to initial state except for the control register
43-- Pin 35 - NP - No Parity - "1" will kill any parity processing
44-- Pin 36 - TSB - Number of Stop Bits - "0" = 1 stop bit; "1" = 2 stop bits. If "1", and 5 bits per character, then we have 1.5 stop bits
45-- pin 37 - NB1
46-- pin 38 - NB2 - Number of bits per character = NB1 + (NB2 * 2) + 5
47-- pin 39 - EPS - Odd or Even Parity Select - "0" = Odd parity; "1" = Even parity. Has no effect if NP is high.
48-- Pin 34 - CS - Control Strobe - Read NP, TSB, EPS, NB1, NB2 into the control register.
49 
50Format of data stream:
51Start bit (low), Bit 0, Bit 1... highest bit, Parity bit (if enabled), 1-2 stop bits (high)
52 
53 
54* Receiver Controls:
55-- Pin 17 - RCP - Clock which is 16x the desired baud rate
56-- Pin 20 - SI - Serial input stream - "1" = Mark (waiting for input), "0" = Space (Start bit) initiates the transfer of a byte
57-- Pin 4 - RDE - "0" causes the received data to appear on RD1 to RD8.
58-- Pins 5 to 12 - RD8 to RD1 - These are the data lines (bits 7 to 0). Data is right-justified.
59-- Pin 16 - SWE - Status word enable - causes the status bits (PE, FE, OR, DAV, TBMT) to appear at the pins.
60-- Pin 19 - DAV - "1" indicates that a byte has been received by the UART, and should now be accepted by the computer
61-- Pin 18 - RDAV - "0" will force DAV low.
62-- Pin 13 - PE - Parity error - "1" indicates that a parity error occured
63-- Pin 14 - FE - Framing error - "1" Indicates that the stop bit was missing
64-- Pin 15 - OR - overrun - "1" indicates that a new character has become available before the computer had accepted the previous character
65 
66* Transmitter controls:
67-- Pin 40 - TCP - Clock which is 16x the desired baud rate
68-- Pin 25 - SO - Serial output stream - it will stay at "1" while no data is being transmitted
69-- Pins 26 to 33 - DB1 to DB8 - These are the data lines containing the byte to be sent
70-- Pin 23 - DS - Data Strobe - "0" will copy DB1 to DB8 into the transmit buffer
71-- Pin 22 - TBMT - Transmit buffer Empty - "1" indicates to the computer that another byte may be sent to the UART
72-- Pin 24 - EOC - End of Character - "0" means that a character is being sent.
73 
74******************************************* COMMON CONTROLS ********************************************************/
75 
76#include "driver.h"
77#include "ay31015.h"
78 
79//typedef struct _ay31015_token ay31015_token;
80static struct // _ay31015_token
81{
82   UINT8 control_reg;
83   UINT8 status_reg;
84   UINT16 second_stop_bit;   // 0, 8, 16
85   UINT16 total_pulses;   // bits * 16
86   UINT8 internal_sample;
87 
88   UINT8 rx_state;
89   UINT8 rx_data;      // byte being received
90   UINT8 rx_buffer;   // received byte waiting to be accepted by computer
91   UINT8 rx_bit_count;
92   UINT8 rx_parity;
93   UINT16 rx_pulses;   // total pulses left
94 
95   UINT8 tx_state;
96   UINT8 tx_data;      // byte being sent
97   UINT8 tx_buffer;   // next byte to send
98   UINT8 tx_parity;
99   UINT16 tx_pulses;   // total pulses left
100   UINT8 si;
101} ay;
102 
103//static struct _ay31015_token ay;
104 
105/* state - must only be altered by the timer callbacks */
106 
107#define IDLE      0
108#define START_BIT   1
109#define PROCESSING   2
110#define PARITY_BIT   3
111#define FIRST_STOP_BIT   4
112#define SECOND_STOP_BIT   5
113#define PREP_TIME   6
114 
115#if 0
116/*-------------------------------------------------
117    get_token - safely gets the data
118-------------------------------------------------*/
119 
120INLINE ay31015_token *get_token(const device_config *device)
121{
122   assert(device != NULL);
123   assert(device->token != NULL);
124   assert(device->type == AY31015);
125   return (ay31015_token *) device->token;
126}
127 
128 
129/*-------------------------------------------------
130    get_config - safely gets the config
131-------------------------------------------------*/
132 
133INLINE const ay31015_config *get_config(const device_config *device)
134{
135   assert(device != NULL);
136   assert(device->token != NULL);
137   assert(device->type == ay31015);
138   return (const ay31015_config *) device->static_config;
139}
140 
141 
142static DEVICE_START(ay31015)
143{
144   ay31015_token *ay;
145//   const ay31015_config *config = get_config(device);
146 
147   ay = get_token(device);
148}
149#endif
150 
151 
152/*-------------------------------------------------
153    ay31015_xr - the reset pin
154-------------------------------------------------*/
155static void ay31015_xr( void )
156{
157   /* total pulses = 16 * data-bits */
158   UINT8 t1;
159   t1 = (ay.control_reg & 3) + 5;               /* data bits */
160   ay.total_pulses = t1 << 4;               /* total clock pulses to load a byte */
161   ay.second_stop_bit = ((ay.control_reg & AY31015_TSB) ? 1 : 0) << 4;      /* 2nd stop bit */
162   if ((t1 == 5) && (ay.second_stop_bit == 16))
163      ay.second_stop_bit = 8;            /* 5 data bits and 2 stop bits = 1.5 stop bits */
164   ay.status_reg = AY31015_EOC | AY31015_TBMT | AY31015_SO;
165   ay.rx_data = 0;
166   ay.tx_data = 0;
167   ay.rx_state = PREP_TIME;
168   ay.tx_state = IDLE;
169   ay.si = 1;
170}
171 
172 
173/*-------------------------------------------------
174    ay31015_init - drivers should call this at
175    machine reset time
176-------------------------------------------------*/
177void ay31015_init( void )
178{
179   ay.control_reg = 0;
180   ay31015_xr();
181}
182 
183 
184/*-------------------------------------------------
185    ay31015_cs - The entire control register is
186    updated at once.
187-------------------------------------------------*/
188void ay31015_cs( UINT8 data )
189{
190   UINT8 t1 = ay.control_reg;
191   ay.control_reg = data;
192   if (ay.control_reg != t1) ay31015_xr();
193}
194 
195 
196/*************************************************** RECEIVE CONTROLS *************************************************/
197 
198 
199/*-------------------------------------------------
200    ay31015_rx_process - convert serial to parallel
201-------------------------------------------------*/
202static TIMER_CALLBACK( ay31015_rx_process )
203{
204   switch (ay.rx_state)
205   {
206      case PREP_TIME:                     // assist sync by ensuring high bit occurs
207         ay.rx_pulses--;
208         if (ay.si)
209            ay.rx_state = IDLE;
210         return;
211 
212      case IDLE:
213         ay.rx_pulses--;
214         if (!ay.si)
215         {
216            ay.rx_state = START_BIT;
217            ay.rx_pulses = 16;
218         }
219         return;
220 
221      case START_BIT:
222         ay.rx_pulses--;
223         if ((ay.rx_pulses == 8) && (ay.si))         // start bit must be low at sample time
224            ay.rx_state = IDLE;
225         else
226         if (!ay.rx_pulses)               // end of start bit
227         {
228            ay.rx_state = PROCESSING;
229            ay.rx_pulses = ay.total_pulses;
230            ay.rx_bit_count = 0;
231            ay.rx_parity = 0;
232            ay.rx_data = 0;
233         }
234         return;
235 
236      case PROCESSING:
237         ay.rx_pulses--;
238         if (!ay.rx_pulses)               // end of a byte
239         {
240            ay.rx_pulses = 16;
241            if (ay.control_reg & AY31015_NP)      // see if we need to get a parity bit
242               ay.rx_state = FIRST_STOP_BIT;
243            else
244               ay.rx_state = PARITY_BIT;
245         }
246         else
247         if (!(ay.rx_pulses & 15))            // end of a bit
248            ay.rx_bit_count++;
249         else
250         if ((ay.rx_pulses & 15) == 8)            // sample input stream
251         {
252            ay.internal_sample = ay.si;
253            ay.rx_parity ^= ay.internal_sample;      // calculate cumulative parity
254            ay.rx_data |= ay.internal_sample << ay.rx_bit_count;
255         }
256         return;
257 
258      case PARITY_BIT:
259         ay.rx_pulses--;
260 
261         if (ay.rx_pulses == 8)               // sample input stream
262            ay.rx_parity ^= ay.si;            // calculate cumulative parity
263         else
264         if (!ay.rx_pulses)               // end of a byte
265         {
266            ay.rx_pulses = 16;
267            ay.rx_state = FIRST_STOP_BIT;
268 
269            if ((ay.status_reg & AY31015_EPS) && (ay.rx_parity))
270               ay.rx_parity = 0;         // odd parity, ok
271            else
272            if ((!(ay.status_reg & AY31015_EPS)) && (!ay.rx_parity))
273               ay.rx_parity = 0;         // even parity, ok
274            else
275               ay.rx_parity = 1;         // parity error
276         }
277         return;
278 
279      case FIRST_STOP_BIT:
280         ay.rx_pulses--;
281         if (ay.rx_pulses == 8)            // sample input stream
282            ay.internal_sample = ay.si;
283         else
284         if (ay.rx_pulses == 7)            // set error flags
285         {
286            if (!ay.internal_sample)
287            {
288               ay.status_reg |= AY31015_FE;      // framing error - the stop bit not high
289               ay.rx_state = PREP_TIME;      // lost sync - start over
290         //      return;
291            }
292            else
293               ay.status_reg &= ~AY31015_FE;
294 
295            if ((ay.rx_parity) && (!(ay.control_reg & AY31015_NP)))
296               ay.status_reg |= AY31015_PE;      // parity error
297            else
298               ay.status_reg &= ~AY31015_PE;
299 
300            if (ay.status_reg & AY31015_DAV)
301               ay.status_reg |= AY31015_OR;      // overrun error - previous byte still in buffer
302            else
303               ay.status_reg &= ~AY31015_OR;
304 
305            ay.rx_buffer = ay.rx_data;      // bring received byte out for computer to read
306         }
307         else
308         if (ay.rx_pulses == 6)
309            ay.status_reg |= AY31015_DAV;      // tell computer that new byte is ready
310         else
311         if (ay.rx_pulses == 4)
312 
313   /* According to the specs, this commented-out code is what happens.
314      However, it is not particularly effective at keeping sync.
315      Therefore, since the input is HIGH, we simply jump to PREP_TIME and
316      wait for the next start bit to begin. */
317 
318//         if (!ay.rx_pulses)            // end of first stop bit
319//         {
320//            if (ay.second_stop_bit)
321//            {
322//               ay.rx_state = SECOND_STOP_BIT;
323//               ay.rx_pulses = ay.second_stop_bit - 2;
324//            }
325//            else
326//               ay.rx_state = PREP_TIME;
327//         }
328//         return;
329//         
330//      case SECOND_STOP_BIT:
331//         ay.rx_pulses--;
332//         if (!ay.rx_pulses)
333            ay.rx_state = PREP_TIME;
334         return;
335   }
336}
337 
338 
339/*-------------------------------------------------
340    ay31015_set_rx_clock_speed - set receive clock
341-------------------------------------------------*/
342void ay31015_set_rx_clock_speed( UINT32 data )
343{
344//   if (data)
345      timer_pulse(ATTOTIME_IN_HZ(data),NULL,0,ay31015_rx_process);
346//   else
347//      turn timer off;
348}
349 
350/*-------------------------------------------------
351    ay31015_swe - The entire status register is
352    returned at once.
353-------------------------------------------------*/
354UINT8 ay31015_swe( void )
355{
356   return ay.status_reg & 0x3f;
357}
358 
359 
360/*-------------------------------------------------
361    ay31015_rde - return a byte to the computer
362-------------------------------------------------*/
363UINT8 ay31015_rde( void )
364{
365   return ay.rx_buffer;
366}
367 
368 
369/*-------------------------------------------------
370    ay31015_rdav - tell uart computer has retrieved
371    the above byte.
372-------------------------------------------------*/
373void ay31015_rdav( void )
374{
375   ay.status_reg &= ~AY31015_DAV;      /* set dav low */
376}
377 
378 
379/*-------------------------------------------------
380    ay31015_si - send a serial bit to the uart
381-------------------------------------------------*/
382void ay31015_si( UINT8 data )
383{
384   ay.si = (data) ? 1 : 0;
385}
386 
387 
388/*************************************************** TRANSMIT CONTROLS *************************************************/
389 
390 
391/*-------------------------------------------------
392    ay31015_tx_process - convert parallel to serial
393-------------------------------------------------*/
394static TIMER_CALLBACK( ay31015_tx_process )
395{
396   UINT8 t1;
397   switch (ay.tx_state)
398   {
399      case IDLE:
400         if (!(ay.status_reg & AY31015_TBMT))
401         {
402            ay.tx_state = PREP_TIME;      // When idle, see if a byte has been sent to us
403            ay.tx_pulses = 1;
404         }
405         return;
406 
407      case PREP_TIME:                  // This phase lets the transmitter regain sync after an idle period
408         ay.tx_pulses--;
409         if (!ay.tx_pulses)
410         {
411            ay.tx_state = START_BIT;
412            ay.tx_pulses = 16;
413         }
414         return;
415 
416      case START_BIT:
417         if (ay.tx_pulses == 16)            // beginning of start bit
418         {
419            ay.tx_data = ay.tx_buffer;         // load the shift register
420            ay.status_reg |= AY31015_TBMT;         // tell computer that another byte can be sent to uart
421            ay.status_reg &= ~AY31015_SO;         // start bit begins now (we are "spacing")
422            ay.status_reg &= ~AY31015_EOC;         // we are no longer idle
423            ay.tx_parity = 0;
424         }
425 
426         ay.tx_pulses--;
427         if (!ay.tx_pulses)               // end of start bit
428         {
429            ay.tx_state = PROCESSING;
430            ay.tx_pulses = ay.total_pulses;
431         }
432         return;
433 
434      case PROCESSING:
435         if (!(ay.tx_pulses & 15))            // beginning of a data bit
436         {
437            if (ay.tx_data & 1)
438            {
439               ay.status_reg |= AY31015_SO;
440               ay.tx_parity++;            // calculate cumulative parity
441            }
442            else
443               ay.status_reg &= ~AY31015_SO;
444 
445            ay.tx_data >>= 1;            // adjust the shift register
446         }
447             
448         ay.tx_pulses--;
449         if (!ay.tx_pulses)               // all data bits sent
450         {
451            ay.tx_pulses = 16;
452            if (ay.control_reg & AY31015_NP)      // see if we need to make a parity bit
453               ay.tx_state = FIRST_STOP_BIT;
454            else
455               ay.tx_state = PARITY_BIT;
456         }
457 
458         return;
459 
460      case PARITY_BIT:
461         if (ay.tx_pulses == 16)
462         {
463            t1 = (ay.control_reg & AY31015_EPS) ? 0 : 1;
464            t1 ^= (ay.tx_parity & 1);
465            if (t1)
466               ay.status_reg |= AY31015_SO;      // extra bit to set the correct parity
467            else
468               ay.status_reg &= ~AY31015_SO;      // it was already correct
469         }
470 
471         ay.tx_pulses--;
472         if (!ay.tx_pulses)
473         {
474            ay.tx_state = FIRST_STOP_BIT;
475            ay.tx_pulses = 16;
476         }
477         return;
478 
479      case FIRST_STOP_BIT:
480         if (ay.tx_pulses == 16)
481            ay.status_reg |= AY31015_SO;         // create a stop bit (marking and soon idle)
482         ay.tx_pulses--;
483         if (!ay.tx_pulses)
484         {
485            ay.status_reg |= AY31015_EOC;         // character is completely sent
486            if (ay.second_stop_bit)
487            {
488               ay.tx_state = SECOND_STOP_BIT;
489               ay.tx_pulses = ay.second_stop_bit;
490            }
491            else
492            if (ay.status_reg & AY31015_TBMT)
493               ay.tx_state = IDLE;         // if nothing to send, go idle
494            else
495            {
496               ay.tx_pulses = 16;
497               ay.tx_state = START_BIT;      // otherwise immediately start next byte
498            }
499         }
500         return;
501 
502      case SECOND_STOP_BIT:
503         ay.tx_pulses--;
504         if (!ay.tx_pulses)
505         {
506            if (ay.status_reg & AY31015_TBMT)
507               ay.tx_state = IDLE;         // if nothing to send, go idle
508            else
509            {
510               ay.tx_pulses = 16;
511               ay.tx_state = START_BIT;      // otherwise immediately start next byte
512            }
513         }
514         return;
515 
516   }
517}
518 
519 
520/*-------------------------------------------------
521    ay31015_set_tx_clock_speed - set transmit clock
522-------------------------------------------------*/
523void ay31015_set_tx_clock_speed( UINT32 data )
524{
525//   if (data)
526      timer_pulse(ATTOTIME_IN_HZ(data),NULL,0,ay31015_tx_process);
527//   else
528//      turn timer off;
529}
530 
531 
532/*-------------------------------------------------
533    ay31015_so - return a serial bit to calling
534    driver.
535-------------------------------------------------*/
536UINT8 ay31015_so( void )
537{
538   return (ay.status_reg & AY31015_SO) ? 1 : 0;
539}
540 
541 
542/*-------------------------------------------------
543    ay31015_ds - accept a byte to transmit, if able
544-------------------------------------------------*/
545void ay31015_ds( UINT8 data )
546{
547   if (ay.status_reg & AY31015_TBMT)
548   {
549      ay.tx_buffer = data;
550      ay.status_reg &= ~AY31015_TBMT;
551   }
552}
553 
554 
555 
556#if 0
557 
558void 
559   ay31015_token *ay = get_token(device);
560   const ay31015_config *config = get_config(device);
561 
562 
563/*-------------------------------------------------
564    DEVICE_GET_INFO(ay31015) - device getinfo
565   function
566-------------------------------------------------*/
567 
568DEVICE_GET_INFO(ay31015)
569{
570   switch(state)
571   {
572      /* --- the following bits of info are returned as 64-bit signed integers --- */
573      case DEVINFO_INT_TOKEN_BYTES:         info->i = sizeof(ay31015_token); break;
574      case DEVINFO_INT_INLINE_CONFIG_BYTES:      info->i = 0; break;
575      case DEVINFO_INT_CLASS:            info->i = DEVICE_CLASS_PERIPHERAL; break;
576      case DEVINFO_INT_IMAGE_TYPE:         info->i = IO_PRINTER; break;
577      case DEVINFO_INT_IMAGE_READABLE:      info->i = 0; break;
578      case DEVINFO_INT_IMAGE_WRITEABLE:      info->i = 1; break;
579      case DEVINFO_INT_IMAGE_CREATABLE:      info->i = 1; break;
580 
581      /* --- the following bits of info are returned as pointers to data or functions --- */
582      case DEVINFO_FCT_START:            info->start = DEVICE_START_NAME(ay31015); break;
583 
584      /* --- the following bits of info are returned as NULL-terminated strings --- */
585      case DEVINFO_STR_NAME:            info->s = "ay31015"; break;
586      case DEVINFO_STR_FAMILY:         info->s = "ay31015"; break;
587      case DEVINFO_STR_SOURCE_FILE:         info->s = __FILE__; break;
588      case DEVINFO_STR_IMAGE_FILE_EXTENSIONS:      info->s = "prn"; break;
589   }
590}
591#endif
592 
src/mess/machine/ay31015.h
r0r2802
1/* ay31015.h
2 
3   Written for MESS by Robbbert on May 29th, 2008.
4 
5*/
6 
7/* control reg */
8#define AY31015_NB1   0x01
9#define AY31015_NB2   0x02
10#define AY31015_TSB   0x04
11#define AY31015_EPS   0x08
12#define AY31015_NP   0x10
13 
14/* status reg */
15#define AY31015_TBMT   0x01
16#define AY31015_DAV   0x02
17#define AY31015_OR   0x04
18#define AY31015_FE   0x08
19#define AY31015_PE   0x10
20#define AY31015_EOC   0x20
21 
22#define AY31015_SO   0x40
23 
24// Reset the device
25void ay31015_init( void );
26 
27// Set Control register
28void ay31015_cs( UINT8 data );
29 
30// Set Receive Clock
31void ay31015_set_rx_clock_speed( UINT32 data );
32 
33// Read status register
34UINT8 ay31015_swe( void );
35 
36// Send a bit to the device
37void ay31015_si( UINT8 data );
38 
39// Read a byte from the device
40UINT8 ay31015_rde( void );
41 
42// Tell device you have read the data
43void ay31015_rdav( void );
44 
45// Set Transmit Clock
46void ay31015_set_tx_clock_speed( UINT32 data );
47 
48// Get serialised output
49UINT8 ay31015_so( void );
50 
51// Send a byte to the device
52void ay31015_ds( UINT8 data );
src/mess/mess.mak
r2801r2802
999999   $(MESS_MACHINE)/aquarius.o \
10001000
10011001$(MESSOBJ)/exidy.a:    \
1002   $(MESS_MACHINE)/hd6402.o     \
1002   $(MESS_MACHINE)/ay31015.o   \
10031003   $(MESS_DRIVERS)/exidy.o      \
10041004   $(MESS_VIDEO)/exidy.o      \
10051005
src/mess/drivers/exidy.c
r2801r2802
88    port fc:
99    ========
1010    input/output:
11        hd6402 uart data
11        uart data
1212
1313    port fd:
1414    ========
15    input: hd6402 uart status
15    input: uart status
1616        bit 4: parity error (RPE)
1717        bit 3: framing error (RFE)
1818        bit 2: over-run (RDP)
r2801r2802
5555
5656    The cassette interface hardware converts square-wave pulses into bits which the uart receives.
5757
58    1. the cassette format: "frequency shift" is converted
59    into the uart data format "non-return to zero"
5860
61    2. on cassette a 1 data bit is stored as a high frequency
62    and a 0 data bit as a low frequency
63    - At 1200 baud, a logic 1 is 1 cycle of 1200hz and a logic 0 is 1/2 cycle of 600hz.
64    - At 300 baud, a logic 1 is 8 cycles of 2400hz and a logic 0 is 4 cycles of 1200hz.
65
66    Attenuation is applied to the signal and the square wave edges are rounded.
67
68    A manchester encoder is used. A flip-flop synchronises input
69    data on the positive-edge of the clock pulse.
70
71    Interestingly the data on cassette is stored in xmodem-checksum.
72
73
74   Due to bugs in the hardware and software of a real Sorcerer, the serial
75   interface misbehaves.
76   1. Sorcerer I had a hardware problem causing rs232 idle to be a space (+9v)
77   instead of mark (-9v). Fixed in Sorcerer II.
78   2. When you select a different baud for rs232, it was "remembered" but not
79   sent to port fe. It only gets sent when motor on was requested. Motor on is
80   only meaningful in a cassette operation.
81   3. The monitor software always resets the device to cassette whenever the
82   keyboard is scanned, motors altered, or an error occurred.
83   4. The above problems make rs232 communication impractical unless you write
84   your own routines or create a corrected monitor rom.
85
5986    Sound:
6087
6188    external speaker connected to the parallel port
r2801r2802
6693
6794 ******************************************************************************
6895
69    The Sorcerer comes with a non-standard Serial Port with connections for
70    rs232 and the 2 cassette players. The connections for cassette 1 are duplicated
71    on a set of phono plugs.
72
7396    The CPU clock speed is 2.106mhz, which was increased to 4.0mhz on the last production runs.
7497
7598    The Sorcerer has a bus connection for S100 equipment. This allows the connection
r2801r2802
79102
80103    The driver "exidyd" emulates the most common form, a cassette-based system with 48k of ram.
81104
105*******************************************************************************
82106
107
108Emulation status:
109
110exidy: 32k disk-based system. Disks not tested. Optional S-100 interface not implemented.
111exidyd: 48k cassette-based system. Disks and S-100 are not options on this system.
112
113Real machines had optional RAM sizes of 4k, 16k, 32k, 48k (officially).
114Unofficially, the cart could hold another 8k of static RAM (4x 6116), giving 56k total.
115
116On the back of the machine is a 50-pin expansion port, which could be hooked to the
117expansion unit.
118
119Also is a 25-pin parallel port, allowing inwards and outwards communication.
120It was often hooked to a printer, a joystick, a music card, or a speaker.
121
122We emulate the printer and the speaker.
123
124Another 25-pin port provided two-way serial communications. Only two speeds are
125available - 300 baud and 1200 baud. There is no handshaking. This protocol is
126currently not emulated.
127
128Other pins on this connector provided for two cassette players. The connections
129for cassette unit 1 are duplicated on a set of phono plugs.
130
131We emulate the use of two cassette units. An option allows you to hear the sound
132of the tape during playback.
133
134The sorcerer has a UART device used by the serial interface and the cassette system.
135So far, it has been tested to work at 300 baud.
136
83137********************************************************************************/
84138#include "driver.h"
85139#include "includes/exidy.h"
86140#include "machine/centroni.h"
87#include "machine/hd6402.h"
88141#include "cpu/z80/z80.h"
89142#include "machine/wd17xx.h"
90143#include "devices/basicdsk.h"
r2801r2802
94147#include "devices/printer.h"
95148#include "devices/z80bin.h"
96149#include "sound/speaker.h"
150#include "machine/ay31015.h"
97151
98152
99153static Z80BIN_EXECUTE( exidy );
r2801r2802
111165}
112166
113167
114static unsigned char exidy_fe;
115static int exidy_keyboard_line;
116static unsigned long exidy_hd6402_state;
168static UINT8 exidy_fe = 0xff;
169static UINT8 exidy_keyboard_line;
117170
118171static WRITE8_HANDLER(exidy_fe_port_w);
119172
173#if 0
174
175The serial code (which was never connected to the outside) is disabled for now.
176
120177/* timer for exidy serial chip transmit and receive */
121static emu_timer *serial_timer;
178//static emu_timer *serial_timer;
122179
123static TIMER_CALLBACK(exidy_serial_timer_callback)
124{
180//static TIMER_CALLBACK(exidy_serial_timer_callback)
181//{
125182   /* if rs232 is enabled, uart is connected to clock defined by bit6 of port fe.
126183    Transmit and receive clocks are connected to the same clock */
127184
128185   /* if rs232 is disabled, receive clock is linked to cassette hardware */
129   if (exidy_fe & 0x080)
130   {
131      /* trigger transmit clock on hd6402 */
132      hd6402_transmit_clock();
133      /* trigger receive clock on hd6402 */
134      hd6402_receive_clock();
135   }
136}
186//   if (exidy_fe & 0x80)
187//   {
188      connect to rs232
189//   }
190//}
191#endif
137192
138193
139
140194/* timer to read cassette waveforms */
141static void *cassette_timer;
195static emu_timer *cassette_timer;
142196
143/* cassette data is converted into bits which are clocked into serial chip */
144static struct serial_connection cassette_serial_connection;
145197
146/* two flip-flops used to store state of bit coming from cassette */
147static int cassette_input_ff[2];
148/* state of clock, used to clock in bits */
149static int cassette_clock_state;
150/* a up-counter. when this reaches a fixed value, the cassette clock state is changed */
151static int cassette_clock_counter;
198static const device_config *cassette_device_image(void)
199{
200   if (exidy_fe & 0x20)
201      return image_from_devtype_and_index(IO_CASSETTE, 1);
202   else
203      return image_from_devtype_and_index(IO_CASSETTE, 0);
204}
152205
153/*  1. the cassette format: "frequency shift" is converted
154    into the uart data format "non-return to zero"
206static UINT8 cass_data[]={ 0, 0, 0, 0, 0, 0, 0 };
155207
156    2. on cassette a 1 data bit is stored as a high frequency
157    and a 0 data bit as a low frequency
158    - At 1200 baud, a logic 1 is 1 cycle of 1200hz and a logic 0 is 1/2 cycle of 600hz.
159    - At 300 baud, a logic 1 is 8 cycles of 2400hz and a logic 0 is 4 cycles of 1200hz.
208static TIMER_CALLBACK(exidy_cassette_tc)
209{
210   UINT8 cass_ws = 0;
211   switch (exidy_fe & 0xc0)      // bit 7 low indicates cassette
212   {
213      case 0x00:            // cassette 300 baud - works
160214
161    Attenuation is applied to the signal and the square wave edges are rounded.
215         /* loading a tape - this is basically the same as the super80.
216            We convert the 1200/2400 Hz signal to a 0 or 1, and send it to the uart. */
162217
163    A manchester encoder is used. A flip-flop synchronises input
164    data on the positive-edge of the clock pulse.
218         cass_data[1]++;
165219
166    Interestingly the data on cassette is stored in xmodem-checksum.
220         cass_ws = (cassette_input(cassette_device_image()) > +0.02) ? 1 : 0;
167221
222         if (cass_ws != cass_data[0])
223         {
224            cass_data[0] = cass_ws;
225            cass_data[2] = ((cass_data[1] < 0x6) || (cass_data[1] > 0x20)) ? 1 : 0;
226            cass_data[1] = 0;
227            if (cass_data[2] != cass_data[3])
228            {
229               ay31015_si(cass_data[2]);
230               cass_data[3] = cass_data[2];
231            }
232         }
168233
169*/
234         /* saving a tape - convert the serial stream from the uart, into 1200 and 2400 Hz frequencies.
235            Synchronisation of the frequency pulses to the uart is extremely important. */
170236
171/* only works for one cassette so far */
172static TIMER_CALLBACK(exidy_cassette_timer_callback)
173{
174   cassette_clock_counter++;
237         cass_data[5]++;
238         if (!(cass_data[5] & 0x1f))
239         {
240            cass_ws = ay31015_so();
241            if (cass_ws != cass_data[4])
242            {
243               cass_data[4] = cass_ws;
244               cass_data[5]=0;
245            }
246         }
175247
176   if (cassette_clock_counter==(4800/1200))
177   {
178      /* reset counter */
179      cassette_clock_counter = 0;
248         if (!(cass_data[5] & 3))
249         {
250            if (!((cass_data[4] == 0) && (cass_data[5] & 4)))
251            {
252               cass_data[6] ^= 1;         // toggle output state, except on 2nd half of low bit
253               cassette_output(cassette_device_image(), cass_data[6] ? -1.0 : +1.0);
254            }
255         }
256         return;
180257
181      /* toggle state of clock */
182      cassette_clock_state^=0x0ffffffff;
258      case 0x40:            // cassette 1200 baud - not working at this time
259         /* loading a tape */
260         cass_data[1]++;
183261
184      /* previously was 0, now gone 1 */
185      /* +ve edge detected */
186      if (cassette_clock_state)
187      {
188         int bit;
262         cass_ws = (cassette_input(cassette_device_image()) > +0.02) ? 1 : 0;
189263
190         /* clock bits into cassette flip flops */
191         /* bit is inverted! */
264         if (cass_ws != cass_data[0])
265         {
266            cass_data[0] = cass_ws;
267            cass_data[2] = ((cass_data[1] < 0xc) || (cass_data[1] > 0x20)) ? 1 : 0;
268            cass_data[1] = 0;
269            if (cass_data[2] != cass_data[3])
270            {
271               ay31015_si(cass_data[2]);
272               cass_data[3] = cass_data[2];
273            }
274            cass_data[2] = 0;
275         }
192276
193         /* detect level */
194         bit = 1;
195         if (cassette_input(image_from_devtype_and_index(IO_CASSETTE, 0)) > 0.0038)
196            bit = 0;
197         cassette_input_ff[0] = bit;
198         /* detect level */
199         bit = 1;
200         if (cassette_input(image_from_devtype_and_index(IO_CASSETTE, 1)) > 0.0038)
201            bit = 0;
277         /* saving a tape - convert the serial stream from the uart, into 600 and 1200 Hz frequencies. */
202278
203         cassette_input_ff[1] = bit;
279         cass_data[5]++;
280         if (!(cass_data[5] & 0x07))
281         {
282            cass_ws = ay31015_so();
283            if (cass_ws != cass_data[4])
284            {
285               cass_data[4] = cass_ws;
286               cass_data[5]=0;
287            }
288         }
204289
205         logerror("cassette bit: %0d\n",bit);
206
207         /* set out data bit */
208         set_out_data_bit(cassette_serial_connection.State, cassette_input_ff[0]);
209         /* output through serial connection */
210         serial_connection_out(&cassette_serial_connection);
211
212         /* update hd6402 receive clock */
213         hd6402_receive_clock();
214      }
290         if (!(cass_data[5] & 7))
291         {
292            if (!((cass_data[4] == 0) && (cass_data[5] & 8)))
293            {
294               cass_data[6] ^= 1;         // toggle output state, except on 2nd half of low bit
295               cassette_output(cassette_device_image(), cass_data[6] ? -1.0 : +1.0);
296            }
297         }
298         return;
215299   }
216300}
217301
218static void exidy_hd6402_callback(int mask, int data)
219{
220   exidy_hd6402_state &=~mask;
221   exidy_hd6402_state |= (data & mask);
222
223   logerror("hd6402 state: %04x %04x\n",mask,data);
224}
225
226/* after the first 4 bytes have been read from ROM, switch the ram back in */
227static TIMER_CALLBACK( exidy_reset )
228{
229   memory_set_bank(1, 0);
230}
231
232302static void exidy_printer_handshake_in(int number, int data, int mask)
233303{
234304   if (mask & CENTRONICS_ACKNOWLEDGE)
r2801r2802
246316   },
247317};
248318
249static void cassette_serial_in(int id, unsigned long state)
319
320/* after the first 4 bytes have been read from ROM, switch the ram back in */
321static TIMER_CALLBACK( exidy_reset )
250322{
251   cassette_serial_connection.input_state = state;
323   memory_set_bank(1, 0);
252324}
253325
254326static MACHINE_START( exidyd )
255327{
256   serial_timer = timer_alloc(exidy_serial_timer_callback, NULL);
257   cassette_timer = timer_alloc(exidy_cassette_timer_callback, NULL);
328//   serial_timer = timer_alloc(exidy_serial_timer_callback, NULL);
329   cassette_timer = timer_alloc(exidy_cassette_tc, NULL);
258330}
259331
260332static MACHINE_START( exidy )
r2801r2802
265337
266338static MACHINE_RESET( exidyd )
267339{
268   hd6402_init();
269   hd6402_set_callback(exidy_hd6402_callback);
270   hd6402_reset();
340   ay31015_init();
271341
272342   centronics_config(0, exidy_cent_config);
273343   /* assumption: select is tied low */
274344   centronics_write_handshake(0, CENTRONICS_SELECT | CENTRONICS_NO_RESET, CENTRONICS_SELECT| CENTRONICS_NO_RESET);
275
276   serial_connection_init(&cassette_serial_connection);
277   serial_connection_set_in_callback(&cassette_serial_connection, cassette_serial_in);
278
279345   exidy_fe_port_w(machine, 0, 0);
280346
281347   timer_set(ATTOTIME_IN_USEC(10), NULL, 0, exidy_reset);
r2801r2802
330396
331397static WRITE8_HANDLER(exidy_fc_port_w)
332398{
333   logerror("exidy fc w: %04x %02x\n",offset,data);
334
335   hd6402_set_input(HD6402_INPUT_TBRL, HD6402_INPUT_TBRL);
336   hd6402_data_w(machine, offset, data);
399   ay31015_ds( data );
337400}
338401
339402
340403static WRITE8_HANDLER(exidy_fd_port_w)
341404{
342   logerror("exidy fd w: %04x %02x\n",offset,data);
343
344   /* bit 0,1: char length select */
345   if (data & 1)
346      hd6402_set_input(HD6402_INPUT_CLS1, HD6402_INPUT_CLS1);
347   else
348      hd6402_set_input(HD6402_INPUT_CLS1, 0);
349
350   if (data & 2)
351      hd6402_set_input(HD6402_INPUT_CLS2, HD6402_INPUT_CLS2);
352   else
353      hd6402_set_input(HD6402_INPUT_CLS2, 0);
354
355   /* bit 2: stop bit count */
356   if (data & 4)
357      hd6402_set_input(HD6402_INPUT_SBS, HD6402_INPUT_SBS);
358   else
359      hd6402_set_input(HD6402_INPUT_SBS, 0);
360
361   /* bit 3: parity type select */
362   if (data & 8)
363      hd6402_set_input(HD6402_INPUT_EPE, HD6402_INPUT_EPE);
364   else
365      hd6402_set_input(HD6402_INPUT_EPE, 0);
366
367   /* bit 4: inhibit parity (no parity) */
368   if (data & 16)
369      hd6402_set_input(HD6402_INPUT_PI, HD6402_INPUT_PI);
370   else
371      hd6402_set_input(HD6402_INPUT_PI, 0);
405   ay31015_cs( data );
372406}
373407
374408#define EXIDY_CASSETTE_MOTOR_MASK ((1<<4)|(1<<5))
r2801r2802
376410
377411static WRITE8_HANDLER(exidy_fe_port_w)
378412{
379   int changed_bits;
413   UINT8 changed_bits = (exidy_fe ^ data) & 0xf0;
414   exidy_fe = data;
415
380416   /* bits 0..3 */
381417   exidy_keyboard_line = data & 0x0f;
382418
383   changed_bits = exidy_fe^data;
419   if (!changed_bits) return;
420
384421   /* bits 4..5 */
385   /* either cassette motor state changed */
386   if ((changed_bits & EXIDY_CASSETTE_MOTOR_MASK)!=0)
422   /* does user want to hear the sound? */
423   if ((input_port_read(machine, "CONFIG") & 8) && (data & EXIDY_CASSETTE_MOTOR_MASK))
387424   {
388      /* cassette 1 motor */
389      cassette_change_state(image_from_devtype_and_index(IO_CASSETTE, 0),
390         (data & 0x10) ? CASSETTE_MOTOR_ENABLED : CASSETTE_MOTOR_DISABLED,
391         CASSETTE_MASK_MOTOR);
392
393      /* cassette 2 motor */
394      cassette_change_state(image_from_devtype_and_index(IO_CASSETTE, 1),
395         (data & 0x20) ? CASSETTE_MOTOR_ENABLED : CASSETTE_MOTOR_DISABLED,
396         CASSETTE_MASK_MOTOR);
397
398      if ((data & EXIDY_CASSETTE_MOTOR_MASK)==0)
425      if (data & 0x20)
399426      {
400         /* both are now off */
401
402         /* stop timer */
403         timer_adjust_oneshot(cassette_timer, attotime_zero, 0);
427         cassette_change_state(image_from_devtype_and_index(IO_CASSETTE, 0), CASSETTE_SPEAKER_MUTED, CASSETTE_MASK_SPEAKER);
428         cassette_change_state(image_from_devtype_and_index(IO_CASSETTE, 1), CASSETTE_SPEAKER_ENABLED, CASSETTE_MASK_SPEAKER);
404429      }
405430      else
406431      {
407         /* if both motors were off previously, at least one motor has been switched on */
408         if ((exidy_fe & EXIDY_CASSETTE_MOTOR_MASK)==0)
409         {
410            cassette_clock_counter = 0;
411            cassette_clock_state = 0;
412            /* start timer */
413            /* the correct baud rate should be being used here (see bit 6 below) */
414            timer_adjust_periodic(cassette_timer, attotime_zero, 0, ATTOTIME_IN_HZ(4800));
415         }
432         cassette_change_state(image_from_devtype_and_index(IO_CASSETTE, 1), CASSETTE_SPEAKER_MUTED, CASSETTE_MASK_SPEAKER);
433         cassette_change_state(image_from_devtype_and_index(IO_CASSETTE, 0), CASSETTE_SPEAKER_ENABLED, CASSETTE_MASK_SPEAKER);
416434      }
417435   }
418   /* bit 7 */
419   if (data & 0x080)
436   else
420437   {
421      /* connect to serial device (not yet emulated) */
422   /* Due to bugs in the hardware and software of a real Sorcerer, the serial
423   interface misbehaves.
424   1. Sorcerer I had a hardware problem causing rs232 idle to be a space (+9v)
425   instead of mark (-9v). Fixed in Sorcerer II.
426   2. When you select a different baud for rs232, it was "remembered" but not
427   sent to port fe. It only gets sent when motor on was requested. Motor on is
428   only meaningful in a cassette operation.
429   3. The monitor software always resets the device to cassette whenever the
430   keyboard is scanned, motors altered, or an error occurred.
431   4. The above problems make rs232 communication impractical unless you write
432   your own routines or create a corrected monitor rom. */
438      cassette_change_state(image_from_devtype_and_index(IO_CASSETTE, 1), CASSETTE_SPEAKER_MUTED, CASSETTE_MASK_SPEAKER);
439      cassette_change_state(image_from_devtype_and_index(IO_CASSETTE, 0), CASSETTE_SPEAKER_MUTED, CASSETTE_MASK_SPEAKER);
433440   }
441
442   /* cassette 1 motor */
443   cassette_change_state(image_from_devtype_and_index(IO_CASSETTE, 0),
444      (data & 0x10) ? CASSETTE_MOTOR_ENABLED : CASSETTE_MOTOR_DISABLED, CASSETTE_MASK_MOTOR);
445
446   /* cassette 2 motor */
447   cassette_change_state(image_from_devtype_and_index(IO_CASSETTE, 1),
448      (data & 0x20) ? CASSETTE_MOTOR_ENABLED : CASSETTE_MOTOR_DISABLED, CASSETTE_MASK_MOTOR);
449
450   if ((data & EXIDY_CASSETTE_MOTOR_MASK) && (~data & 0x80))
451      timer_adjust_periodic(cassette_timer, attotime_zero, 0, ATTOTIME_IN_HZ(19200));
434452   else
453      timer_adjust_oneshot(cassette_timer, attotime_zero, 0);
454
455   /* bit 6 */
456   if (changed_bits & 0x40)
435457   {
436      /* connect to tape */
437      hd6402_connect(&cassette_serial_connection);
458      ay31015_set_rx_clock_speed ((data & 0x40) ? 19200 : 4800);
459      ay31015_set_tx_clock_speed ((data & 0x40) ? 14400 : 4800);
438460   }
439   /* bit 6 */
440   if ((changed_bits & (1<<6))!=0)
461
462   /* bit 7 */
463   if (changed_bits & 0x80)
441464   {
442      int baud_rate;
443
444      baud_rate = 300;
445      if (data & (1<<6))
465      if (data & 0x80)
446466      {
447         baud_rate = 1200;
467      /* connect to serial device (not yet emulated) */
468//         timer_adjust_periodic(serial_timer, attotime_zero, 0, ATTOTIME_IN_HZ(baud_rate));
448469      }
449
450      timer_adjust_periodic(serial_timer, attotime_zero, 0, ATTOTIME_IN_HZ(baud_rate));
470      else
471      {
472      /* connect to tape */
473//         hd6402_connect(&cassette_serial_connection);
474      }
451475   }
452
453   exidy_fe = data;
454476}
455477
456478static WRITE8_HANDLER(exidy_ff_port_w)
r2801r2802
473495
474496static READ8_HANDLER(exidy_fc_port_r)
475497{
476   UINT8 data;
477
478   hd6402_set_input(HD6402_INPUT_DRR, HD6402_INPUT_DRR);
479   data = hd6402_data_r(machine, offset);
480
481   logerror("exidy fc r: %04x %02x\n",offset,data);
482
498   UINT8 data = ay31015_rde();
499   ay31015_rdav();
483500   return data;
484501}
485502
486503static READ8_HANDLER(exidy_fd_port_r)
487504{
488505   /* set unused bits high */
489   UINT8 data = 0xe0;
490
491   /* bit 4: parity error */
492   if (exidy_hd6402_state & HD6402_OUTPUT_PE) data |= 16;
493
494   /* bit 3: framing error */
495   if (exidy_hd6402_state & HD6402_OUTPUT_FE) data |= 8;
496
497   /* bit 2: over-run error */
498   if (exidy_hd6402_state & HD6402_OUTPUT_OE) data |= 4;
499
500   /* bit 1: data receive ready - data ready in receive reg */
501   if (exidy_hd6402_state & HD6402_OUTPUT_DR) data |= 2;
502
503   /* bit 0: transmitter buffer receive empty */
504   /* if this BIT is forced high, then the cassette save routine does not hang */
505   if (exidy_hd6402_state & HD6402_OUTPUT_TBRE) data |= 1;
506
507   logerror("exidy fd r: %04x %02x\n",offset,data);
508
509   return data;
506   return ay31015_swe() | 0xe0;
510507}
511508
512static READ8_HANDLER(exidy_fe_port_r)
509static READ8_HANDLER(exidy_fe_port_r)
513510{
514511   /* bits 6..7
515512     - hardware handshakes from user port
r2801r2802
573570static ADDRESS_MAP_START( exidyd_mem , ADDRESS_SPACE_PROGRAM, 8)
574571   ADDRESS_MAP_UNMAP_HIGH
575572   AM_RANGE(0x0000, 0x07ff) AM_RAMBANK(1)
576   AM_RANGE(0x0800, 0xbfff) AM_RAM      /* ram 48k diskless machine */
573   AM_RANGE(0x0800, 0xbfff) AM_RAM      /* ram 48k cassette-based machine */
577574   AM_RANGE(0xc000, 0xefff) AM_ROM      /* rom pac and bios */
578575   AM_RANGE(0xf000, 0xf7ff) AM_RAM      /* screen ram */
579576   AM_RANGE(0xf800, 0xfbff) AM_ROM      /* char rom */
r2801r2802
716713   PORT_CONFNAME( 0x02, 0x00, "Parallel port" )
717714   PORT_CONFSETTING(    0x00, "Speaker" )
718715   PORT_CONFSETTING(    0x02, "Printer" )
719//   PORT_CONFNAME( 0x08, 0x08, "Cassette Speaker")
720//   PORT_CONFSETTING(    0x08, DEF_STR(On))
721//   PORT_CONFSETTING(    0x00, DEF_STR(Off))
716   PORT_CONFNAME( 0x08, 0x08, "Cassette Speaker")
717   PORT_CONFSETTING(    0x08, DEF_STR(On))
718   PORT_CONFSETTING(    0x00, DEF_STR(Off))
722719INPUT_PORTS_END
723720
724721/**********************************************************************************************************/
r2801r2802
746743
747744   /* sound hardware */
748745   MDRV_SPEAKER_STANDARD_MONO("mono")
746   MDRV_SOUND_ADD(WAVE, 0)
747   MDRV_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)   // cass1 speaker
748   MDRV_SOUND_ADD(WAVE, 1)
749   MDRV_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)   // cass2 speaker
749750   MDRV_SOUND_ADD(SPEAKER, 0)
750   MDRV_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)
751   MDRV_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)   // speaker on parallel port
751752
752753   /* printer */
753754   MDRV_DEVICE_ADD("printer", PRINTER)
r2801r2802
770771{
771772   UINT8 *RAM = memory_region(REGION_CPU1);
772773   memory_configure_bank(1, 0, 2, &RAM[0x0000], 0xe000);
773//   timer_pulse(ATTOTIME_IN_HZ(200000),NULL,0,exidy_timer);      /* timer for cassette */
774774}
775775
776776/***************************************************************************
r2801r2802
851851   switch(state)
852852   {
853853      /* --- the following bits of info are returned as 64-bit signed integers --- */
854      case MESS_DEVINFO_INT_COUNT:                     info->i = 4; break;
854      case MESS_DEVINFO_INT_COUNT:         info->i = 4; break;
855855
856856      /* --- the following bits of info are returned as pointers to data or functions --- */
857      case MESS_DEVINFO_PTR_LOAD:                     info->load = DEVICE_IMAGE_LOAD_NAME(exidy_floppy); break;
857      case MESS_DEVINFO_PTR_LOAD:         info->load = DEVICE_IMAGE_LOAD_NAME(exidy_floppy); break;
858858
859859      /* --- the following bits of info are returned as NULL-terminated strings --- */
860      case MESS_DEVINFO_STR_FILE_EXTENSIONS:            strcpy(info->s = device_temp_str(), "dsk"); break;
860      case MESS_DEVINFO_STR_FILE_EXTENSIONS:      strcpy(info->s = device_temp_str(), "dsk"); break;
861861
862      default:                              legacybasicdsk_device_getinfo(devclass, state, info); break;
862      default:               legacybasicdsk_device_getinfo(devclass, state, info); break;
863863   }
864864}
865865
r2801r2802
869869   switch(state)
870870   {
871871      /* --- the following bits of info are returned as 64-bit signed integers --- */
872      case MESS_DEVINFO_INT_COUNT:                     info->i = 2; break;
872      case MESS_DEVINFO_INT_COUNT:         info->i = 2; break;
873      case MESS_DEVINFO_INT_CASSETTE_DEFAULT_STATE:   info->i = CASSETTE_STOPPED | CASSETTE_MOTOR_DISABLED | CASSETTE_SPEAKER_ENABLED; break;
873874
874      default:                              cassette_device_getinfo(devclass, state, info); break;
875      default:               cassette_device_getinfo(devclass, state, info); break;
875876   }
876877}
877878
878879SYSTEM_CONFIG_START(exidy)
879880   CONFIG_DEVICE(exidy_floppy_getinfo)
880881   CONFIG_DEVICE(cartslot_device_getinfo)
881   CONFIG_DEVICE(exidy_cassette_getinfo)      // use of cassette causes a hang
882   CONFIG_DEVICE(exidy_cassette_getinfo)
882883SYSTEM_CONFIG_END
883884
884885SYSTEM_CONFIG_START(exidyd)
885886   CONFIG_DEVICE(cartslot_device_getinfo)
886   CONFIG_DEVICE(exidy_cassette_getinfo)      // use of cassette causes a hang
887   CONFIG_DEVICE(exidy_cassette_getinfo)
887888SYSTEM_CONFIG_END
888889
889890

Previous 15994 Revisions Next


© 1998-2018 The MESS Team