trunk/src/mess/devices/kermit.c
r17575 | r17576 | |
1 | | /* Kermit protocol implementation. |
2 | | |
3 | | Transfer between an emulated machine and an image using the kermit protocol. |
4 | | |
5 | | Used in the HP48 S/SX/G/GX emulation. |
6 | | |
7 | | Based on the 'KERMIT PROTOCOL MANUAL', Sixth Edition, by Frank da Cruz, |
8 | | Columbia University Center for Computing Activities, New York, June 1986. |
9 | | Available at: http://www-vs.informatik.uni-ulm.de/teach/ws05/rn1/Kermit%20Protocol.pdf |
10 | | |
11 | | Used in the HP48 S/SX/G/GX emulation. |
12 | | For HP48 specific kermit notes, see http://www.columbia.edu/kermit/hp48.html |
13 | | |
14 | | Only the basic protocol is implemented. |
15 | | The following features are NOT supported: |
16 | | - 8-bit quoting (QBIN) |
17 | | - 2- or 3-byte checksums (only 1-byte supported) |
18 | | - repeat count |
19 | | - file attribute packets |
20 | | - sliding window |
21 | | - extended length packets |
22 | | - server mode |
23 | | |
24 | | Author: Antoine Mine' |
25 | | Date: 29/03/2008 |
26 | | */ |
27 | | |
28 | | |
29 | | #include "emu.h" |
30 | | #include "kermit.h" |
31 | | |
32 | | |
33 | | /* debugging */ |
34 | | #define VERBOSE 0 |
35 | | |
36 | | #define LOG(x) do { if (VERBOSE) logerror x; } while (0) |
37 | | |
38 | | /* protocol bytes */ |
39 | | #define KERMIT_SOH 0x01 /* (default) start of header */ |
40 | | |
41 | | /* packet types */ |
42 | | #define KERMIT_DATA 'D' /* data packet */ |
43 | | #define KERMIT_ACK 'Y' /* acknowledge */ |
44 | | #define KERMIT_NAK 'N' /* negative acknowledge */ |
45 | | #define KERMIT_SEND 'S' /* send initiate (exchange parameters) */ |
46 | | #define KERMIT_EOT 'B' /* break transmission */ |
47 | | #define KERMIT_FILE 'F' /* file header */ |
48 | | #define KERMIT_EOF 'Z' /* end of file */ |
49 | | #define KERMIT_ERR 'E' /* error */ |
50 | | |
51 | | #define KERMIT_QCTL '#' /* default escape character */ |
52 | | #define KERMIT_EOL 15 /* default terminator: carriage-return */ |
53 | | #define KERMIT_MAXL 80 /* default maximum packet length */ |
54 | | |
55 | | /* protocol state, to drive action */ |
56 | | #define KERMIT_IDLE 0 /* nothing to do */ |
57 | | #define KERMIT_RESET 1 /* reset after sending the last packet */ |
58 | | #define KERMIT_RECEIVE 2 /* receiving */ |
59 | | #define KERMIT_SEND_DATA 3 /* sending data */ |
60 | | #define KERMIT_SEND_EOF 4 /* sending EOF */ |
61 | | #define KERMIT_SEND_EOT 5 /* sendinf EOT */ |
62 | | |
63 | | /* packet retry parameters */ |
64 | | #define KERMIT_MAX_RETRIES 5 |
65 | | #define KERMIT_RETRY_DELAY attotime::from_seconds( 10 ) |
66 | | |
67 | | |
68 | | /* packet format is: |
69 | | |
70 | | <mark> <len> <seq> <type> <data0> ... <datan> <check> |
71 | | |
72 | | - <mark> KERMIT_SOH |
73 | | - <len> number of bytes after <len> (max=94), plus 32 |
74 | | - <seq> sequence number, modulo 63, plus 32 |
75 | | - <type> one of KERMIT_ packet types |
76 | | - <data> payload, with control characters escaped with KERMIT_QCTL |
77 | | - <check> checksum, from <len> to <datan>, excluding <mark> |
78 | | |
79 | | the packet may be followed by arbitrary (non KERMIT_SOH) data, not counted |
80 | | in <len>, <check>, and not interpreted |
81 | | there is generally at least one KERMIT_EOL |
82 | | */ |
83 | | |
84 | | typedef struct { |
85 | | |
86 | | UINT8 pin[1024]; /* packet received */ |
87 | | UINT8 pout[1024]; /* packet sent */ |
88 | | UINT32 seq; /* sequence number, starting at 0 */ |
89 | | UINT16 posin; /* position in pin */ |
90 | | UINT16 posout; /* position in pout */ |
91 | | UINT16 nbout; /* size of pout */ |
92 | | |
93 | | UINT8 state; /* current protocol state */ |
94 | | UINT8 retries; /* packet retries remaining */ |
95 | | |
96 | | /* (relevant) configuration information, sent in S and D packet */ |
97 | | UINT8 maxl; /* max packet length (value of <len>) */ |
98 | | UINT8 npad; /* number of padding characters before packet */ |
99 | | UINT8 padc; /* padding character */ |
100 | | UINT8 eol; /* character to add after packet */ |
101 | | UINT8 qctl; /* escape character */ |
102 | | |
103 | | emu_timer* resend; /* auto-resend packet */ |
104 | | |
105 | | device_image_interface* image; /* underlying image */ |
106 | | |
107 | | running_machine *machine; |
108 | | kermit_config* conf; |
109 | | |
110 | | } kermit; |
111 | | |
112 | | |
113 | | INLINE kermit *get_safe_token(device_t *device) |
114 | | { |
115 | | assert(device != NULL); |
116 | | assert(device->type() == KERMIT); |
117 | | |
118 | | return (kermit*)downcast<legacy_device_base *>(device)->token(); |
119 | | } |
120 | | |
121 | | static int kermit_is_char( UINT8 data ) |
122 | | { |
123 | | return data >= 32 && data <= 126; |
124 | | } |
125 | | |
126 | | |
127 | | static UINT8 kermit_tochar( UINT8 data ) |
128 | | { |
129 | | if ( data > 94 ) |
130 | | { |
131 | | logerror( "kermit: tochar: %i not in the range 0-94\n", data ); |
132 | | } |
133 | | return data + 32; |
134 | | } |
135 | | |
136 | | static UINT8 kermit_unchar( UINT8 data ) |
137 | | { |
138 | | if ( data < 32 || data > 126 ) |
139 | | { |
140 | | logerror( "kermit: unchar: %i not in the range 32-126\n", data ); |
141 | | } |
142 | | return data - 32; |
143 | | } |
144 | | |
145 | | #define kermit_ctl(x) ((x) ^ 0x40) |
146 | | |
147 | | static int kermit_is_ctl( UINT8 x ) |
148 | | { |
149 | | x &= 0x7f; |
150 | | return (x < 32) || (x == 127); |
151 | | } |
152 | | |
153 | | static UINT8 kermit_checksum( UINT8* packet ) |
154 | | { |
155 | | int i, len = kermit_unchar( packet[1] ); |
156 | | UINT8 sum = 0; |
157 | | for ( i = 0; i < len; i++ ) |
158 | | sum += packet[ i + 1 ]; |
159 | | sum = kermit_tochar( (sum + (sum >> 6)) & 63 ); |
160 | | return sum; |
161 | | } |
162 | | |
163 | | /* starts sending a new packet */ |
164 | | static void kermit_start_sending( kermit* state ) |
165 | | { |
166 | | int i; |
167 | | |
168 | | for (i=1;i<state->nbout;i++) |
169 | | if (kermit_is_ctl(state->pout[i])) |
170 | | logerror( "send: not char %i at pos %i\n", state->pout[i], i ); |
171 | | |
172 | | if ( state->nbout <= 0 ) return; |
173 | | |
174 | | /* prepend padding and append eol */ |
175 | | if ( state->npad > 0 ) |
176 | | { |
177 | | memmove( state->pout + state->npad, state->pout, state->nbout ); |
178 | | memset( state->pout, state->padc, state->npad ); |
179 | | state->nbout += state->npad; |
180 | | } |
181 | | state->pout[ state->nbout ] = state->eol; |
182 | | state->nbout++; |
183 | | |
184 | | if ( state->conf && state->conf->send ) |
185 | | { |
186 | | state->conf->send( *state->machine, state->pout[ 0 ] ); |
187 | | } |
188 | | state->posout = 1; |
189 | | |
190 | | state->retries = KERMIT_MAX_RETRIES; |
191 | | state->resend->adjust( KERMIT_RETRY_DELAY, 0, KERMIT_RETRY_DELAY ); |
192 | | } |
193 | | |
194 | | static void kermit_reset( kermit* state ); |
195 | | |
196 | | static void kermit_resend( kermit* state ) |
197 | | { |
198 | | if ( state->conf && state->conf->send ) |
199 | | { |
200 | | /* retry */ |
201 | | if ( state->nbout == 0 ) return; |
202 | | if ( state->retries <= 0 ) |
203 | | { |
204 | | kermit_reset( state ); |
205 | | return; |
206 | | } |
207 | | |
208 | | state->conf->send( *state->machine, state->pout[ 0 ] ); |
209 | | |
210 | | state->posout = 1; |
211 | | state->retries--; |
212 | | LOG(( "kermit: resend packet (%i tries left)\n", state->retries )); |
213 | | } |
214 | | } |
215 | | |
216 | | /* resend packet periodically */ |
217 | | static TIMER_CALLBACK( kermit_resend_cb ) |
218 | | { |
219 | | kermit* state = (kermit*) ptr; |
220 | | if ( state->posout >= state->nbout) |
221 | | { |
222 | | kermit_resend( state ); |
223 | | } |
224 | | } |
225 | | |
226 | | /* fetches image data and wrap it into a kermit data packet */ |
227 | | static void kermit_send_data_packet( kermit* state ) |
228 | | { |
229 | | int len; |
230 | | LOG(( "kermit: send data packet\n" )); |
231 | | for ( len = 2; len < state->maxl-2; len++ ) |
232 | | { |
233 | | UINT8 c; |
234 | | if ( state->image->image_feof() ) break; |
235 | | c = state->image->fgetc(); |
236 | | if ( kermit_is_ctl( c ) ) |
237 | | { |
238 | | /* escape control char */ |
239 | | state->pout[ 2 + len ] = state->qctl; |
240 | | len++; |
241 | | state->pout[ 2 + len ] = kermit_ctl( c ); |
242 | | } |
243 | | else if ( (c & 0x7f) == state->qctl ) |
244 | | { |
245 | | /* escape escape char */ |
246 | | state->pout[ 2 + len ] = state->qctl; |
247 | | len++; |
248 | | state->pout[ 2 + len ] = c; |
249 | | } |
250 | | else |
251 | | { |
252 | | state->pout[ 2 + len ] = c; |
253 | | } |
254 | | } |
255 | | state->pout[ 0 ] = KERMIT_SOH; |
256 | | state->pout[ 1 ] = kermit_tochar( len + 1 ); |
257 | | state->pout[ 2 ] = kermit_tochar( state->seq & 63 ); |
258 | | state->pout[ 3 ] = KERMIT_DATA; |
259 | | state->pout[ 2 + len ] = kermit_checksum( state->pout ); |
260 | | state->nbout = len + 3; |
261 | | kermit_start_sending( state ); |
262 | | } |
263 | | |
264 | | /* write data from packet to the image */ |
265 | | static void kermit_write_data_packet( kermit* state ) |
266 | | { |
267 | | int i, len = kermit_unchar( state->pin[1] ); |
268 | | LOG(( "kermit: received data pack, len=%i\n", len )); |
269 | | for ( i = 4; i <= len; i++ ) |
270 | | { |
271 | | UINT8 c = state->pin[i]; |
272 | | if ( (c /*& 0x7f*/) == state->qctl ) |
273 | | { |
274 | | /* unescape */ |
275 | | i++; |
276 | | c = state->pin[i]; |
277 | | if ( kermit_is_ctl( kermit_ctl( c ) ) ) |
278 | | { |
279 | | c = kermit_ctl( c ); |
280 | | } |
281 | | } |
282 | | state->image->fwrite(&c, 1 ); |
283 | | } |
284 | | } |
285 | | |
286 | | /* validate received packet and acquire seq number, <0 if error */ |
287 | | static int kermit_validate_packet( kermit* state ) |
288 | | { |
289 | | int len; |
290 | | if ( state->pin[ 0 ] != KERMIT_SOH ) return -1; |
291 | | if ( !kermit_is_char( state->pin[1] ) ) return -1; |
292 | | if ( !kermit_is_char( state->pin[2] ) ) return -1; |
293 | | len = kermit_unchar( state->pin[1] ); |
294 | | if ( state->pin[ 1 + len ] != kermit_checksum( state->pin ) ) return -1; |
295 | | return 0; |
296 | | } |
297 | | |
298 | | /* interpret configuration packet, <0 if error */ |
299 | | static int kermit_get_conf( kermit* state ) |
300 | | { |
301 | | int len = kermit_unchar( state->pin[1] ); |
302 | | if ( len >= 4 ) state->maxl = kermit_unchar( state->pin[ 4 ] ); |
303 | | if ( len >= 6 ) state->npad = kermit_unchar( state->pin[ 6 ] ); |
304 | | if ( len >= 7 ) state->padc = kermit_ctl( state->pin[ 7 ] ); |
305 | | if ( len >= 8 ) state->eol = kermit_unchar( state->pin[ 8 ] ); |
306 | | if ( len >= 9 ) state->qctl = state->pin[ 9 ]; |
307 | | |
308 | | LOG(( "kermit: get conf: len=%i, maxl=%i, npad=%i, padc=%i, eol=%i, qctl=%i\n", |
309 | | len, state->maxl, state->npad, state->padc, state->eol, state->qctl )); |
310 | | |
311 | | /* validation */ |
312 | | if ( state->maxl < 10 || state->maxl > 94 ) return -1; |
313 | | return 0; |
314 | | } |
315 | | |
316 | | /* create a configuration packet, with header h */ |
317 | | static void kermit_send_conf_packet( kermit* state, UINT8 h ) |
318 | | { |
319 | | LOG(( "kermit: send conf packet of type %c\n", h )); |
320 | | state->seq = 0; |
321 | | state->pout[ 0 ] = KERMIT_SOH; |
322 | | state->pout[ 1 ] = kermit_tochar( 13 ); |
323 | | state->pout[ 2 ] = kermit_tochar( state->seq & 63 ); |
324 | | state->pout[ 3 ] = h; |
325 | | state->pout[ 4 ] = kermit_tochar( state->maxl ); /* maxl */ |
326 | | state->pout[ 5 ] = kermit_tochar( 1 ); /* time: 1 sec */ |
327 | | state->pout[ 6 ] = kermit_tochar( state->npad ); /* npad */ |
328 | | state->pout[ 7 ] = kermit_ctl( state->padc ); /* padc */ |
329 | | state->pout[ 8 ] = kermit_tochar( state->eol ); /* eol */ |
330 | | state->pout[ 9 ] = state->qctl; /* qtcl */ |
331 | | state->pout[ 10 ] = 'N'; /* qbin: no 8-bit quoting */ |
332 | | state->pout[ 11 ] = '1'; /* chkt: single character checksum */ |
333 | | state->pout[ 12 ] = ' '; /* rept: no repeat count */ |
334 | | state->pout[ 13 ] = kermit_tochar( 0 ); /* capas: no capabilities */ |
335 | | state->pout[ 14 ] = kermit_checksum( state->pout ); |
336 | | state->nbout = 15; |
337 | | kermit_start_sending( state ); |
338 | | } |
339 | | |
340 | | /* sends a packet with no data */ |
341 | | static void kermit_send_simple_packet( kermit* state, UINT8 h ) |
342 | | { |
343 | | LOG(( "kermit: send empty packet of type %c, seq=%i\n", h, state->seq & 63 )); |
344 | | state->pout[ 0 ] = KERMIT_SOH; |
345 | | state->pout[ 1 ] = kermit_tochar( 3 ); |
346 | | state->pout[ 2 ] = kermit_tochar( state->seq & 63 ); |
347 | | state->pout[ 3 ] = h; |
348 | | state->pout[ 4 ] = kermit_checksum( state->pout ); |
349 | | state->nbout = 5; |
350 | | kermit_start_sending( state ); |
351 | | } |
352 | | |
353 | | /* sends a packet with string data */ |
354 | | static void kermit_send_string_packet( kermit* state, UINT8 h, const char* data ) |
355 | | { |
356 | | int i, len; |
357 | | LOG(( "kermit: send string packet of type %c, data=%s, seq=%i\n", h, data, state->seq & 63 )); |
358 | | for ( len = i = 0; (len < state->maxl - 5) && data[i]; i++ ) |
359 | | { |
360 | | char c = data[i]; |
361 | | if ( kermit_is_char( c ) && ( c != '_' ) && ( c != ' ' ) ) |
362 | | { |
363 | | state->pout[ 4 + len ] = c; |
364 | | len++; |
365 | | } |
366 | | } |
367 | | state->pout[ 0 ] = KERMIT_SOH; |
368 | | state->pout[ 1 ] = kermit_tochar( len + 3 ); |
369 | | state->pout[ 2 ] = kermit_tochar( state->seq & 63 ); |
370 | | state->pout[ 3 ] = h; |
371 | | state->pout[ 4 + len ] = kermit_checksum( state->pout ); |
372 | | state->nbout = len + 5; |
373 | | kermit_start_sending( state ); |
374 | | } |
375 | | |
376 | | /* extract the string contained in received packet */ |
377 | | static char* kermit_string_in_packet( kermit* state ) |
378 | | { |
379 | | int len = kermit_unchar( state->pin[1] ); |
380 | | state->pin[ len + 1 ] = 0; |
381 | | return (char*) state->pin + 4; |
382 | | } |
383 | | |
384 | | static void kermit_reset( kermit* state ) |
385 | | { |
386 | | /* default config */ |
387 | | state->maxl = KERMIT_MAXL; |
388 | | state->npad = 0; |
389 | | state->padc = 0; |
390 | | state->eol = KERMIT_EOL; |
391 | | state->qctl = KERMIT_QCTL; |
392 | | |
393 | | state->retries = KERMIT_MAX_RETRIES; |
394 | | state->posin = 0; |
395 | | state->posout = 0; |
396 | | state->nbout = 0; |
397 | | state->state = KERMIT_IDLE; |
398 | | state->seq = 0; |
399 | | |
400 | | if ( state->image ) |
401 | | { |
402 | | state->image->fseek( SEEK_SET, 0 ); |
403 | | } |
404 | | |
405 | | state->resend->adjust( attotime::never, 0, attotime::never ); |
406 | | } |
407 | | |
408 | | |
409 | | /* emulated machine sends a byte to the outside (us) */ |
410 | | void kermit_receive_byte( device_t *device, UINT8 data ) |
411 | | { |
412 | | kermit* state = get_safe_token(device); |
413 | | |
414 | | LOG(( "get %i %2x %c (%i)\n", data, data, data, state->posin )); |
415 | | |
416 | | /* get SOH */ |
417 | | if ( (data == KERMIT_SOH) && (state->posin <= 1) ) |
418 | | { |
419 | | state->pin[ 0 ] = data; |
420 | | state->posin = 1; |
421 | | } |
422 | | |
423 | | /* get packet contents */ |
424 | | else if ( state->posin > 0 ) |
425 | | { |
426 | | if ( state->posin >= sizeof( state->pout ) ) |
427 | | { |
428 | | LOG(( "kermit: too many bytes received\n" )); |
429 | | state->posin = 0; |
430 | | kermit_send_simple_packet( state, KERMIT_NAK ); |
431 | | return; |
432 | | } |
433 | | |
434 | | if (kermit_is_ctl(data)) |
435 | | logerror( "received: not char %i at pos %i\n", data, state->posin ); |
436 | | |
437 | | state->pin[ state->posin ] = data; |
438 | | state->posin++; |
439 | | |
440 | | if ( state->posin > 5 ) |
441 | | { |
442 | | int len, seq, typ; |
443 | | if ( !kermit_is_char( state->pin[1] ) || |
444 | | (kermit_unchar( state->pin[1] ) < 3) || |
445 | | (kermit_unchar( state->pin[1] ) > state->maxl) ) |
446 | | { |
447 | | LOG(( "kermit: invalid packet size %i-32, not in 3-%i\n", state->pin[1], state->maxl )); |
448 | | kermit_resend( state ); |
449 | | return; |
450 | | } |
451 | | |
452 | | len = kermit_unchar( state->pin[1] ); |
453 | | |
454 | | if ( state->posin >= len + 2 ) |
455 | | { |
456 | | /* got packet! */ |
457 | | state->posin = 0; |
458 | | if ( kermit_validate_packet( state ) ) |
459 | | { |
460 | | LOG(( "kermit: invalid packet\n" )); |
461 | | kermit_resend( state ); |
462 | | return; |
463 | | } |
464 | | |
465 | | typ = state->pin[3]; |
466 | | seq = kermit_unchar( state->pin[2] ); |
467 | | |
468 | | LOG(( "kermit: received packet type=%c, seq=%i, len=%i\n", typ, seq, len )); |
469 | | |
470 | | if ( !state->image ) |
471 | | { |
472 | | kermit_send_string_packet( state, KERMIT_ERR, "NO IMAGE" ); |
473 | | return; |
474 | | } |
475 | | |
476 | | |
477 | | switch ( typ ) |
478 | | { |
479 | | |
480 | | /* receiving */ |
481 | | |
482 | | case KERMIT_SEND: |
483 | | kermit_get_conf( state ); |
484 | | if ( state->maxl >= KERMIT_MAXL ) |
485 | | { |
486 | | state->maxl = KERMIT_MAXL; |
487 | | } |
488 | | kermit_send_conf_packet( state, KERMIT_ACK ); |
489 | | state->state = KERMIT_RECEIVE; |
490 | | break; |
491 | | |
492 | | case KERMIT_FILE: |
493 | | LOG(( "kermit: got file name '%s'\n", kermit_string_in_packet( state ) )); |
494 | | state->seq = seq; |
495 | | kermit_send_simple_packet( state, KERMIT_ACK ); |
496 | | break; |
497 | | |
498 | | case KERMIT_DATA: |
499 | | case KERMIT_EOF: |
500 | | if ( seq == ((state->seq + 1) & 63) ) |
501 | | { |
502 | | /* next packet */ |
503 | | if ( typ == KERMIT_DATA ) |
504 | | { |
505 | | kermit_write_data_packet( state ); |
506 | | } |
507 | | state->seq = seq; |
508 | | kermit_send_simple_packet( state, KERMIT_ACK ); |
509 | | } |
510 | | else if ( seq == (state->seq & 63) ) |
511 | | { |
512 | | /* same packet */ |
513 | | kermit_send_simple_packet( state, KERMIT_ACK ); |
514 | | } |
515 | | else |
516 | | { |
517 | | /* unexpected sequence number */ |
518 | | LOG(( "kermit: got seq=%i, expected %i\n", seq, (state->seq + 1) & 63 )); |
519 | | state->seq++; |
520 | | kermit_send_simple_packet( state, KERMIT_NAK ); |
521 | | state->seq--; |
522 | | } |
523 | | break; |
524 | | |
525 | | case KERMIT_EOT: |
526 | | /* send ack and reset */ |
527 | | state->seq = seq; |
528 | | kermit_send_simple_packet( state, KERMIT_ACK ); |
529 | | state->state = KERMIT_RESET; |
530 | | break; |
531 | | |
532 | | |
533 | | /* sending */ |
534 | | |
535 | | case KERMIT_NAK: |
536 | | case KERMIT_ACK: |
537 | | |
538 | | if ( (typ == KERMIT_NAK) && (seq == 0) && (state->state == KERMIT_IDLE) ) |
539 | | { |
540 | | /* transfer start */ |
541 | | kermit_send_conf_packet( state, KERMIT_SEND ); |
542 | | break; |
543 | | } |
544 | | |
545 | | if ( ((seq == (state->seq & 63)) && (typ == KERMIT_ACK)) || |
546 | | ((seq == ((state->seq + 1) & 63)) && (typ == KERMIT_NAK)) ) |
547 | | { |
548 | | /* send next packet */ |
549 | | |
550 | | state->seq = state->seq + 1; |
551 | | |
552 | | switch ( state->state ) |
553 | | { |
554 | | case KERMIT_IDLE: |
555 | | /* get conf & send file name */ |
556 | | kermit_get_conf( state ); |
557 | | kermit_send_string_packet( state, KERMIT_FILE, state->image->basename() ); |
558 | | state->state = KERMIT_SEND_DATA; |
559 | | break; |
560 | | |
561 | | case KERMIT_SEND_DATA: |
562 | | /* send next data packet or EOF */ |
563 | | if ( state->image->image_feof() ) |
564 | | { |
565 | | kermit_send_simple_packet( state, KERMIT_EOF ); |
566 | | state->state = KERMIT_SEND_EOF; |
567 | | } |
568 | | else |
569 | | { |
570 | | kermit_send_data_packet( state ); |
571 | | } |
572 | | break; |
573 | | |
574 | | case KERMIT_SEND_EOF: |
575 | | /* send EOT */ |
576 | | kermit_send_simple_packet( state, KERMIT_EOT ); |
577 | | state->state = KERMIT_SEND_EOT; |
578 | | break; |
579 | | |
580 | | case KERMIT_SEND_EOT: |
581 | | /* reset */ |
582 | | kermit_reset( state ); |
583 | | state->state = KERMIT_RESET; |
584 | | break; |
585 | | |
586 | | } |
587 | | } |
588 | | |
589 | | else if ( (seq == (state->seq & 63)) && (typ == KERMIT_NAK) ) |
590 | | { |
591 | | /* resend last packet */ |
592 | | kermit_resend( state ); |
593 | | } |
594 | | else |
595 | | { |
596 | | /* bad */ |
597 | | LOG(( "kermit: expected to send %i, got seq=%i\n", (state->seq + 1) & 63, seq )); |
598 | | kermit_reset( state ); |
599 | | } |
600 | | break; |
601 | | |
602 | | /* errors */ |
603 | | |
604 | | case KERMIT_ERR: |
605 | | LOG(( "kermit: got error '%s'\n", kermit_string_in_packet( state ) )); |
606 | | state->seq = seq; |
607 | | kermit_reset( state ); |
608 | | break; |
609 | | |
610 | | default: |
611 | | LOG(( "kermit: ignoring packet type %c\n", state->pin[ 3 ] )); |
612 | | /* no abort, just ignoring */ |
613 | | } |
614 | | } |
615 | | } |
616 | | } |
617 | | } |
618 | | |
619 | | void kermit_byte_transmitted( device_t *device ) |
620 | | { |
621 | | kermit* state = get_safe_token(device); |
622 | | |
623 | | LOG(( "transmitted %i %2x %c, %i / %i\n", state->pout[ state->posout-1 ], state->pout[ state->posout-1 ], state->pout[ state->posout-1 ], state->posout - 1, state->nbout - 1 )); |
624 | | |
625 | | /* at end of packet */ |
626 | | if ( state->posout >= state->nbout ) |
627 | | { |
628 | | if ( state->state == KERMIT_RESET ) |
629 | | { |
630 | | kermit_reset( state ); |
631 | | } |
632 | | return; |
633 | | } |
634 | | |
635 | | if ( state->conf && state->conf->send ) |
636 | | { |
637 | | state->conf->send(*state->machine, state->pout[ state->posout ] ); |
638 | | } |
639 | | state->posout++; |
640 | | } |
641 | | |
642 | | static DEVICE_START( kermit ) |
643 | | { |
644 | | kermit* state = get_safe_token(device); |
645 | | LOG(( "kermit: start\n" )); |
646 | | state->image = NULL; |
647 | | state->conf = (kermit_config*) device->static_config(); |
648 | | state->machine = &device->machine(); |
649 | | state->resend = device->machine().scheduler().timer_alloc(FUNC(kermit_resend_cb), state ); |
650 | | kermit_reset( state ); |
651 | | } |
652 | | |
653 | | static DEVICE_RESET( kermit ) |
654 | | { |
655 | | kermit* state = get_safe_token(device); |
656 | | LOG(( "kermit: reset\n" )); |
657 | | kermit_reset( state ); |
658 | | } |
659 | | |
660 | | static DEVICE_IMAGE_LOAD( kermit ) |
661 | | { |
662 | | kermit* state = get_safe_token(&image.device()); |
663 | | LOG(( "kermit: image load\n" )); |
664 | | state->image = ℑ |
665 | | kermit_reset( state ); |
666 | | return IMAGE_INIT_PASS; |
667 | | } |
668 | | |
669 | | static DEVICE_IMAGE_CREATE( kermit ) |
670 | | { |
671 | | kermit* state = get_safe_token(&image.device()); |
672 | | LOG(( "kermit: image create\n" )); |
673 | | state->image = ℑ |
674 | | kermit_reset( state ); |
675 | | return IMAGE_INIT_PASS; |
676 | | } |
677 | | |
678 | | static DEVICE_IMAGE_UNLOAD( kermit ) |
679 | | { |
680 | | kermit* state = get_safe_token(&image.device()); |
681 | | LOG(( "kermit: image unload\n" )); |
682 | | state->image = NULL; |
683 | | kermit_reset( state ); |
684 | | } |
685 | | |
686 | | DEVICE_GET_INFO( kermit ) |
687 | | |
688 | | { |
689 | | switch ( state ) { |
690 | | case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof( kermit ); break; |
691 | | case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break; |
692 | | case DEVINFO_INT_IMAGE_TYPE: info->i = IO_SERIAL; break; |
693 | | case DEVINFO_INT_IMAGE_READABLE: info->i = 1; break; |
694 | | case DEVINFO_INT_IMAGE_WRITEABLE: info->i = 1; break; |
695 | | case DEVINFO_INT_IMAGE_CREATABLE: info->i = 1; break; |
696 | | case DEVINFO_FCT_START: info->start = DEVICE_START_NAME( kermit ); break; |
697 | | case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME( kermit ); break; |
698 | | case DEVINFO_FCT_IMAGE_LOAD: info->f = (genf *) DEVICE_IMAGE_LOAD_NAME( kermit ); break; |
699 | | case DEVINFO_FCT_IMAGE_UNLOAD: info->f = (genf *) DEVICE_IMAGE_UNLOAD_NAME( kermit ); break; |
700 | | case DEVINFO_FCT_IMAGE_CREATE: info->f = (genf *) DEVICE_IMAGE_CREATE_NAME( kermit ); break; |
701 | | case DEVINFO_STR_IMAGE_BRIEF_INSTANCE_NAME: strcpy(info->s, "k"); break; |
702 | | case DEVINFO_STR_IMAGE_INSTANCE_NAME: |
703 | | case DEVINFO_STR_NAME: strcpy(info->s, "Kermit"); break; |
704 | | case DEVINFO_STR_FAMILY: strcpy(info->s, "Serial protocol"); break; |
705 | | case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break; |
706 | | case DEVINFO_STR_IMAGE_FILE_EXTENSIONS: strcpy(info->s, ""); break; |
707 | | } |
708 | | } |
709 | | |
710 | | DEFINE_LEGACY_IMAGE_DEVICE(KERMIT, kermit); |
trunk/src/mess/audio/ted7360.c
r17575 | r17576 | |
1 | | /*************************************************************************** |
2 | | |
3 | | TExt Display 7360 |
4 | | PeT mess@utanet.at |
5 | | |
6 | | |
7 | | 2010-02: Converted to be a device and merged video/audio emulation |
8 | | |
9 | | TODO: |
10 | | - Plenty of clean-ups |
11 | | |
12 | | ***************************************************************************/ |
13 | | /* |
14 | | Metal Oxid Semicontuctor MOS |
15 | | Commodore Business Machine CBM |
16 | | Textured Display Ted7360 |
17 | | ------------------------ |
18 | | |
19 | | 7360/8360 (NTSC-M, PAL-B by same chip ?) |
20 | | 8365 PAL-N |
21 | | 8366 PAL-M |
22 | | |
23 | | Ted7360 used in Commodore C16 |
24 | | Ted8360 used in Commodore C116/Plus4 |
25 | | should be 100% software compatible with Ted7360 |
26 | | |
27 | | video unit (without sprites), dram controller seams to be much like vic6567 |
28 | | |
29 | | PAL/NTSC variants |
30 | | |
31 | | functions of this chip: |
32 | | memory controller |
33 | | dram controller |
34 | | cpu clock generation with single and double clock switching |
35 | | 3 timer |
36 | | 1 8bit latched input |
37 | | 2 channel sound/noise generator |
38 | | video controller |
39 | | interrupt controller for timer and video |
40 | | |
41 | | Reasons for this document: |
42 | | document state in mess c16/plus4 emulator |
43 | | base to discuss ted7360 with others (i have no c16 computer anymore) |
44 | | |
45 | | pal: |
46 | | clock 17734470 |
47 | | divided by 5 for base clock (pixel clock changing edges?) |
48 | | 312 lines |
49 | | 50 hertz vertical refresh |
50 | | |
51 | | ntsc: |
52 | | clock 14318180 |
53 | | divided by 4 for base clock (pixel clock changing edges?) |
54 | | 262 lines |
55 | | 60 hertz vertical refresh |
56 | | |
57 | | registers: |
58 | | 0xff00 timer 1 low byte |
59 | | 0xff01 timer 1 high byte |
60 | | 0xff02 timer 2 low byte |
61 | | 0xff03 timer 2 high byte |
62 | | 0xff04 timer 3 low byte |
63 | | 0xff05 timer 3 high byte |
64 | | 0xff06 |
65 | | bit 7 test? |
66 | | bit 6 ecm on |
67 | | bit 5 hires on |
68 | | bit 4 screen on |
69 | | bit 3 25 raws (0 24 raws) |
70 | | bit 2-0 vertical position |
71 | | 0xff07 |
72 | | bit 7 reverse off (0 on) |
73 | | bit 6 read only NTSC (0 PAL) |
74 | | bit 5 freeze horicontal position? |
75 | | bit 4 multicolor on |
76 | | bit 3 40 columns (0 38 columns) |
77 | | bit 2-0 horicontal pos |
78 | | 0xff08 input latch (0 input low), write reloads latch |
79 | | 0xff09 interrupt request |
80 | | 7: interrupt |
81 | | 6: timer 3 |
82 | | 5: ? |
83 | | 4: timer 2 |
84 | | 3: timer 1 |
85 | | 2: lightpen |
86 | | 1: rasterline |
87 | | 0: 1 (asl quitting) |
88 | | 0xff0a interrupt enable |
89 | | 7: ? |
90 | | 6: timer 3 |
91 | | 5: ? |
92 | | 4: timer 2 |
93 | | 3: timer 1 |
94 | | 2: lightpen |
95 | | 1: rasterline |
96 | | 0: irq rasterline bit 8 |
97 | | 0xff0b |
98 | | 7-0: irq rasterline 7-0 |
99 | | 0xff0c |
100 | | 7-2: 1? |
101 | | 1,0: cursorpos bit 9,8 |
102 | | 0xff0d cursorpos bit 7-0 |
103 | | 0xff0e tone channel 1: frequency 7-0 |
104 | | 0xff0f tone channel 2: frequency 7-0 |
105 | | 0xff10 |
106 | | 7-2: ? |
107 | | 1,0: tone channel 2 bit 9,8 |
108 | | 0xff11 |
109 | | 7: sound reload |
110 | | 6: tone 2 noise on (tone 2 must be off for noise) |
111 | | 5: tone 2 tone on |
112 | | 4: tone 1 on |
113 | | 3-0: volume 8?-0 |
114 | | 0xff12 |
115 | | 7,6: ? |
116 | | 5-3: bitmap address bit 15-13 |
117 | | 2: bitmapmemory?, charactermemory in rom (0 ram) |
118 | | 1,0: tone 1 frequency bit 9,8 |
119 | | 0xff13 |
120 | | 7-2: chargen address bit 15-11 |
121 | | 2: chargen address bit 10 (only used when reverse is off) |
122 | | 1: single clock in overscan area (0 double clock) |
123 | | 0: ram (0)/rom status |
124 | | 0xff14 |
125 | | 7-2: video address bit 15-10 |
126 | | 1,0: ? |
127 | | 0xff15 |
128 | | 7: ? |
129 | | 6-0: backgroundcolor |
130 | | 0xff16 |
131 | | 7: ? |
132 | | 6-0: color1 |
133 | | 0xff17 |
134 | | 7: ? |
135 | | 6-0: color2 |
136 | | 0xff18 |
137 | | 7: ? |
138 | | 6-0: color3 |
139 | | 0xff19 |
140 | | 7: ? |
141 | | 6-0: framecolor |
142 | | 0xff1a |
143 | | 7-2: ? |
144 | | 1,0: bitmap reload(cursorpos2) bit 9-8 |
145 | | 0xff1b bitmap reload bit 7-0 |
146 | | 0xff1c |
147 | | 7-1: 1? (matrix expects this) |
148 | | 0: current rasterline bit 8 |
149 | | 0xff1d current rasterline bit 7-0 |
150 | | 0xff1e |
151 | | 7-0: current rastercolumn /2 (0 begin visible area?) |
152 | | 0xff1f cursorblink? |
153 | | 7: ? |
154 | | 6-3: blink counter |
155 | | 2-0: vsub |
156 | | 0xff3e write switches to rom |
157 | | 0xff3f write switches to dram |
158 | | |
159 | | memory controller |
160 | | 0x8000-0xfcff, 0xff20-0xffff |
161 | | read selection between dram and rom |
162 | | 0xff3e-0xff3f write nothing (would change main memory in 16k ram c16) |
163 | | |
164 | | clock generator |
165 | | in displayed area ted need 3 memory cycles to get data for video chip |
166 | | memory system runs at approximately 4 megahertz |
167 | | so only 1 megahertz is available for the cpu |
168 | | in the other area the clock can be doubled for the cpu |
169 | | |
170 | | dram controller |
171 | | generator of refresh cycles |
172 | | when are these occuring? |
173 | | vic6567 in each rasterline reads 5 refresh addresses |
174 | | |
175 | | sound generator |
176 | | 2 channels |
177 | | channel 2 can be switched to generate noise |
178 | | volume control (0-8?) |
179 | | tone reload bit? |
180 | | samples ton/noise? |
181 | | frequency=(base clock/32)/(1024-value) |
182 | | |
183 | | timer |
184 | | timer count down |
185 | | when reaching 0 |
186 | | they restart from 0xffff |
187 | | set the interrupt request flag |
188 | | writing to low byte stops timer |
189 | | writing to high byte restarts timer with current value |
190 | | |
191 | | interrupt controller |
192 | | interrupt sources must be enabled in the enable register to generate |
193 | | an interrupt |
194 | | request flag are set also when not enabled |
195 | | interrupt is generated when rising edge on request and enable |
196 | | quitting of interrupt is done via writing 1 to the request bit |
197 | | what happens with request interrupts when the are enabled? |
198 | | |
199 | | Video part |
200 | | colors |
201 | | bit 3-0 color |
202 | | black, white, red, cyan |
203 | | purple, green, blue, yellow |
204 | | orange, light orange, pink, light cyan, |
205 | | light violett, light green, light blue, light yellow |
206 | | bit 6-4 luminance (0 dark) |
207 | | r,g,b values from 0 to 127 |
208 | | taken from digitized tv screen shot |
209 | | 0x06,0x01,0x03, 0x2b,0x2b,0x2b, 0x67,0x0e,0x0f, 0x00,0x3f,0x42, |
210 | | 0x57,0x00,0x6d, 0x00,0x4e,0x00, 0x19,0x1c,0x94, 0x38,0x38,0x00, |
211 | | 0x56,0x20,0x00, 0x4b,0x28,0x00, 0x16,0x48,0x00, 0x69,0x07,0x2f, |
212 | | 0x00,0x46,0x26, 0x06,0x2a,0x80, 0x2a,0x14,0x9b, 0x0b,0x49,0x00, |
213 | | |
214 | | 0x00,0x03,0x02, 0x3d,0x3d,0x3d, 0x75,0x1e,0x20, 0x00,0x50,0x4f, |
215 | | 0x6a,0x10,0x78, 0x04,0x5c,0x00, 0x2a,0x2a,0xa3, 0x4c,0x47,0x00, |
216 | | 0x69,0x2f,0x00, 0x59,0x38,0x00, 0x26,0x56,0x00, 0x75,0x15,0x41, |
217 | | 0x00,0x58,0x3d, 0x15,0x3d,0x8f, 0x39,0x22,0xae, 0x19,0x59,0x00, |
218 | | |
219 | | 0x00,0x03,0x04, 0x42,0x42,0x42, 0x7b,0x28,0x20, 0x02,0x56,0x59, |
220 | | 0x6f,0x1a,0x82, 0x0a,0x65,0x09, 0x30,0x34,0xa7, 0x50,0x51,0x00, |
221 | | 0x6e,0x36,0x00, 0x65,0x40,0x00, 0x2c,0x5c,0x00, 0x7d,0x1e,0x45, |
222 | | 0x01,0x61,0x45, 0x1c,0x45,0x99, 0x42,0x2d,0xad, 0x1d,0x62,0x00, |
223 | | |
224 | | 0x05,0x00,0x02, 0x56,0x55,0x5a, 0x90,0x3c,0x3b, 0x17,0x6d,0x72, |
225 | | 0x87,0x2d,0x99, 0x1f,0x7b,0x15, 0x46,0x49,0xc1, 0x66,0x63,0x00, |
226 | | 0x84,0x4c,0x0d, 0x73,0x55,0x00, 0x40,0x72,0x00, 0x91,0x33,0x5e, |
227 | | 0x19,0x74,0x5c, 0x32,0x59,0xae, 0x59,0x3f,0xc3, 0x32,0x76,0x00, |
228 | | |
229 | | 0x02,0x01,0x06, 0x84,0x7e,0x85, 0xbb,0x67,0x68, 0x45,0x96,0x96, |
230 | | 0xaf,0x58,0xc3, 0x4a,0xa7,0x3e, 0x73,0x73,0xec, 0x92,0x8d,0x11, |
231 | | 0xaf,0x78,0x32, 0xa1,0x80,0x20, 0x6c,0x9e,0x12, 0xba,0x5f,0x89, |
232 | | 0x46,0x9f,0x83, 0x61,0x85,0xdd, 0x84,0x6c,0xef, 0x5d,0xa3,0x29, |
233 | | |
234 | | 0x02,0x00,0x0a, 0xb2,0xac,0xb3, 0xe9,0x92,0x92, 0x6c,0xc3,0xc1, |
235 | | 0xd9,0x86,0xf0, 0x79,0xd1,0x76, 0x9d,0xa1,0xff, 0xbd,0xbe,0x40, |
236 | | 0xdc,0xa2,0x61, 0xd1,0xa9,0x4c, 0x93,0xc8,0x3d, 0xe9,0x8a,0xb1, |
237 | | 0x6f,0xcd,0xab, 0x8a,0xb4,0xff, 0xb2,0x9a,0xff, 0x88,0xcb,0x59, |
238 | | |
239 | | 0x02,0x00,0x0a, 0xc7,0xca,0xc9, 0xff,0xac,0xac, 0x85,0xd8,0xe0, |
240 | | 0xf3,0x9c,0xff, 0x92,0xea,0x8a, 0xb7,0xba,0xff, 0xd6,0xd3,0x5b, |
241 | | 0xf3,0xbe,0x79, 0xe6,0xc5,0x65, 0xb0,0xe0,0x57, 0xff,0xa4,0xcf, |
242 | | 0x89,0xe5,0xc8, 0xa4,0xca,0xff, 0xca,0xb3,0xff, 0xa2,0xe5,0x7a, |
243 | | |
244 | | 0x01,0x01,0x01, 0xff,0xff,0xff, 0xff,0xf6,0xf2, 0xd1,0xff,0xff, |
245 | | 0xff,0xe9,0xff, 0xdb,0xff,0xd3, 0xfd,0xff,0xff, 0xff,0xff,0xa3, |
246 | | 0xff,0xff,0xc1, 0xff,0xff,0xb2, 0xfc,0xff,0xa2, 0xff,0xee,0xff, |
247 | | 0xd1,0xff,0xff, 0xeb,0xff,0xff, 0xff,0xf8,0xff, 0xed,0xff,0xbc |
248 | | |
249 | | video generation |
250 | | column counter from 0 to 39 |
251 | | line counter from 0 to 199 |
252 | | |
253 | | character pointer position/hires: color 0-15 position |
254 | | videoaddr+0x400+(line/8)*40+column |
255 | | color position/hires: color luminance position |
256 | | videoaddr+(line/8)*40+column |
257 | | character bitmap position |
258 | | chargenaddr+(character pointer)+(line&7) |
259 | | bitmap position |
260 | | bitmapaddr+(line/8)*40+column+(line&7) |
261 | | |
262 | | normal text mode (reverse off, ecm off, multicolor off, hires off) |
263 | | character pointer based |
264 | | fetch character pointer, fetch character bitmap, fetch color |
265 | | pixel on color (color)&0x7f |
266 | | pixel off color backgroundcolor |
267 | | blinking (synchron to cursor) (color&0x80) |
268 | | reverse text mode (reverse on, ecm off, multicolor off, hires off) |
269 | | character pointer &0x7f |
270 | | character pointer bit 7 |
271 | | set |
272 | | pixel off color attribut &0x7f |
273 | | pixel on color backgroundcolor |
274 | | clear |
275 | | like normal text mode |
276 | | blinking (synchron to cursor) (color&0x80) |
277 | | multicolor text mode (ecm off, multicolor on, hires off) |
278 | | reverse ? |
279 | | attribut bit 3 character in multicolor (else monocolor character) |
280 | | pixel on color attribut 0x77 |
281 | | 0 backgroundcolor |
282 | | 1 color1 |
283 | | 2 color2 |
284 | | 3 attribut &0x77 |
285 | | (color&0x80) ? |
286 | | ecm text mode (ecm on) |
287 | | reverse ? |
288 | | multicolor ? (c64/vic6567 black display?) |
289 | | hires ? (c64/vic6567 black display?) |
290 | | character pointer &0x3f |
291 | | character pointer bit 7,6 select pixel off color |
292 | | 0 backgroundcolor ? |
293 | | 1 color1? |
294 | | 2 color2? |
295 | | 3 color3? |
296 | | (color&0x80)? |
297 | | hires (ecm off, multicolor off, hires on) |
298 | | bitmap based |
299 | | fetch bitmap, fetch color, fetch color luminance |
300 | | reverse ? |
301 | | pixel on color |
302 | | 6-4: (color luminance) bit 2-0 |
303 | | 3-0: (color) bit 7-4 |
304 | | pixel off color |
305 | | 6-4: (color luminance) bit 6-4 |
306 | | 3-0: (color) bit 3-0 |
307 | | (color) bit 7? |
308 | | (color luminance) bit 7? |
309 | | hires multicolor (ecm off, multicolor on, hires on) |
310 | | reverse ? |
311 | | 0 backgroundcolor |
312 | | 1 |
313 | | 6-4: (color luminance) bit 2-0 |
314 | | 3-0: (color) bit 7-4 |
315 | | 2 |
316 | | 6-4: (color luminance) bit 6-4 |
317 | | 3-0: (color) bit 3-0 |
318 | | 3 color1 |
319 | | (color) bit 7? |
320 | | (color luminance) bit 7? |
321 | | scrolling support |
322 | | visible part of the display in fixed position |
323 | | columns 38 mode left 7 and right 9 pixel less displayed |
324 | | but line generation start at the same position as in columns 40 mode |
325 | | lines25 flag top and bottom 4 pixel less displayed ? |
326 | | horicontal scrolling support |
327 | | in columns 38 mode |
328 | | horicontal position 1-7: pixel later started line generation |
329 | | horicontal position 0: 8 pixels later started line generation |
330 | | in columns 40 mode ? |
331 | | vertical scrolling support |
332 | | in lines 24 mode |
333 | | vertical position 1-7: lines later started line generation |
334 | | vertical position 0: 8 lines later started line generation |
335 | | in lines 25 mode? |
336 | | vertial position 3: for correct display |
337 | | |
338 | | hardware cursor |
339 | | full 8x8 in (color) color |
340 | | flashing when in multicolor, hires ? |
341 | | flashes with about 1 hertz |
342 | | bitmap reload? |
343 | | |
344 | | rasterline/rastercolumn |
345 | | values in registers begin visible area 0 |
346 | | vic 6567 |
347 | | pal line 0 beginning of vertical refresh |
348 | | ntsc line 0 in bottom frame |
349 | | beginning of 25 lines screen 0x33 (24 lines screen 0x37) |
350 | | beginning of 40 columns line 0x18 (38 columns 0x1f) |
351 | | |
352 | | lightpen |
353 | | (where to store values?) |
354 | | i found a lightpen hardware description with a demo and drawing program |
355 | | lightpen must be connected to joy0 (button) |
356 | | demo program: |
357 | | disables interrupt, polles joy0 button (0xfd0d? plus 4 related???) |
358 | | and reads the rasterline value! |
359 | | so i no exact column value reachable! |
360 | | */ |
361 | | #include "emu.h" |
362 | | #include "audio/ted7360.h" |
363 | | |
364 | | |
365 | | typedef struct _ted7360_state ted7360_state; |
366 | | struct _ted7360_state |
367 | | { |
368 | | ted_type type; |
369 | | |
370 | | screen_device *screen; // screen which sets bitmap properties |
371 | | |
372 | | UINT8 reg[0x20]; |
373 | | |
374 | | bitmap_ind16 *bitmap; |
375 | | |
376 | | int rom; |
377 | | |
378 | | int frame_count; |
379 | | |
380 | | int lines; |
381 | | int timer1_active, timer2_active, timer3_active; |
382 | | emu_timer *timer1, *timer2, *timer3; |
383 | | int cursor1; |
384 | | |
385 | | ted7360_dma_read dma_read; |
386 | | ted7360_dma_read_rom dma_read_rom; |
387 | | ted7360_irq interrupt; // c16_interrupt |
388 | | ted7360_key_cb keyboard_cb; // c16_read_keyboard |
389 | | |
390 | | int chargenaddr, bitmapaddr, videoaddr; |
391 | | |
392 | | int x_begin, x_end; |
393 | | int y_begin, y_end; |
394 | | |
395 | | UINT16 c16_bitmap[2], bitmapmulti[4], mono[2], monoinversed[2], multi[4], ecmcolor[2], colors[5]; |
396 | | |
397 | | int rasterline, lastline; |
398 | | double rastertime; |
399 | | |
400 | | |
401 | | /* sound part */ |
402 | | int tone1pos, tone2pos, |
403 | | tone1samples, tone2samples, |
404 | | noisesize, /* number of samples */ |
405 | | noisepos, /* pos of tone */ |
406 | | noisesamples; /* count of samples to give out per tone */ |
407 | | |
408 | | sound_stream *channel; |
409 | | UINT8 *noise; |
410 | | }; |
411 | | |
412 | | /***************************************************************************** |
413 | | CONSTANTS |
414 | | *****************************************************************************/ |
415 | | |
416 | | |
417 | | #define VERBOSE_LEVEL 0 |
418 | | #define DBG_LOG(N,M,A) \ |
419 | | do { \ |
420 | | if(VERBOSE_LEVEL >= N) \ |
421 | | { \ |
422 | | if( M ) \ |
423 | | logerror("%11.6f: %-24s", device->machine().time().as_double(), (char*) M ); \ |
424 | | logerror A; \ |
425 | | } \ |
426 | | } while(0) |
427 | | |
428 | | |
429 | | #define VREFRESHINLINES 28 |
430 | | |
431 | | #define TIMER1HELPER (ted7360->reg[0] | (ted7360->reg[1] << 8)) |
432 | | #define TIMER2HELPER (ted7360->reg[2] | (ted7360->reg[3] << 8)) |
433 | | #define TIMER3HELPER (ted7360->reg[4] | (ted7360->reg[5] << 8)) |
434 | | #define TIMER1 (TIMER1HELPER ? TIMER1HELPER : 0x10000) |
435 | | #define TIMER2 (TIMER2HELPER ? TIMER2HELPER : 0x10000) |
436 | | #define TIMER3 (TIMER3HELPER ? TIMER3HELPER : 0x10000) |
437 | | |
438 | | #define TED7360_YPOS 40 |
439 | | #define RASTERLINE_2_C16(a) ((a + ted7360->lines - TED7360_YPOS - 5) % ted7360->lines) |
440 | | #define C16_2_RASTERLINE(a) ((a + TED7360_YPOS + 5) % ted7360->lines) |
441 | | #define XPOS 8 |
442 | | #define YPOS 8 |
443 | | |
444 | | #define SCREENON (ted7360->reg[6] & 0x10) |
445 | | #define TEST (ted7360->reg[6] & 0x80) |
446 | | #define VERTICALPOS (ted7360->reg[6] & 0x07) |
447 | | #define HORICONTALPOS (ted7360->reg[7] & 0x07) |
448 | | #define ECMON (ted7360->reg[6] & 0x40) |
449 | | #define HIRESON (ted7360->reg[6] & 0x20) |
450 | | #define MULTICOLORON (ted7360->reg[7] & 0x10) |
451 | | #define REVERSEON (!(ted7360->reg[7] & 0x80)) |
452 | | |
453 | | /* hardware inverts character when bit 7 set (character taken &0x7f) */ |
454 | | /* instead of fetching character with higher number! */ |
455 | | #define LINES25 (ted7360->reg[6] & 0x08) /* else 24 Lines */ |
456 | | #define LINES (LINES25 ? 25 : 24) |
457 | | #define YSIZE (LINES * 8) |
458 | | #define COLUMNS40 (ted7360->reg[7] & 0x08) /* else 38 Columns */ |
459 | | #define COLUMNS (COLUMNS40 ? 40 : 38) |
460 | | #define XSIZE (COLUMNS * 8) |
461 | | |
462 | | #define INROM (ted7360->reg[0x12] & 0x04) |
463 | | #define CHARGENADDR (REVERSEON && !HIRESON && !MULTICOLORON ? ((ted7360->reg[0x13] & 0xfc) << 8) : ((ted7360->reg[0x13] & 0xf8) << 8)) |
464 | | #define BITMAPADDR ((ted7360->reg[0x12] & 0x38) << 10) |
465 | | #define VIDEOADDR ((ted7360->reg[0x14] & 0xf8) << 8) |
466 | | |
467 | | #define RASTERLINE (((ted7360->reg[0xa] & 0x01) << 8) | ted7360->reg[0xb]) |
468 | | #define CURSOR1POS (ted7360->reg[0xd] | ((ted7360->reg[0xc] & 0x03) << 8)) |
469 | | #define CURSOR2POS (ted7360->reg[0x1b] | ((ted7360->reg[0x1a] & 0x03) << 8)) |
470 | | #define CURSORRATE ((ted7360->reg[0x1f] & 0x7c) >> 2) |
471 | | |
472 | | #define BACKGROUNDCOLOR (ted7360->reg[0x15] & 0x7f) |
473 | | #define FOREGROUNDCOLOR (ted7360->reg[0x16] & 0x7f) |
474 | | #define MULTICOLOR1 (ted7360->reg[0x17] & 0x7f) |
475 | | #define MULTICOLOR2 (ted7360->reg[0x18] & 0x7f) |
476 | | #define FRAMECOLOR (ted7360->reg[0x19] & 0x7f) |
477 | | |
478 | | #define TED7360_VRETRACERATE ((ted7360->type == TED7360_PAL) ? TED7360PAL_VRETRACERATE : TED7360NTSC_VRETRACERATE) |
479 | | #define TED7360_CLOCK (((ted7360->type == TED7360_PAL) ? TED7360PAL_CLOCK : TED7360NTSC_CLOCK) / 4) |
480 | | #define TED7360_LINES ((ted7360->type == TED7360_PAL) ? TED7360PAL_LINES : TED7360NTSC_LINES) |
481 | | |
482 | | static attotime TEDTIME_IN_CYCLES(int pal, int cycles) |
483 | | { |
484 | | double d = (double)(cycles) / (pal ? TED7360PAL_CLOCK : TED7360NTSC_CLOCK); |
485 | | return attotime::from_double(d); |
486 | | } |
487 | | |
488 | | static int TEDTIME_TO_CYCLES(int pal, attotime t) |
489 | | { |
490 | | double d = t.as_double(); |
491 | | return (int)((d) * (pal ? TED7360PAL_CLOCK : TED7360NTSC_CLOCK)); |
492 | | } |
493 | | |
494 | | /***************************************************************************** |
495 | | INLINE FUNCTIONS |
496 | | *****************************************************************************/ |
497 | | |
498 | | INLINE ted7360_state *get_safe_token( device_t *device ) |
499 | | { |
500 | | assert(device != NULL); |
501 | | assert(device->type() == TED7360); |
502 | | |
503 | | return (ted7360_state *)downcast<legacy_device_base *>(device)->token(); |
504 | | } |
505 | | |
506 | | INLINE const ted7360_interface *get_interface( device_t *device ) |
507 | | { |
508 | | assert(device != NULL); |
509 | | assert(device->type() == TED7360); |
510 | | |
511 | | return (const ted7360_interface *) device->static_config(); |
512 | | } |
513 | | |
514 | | /***************************************************************************** |
515 | | IMPLEMENTATION |
516 | | *****************************************************************************/ |
517 | | |
518 | | static void ted7360_soundport_w( device_t *device, int offset, int data ); |
519 | | |
520 | | static void ted7360_set_interrupt( running_machine &machine, int mask, ted7360_state *ted7360 ) |
521 | | { |
522 | | /* kernel itself polls for timer 2 shot (interrupt disabled!) when cassette loading */ |
523 | | ted7360->reg[9] |= mask; |
524 | | if ((ted7360->reg[0xa] & ted7360->reg[9] & 0x5e)) |
525 | | { |
526 | | if (!(ted7360->reg[9] & 0x80)) |
527 | | { |
528 | | //DBG_LOG(1, "ted7360", ("irq start %.2x\n", mask)); |
529 | | ted7360->reg[9] |= 0x80; |
530 | | ted7360->interrupt(machine, 1); |
531 | | } |
532 | | } |
533 | | ted7360->reg[9] |= mask; |
534 | | } |
535 | | |
536 | | static void ted7360_clear_interrupt( device_t *device, int mask ) |
537 | | { |
538 | | ted7360_state *ted7360 = get_safe_token(device); |
539 | | |
540 | | ted7360->reg[9] &= ~mask; |
541 | | if ((ted7360->reg[9] & 0x80) && !(ted7360->reg[9] & ted7360->reg[0xa] & 0x5e)) |
542 | | { |
543 | | DBG_LOG(1, "ted7360", ("irq end %.2x\n", mask)); |
544 | | ted7360->reg[9] &= ~0x80; |
545 | | ted7360->interrupt(device->machine(), 0); |
546 | | } |
547 | | } |
548 | | |
549 | | static int ted7360_rastercolumn( device_t *device ) |
550 | | { |
551 | | ted7360_state *ted7360 = get_safe_token(device); |
552 | | return (int) ((device->machine().time().as_double() - ted7360->rastertime) * TED7360_VRETRACERATE * ted7360->lines * 57 * 8 + 0.5); |
553 | | } |
554 | | |
555 | | static TIMER_CALLBACK(ted7360_timer_timeout) |
556 | | { |
557 | | ted7360_state *ted7360 = (ted7360_state *)ptr; |
558 | | int which = param; |
559 | | |
560 | | //DBG_LOG(3, "ted7360 ", ("timer %d timeout\n", which)); |
561 | | switch (which) |
562 | | { |
563 | | case 1: |
564 | | // proved by digisound of several intros like eoroidpro |
565 | | ted7360->timer1->adjust(TEDTIME_IN_CYCLES((ted7360->type == TED7360_PAL), TIMER1), 1); |
566 | | ted7360->timer1_active = 1; |
567 | | ted7360_set_interrupt(machine, 0x08, ted7360); |
568 | | break; |
569 | | case 2: |
570 | | ted7360->timer2->adjust(TEDTIME_IN_CYCLES((ted7360->type == TED7360_PAL), 0x10000), 2); |
571 | | ted7360->timer2_active = 1; |
572 | | ted7360_set_interrupt(machine, 0x10, ted7360); |
573 | | break; |
574 | | case 3: |
575 | | ted7360->timer3->adjust(TEDTIME_IN_CYCLES((ted7360->type == TED7360_PAL), 0x10000), 3); |
576 | | ted7360->timer3_active = 1; |
577 | | ted7360_set_interrupt(machine, 0x40, ted7360); |
578 | | break; |
579 | | } |
580 | | } |
581 | | |
582 | | static void ted7360_draw_character( device_t *device, int ybegin, int yend, int ch, int yoff, int xoff, UINT16 *color ) |
583 | | { |
584 | | ted7360_state *ted7360 = get_safe_token(device); |
585 | | int y, code; |
586 | | |
587 | | for (y = ybegin; y <= yend; y++) |
588 | | { |
589 | | if (INROM) |
590 | | code = ted7360->dma_read_rom(device->machine(), ted7360->chargenaddr + ch * 8 + y); |
591 | | else |
592 | | code = ted7360->dma_read(device->machine(), ted7360->chargenaddr + ch * 8 + y); |
593 | | |
594 | | ted7360->bitmap->pix16(y + yoff, 0 + xoff) = color[code >> 7]; |
595 | | ted7360->bitmap->pix16(y + yoff, 1 + xoff) = color[(code >> 6) & 1]; |
596 | | ted7360->bitmap->pix16(y + yoff, 2 + xoff) = color[(code >> 5) & 1]; |
597 | | ted7360->bitmap->pix16(y + yoff, 3 + xoff) = color[(code >> 4) & 1]; |
598 | | ted7360->bitmap->pix16(y + yoff, 4 + xoff) = color[(code >> 3) & 1]; |
599 | | ted7360->bitmap->pix16(y + yoff, 5 + xoff) = color[(code >> 2) & 1]; |
600 | | ted7360->bitmap->pix16(y + yoff, 6 + xoff) = color[(code >> 1) & 1]; |
601 | | ted7360->bitmap->pix16(y + yoff, 7 + xoff) = color[code & 1]; |
602 | | } |
603 | | } |
604 | | |
605 | | static void ted7360_draw_character_multi( device_t *device, int ybegin, int yend, int ch, int yoff, int xoff ) |
606 | | { |
607 | | ted7360_state *ted7360 = get_safe_token(device); |
608 | | int y, code; |
609 | | |
610 | | for (y = ybegin; y <= yend; y++) |
611 | | { |
612 | | if (INROM) |
613 | | code = ted7360->dma_read_rom(device->machine(), ted7360->chargenaddr + ch * 8 + y); |
614 | | else |
615 | | code = ted7360->dma_read(device->machine(), ted7360->chargenaddr + ch * 8 + y); |
616 | | |
617 | | ted7360->bitmap->pix16(y + yoff, 0 + xoff) = |
618 | | ted7360->bitmap->pix16(y + yoff, 1 + xoff) = ted7360->multi[code >> 6]; |
619 | | ted7360->bitmap->pix16(y + yoff, 2 + xoff) = |
620 | | ted7360->bitmap->pix16(y + yoff, 3 + xoff) = ted7360->multi[(code >> 4) & 3]; |
621 | | ted7360->bitmap->pix16(y + yoff, 4 + xoff) = |
622 | | ted7360->bitmap->pix16(y + yoff, 5 + xoff) = ted7360->multi[(code >> 2) & 3]; |
623 | | ted7360->bitmap->pix16(y + yoff, 6 + xoff) = |
624 | | ted7360->bitmap->pix16(y + yoff, 7 + xoff) = ted7360->multi[code & 3]; |
625 | | } |
626 | | } |
627 | | |
628 | | static void ted7360_draw_bitmap( device_t *device, int ybegin, int yend, int ch, int yoff, int xoff ) |
629 | | { |
630 | | ted7360_state *ted7360 = get_safe_token(device); |
631 | | int y, code; |
632 | | |
633 | | for (y = ybegin; y <= yend; y++) |
634 | | { |
635 | | code = ted7360->dma_read(device->machine(), ted7360->bitmapaddr + ch * 8 + y); |
636 | | ted7360->bitmap->pix16(y + yoff, 0 + xoff) = ted7360->c16_bitmap[code >> 7]; |
637 | | ted7360->bitmap->pix16(y + yoff, 1 + xoff) = ted7360->c16_bitmap[(code >> 6) & 1]; |
638 | | ted7360->bitmap->pix16(y + yoff, 2 + xoff) = ted7360->c16_bitmap[(code >> 5) & 1]; |
639 | | ted7360->bitmap->pix16(y + yoff, 3 + xoff) = ted7360->c16_bitmap[(code >> 4) & 1]; |
640 | | ted7360->bitmap->pix16(y + yoff, 4 + xoff) = ted7360->c16_bitmap[(code >> 3) & 1]; |
641 | | ted7360->bitmap->pix16(y + yoff, 5 + xoff) = ted7360->c16_bitmap[(code >> 2) & 1]; |
642 | | ted7360->bitmap->pix16(y + yoff, 6 + xoff) = ted7360->c16_bitmap[(code >> 1) & 1]; |
643 | | ted7360->bitmap->pix16(y + yoff, 7 + xoff) = ted7360->c16_bitmap[code & 1]; |
644 | | } |
645 | | } |
646 | | |
647 | | static void ted7360_draw_bitmap_multi( device_t *device, int ybegin, int yend, int ch, int yoff, int xoff ) |
648 | | { |
649 | | ted7360_state *ted7360 = get_safe_token(device); |
650 | | int y, code; |
651 | | |
652 | | for (y = ybegin; y <= yend; y++) |
653 | | { |
654 | | code = ted7360->dma_read(device->machine(), ted7360->bitmapaddr + ch * 8 + y); |
655 | | |
656 | | ted7360->bitmap->pix16(y + yoff, 0 + xoff) = |
657 | | ted7360->bitmap->pix16(y + yoff, 1 + xoff) = ted7360->bitmapmulti[code >> 6]; |
658 | | ted7360->bitmap->pix16(y + yoff, 2 + xoff) = |
659 | | ted7360->bitmap->pix16(y + yoff, 3 + xoff) = ted7360->bitmapmulti[(code >> 4) & 3]; |
660 | | ted7360->bitmap->pix16(y + yoff, 4 + xoff) = |
661 | | ted7360->bitmap->pix16(y + yoff, 5 + xoff) = ted7360->bitmapmulti[(code >> 2) & 3]; |
662 | | ted7360->bitmap->pix16(y + yoff, 6 + xoff) = |
663 | | ted7360->bitmap->pix16(y + yoff, 7 + xoff) = ted7360->bitmapmulti[code & 3]; |
664 | | } |
665 | | } |
666 | | |
667 | | #ifndef memset16 |
668 | | static void *memset16 (void *dest, int value, size_t size) |
669 | | { |
670 | | register int i; |
671 | | |
672 | | for (i = 0; i < size; i++) |
673 | | ((short *) dest)[i] = value; |
674 | | return dest; |
675 | | } |
676 | | #endif |
677 | | |
678 | | static void ted7360_draw_cursor( device_t *device, int ybegin, int yend, int yoff, int xoff, int color ) |
679 | | { |
680 | | ted7360_state *ted7360 = get_safe_token(device); |
681 | | int y; |
682 | | |
683 | | for (y = ybegin; y <= yend; y++) |
684 | | { |
685 | | memset16(&ted7360->bitmap->pix16(yoff + y, xoff), color, 8); |
686 | | } |
687 | | } |
688 | | |
689 | | static void ted7360_drawlines( device_t *device, int first, int last ) |
690 | | { |
691 | | ted7360_state *ted7360 = get_safe_token(device); |
692 | | int line, vline, end; |
693 | | int attr, ch, c1, c2, ecm; |
694 | | int offs, yoff, xoff, ybegin, yend, xbegin, xend; |
695 | | int i; |
696 | | |
697 | | ted7360->lastline = last; |
698 | | |
699 | | /* top part of display not rastered */ |
700 | | first -= TED7360_YPOS; |
701 | | last -= TED7360_YPOS; |
702 | | if ((first >= last) || (last <= 0)) |
703 | | return; |
704 | | if (first < 0) |
705 | | first = 0; |
706 | | |
707 | | if (!SCREENON) |
708 | | { |
709 | | for (line = first; (line < last) && (line < ted7360->bitmap->height()); line++) |
710 | | memset16(&ted7360->bitmap->pix16(line), 0, ted7360->bitmap->width()); |
711 | | return; |
712 | | } |
713 | | |
714 | | if (COLUMNS40) |
715 | | xbegin = XPOS, xend = xbegin + 320; |
716 | | else |
717 | | xbegin = XPOS + 7, xend = xbegin + 304; |
718 | | |
719 | | if (last < ted7360->y_begin) |
720 | | end = last; |
721 | | else |
722 | | end = ted7360->y_begin + YPOS; |
723 | | { |
724 | | for (line = first; line < end; line++) |
725 | | memset16(&ted7360->bitmap->pix16(line), FRAMECOLOR, ted7360->bitmap->width()); |
726 | | } |
727 | | if (LINES25) |
728 | | vline = line - ted7360->y_begin - YPOS; |
729 | | else |
730 | | vline = line - ted7360->y_begin - YPOS + 8 - VERTICALPOS; |
731 | | |
732 | | if (last < ted7360->y_end + YPOS) |
733 | | end = last; |
734 | | else |
735 | | end = ted7360->y_end + YPOS; |
736 | | |
737 | | for (; line < end; vline = (vline + 8) & ~7, line = line + 1 + yend - ybegin) |
738 | | { |
739 | | offs = (vline >> 3) * 40; |
740 | | ybegin = vline & 7; |
741 | | yoff = line - ybegin; |
742 | | yend = (yoff + 7 < end) ? 7 : (end - yoff - 1); |
743 | | /* rendering 39 characters */ |
744 | | /* left and right borders are overwritten later */ |
745 | | |
746 | | for (xoff = ted7360->x_begin + XPOS; xoff < ted7360->x_end + XPOS; xoff += 8, offs++) |
747 | | { |
748 | | if (HIRESON) |
749 | | { |
750 | | ch = ted7360->dma_read(device->machine(), (ted7360->videoaddr | 0x400) + offs); |
751 | | attr = ted7360->dma_read(device->machine(), ted7360->videoaddr + offs); |
752 | | c1 = ((ch >> 4) & 0xf) | (attr << 4); |
753 | | c2 = (ch & 0xf) | (attr & 0x70); |
754 | | ted7360->bitmapmulti[1] = ted7360->c16_bitmap[1] = c1 & 0x7f; |
755 | | ted7360->bitmapmulti[2] = ted7360->c16_bitmap[0] = c2 & 0x7f; |
756 | | if (MULTICOLORON) |
757 | | { |
758 | | ted7360_draw_bitmap_multi(device, ybegin, yend, offs, yoff, xoff); |
759 | | } |
760 | | else |
761 | | { |
762 | | ted7360_draw_bitmap(device, ybegin, yend, offs, yoff, xoff); |
763 | | } |
764 | | } |
765 | | else |
766 | | { |
767 | | ch = ted7360->dma_read(device->machine(), (ted7360->videoaddr | 0x400) + offs); |
768 | | attr = ted7360->dma_read(device->machine(), ted7360->videoaddr + offs); |
769 | | // levente harsfalvi's docu says cursor off in ecm and multicolor |
770 | | if (ECMON) |
771 | | { |
772 | | // hardware reverse off |
773 | | ecm = ch >> 6; |
774 | | ted7360->ecmcolor[0] = ted7360->colors[ecm]; |
775 | | ted7360->ecmcolor[1] = attr & 0x7f; |
776 | | ted7360_draw_character(device, ybegin, yend, ch & ~0xc0, yoff, xoff, ted7360->ecmcolor); |
777 | | } |
778 | | else if (MULTICOLORON) |
779 | | { |
780 | | // hardware reverse off |
781 | | if (attr & 8) |
782 | | { |
783 | | ted7360->multi[3] = attr & 0x77; |
784 | | ted7360_draw_character_multi(device, ybegin, yend, ch, yoff, xoff); |
785 | | } |
786 | | else |
787 | | { |
788 | | ted7360->mono[1] = attr & 0x7f; |
789 | | ted7360_draw_character(device, ybegin, yend, ch, yoff, xoff, ted7360->mono); |
790 | | } |
791 | | } |
792 | | else if (ted7360->cursor1 && (offs == CURSOR1POS)) |
793 | | { |
794 | | ted7360_draw_cursor(device, ybegin, yend, yoff, xoff, attr & 0x7f); |
795 | | } |
796 | | else if (REVERSEON && (ch & 0x80)) |
797 | | { |
798 | | ted7360->monoinversed[0] = attr & 0x7f; |
799 | | if (ted7360->cursor1 && (attr & 0x80)) |
800 | | ted7360_draw_cursor(device, ybegin, yend, yoff, xoff, ted7360->monoinversed[0]); |
801 | | else |
802 | | ted7360_draw_character(device, ybegin, yend, ch & ~0x80, yoff, xoff, ted7360->monoinversed); |
803 | | } |
804 | | else |
805 | | { |
806 | | ted7360->mono[1] = attr & 0x7f; |
807 | | if (ted7360->cursor1 && (attr & 0x80)) |
808 | | ted7360_draw_cursor(device, ybegin, yend, yoff, xoff, ted7360->mono[0]); |
809 | | else |
810 | | ted7360_draw_character(device, ybegin, yend, ch, yoff, xoff, ted7360->mono); |
811 | | } |
812 | | } |
813 | | } |
814 | | |
815 | | for (i = ybegin; i <= yend; i++) |
816 | | { |
817 | | memset16(&ted7360->bitmap->pix16(yoff + i), FRAMECOLOR, xbegin); |
818 | | memset16(&ted7360->bitmap->pix16(yoff + i, xend), FRAMECOLOR, ted7360->bitmap->width() - xend); |
819 | | } |
820 | | } |
821 | | |
822 | | if (last < ted7360->bitmap->height()) |
823 | | end = last; |
824 | | else |
825 | | end = ted7360->bitmap->height(); |
826 | | |
827 | | for (; line < end; line++) |
828 | | { |
829 | | memset16(&ted7360->bitmap->pix16(line), FRAMECOLOR, ted7360->bitmap->width()); |
830 | | } |
831 | | } |
832 | | |
833 | | |
834 | | WRITE8_DEVICE_HANDLER( ted7360_port_w ) |
835 | | { |
836 | | ted7360_state *ted7360 = get_safe_token(device); |
837 | | int old; |
838 | | |
839 | | if ((offset != 8) && ((offset < 0x15) || (offset > 0x19))) |
840 | | { |
841 | | DBG_LOG(1, "ted7360_port_w", ("%.2x:%.2x\n", offset, data)); |
842 | | } |
843 | | |
844 | | switch (offset) |
845 | | { |
846 | | case 0xe: |
847 | | case 0xf: |
848 | | case 0x10: |
849 | | case 0x11: |
850 | | case 0x12: |
851 | | ted7360_soundport_w(device, offset, data); |
852 | | break; |
853 | | } |
854 | | switch (offset) |
855 | | { |
856 | | case 0: /* stop timer 1 */ |
857 | | ted7360->reg[offset] = data; |
858 | | |
859 | | if (ted7360->timer1_active) |
860 | | { |
861 | | ted7360->reg[1] = TEDTIME_TO_CYCLES((ted7360->type == TED7360_PAL), ted7360->timer1->remaining()) >> 8; |
862 | | ted7360->timer1->reset(); |
863 | | ted7360->timer1_active = 0; |
864 | | } |
865 | | break; |
866 | | case 1: /* start timer 1 */ |
867 | | ted7360->reg[offset] = data; |
868 | | ted7360->timer1->adjust(TEDTIME_IN_CYCLES((ted7360->type == TED7360_PAL), TIMER1), 1); |
869 | | ted7360->timer1_active = 1; |
870 | | break; |
871 | | case 2: /* stop timer 2 */ |
872 | | ted7360->reg[offset] = data; |
873 | | if (ted7360->timer2_active) |
874 | | { |
875 | | ted7360->reg[3] = TEDTIME_TO_CYCLES((ted7360->type == TED7360_PAL), ted7360->timer2->remaining()) >> 8; |
876 | | ted7360->timer2->reset(); |
877 | | ted7360->timer2_active = 0; |
878 | | } |
879 | | break; |
880 | | case 3: /* start timer 2 */ |
881 | | ted7360->reg[offset] = data; |
882 | | ted7360->timer2->adjust(TEDTIME_IN_CYCLES((ted7360->type == TED7360_PAL), TIMER2), 2); |
883 | | ted7360->timer2_active = 1; |
884 | | break; |
885 | | case 4: /* stop timer 3 */ |
886 | | ted7360->reg[offset] = data; |
887 | | if (ted7360->timer3_active) |
888 | | { |
889 | | ted7360->reg[5] = TEDTIME_TO_CYCLES((ted7360->type == TED7360_PAL), ted7360->timer3->remaining()) >> 8; |
890 | | ted7360->timer3->reset(); |
891 | | ted7360->timer3_active = 0; |
892 | | } |
893 | | break; |
894 | | case 5: /* start timer 3 */ |
895 | | ted7360->reg[offset] = data; |
896 | | ted7360->timer3->adjust(TEDTIME_IN_CYCLES((ted7360->type == TED7360_PAL), TIMER3), 3); |
897 | | ted7360->timer3_active = 1; |
898 | | break; |
899 | | case 6: |
900 | | if (ted7360->reg[offset] != data) |
901 | | { |
902 | | ted7360_drawlines(device, ted7360->lastline, ted7360->rasterline); |
903 | | ted7360->reg[offset] = data; |
904 | | if (LINES25) |
905 | | { |
906 | | ted7360->y_begin = 0; |
907 | | ted7360->y_end = ted7360->y_begin + 200; |
908 | | } |
909 | | else |
910 | | { |
911 | | ted7360->y_begin = 4; |
912 | | ted7360->y_end = ted7360->y_begin + 192; |
913 | | } |
914 | | ted7360->chargenaddr = CHARGENADDR; |
915 | | } |
916 | | break; |
917 | | case 7: |
918 | | if (ted7360->reg[offset] != data) |
919 | | { |
920 | | ted7360_drawlines(device, ted7360->lastline, ted7360->rasterline); |
921 | | ted7360->reg[offset] = data; |
922 | | if (COLUMNS40) |
923 | | { |
924 | | ted7360->x_begin = 0; |
925 | | ted7360->x_end = ted7360->x_begin + 320; |
926 | | } |
927 | | else |
928 | | { |
929 | | ted7360->x_begin = HORICONTALPOS; |
930 | | ted7360->x_end = ted7360->x_begin + 320; |
931 | | } |
932 | | DBG_LOG(3, "ted7360_port_w", ("%s %s\n", data & 0x40 ? "ntsc" : "pal", data & 0x20 ? "hori freeze" : "")); |
933 | | ted7360->chargenaddr = CHARGENADDR; |
934 | | } |
935 | | break; |
936 | | case 8: |
937 | | ted7360->reg[offset] = ted7360->keyboard_cb(device->machine(), data); |
938 | | break; |
939 | | case 9: |
940 | | if (data & 0x08) |
941 | | ted7360_clear_interrupt(device, 8); |
942 | | if (data & 0x10) |
943 | | ted7360_clear_interrupt(device, 0x10); |
944 | | if (data & 0x40) |
945 | | ted7360_clear_interrupt(device, 0x40); |
946 | | if (data & 0x02) |
947 | | ted7360_clear_interrupt(device, 2); |
948 | | break; |
949 | | case 0xa: |
950 | | old = data; |
951 | | ted7360->reg[offset] = data | 0xa0; |
952 | | #if 0 |
953 | | ted7360->reg[9] = (ted7360->reg[9] & 0xa1) | (ted7360->reg[9] & data & 0x5e); |
954 | | if (ted7360->reg[9] & 0x80) |
955 | | ted7360_clear_interrupt(device, 0); |
956 | | #endif |
957 | | if ((data ^ old) & 1) |
958 | | { |
959 | | /* DBG_LOG(1,"set rasterline hi",("soll:%d\n",RASTERLINE)); */ |
960 | | } |
961 | | break; |
962 | | case 0xb: |
963 | | if (data != ted7360->reg[offset]) |
964 | | { |
965 | | ted7360_drawlines(device, ted7360->lastline, ted7360->rasterline); |
966 | | ted7360->reg[offset] = data; |
967 | | /* DBG_LOG(1,"set rasterline lo",("soll:%d\n",RASTERLINE)); */ |
968 | | } |
969 | | break; |
970 | | case 0xc: |
971 | | case 0xd: |
972 | | if (ted7360->reg[offset] != data) |
973 | | { |
974 | | ted7360_drawlines(device, ted7360->lastline, ted7360->rasterline); |
975 | | ted7360->reg[offset] = data; |
976 | | } |
977 | | break; |
978 | | case 0x12: |
979 | | if (ted7360->reg[offset] != data) |
980 | | { |
981 | | ted7360_drawlines(device, ted7360->lastline, ted7360->rasterline); |
982 | | ted7360->reg[offset] = data; |
983 | | ted7360->bitmapaddr = BITMAPADDR; |
984 | | ted7360->chargenaddr = CHARGENADDR; |
985 | | DBG_LOG(3, "ted7360_port_w", ("bitmap %.4x %s\n", BITMAPADDR, INROM ? "rom" : "ram")); |
986 | | } |
987 | | break; |
988 | | case 0x13: |
989 | | if (ted7360->reg[offset] != data) |
990 | | { |
991 | | ted7360_drawlines(device, ted7360->lastline, ted7360->rasterline); |
992 | | ted7360->reg[offset] = data; |
993 | | ted7360->chargenaddr = CHARGENADDR; |
994 | | DBG_LOG(3, "ted7360_port_w", ("chargen %.4x %s %d\n", CHARGENADDR, data & 2 ? "" : "doubleclock", data & 1)); |
995 | | } |
996 | | break; |
997 | | case 0x14: |
998 | | if (ted7360->reg[offset] != data) |
999 | | { |
1000 | | ted7360_drawlines(device, ted7360->lastline, ted7360->rasterline); |
1001 | | ted7360->reg[offset] = data; |
1002 | | ted7360->videoaddr = VIDEOADDR; |
1003 | | DBG_LOG(3, "ted7360_port_w", ("videoram %.4x\n", VIDEOADDR)); |
1004 | | } |
1005 | | break; |
1006 | | case 0x15: /* backgroundcolor */ |
1007 | | if (ted7360->reg[offset] != data) |
1008 | | { |
1009 | | ted7360_drawlines(device, ted7360->lastline, ted7360->rasterline); |
1010 | | ted7360->reg[offset] = data; |
1011 | | ted7360->monoinversed[1] = ted7360->mono[0] = ted7360->bitmapmulti[0] = ted7360->multi[0] = ted7360->colors[0] = BACKGROUNDCOLOR; |
1012 | | } |
1013 | | break; |
1014 | | case 0x16: /* foregroundcolor */ |
1015 | | if (ted7360->reg[offset] != data) |
1016 | | { |
1017 | | ted7360_drawlines(device, ted7360->lastline, ted7360->rasterline); |
1018 | | ted7360->reg[offset] = data; |
1019 | | ted7360->bitmapmulti[3] = ted7360->multi[1] = ted7360->colors[1] = FOREGROUNDCOLOR; |
1020 | | } |
1021 | | break; |
1022 | | case 0x17: /* multicolor 1 */ |
1023 | | if (ted7360->reg[offset] != data) |
1024 | | { |
1025 | | ted7360_drawlines(device, ted7360->lastline, ted7360->rasterline); |
1026 | | ted7360->reg[offset] = data; |
1027 | | ted7360->multi[2] = ted7360->colors[2] = MULTICOLOR1; |
1028 | | } |
1029 | | break; |
1030 | | case 0x18: /* multicolor 2 */ |
1031 | | if (ted7360->reg[offset] != data) |
1032 | | { |
1033 | | ted7360_drawlines(device, ted7360->lastline, ted7360->rasterline); |
1034 | | ted7360->reg[offset] = data; |
1035 | | ted7360->colors[3] = MULTICOLOR2; |
1036 | | } |
1037 | | break; |
1038 | | case 0x19: /* framecolor */ |
1039 | | if (ted7360->reg[offset] != data) |
1040 | | { |
1041 | | ted7360_drawlines(device, ted7360->lastline, ted7360->rasterline); |
1042 | | ted7360->reg[offset] = data; |
1043 | | ted7360->colors[4] = FRAMECOLOR; |
1044 | | } |
1045 | | break; |
1046 | | case 0x1c: |
1047 | | ted7360->reg[offset] = data; /*? */ |
1048 | | DBG_LOG(1, "ted7360_port_w", ("write to rasterline high %.2x\n", |
1049 | | data)); |
1050 | | break; |
1051 | | case 0x1f: |
1052 | | ted7360->reg[offset] = data; |
1053 | | DBG_LOG(1, "ted7360_port_w", ("write to cursorblink %.2x\n", data)); |
1054 | | break; |
1055 | | default: |
1056 | | ted7360->reg[offset] = data; |
1057 | | break; |
1058 | | } |
1059 | | } |
1060 | | |
1061 | | READ8_DEVICE_HANDLER( ted7360_port_r ) |
1062 | | { |
1063 | | ted7360_state *ted7360 = get_safe_token(device); |
1064 | | int val = 0; |
1065 | | |
1066 | | switch (offset) |
1067 | | { |
1068 | | case 0: |
1069 | | if (ted7360->timer1) |
1070 | | val = TEDTIME_TO_CYCLES((ted7360->type == TED7360_PAL), ted7360->timer1->remaining()) & 0xff; |
1071 | | else |
1072 | | val = ted7360->reg[offset]; |
1073 | | break; |
1074 | | case 1: |
1075 | | if (ted7360->timer1) |
1076 | | val = TEDTIME_TO_CYCLES((ted7360->type == TED7360_PAL), ted7360->timer1->remaining()) >> 8; |
1077 | | else |
1078 | | val = ted7360->reg[offset]; |
1079 | | break; |
1080 | | case 2: |
1081 | | if (ted7360->timer2) |
1082 | | val = TEDTIME_TO_CYCLES((ted7360->type == TED7360_PAL), ted7360->timer2->remaining()) & 0xff; |
1083 | | else |
1084 | | val = ted7360->reg[offset]; |
1085 | | break; |
1086 | | case 3: |
1087 | | if (ted7360->timer2) |
1088 | | val = TEDTIME_TO_CYCLES((ted7360->type == TED7360_PAL), ted7360->timer2->remaining()) >> 8; |
1089 | | else |
1090 | | val = ted7360->reg[offset]; |
1091 | | break; |
1092 | | case 4: |
1093 | | if (ted7360->timer3) |
1094 | | val = TEDTIME_TO_CYCLES((ted7360->type == TED7360_PAL), ted7360->timer3->remaining()) & 0xff; |
1095 | | else |
1096 | | val = ted7360->reg[offset]; |
1097 | | break; |
1098 | | case 5: |
1099 | | if (ted7360->timer3) |
1100 | | val = TEDTIME_TO_CYCLES((ted7360->type == TED7360_PAL), ted7360->timer3->remaining()) >> 8; |
1101 | | else |
1102 | | val = ted7360->reg[offset]; |
1103 | | break; |
1104 | | case 7: |
1105 | | val = (ted7360->reg[offset] & ~0x40); |
1106 | | if (ted7360->type == TED7360_NTSC) |
1107 | | val |= 0x40; |
1108 | | break; |
1109 | | case 9: |
1110 | | val = ted7360->reg[offset] | 1; |
1111 | | break; |
1112 | | case 0xa: |
1113 | | val = ted7360->reg[offset]; |
1114 | | break; |
1115 | | case 0xb: |
1116 | | val = ted7360->reg[offset]; |
1117 | | break; |
1118 | | case 0x0c: |
1119 | | val = ted7360->reg[offset] |= 0xfc; |
1120 | | break; |
1121 | | case 0x13: |
1122 | | val = ted7360->reg[offset] & ~1; |
1123 | | if (ted7360->rom) |
1124 | | val |= 1; |
1125 | | break; |
1126 | | case 0x1c: /*rasterline */ |
1127 | | ted7360_drawlines(device, ted7360->lastline, ted7360->rasterline); |
1128 | | val = ((RASTERLINE_2_C16(ted7360->rasterline) & 0x100) >> 8) | 0xfe; /* expected by matrix */ |
1129 | | break; |
1130 | | case 0x1d: /*rasterline */ |
1131 | | ted7360_drawlines(device, ted7360->lastline, ted7360->rasterline); |
1132 | | val = RASTERLINE_2_C16(ted7360->rasterline) & 0xff; |
1133 | | break; |
1134 | | case 0x1e: /*rastercolumn */ |
1135 | | val = ted7360_rastercolumn(device) / 2; /* pengo >=0x99 */ |
1136 | | break; |
1137 | | case 0x1f: |
1138 | | val = ((ted7360->rasterline & 7) << 4) | (ted7360->reg[offset] & 0x0f); |
1139 | | DBG_LOG(1, "ted7360_port_w", ("read from cursorblink %.2x\n", val)); |
1140 | | break; |
1141 | | default: |
1142 | | val = ted7360->reg[offset]; |
1143 | | break; |
1144 | | } |
1145 | | |
1146 | | if ((offset != 8) && (offset >= 6) && (offset != 0x1c) && (offset != 0x1d) && (offset != 9) && ((offset < 0x15) || (offset > 0x19))) |
1147 | | { |
1148 | | DBG_LOG(1, "ted7360_port_r", ("%.2x:%.2x\n", offset, val)); |
1149 | | } |
1150 | | |
1151 | | return val; |
1152 | | } |
1153 | | |
1154 | | WRITE_LINE_DEVICE_HANDLER( ted7360_rom_switch_w ) |
1155 | | { |
1156 | | ted7360_state *ted7360 = get_safe_token(device); |
1157 | | ted7360->rom = state; |
1158 | | } |
1159 | | |
1160 | | READ_LINE_DEVICE_HANDLER( ted7360_rom_switch_r ) |
1161 | | { |
1162 | | ted7360_state *ted7360 = get_safe_token(device); |
1163 | | return ted7360->rom; |
1164 | | } |
1165 | | |
1166 | | void ted7360_frame_interrupt_gen( device_t *device ) |
1167 | | { |
1168 | | ted7360_state *ted7360 = get_safe_token(device); |
1169 | | |
1170 | | if ((ted7360->reg[0x1f] & 0xf) >= 0x0f) |
1171 | | { |
1172 | | /* if (ted7360->frame_count >= CURSORRATE) */ |
1173 | | ted7360->cursor1 ^= 1; |
1174 | | ted7360->reg[0x1f] &= ~0xf; |
1175 | | ted7360->frame_count = 0; |
1176 | | } |
1177 | | else |
1178 | | ted7360->reg[0x1f]++; |
1179 | | } |
1180 | | |
1181 | | void ted7360_raster_interrupt_gen( device_t *device ) |
1182 | | { |
1183 | | ted7360_state *ted7360 = get_safe_token(device); |
1184 | | |
1185 | | ted7360->rasterline++; |
1186 | | ted7360->rastertime = device->machine().time().as_double(); |
1187 | | if (ted7360->rasterline >= ted7360->lines) |
1188 | | { |
1189 | | ted7360->rasterline = 0; |
1190 | | ted7360_drawlines(device, ted7360->lastline, TED7360_LINES); |
1191 | | ted7360->lastline = 0; |
1192 | | } |
1193 | | |
1194 | | if (ted7360->rasterline == C16_2_RASTERLINE(RASTERLINE)) |
1195 | | { |
1196 | | ted7360_drawlines(device, ted7360->lastline, ted7360->rasterline); |
1197 | | ted7360_set_interrupt(device->machine(), 2, ted7360); |
1198 | | } |
1199 | | } |
1200 | | |
1201 | | UINT32 ted7360_video_update( device_t *device, bitmap_ind16 &bitmap, const rectangle &cliprect ) |
1202 | | { |
1203 | | ted7360_state *ted7360 = get_safe_token(device); |
1204 | | |
1205 | | copybitmap(bitmap, *ted7360->bitmap, 0, 0, 0, 0, cliprect); |
1206 | | return 0; |
1207 | | } |
1208 | | |
1209 | | |
1210 | | /* Sound emulation */ |
1211 | | |
1212 | | #define NOISE_BUFFER_SIZE_SEC 5 |
1213 | | |
1214 | | #define TONE_ON (!(ted7360->reg[0x11] & 0x80)) /* or tone update!? */ |
1215 | | #define TONE1_ON ((ted7360->reg[0x11] & 0x10)) |
1216 | | #define TONE1_VALUE (ted7360->reg[0x0e] | ((ted7360->reg[0x12] & 3) << 8)) |
1217 | | #define TONE2_ON ((ted7360->reg[0x11] & 0x20)) |
1218 | | #define TONE2_VALUE (ted7360->reg[0x0f] | ((ted7360->reg[0x10] & 3) << 8)) |
1219 | | #define VOLUME (ted7360->reg[0x11] & 0x0f) |
1220 | | #define NOISE_ON (ted7360->reg[0x11] & 0x40) |
1221 | | |
1222 | | /* |
1223 | | * pal 111860.781 |
1224 | | * ntsc 111840.45 |
1225 | | */ |
1226 | | #define TONE_FREQUENCY(reg) ((TED7360_CLOCK >> 3) / (1024 - reg)) |
1227 | | #define TONE_FREQUENCY_MIN (TONE_FREQUENCY(0)) |
1228 | | #define NOISE_FREQUENCY (TED7360_CLOCK / 8 / (1024 - TONE2_VALUE)) |
1229 | | #define NOISE_FREQUENCY_MAX (TED7360_CLOCK / 8) |
1230 | | |
1231 | | |
1232 | | static void ted7360_soundport_w( device_t *device, int offset, int data ) |
1233 | | { |
1234 | | ted7360_state *ted7360 = get_safe_token(device); |
1235 | | |
1236 | | // int old = ted7360->reg[offset]; |
1237 | | ted7360->channel->update(); |
1238 | | |
1239 | | switch (offset) |
1240 | | { |
1241 | | case 0x0e: |
1242 | | case 0x12: |
1243 | | if (offset == 0x12) |
1244 | | ted7360->reg[offset] = (ted7360->reg[offset] & ~3) | (data & 3); |
1245 | | else |
1246 | | ted7360->reg[offset] = data; |
1247 | | |
1248 | | ted7360->tone1samples = device->machine().sample_rate() / TONE_FREQUENCY (TONE1_VALUE); |
1249 | | DBG_LOG(1, "ted7360", ("tone1 %d %d sample:%d\n", TONE1_VALUE, TONE_FREQUENCY(TONE1_VALUE), ted7360->tone1samples)); |
1250 | | break; |
1251 | | |
1252 | | case 0xf: |
1253 | | case 0x10: |
1254 | | ted7360->reg[offset] = data; |
1255 | | |
1256 | | ted7360->tone2samples = device->machine().sample_rate() / TONE_FREQUENCY (TONE2_VALUE); |
1257 | | DBG_LOG (1, "ted7360", ("tone2 %d %d sample:%d\n", TONE2_VALUE, TONE_FREQUENCY(TONE2_VALUE), ted7360->tone2samples)); |
1258 | | |
1259 | | ted7360->noisesamples = (int) ((double) NOISE_FREQUENCY_MAX * device->machine().sample_rate() * NOISE_BUFFER_SIZE_SEC / NOISE_FREQUENCY); |
1260 | | DBG_LOG (1, "ted7360", ("noise %d sample:%d\n", NOISE_FREQUENCY, ted7360->noisesamples)); |
1261 | | |
1262 | | if (!NOISE_ON || ((double) ted7360->noisepos / ted7360->noisesamples >= 1.0)) |
1263 | | ted7360->noisepos = 0; |
1264 | | break; |
1265 | | |
1266 | | case 0x11: |
1267 | | ted7360->reg[offset] = data; |
1268 | | DBG_LOG(1, "ted7360", ("%s volume %d, %s %s %s\n", TONE_ON?"on":"off", |
1269 | | VOLUME, TONE1_ON?"tone1":"", TONE2_ON?"tone2":"", NOISE_ON?"noise":"")); |
1270 | | |
1271 | | if (!TONE_ON||!TONE1_ON) ted7360->tone1pos = 0; |
1272 | | if (!TONE_ON||!TONE2_ON) ted7360->tone2pos = 0; |
1273 | | if (!TONE_ON||!NOISE_ON) ted7360->noisepos = 0; |
1274 | | break; |
1275 | | } |
1276 | | } |
1277 | | |
1278 | | |
1279 | | /************************************/ |
1280 | | /* Sound handler update */ |
1281 | | /************************************/ |
1282 | | |
1283 | | static STREAM_UPDATE( ted7360_update ) |
1284 | | { |
1285 | | ted7360_state *ted7360 = get_safe_token(device); |
1286 | | int i, v, a; |
1287 | | stream_sample_t *buffer = outputs[0]; |
1288 | | |
1289 | | for (i = 0; i < samples; i++) |
1290 | | { |
1291 | | v = 0; |
1292 | | |
1293 | | if (TONE1_ON) |
1294 | | { |
1295 | | if (ted7360->tone1pos <= ted7360->tone1samples / 2 || !TONE_ON) |
1296 | | v += 0x2ff; // depends on the volume between sound and noise |
1297 | | |
1298 | | ted7360->tone1pos++; |
1299 | | |
1300 | | if (ted7360->tone1pos > ted7360->tone1samples) |
1301 | | ted7360->tone1pos = 0; |
1302 | | } |
1303 | | |
1304 | | if (TONE2_ON || NOISE_ON ) |
1305 | | { |
1306 | | if (TONE2_ON) |
1307 | | { /*higher priority ?! */ |
1308 | | if (ted7360->tone2pos <= ted7360->tone2samples / 2 || !TONE_ON) |
1309 | | v += 0x2ff; |
1310 | | |
1311 | | ted7360->tone2pos++; |
1312 | | |
1313 | | if (ted7360->tone2pos > ted7360->tone2samples) |
1314 | | ted7360->tone2pos = 0; |
1315 | | } |
1316 | | else |
1317 | | { |
1318 | | v += ted7360->noise[(int) ((double) ted7360->noisepos * ted7360->noisesize / ted7360->noisesamples)]; |
1319 | | ted7360->noisepos++; |
1320 | | |
1321 | | if ((double) ted7360->noisepos / ted7360->noisesamples >= 1.0) |
1322 | | ted7360->noisepos = 0; |
1323 | | } |
1324 | | } |
1325 | | |
1326 | | a = VOLUME; |
1327 | | if (a > 8) |
1328 | | a = 8; |
1329 | | |
1330 | | v = v * a; |
1331 | | |
1332 | | buffer[i] = v; |
1333 | | } |
1334 | | } |
1335 | | |
1336 | | /***************************************************************************** |
1337 | | DEVICE INTERFACE |
1338 | | *****************************************************************************/ |
1339 | | |
1340 | | /************************************/ |
1341 | | /* Sound handler start */ |
1342 | | /************************************/ |
1343 | | |
1344 | | static void ted7360_sound_start( device_t *device ) |
1345 | | { |
1346 | | ted7360_state *ted7360 = get_safe_token(device); |
1347 | | int i; |
1348 | | |
1349 | | ted7360->channel = device->machine().sound().stream_alloc(*device, 0, 1, device->machine().sample_rate(), 0, ted7360_update); |
1350 | | |
1351 | | /* buffer for fastest played sample for 5 second so we have enough data for min 5 second */ |
1352 | | ted7360->noisesize = NOISE_FREQUENCY_MAX * NOISE_BUFFER_SIZE_SEC; |
1353 | | ted7360->noise = auto_alloc_array(device->machine(), UINT8, ted7360->noisesize); |
1354 | | |
1355 | | { |
1356 | | int noiseshift = 0x7ffff8; |
1357 | | UINT8 data; |
1358 | | |
1359 | | for (i = 0; i < ted7360->noisesize; i++) |
1360 | | { |
1361 | | data = 0; |
1362 | | if (noiseshift & 0x400000) |
1363 | | data |= 0x80; |
1364 | | if (noiseshift & 0x100000) |
1365 | | data |= 0x40; |
1366 | | if (noiseshift & 0x010000) |
1367 | | data |= 0x20; |
1368 | | if (noiseshift & 0x002000) |
1369 | | data |= 0x10; |
1370 | | if (noiseshift & 0x000800) |
1371 | | data |= 0x08; |
1372 | | if (noiseshift & 0x000080) |
1373 | | data |= 0x04; |
1374 | | if (noiseshift & 0x000010) |
1375 | | data |= 0x02; |
1376 | | if (noiseshift & 0x000004) |
1377 | | data |= 0x01; |
1378 | | ted7360->noise[i] = data; |
1379 | | if (((noiseshift & 0x400000) == 0) != ((noiseshift & 0x002000) == 0)) |
1380 | | noiseshift = (noiseshift << 1) | 1; |
1381 | | else |
1382 | | noiseshift <<= 1; |
1383 | | } |
1384 | | } |
1385 | | } |
1386 | | |
1387 | | static DEVICE_START( ted7360 ) |
1388 | | { |
1389 | | ted7360_state *ted7360 = get_safe_token(device); |
1390 | | const ted7360_interface *intf = (ted7360_interface *)device->static_config(); |
1391 | | int width, height; |
1392 | | |
1393 | | ted7360->screen = device->machine().device<screen_device>(intf->screen); |
1394 | | width = ted7360->screen->width(); |
1395 | | height = ted7360->screen->height(); |
1396 | | |
1397 | | ted7360->bitmap = auto_bitmap_ind16_alloc(device->machine(), width, height); |
1398 | | |
1399 | | ted7360->type = intf->type; |
1400 | | |
1401 | | ted7360->dma_read = intf->dma_read; |
1402 | | ted7360->dma_read_rom = intf->dma_read_rom; |
1403 | | ted7360->interrupt = intf->irq; |
1404 | | |
1405 | | ted7360->keyboard_cb = intf->keyb_cb; |
1406 | | |
1407 | | ted7360->timer1 = device->machine().scheduler().timer_alloc(FUNC(ted7360_timer_timeout), ted7360); |
1408 | | ted7360->timer2 = device->machine().scheduler().timer_alloc(FUNC(ted7360_timer_timeout), ted7360); |
1409 | | ted7360->timer3 = device->machine().scheduler().timer_alloc(FUNC(ted7360_timer_timeout), ted7360); |
1410 | | |
1411 | | ted7360_sound_start(device); |
1412 | | |
1413 | | device->save_item(NAME(ted7360->reg)); |
1414 | | |
1415 | | device->save_item(NAME(*ted7360->bitmap)); |
1416 | | |
1417 | | device->save_item(NAME(ted7360->rom)); |
1418 | | device->save_item(NAME(ted7360->lines)); |
1419 | | device->save_item(NAME(ted7360->chargenaddr)); |
1420 | | device->save_item(NAME(ted7360->bitmapaddr)); |
1421 | | device->save_item(NAME(ted7360->videoaddr)); |
1422 | | device->save_item(NAME(ted7360->timer1_active)); |
1423 | | device->save_item(NAME(ted7360->timer2_active)); |
1424 | | device->save_item(NAME(ted7360->timer3_active)); |
1425 | | device->save_item(NAME(ted7360->cursor1)); |
1426 | | device->save_item(NAME(ted7360->rasterline)); |
1427 | | device->save_item(NAME(ted7360->lastline)); |
1428 | | device->save_item(NAME(ted7360->rastertime)); |
1429 | | device->save_item(NAME(ted7360->frame_count)); |
1430 | | device->save_item(NAME(ted7360->x_begin)); |
1431 | | device->save_item(NAME(ted7360->x_end)); |
1432 | | device->save_item(NAME(ted7360->y_begin)); |
1433 | | device->save_item(NAME(ted7360->y_end)); |
1434 | | |
1435 | | device->save_item(NAME(ted7360->c16_bitmap)); |
1436 | | device->save_item(NAME(ted7360->bitmapmulti)); |
1437 | | device->save_item(NAME(ted7360->mono)); |
1438 | | device->save_item(NAME(ted7360->monoinversed)); |
1439 | | device->save_item(NAME(ted7360->multi)); |
1440 | | device->save_item(NAME(ted7360->ecmcolor)); |
1441 | | device->save_item(NAME(ted7360->colors)); |
1442 | | |
1443 | | device->save_item(NAME(ted7360->tone1pos)); |
1444 | | device->save_item(NAME(ted7360->tone2pos)); |
1445 | | device->save_item(NAME(ted7360->tone1samples)); |
1446 | | device->save_item(NAME(ted7360->tone2samples)); |
1447 | | device->save_item(NAME(ted7360->noisepos)); |
1448 | | device->save_item(NAME(ted7360->noisesamples)); |
1449 | | } |
1450 | | |
1451 | | static DEVICE_RESET( ted7360 ) |
1452 | | { |
1453 | | ted7360_state *ted7360 = get_safe_token(device); |
1454 | | |
1455 | | memset(ted7360->reg, 0, ARRAY_LENGTH(ted7360->reg)); |
1456 | | |
1457 | | ted7360->rom = 1; // FIXME: at start should be RAM or ROM? old c16 code set it to ROM at init: is it correct? |
1458 | | |
1459 | | ted7360->lines = TED7360_LINES; |
1460 | | ted7360->chargenaddr = ted7360->bitmapaddr = ted7360->videoaddr = 0; |
1461 | | ted7360->timer1_active = ted7360->timer2_active = ted7360->timer3_active = 0; |
1462 | | ted7360->cursor1 = 0; |
1463 | | |
1464 | | ted7360->rasterline = 0; |
1465 | | ted7360->lastline = 0; |
1466 | | |
1467 | | ted7360->rastertime = 0.0; |
1468 | | |
1469 | | ted7360->frame_count = 0; |
1470 | | |
1471 | | ted7360->x_begin = 0; |
1472 | | ted7360->x_end = 0; |
1473 | | ted7360->y_begin = 0; |
1474 | | ted7360->y_end = 0; |
1475 | | |
1476 | | memset(ted7360->c16_bitmap, 0, ARRAY_LENGTH(ted7360->c16_bitmap)); |
1477 | | memset(ted7360->bitmapmulti, 0, ARRAY_LENGTH(ted7360->bitmapmulti)); |
1478 | | memset(ted7360->mono, 0, ARRAY_LENGTH(ted7360->mono)); |
1479 | | memset(ted7360->monoinversed, 0, ARRAY_LENGTH(ted7360->monoinversed)); |
1480 | | memset(ted7360->multi, 0, ARRAY_LENGTH(ted7360->multi)); |
1481 | | memset(ted7360->ecmcolor, 0, ARRAY_LENGTH(ted7360->ecmcolor)); |
1482 | | memset(ted7360->colors, 0, ARRAY_LENGTH(ted7360->colors)); |
1483 | | |
1484 | | ted7360->tone1pos = 0; |
1485 | | ted7360->tone2pos = 0; |
1486 | | ted7360->tone1samples = 1; |
1487 | | ted7360->tone2samples = 1; |
1488 | | ted7360->noisepos = 0; |
1489 | | ted7360->noisesamples = 1; |
1490 | | } |
1491 | | |
1492 | | |
1493 | | /*------------------------------------------------- |
1494 | | device definition |
1495 | | -------------------------------------------------*/ |
1496 | | |
1497 | | static const char DEVTEMPLATE_SOURCE[] = __FILE__; |
1498 | | |
1499 | | #define DEVTEMPLATE_ID(p,s) p##ted7360##s |
1500 | | #define DEVTEMPLATE_FEATURES DT_HAS_START | DT_HAS_RESET |
1501 | | #define DEVTEMPLATE_NAME "CBM TED 7360" |
1502 | | #define DEVTEMPLATE_FAMILY "CBM Text Display Video Chip" |
1503 | | #include "devtempl.h" |
1504 | | |
1505 | | DEFINE_LEGACY_SOUND_DEVICE(TED7360, ted7360); |
trunk/src/mess/machine/c16.c
r17575 | r17576 | |
1 | | /*************************************************************************** |
2 | | |
3 | | commodore c16 home computer |
4 | | |
5 | | peter.trauner@jk.uni-linz.ac.at |
6 | | documentation |
7 | | www.funet.fi |
8 | | |
9 | | ***************************************************************************/ |
10 | | |
11 | | #include "emu.h" |
12 | | #include "audio/ted7360.h" |
13 | | #include "cpu/m6502/m6502.h" |
14 | | #include "imagedev/cassette.h" |
15 | | #include "imagedev/cartslot.h" |
16 | | #include "machine/ram.h" |
17 | | #include "includes/c16.h" |
18 | | #include "machine/cbmiec.h" |
19 | | #include "sound/sid6581.h" |
20 | | |
21 | | #define VERBOSE_LEVEL 0 |
22 | | #define DBG_LOG( MACHINE, N, M, A ) \ |
23 | | do { \ |
24 | | if(VERBOSE_LEVEL >= N) \ |
25 | | { \ |
26 | | if( M ) \ |
27 | | logerror("%11.6f: %-24s", MACHINE.time().as_double(), (char*) M ); \ |
28 | | logerror A; \ |
29 | | } \ |
30 | | } while (0) |
31 | | |
32 | | |
33 | | /* |
34 | | * tia6523 |
35 | | * |
36 | | * connector to floppy c1551 (delivered with c1551 as c16 expansion) |
37 | | * port a for data read/write |
38 | | * port b |
39 | | * 0 status 0 |
40 | | * 1 status 1 |
41 | | * port c |
42 | | * 6 dav output edge data on port a available |
43 | | * 7 ack input edge ready for next datum |
44 | | */ |
45 | | |
46 | | /* |
47 | | ddr bit 1 port line is output |
48 | | port bit 1 port line is high |
49 | | |
50 | | serial bus |
51 | | 1 serial srq in (ignored) |
52 | | 2 gnd |
53 | | 3 atn out (pull up) |
54 | | 4 clock in/out (pull up) |
55 | | 5 data in/out (pull up) |
56 | | 6 /reset (pull up) hardware |
57 | | |
58 | | |
59 | | p0 negated serial bus pin 5 /data out |
60 | | p1 negated serial bus pin 4 /clock out, cassette write |
61 | | p2 negated serial bus pin 3 /atn out |
62 | | p3 cassette motor out |
63 | | |
64 | | p4 cassette read |
65 | | p5 not connected (or not available on MOS7501?) |
66 | | p6 serial clock in |
67 | | p7 serial data in, serial bus 5 |
68 | | */ |
69 | | |
70 | | WRITE8_DEVICE_HANDLER(c16_m7501_port_write) |
71 | | { |
72 | | c16_state *state = device->machine().driver_data<c16_state>(); |
73 | | |
74 | | /* bit zero then output 0 */ |
75 | | state->m_iec->atn_w(!BIT(data, 2)); |
76 | | state->m_iec->clk_w(!BIT(data, 1)); |
77 | | state->m_iec->data_w(!BIT(data, 0)); |
78 | | |
79 | | state->m_cassette->output(!BIT(data, 1) ? -(0x5a9e >> 1) : +(0x5a9e >> 1)); |
80 | | |
81 | | state->m_cassette->change_state(BIT(data, 7) ? CASSETTE_MOTOR_DISABLED : CASSETTE_MOTOR_ENABLED, CASSETTE_MASK_MOTOR); |
82 | | } |
83 | | |
84 | | READ8_DEVICE_HANDLER(c16_m7501_port_read) |
85 | | { |
86 | | c16_state *state = device->machine().driver_data<c16_state>(); |
87 | | UINT8 data = 0xff; |
88 | | UINT8 c16_port7501 = m6510_get_port(state->m_maincpu); |
89 | | |
90 | | if (BIT(c16_port7501, 0) || !state->m_iec->data_r()) |
91 | | data &= ~0x80; |
92 | | |
93 | | if (BIT(c16_port7501, 1) || !state->m_iec->clk_r()) |
94 | | data &= ~0x40; |
95 | | |
96 | | // data &= ~0x20; // port bit not in pinout |
97 | | |
98 | | if (state->m_cassette->input() > +0.0) |
99 | | data |= 0x10; |
100 | | else |
101 | | data &= ~0x10; |
102 | | |
103 | | return data; |
104 | | } |
105 | | |
106 | | static void c16_bankswitch( running_machine &machine ) |
107 | | { |
108 | | c16_state *state = machine.driver_data<c16_state>(); |
109 | | UINT8 *rom = state->memregion("maincpu")->base(); |
110 | | state->membank("bank9")->set_base(state->m_messram->pointer()); |
111 | | |
112 | | switch (state->m_lowrom) |
113 | | { |
114 | | case 0: |
115 | | state->membank("bank2")->set_base(rom + 0x10000); |
116 | | break; |
117 | | case 1: |
118 | | state->membank("bank2")->set_base(rom + 0x18000); |
119 | | break; |
120 | | case 2: |
121 | | state->membank("bank2")->set_base(rom + 0x20000); |
122 | | break; |
123 | | case 3: |
124 | | state->membank("bank2")->set_base(rom + 0x28000); |
125 | | break; |
126 | | } |
127 | | |
128 | | switch (state->m_highrom) |
129 | | { |
130 | | case 0: |
131 | | state->membank("bank3")->set_base(rom + 0x14000); |
132 | | state->membank("bank8")->set_base(rom + 0x17f20); |
133 | | break; |
134 | | case 1: |
135 | | state->membank("bank3")->set_base(rom + 0x1c000); |
136 | | state->membank("bank8")->set_base(rom + 0x1ff20); |
137 | | break; |
138 | | case 2: |
139 | | state->membank("bank3")->set_base(rom + 0x24000); |
140 | | state->membank("bank8")->set_base(rom + 0x27f20); |
141 | | break; |
142 | | case 3: |
143 | | state->membank("bank3")->set_base(rom + 0x2c000); |
144 | | state->membank("bank8")->set_base(rom + 0x2ff20); |
145 | | break; |
146 | | } |
147 | | state->membank("bank4")->set_base(rom + 0x17c00); |
148 | | } |
149 | | |
150 | | WRITE8_HANDLER( c16_switch_to_rom ) |
151 | | { |
152 | | c16_state *state = space->machine().driver_data<c16_state>(); |
153 | | |
154 | | ted7360_rom_switch_w(state->m_ted7360, 1); |
155 | | c16_bankswitch(space->machine()); |
156 | | } |
157 | | |
158 | | /* write access to fddX load data flipflop |
159 | | * and selects roms |
160 | | * a0 a1 |
161 | | * 0 0 basic |
162 | | * 0 1 plus4 low |
163 | | * 1 0 c1 low |
164 | | * 1 1 c2 low |
165 | | * |
166 | | * a2 a3 |
167 | | * 0 0 kernal |
168 | | * 0 1 plus4 hi |
169 | | * 1 0 c1 high |
170 | | * 1 1 c2 high */ |
171 | | WRITE8_HANDLER( c16_select_roms ) |
172 | | { |
173 | | c16_state *state = space->machine().driver_data<c16_state>(); |
174 | | |
175 | | state->m_lowrom = offset & 0x03; |
176 | | state->m_highrom = (offset & 0x0c) >> 2; |
177 | | if (ted7360_rom_switch_r(state->m_ted7360)) |
178 | | c16_bankswitch(space->machine()); |
179 | | } |
180 | | |
181 | | WRITE8_HANDLER( c16_switch_to_ram ) |
182 | | { |
183 | | c16_state *state = space->machine().driver_data<c16_state>(); |
184 | | UINT8 *ram = state->m_messram->pointer(); |
185 | | UINT32 ram_size = state->m_messram->size(); |
186 | | |
187 | | ted7360_rom_switch_w(state->m_ted7360, 0); |
188 | | |
189 | | state->membank("bank2")->set_base(ram + (0x8000 % ram_size)); |
190 | | state->membank("bank3")->set_base(ram + (0xc000 % ram_size)); |
191 | | state->membank("bank4")->set_base(ram + (0xfc00 % ram_size)); |
192 | | state->membank("bank8")->set_base(ram + (0xff20 % ram_size)); |
193 | | } |
194 | | |
195 | | UINT8 c16_read_keyboard( running_machine &machine, int databus ) |
196 | | { |
197 | | c16_state *state = machine.driver_data<c16_state>(); |
198 | | UINT8 value = 0xff; |
199 | | int i; |
200 | | |
201 | | for (i = 0; i < 8; i++) |
202 | | { |
203 | | if (!BIT(state->m_port6529, i)) |
204 | | value &= state->m_keyline[i]; |
205 | | } |
206 | | |
207 | | /* looks like joy 0 needs dataline2 low |
208 | | * and joy 1 needs dataline1 low |
209 | | * write to 0xff08 (value on databus) reloads latches */ |
210 | | if (!BIT(databus, 2)) |
211 | | value &= state->m_keyline[8]; |
212 | | |
213 | | if (!BIT(databus, 1)) |
214 | | value &= state->m_keyline[9]; |
215 | | |
216 | | return value; |
217 | | } |
218 | | |
219 | | /* |
220 | | * mos 6529 |
221 | | * simple 1 port 8bit input output |
222 | | * output with pull up resistors, 0 means low |
223 | | * input, 0 means low |
224 | | */ |
225 | | /* |
226 | | * ic used as output, |
227 | | * output low means keyboard line selected |
228 | | * keyboard line is then read into the ted7360 latch |
229 | | */ |
230 | | WRITE8_HANDLER( c16_6529_port_w ) |
231 | | { |
232 | | c16_state *state = space->machine().driver_data<c16_state>(); |
233 | | state->m_port6529 = data; |
234 | | } |
235 | | |
236 | | READ8_HANDLER( c16_6529_port_r ) |
237 | | { |
238 | | c16_state *state = space->machine().driver_data<c16_state>(); |
239 | | return state->m_port6529 & (c16_read_keyboard (space->machine(), 0xff /*databus */ ) | (state->m_port6529 ^ 0xff)); |
240 | | } |
241 | | |
242 | | /* |
243 | | * p0 Userport b |
244 | | * p1 Userport k |
245 | | * p2 Userport 4, cassette sense |
246 | | * p3 Userport 5 |
247 | | * p4 Userport 6 |
248 | | * p5 Userport 7 |
249 | | * p6 Userport j |
250 | | * p7 Userport f |
251 | | */ |
252 | | WRITE8_HANDLER( plus4_6529_port_w ) |
253 | | { |
254 | | } |
255 | | |
256 | | READ8_HANDLER( plus4_6529_port_r ) |
257 | | { |
258 | | c16_state *state = space->machine().driver_data<c16_state>(); |
259 | | int data = 0x00; |
260 | | |
261 | | if ((state->m_cassette->get_state() & CASSETTE_MASK_UISTATE) != CASSETTE_STOPPED) |
262 | | data &= ~0x04; |
263 | | else |
264 | | data |= 0x04; |
265 | | |
266 | | return data; |
267 | | } |
268 | | |
269 | | READ8_HANDLER( c16_fd1x_r ) |
270 | | { |
271 | | c16_state *state = space->machine().driver_data<c16_state>(); |
272 | | int data = 0x00; |
273 | | |
274 | | if ((state->m_cassette->get_state() & CASSETTE_MASK_UISTATE) != CASSETTE_STOPPED) |
275 | | data &= ~0x04; |
276 | | else |
277 | | data |= 0x04; |
278 | | |
279 | | return data; |
280 | | } |
281 | | |
282 | | /** |
283 | | 0 write: transmit data |
284 | | 0 read: receiver data |
285 | | 1 write: programmed rest (data is dont care) |
286 | | 1 read: status register |
287 | | 2 command register |
288 | | 3 control register |
289 | | control register (offset 3) |
290 | | cleared by hardware reset, not changed by programmed reset |
291 | | 7: 2 stop bits (0 1 stop bit) |
292 | | 6,5: data word length |
293 | | 00 8 bits |
294 | | 01 7 |
295 | | 10 6 |
296 | | 11 5 |
297 | | 4: ?? clock source |
298 | | 0 external receiver clock |
299 | | 1 baud rate generator |
300 | | 3-0: baud rate generator |
301 | | 0000 use external clock |
302 | | 0001 60 |
303 | | 0010 75 |
304 | | 0011 |
305 | | 0100 |
306 | | 0101 |
307 | | 0110 300 |
308 | | 0111 600 |
309 | | 1000 1200 |
310 | | 1001 |
311 | | 1010 2400 |
312 | | 1011 3600 |
313 | | 1100 4800 |
314 | | 1101 7200 |
315 | | 1110 9600 |
316 | | 1111 19200 |
317 | | control register |
318 | | */ |
319 | | WRITE8_HANDLER( c16_6551_port_w ) |
320 | | { |
321 | | c16_state *state = space->machine().driver_data<c16_state>(); |
322 | | |
323 | | offset &= 0x03; |
324 | | DBG_LOG(space->machine(), 3, "6551", ("port write %.2x %.2x\n", offset, data)); |
325 | | state->m_port6529 = data; |
326 | | } |
327 | | |
328 | | READ8_HANDLER( c16_6551_port_r ) |
329 | | { |
330 | | int data = 0x00; |
331 | | |
332 | | offset &= 0x03; |
333 | | DBG_LOG(space->machine(), 3, "6551", ("port read %.2x %.2x\n", offset, data)); |
334 | | return data; |
335 | | } |
336 | | |
337 | | int c16_dma_read( running_machine &machine, int offset ) |
338 | | { |
339 | | c16_state *state = machine.driver_data<c16_state>(); |
340 | | return state->m_messram->pointer()[offset % state->m_messram->size()]; |
341 | | } |
342 | | |
343 | | int c16_dma_read_rom( running_machine &machine, int offset ) |
344 | | { |
345 | | c16_state *state = machine.driver_data<c16_state>(); |
346 | | |
347 | | /* should read real c16 system bus from 0xfd00 -ff1f */ |
348 | | if (offset >= 0xc000) |
349 | | { /* rom address in rom */ |
350 | | if ((offset >= 0xfc00) && (offset < 0xfd00)) |
351 | | return state->m_mem10000[offset]; |
352 | | |
353 | | switch (state->m_highrom) |
354 | | { |
355 | | case 0: |
356 | | return state->m_mem10000[offset & 0x7fff]; |
357 | | case 1: |
358 | | return state->m_mem18000[offset & 0x7fff]; |
359 | | case 2: |
360 | | return state->m_mem20000[offset & 0x7fff]; |
361 | | case 3: |
362 | | return state->m_mem28000[offset & 0x7fff]; |
363 | | } |
364 | | } |
365 | | |
366 | | if (offset >= 0x8000) |
367 | | { /* rom address in rom */ |
368 | | switch (state->m_lowrom) |
369 | | { |
370 | | case 0: |
371 | | return state->m_mem10000[offset & 0x7fff]; |
372 | | case 1: |
373 | | return state->m_mem18000[offset & 0x7fff]; |
374 | | case 2: |
375 | | return state->m_mem20000[offset & 0x7fff]; |
376 | | case 3: |
377 | | return state->m_mem28000[offset & 0x7fff]; |
378 | | } |
379 | | } |
380 | | |
381 | | return state->m_messram->pointer()[offset % state->m_messram->size()]; |
382 | | } |
383 | | |
384 | | void c16_interrupt( running_machine &machine, int level ) |
385 | | { |
386 | | c16_state *state = machine.driver_data<c16_state>(); |
387 | | |
388 | | if (level != state->m_old_level) |
389 | | { |
390 | | DBG_LOG(machine, 3, "mos7501", ("irq %s\n", level ? "start" : "end")); |
391 | | device_set_input_line(state->m_maincpu, M6510_IRQ_LINE, level); |
392 | | state->m_old_level = level; |
393 | | } |
394 | | } |
395 | | |
396 | | static void c16_common_driver_init( running_machine &machine ) |
397 | | { |
398 | | c16_state *state = machine.driver_data<c16_state>(); |
399 | | UINT8 *rom = state->memregion("maincpu")->base(); |
400 | | |
401 | | /* initial bankswitch (notice that TED7360 is init to ROM) */ |
402 | | state->membank("bank2")->set_base(rom + 0x10000); |
403 | | state->membank("bank3")->set_base(rom + 0x14000); |
404 | | state->membank("bank4")->set_base(rom + 0x17c00); |
405 | | state->membank("bank8")->set_base(rom + 0x17f20); |
406 | | |
407 | | state->m_mem10000 = rom + 0x10000; |
408 | | state->m_mem14000 = rom + 0x14000; |
409 | | state->m_mem18000 = rom + 0x18000; |
410 | | state->m_mem1c000 = rom + 0x1c000; |
411 | | state->m_mem20000 = rom + 0x20000; |
412 | | state->m_mem24000 = rom + 0x24000; |
413 | | state->m_mem28000 = rom + 0x28000; |
414 | | state->m_mem2c000 = rom + 0x2c000; |
415 | | } |
416 | | |
417 | | DRIVER_INIT_MEMBER(c16_state,c16) |
418 | | { |
419 | | c16_common_driver_init(machine()); |
420 | | |
421 | | m_sidcard = 0; |
422 | | m_pal = 1; |
423 | | } |
424 | | |
425 | | DRIVER_INIT_MEMBER(c16_state,plus4) |
426 | | { |
427 | | c16_common_driver_init(machine()); |
428 | | |
429 | | m_sidcard = 0; |
430 | | m_pal = 0; |
431 | | } |
432 | | |
433 | | DRIVER_INIT_MEMBER(c16_state,c16sid) |
434 | | { |
435 | | c16_common_driver_init(machine()); |
436 | | |
437 | | m_sidcard = 1; |
438 | | m_pal = 1; |
439 | | } |
440 | | |
441 | | DRIVER_INIT_MEMBER(c16_state,plus4sid) |
442 | | { |
443 | | c16_common_driver_init(machine()); |
444 | | |
445 | | m_sidcard = 1; |
446 | | m_pal = 0; |
447 | | } |
448 | | |
449 | | MACHINE_RESET( c16 ) |
450 | | { |
451 | | address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM); |
452 | | c16_state *state = machine.driver_data<c16_state>(); |
453 | | UINT8 *ram = state->m_messram->pointer(); |
454 | | UINT32 ram_size = state->m_messram->size(); |
455 | | |
456 | | memset(state->m_keyline, 0xff, ARRAY_LENGTH(state->m_keyline)); |
457 | | |
458 | | state->m_lowrom = 0; |
459 | | state->m_highrom = 0; |
460 | | state->m_old_level = 0; |
461 | | state->m_port6529 = 0; |
462 | | |
463 | | if (state->m_pal) |
464 | | { |
465 | | state->membank("bank1")->set_base(ram + (0x4000 % ram_size)); |
466 | | |
467 | | state->membank("bank5")->set_base(ram + (0x4000 % ram_size)); |
468 | | state->membank("bank6")->set_base(ram + (0x8000 % ram_size)); |
469 | | state->membank("bank7")->set_base(ram + (0xc000 % ram_size)); |
470 | | |
471 | | space->install_write_bank(0xff20, 0xff3d,"bank10"); |
472 | | space->install_write_bank(0xff40, 0xffff, "bank11"); |
473 | | state->membank("bank10")->set_base(ram + (0xff20 % ram_size)); |
474 | | state->membank("bank11")->set_base(ram + (0xff40 % ram_size)); |
475 | | } |
476 | | else |
477 | | { |
478 | | space->install_write_bank(0x4000, 0xfcff, "bank10"); |
479 | | state->membank("bank10")->set_base(ram + (0x4000 % ram_size)); |
480 | | } |
481 | | } |
482 | | |
483 | | #if 0 |
484 | | // FIXME |
485 | | // in very old MESS versions, we had these handlers to enable SID writes to 0xd400. |
486 | | // would a real SID Card allow for this? If not, this should be removed completely |
487 | | static WRITE8_HANDLER( c16_sidcart_16k ) |
488 | | { |
489 | | c16_state *state = space->machine().driver_data<c16_state>(); |
490 | | UINT8 *ram = state->m_messram->pointer(); |
491 | | |
492 | | ram[0x1400 + offset] = data; |
493 | | ram[0x5400 + offset] = data; |
494 | | ram[0x9400 + offset] = data; |
495 | | ram[0xd400 + offset] = data; |
496 | | |
497 | | sid6581_w(state->m_sid, offset, data); |
498 | | } |
499 | | |
500 | | static WRITE8_HANDLER( c16_sidcart_64k ) |
501 | | { |
502 | | c16_state *state = space->machine().driver_data<c16_state>(); |
503 | | |
504 | | state->m_messram->pointer()[0xd400 + offset] = data; |
505 | | |
506 | | sid6581_w(state->m_sid, offset, data); |
507 | | } |
508 | | |
509 | | static TIMER_CALLBACK( c16_sidhack_tick ) |
510 | | { |
511 | | address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM); |
512 | | c16_state *state = space->machine().driver_data<c16_state>(); |
513 | | |
514 | | if (machine.root_device().ioport("SID")->read_safe(0x00) & 0x02) |
515 | | { |
516 | | if (state->m_pal) |
517 | | space->install_legacy_write_handler(0xd400, 0xd41f, FUNC(c16_sidcart_16k)); |
518 | | else |
519 | | space->install_legacy_write_handler(0xd400, 0xd41f, FUNC(c16_sidcart_64k)); |
520 | | } |
521 | | else |
522 | | { |
523 | | space->unmap_write(0xd400, 0xd41f); |
524 | | } |
525 | | } |
526 | | #endif |
527 | | |
528 | | static TIMER_CALLBACK( c16_sidcard_tick ) |
529 | | { |
530 | | c16_state *state = machine.driver_data<c16_state>(); |
531 | | address_space *space = state->m_maincpu->memory().space(AS_PROGRAM); |
532 | | |
533 | | if (machine.root_device().ioport("SID")->read_safe(0x00) & 0x01) |
534 | | space->install_legacy_readwrite_handler(*state->m_sid, 0xfe80, 0xfe9f, FUNC(sid6581_r), FUNC(sid6581_w)); |
535 | | else |
536 | | space->install_legacy_readwrite_handler(*state->m_sid, 0xfd40, 0xfd5f, FUNC(sid6581_r), FUNC(sid6581_w)); |
537 | | } |
538 | | |
539 | | INTERRUPT_GEN( c16_frame_interrupt ) |
540 | | { |
541 | | c16_state *state = device->machine().driver_data<c16_state>(); |
542 | | int value, i; |
543 | | static const char *const c16ports[] = { "ROW0", "ROW1", "ROW2", "ROW3", "ROW4", "ROW5", "ROW6", "ROW7" }; |
544 | | |
545 | | /* Lines 0-7 : common keyboard */ |
546 | | for (i = 0; i < 8; i++) |
547 | | { |
548 | | value = 0xff; |
549 | | value &= ~device->machine().root_device().ioport(c16ports[i])->read(); |
550 | | |
551 | | /* Shift Lock is mapped on Left/Right Shift */ |
552 | | if ((i == 1) && (device->machine().root_device().ioport("SPECIAL")->read() & 0x80)) |
553 | | value &= ~0x80; |
554 | | |
555 | | state->m_keyline[i] = value; |
556 | | } |
557 | | |
558 | | if (device->machine().root_device().ioport("CTRLSEL")->read() & 0x01) |
559 | | { |
560 | | value = 0xff; |
561 | | if (device->machine().root_device().ioport("JOY0")->read() & 0x10) /* Joypad1_Button */ |
562 | | { |
563 | | if (device->machine().root_device().ioport("SPECIAL")->read() & 0x40) |
564 | | value &= ~0x80; |
565 | | else |
566 | | value &= ~0x40; |
567 | | } |
568 | | |
569 | | value &= ~(device->machine().root_device().ioport("JOY0")->read() & 0x0f); /* Other Inputs Joypad1 */ |
570 | | |
571 | | if (device->machine().root_device().ioport("SPECIAL")->read() & 0x40) |
572 | | state->m_keyline[9] = value; |
573 | | else |
574 | | state->m_keyline[8] = value; |
575 | | } |
576 | | |
577 | | if (device->machine().root_device().ioport("CTRLSEL")->read() & 0x10) |
578 | | { |
579 | | value = 0xff; |
580 | | if (device->machine().root_device().ioport("JOY1")->read() & 0x10) /* Joypad2_Button */ |
581 | | { |
582 | | if (device->machine().root_device().ioport("SPECIAL")->read() & 0x40) |
583 | | value &= ~0x40; |
584 | | else |
585 | | value &= ~0x80; |
586 | | } |
587 | | |
588 | | value &= ~(device->machine().root_device().ioport("JOY1")->read() & 0x0f); /* Other Inputs Joypad2 */ |
589 | | |
590 | | if (device->machine().root_device().ioport("SPECIAL")->read() & 0x40) |
591 | | state->m_keyline[8] = value; |
592 | | else |
593 | | state->m_keyline[9] = value; |
594 | | } |
595 | | |
596 | | ted7360_frame_interrupt_gen(state->m_ted7360); |
597 | | |
598 | | if (state->m_sidcard) |
599 | | { |
600 | | /* if we are emulating the SID card, check which memory area should be accessed */ |
601 | | device->machine().scheduler().timer_set(attotime::zero, FUNC(c16_sidcard_tick)); |
602 | | #if 0 |
603 | | /* if we are emulating the SID card, check if writes to 0xd400 have been enabled */ |
604 | | device->machine().scheduler().timer_set(attotime::zero, FUNC(c16_sidhack_tick)); |
605 | | #endif |
606 | | } |
607 | | |
608 | | set_led_status(device->machine(), 1, device->machine().root_device().ioport("SPECIAL")->read() & 0x80 ? 1 : 0); /* Shift Lock */ |
609 | | set_led_status(device->machine(), 0, device->machine().root_device().ioport("SPECIAL")->read() & 0x40 ? 1 : 0); /* Joystick Swap */ |
610 | | } |
611 | | |
612 | | |
613 | | /*********************************************** |
614 | | |
615 | | C16 Cartridges |
616 | | |
617 | | ***********************************************/ |
618 | | |
619 | | static void plus4_software_list_cartridge_load(device_image_interface &image) |
620 | | { |
621 | | UINT8 *mem = image.device().machine().root_device().memregion("maincpu")->base(); |
622 | | |
623 | | size_t size = image.get_software_region_length("c1l"); |
624 | | if (size) |
625 | | memcpy(mem + 0x20000, image.get_software_region("c1l"), size); |
626 | | |
627 | | size = image.get_software_region_length("c1h"); |
628 | | if (size) |
629 | | memcpy(mem + 0x24000, image.get_software_region("c1h"), size); |
630 | | |
631 | | size = image.get_software_region_length("c2l"); |
632 | | if (size) |
633 | | memcpy(mem + 0x28000, image.get_software_region("c2l"), size); |
634 | | |
635 | | size = image.get_software_region_length("c2h"); |
636 | | if (size) |
637 | | memcpy(mem + 0x2c000, image.get_software_region("c2h"), size); |
638 | | } |
639 | | |
640 | | static int plus4_crt_load( device_image_interface &image ) |
641 | | { |
642 | | UINT8 *mem = image.device().machine().root_device().memregion("maincpu")->base(); |
643 | | int size = image.length(), test; |
644 | | const char *filetype; |
645 | | int address = 0; |
646 | | |
647 | | /* magic lowrom at offset 7: $43 $42 $4d */ |
648 | | /* if at offset 6 stands 1 it will immediatly jumped to offset 0 (0x8000) */ |
649 | | static const unsigned char magic[] = {0x43, 0x42, 0x4d}; |
650 | | unsigned char buffer[sizeof (magic)]; |
651 | | |
652 | | image.fseek(7, SEEK_SET); |
653 | | image.fread( buffer, sizeof (magic)); |
654 | | image.fseek(0, SEEK_SET); |
655 | | |
656 | | /* Check if our cart has the magic string, and set its loading address */ |
657 | | if (!memcmp(buffer, magic, sizeof (magic))) |
658 | | address = 0x20000; |
659 | | |
660 | | /* Give a loading address to non .bin / non .rom carts as well */ |
661 | | filetype = image.filetype(); |
662 | | |
663 | | /* We would support .hi and .lo files, but currently I'm not sure where to load them. |
664 | | We simply load them at 0x20000 at this stage, even if it's probably wrong! |
665 | | It could also well be that they both need to be loaded at the same time, but this |
666 | | is now impossible since I reduced to 1 the number of cart slots. |
667 | | More investigations are in order if any .hi, .lo dump would surface! */ |
668 | | if (!mame_stricmp(filetype, "hi")) |
669 | | address = 0x20000; /* FIX ME! */ |
670 | | |
671 | | else if (!mame_stricmp(filetype, "lo")) |
672 | | address = 0x20000; /* FIX ME! */ |
673 | | |
674 | | /* As a last try, give a reasonable loading address also to .bin/.rom without the magic string */ |
675 | | else if (!address) |
676 | | { |
677 | | logerror("Cart %s does not contain the magic string: it may be loaded at the wrong memory address!\n", image.filename()); |
678 | | address = 0x20000; |
679 | | } |
680 | | |
681 | | logerror("Loading cart %s at %.5x size:%.4x\n", image.filename(), address, size); |
682 | | |
683 | | /* Finally load the cart */ |
684 | | test = image.fread( mem + address, size); |
685 | | |
686 | | if (test != size) |
687 | | return IMAGE_INIT_FAIL; |
688 | | |
689 | | return IMAGE_INIT_PASS; |
690 | | } |
691 | | |
692 | | static DEVICE_IMAGE_LOAD( c16_cart ) |
693 | | { |
694 | | int result = IMAGE_INIT_PASS; |
695 | | |
696 | | if (image.software_entry() != NULL) |
697 | | { |
698 | | plus4_software_list_cartridge_load(image); |
699 | | } |
700 | | else |
701 | | { |
702 | | result = plus4_crt_load(image); |
703 | | } |
704 | | |
705 | | return result; |
706 | | } |
707 | | |
708 | | MACHINE_CONFIG_FRAGMENT( c16_cartslot ) |
709 | | MCFG_CARTSLOT_ADD("cart") |
710 | | MCFG_CARTSLOT_EXTENSION_LIST("bin,rom,hi,lo") |
711 | | MCFG_CARTSLOT_NOT_MANDATORY |
712 | | MCFG_CARTSLOT_INTERFACE("plus4_cart") |
713 | | MCFG_CARTSLOT_LOAD(c16_cart) |
714 | | MCFG_SOFTWARE_LIST_ADD("cart_list", "plus4_cart") |
715 | | MACHINE_CONFIG_END |
trunk/src/mess/machine/ti85_ser.c
r17575 | r17576 | |
1 | | |
2 | | #include "emu.h" |
3 | | #include "emuopts.h" |
4 | | #include "ti85_ser.h" |
5 | | |
6 | | enum |
7 | | { |
8 | | TI85_SEND_STOP, |
9 | | TI85_SEND_HEADER, |
10 | | TI85_RECEIVE_OK_1, |
11 | | TI85_RECEIVE_ANSWER_1, |
12 | | TI85_RECEIVE_ANSWER_2, |
13 | | TI85_RECEIVE_ANSWER_3, |
14 | | TI85_SEND_OK, |
15 | | TI85_SEND_DATA, |
16 | | TI85_RECEIVE_OK_2, |
17 | | TI85_SEND_END, |
18 | | TI85_RECEIVE_OK_3, |
19 | | TI85_RECEIVE_HEADER_1, |
20 | | TI85_PREPARE_VARIABLE_DATA, |
21 | | TI85_RECEIVE_HEADER_2, |
22 | | TI85_SEND_OK_1, |
23 | | TI85_SEND_CONTINUE, |
24 | | TI85_RECEIVE_OK, |
25 | | TI85_RECEIVE_DATA, |
26 | | TI85_SEND_OK_2, |
27 | | TI85_RECEIVE_END_OR_HEADER_1, |
28 | | TI85_SEND_OK_3, |
29 | | TI85_PREPARE_SCREEN_REQUEST, |
30 | | TI85_SEND_SCREEN_REQUEST |
31 | | }; |
32 | | |
33 | | //supported image formats |
34 | | enum |
35 | | { |
36 | | TI_FILE_UNK, |
37 | | TI_FILE_V1, //used for TI-85 and TI-86 image |
38 | | TI_FILE_V2, //used for TI-82, TI-83 and TI-73 image |
39 | | TI_FILE_V3 //used for TI-83+ and TI-84+ image |
40 | | }; |
41 | | |
42 | | #define TI85_HEADER_SIZE 0x37 |
43 | | |
44 | | #define TI85_SEND_VARIABLES 1 |
45 | | #define TI85_SEND_BACKUP 2 |
46 | | #define TI85_RECEIVE_BACKUP 3 |
47 | | #define TI85_RECEIVE_VARIABLES 4 |
48 | | #define TI85_RECEIVE_SCREEN 5 |
49 | | |
50 | | #define TI85_PC_OK_PACKET_SIZE 4 |
51 | | #define TI85_PC_END_PACKET_SIZE 4 |
52 | | |
53 | | #define TI82_BACKUP_ID 0x0f //used by the TI-82 |
54 | | #define TI85_BACKUP_ID 0x1d //used by the TI-85 and TI-86 |
55 | | #define TI83_BACKUP_ID 0x13 //used by the TI-73, TI-83 and TI-83+ |
56 | | |
57 | | //known tranfer ID |
58 | | #define TI_TRANFER_ID_TI73 0x07 |
59 | | #define TI_TRANFER_ID_TI82 0x02 |
60 | | #define TI_TRANFER_ID_TI83 0x03 |
61 | | #define TI_TRANFER_ID_TI83P 0x23 |
62 | | #define TI_TRANFER_ID_TI85 0x05 |
63 | | #define TI_TRANFER_ID_TI86 0x06 |
64 | | |
65 | | //packet type |
66 | | #define TI_OK_PACKET 0x56 |
67 | | #define TI_CONTINUE_PACKET 0x09 |
68 | | #define TI_SCREEN_REQUEST_PACKET 0x6d |
69 | | #define TI_END_PACKET 0x92 |
70 | | |
71 | | static const UINT8 ti73_file_signature[] = {0x2a, 0x2a, 0x54, 0x49, 0x37, 0x33, 0x2a, 0x2a, 0x1a, 0x0a, 0x00}; |
72 | | static const UINT8 ti85_file_signature[] = {0x2a, 0x2a, 0x54, 0x49, 0x38, 0x35, 0x2a, 0x2a, 0x1a, 0x0c, 0x00}; |
73 | | static const UINT8 ti82_file_signature[] = {0x2a, 0x2a, 0x54, 0x49, 0x38, 0x32, 0x2a, 0x2a, 0x1a, 0x0a, 0x00}; |
74 | | static const UINT8 ti83_file_signature[] = {0x2a, 0x2a, 0x54, 0x49, 0x38, 0x33, 0x2a, 0x2a, 0x1a, 0x0a, 0x00}; |
75 | | static const UINT8 ti83p_file_signature[]= {0x2a, 0x2a, 0x54, 0x49, 0x38, 0x33, 0x46, 0x2a, 0x1a, 0x0a, 0x00}; |
76 | | static const UINT8 ti86_file_signature[] = {0x2a, 0x2a, 0x54, 0x49, 0x38, 0x36, 0x2a, 0x2a, 0x1a, 0x0a, 0x00}; |
77 | | |
78 | | typedef struct { |
79 | | UINT16 head_size; |
80 | | UINT16 data_size; |
81 | | unsigned char type; |
82 | | unsigned char name_size; |
83 | | unsigned int offset; |
84 | | } ti85_entry; |
85 | | |
86 | | |
87 | | typedef struct { |
88 | | UINT8* header; |
89 | | UINT16 header_size; |
90 | | UINT8* ok; |
91 | | UINT16 ok_size; |
92 | | UINT8* data; |
93 | | UINT32 data_size; |
94 | | } ti85_serial_variable; |
95 | | |
96 | | |
97 | | typedef struct { |
98 | | ti85_serial_variable * variables; |
99 | | UINT8* end; |
100 | | UINT16 end_size; |
101 | | UINT16 number_of_variables; |
102 | | } ti85_serial_data; |
103 | | |
104 | | |
105 | | typedef struct |
106 | | { |
107 | | UINT8 status; |
108 | | int transfer_type; |
109 | | UINT8 image_type; |
110 | | UINT8 send_id; /* ID used for PC to TI transfer */ |
111 | | UINT8 receive_id; /* ID used for TI to PC transfer */ |
112 | | UINT8 red_out; /* signal line from machine */ |
113 | | UINT8 white_out; /* signal line from machine */ |
114 | | UINT8 red_in; /* signal line to machine */ |
115 | | UINT8 white_in; /* signal line to machine */ |
116 | | UINT8 *receive_buffer; |
117 | | UINT8 *receive_data; |
118 | | ti85_serial_data stream; |
119 | | /* receive_data_counter and send_data_counter can be combined? */ |
120 | | UINT32 receive_data_counter; /* from ti85_receive_serial */ |
121 | | UINT32 send_data_counter; /* from ti85_send_serial */ |
122 | | /* variables_variable_number, send_backup_variable_number, and backup_variable_number can be combined? */ |
123 | | UINT16 variables_variable_number; /* from ti85_send_variables */ |
124 | | UINT16 send_backup_variable_number; /* from ti85_send_backup */ |
125 | | int variable_number; /* from ti85_receive_variables */ |
126 | | UINT8 *var_data; /* from ti85_receive_variables */ |
127 | | UINT32 var_file_number; /* from ti85_receive_variables */ |
128 | | UINT8 *var_file_data; /* from ti85_receive_variables */ |
129 | | int var_file_size; /* from ti85_receive_variables */ |
130 | | int backup_variable_number; /* from ti85_receive_backup */ |
131 | | int backup_data_size[3]; /* from ti85_receive_backup */ |
132 | | UINT8 *backup_file_data; /* from ti85_receive_backup */ |
133 | | UINT32 backup_file_number; /* from ti85_receive_backup */ |
134 | | UINT32 image_file_number; /* from ti85_receive_screen */ |
135 | | } ti85serial_state; |
136 | | |
137 | | |
138 | | INLINE ti85serial_state *get_token(device_t *device) |
139 | | { |
140 | | assert(device != NULL); |
141 | | assert((device->type() == TI82SERIAL) || |
142 | | (device->type() == TI73SERIAL) || |
143 | | (device->type() == TI83PSERIAL) || |
144 | | (device->type() == TI85SERIAL) || |
145 | | (device->type() == TI86SERIAL)); |
146 | | return (ti85serial_state *) downcast<legacy_device_base *>(device)->token(); |
147 | | } |
148 | | |
149 | | |
150 | | static UINT16 ti85_calculate_checksum(const UINT8* data, unsigned int size) |
151 | | { |
152 | | UINT16 checksum = 0; |
153 | | unsigned int i; |
154 | | |
155 | | for (i = 0; i<size; i++) |
156 | | checksum += data[i]; |
157 | | return checksum; |
158 | | } |
159 | | |
160 | | |
161 | | static UINT16 ti85_variables_count (const UINT8 * ti85_data, unsigned int ti85_data_size) |
162 | | { |
163 | | unsigned int pos, head_size, var_size; |
164 | | UINT16 number_of_entries = 0; |
165 | | pos = TI85_HEADER_SIZE; |
166 | | while (pos < ti85_data_size-2) |
167 | | { |
168 | | head_size = ti85_data[pos+0x00] + ti85_data[pos+0x01]*256; |
169 | | var_size = ti85_data[pos+0x02] + ti85_data[pos+0x03]*256; |
170 | | pos += head_size+var_size+4; |
171 | | number_of_entries++; |
172 | | } |
173 | | return number_of_entries; |
174 | | } |
175 | | |
176 | | |
177 | | static void ti85_free_serial_data_memory (device_t *device) |
178 | | { |
179 | | ti85serial_state *ti85serial = get_token( device ); |
180 | | |
181 | | if (ti85serial->receive_buffer) |
182 | | { |
183 | | free (ti85serial->receive_buffer); |
184 | | ti85serial->receive_buffer = NULL; |
185 | | } |
186 | | if (ti85serial->receive_data) |
187 | | { |
188 | | free (ti85serial->receive_data); |
189 | | ti85serial->receive_data = NULL; |
190 | | } |
191 | | } |
192 | | |
193 | | |
194 | | static int ti85_alloc_serial_data_memory (device_t *device, UINT32 size) |
195 | | { |
196 | | ti85serial_state *ti85serial = get_token( device ); |
197 | | |
198 | | if (!ti85serial->receive_buffer) |
199 | | { |
200 | | ti85serial->receive_buffer = (UINT8*) malloc (8*size*sizeof(UINT8)); |
201 | | if (!ti85serial->receive_buffer) |
202 | | return 0; |
203 | | } |
204 | | |
205 | | if (!ti85serial->receive_data) |
206 | | { |
207 | | ti85serial->receive_data = (UINT8*) malloc (size * sizeof(UINT8)); |
208 | | if (!ti85serial->receive_data) |
209 | | { |
210 | | free (ti85serial->receive_buffer); |
211 | | ti85serial->receive_buffer = NULL; |
212 | | return 0; |
213 | | } |
214 | | } |
215 | | return 1; |
216 | | } |
217 | | |
218 | | |
219 | | static void ti85_backup_read (const UINT8 * ti85_data, unsigned int ti85_data_size, ti85_entry * ti85_entries) |
220 | | { |
221 | | unsigned int pos = 0x42+2; |
222 | | |
223 | | ti85_entries[0].head_size = 0x09; |
224 | | ti85_entries[0].data_size = ti85_data[0x39] + ti85_data[0x3a]*256; |
225 | | ti85_entries[0].offset = pos; |
226 | | pos += ti85_entries[0].data_size + 2; |
227 | | ti85_entries[1].head_size = 0; |
228 | | ti85_entries[1].data_size = ti85_data[0x3c] + ti85_data[0x3d]*256; |
229 | | ti85_entries[1].offset = pos; |
230 | | pos += ti85_entries[1].data_size + 2; |
231 | | ti85_entries[2].head_size = 0; |
232 | | ti85_entries[2].data_size = ti85_data[0x3e] + ti85_data[0x3f]*256; |
233 | | ti85_entries[2].offset = pos; |
234 | | } |
235 | | |
236 | | |
237 | | static void ti85_variables_read (device_t *device, const UINT8 * ti85_data, unsigned int ti85_data_size, ti85_entry * ti85_entries) |
238 | | { |
239 | | ti85serial_state *ti85serial = get_token( device ); |
240 | | unsigned int pos, i=0; |
241 | | |
242 | | pos = TI85_HEADER_SIZE; |
243 | | while (pos < ti85_data_size-2) |
244 | | { |
245 | | ti85_entries[i].head_size = ti85_data[pos+0x00] + ti85_data[pos+0x01]*256; |
246 | | ti85_entries[i].data_size = ti85_data[pos+0x02] + ti85_data[pos+0x03]*256; |
247 | | ti85_entries[i].type = ti85_data[pos+0x04]; |
248 | | ti85_entries[i].name_size = (ti85serial->image_type != TI_FILE_V1) ? 8 : ti85_data[pos+0x05]; |
249 | | ti85_entries[i].offset = pos; |
250 | | pos += ti85_entries[i].head_size+ti85_entries[i].data_size+4; |
251 | | i++; |
252 | | } |
253 | | } |
254 | | |
255 | | |
256 | | static int ti85_receive_serial (device_t *device, UINT8* received_data, UINT32 received_data_size) |
257 | | { |
258 | | ti85serial_state *ti85serial = get_token( device ); |
259 | | |
260 | | if (ti85serial->receive_data_counter >= received_data_size) |
261 | | { |
262 | | if (!ti85serial->red_out && !ti85serial->white_out) |
263 | | { |
264 | | ti85serial->red_in = ti85serial->white_in = 1; |
265 | | ti85serial->receive_data_counter = 0; |
266 | | return 0; |
267 | | } |
268 | | return 1; |
269 | | } |
270 | | |
271 | | if (ti85serial->red_in && ti85serial->white_in && (ti85serial->red_out!=ti85serial->white_out)) |
272 | | { |
273 | | ti85serial->white_in = ti85serial->white_out; |
274 | | ti85serial->red_in = ti85serial->red_out; |
275 | | received_data[ti85serial->receive_data_counter] = ti85serial->white_out; |
276 | | return 1; |
277 | | } |
278 | | |
279 | | if (ti85serial->red_in!=ti85serial->white_in && !ti85serial->red_out && !ti85serial->white_out) |
280 | | { |
281 | | ti85serial->red_in = ti85serial->white_in = 1; |
282 | | ti85serial->receive_data_counter ++; |
283 | | return 1; |
284 | | } |
285 | | return 1; |
286 | | } |
287 | | |
288 | | |
289 | | static int ti85_send_serial(device_t *device, UINT8* serial_data, UINT32 serial_data_size) |
290 | | { |
291 | | ti85serial_state *ti85serial = get_token( device ); |
292 | | |
293 | | if (ti85serial->send_data_counter>=serial_data_size) |
294 | | { |
295 | | if (!ti85serial->red_out && !ti85serial->white_out) |
296 | | { |
297 | | ti85serial->red_in = ti85serial->white_in = 1; |
298 | | ti85serial->send_data_counter = 0; |
299 | | return 0; |
300 | | } |
301 | | ti85serial->red_in = ti85serial->white_in = 1; |
302 | | return 1; |
303 | | } |
304 | | |
305 | | if (ti85serial->red_in && ti85serial->white_in && !ti85serial->red_out && !ti85serial->white_out) |
306 | | { |
307 | | ti85serial->red_in = serial_data[ti85serial->send_data_counter] ? 1 : 0; |
308 | | ti85serial->white_in = serial_data[ti85serial->send_data_counter] ? 0 : 1; |
309 | | return 1; |
310 | | } |
311 | | |
312 | | if ((ti85serial->red_in == ti85serial->red_out) && (ti85serial->white_in == ti85serial->white_out)) |
313 | | { |
314 | | ti85serial->red_in = ti85serial->white_in = 1; |
315 | | ti85serial->send_data_counter++; |
316 | | return 1; |
317 | | } |
318 | | return 1; |
319 | | } |
320 | | |
321 | | |
322 | | static void ti85_convert_data_to_stream (const UINT8* file_data, unsigned int size, UINT8* serial_data) |
323 | | { |
324 | | unsigned int i, bits; |
325 | | |
326 | | for (i=0; i<size; i++) |
327 | | for (bits = 0; bits < 8; bits++) |
328 | | serial_data[i*8+bits] = (file_data[i]>>bits) & 0x01; |
329 | | } |
330 | | |
331 | | |
332 | | static void ti85_append_head_to_stream (UINT8 transfer_id, UINT8 tranfer_type, UINT8* serial_data) |
333 | | { |
334 | | UINT8 tmp_data[4]; |
335 | | |
336 | | tmp_data[0] = transfer_id; |
337 | | tmp_data[1] = tranfer_type; |
338 | | tmp_data[2] = 0; |
339 | | tmp_data[3] = 0; |
340 | | |
341 | | ti85_convert_data_to_stream(tmp_data, sizeof(tmp_data), serial_data); |
342 | | } |
343 | | |
344 | | |
345 | | static void ti85_convert_stream_to_data (const UINT8* serial_data, UINT32 size, UINT8* data) |
346 | | { |
347 | | UINT32 i; |
348 | | UINT8 bits; |
349 | | |
350 | | size = size/8; |
351 | | |
352 | | for (i=0; i<size; i++) |
353 | | { |
354 | | data[i] = 0; |
355 | | for (bits = 0; bits < 8; bits++) |
356 | | data[i] |= serial_data[i*8+bits]<<bits; |
357 | | } |
358 | | } |
359 | | |
360 | | |
361 | | static int ti85_convert_file_data_to_serial_stream (device_t *device, const UINT8* file_data, unsigned int file_size, ti85_serial_data* serial_data) |
362 | | { |
363 | | ti85serial_state *ti85serial = get_token( device ); |
364 | | UINT16 i; |
365 | | UINT16 number_of_entries; |
366 | | UINT8 backup_id = (ti85serial->image_type == TI_FILE_V1) ? TI85_BACKUP_ID : ((device->type() == TI82SERIAL) ? TI82_BACKUP_ID : TI83_BACKUP_ID); |
367 | | |
368 | | ti85_entry* ti85_entries = NULL; |
369 | | |
370 | | UINT8* temp_data_to_convert = NULL; |
371 | | UINT16 checksum; |
372 | | |
373 | | //verify that the provided file is compatible with the model |
374 | | if (device->type() == TI73SERIAL) |
375 | | if (strncmp((char *) file_data, (char *) ti73_file_signature, 11)) |
376 | | return 0; |
377 | | if (device->type() == TI85SERIAL) |
378 | | if (strncmp((char *) file_data, (char *) ti85_file_signature, 11)) |
379 | | return 0; |
380 | | if (device->type() == TI82SERIAL) |
381 | | if (strncmp((char *) file_data, (char *) ti82_file_signature, 11)) |
382 | | return 0; |
383 | | if (device->type() == TI83PSERIAL) //TI-83+ is compatible with TI-83 and TI-82 file |
384 | | if (strncmp((char *) file_data, (char *) ti83p_file_signature, 10) && strncmp((char *) file_data, (char *) ti83_file_signature, 11) |
385 | | && strncmp((char *) file_data, (char *) ti82_file_signature, 11)) |
386 | | return 0; |
387 | | if (device->type() == TI86SERIAL) //TI-86 is compatible with TI-85 file |
388 | | if (strncmp((char *) file_data, (char *) ti86_file_signature, 11) && strncmp((char *) file_data, (char *) ti85_file_signature, 11)) |
389 | | return 0; |
390 | | |
391 | | //identify the image |
392 | | if (!strncmp((char *) file_data, (char *) ti73_file_signature, 11)) |
393 | | { |
394 | | ti85serial->send_id = TI_TRANFER_ID_TI73; |
395 | | ti85serial->image_type = TI_FILE_V2; |
396 | | } |
397 | | else if (!strncmp((char *) file_data, (char *) ti85_file_signature, 11)) |
398 | | { |
399 | | ti85serial->send_id = TI_TRANFER_ID_TI85; |
400 | | ti85serial->image_type = TI_FILE_V1; |
401 | | } |
402 | | else if (!strncmp((char *) file_data, (char *) ti82_file_signature, 11)) |
403 | | { |
404 | | ti85serial->send_id = TI_TRANFER_ID_TI82; |
405 | | ti85serial->image_type = TI_FILE_V2; |
406 | | } |
407 | | else if (!strncmp((char *) file_data, (char *) ti83_file_signature, 11)) |
408 | | { |
409 | | ti85serial->send_id = TI_TRANFER_ID_TI83; |
410 | | ti85serial->image_type = TI_FILE_V2; |
411 | | } |
412 | | else if (!strncmp((char *) file_data, (char *) ti83p_file_signature, 11)) |
413 | | { |
414 | | ti85serial->send_id = TI_TRANFER_ID_TI83P; |
415 | | ti85serial->image_type = TI_FILE_V3; |
416 | | } |
417 | | else if (!strncmp((char *) file_data, (char *) ti86_file_signature, 11)) |
418 | | { |
419 | | ti85serial->send_id = TI_TRANFER_ID_TI86; |
420 | | ti85serial->image_type = TI_FILE_V1; |
421 | | } |
422 | | |
423 | | logerror("Image ID: 0x%02x, version: 0x%02x\n", ti85serial->send_id, ti85serial->image_type); |
424 | | |
425 | | /*Serial stream preparing*/ |
426 | | serial_data->end = NULL; |
427 | | |
428 | | number_of_entries = (file_data[0x3b]==backup_id) ? 3 : ti85_variables_count(file_data, file_size); |
429 | | if (!number_of_entries) return 0; |
430 | | |
431 | | serial_data->variables = (ti85_serial_variable*)malloc(sizeof(ti85_serial_variable)*number_of_entries); |
432 | | if (!serial_data->variables) return 0; |
433 | | |
434 | | for (i=0; i<number_of_entries; i++) |
435 | | { |
436 | | serial_data->variables[i].header = NULL; |
437 | | serial_data->variables[i].ok = NULL; |
438 | | serial_data->variables[i].data = NULL; |
439 | | } |
440 | | |
441 | | serial_data->number_of_variables = number_of_entries; |
442 | | |
443 | | ti85_entries = (ti85_entry*) malloc (sizeof(ti85_entry)*number_of_entries); |
444 | | if (!ti85_entries) return 0; |
445 | | |
446 | | if (file_data[0x3b]==backup_id) |
447 | | { |
448 | | ti85serial->transfer_type = TI85_SEND_BACKUP; |
449 | | ti85_backup_read (file_data, file_size, ti85_entries); |
450 | | } |
451 | | else |
452 | | { |
453 | | ti85serial->transfer_type = TI85_SEND_VARIABLES; |
454 | | ti85_variables_read (device, file_data, file_size, ti85_entries); |
455 | | } |
456 | | for (i=0; i<number_of_entries; i++) |
457 | | { |
458 | | /*Header packet*/ |
459 | | if (file_data[0x3b]==backup_id) |
460 | | { |
461 | | if (!i) |
462 | | { |
463 | | temp_data_to_convert = (UINT8*) malloc (0x0f); |
464 | | if (!temp_data_to_convert) |
465 | | { |
466 | | free (ti85_entries); |
467 | | return 0; |
468 | | } |
469 | | serial_data->variables[i].header = (UINT8*) malloc (0x0f*8); |
470 | | |
471 | | if (!serial_data->variables[i].header) |
472 | | { |
473 | | free (ti85_entries); |
474 | | free (temp_data_to_convert); |
475 | | return 0; |
476 | | } |
477 | | serial_data->variables[i].header_size = 0x0f*8; |
478 | | temp_data_to_convert[0] = ti85serial->send_id; //PC sends |
479 | | temp_data_to_convert[1] = 0x06; //header |
480 | | memcpy( temp_data_to_convert+0x02, file_data+0x37, 0x0b); |
481 | | checksum = ti85_calculate_checksum(temp_data_to_convert+4, 0x09); |
482 | | temp_data_to_convert[13] = checksum&0x00ff; |
483 | | temp_data_to_convert[14] = (checksum&0xff00)>>8; |
484 | | ti85_convert_data_to_stream(temp_data_to_convert, 0x0f, serial_data->variables[i].header); |
485 | | free(temp_data_to_convert); |
486 | | } |
487 | | else |
488 | | { |
489 | | serial_data->variables[i].header = NULL; |
490 | | serial_data->variables[i].header_size = 0; |
491 | | } |
492 | | } |
493 | | else |
494 | | { |
495 | | temp_data_to_convert = (UINT8*) malloc (10+ti85_entries[i].name_size); |
496 | | if (!temp_data_to_convert) |
497 | | { |
498 | | free (ti85_entries); |
499 | | return 0; |
500 | | } |
501 | | serial_data->variables[i].header = (UINT8*) malloc ((10+ti85_entries[i].name_size)*8); |
502 | | if (!serial_data->variables[i].header) |
503 | | { |
504 | | free (temp_data_to_convert); |
505 | | free (ti85_entries); |
506 | | return 0; |
507 | | } |
508 | | |
509 | | if (ti85serial->image_type == TI_FILE_V1) |
510 | | { |
511 | | serial_data->variables[i].header_size = (10+ti85_entries[i].name_size)*8; |
512 | | |
513 | | temp_data_to_convert[0] = ti85serial->send_id; |
514 | | temp_data_to_convert[1] = 0x06; //header |
515 | | temp_data_to_convert[2] = (4+ti85_entries[i].name_size)&0x00ff; |
516 | | temp_data_to_convert[3] = ((4+ti85_entries[i].name_size)&0xff00)>>8; |
517 | | temp_data_to_convert[4] = (ti85_entries[i].data_size)&0x00ff; |
518 | | temp_data_to_convert[5] = ((ti85_entries[i].data_size)&0xff00)>>8; |
519 | | temp_data_to_convert[6] = ti85_entries[i].type; |
520 | | temp_data_to_convert[7] = ti85_entries[i].name_size; |
521 | | memcpy(temp_data_to_convert+8, file_data+ti85_entries[i].offset+0x06, ti85_entries[i].name_size); |
522 | | checksum = ti85_calculate_checksum(temp_data_to_convert+4,ti85_entries[i].name_size+4); |
523 | | temp_data_to_convert[10+ti85_entries[i].name_size-2] = checksum&0x00ff; |
524 | | temp_data_to_convert[10+ti85_entries[i].name_size-1] = (checksum&0xff00)>>8; |
525 | | ti85_convert_data_to_stream(temp_data_to_convert, 10+ti85_entries[i].name_size, serial_data->variables[i].header); |
526 | | } |
527 | | |
528 | | if (ti85serial->image_type == TI_FILE_V2 || ti85serial->image_type == TI_FILE_V3) |
529 | | { |
530 | | serial_data->variables[i].header_size = (9+ti85_entries[i].name_size)*8; |
531 | | |
532 | | temp_data_to_convert[0] = ti85serial->send_id; |
533 | | temp_data_to_convert[1] = 0x06; //header |
534 | | temp_data_to_convert[2] = (3+ti85_entries[i].name_size)&0x00ff; |
535 | | temp_data_to_convert[3] = ((3+ti85_entries[i].name_size)&0xff00)>>8; |
536 | | temp_data_to_convert[4] = (ti85_entries[i].data_size)&0x00ff; |
537 | | temp_data_to_convert[5] = ((ti85_entries[i].data_size)&0xff00)>>8; |
538 | | temp_data_to_convert[6] = ti85_entries[i].type; |
539 | | memcpy(temp_data_to_convert+7, file_data+ti85_entries[i].offset+0x05, ti85_entries[i].name_size); |
540 | | checksum = ti85_calculate_checksum(temp_data_to_convert+4,ti85_entries[i].name_size+3); |
541 | | temp_data_to_convert[9+ti85_entries[i].name_size-2] = checksum&0x00ff; |
542 | | temp_data_to_convert[9+ti85_entries[i].name_size-1] = (checksum&0xff00)>>8; |
543 | | ti85_convert_data_to_stream(temp_data_to_convert, 9+ti85_entries[i].name_size, serial_data->variables[i].header); |
544 | | } |
545 | | |
546 | | free(temp_data_to_convert); |
547 | | } |
548 | | |
549 | | /*OK packet*/ |
550 | | serial_data->variables[i].ok = (UINT8*) malloc (TI85_PC_OK_PACKET_SIZE*8); |
551 | | if (!serial_data->variables[i].ok) |
552 | | { |
553 | | free (ti85_entries); |
554 | | return 0; |
555 | | } |
556 | | ti85_append_head_to_stream(ti85serial->send_id, TI_OK_PACKET, serial_data->variables[i].ok); |
557 | | serial_data->variables[i].ok_size = TI85_PC_OK_PACKET_SIZE*8; |
558 | | |
559 | | /*Data packet*/ |
560 | | temp_data_to_convert = (UINT8*) malloc (6+ti85_entries[i].data_size); |
561 | | if (!temp_data_to_convert) |
562 | | { |
563 | | free (ti85_entries); |
564 | | return 0; |
565 | | } |
566 | | serial_data->variables[i].data = (UINT8*) malloc ((6+ti85_entries[i].data_size)*8); |
567 | | if (!serial_data->variables[i].data) |
568 | | { |
569 | | free (temp_data_to_convert); |
570 | | free (ti85_entries); |
571 | | return 0; |
572 | | } |
573 | | serial_data->variables[i].data_size = (6+ti85_entries[i].data_size)*8; |
574 | | |
575 | | temp_data_to_convert[0] = ti85serial->send_id; |
576 | | temp_data_to_convert[1] = 0x15; //data |
577 | | temp_data_to_convert[2] = (ti85_entries[i].data_size)&0x00ff; |
578 | | temp_data_to_convert[3] = ((ti85_entries[i].data_size)&0xff00)>>8; |
579 | | |
580 | | UINT8 name_start = (ti85serial->image_type != TI_FILE_V1) ? 5 : 6; |
581 | | |
582 | | //TI-83+ files have two additional byte used for the file's version and flag |
583 | | if (ti85serial->image_type == TI_FILE_V3) |
584 | | name_start += 2; |
585 | | |
586 | | if (file_data[0x3b]==backup_id) |
587 | | memcpy(temp_data_to_convert+4, file_data+ti85_entries[i].offset, ti85_entries[i].data_size); |
588 | | else |
589 | | memcpy(temp_data_to_convert+4, file_data+ti85_entries[i].offset+name_start+ti85_entries[i].name_size+0x02, ti85_entries[i].data_size); |
590 | | |
591 | | checksum = ti85_calculate_checksum(temp_data_to_convert+4,ti85_entries[i].data_size); |
592 | | temp_data_to_convert[6+ti85_entries[i].data_size-2] = checksum&0x00ff; |
593 | | temp_data_to_convert[6+ti85_entries[i].data_size-1] = (checksum&0xff00)>>8; |
594 | | ti85_convert_data_to_stream(temp_data_to_convert, 6+ti85_entries[i].data_size, serial_data->variables[i].data); |
595 | | free(temp_data_to_convert); |
596 | | } |
597 | | |
598 | | |
599 | | /*END packet*/ |
600 | | serial_data->end = (UINT8*) malloc (TI85_PC_END_PACKET_SIZE*8); |
601 | | if (!serial_data->end) |
602 | | { |
603 | | free (ti85_entries); |
604 | | return 0; |
605 | | } |
606 | | ti85_append_head_to_stream(ti85serial->send_id, TI_END_PACKET, serial_data->end); |
607 | | serial_data->end_size = TI85_PC_END_PACKET_SIZE*8; |
608 | | |
609 | | free (ti85_entries); |
610 | | |
611 | | return 1; |
612 | | } |
613 | | |
614 | | |
615 | | static void ti85_free_serial_stream (ti85_serial_data* serial_data) |
616 | | { |
617 | | UINT16 i; |
618 | | if (serial_data->variables) |
619 | | { |
620 | | for (i=0; i<serial_data->number_of_variables; i++) |
621 | | { |
622 | | if (serial_data->variables[i].header) free (serial_data->variables[i].header); |
623 | | if (serial_data->variables[i].ok) free (serial_data->variables[i].ok); |
624 | | if (serial_data->variables[i].data) free (serial_data->variables[i].data); |
625 | | } |
626 | | free (serial_data->variables); |
627 | | serial_data->variables = NULL; |
628 | | } |
629 | | serial_data->number_of_variables = 0; |
630 | | if (serial_data->end) |
631 | | { |
632 | | free (serial_data->end); |
633 | | serial_data->end = NULL; |
634 | | } |
635 | | } |
636 | | |
637 | | |
638 | | static void ti85_send_variables (device_t *device) |
639 | | { |
640 | | ti85serial_state *ti85serial = get_token( device ); |
641 | | |
642 | | if (!ti85_alloc_serial_data_memory(device, 7)) |
643 | | ti85serial->status = TI85_SEND_STOP; |
644 | | |
645 | | switch (ti85serial->status) |
646 | | { |
647 | | case TI85_SEND_HEADER: |
648 | | if(!ti85_send_serial(device, ti85serial->stream.variables[ti85serial->variables_variable_number].header,ti85serial->stream.variables[ti85serial->variables_variable_number].header_size)) |
649 | | { |
650 | | ti85serial->status = TI85_RECEIVE_OK_1; |
651 | | memset (ti85serial->receive_data, 0, 7); |
652 | | logerror ("Header sent\n"); |
653 | | } |
654 | | break; |
655 | | case TI85_RECEIVE_OK_1: |
656 | | if(!ti85_receive_serial (device, ti85serial->receive_buffer, 4*8)) |
657 | | { |
658 | | ti85_convert_stream_to_data (ti85serial->receive_buffer, 4*8, ti85serial->receive_data); |
659 | | ti85serial->status = TI85_RECEIVE_ANSWER_1; |
660 | | logerror ("OK received\n"); |
661 | | } |
662 | | break; |
663 | | case TI85_RECEIVE_ANSWER_1: |
664 | | if(!ti85_receive_serial (device, ti85serial->receive_buffer, 4*8)) |
665 | | { |
666 | | ti85_convert_stream_to_data (ti85serial->receive_buffer, 4*8, ti85serial->receive_data); |
667 | | switch (ti85serial->receive_data[1]) |
668 | | { |
669 | | case 0x09: //continue |
670 | | ti85serial->status = TI85_SEND_OK; |
671 | | logerror ("Continue received\n"); |
672 | | break; |
673 | | case 0x36: //out of memory, skip or exit |
674 | | ti85serial->status = TI85_RECEIVE_ANSWER_2; |
675 | | break; |
676 | | } |
677 | | } |
678 | | break; |
679 | | case TI85_RECEIVE_ANSWER_2: |
680 | | if(!ti85_receive_serial (device, ti85serial->receive_buffer+4*8, 1*8)) |
681 | | { |
682 | | ti85_convert_stream_to_data (ti85serial->receive_buffer, 5*8, ti85serial->receive_data); |
683 | | switch (ti85serial->receive_data[4]) |
684 | | { |
685 | | case 0x01: //exit |
686 | | case 0x02: //skip |
687 | | ti85serial->status = TI85_RECEIVE_ANSWER_3; |
688 | | break; |
689 | | case 0x03: //out of memory |
690 | | ti85serial->variables_variable_number = 0; |
691 | | ti85_free_serial_data_memory(device); |
692 | | ti85serial->status = TI85_SEND_STOP; |
693 | | break; |
694 | | } |
695 | | } |
696 | | break; |
697 | | case TI85_RECEIVE_ANSWER_3: |
698 | | if(!ti85_receive_serial (device, ti85serial->receive_buffer+5*8, 2*8)) |
699 | | { |
700 | | ti85_convert_stream_to_data (ti85serial->receive_buffer, 7*8, ti85serial->receive_data); |
701 | | switch (ti85serial->receive_data[4]) |
702 | | { |
703 | | case 0x01: //exit |
704 | | ti85serial->variables_variable_number = 0; |
705 | | ti85_free_serial_data_memory(device); |
706 | | ti85serial->status = TI85_SEND_STOP; |
707 | | break; |
708 | | case 0x02: //skip |
709 | | ti85serial->variables_variable_number++; |
710 | | ti85serial->status = TI85_SEND_OK; |
711 | | break; |
712 | | } |
713 | | } |
714 | | break; |
715 | | case TI85_SEND_OK: |
716 | | if(!ti85_send_serial(device, ti85serial->stream.variables[ti85serial->variables_variable_number].ok,ti85serial->stream.variables[ti85serial->variables_variable_number].ok_size)) |
717 | | { |
718 | | ti85serial->status = (ti85serial->receive_data[4]==0x02) ? ((ti85serial->variables_variable_number < ti85serial->stream.number_of_variables) ? TI85_SEND_HEADER : TI85_SEND_END) : TI85_SEND_DATA; |
719 | | memset(ti85serial->receive_data, 0, 7); |
720 | | } |
721 | | break; |
722 | | case TI85_SEND_DATA: |
723 | | if(!ti85_send_serial(device, ti85serial->stream.variables[ti85serial->variables_variable_number].data,ti85serial->stream.variables[ti85serial->variables_variable_number].data_size)) |
724 | | ti85serial->status = TI85_RECEIVE_OK_2; |
725 | | break; |
726 | | case TI85_RECEIVE_OK_2: |
727 | | if(!ti85_receive_serial (device, ti85serial->receive_buffer, 4*8)) |
728 | | { |
729 | | ti85serial->variables_variable_number++; |
730 | | ti85_convert_stream_to_data (ti85serial->receive_buffer, 4*8, ti85serial->receive_data); |
731 | | ti85serial->status = (ti85serial->variables_variable_number < ti85serial->stream.number_of_variables) ? TI85_SEND_HEADER : TI85_SEND_END; |
732 | | } |
733 | | break; |
734 | | case TI85_SEND_END: |
735 | | if(!ti85_send_serial(device, ti85serial->stream.end,ti85serial->stream.end_size)) |
736 | | { |
737 | | logerror ("End sent\n"); |
738 | | ti85serial->variables_variable_number = 0; |
739 | | ti85serial->status = TI85_RECEIVE_OK_3; |
740 | | } |
741 | | break; |
742 | | case TI85_RECEIVE_OK_3: |
743 | | if(!ti85_receive_serial (device, ti85serial->receive_buffer, 4*8)) |
744 | | { |
745 | | logerror ("OK received\n"); |
746 | | ti85_convert_stream_to_data (ti85serial->receive_buffer, 4*8, ti85serial->receive_data); |
747 | | ti85_free_serial_data_memory(device); |
748 | | ti85serial->status = TI85_SEND_STOP; |
749 | | } |
750 | | break; |
751 | | } |
752 | | } |
753 | | |
754 | | |
755 | | static void ti85_send_backup (device_t *device) |
756 | | { |
757 | | ti85serial_state *ti85serial = get_token( device ); |
758 | | |
759 | | if (!ti85_alloc_serial_data_memory(device, 7)) |
760 | | ti85serial->status = TI85_SEND_STOP; |
761 | | |
762 | | switch (ti85serial->status) |
763 | | { |
764 | | case TI85_SEND_HEADER: |
765 | | if(!ti85_send_serial(device, ti85serial->stream.variables[ti85serial->send_backup_variable_number].header,ti85serial->stream.variables[ti85serial->send_backup_variable_number].header_size)) |
766 | | ti85serial->status = TI85_RECEIVE_OK_1; |
767 | | break; |
768 | | case TI85_RECEIVE_OK_1: |
769 | | if(!ti85_receive_serial (device, ti85serial->receive_buffer, 4*8)) |
770 | | { |
771 | | ti85_convert_stream_to_data (ti85serial->receive_buffer, 4*8, ti85serial->receive_data); |
772 | | ti85serial->status = TI85_RECEIVE_ANSWER_1; |
773 | | } |
774 | | break; |
775 | | case TI85_RECEIVE_ANSWER_1: |
776 | | if(!ti85_receive_serial (device, ti85serial->receive_buffer, 4*8)) |
777 | | { |
778 | | ti85_convert_stream_to_data (ti85serial->receive_buffer, 4*8, ti85serial->receive_data); |
779 | | switch (ti85serial->receive_data[1]) |
780 | | { |
781 | | case 0x09: //continue |
782 | | ti85serial->status = TI85_SEND_OK; |
783 | | break; |
784 | | case 0x36: //out of memory, skip or exit |
785 | | ti85serial->status = TI85_RECEIVE_ANSWER_2; |
786 | | break; |
787 | | } |
788 | | } |
789 | | break; |
790 | | case TI85_RECEIVE_ANSWER_2: |
791 | | if(!ti85_receive_serial (device, ti85serial->receive_buffer+4*8, 3*8)) |
792 | | { |
793 | | ti85_convert_stream_to_data (ti85serial->receive_buffer, 5*8, ti85serial->receive_data); |
794 | | ti85serial->send_backup_variable_number = 0; |
795 | | ti85_free_serial_data_memory(device); |
796 | | ti85serial->status = TI85_SEND_STOP; |
797 | | } |
798 | | break; |
799 | | case TI85_SEND_OK: |
800 | | if(!ti85_send_serial(device, ti85serial->stream.variables[ti85serial->send_backup_variable_number].ok,ti85serial->stream.variables[ti85serial->send_backup_variable_number].ok_size)) |
801 | | ti85serial->status = TI85_SEND_DATA; |
802 | | break; |
803 | | case TI85_SEND_DATA: |
804 | | if(!ti85_send_serial(device, ti85serial->stream.variables[ti85serial->send_backup_variable_number].data,ti85serial->stream.variables[ti85serial->send_backup_variable_number].data_size)) |
805 | | ti85serial->status = TI85_RECEIVE_OK_2; |
806 | | break; |
807 | | case TI85_RECEIVE_OK_2: |
808 | | if(!ti85_receive_serial (device, ti85serial->receive_buffer, 4*8)) |
809 | | { |
810 | | ti85serial->send_backup_variable_number++; |
811 | | ti85_convert_stream_to_data (ti85serial->receive_buffer, 4*8, ti85serial->receive_data); |
812 | | ti85serial->status = (ti85serial->send_backup_variable_number < ti85serial->stream.number_of_variables) ? TI85_SEND_DATA : TI85_SEND_END; |
813 | | } |
814 | | break; |
815 | | case TI85_SEND_END: |
816 | | if(!ti85_send_serial(device, ti85serial->stream.end,ti85serial->stream.end_size)) |
817 | | { |
818 | | ti85serial->send_backup_variable_number = 0; |
819 | | ti85_free_serial_data_memory(device); |
820 | | ti85serial->status = TI85_SEND_STOP; |
821 | | } |
822 | | break; |
823 | | } |
824 | | } |
825 | | |
826 | | |
827 | | static void ti85_receive_variables (device_t *device) |
828 | | { |
829 | | ti85serial_state *ti85serial = get_token( device ); |
830 | | char var_file_name[16]; |
831 | | UINT8* temp; |
832 | | file_error filerr; |
833 | | |
834 | | switch (ti85serial->status) |
835 | | { |
836 | | case TI85_RECEIVE_HEADER_1: |
837 | | if(!ti85_receive_serial(device, ti85serial->receive_buffer+4*8, 3*8)) |
838 | | { |
839 | | ti85_convert_stream_to_data (ti85serial->receive_buffer+4*8, 3*8, ti85serial->receive_data+4); |
840 | | ti85serial->status = TI85_PREPARE_VARIABLE_DATA; |
841 | | } |
842 | | break; |
843 | | case TI85_PREPARE_VARIABLE_DATA: |
844 | | ti85serial->var_data = (UINT8*) malloc (ti85serial->receive_data[2]+2+ti85serial->receive_data[4]+ti85serial->receive_data[5]*256+2); |
845 | | if(!ti85serial->var_data) |
846 | | ti85serial->status = TI85_SEND_STOP; |
847 | | memcpy (ti85serial->var_data, ti85serial->receive_data+2, 5); |
848 | | ti85_free_serial_data_memory(device); |
849 | | if (!ti85_alloc_serial_data_memory(device, ti85serial->var_data[0]-1)) |
850 | | { |
851 | | free(ti85serial->var_data); ti85serial->var_data = NULL; |
852 | | free(ti85serial->var_file_data); ti85serial->var_file_data = NULL; |
853 | | ti85serial->status = TI85_SEND_STOP; |
854 | | return; |
855 | | } |
856 | | ti85serial->status = TI85_RECEIVE_HEADER_2; |
857 | | case TI85_RECEIVE_HEADER_2: |
858 | | if(!ti85_receive_serial(device, ti85serial->receive_buffer, (ti85serial->var_data[0]-1)*8)) |
859 | | { |
860 | | ti85_convert_stream_to_data (ti85serial->receive_buffer, (ti85serial->var_data[0]-1)*8, ti85serial->receive_data); |
861 | | memcpy (ti85serial->var_data+5, ti85serial->receive_data, ti85serial->var_data[0]-3); |
862 | | ti85_free_serial_data_memory(device); |
863 | | if(!ti85_alloc_serial_data_memory (device, 8)) |
864 | | { |
865 | | free(ti85serial->var_data); ti85serial->var_data = NULL; |
866 | | free(ti85serial->var_file_data); ti85serial->var_file_data = NULL; |
867 | | ti85serial->status = TI85_SEND_STOP; |
868 | | return; |
869 | | } |
870 | | ti85_append_head_to_stream(ti85serial->receive_id, TI_OK_PACKET, ti85serial->receive_buffer); |
871 | | ti85_append_head_to_stream(ti85serial->receive_id, TI_CONTINUE_PACKET, ti85serial->receive_buffer+4*8); |
872 | | ti85serial->status = TI85_SEND_OK_1; |
873 | | } |
874 | | break; |
875 | | case TI85_SEND_OK_1: |
876 | | if(!ti85_send_serial(device, ti85serial->receive_buffer, 4*8)) |
877 | | ti85serial->status = TI85_SEND_CONTINUE; |
878 | | break; |
879 | | case TI85_SEND_CONTINUE: |
880 | | if(!ti85_send_serial(device, ti85serial->receive_buffer+4*8, 4*8)) |
881 | | { |
882 | | ti85_free_serial_data_memory(device); |
883 | | if(!ti85_alloc_serial_data_memory(device, 4)) |
884 | | { |
885 | | free(ti85serial->var_data); ti85serial->var_data = NULL; |
886 | | free(ti85serial->var_file_data); ti85serial->var_file_data = NULL; |
887 | | ti85serial->status = TI85_SEND_STOP; |
888 | | return; |
889 | | } |
890 | | ti85serial->status = TI85_RECEIVE_OK; |
891 | | } |
892 | | break; |
893 | | case TI85_RECEIVE_OK: |
894 | | if(!ti85_receive_serial (device, ti85serial->receive_buffer, 4*8)) |
895 | | { |
896 | | ti85_convert_stream_to_data (ti85serial->receive_buffer, 4*8, ti85serial->receive_data); |
897 | | ti85_free_serial_data_memory(device); |
898 | | if(!ti85_alloc_serial_data_memory(device, ti85serial->var_data[2]+ti85serial->var_data[3]*256+6)) |
899 | | { |
900 | | free(ti85serial->var_data); ti85serial->var_data = NULL; |
901 | | free(ti85serial->var_file_data); ti85serial->var_file_data = NULL; |
902 | | ti85serial->status = TI85_SEND_STOP; |
903 | | return; |
904 | | } |
905 | | ti85serial->status = TI85_RECEIVE_DATA; |
906 | | } |
907 | | break; |
908 | | case TI85_RECEIVE_DATA: |
909 | | if(!ti85_receive_serial (device, ti85serial->receive_buffer, (ti85serial->var_data[2]+ti85serial->var_data[3]*256+6)*8)) |
910 | | { |
911 | | ti85_convert_stream_to_data (ti85serial->receive_buffer, (ti85serial->var_data[2]+ti85serial->var_data[3]*256+6)*8, ti85serial->receive_data); |
912 | | memcpy (ti85serial->var_data+ti85serial->var_data[0]+2, ti85serial->receive_data+2, ti85serial->var_data[2]+ti85serial->var_data[3]*256+2); |
913 | | ti85_free_serial_data_memory(device); |
914 | | if(!ti85_alloc_serial_data_memory (device, 4)) |
915 | | { |
916 | | free(ti85serial->var_data); ti85serial->var_data = NULL; |
917 | | free(ti85serial->var_file_data); ti85serial->var_file_data = NULL; |
918 | | ti85serial->status = TI85_SEND_STOP; |
919 | | return; |
920 | | } |
921 | | ti85_append_head_to_stream(ti85serial->receive_id, TI_OK_PACKET, ti85serial->receive_buffer); |
922 | | ti85serial->status = TI85_SEND_OK_2; |
923 | | } |
924 | | break; |
925 | | case TI85_SEND_OK_2: |
926 | | if(!ti85_send_serial(device, ti85serial->receive_buffer, 4*8)) |
927 | | { |
928 | | ti85_free_serial_data_memory(device); |
929 | | if(!ti85_alloc_serial_data_memory(device, 7)) |
930 | | { |
931 | | free(ti85serial->var_data); ti85serial->var_data = NULL; |
932 | | free(ti85serial->var_file_data); ti85serial->var_file_data = NULL; |
933 | | ti85serial->status = TI85_SEND_STOP; |
934 | | return; |
935 | | } |
936 | | ti85serial->status = TI85_RECEIVE_END_OR_HEADER_1; |
937 | | } |
938 | | break; |
939 | | case TI85_RECEIVE_END_OR_HEADER_1: |
940 | | if(!ti85_receive_serial (device, ti85serial->receive_buffer, 4*8)) |
941 | | { |
942 | | if (ti85serial->variable_number == 0) |
943 | | { |
944 | | ti85serial->var_file_data = (UINT8*) malloc (0x39); |
945 | | if (!ti85serial->var_file_data) |
946 | | { |
947 | | free (ti85serial->var_data); ti85serial->var_data = NULL; |
948 | | free (ti85serial->var_file_data); ti85serial->var_file_data = NULL; |
949 | | ti85serial->status = TI85_SEND_STOP; |
950 | | } |
951 | | else |
952 | | { |
953 | | memcpy(ti85serial->var_file_data, ti85_file_signature, 0x0b); |
954 | | memcpy(ti85serial->var_file_data+0x0b, "File created by MESS", 0x14); |
955 | | memset(ti85serial->var_file_data+0x1f, 0, 0x1a); |
956 | | ti85serial->var_file_size = 0x39; |
957 | | } |
958 | | } |
959 | | temp = (UINT8*)malloc (ti85serial->var_file_size+ti85serial->var_data[0]+2+ti85serial->var_data[2]+ti85serial->var_data[3]*256+2); |
960 | | if (temp) |
961 | | { |
962 | | memcpy (temp, ti85serial->var_file_data, ti85serial->var_file_size); |
963 | | free (ti85serial->var_file_data); |
964 | | ti85serial->var_file_data = temp; |
965 | | memcpy (ti85serial->var_file_data + ti85serial->var_file_size -2, ti85serial->var_data, ti85serial->var_data[0]+2+ti85serial->var_data[2]+ti85serial->var_data[3]*256+2); |
966 | | ti85serial->var_file_size += ti85serial->var_data[0]+2+ti85serial->var_data[2]+ti85serial->var_data[3]*256+2; |
967 | | ti85serial->var_file_data[0x35] = (ti85serial->var_file_size-0x39)&0x00ff; |
968 | | ti85serial->var_file_data[0x36] = ((ti85serial->var_file_size-0x39)&0xff00)>>8; |
969 | | ti85serial->var_file_data[ti85serial->var_file_size-2] = ti85_calculate_checksum(ti85serial->var_file_data+0x37, ti85serial->var_file_size-0x39)&0x00ff; |
970 | | ti85serial->var_file_data[ti85serial->var_file_size-1] = (ti85_calculate_checksum(ti85serial->var_file_data+0x37, ti85serial->var_file_size-0x39)&0xff00)>>8; |
971 | | } |
972 | | free (ti85serial->var_data); |
973 | | ti85serial->var_data = NULL; |
974 | | ti85serial->variable_number ++; |
975 | | |
976 | | ti85_convert_stream_to_data (ti85serial->receive_buffer, 4*8, ti85serial->receive_data); |
977 | | if (ti85serial->receive_data[1] == 0x06) |
978 | | ti85serial->status = TI85_RECEIVE_HEADER_1; |
979 | | else |
980 | | { |
981 | | ti85_free_serial_data_memory(device); |
982 | | if(!ti85_alloc_serial_data_memory (device, 4)) |
983 | | { |
984 | | free(ti85serial->var_data); ti85serial->var_data = NULL; |
985 | | free(ti85serial->var_file_data); ti85serial->var_file_data = NULL; |
986 | | ti85serial->status = TI85_SEND_STOP; |
987 | | return; |
988 | | } |
989 | | ti85_append_head_to_stream(ti85serial->receive_id, TI_OK_PACKET, ti85serial->receive_buffer); |
990 | | ti85serial->status = TI85_SEND_OK_3; |
991 | | } |
992 | | } |
993 | | break; |
994 | | case TI85_SEND_OK_3: |
995 | | if(!ti85_send_serial(device, ti85serial->receive_buffer, 4*8)) |
996 | | { |
997 | | ti85_free_serial_data_memory(device); |
998 | | ti85serial->variable_number = 0; |
999 | | ti85serial->status = TI85_SEND_STOP; |
1000 | | sprintf (var_file_name, "%08d.85g", ti85serial->var_file_number); |
1001 | | emu_file var_file(device->machine().options().memcard_directory(), OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); |
1002 | | filerr = var_file.open(var_file_name); |
1003 | | |
1004 | | if (filerr == FILERR_NONE) |
1005 | | { |
1006 | | var_file.write(ti85serial->var_file_data, ti85serial->var_file_size); |
1007 | | free (ti85serial->var_file_data); |
1008 | | ti85serial->var_file_data = NULL; |
1009 | | ti85serial->var_file_size = 0; |
1010 | | ti85serial->var_file_number++; |
1011 | | } |
1012 | | } |
1013 | | break; |
1014 | | } |
1015 | | } |
1016 | | |
1017 | | |
1018 | | static void ti85_receive_backup (device_t *device) |
1019 | | { |
1020 | | ti85serial_state *ti85serial = get_token( device ); |
1021 | | |
1022 | | file_error filerr; |
1023 | | char backup_file_name[] = "00000000.85b"; |
1024 | | |
1025 | | switch (ti85serial->status) |
1026 | | { |
1027 | | case TI85_RECEIVE_HEADER_2: |
1028 | | if(!ti85_receive_serial(device, ti85serial->receive_buffer+7*8, 8*8)) |
1029 | | { |
1030 | | ti85_convert_stream_to_data (ti85serial->receive_buffer+7*8, 8*8, ti85serial->receive_data+7); |
1031 | | ti85serial->backup_data_size[0] = ti85serial->receive_data[4] + ti85serial->receive_data[5]*256; |
1032 | | ti85serial->backup_data_size[1] = ti85serial->receive_data[7] + ti85serial->receive_data[8]*256; |
1033 | | ti85serial->backup_data_size[2] = ti85serial->receive_data[9] + ti85serial->receive_data[10]*256; |
1034 | | ti85serial->backup_file_data = (UINT8*)malloc (0x42+0x06+ti85serial->backup_data_size[0]+ti85serial->backup_data_size[1]+ti85serial->backup_data_size[2]+0x02); |
1035 | | if(!ti85serial->backup_file_data) |
1036 | | { |
1037 | | ti85serial->backup_variable_number = 0; |
1038 | | ti85serial->status = TI85_SEND_STOP; |
1039 | | return; |
1040 | | } |
1041 | | memcpy(ti85serial->backup_file_data, ti85_file_signature, 0x0b); |
1042 | | memcpy(ti85serial->backup_file_data+0x0b, "File created by MESS", 0x14); |
1043 | | memset(ti85serial->backup_file_data+0x1f, 0, 0x16); |
1044 | | ti85serial->backup_file_data[0x35] = (ti85serial->backup_data_size[0]+ti85serial->backup_data_size[1]+ti85serial->backup_data_size[2]+0x11)&0x00ff; |
1045 | | ti85serial->backup_file_data[0x36] = ((ti85serial->backup_data_size[0]+ti85serial->backup_data_size[1]+ti85serial->backup_data_size[2]+0x11)&0xff00)>>8; |
1046 | | memcpy(ti85serial->backup_file_data+0x37, ti85serial->receive_data+0x02, 0x0b); |
1047 | | ti85_free_serial_data_memory(device); |
1048 | | if(!ti85_alloc_serial_data_memory (device, 8)) |
1049 | | { |
1050 | | free(ti85serial->backup_file_data); ti85serial->backup_file_data = NULL; |
1051 | | ti85serial->backup_variable_number = 0; |
1052 | | ti85serial->status = TI85_SEND_STOP; |
1053 | | return; |
1054 | | } |
1055 | | ti85_append_head_to_stream(ti85serial->receive_id, TI_OK_PACKET, ti85serial->receive_buffer); |
1056 | | ti85_append_head_to_stream(ti85serial->receive_id, TI_CONTINUE_PACKET, ti85serial->receive_buffer+4*8); |
1057 | | ti85serial->status = TI85_SEND_OK_1; |
1058 | | } |
1059 | | break; |
1060 | | case TI85_SEND_OK_1: |
1061 | | if(!ti85_send_serial(device, ti85serial->receive_buffer, 4*8)) |
1062 | | ti85serial->status = TI85_SEND_CONTINUE; |
1063 | | break; |
1064 | | case TI85_SEND_CONTINUE: |
1065 | | if(!ti85_send_serial(device, ti85serial->receive_buffer+4*8, 4*8)) |
1066 | | { |
1067 | | ti85_free_serial_data_memory(device); |
1068 | | if(!ti85_alloc_serial_data_memory(device, 4)) |
1069 | | { |
1070 | | free(ti85serial->backup_file_data); ti85serial->backup_file_data = NULL; |
1071 | | ti85serial->backup_variable_number = 0; |
1072 | | ti85serial->status = TI85_SEND_STOP; |
1073 | | return; |
1074 | | } |
1075 | | ti85serial->status = TI85_RECEIVE_OK; |
1076 | | } |
1077 | | break; |
1078 | | case TI85_RECEIVE_OK: |
1079 | | if(!ti85_receive_serial (device, ti85serial->receive_buffer, 4*8)) |
1080 | | { |
1081 | | ti85_convert_stream_to_data (ti85serial->receive_buffer, 4*8, ti85serial->receive_data); |
1082 | | ti85_free_serial_data_memory(device); |
1083 | | if(!ti85_alloc_serial_data_memory(device, ti85serial->backup_data_size[ti85serial->backup_variable_number]+6)) |
1084 | | { |
1085 | | free(ti85serial->backup_file_data); ti85serial->backup_file_data = NULL; |
1086 | | ti85serial->backup_variable_number = 0; |
1087 | | ti85serial->status = TI85_SEND_STOP; |
1088 | | return; |
1089 | | } |
1090 | | ti85serial->status = TI85_RECEIVE_DATA; |
1091 | | } |
1092 | | break; |
1093 | | case TI85_RECEIVE_DATA: |
1094 | | if(!ti85_receive_serial (device, ti85serial->receive_buffer, (ti85serial->backup_data_size[ti85serial->backup_variable_number]+6)*8)) |
1095 | | { |
1096 | | ti85_convert_stream_to_data (ti85serial->receive_buffer, (ti85serial->backup_data_size[ti85serial->backup_variable_number]+6)*8, ti85serial->receive_data); |
1097 | | switch (ti85serial->backup_variable_number) |
1098 | | { |
1099 | | case 0: |
1100 | | memcpy(ti85serial->backup_file_data+0x42, ti85serial->receive_data+0x02, ti85serial->backup_data_size[0]+0x02); |
1101 | | break; |
1102 | | case 1: |
1103 | | memcpy(ti85serial->backup_file_data+0x42+ti85serial->backup_data_size[0]+0x02, ti85serial->receive_data+0x02, ti85serial->backup_data_size[1]+0x02); |
1104 | | break; |
1105 | | case 2: |
1106 | | memcpy(ti85serial->backup_file_data+0x42+ti85serial->backup_data_size[0]+ti85serial->backup_data_size[1]+0x04, ti85serial->receive_data+0x02, ti85serial->backup_data_size[2]+0x02); |
1107 | | break; |
1108 | | } |
1109 | | ti85_free_serial_data_memory(device); |
1110 | | if(!ti85_alloc_serial_data_memory (device, 4)) |
1111 | | { |
1112 | | free(ti85serial->backup_file_data); ti85serial->backup_file_data = NULL; |
1113 | | ti85serial->backup_variable_number = 0; |
1114 | | ti85serial->status = TI85_SEND_STOP; |
1115 | | return; |
1116 | | } |
1117 | | ti85_append_head_to_stream(ti85serial->receive_id, TI_OK_PACKET, ti85serial->receive_buffer); |
1118 | | ti85serial->status = TI85_SEND_OK_2; |
1119 | | } |
1120 | | break; |
1121 | | case TI85_SEND_OK_2: |
1122 | | if(!ti85_send_serial(device, ti85serial->receive_buffer, 4*8)) |
1123 | | { |
1124 | | ti85_free_serial_data_memory(device); |
1125 | | ti85serial->backup_variable_number++; |
1126 | | if (ti85serial->backup_variable_number<3) |
1127 | | { |
1128 | | if(!ti85_alloc_serial_data_memory(device, ti85serial->backup_data_size[ti85serial->backup_variable_number]+6)) |
1129 | | { |
1130 | | free(ti85serial->backup_file_data); ti85serial->backup_file_data = NULL; |
1131 | | ti85serial->backup_variable_number = 0; |
1132 | | ti85serial->status = TI85_SEND_STOP; |
1133 | | return; |
1134 | | } |
1135 | | ti85serial->status = TI85_RECEIVE_DATA; |
1136 | | } |
1137 | | else |
1138 | | { |
1139 | | ti85serial->backup_variable_number = 0; |
1140 | | ti85serial->backup_file_data[0x42+0x06+ti85serial->backup_data_size[0]+ti85serial->backup_data_size[1]+ti85serial->backup_data_size[2]] = ti85_calculate_checksum(ti85serial->backup_file_data+0x37, 0x42+ti85serial->backup_data_size[0]+ti85serial->backup_data_size[1]+ti85serial->backup_data_size[2]+0x06-0x37)&0x00ff; |
1141 | | ti85serial->backup_file_data[0x42+0x06+ti85serial->backup_data_size[0]+ti85serial->backup_data_size[1]+ti85serial->backup_data_size[2]+0x01] = (ti85_calculate_checksum(ti85serial->backup_file_data+0x37, 0x42+ti85serial->backup_data_size[0]+ti85serial->backup_data_size[1]+ti85serial->backup_data_size[2]+0x06-0x37)&0xff00)>>8; |
1142 | | sprintf (backup_file_name, "%08d.85b", ti85serial->backup_file_number); |
1143 | | |
1144 | | emu_file backup_file(device->machine().options().memcard_directory(), OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); |
1145 | | filerr = backup_file.open(backup_file_name); |
1146 | | |
1147 | | if (filerr == FILERR_NONE) |
1148 | | { |
1149 | | backup_file.write(ti85serial->backup_file_data, 0x42+0x06+ti85serial->backup_data_size[0]+ti85serial->backup_data_size[1]+ti85serial->backup_data_size[2]+0x02); |
1150 | | ti85serial->backup_file_number++; |
1151 | | } |
1152 | | free(ti85serial->backup_file_data); ti85serial->backup_file_data = NULL; |
1153 | | ti85serial->status = TI85_SEND_STOP; |
1154 | | } |
1155 | | } |
1156 | | break; |
1157 | | } |
1158 | | } |
1159 | | |
1160 | | static void ti85_receive_screen (device_t *device) |
1161 | | { |
1162 | | ti85serial_state *ti85serial = get_token( device ); |
1163 | | char image_file_name[] = "00000000.85i"; |
1164 | | file_error filerr; |
1165 | | UINT8 * image_file_data; |
1166 | | |
1167 | | switch (ti85serial->status) |
1168 | | { |
1169 | | case TI85_PREPARE_SCREEN_REQUEST: |
1170 | | if(!ti85_alloc_serial_data_memory (device, 4)) |
1171 | | { |
1172 | | ti85serial->status = TI85_SEND_STOP; |
1173 | | return; |
1174 | | } |
1175 | | ti85_append_head_to_stream(ti85serial->receive_id, TI_SCREEN_REQUEST_PACKET, ti85serial->receive_buffer); |
1176 | | ti85serial->status = TI85_SEND_SCREEN_REQUEST; |
1177 | | break; |
1178 | | case TI85_SEND_SCREEN_REQUEST: |
1179 | | if(!ti85_send_serial(device, ti85serial->receive_buffer, 4*8)) |
1180 | | { |
1181 | | ti85_free_serial_data_memory(device); |
1182 | | if(!ti85_alloc_serial_data_memory (device, 4)) |
1183 | | { |
1184 | | ti85serial->status = TI85_SEND_STOP; |
1185 | | return; |
1186 | | } |
1187 | | ti85serial->status = TI85_RECEIVE_OK; |
1188 | | } |
1189 | | break; |
1190 | | case TI85_RECEIVE_OK: |
1191 | | if(!ti85_receive_serial (device, ti85serial->receive_buffer, 4*8)) |
1192 | | { |
1193 | | ti85_convert_stream_to_data (ti85serial->receive_buffer, 4*8, ti85serial->receive_data); |
1194 | | ti85_free_serial_data_memory(device); |
1195 | | if(!ti85_alloc_serial_data_memory (device, 1030)) |
1196 | | { |
1197 | | ti85serial->status = TI85_SEND_STOP; |
1198 | | return; |
1199 | | } |
1200 | | ti85serial->status = TI85_RECEIVE_DATA; |
1201 | | } |
1202 | | break; |
1203 | | case TI85_RECEIVE_DATA: |
1204 | | if(!ti85_receive_serial (device, ti85serial->receive_buffer, 1030*8)) |
1205 | | { |
1206 | | ti85_convert_stream_to_data (ti85serial->receive_buffer, 1030*8, ti85serial->receive_data); |
1207 | | sprintf (image_file_name, "%08d.85i", ti85serial->image_file_number); |
1208 | | |
1209 | | emu_file image_file(device->machine().options().memcard_directory(), OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); |
1210 | | filerr = image_file.open(image_file_name); |
1211 | | |
1212 | | if (filerr == FILERR_NONE) |
1213 | | { |
1214 | | image_file_data = (UINT8*)malloc (0x49+1008); |
1215 | | if(!image_file_data) |
1216 | | { |
1217 | | ti85_free_serial_data_memory(device); |
1218 | | ti85serial->status = TI85_SEND_OK; |
1219 | | return; |
1220 | | } |
1221 | | memcpy(image_file_data, ti85_file_signature, 0x0b); |
1222 | | memcpy(image_file_data+0x0b, "File created by MESS", 0x14); |
1223 | | memset(image_file_data+0x1f, 0, 0x16); |
1224 | | image_file_data[0x35] = 0x00; |
1225 | | image_file_data[0x36] = 0x04; |
1226 | | image_file_data[0x37] = 0x0a; //header size |
1227 | | image_file_data[0x38] = 0x00; |
1228 | | image_file_data[0x39] = 0xf2; //data size |
1229 | | image_file_data[0x3a] = 0x03; |
1230 | | image_file_data[0x3b] = 0x11; //data type |
1231 | | image_file_data[0x3c] = 0x06; //name size |
1232 | | memcpy(image_file_data+0x3d, "Screen", 0x06); |
1233 | | image_file_data[0x43] = 0xf2; |
1234 | | image_file_data[0x44] = 0x03; |
1235 | | image_file_data[0x45] = 0xf0; |
1236 | | image_file_data[0x46] = 0x03; |
1237 | | memcpy(image_file_data+0x47, ti85serial->receive_data+4, 1008); |
1238 | | image_file_data[1008+0x49-2] = ti85_calculate_checksum(image_file_data+0x37, 1008+0x10)&0x00ff; |
1239 | | image_file_data[1008+0x49-1] = (ti85_calculate_checksum(image_file_data+0x37, 1008+0x10)&0xff00)>>8; |
1240 | | image_file.write(image_file_data, 1008+0x49); |
1241 | | free(image_file_data); |
1242 | | ti85serial->image_file_number++; |
1243 | | } |
1244 | | ti85_free_serial_data_memory(device); |
1245 | | if(!ti85_alloc_serial_data_memory (device, 4)) |
1246 | | { |
1247 | | ti85serial->status = TI85_SEND_STOP; |
1248 | | return; |
1249 | | } |
1250 | | ti85_append_head_to_stream(ti85serial->receive_id, TI_OK_PACKET, ti85serial->receive_buffer); |
1251 | | ti85serial->status = TI85_SEND_OK; |
1252 | | } |
1253 | | break; |
1254 | | case TI85_SEND_OK: |
1255 | | if(!ti85_send_serial(device, ti85serial->receive_buffer, 4*8)) |
1256 | | { |
1257 | | ti85_free_serial_data_memory(device); |
1258 | | ti85serial->status = TI85_SEND_STOP; |
1259 | | } |
1260 | | break; |
1261 | | } |
1262 | | } |
1263 | | |
1264 | | |
1265 | | void ti85_update_serial (device_t *device) |
1266 | | { |
1267 | | ti85serial_state *ti85serial = get_token( device ); |
1268 | | |
1269 | | if (ti85serial->status == TI85_SEND_STOP) |
1270 | | { |
1271 | | if (input_port_read(*device, "SERIAL") & 0x01) |
1272 | | { |
1273 | | if(!ti85_alloc_serial_data_memory(device, 15)) return; |
1274 | | if(!ti85_receive_serial (device, ti85serial->receive_buffer, 7*8)) |
1275 | | { |
1276 | | ti85_convert_stream_to_data (ti85serial->receive_buffer, 7*8, ti85serial->receive_data); |
1277 | | if (ti85serial->receive_data[0]!=0x85 || ti85serial->receive_data[1]!=0x06) |
1278 | | { |
1279 | | ti85_receive_serial (device, NULL, 0); |
1280 | | return; |
1281 | | } |
1282 | | ti85serial->transfer_type = (ti85serial->receive_data[6]==0x1d) ? TI85_RECEIVE_BACKUP : TI85_RECEIVE_VARIABLES; |
1283 | | ti85serial->status = (ti85serial->receive_data[6]==0x1d) ? TI85_RECEIVE_HEADER_2 : TI85_PREPARE_VARIABLE_DATA; |
1284 | | } |
1285 | | } |
1286 | | else |
1287 | | { |
1288 | | ti85_receive_serial(device, NULL, 0); |
1289 | | ti85_free_serial_data_memory(device); |
1290 | | if (input_port_read(*device, "DUMP") & 0x01) |
1291 | | { |
1292 | | ti85serial->status = TI85_PREPARE_SCREEN_REQUEST; |
1293 | | ti85serial->transfer_type = TI85_RECEIVE_SCREEN; |
1294 | | } |
1295 | | return; |
1296 | | } |
1297 | | } |
1298 | | |
1299 | | switch (ti85serial->transfer_type) |
1300 | | { |
1301 | | case TI85_SEND_VARIABLES: |
1302 | | ti85_send_variables(device); |
1303 | | break; |
1304 | | case TI85_SEND_BACKUP: |
1305 | | ti85_send_backup(device); |
1306 | | break; |
1307 | | case TI85_RECEIVE_BACKUP: |
1308 | | ti85_receive_backup(device); |
1309 | | break; |
1310 | | case TI85_RECEIVE_VARIABLES: |
1311 | | ti85_receive_variables(device); |
1312 | | break; |
1313 | | case TI85_RECEIVE_SCREEN: |
1314 | | ti85_receive_screen(device); |
1315 | | break; |
1316 | | } |
1317 | | } |
1318 | | |
1319 | | |
1320 | | WRITE8_DEVICE_HANDLER( ti85serial_red_out ) |
1321 | | { |
1322 | | ti85serial_state *ti85serial = get_token( device ); |
1323 | | |
1324 | | ti85serial->red_out = data; |
1325 | | } |
1326 | | |
1327 | | |
1328 | | WRITE8_DEVICE_HANDLER( ti85serial_white_out ) |
1329 | | { |
1330 | | ti85serial_state *ti85serial = get_token( device ); |
1331 | | |
1332 | | ti85serial->white_out = data; |
1333 | | } |
1334 | | |
1335 | | |
1336 | | READ8_DEVICE_HANDLER( ti85serial_red_in ) |
1337 | | { |
1338 | | ti85serial_state *ti85serial = get_token( device ); |
1339 | | |
1340 | | return ti85serial->red_in; |
1341 | | } |
1342 | | |
1343 | | |
1344 | | READ8_DEVICE_HANDLER( ti85serial_white_in ) |
1345 | | { |
1346 | | ti85serial_state *ti85serial = get_token( device ); |
1347 | | |
1348 | | return ti85serial->white_in; |
1349 | | } |
1350 | | |
1351 | | |
1352 | | static DEVICE_START( ti85serial ) |
1353 | | { |
1354 | | ti85serial_state *ti85serial = get_token( device ); |
1355 | | |
1356 | | ti85serial->transfer_type = TI85_SEND_VARIABLES; |
1357 | | ti85serial->receive_buffer = NULL; |
1358 | | ti85serial->receive_data = NULL; |
1359 | | ti85serial->var_file_number = 0; |
1360 | | ti85serial->backup_file_number = 0; |
1361 | | ti85serial->image_file_number = 0; |
1362 | | } |
1363 | | |
1364 | | |
1365 | | static DEVICE_STOP( ti85serial ) |
1366 | | { |
1367 | | ti85serial_state *ti85serial = get_token( device ); |
1368 | | |
1369 | | ti85_free_serial_data_memory(device); |
1370 | | if (ti85serial->var_data) |
1371 | | { |
1372 | | free(ti85serial->var_data); ti85serial->var_data = NULL; |
1373 | | } |
1374 | | if (ti85serial->var_file_data) |
1375 | | { |
1376 | | free(ti85serial->var_file_data); ti85serial->var_file_data = NULL; |
1377 | | } |
1378 | | if (ti85serial->backup_file_data) |
1379 | | { |
1380 | | free(ti85serial->backup_file_data); ti85serial->backup_file_data = NULL; |
1381 | | } |
1382 | | } |
1383 | | |
1384 | | |
1385 | | static DEVICE_RESET( ti85serial ) |
1386 | | { |
1387 | | ti85serial_state *ti85serial = get_token( device ); |
1388 | | |
1389 | | ti85serial->receive_data_counter = 0; |
1390 | | ti85serial->send_data_counter = 0; |
1391 | | ti85_free_serial_data_memory(device); |
1392 | | ti85serial->red_in = 0; |
1393 | | ti85serial->white_in = 0; |
1394 | | ti85serial->red_out = 1; |
1395 | | ti85serial->white_out = 1; |
1396 | | ti85serial->variables_variable_number = 0; |
1397 | | ti85serial->send_backup_variable_number = 0; |
1398 | | ti85serial->var_data = NULL; |
1399 | | ti85serial->var_file_data = NULL; |
1400 | | ti85serial->var_file_size = 0; |
1401 | | ti85serial->variable_number = 0; |
1402 | | ti85serial->backup_file_data = NULL; |
1403 | | ti85serial->backup_variable_number = 0; |
1404 | | ti85serial->status = TI85_SEND_STOP; |
1405 | | |
1406 | | //initialize the receive_id used for TI to PC transfer |
1407 | | if (device->type() == TI73SERIAL) |
1408 | | ti85serial->receive_id = TI_TRANFER_ID_TI73; |
1409 | | else if (device->type() == TI85SERIAL) |
1410 | | ti85serial->receive_id = TI_TRANFER_ID_TI85; |
1411 | | else if (device->type() == TI82SERIAL) |
1412 | | ti85serial->receive_id = TI_TRANFER_ID_TI82; |
1413 | | else if (device->type() == TI83PSERIAL) |
1414 | | ti85serial->receive_id = TI_TRANFER_ID_TI83P; |
1415 | | else if (device->type() == TI86SERIAL) |
1416 | | ti85serial->receive_id = TI_TRANFER_ID_TI86; |
1417 | | |
1418 | | ti85serial->send_id = ti85serial->receive_id; |
1419 | | } |
1420 | | |
1421 | | |
1422 | | static DEVICE_IMAGE_LOAD( ti85serial ) |
1423 | | { |
1424 | | ti85serial_state *ti85serial = get_token( image ); |
1425 | | UINT8* file_data; |
1426 | | UINT16 file_size; |
1427 | | |
1428 | | if (ti85serial->status != TI85_SEND_STOP) return IMAGE_INIT_FAIL; |
1429 | | |
1430 | | file_size = image.length(); |
1431 | | |
1432 | | if (file_size != 0) |
1433 | | { |
1434 | | file_data = auto_alloc_array(image.device().machine(), UINT8, file_size); |
1435 | | image.fread( file_data, file_size); |
1436 | | |
1437 | | if(!ti85_convert_file_data_to_serial_stream(image, file_data, file_size, &ti85serial->stream)) |
1438 | | { |
1439 | | ti85_free_serial_stream (&ti85serial->stream); |
1440 | | return IMAGE_INIT_FAIL; |
1441 | | } |
1442 | | |
1443 | | ti85serial->status = TI85_SEND_HEADER; |
1444 | | } |
1445 | | else |
1446 | | { |
1447 | | return IMAGE_INIT_FAIL; |
1448 | | } |
1449 | | return IMAGE_INIT_PASS; |
1450 | | } |
1451 | | |
1452 | | |
1453 | | static DEVICE_IMAGE_UNLOAD( ti85serial ) |
1454 | | { |
1455 | | ti85serial_state *ti85serial = get_token( image ); |
1456 | | |
1457 | | ti85_free_serial_data_memory(image); |
1458 | | ti85serial->status = TI85_SEND_STOP; |
1459 | | ti85_free_serial_stream (&ti85serial->stream); |
1460 | | } |
1461 | | |
1462 | | |
1463 | | static INPUT_PORTS_START ( ti85serial ) |
1464 | | PORT_START("SERIAL") /* receive data from calculator */ |
1465 | | PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Receive data") PORT_CODE(KEYCODE_R) |
1466 | | PORT_START("DUMP") /* screen dump requesting */ |
1467 | | PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Screen dump request") PORT_CODE(KEYCODE_S) |
1468 | | INPUT_PORTS_END |
1469 | | |
1470 | | |
1471 | | DEVICE_GET_INFO( ti85serial ) |
1472 | | { |
1473 | | switch ( state ) |
1474 | | { |
1475 | | case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof( ti85serial_state ); break; |
1476 | | case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break; |
1477 | | case DEVINFO_INT_IMAGE_TYPE: info->i = IO_SERIAL; break; |
1478 | | case DEVINFO_INT_IMAGE_READABLE: info->i = 1; break; |
1479 | | case DEVINFO_INT_IMAGE_WRITEABLE: info->i = 0; break; |
1480 | | case DEVINFO_INT_IMAGE_CREATABLE: info->i = 0; break; |
1481 | | case DEVINFO_FCT_START: info->start = DEVICE_START_NAME( ti85serial ); break; |
1482 | | case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME( ti85serial ); break; |
1483 | | case DEVINFO_FCT_STOP: info->stop = DEVICE_STOP_NAME( ti85serial ); break; |
1484 | | case DEVINFO_FCT_IMAGE_LOAD: info->f = (genf *) DEVICE_IMAGE_LOAD_NAME( ti85serial ); break; |
1485 | | case DEVINFO_FCT_IMAGE_UNLOAD: info->f = (genf *) DEVICE_IMAGE_UNLOAD_NAME( ti85serial ); break; |
1486 | | case DEVINFO_PTR_INPUT_PORTS: info->ipt = INPUT_PORTS_NAME( ti85serial ); break; |
1487 | | case DEVINFO_STR_IMAGE_BRIEF_INSTANCE_NAME: strcpy(info->s, "ser"); break; |
1488 | | case DEVINFO_STR_IMAGE_INSTANCE_NAME: strcpy(info->s, "serial"); break; |
1489 | | case DEVINFO_STR_NAME: strcpy(info->s, "TI85 Serial"); break; |
1490 | | case DEVINFO_STR_FAMILY: strcpy(info->s, "serial protocol"); break; |
1491 | | case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break; |
1492 | | case DEVINFO_STR_IMAGE_FILE_EXTENSIONS: strcpy(info->s, "85p,85s,85i,85n,85c,85l,85k,85m,85v,85d,85e,85r,85g,85b"); break; |
1493 | | } |
1494 | | } |
1495 | | |
1496 | | DEVICE_GET_INFO( ti73serial ) |
1497 | | { |
1498 | | switch ( state ) |
1499 | | { |
1500 | | case DEVINFO_STR_NAME: strcpy(info->s, "TI73 Serial"); break; |
1501 | | case DEVINFO_STR_IMAGE_FILE_EXTENSIONS: strcpy(info->s, "73p,73s,73i,73n,73c,73l,73k,73m,73v,73d,73e,73r,73g"); break; |
1502 | | default: DEVICE_GET_INFO_CALL( ti85serial ); |
1503 | | } |
1504 | | } |
1505 | | |
1506 | | DEVICE_GET_INFO( ti82serial ) |
1507 | | { |
1508 | | switch ( state ) |
1509 | | { |
1510 | | case DEVINFO_STR_NAME: strcpy(info->s, "TI82 Serial"); break; |
1511 | | case DEVINFO_STR_IMAGE_FILE_EXTENSIONS: strcpy(info->s, "82p,82s,82i,82n,82c,82l,82k,82m,82v,82d,82e,82r,82g"); break; |
1512 | | default: DEVICE_GET_INFO_CALL( ti85serial ); |
1513 | | } |
1514 | | } |
1515 | | |
1516 | | |
1517 | | DEVICE_GET_INFO( ti83pserial ) |
1518 | | { |
1519 | | switch ( state ) |
1520 | | { |
1521 | | case DEVINFO_STR_NAME: strcpy(info->s, "TI83 Plus Serial"); break; |
1522 | | case DEVINFO_STR_IMAGE_FILE_EXTENSIONS: strcpy(info->s, "82p,82s,82i,82n,82c,82l,82k,82m,82v,82d,82e,82r,82g," //for TI-82 compatibility |
1523 | | "83p,83s,83i,83n,83c,83l,83k,83m,83v,83d,83e,83r,83g," //for TI-83 compatibility |
1524 | | "8xc,8xd,8xg,8xi,8xl,8xm,8xn,8xp,8xs,8xt,8xv,8xw,8xy,8xz"); break; |
1525 | | default: DEVICE_GET_INFO_CALL( ti85serial ); |
1526 | | } |
1527 | | } |
1528 | | |
1529 | | DEVICE_GET_INFO( ti86serial ) |
1530 | | { |
1531 | | switch ( state ) |
1532 | | { |
1533 | | case DEVINFO_STR_NAME: strcpy(info->s, "TI86 Serial"); break; |
1534 | | case DEVINFO_STR_IMAGE_FILE_EXTENSIONS: strcpy(info->s, "85p,85s,85i,85n,85c,85l,85k,85m,85v,85d,85e,85r,85g,85b" //for TI-85 compatibility |
1535 | | "86p,86s,86i,86n,86c,86l,86k,86m,86v,86d,86e,86r,86g"); break; |
1536 | | default: DEVICE_GET_INFO_CALL( ti85serial ); |
1537 | | } |
1538 | | } |
1539 | | |
1540 | | DEFINE_LEGACY_IMAGE_DEVICE(TI85SERIAL, ti85serial); |
1541 | | DEFINE_LEGACY_IMAGE_DEVICE(TI73SERIAL, ti73serial); |
1542 | | DEFINE_LEGACY_IMAGE_DEVICE(TI82SERIAL, ti82serial); |
1543 | | DEFINE_LEGACY_IMAGE_DEVICE(TI83PSERIAL, ti83pserial); |
1544 | | DEFINE_LEGACY_IMAGE_DEVICE(TI86SERIAL, ti86serial); |
trunk/src/mess/drivers/c16.c
r17575 | r17576 | |
1 | | /*************************************************************************** |
2 | | commodore c16 home computer |
3 | | |
4 | | PeT mess@utanet.at |
5 | | |
6 | | documentation |
7 | | www.funet.fi |
8 | | |
9 | | ***************************************************************************/ |
10 | | |
11 | | /* |
12 | | |
13 | | 2008 - Driver Updates |
14 | | --------------------- |
15 | | |
16 | | (most of the informations are taken from http://www.zimmers.net/cbmpics/ ) |
17 | | |
18 | | |
19 | | [CBM systems which belong to this driver] |
20 | | |
21 | | * Commodore 116 (1984, Europe only) |
22 | | |
23 | | Entry level computer of the Commodore 264 family, it was marketed only |
24 | | in Europe. It was impressive for the small size of its case, but it didn't |
25 | | meet commercial success |
26 | | |
27 | | CPU: MOS Technology 7501 (variable clock rate, with max 1.76 MHz) |
28 | | RAM: 16 kilobytes (expandable to 64k internally) |
29 | | ROM: 32 kilobytes |
30 | | Video: MOS Technology 7360 "TED" (5 Video modes; Max. Resolution 320x200; |
31 | | 40 columns text; Palette of 16 colors in 8 shades, for 128 colors) |
32 | | Sound: MOS Technology 7360 "TED" (2 voice tone-generating sound capabilities) |
33 | | Ports: MOS 7360 (2 Joystick/Mouse ports; CBM Serial port; 'TED' port; "TV" |
34 | | Port and switch; CBM Monitor port; Power and reset switches; Power |
35 | | connector) |
36 | | Keyboard: QWERTY 62 key "membrane" (8 programmable function keys; 4 direction |
37 | | cursor-pad) |
38 | | |
39 | | |
40 | | * Commodore 16 (1984) |
41 | | |
42 | | Redesigned version of the C116, with a different case and a different |
43 | | keyboard. |
44 | | |
45 | | CPU: MOS Technology 7501 (variable clock rate, with max 1.76 MHz) |
46 | | RAM: 16 kilobytes (expandable to 64k internally) |
47 | | ROM: 32 kilobytes |
48 | | Video: MOS Technology 7360 "TED" (5 Video modes; Max. Resolution 320x200; |
49 | | 40 columns text; Palette of 16 colors in 8 shades, for 128 colors) |
50 | | Sound: MOS Technology 7360 "TED" (2 voice tone-generating sound capabilities) |
51 | | Ports: MOS 7360 (2 Joystick/Mouse ports; CBM Serial port; 'TED' port; "TV" |
52 | | Port and switch; CBM Monitor port; Power and reset switches; Power |
53 | | connector) |
54 | | Keyboard: QWERTY 66 key typewriter style (8 programmable function keys; |
55 | | 4 direction cursor-pad) |
56 | | |
57 | | |
58 | | * Commodore Plus/4 (1984) |
59 | | |
60 | | This system became the middle tier of the Commodore 264 family, replacing |
61 | | the original Commodore 264. The Plus/4 is basically the same as the C264, |
62 | | but the name refers to the four built-in programs which came with the |
63 | | machine: Word Processing, Spreadsheet, Database software, Graphing package. |
64 | | |
65 | | CPU: MOS Technology 7501 (variable clock rate, with max 1.76 MHz) |
66 | | RAM: 64 kilobytes (expandable to 64k internally) |
67 | | ROM: 64 kilobytes |
68 | | Video: MOS Technology 7360 "TED" (5 Video modes; Max. Resolution 320x200; |
69 | | 40 columns text; Palette of 16 colors in 8 shades, for 128 colors) |
70 | | Sound: MOS Technology 7360 "TED" (2 voice tone-generating sound capabilities) |
71 | | Ports: MOS 7360 (2 Joystick/Mouse ports; CBM Serial port; 'TED' port; "TV" |
72 | | Port and switch; CBM Monitor port; Power and reset switches; Power |
73 | | connector) |
74 | | Keyboard: Full-sized QWERTY 67 key (8 programmable function keys; |
75 | | 4 direction cursor-pad) |
76 | | |
77 | | |
78 | | * Commodore 232 (1984, Prototype) |
79 | | |
80 | | This system never reached the production and only few units exist. It is |
81 | | in between the C16 and the C264, with its 32 kilobytes of RAM. |
82 | | |
83 | | |
84 | | * Commodore 264 (1984, Prototype) |
85 | | |
86 | | Basically the same of a Plus/4 but without the built-in programs. |
87 | | |
88 | | |
89 | | * Commodore V364 (1984, Prototype) |
90 | | |
91 | | This system was supposed to become the high-end system of the family, |
92 | | featuring 64 kilobytes of RAM, the same technology of the Plus/4, a |
93 | | keyboard with numeric keypad and built in voice synthesis capabilities. |
94 | | |
95 | | [TO DO] |
96 | | |
97 | | * Supported Systems: |
98 | | |
99 | | - Once we can add / remove devices, we shall only support c16, c116 and plus/4, |
100 | | removing the separated drivers for different floppy drives |
101 | | |
102 | | * Other Peripherals: |
103 | | |
104 | | - Lightpen support is unfinished |
105 | | - Missing support for (it might or might not be added eventually): |
106 | | printers and other devices; most expansion modules; userport; rs232/v.24 interface. |
107 | | |
108 | | * System Specific |
109 | | |
110 | | - V364 lacks speech hardware emulation |
111 | | |
112 | | */ |
113 | | |
114 | | |
115 | | #include "emu.h" |
116 | | #include "audio/ted7360.h" |
117 | | #include "audio/t6721.h" |
118 | | #include "cpu/m6502/m6502.h" |
119 | | #include "machine/ram.h" |
120 | | #include "formats/cbm_snqk.h" |
121 | | #include "includes/cbm.h" |
122 | | #include "includes/c16.h" |
123 | | #include "machine/c1551.h" |
124 | | #include "machine/cbmiec.h" |
125 | | #include "machine/cbmipt.h" |
126 | | #include "sound/sid6581.h" |
127 | | #include "machine/plus4exp.h" |
128 | | #include "machine/plus4user.h" |
129 | | |
130 | | |
131 | | /************************************* |
132 | | * |
133 | | * Main CPU memory handlers |
134 | | * |
135 | | *************************************/ |
136 | | |
137 | | |
138 | | /* |
139 | | * commodore c16/c116/plus 4 |
140 | | * 16 KByte (C16/C116) or 32 KByte or 64 KByte (plus4) RAM |
141 | | * 32 KByte Rom (C16/C116) 64 KByte Rom (plus4) |
142 | | * availability to append additional 64 KByte Rom |
143 | | * |
144 | | * ports 0xfd00 till 0xff3f are always read/writeable for the cpu |
145 | | * for the video interface chip it seams to read from |
146 | | * ram or from rom in this area |
147 | | * |
148 | | * writes go always to ram |
149 | | * only 16 KByte Ram mapped to 0x4000,0x8000,0xc000 |
150 | | * only 32 KByte Ram mapped to 0x8000 |
151 | | * |
152 | | * rom bank at 0x8000: 16K Byte(low bank) |
153 | | * first: basic |
154 | | * second(plus 4 only): plus4 rom low |
155 | | * third: expansion slot |
156 | | * fourth: expansion slot |
157 | | * rom bank at 0xc000: 16K Byte(high bank) |
158 | | * first: kernal |
159 | | * second(plus 4 only): plus4 rom high |
160 | | * third: expansion slot |
161 | | * fourth: expansion slot |
162 | | * writes to 0xfddx select rom banks: |
163 | | * address line 0 and 1: rom bank low |
164 | | * address line 2 and 3: rom bank high |
165 | | * |
166 | | * writes to 0xff3e switches to roms (0x8000 till 0xfd00, 0xff40 till 0xffff) |
167 | | * writes to 0xff3f switches to rams |
168 | | * |
169 | | * at 0xfc00 till 0xfcff is ram or rom kernal readable |
170 | | */ |
171 | | |
172 | | static ADDRESS_MAP_START(c16_map, AS_PROGRAM, 8, c16_state ) |
173 | | AM_RANGE(0x0000, 0x3fff) AM_RAMBANK("bank9") |
174 | | AM_RANGE(0x4000, 0x7fff) AM_READ_BANK("bank1") AM_WRITE_BANK("bank5") /* only ram memory configuration */ |
175 | | AM_RANGE(0x8000, 0xbfff) AM_READ_BANK("bank2") AM_WRITE_BANK("bank6") |
176 | | AM_RANGE(0xc000, 0xfbff) AM_READ_BANK("bank3") |
177 | | AM_RANGE(0xfc00, 0xfcff) AM_READ_BANK("bank4") |
178 | | AM_RANGE(0xc000, 0xfcff) AM_WRITE_BANK("bank7") |
179 | | AM_RANGE(0xfd10, 0xfd1f) AM_READ_LEGACY(c16_fd1x_r) |
180 | | AM_RANGE(0xfd30, 0xfd3f) AM_READWRITE_LEGACY(c16_6529_port_r, c16_6529_port_w) /* 6529 keyboard matrix */ |
181 | | AM_RANGE(0xfdd0, 0xfddf) AM_WRITE_LEGACY(c16_select_roms) /* rom chips selection */ |
182 | | AM_RANGE(0xff00, 0xff1f) AM_DEVREADWRITE_LEGACY("ted7360", ted7360_port_r, ted7360_port_w) |
183 | | AM_RANGE(0xff20, 0xffff) AM_READ_BANK("bank8") |
184 | | AM_RANGE(0xff3e, 0xff3e) AM_WRITE_LEGACY(c16_switch_to_rom) |
185 | | AM_RANGE(0xff3f, 0xff3f) AM_WRITE_LEGACY(c16_switch_to_ram) |
186 | | ADDRESS_MAP_END |
187 | | |
188 | | static ADDRESS_MAP_START(plus4_map, AS_PROGRAM, 8, c16_state ) |
189 | | AM_RANGE(0x0000, 0x7fff) AM_READ_BANK("bank9") |
190 | | AM_RANGE(0x8000, 0xbfff) AM_READ_BANK("bank2") |
191 | | AM_RANGE(0xc000, 0xfbff) AM_READ_BANK("bank3") |
192 | | AM_RANGE(0xfc00, 0xfcff) AM_READ_BANK("bank4") |
193 | | AM_RANGE(0x0000, 0xfcff) AM_WRITE_BANK("bank9") |
194 | | AM_RANGE(0xfd00, 0xfd0f) AM_READWRITE_LEGACY(c16_6551_port_r, c16_6551_port_w) |
195 | | AM_RANGE(0xfd10, 0xfd1f) AM_READWRITE_LEGACY(plus4_6529_port_r, plus4_6529_port_w) |
196 | | AM_RANGE(0xfd30, 0xfd3f) AM_READWRITE_LEGACY(c16_6529_port_r, c16_6529_port_w) /* 6529 keyboard matrix */ |
197 | | AM_RANGE(0xfdd0, 0xfddf) AM_WRITE_LEGACY(c16_select_roms) /* rom chips selection */ |
198 | | AM_RANGE(0xff00, 0xff1f) AM_DEVREADWRITE_LEGACY("ted7360", ted7360_port_r, ted7360_port_w) |
199 | | AM_RANGE(0xff20, 0xffff) AM_READ_BANK("bank8") |
200 | | AM_RANGE(0xff20, 0xff3d) AM_WRITEONLY |
201 | | AM_RANGE(0xff3e, 0xff3e) AM_WRITE_LEGACY(c16_switch_to_rom) |
202 | | AM_RANGE(0xff3f, 0xff3f) AM_WRITE_LEGACY(c16_switch_to_ram) |
203 | | AM_RANGE(0xff40, 0xffff) AM_WRITEONLY |
204 | | ADDRESS_MAP_END |
205 | | |
206 | | static ADDRESS_MAP_START(c364_map , AS_PROGRAM, 8, c16_state ) |
207 | | AM_RANGE(0x0000, 0x7fff) AM_READ_BANK("bank9") |
208 | | AM_RANGE(0x8000, 0xbfff) AM_READ_BANK("bank2") |
209 | | AM_RANGE(0xc000, 0xfbff) AM_READ_BANK("bank3") |
210 | | AM_RANGE(0xfc00, 0xfcff) AM_READ_BANK("bank4") |
211 | | AM_RANGE(0x0000, 0xfcff) AM_WRITE_BANK("bank9") |
212 | | AM_RANGE(0xfd00, 0xfd0f) AM_READWRITE_LEGACY(c16_6551_port_r, c16_6551_port_w) |
213 | | AM_RANGE(0xfd10, 0xfd1f) AM_READWRITE_LEGACY(plus4_6529_port_r, plus4_6529_port_w) |
214 | | AM_RANGE(0xfd20, 0xfd2f) AM_DEVREADWRITE_LEGACY("t6721", t6721_speech_r, t6721_speech_w) |
215 | | AM_RANGE(0xfd30, 0xfd3f) AM_READWRITE_LEGACY(c16_6529_port_r, c16_6529_port_w) /* 6529 keyboard matrix */ |
216 | | AM_RANGE(0xfdd0, 0xfddf) AM_WRITE_LEGACY(c16_select_roms) /* rom chips selection */ |
217 | | AM_RANGE(0xff00, 0xff1f) AM_DEVREADWRITE_LEGACY("ted7360", ted7360_port_r, ted7360_port_w) |
218 | | AM_RANGE(0xff20, 0xffff) AM_READ_BANK("bank8") |
219 | | AM_RANGE(0xff20, 0xff3d) AM_WRITEONLY |
220 | | AM_RANGE(0xff3e, 0xff3e) AM_WRITE_LEGACY(c16_switch_to_rom) |
221 | | AM_RANGE(0xff3f, 0xff3f) AM_WRITE_LEGACY(c16_switch_to_ram) |
222 | | AM_RANGE(0xff40, 0xffff) AM_WRITEONLY |
223 | | ADDRESS_MAP_END |
224 | | |
225 | | |
226 | | /************************************* |
227 | | * |
228 | | * Input Ports |
229 | | * |
230 | | *************************************/ |
231 | | |
232 | | static INPUT_PORTS_START( c16 ) |
233 | | PORT_INCLUDE( common_cbm_keyboard ) /* ROW0 -> ROW7 */ |
234 | | |
235 | | PORT_MODIFY("ROW0") |
236 | | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("@") PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('@') |
237 | | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3)) PORT_CHAR(UCHAR_MAMEKEY(F6)) |
238 | | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2)) PORT_CHAR(UCHAR_MAMEKEY(F5)) |
239 | | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1)) PORT_CHAR(UCHAR_MAMEKEY(F4)) |
240 | | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("HELP f7") PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F8)) PORT_CHAR(UCHAR_MAMEKEY(F7)) |
241 | | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_INSERT) PORT_CHAR(0xA3) |
242 | | |
243 | | PORT_MODIFY("ROW1") |
244 | | /* Both Shift keys were mapped to the same bit */ |
245 | | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Shift (Left & Right)") PORT_CODE(KEYCODE_LSHIFT) PORT_CODE(KEYCODE_RSHIFT) |
246 | | |
247 | | PORT_MODIFY("ROW4") |
248 | | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("0 \xE2\x86\x91") PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(0x2191) |
249 | | |
250 | | PORT_MODIFY("ROW5") |
251 | | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("-") PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') |
252 | | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSLASH2) PORT_CHAR(UCHAR_MAMEKEY(UP)) |
253 | | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_PGUP) PORT_CHAR(UCHAR_MAMEKEY(DOWN)) |
254 | | |
255 | | PORT_MODIFY("ROW6") |
256 | | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR('+') |
257 | | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("= Pi \xE2\x86\x90") PORT_CODE(KEYCODE_PGDN) PORT_CHAR('=') PORT_CHAR(0x03C0) PORT_CHAR(0x2190) |
258 | | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC)) |
259 | | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) |
260 | | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('*') |
261 | | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_MINUS) PORT_CHAR(UCHAR_MAMEKEY(LEFT)) |
262 | | |
263 | | PORT_MODIFY("ROW7") |
264 | | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Home Clear") PORT_CODE(KEYCODE_DEL) PORT_CHAR(UCHAR_MAMEKEY(HOME)) |
265 | | |
266 | | PORT_INCLUDE( c16_special ) /* SPECIAL */ |
267 | | |
268 | | PORT_INCLUDE( c16_controls ) /* CTRLSEL, JOY0, JOY1 */ |
269 | | INPUT_PORTS_END |
270 | | |
271 | | |
272 | | static INPUT_PORTS_START( plus4 ) |
273 | | PORT_INCLUDE( c16 ) |
274 | | |
275 | | PORT_MODIFY( "ROW0" ) |
276 | | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(0xA3) |
277 | | PORT_MODIFY( "ROW5" ) |
278 | | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('-') |
279 | | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP)) |
280 | | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN)) |
281 | | PORT_MODIFY( "ROW6" ) |
282 | | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('+') |
283 | | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("= Pi \xE2\x86\x90") PORT_CODE(KEYCODE_BACKSLASH2) PORT_CHAR('=') PORT_CHAR(0x03C0) PORT_CHAR(0x2190) |
284 | | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) |
285 | | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_INSERT) PORT_CHAR('*') |
286 | | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT)) |
287 | | INPUT_PORTS_END |
288 | | |
289 | | static INPUT_PORTS_START( c16sid ) |
290 | | PORT_INCLUDE( c16 ) |
291 | | |
292 | | PORT_START("SID") |
293 | | PORT_CONFNAME( 0x01, 0x00, "SID Card Address") |
294 | | PORT_CONFSETTING( 0x00, "0xfd40" ) |
295 | | PORT_CONFSETTING( 0x01, "0xfe80" ) |
296 | | #if 0 |
297 | | PORT_CONFNAME( 0x02, 0x00, "Enable SID writes to 0xd400") |
298 | | PORT_CONFSETTING( 0x00, DEF_STR( No ) ) |
299 | | PORT_CONFSETTING( 0x02, DEF_STR( Yes ) ) |
300 | | #endif |
301 | | INPUT_PORTS_END |
302 | | |
303 | | |
304 | | static INPUT_PORTS_START( plus4sid ) |
305 | | PORT_INCLUDE( plus4 ) |
306 | | |
307 | | PORT_START("SID") |
308 | | PORT_CONFNAME( 0x01, 0x00, "SID Card Address") |
309 | | PORT_CONFSETTING( 0x00, "0xfd40" ) |
310 | | PORT_CONFSETTING( 0x01, "0xfe80" ) |
311 | | #if 0 |
312 | | PORT_CONFNAME( 0x02, 0x00, "Enable SID writes to 0xd400") |
313 | | PORT_CONFSETTING( 0x00, DEF_STR( No ) ) |
314 | | PORT_CONFSETTING( 0x02, DEF_STR( Yes ) ) |
315 | | #endif |
316 | | INPUT_PORTS_END |
317 | | |
318 | | |
319 | | /************************************* |
320 | | * |
321 | | * Graphics definitions |
322 | | * |
323 | | *************************************/ |
324 | | |
325 | | static const unsigned char ted7360_palette[] = |
326 | | { |
327 | | /* black, white, red, cyan */ |
328 | | /* purple, green, blue, yellow */ |
329 | | /* orange, light orange, pink, light cyan, */ |
330 | | /* light violett, light green, light blue, light yellow */ |
331 | | /* these 16 colors are 8 times here in different luminance (dark..light) */ |
332 | | /* taken from digitized tv screenshot */ |
333 | | 0x06, 0x01, 0x03, 0x2b, 0x2b, 0x2b, 0x67, 0x0e, 0x0f, 0x00, 0x3f, 0x42, |
334 | | 0x57, 0x00, 0x6d, 0x00, 0x4e, 0x00, 0x19, 0x1c, 0x94, 0x38, 0x38, 0x00, |
335 | | 0x56, 0x20, 0x00, 0x4b, 0x28, 0x00, 0x16, 0x48, 0x00, 0x69, 0x07, 0x2f, |
336 | | 0x00, 0x46, 0x26, 0x06, 0x2a, 0x80, 0x2a, 0x14, 0x9b, 0x0b, 0x49, 0x00, |
337 | | |
338 | | 0x00, 0x03, 0x02, 0x3d, 0x3d, 0x3d, 0x75, 0x1e, 0x20, 0x00, 0x50, 0x4f, |
339 | | 0x6a, 0x10, 0x78, 0x04, 0x5c, 0x00, 0x2a, 0x2a, 0xa3, 0x4c, 0x47, 0x00, |
340 | | 0x69, 0x2f, 0x00, 0x59, 0x38, 0x00, 0x26, 0x56, 0x00, 0x75, 0x15, 0x41, |
341 | | 0x00, 0x58, 0x3d, 0x15, 0x3d, 0x8f, 0x39, 0x22, 0xae, 0x19, 0x59, 0x00, |
342 | | |
343 | | 0x00, 0x03, 0x04, 0x42, 0x42, 0x42, 0x7b, 0x28, 0x20, 0x02, 0x56, 0x59, |
344 | | 0x6f, 0x1a, 0x82, 0x0a, 0x65, 0x09, 0x30, 0x34, 0xa7, 0x50, 0x51, 0x00, |
345 | | 0x6e, 0x36, 0x00, 0x65, 0x40, 0x00, 0x2c, 0x5c, 0x00, 0x7d, 0x1e, 0x45, |
346 | | 0x01, 0x61, 0x45, 0x1c, 0x45, 0x99, 0x42, 0x2d, 0xad, 0x1d, 0x62, 0x00, |
347 | | |
348 | | 0x05, 0x00, 0x02, 0x56, 0x55, 0x5a, 0x90, 0x3c, 0x3b, 0x17, 0x6d, 0x72, |
349 | | 0x87, 0x2d, 0x99, 0x1f, 0x7b, 0x15, 0x46, 0x49, 0xc1, 0x66, 0x63, 0x00, |
350 | | 0x84, 0x4c, 0x0d, 0x73, 0x55, 0x00, 0x40, 0x72, 0x00, 0x91, 0x33, 0x5e, |
351 | | 0x19, 0x74, 0x5c, 0x32, 0x59, 0xae, 0x59, 0x3f, 0xc3, 0x32, 0x76, 0x00, |
352 | | |
353 | | 0x02, 0x01, 0x06, 0x84, 0x7e, 0x85, 0xbb, 0x67, 0x68, 0x45, 0x96, 0x96, |
354 | | 0xaf, 0x58, 0xc3, 0x4a, 0xa7, 0x3e, 0x73, 0x73, 0xec, 0x92, 0x8d, 0x11, |
355 | | 0xaf, 0x78, 0x32, 0xa1, 0x80, 0x20, 0x6c, 0x9e, 0x12, 0xba, 0x5f, 0x89, |
356 | | 0x46, 0x9f, 0x83, 0x61, 0x85, 0xdd, 0x84, 0x6c, 0xef, 0x5d, 0xa3, 0x29, |
357 | | |
358 | | 0x02, 0x00, 0x0a, 0xb2, 0xac, 0xb3, 0xe9, 0x92, 0x92, 0x6c, 0xc3, 0xc1, |
359 | | 0xd9, 0x86, 0xf0, 0x79, 0xd1, 0x76, 0x9d, 0xa1, 0xff, 0xbd, 0xbe, 0x40, |
360 | | 0xdc, 0xa2, 0x61, 0xd1, 0xa9, 0x4c, 0x93, 0xc8, 0x3d, 0xe9, 0x8a, 0xb1, |
361 | | 0x6f, 0xcd, 0xab, 0x8a, 0xb4, 0xff, 0xb2, 0x9a, 0xff, 0x88, 0xcb, 0x59, |
362 | | |
363 | | 0x02, 0x00, 0x0a, 0xc7, 0xca, 0xc9, 0xff, 0xac, 0xac, 0x85, 0xd8, 0xe0, |
364 | | 0xf3, 0x9c, 0xff, 0x92, 0xea, 0x8a, 0xb7, 0xba, 0xff, 0xd6, 0xd3, 0x5b, |
365 | | 0xf3, 0xbe, 0x79, 0xe6, 0xc5, 0x65, 0xb0, 0xe0, 0x57, 0xff, 0xa4, 0xcf, |
366 | | 0x89, 0xe5, 0xc8, 0xa4, 0xca, 0xff, 0xca, 0xb3, 0xff, 0xa2, 0xe5, 0x7a, |
367 | | |
368 | | 0x01, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xf6, 0xf2, 0xd1, 0xff, 0xff, |
369 | | 0xff, 0xe9, 0xff, 0xdb, 0xff, 0xd3, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xa3, |
370 | | 0xff, 0xff, 0xc1, 0xff, 0xff, 0xb2, 0xfc, 0xff, 0xa2, 0xff, 0xee, 0xff, |
371 | | 0xd1, 0xff, 0xff, 0xeb, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xed, 0xff, 0xbc |
372 | | }; |
373 | | |
374 | | static PALETTE_INIT( c16 ) |
375 | | { |
376 | | int i; |
377 | | |
378 | | for (i = 0; i < sizeof(ted7360_palette) / 3; i++) |
379 | | palette_set_color_rgb(machine, i, ted7360_palette[i * 3], ted7360_palette[i * 3 + 1], ted7360_palette[i * 3 + 2]); |
380 | | } |
381 | | |
382 | | /************************************* |
383 | | * |
384 | | * TED7360 interfaces |
385 | | * |
386 | | *************************************/ |
387 | | |
388 | | static const ted7360_interface c16_ted7360_intf = { |
389 | | "screen", |
390 | | TED7360_PAL, |
391 | | c16_dma_read, |
392 | | c16_dma_read_rom, |
393 | | c16_interrupt, |
394 | | c16_read_keyboard |
395 | | }; |
396 | | |
397 | | static const ted7360_interface plus4_ted7360_intf = { |
398 | | "screen", |
399 | | TED7360_NTSC, |
400 | | c16_dma_read, |
401 | | c16_dma_read_rom, |
402 | | c16_interrupt, |
403 | | c16_read_keyboard |
404 | | }; |
405 | | |
406 | | |
407 | | /************************************* |
408 | | * |
409 | | * Machine driver |
410 | | * |
411 | | *************************************/ |
412 | | |
413 | | static const m6502_interface c16_m7501_interface = |
414 | | { |
415 | | NULL, /* read_indexed_func */ |
416 | | NULL, /* write_indexed_func */ |
417 | | DEVCB_HANDLER(c16_m7501_port_read), /* port_read_func */ |
418 | | DEVCB_HANDLER(c16_m7501_port_write) /* port_write_func */ |
419 | | }; |
420 | | |
421 | | static CBM_IEC_INTERFACE( cbm_iec_intf ) |
422 | | { |
423 | | DEVCB_NULL, |
424 | | DEVCB_NULL, |
425 | | DEVCB_NULL, |
426 | | DEVCB_NULL, |
427 | | DEVCB_NULL |
428 | | }; |
429 | | |
430 | | static PLUS4_EXPANSION_INTERFACE( expansion_intf ) |
431 | | { |
432 | | DEVCB_NULL, |
433 | | DEVCB_NULL, |
434 | | DEVCB_NULL, |
435 | | DEVCB_NULL, |
436 | | DEVCB_NULL |
437 | | }; |
438 | | |
439 | | static PLUS4_USER_PORT_INTERFACE( user_intf ) |
440 | | { |
441 | | DEVCB_NULL |
442 | | }; |
443 | | |
444 | | static SCREEN_UPDATE_IND16( c16 ) |
445 | | { |
446 | | c16_state *state = screen.machine().driver_data<c16_state>(); |
447 | | ted7360_video_update(state->m_ted7360, bitmap, cliprect); |
448 | | return 0; |
449 | | } |
450 | | |
451 | | static INTERRUPT_GEN( c16_raster_interrupt ) |
452 | | { |
453 | | c16_state *state = device->machine().driver_data<c16_state>(); |
454 | | ted7360_raster_interrupt_gen(state->m_ted7360); |
455 | | } |
456 | | |
457 | | |
458 | | static MACHINE_START( c16 ) |
459 | | { |
460 | | c16_state *state = machine.driver_data<c16_state>(); |
461 | | |
462 | | state->m_maincpu = machine.device<legacy_cpu_device>("maincpu"); |
463 | | state->m_ted7360 = machine.device("ted7360"); |
464 | | state->m_cassette = machine.device<cassette_image_device>(CASSETTE_TAG); |
465 | | state->m_messram = machine.device<ram_device>(RAM_TAG); |
466 | | state->m_sid = machine.device("sid"); |
467 | | |
468 | | state->save_item(NAME(state->m_old_level)); |
469 | | state->save_item(NAME(state->m_lowrom)); |
470 | | state->save_item(NAME(state->m_highrom)); |
471 | | state->save_item(NAME(state->m_port6529)); |
472 | | state->save_item(NAME(state->m_keyline)); |
473 | | } |
474 | | |
475 | | static MACHINE_CONFIG_START( c16, c16_state ) |
476 | | /* basic machine hardware */ |
477 | | MCFG_CPU_ADD("maincpu", M7501, XTAL_17_73447MHz/20) |
478 | | MCFG_CPU_PROGRAM_MAP(c16_map) |
479 | | MCFG_CPU_CONFIG( c16_m7501_interface ) |
480 | | MCFG_CPU_VBLANK_INT("screen", c16_frame_interrupt) |
481 | | MCFG_CPU_PERIODIC_INT(c16_raster_interrupt, TED7360_HRETRACERATE) |
482 | | MCFG_QUANTUM_TIME(attotime::from_hz(60)) |
483 | | |
484 | | MCFG_MACHINE_START( c16 ) |
485 | | MCFG_MACHINE_RESET( c16 ) |
486 | | |
487 | | /* video hardware */ |
488 | | MCFG_SCREEN_ADD("screen", RASTER) |
489 | | MCFG_SCREEN_REFRESH_RATE(TED7360PAL_VRETRACERATE) |
490 | | MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) /* not accurate */ |
491 | | MCFG_SCREEN_SIZE(336, 216) |
492 | | MCFG_SCREEN_VISIBLE_AREA(0, 336 - 1, 0, 216 - 1) |
493 | | MCFG_SCREEN_UPDATE_STATIC( c16 ) |
494 | | |
495 | | MCFG_PALETTE_LENGTH(ARRAY_LENGTH(ted7360_palette) / 3) |
496 | | MCFG_PALETTE_INIT(c16) |
497 | | |
498 | | /* sound hardware */ |
499 | | MCFG_SPEAKER_STANDARD_MONO("mono") |
500 | | MCFG_TED7360_ADD("ted7360", c16_ted7360_intf) |
501 | | MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25) |
502 | | |
503 | | /* devices */ |
504 | | MCFG_QUICKLOAD_ADD("quickload", cbm_c16, "p00,prg", CBM_QUICKLOAD_DELAY_SECONDS) |
505 | | |
506 | | /* cassette */ |
507 | | MCFG_CASSETTE_ADD( CASSETTE_TAG, cbm_cassette_interface ) |
508 | | |
509 | | MCFG_FRAGMENT_ADD(c16_cartslot) |
510 | | |
511 | | MCFG_C1551_ADD(C1551_TAG, 8) |
512 | | MCFG_SOFTWARE_LIST_ADD("disk_list", "plus4_flop") |
513 | | |
514 | | /* IEC serial bus */ |
515 | | MCFG_CBM_IEC_ADD(cbm_iec_intf, NULL) |
516 | | |
517 | | MCFG_PLUS4_EXPANSION_SLOT_ADD(PLUS4_EXPANSION_SLOT_TAG, XTAL_17_73447MHz/20, expansion_intf, plus4_expansion_cards, NULL, NULL) |
518 | | MCFG_PLUS4_USER_PORT_ADD(PLUS4_USER_PORT_TAG, user_intf, plus4_user_port_cards, NULL, NULL) |
519 | | |
520 | | /* internal ram */ |
521 | | MCFG_RAM_ADD(RAM_TAG) |
522 | | MCFG_RAM_DEFAULT_SIZE("64K") |
523 | | MCFG_RAM_EXTRA_OPTIONS("16K,32K") |
524 | | MACHINE_CONFIG_END |
525 | | |
526 | | static MACHINE_CONFIG_DERIVED( plus4, c16 ) |
527 | | MCFG_CPU_MODIFY( "maincpu" ) |
528 | | MCFG_CPU_CLOCK( XTAL_14_31818MHz/16 ) |
529 | | MCFG_CPU_PROGRAM_MAP(plus4_map) |
530 | | MCFG_CPU_CONFIG( c16_m7501_interface ) |
531 | | |
532 | | MCFG_SCREEN_MODIFY("screen") |
533 | | MCFG_SCREEN_REFRESH_RATE(TED7360NTSC_VRETRACERATE) |
534 | | |
535 | | MCFG_DEVICE_REMOVE("ted7360") |
536 | | MCFG_TED7360_ADD("ted7360", plus4_ted7360_intf) |
537 | | MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25) |
538 | | |
539 | | /* internal ram */ |
540 | | MCFG_RAM_MODIFY(RAM_TAG) |
541 | | MCFG_RAM_DEFAULT_SIZE("64K") |
542 | | MACHINE_CONFIG_END |
543 | | |
544 | | static MACHINE_CONFIG_DERIVED( c364, plus4 ) |
545 | | MCFG_SCREEN_MODIFY("screen") |
546 | | MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) /* not accurate */ |
547 | | MCFG_CPU_MODIFY( "maincpu" ) |
548 | | MCFG_CPU_PROGRAM_MAP(c364_map) |
549 | | |
550 | | MCFG_T6721_ADD("t6721") |
551 | | MACHINE_CONFIG_END |
552 | | |
553 | | static MACHINE_CONFIG_DERIVED( c264, c16 ) |
554 | | /* internal ram */ |
555 | | MCFG_RAM_MODIFY(RAM_TAG) |
556 | | MCFG_RAM_DEFAULT_SIZE("64K") |
557 | | MACHINE_CONFIG_END |
558 | | |
559 | | static MACHINE_CONFIG_DERIVED( c16sid, c16 ) |
560 | | |
561 | | MCFG_SOUND_ADD("sid", SID8580, TED7360PAL_CLOCK/4) |
562 | | MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25) |
563 | | MACHINE_CONFIG_END |
564 | | |
565 | | static MACHINE_CONFIG_DERIVED( plus4sid, plus4 ) |
566 | | |
567 | | MCFG_SOUND_ADD("sid", SID8580, TED7360NTSC_CLOCK/4) |
568 | | MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25) |
569 | | MACHINE_CONFIG_END |
570 | | |
571 | | |
572 | | /************************************* |
573 | | * |
574 | | * ROM definition(s) |
575 | | * |
576 | | *************************************/ |
577 | | ROM_START( c232 ) |
578 | | ROM_REGION( 0x40000, "maincpu", 0 ) |
579 | | ROM_LOAD( "318006-01.bin", 0x10000, 0x4000, CRC(74eaae87) SHA1(161c96b4ad20f3a4f2321808e37a5ded26a135dd) ) |
580 | | ROM_LOAD( "318004-01.bin", 0x14000, 0x4000, CRC(dbdc3319) SHA1(3c77caf72914c1c0a0875b3a7f6935cd30c54201) ) |
581 | | ROM_END |
582 | | |
583 | | ROM_START( c264 ) |
584 | | ROM_REGION( 0x40000, "maincpu", 0 ) |
585 | | ROM_LOAD( "basic-264.bin", 0x10000, 0x4000, CRC(6a2fc8e3) SHA1(473fce23afa07000cdca899fbcffd6961b36a8a0) ) |
586 | | ROM_LOAD( "kernal-264.bin", 0x14000, 0x4000, CRC(8f32abe7) SHA1(d481faf5fcbb331878dc7851c642d04f26a32873) ) |
587 | | ROM_END |
588 | | |
589 | | ROM_START( c364 ) |
590 | | ROM_REGION( 0x40000, "maincpu", 0 ) |
591 | | ROM_LOAD( "318006.01", 0x10000, 0x4000, CRC(74eaae87) SHA1(161c96b4ad20f3a4f2321808e37a5ded26a135dd) ) |
592 | | ROM_LOAD( "kern364p.bin", 0x14000, 0x4000, CRC(84fd4f7a) SHA1(b9a5b5dacd57ca117ef0b3af29e91998bf4d7e5f) ) |
593 | | ROM_LOAD( "317053-01.bin", 0x18000, 0x4000, CRC(4fd1d8cb) SHA1(3b69f6e7cb4c18bb08e203fb18b7dabfa853390f) ) |
594 | | ROM_LOAD( "317054-01.bin", 0x1c000, 0x4000, CRC(109de2fc) SHA1(0ad7ac2db7da692d972e586ca0dfd747d82c7693) ) |
595 | | /* at address 0x20000 not so good */ |
596 | | ROM_LOAD( "spk3cc4.bin", 0x28000, 0x4000, CRC(5227c2ee) SHA1(59af401cbb2194f689898271c6e8aafa28a7af11) ) |
597 | | ROM_END |
598 | | |
599 | | |
600 | | ROM_START( c16 ) |
601 | | ROM_REGION( 0x40000, "maincpu", 0 ) |
602 | | ROM_DEFAULT_BIOS("r5") |
603 | | ROM_LOAD( "318006-01.u3", 0x10000, 0x4000, CRC(74eaae87) SHA1(161c96b4ad20f3a4f2321808e37a5ded26a135dd) ) |
604 | | |
605 | | ROM_SYSTEM_BIOS( 0, "r3", "rev. 3" ) |
606 | | ROMX_LOAD( "318004-03.u4", 0x14000, 0x4000, CRC(77bab934) SHA1(97814dab9d757fe5a3a61d357a9a81da588a9783), ROM_BIOS(1) ) |
607 | | ROM_SYSTEM_BIOS( 1, "r4", "rev. 4" ) |
608 | | ROMX_LOAD( "318004-04.u4", 0x14000, 0x4000, CRC(be54ed79) SHA1(514ad3c29d01a2c0a3b143d9c1d4143b1912b793), ROM_BIOS(2) ) |
609 | | ROM_SYSTEM_BIOS( 2, "r5", "rev. 5" ) |
610 | | ROMX_LOAD( "318004-05.u4", 0x14000, 0x4000, CRC(71c07bd4) SHA1(7c7e07f016391174a557e790c4ef1cbe33512cdb), ROM_BIOS(3) ) |
611 | | ROM_END |
612 | | |
613 | | #define rom_c16c rom_c16 |
614 | | #define rom_c16v rom_c16 |
615 | | |
616 | | #define rom_c116 rom_c16 |
617 | | #define rom_c116c rom_c16c |
618 | | #define rom_c116v rom_c16v |
619 | | |
620 | | ROM_START( c16hun ) |
621 | | ROM_REGION( 0x40000, "maincpu", 0 ) |
622 | | ROM_LOAD( "318006-01.u3", 0x10000, 0x4000, CRC(74eaae87) SHA1(161c96b4ad20f3a4f2321808e37a5ded26a135dd) ) |
623 | | ROM_LOAD( "hungary.u4", 0x14000, 0x4000, CRC(775f60c5) SHA1(20cf3c4bf6c54ef09799af41887218933f2e27ee) ) |
624 | | ROM_END |
625 | | |
626 | | ROM_START( plus4 ) |
627 | | ROM_REGION( 0x40000, "maincpu", 0 ) |
628 | | ROM_DEFAULT_BIOS("r5") |
629 | | ROM_SYSTEM_BIOS( 0, "r4", "rev. 4" ) |
630 | | ROMX_LOAD( "318005-04.u24", 0x14000, 0x4000, CRC(799a633d) SHA1(5df52c693387c0e2b5d682613a3b5a65477311cf), ROM_BIOS(1) ) |
631 | | ROM_SYSTEM_BIOS( 1, "r5", "rev. 5" ) |
632 | | ROMX_LOAD( "318005-05.u24", 0x14000, 0x4000, CRC(70295038) SHA1(a3d9e5be091b98de39a046ab167fb7632d053682), ROM_BIOS(2) ) |
633 | | ROM_SYSTEM_BIOS( 2, "jiffydos", "JiffyDOS v6.01" ) |
634 | | ROMX_LOAD( "jiffydos plus4.u24", 0x10000, 0x8000, CRC(818d3f45) SHA1(9bc1b1c3da9ca642deae717905f990d8e36e6c3b), ROM_BIOS(3) ) |
635 | | |
636 | | ROM_LOAD( "318006-01.u23", 0x10000, 0x4000, CRC(74eaae87) SHA1(161c96b4ad20f3a4f2321808e37a5ded26a135dd) ) |
637 | | |
638 | | ROM_LOAD( "317053-01.u25", 0x18000, 0x4000, CRC(4fd1d8cb) SHA1(3b69f6e7cb4c18bb08e203fb18b7dabfa853390f) ) |
639 | | ROM_LOAD( "317054-01.26", 0x1c000, 0x4000, CRC(109de2fc) SHA1(0ad7ac2db7da692d972e586ca0dfd747d82c7693) ) |
640 | | ROM_END |
641 | | |
642 | | #define rom_plus4c rom_plus4 |
643 | | #define rom_plus4v rom_plus4 |
644 | | |
645 | | #define rom_c16sid rom_c16 |
646 | | #define rom_plus4sid rom_plus4 |
647 | | |
648 | | /*************************************************************************** |
649 | | |
650 | | Game driver(s) |
651 | | |
652 | | ***************************************************************************/ |
653 | | |
654 | | /* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME FLAGS */ |
655 | | |
656 | | COMP( 1984, c16, 0, 0, c16, c16, c16_state, c16, "Commodore Business Machines", "Commodore 16 (PAL)", 0) |
657 | | COMP( 1984, c16hun, c16, 0, c16, c16, c16_state, c16, "Commodore Business Machines", "Commodore 16 Novotrade (PAL, Hungary)", 0) |
658 | | |
659 | | COMP( 1984, c116, c16, 0, c16, c16, c16_state, c16, "Commodore Business Machines", "Commodore 116 (PAL)", 0) |
660 | | |
661 | | COMP( 1984, plus4, c16, 0, plus4, plus4, c16_state, plus4, "Commodore Business Machines", "Commodore Plus/4 (NTSC)", 0) |
662 | | |
663 | | COMP( 1984, c232, c16, 0, c16, c16, c16_state, c16, "Commodore Business Machines", "Commodore 232 (Prototype)", 0) |
664 | | COMP( 1984, c264, c16, 0, c264, plus4, c16_state, plus4, "Commodore Business Machines", "Commodore 264 (Prototype)", 0) |
665 | | COMP( 1984, c364, c16, 0, c364, plus4, c16_state, plus4, "Commodore Business Machines", "Commodore V364 (Prototype)", GAME_IMPERFECT_SOUND) |
666 | | |
667 | | COMP( 1984, c16sid, c16, 0, c16sid, c16sid, c16_state, c16sid, "Commodore Business Machines", "Commodore 16 (PAL, SID Card)", GAME_UNOFFICIAL | GAME_IMPERFECT_SOUND) |
668 | | COMP( 1984, plus4sid, c16, 0, plus4sid, plus4sid, c16_state, plus4sid, "Commodore Business Machines", "Commodore Plus/4 (NTSC, SID Card)", GAME_UNOFFICIAL | GAME_IMPERFECT_SOUND) |