OSDN Git Service

[General] Convert sourcecode's CRLF format: DOS(WINDOWS) to Unix, to apply patches...
[csp-qt/common_source_project-fm7.git] / source / src / vm / x1 / psub.cpp
1 /*
2         SHARP X1 Emulator 'eX1'
3         SHARP X1twin Emulator 'eX1twin'
4         SHARP X1turbo Emulator 'eX1turbo'
5
6         Author : Takeda.Toshiya
7         Date   : 2009.03.15-
8
9         [ pseudo sub cpu ]
10 */
11
12 #include "psub.h"
13 #include "../datarec.h"
14 #include "../i8255.h"
15 #include "../../fifo.h"
16 #include "../../fileio.h"
17
18 //#define DEBUG_COMMAND
19
20 #define EVENT_1SEC      0
21 #define EVENT_DRIVE     1
22 #define EVENT_REPEAT    2
23
24 #define CMT_EJECT       0x00
25 #define CMT_STOP        0x01
26 #define CMT_PLAY        0x02
27 #define CMT_FAST_FWD    0x03
28 #define CMT_FAST_REW    0x04
29 #define CMT_APSS_PLUS   0x05
30 #define CMT_APSS_MINUS  0x06
31 #define CMT_REC         0x0a
32
33 // TODO: XFER = 0xe8 ???
34
35 static const uint8 keycode[256] = {     // normal
36         0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x08, 0x09, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00,
37         0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0xe8, 0x00, 0x00, 0x00,
38         0x20, 0x0e, 0x0f, 0x11, 0x0b, 0x1d, 0x1e, 0x1c, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x12, 0x08, 0x00,
39         0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
40         0x00, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
41         0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00,
42         0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
43         0x71, 0x72, 0x73, 0x74, 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
44         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
45         0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
46         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
47         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x3b, 0x2c, 0x2d, 0x2e, 0x2f,
48         0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
49         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b, 0x5c, 0x5d, 0x5e, 0x00,
50         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
51         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
52 };
53 static const uint8 keycode_s[256] = {   // shift
54         0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x12, 0x09, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00,
55         0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0xe8, 0x00, 0x00, 0x00,
56         0x20, 0x0e, 0x0f, 0x11, 0x0c, 0x1d, 0x1e, 0x1c, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x12, 0x08, 0x00,
57         0x30, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
58         0x00, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
59         0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00,
60         0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2a, 0x2b, 0x3c, 0x2d, 0x2e, 0x3f,
61         0x76, 0x77, 0x78, 0x79, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
62         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
63         0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
64         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
65         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x2b, 0x3c, 0x3d, 0x3e, 0x3f,
66         0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
67         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x60, 0x00,
68         0x00, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
69         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
70 };
71 static const uint8 keycode_g[256] = {   // graph
72         0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
73         0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0x00, 0x00, 0x00,
74         0x00, 0x0e, 0x0f, 0x11, 0x0b, 0x1d, 0x1e, 0x1c, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x12, 0x08, 0x00,
75         0xfa, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
76         0x00, 0x7f, 0x84, 0x82, 0xea, 0xe2, 0xeb, 0xec, 0xed, 0xe7, 0xee, 0xef, 0x8e, 0x86, 0x85, 0xf0,
77         0x8d, 0xe0, 0xe3, 0xe9, 0xe4, 0xe6, 0x83, 0xe1, 0x81, 0xe5, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
78         0x8f, 0x99, 0x92, 0x98, 0x95, 0x96, 0x94, 0x9a, 0x93, 0x97, 0x9b, 0x9d, 0x87, 0x9c, 0x91, 0x9e,
79         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
80         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
81         0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
82         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
83         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd, 0x89, 0x87, 0x8c, 0x88, 0xfe,
84         0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
85         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xfb, 0xe8, 0x8b, 0x00,
86         0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
87         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
88 };
89 static const uint8 keycode_c[256] = {   // ctrl
90         0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x08, 0x09, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00,
91         0x1c, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0xe8, 0x00, 0x00, 0x00,
92         0x00, 0x0e, 0x0f, 0x11, 0x0b, 0x1d, 0x1e, 0x1c, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x12, 0x08, 0x00,
93         0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
94         0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
95         0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00,
96         0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2a, 0x2b, 0x00, 0x2d, 0x2e, 0x2f,
97         0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0xeb, 0xe2, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
98         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
99         0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
100         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
101         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x3b, 0x00, 0x2d, 0x00, 0x00,
102         0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
103         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x1c, 0x1d, 0x1e, 0x00,
104         0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
105         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
106 };
107 static const uint8 keycode_k[256] = {   // kana
108         0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x08, 0x09, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00,
109         0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0xe8, 0x00, 0x00, 0x00,
110         0x20, 0x0e, 0x0f, 0x11, 0x0b, 0x1d, 0x1e, 0x1c, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x12, 0x08, 0x00,
111         0xdc, 0xc7, 0xcc, 0xb1, 0xb3, 0xb4, 0xb5, 0xd4, 0xd5, 0xd6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
112         0x00, 0xc1, 0xba, 0xbf, 0xbc, 0xb2, 0xca, 0xb7, 0xb8, 0xc6, 0xcf, 0xc9, 0xd8, 0xd3, 0xd0, 0xd7,
113         0xbe, 0xc0, 0xbd, 0xc4, 0xb6, 0xc5, 0xcb, 0xc3, 0xbb, 0xdd, 0xc2, 0x00, 0x00, 0x00, 0x00, 0x00,
114         0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2a, 0x2b, 0xc8, 0x2d, 0x2e, 0xd2,
115         0x71, 0x72, 0x73, 0x74, 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
116         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
117         0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
118         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
119         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb9, 0xda, 0xc8, 0xce, 0xd9, 0xd2,
120         0xde, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
121         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdf, 0xb0, 0xd1, 0xcd, 0x00,
122         0x00, 0x00, 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
123         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
124 };
125 static const uint8 keycode_ks[256] = {  // kana+shift
126         0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x12, 0x09, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00,
127         0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0xe8, 0x00, 0x00, 0x00,
128         0x20, 0x0e, 0x0f, 0x11, 0x0c, 0x1d, 0x1e, 0x1c, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x12, 0x08, 0x00,
129         0xa6, 0xc7, 0xcc, 0xa7, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
130         0x00, 0xc1, 0xba, 0xbf, 0xbc, 0xa8, 0xca, 0xb7, 0xb8, 0xc6, 0xcf, 0xc9, 0xd8, 0xd3, 0xd0, 0xd7,
131         0xbe, 0xc0, 0xbd, 0xc4, 0xb6, 0xc5, 0xcb, 0xc3, 0xbb, 0xdd, 0xaf, 0x00, 0x00, 0x00, 0x00, 0x00,
132         0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2a, 0x2b, 0xa4, 0x2d, 0x2e, 0xa5,
133         0x76, 0x77, 0x78, 0x79, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
134         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
135         0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
136         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
137         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb9, 0xda, 0xa4, 0xce, 0xa1, 0xa5,
138         0xde, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
139         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa2, 0xb0, 0xa3, 0xcd, 0x00,
140         0x00, 0x00, 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
141         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
142 };
143
144 void PSUB::initialize()
145 {
146         key_buf = new FIFO(8);
147         key_stat = emu->key_buffer();
148         
149         emu->get_host_time(&cur_time);
150         
151         // register events
152         register_event(this, EVENT_1SEC, 1000000, true, &time_register_id);
153         register_event(this, EVENT_DRIVE, 400, true, NULL);
154 }
155
156 void PSUB::release()
157 {
158         key_buf->release();
159         delete key_buf;
160 }
161
162 void PSUB::reset()
163 {
164         memset(databuf, 0, sizeof(databuf));
165         databuf[0x16][0] = 0xff;
166         datap = &databuf[0][0]; // temporary fix
167         mode = 0;
168         cmdlen = datalen = 0;
169         
170         play = rec = eot = false;
171         
172         ibf = true;
173         set_ibf(false);
174         obf = false;
175         set_obf(true);
176         
177         // key buffer
178         key_buf->clear();
179         key_prev = key_break = 0;
180         key_shift = key_ctrl = key_graph = false;
181         key_caps_locked = key_kana_locked = false;
182         key_register_id = -1;
183         
184         // interrupt
185         iei = true;
186         intr = false;
187         
188         // break
189         d_pio->write_signal(SIG_I8255_PORT_B, 0xff, 1);
190 }
191
192 void PSUB::write_io8(uint32 addr, uint32 data)
193 {
194         inbuf = data;
195         set_ibf(true);
196 }
197
198 uint32 PSUB::read_io8(uint32 addr)
199 {
200         set_obf(true);
201         intr = false;
202         update_intr();
203         return outbuf;
204 }
205
206 void PSUB::write_signal(int id, uint32 data, uint32 mask)
207 {
208         if(id == SIG_PSUB_TAPE_REMOTE) {
209                 if(!(data & mask) && (play || rec)) {
210                         databuf[0x1a][0] = CMT_STOP;
211                 }
212         } else if(id == SIG_PSUB_TAPE_END) {
213                 eot = ((data & mask) != 0);
214         }
215 }
216
217 void PSUB::set_intr_iei(bool val)
218 {
219         if(iei != val) {
220                 iei = val;
221                 update_intr();
222         }
223 }
224
225 uint32 PSUB::intr_ack()
226 {
227         return read_io8(0x1900);
228 }
229
230 void PSUB::intr_reti()
231 {
232         // NOTE: some software uses RET, not RETI ???
233 }
234
235 void PSUB::update_intr()
236 {
237         if(intr && iei) {
238                 d_cpu->set_intr_line(true, true, intr_bit);
239         } else {
240                 d_cpu->set_intr_line(false, true, intr_bit);
241         }
242 }
243
244 void PSUB::event_callback(int event_id, int err)
245 {
246         if(event_id == EVENT_1SEC) {
247                 if(cur_time.initialized) {
248                         cur_time.increment();
249                 } else {
250                         emu->get_host_time(&cur_time);  // resync
251                         cur_time.initialized = true;
252                 }
253         } else if(event_id == EVENT_DRIVE) {
254                 // drive sub cpu
255                 static const int cmdlen_tbl[] = {
256                         0, 1, 0, 0, 1, 0, 1, 0, 0, 3, 0, 3, 0
257                 };
258                 
259 #ifdef _X1TWIN
260                 // clear key buffer
261                 if(vm->cart_inserted(0)) {
262                         // clear key
263                         key_buf->clear();
264                 }
265 #endif
266                 if(ibf) {
267                         // sub cpu received data from main cpu
268                         if(cmdlen) {
269                                 // this is command parameter
270                                 *datap++ = inbuf;
271 #ifdef DEBUG_COMMAND
272                                 emu->out_debug_log(_T(" %2x"), inbuf);
273 #endif
274                                 cmdlen--;
275                         } else {
276                                 // this is new command
277                                 mode = inbuf;
278 #ifdef DEBUG_COMMAND
279                                 emu->out_debug_log(_T("X1 PSUB: cmd %2x"), inbuf);
280 #endif
281                                 if(0xd0 <= mode && mode <= 0xd7) {
282                                         cmdlen = 6;
283                                         datap = &databuf[mode - 0xd0][0]; // receive buffer
284                                 } else if(0xe3 <= mode && mode <= 0xef) {
285                                         cmdlen = cmdlen_tbl[mode - 0xe3];
286                                         datap = &databuf[mode - 0xd0][0]; // receive buffer
287                                 }
288                         }
289                         if(cmdlen == 0) {
290                                 // this command has no parameters or all parameters are received,
291                                 // so cpu processes the command
292 #ifdef DEBUG_COMMAND
293                                 emu->out_debug_log(_T("\n"));
294 #endif
295                                 process_cmd();
296                         }
297                         // sub cpu can accept new command or parameter
298                         set_ibf(false);
299                         set_obf(true);
300                         
301                         // if command is not finished, key irq is not raised
302                         if(cmdlen || datalen) {
303                                 return;
304                         }
305                 }
306                 if(obf) {
307                         // sub cpu can send data to main cpu
308                         if(datalen) {
309                                 // sub cpu sends result data
310                                 outbuf = *datap++;
311                                 set_obf(false);
312                                 datalen--;
313                         } else if(!key_buf->empty() && databuf[0x14][0] && !intr && iei) {
314                                 // key buffer is not empty and interrupt is not disabled,
315                                 // so sub cpu sends vector and raise irq
316                                 outbuf = databuf[0x14][0];
317                                 set_obf(false);
318                                 intr = true;
319                                 update_intr();
320                                 
321                                 // read key buffer
322                                 mode = 0xe6;
323                                 process_cmd();
324                         }
325                 }
326         } else if(event_id == EVENT_REPEAT) {
327                 key_register_id = -1;
328                 key_down(key_prev, true);
329         }
330 }
331
332 // shift, ctrl, graph, caps, kana
333 #define IS_LOWBYTE_KEY(c) ((c >= 0x10 && c <= 0x12) || c == 0x14 || c == 0x15)
334
335 void PSUB::key_down(int code, bool repeat)
336 {
337         // check keycode
338         switch(code) {
339         case 0x10:
340                 key_shift = true;
341                 break;
342         case 0x11:
343                 key_ctrl = true;
344                 break;
345         case 0x12:
346                 key_graph = true;
347                 break;
348         case 0x14:
349                 key_caps_locked = !key_caps_locked;
350                 break;
351         case 0x15:
352                 key_kana_locked = !key_kana_locked;
353                 break;
354         }
355         uint16 lh = get_key(code, repeat);
356         if(lh & 0xff00) {
357                 lh &= ~0x40;
358                 if(!databuf[0x14][0]) {
359                         key_buf->clear();
360                 }
361                 key_buf->write(lh);
362                 key_prev = code;
363                 
364                 // setup key repeat event
365                 if(key_register_id != -1) {
366                         cancel_event(this, key_register_id);
367                         key_register_id = -1;
368                 }
369                 if(!(0x70 <= code && code <= 0x87)) {
370                         if(repeat) {
371                                 register_event(this, EVENT_REPEAT, 61165, false, &key_register_id);     // 61.165 msec
372                         } else {
373                                 register_event(this, EVENT_REPEAT, 557085, false, &key_register_id);    // 557.085 msec
374                         }
375                 }
376                 
377                 // break key is pressed
378                 if((lh >> 8) == 3) {
379                         d_pio->write_signal(SIG_I8255_PORT_B, 0, 1);
380                         key_break = code;
381                 }
382 #ifdef _X1TURBO_FEATURE
383         } else if(key_prev == 0 && IS_LOWBYTE_KEY(code)) {
384                 key_buf->write(0xff);
385 #endif
386         }
387 }
388
389 void PSUB::key_up(int code)
390 {
391         // check keycode
392         switch(code) {
393         case 0x10:
394                 key_shift = false;
395                 break;
396         case 0x11:
397                 key_ctrl = false;
398                 break;
399         case 0x12:
400                 key_graph = false;
401                 break;
402         }
403 #ifdef _X1TURBO_FEATURE
404         if(code == key_prev || (key_prev == 0 && IS_LOWBYTE_KEY(code))) {
405 #else
406         if(code == key_prev) {
407 #endif
408                 // last pressed key is released
409                 if(!databuf[0x14][0]) {
410                         key_buf->clear();
411                 }
412                 key_buf->write(0xff);
413                 key_prev = 0;
414                 if(key_register_id != -1) {
415                         cancel_event(this, key_register_id);
416                         key_register_id = -1;
417                 }
418         }
419         if(code == key_break) {
420                 // break key is released
421                 d_pio->write_signal(SIG_I8255_PORT_B, 0xff, 1);
422                 key_break = 0;
423         }
424 }
425
426 void PSUB::play_tape(bool value)
427 {
428         if(value) {
429                 databuf[0x1a][0] = CMT_STOP;
430         } else {
431                 databuf[0x1a][0] = CMT_EJECT;
432         }
433         play = value;
434         rec = false;
435         d_drec->set_remote(false);
436 }
437
438 void PSUB::rec_tape(bool value)
439 {
440         if(value) {
441                 databuf[0x1a][0] = CMT_STOP;
442         } else {
443                 databuf[0x1a][0] = CMT_EJECT;
444         }
445         play = false;
446         rec = value;
447         d_drec->set_remote(false);
448 }
449
450 void PSUB::close_tape()
451 {
452         if(play || rec) {
453                 databuf[0x1a][0] = CMT_EJECT;
454                 play = rec = false;
455                 d_drec->set_remote(false);
456         }
457 }
458
459 void PSUB::process_cmd()
460 {
461         uint16 lh = 0xff;
462         
463         // preset 
464         if(0xd0 <= mode && mode < 0xf0) {
465                 datap = &databuf[mode - 0xd0][0]; // send buffer
466         }
467         datalen = 0;
468         
469         // process command
470         switch(mode) {
471         case 0x00:
472                 // reset receive/send buffer
473                 break;
474         case 0xd0:
475         case 0xd1:
476         case 0xd2:
477         case 0xd3:
478         case 0xd4:
479         case 0xd5:
480         case 0xd6:
481         case 0xd7:
482                 // timer set
483                 break;
484         case 0xd8:
485         case 0xd9:
486         case 0xda:
487         case 0xdb:
488         case 0xdc:
489         case 0xdd:
490         case 0xde:
491         case 0xdf:
492                 // timer read
493                 datap = &databuf[mode - 0xd8][0];       // data buffer for timer set
494                 datalen = 6;
495                 break;
496 #ifdef _X1TURBO_FEATURE
497         case 0xe3:
498                 // game key read (for turbo)
499                 databuf[0x13][0] = databuf[0x13][1] = databuf[0x13][2] = 0;
500                 if(config.device_type != 0) {
501                         databuf[0x13][0] |= key_stat[0x51] ? 0x80 : 0;  // q
502                         databuf[0x13][0] |= key_stat[0x57] ? 0x40 : 0;  // w
503                         databuf[0x13][0] |= key_stat[0x45] ? 0x20 : 0;  // e
504                         databuf[0x13][0] |= key_stat[0x41] ? 0x10 : 0;  // a
505                         databuf[0x13][0] |= key_stat[0x44] ? 0x08 : 0;  // d
506                         databuf[0x13][0] |= key_stat[0x5a] ? 0x04 : 0;  // z
507                         databuf[0x13][0] |= key_stat[0x58] ? 0x02 : 0;  // x
508                         databuf[0x13][0] |= key_stat[0x43] ? 0x01 : 0;  // c
509                         databuf[0x13][1] |= key_stat[0x67] ? 0x80 : 0;  // 7
510                         databuf[0x13][1] |= key_stat[0x64] ? 0x40 : 0;  // 4
511                         databuf[0x13][1] |= key_stat[0x61] ? 0x20 : 0;  // 1
512                         databuf[0x13][1] |= key_stat[0x68] ? 0x10 : 0;  // 8
513                         databuf[0x13][1] |= key_stat[0x62] ? 0x08 : 0;  // 2
514                         databuf[0x13][1] |= key_stat[0x69] ? 0x04 : 0;  // 9
515                         databuf[0x13][1] |= key_stat[0x66] ? 0x02 : 0;  // 6
516                         databuf[0x13][1] |= key_stat[0x63] ? 0x01 : 0;  // 3
517                         databuf[0x13][2] |= key_stat[0x1b] ? 0x80 : 0;  // esc
518                         databuf[0x13][2] |= key_stat[0x61] ? 0x40 : 0;  // 1
519                         databuf[0x13][2] |= key_stat[0x6d] ? 0x20 : 0;  // -
520                         databuf[0x13][2] |= key_stat[0x6b] ? 0x10 : 0;  // +
521                         databuf[0x13][2] |= key_stat[0x6a] ? 0x08 : 0;  // *
522                         databuf[0x13][2] |= key_stat[0x09] ? 0x04 : 0;  // tab
523                         databuf[0x13][2] |= key_stat[0x20] ? 0x02 : 0;  // sp
524                         databuf[0x13][2] |= key_stat[0x0d] ? 0x01 : 0;  // ret
525                 }
526                 datalen = 3;
527                 break;
528 #endif
529         case 0xe4:
530                 // irq vector
531 //              if(!databuf[0x14][0]) {
532                         while(!key_buf->empty()) {
533                                 lh = key_buf->read();
534                                 // ???
535                                 databuf[0x16][0] = lh & 0xff;
536                                 databuf[0x16][1] = lh >> 8;
537                         }
538 //              }
539                 intr = false;
540                 update_intr();
541                 break;
542         case 0xe6:
543                 // keydata read
544                 if(!databuf[0x14][0]) {
545                         // interrupt disabled
546                         while(!key_buf->empty()) {
547                                 lh = key_buf->read();
548                                 databuf[0x16][0] = lh & 0xff;
549                                 databuf[0x16][1] = lh >> 8;
550                         }
551                 } else {
552                         // interrupt enabed
553                         if(!key_buf->empty()) {
554                                 lh = key_buf->read();
555                                 databuf[0x16][0] = lh & 0xff;
556                                 databuf[0x16][1] = lh >> 8;
557                         }
558                 }
559 #ifdef _X1TURBO_FEATURE
560                 databuf[0x16][0] &= ~0x1f;
561                 databuf[0x16][0] |= get_key_low() & 0x1f;
562 #endif
563 #ifdef DEBUG_COMMAND
564                 emu->out_debug_log(_T("X1 PSUB: keycode %2x %2x\n"), databuf[0x16][0], databuf[0x16][1]);
565 #endif
566                 datalen = 2;
567                 break;
568         case 0xe7:
569                 // TV controll
570                 databuf[0x18][0] = databuf[0x17][0];
571                 break;
572         case 0xe8:
573                 // TV controll read
574                 datalen = 1;
575                 break;
576         case 0xe9:
577                 // CMT controll
578                 if(databuf[0x1a][0] != databuf[0x19][0]) {
579                         uint8 new_status = databuf[0x19][0];
580                         switch(databuf[0x19][0]) {
581                         case CMT_EJECT:
582                                 emu->close_tape();
583                                 break;
584                         case CMT_STOP:
585                                 d_drec->set_remote(false);
586                                 break;
587                         case CMT_PLAY:
588                                 if(play) {
589                                         d_drec->set_ff_rew(0);
590                                         d_drec->set_remote(true);
591                                 } else if(rec) {
592                                         new_status = CMT_STOP;
593                                 } else {
594                                         new_status = CMT_EJECT;
595                                 }
596                                 break;
597                         case CMT_FAST_FWD:
598                                 if(play) {
599                                         d_drec->set_ff_rew(1);
600                                         d_drec->set_remote(true);
601                                 } else if(rec) {
602                                         new_status = CMT_STOP;
603                                 } else {
604                                         new_status = CMT_EJECT;
605                                 }
606                                 break;
607                         case CMT_FAST_REW:
608                                 if(play) {
609                                         d_drec->set_ff_rew(-1);
610                                         d_drec->set_remote(true);
611                                 } else if(rec) {
612                                         new_status = CMT_STOP;
613                                 } else {
614                                         new_status = CMT_EJECT;
615                                 }
616                                 break;
617                         case CMT_APSS_PLUS:
618                         case CMT_APSS_MINUS:
619                                 if(play) {
620                                         d_drec->do_apss((databuf[0x19][0] == CMT_APSS_PLUS) ? 1 : -1);
621                                         new_status = CMT_STOP;
622                                 } else if(rec) {
623                                         new_status = CMT_STOP;
624                                 } else {
625                                         new_status = CMT_EJECT;
626                                 }
627                                 break;
628                         case CMT_REC:
629                                 if(play) {
630                                         new_status = CMT_STOP;
631                                 } else if(rec) {
632                                         d_drec->set_remote(true);
633                                 } else {
634                                         new_status = CMT_EJECT;
635                                 }
636                                 break;
637 #ifdef DEBUG_COMMAND
638                         default:
639                                 emu->out_debug_log(_T("X1 PSUB: unknown CMT control %2x\n"), databuf[0x19][0]);
640                                 break;
641 #endif
642                         }
643                         databuf[0x1a][0] = new_status;
644                 }
645                 break;
646         case 0xea:
647                 // CMT status
648                 datalen = 1;
649                 break;
650         case 0xeb:
651                 // CMT sensor (bit2=WP, bit1=SET, bit0=END)
652                 databuf[0x1b][0] = (play ? 2 : rec ? 6 : 0) | (play && eot ? 1 : 0);
653                 datalen = 1;
654                 break;
655         case 0xec:
656                 // set calender
657                 cur_time.year = FROM_BCD(databuf[0x1c][0]);
658                 if((databuf[0x1c][1] & 0xf0) != 0) {
659                         cur_time.month = databuf[0x1c][1] >> 4;
660                 }
661 //              cur_time.day_of_week = databuf[0x1c][1] & 7;
662                 if(databuf[0x1c][2] != 0) {
663                         cur_time.day = FROM_BCD(databuf[0x1c][2]);
664                 }
665                 cur_time.update_year();
666                 cur_time.update_day_of_week();
667                 break;
668         case 0xed:
669                 // get calender
670                 databuf[0x1d][0] = TO_BCD(cur_time.year);
671                 databuf[0x1d][1] = (cur_time.month << 4) | cur_time.day_of_week;
672                 databuf[0x1d][2] = TO_BCD(cur_time.day);
673                 datalen = 3;
674                 break;
675         case 0xee:
676                 // set time
677                 cur_time.hour = FROM_BCD(databuf[0x1e][0]);
678                 cur_time.minute = FROM_BCD(databuf[0x1e][1] & 0x7f);
679                 cur_time.second = FROM_BCD(databuf[0x1e][2] & 0x7f);
680                 // restart event
681                 cancel_event(this, time_register_id);
682                 register_event(this, EVENT_1SEC, 1000000, true, &time_register_id);
683                 break;
684         case 0xef:
685                 // get time
686                 databuf[0x1f][0] = TO_BCD(cur_time.hour);
687                 databuf[0x1f][1] = TO_BCD(cur_time.minute);
688                 databuf[0x1f][2] = TO_BCD(cur_time.second);
689                 datalen = 3;
690                 break;
691 #ifdef DEBUG_COMMAND
692         default:
693                 emu->out_debug_log(_T("X1 PSUB: unknown cmd %2x\n"), mode);
694 #endif
695         }
696 }
697
698 void PSUB::set_ibf(bool val)
699 {
700         if(ibf != val) {
701                 d_pio->write_signal(SIG_I8255_PORT_B, val ? 0xff : 0, 0x40);
702                 ibf = val;
703         }
704 }
705
706 void PSUB::set_obf(bool val)
707 {
708         if(obf != val) {
709                 d_pio->write_signal(SIG_I8255_PORT_B, val ? 0xff : 0, 0x20);
710                 obf = val;
711         }
712 }
713
714 uint8 PSUB::get_key_low()
715 {
716         uint8 l = 0xff;
717         
718         if(key_ctrl) {
719                 l &= ~0x01;     // ctrl
720         }
721         if(key_shift) {
722                 l &= ~0x02;     // shift
723         }
724         if(key_kana_locked) {
725                 l &= ~0x04;     // kana
726         }
727         if(key_caps_locked) {
728                 l &= ~0x08;     // caps
729         }
730         if(key_graph) {
731                 l &= ~0x10;     // graph (alt)
732         }
733         return l;
734 }
735
736 uint16 PSUB::get_key(int code, bool repeat)
737 {
738         uint8 l = get_key_low();
739         uint8 h = 0;
740         
741         if(repeat) {
742                 l &= ~0x20;     // repeat
743         }
744         if(0x60 <= code && code <= 0x74) {
745                 l &= ~0x80;     // function or numpad
746         }
747         if(key_kana_locked) {
748                 if(!(l & 0x02)) {
749                         h = keycode_ks[code];   // kana+shift
750                 } else {
751                         h = keycode_k[code];    // kana
752                 }
753         } else {
754                 if(!(l & 0x01)) {
755                         h = keycode_c[code];    // ctrl
756                 } else if(!(l & 0x10)) {
757                         h = keycode_g[code];    // graph
758                 } else {
759                         if(!(l & 0x02)) {
760                                 h = keycode_s[code];    // shift
761                         } else {
762                                 h = keycode[code];      // (none shifted)
763                         }
764                         if(key_caps_locked) {
765                                 if(0x41 <= code && code <= 0x5a) {
766                                         h ^= 0x20;      // alphabet
767                                 }
768                         }
769                 }
770         }
771 #ifndef _X1TURBO_FEATURE
772         if(!h) {
773                 l = 0xff;
774         }
775 #endif
776         return l | (h << 8);
777 }
778
779 #define STATE_VERSION   1
780
781 void PSUB::save_state(FILEIO* state_fio)
782 {
783         state_fio->FputUint32(STATE_VERSION);
784         state_fio->FputInt32(this_device_id);
785         
786         cur_time.save_state((void *)state_fio);
787         state_fio->FputInt32(time_register_id);
788         state_fio->Fwrite(databuf, sizeof(databuf), 1);
789         state_fio->FputInt32((int)(datap - &databuf[0][0]));
790         state_fio->FputUint8(mode);
791         state_fio->FputUint8(inbuf);
792         state_fio->FputUint8(outbuf);
793         state_fio->FputBool(ibf);
794         state_fio->FputBool(obf);
795         state_fio->FputInt32(cmdlen);
796         state_fio->FputInt32(datalen);
797         key_buf->save_state((void *)state_fio);
798         state_fio->FputInt32(key_prev);
799         state_fio->FputInt32(key_break);
800         state_fio->FputBool(key_shift);
801         state_fio->FputBool(key_ctrl);
802         state_fio->FputBool(key_graph);
803         state_fio->FputBool(key_caps_locked);
804         state_fio->FputBool(key_kana_locked);
805         state_fio->FputInt32(key_register_id);
806         state_fio->FputBool(play);
807         state_fio->FputBool(rec);
808         state_fio->FputBool(eot);
809         state_fio->FputBool(iei);
810         state_fio->FputBool(intr);
811         state_fio->FputUint32(intr_bit);
812 }
813
814 bool PSUB::load_state(FILEIO* state_fio)
815 {
816         if(state_fio->FgetUint32() != STATE_VERSION) {
817                 return false;
818         }
819         if(state_fio->FgetInt32() != this_device_id) {
820                 return false;
821         }
822         if(!cur_time.load_state((void *)state_fio)) {
823                 return false;
824         }
825         time_register_id = state_fio->FgetInt32();
826         state_fio->Fread(databuf, sizeof(databuf), 1);
827         datap = &databuf[0][0] + state_fio->FgetInt32();
828         mode = state_fio->FgetUint8();
829         inbuf = state_fio->FgetUint8();
830         outbuf = state_fio->FgetUint8();
831         ibf = state_fio->FgetBool();
832         obf = state_fio->FgetBool();
833         cmdlen = state_fio->FgetInt32();
834         datalen = state_fio->FgetInt32();
835         if(!key_buf->load_state((void *)state_fio)) {
836                 return false;
837         }
838         key_prev = state_fio->FgetInt32();
839         key_break = state_fio->FgetInt32();
840         key_shift = state_fio->FgetBool();
841         key_ctrl = state_fio->FgetBool();
842         key_graph = state_fio->FgetBool();
843         key_caps_locked = state_fio->FgetBool();
844         key_kana_locked = state_fio->FgetBool();
845         key_register_id = state_fio->FgetInt32();
846         play = state_fio->FgetBool();
847         rec = state_fio->FgetBool();
848         eot = state_fio->FgetBool();
849         iei = state_fio->FgetBool();
850         intr = state_fio->FgetBool();
851         intr_bit = state_fio->FgetUint32();
852         return true;
853 }
854