OSDN Git Service

[General][Qt] Merge upstream 2015-03-15.
[csp-qt/common_source_project-fm7.git] / source / src / vm / x07 / io.cpp
1 /*
2         CANON X-07 Emulator 'eX-07'
3
4         Origin : J.Brigaud
5         Author : Takeda.Toshiya
6         Date   : 2007.12.26 -
7
8         [ i/o ]
9 */
10
11 #if defined(_MSC_VER) && (_MSC_VER >= 1400)
12 #pragma warning( disable : 4996 )
13 #endif
14
15 #include <math.h>
16 #include "io.h"
17 #include "../beep.h"
18 #include "../z80.h"
19 #include "../../fifo.h"
20
21 #define EVENT_BEEP      0
22 #define EVENT_CMT       1
23 #define EVENT_1SEC      2
24
25 static const uint8 sub_cmd_len[0x47] = {
26         1,      // 00   Unknown
27         1,      // 01   TimeCall
28         1,      // 02   Stick
29         1,      // 03   Strig
30         1,      // 04   Strig1
31         3,      // 05   RamRead
32         4,      // 06   RamWrite
33         3,      // 07   ScrollSet
34         1,      // 08   ScrollExet
35         2,      // 09   LineClear
36         9,      // 0a   TimeSet
37         1,      // 0b   CalcDay
38         9,      // 0c   AlarmSet
39         1,      // 0d   BuzzerOff
40         1,      // 0e   BuzzerOn
41         2,      // 0f   TrfLine
42         3,      // 10   TestPoint
43         3,      // 11   Pset
44         3,      // 12   Preset
45         3,      // 13   Peor
46         5,      // 14   Line
47         4,      // 15   Circle
48         0x82,   // 16   UDKWrite
49         2,      // 17   UDKRead
50         1,      // 18   UDKOn
51         1,      // 19   UDKOff
52         10,     // 1a   UDCWrite
53         2,      // 1b   UDCRead
54         1,      // 1c   UDCInt
55         0x81,   // 1d   StartPgmWrite
56         0x81,   // 1e   SPWriteCont
57         1,      // 1f   SPOn
58         1,      // 20   SPOff
59         1,      // 21   StartPgmRead
60         1,      // 22   OnStat
61         1,      // 23   OFFReq
62         4,      // 24   Locate
63         1,      // 25   CursOn
64         1,      // 26   CursOff
65         3,      // 27   TestKey
66         2,      // 28   TestChr
67         1,      // 29   InitSec
68         2,      // 2a   InitDate
69         1,      // 2b   ScrOff
70         1,      // 2c   ScrOn
71         1,      // 2d   KeyBufferClear
72         1,      // 2e   ClsScr
73         1,      // 2f   Home
74         1,      // 30   OutUdkOn
75         1,      // 31   OutUDKOff
76         1,      // 32   RepateKeyOn
77         1,      // 33   RepateKeyOff
78         1,      // 34   UDK=KANA
79         0x82,   // 35   UdkContWrite
80         1,      // 36   AlarmRead
81         1,      // 37   BuzzZero
82         1,      // 38   ClickOff
83         1,      // 39   ClickOn
84         1,      // 3a   LocateClose
85         1,      // 3b   KeybOn
86         1,      // 3c   KeybOff
87         1,      // 3d   ExecStartPgm
88         1,      // 3e   UnexecStartPgm
89         1,      // 3f   Sleep
90         1,      // 40   UDKInit
91         9,      // 41   OutUDC
92         1,      // 42   ReadCar
93         3,      // 43   ScanR
94         3,      // 44   ScanL
95         1,      // 45   TimeChk
96         1       // 46   AlmChk
97 };
98
99 static const char *udk_ini[12] = {
100         "tim?TIME$^",
101         "cldCLOAD\"",
102         "locLOCATE ",
103         "lstLIST ",
104         "runRUN^",
105         "",
106         "dat?DATE$^",
107         "csvCSAVE\"",
108         "prtPRINT ",
109         "slpSLEEP",
110         "cntCONT^",
111         ""
112 };
113
114 static const int udk_ofs[12] = {
115         0, 42, 84, 126, 168, 210, 256, 298, 340, 382, 424, 466
116 };
117
118 static const int udk_size[12] = {
119         42, 42, 42, 42, 42, 46, 42, 42, 42, 42, 42, 46
120 };
121
122 static const int key_tbl[256] = {
123         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x0d,0x00,0x00,
124         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
125         0x20,0x00,0x00,0x00, 0x0b,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x12,0x16,0x00,
126         0x30,0x31,0x32,0x33, 0x34,0x35,0x36,0x37, 0x38,0x39,0x00,0x00, 0x00,0x00,0x00,0x00,
127         0x00,0x41,0x42,0x43, 0x44,0x45,0x46,0x47, 0x48,0x49,0x4a,0x4b, 0x4c,0x4d,0x4e,0x4f,
128         0x50,0x51,0x52,0x53, 0x54,0x55,0x56,0x57, 0x58,0x59,0x5a,0x00, 0x00,0x00,0x00,0x00,
129         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
130         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
131         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
132         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
133         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
134         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x3a,0x3b, 0x2c,0x2d,0x2e,0x2f,
135         0x40,0x00,0x00,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,0x5b, 0x5c,0x5d,0x5e,0x00,
137         0x00,0x00,0x5c,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
138         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00
139 };
140
141 static const int key_tbl_s[256] = {
142         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x0d,0x00,0x00,
143         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
144         0x20,0x00,0x00,0x00, 0x0c,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x12,0x16,0x00,
145         0x00,0x21,0x22,0x23, 0x24,0x25,0x26,0x27, 0x28,0x29,0x00,0x00, 0x00,0x00,0x00,0x00,
146         0x00,0x61,0x62,0x63, 0x64,0x65,0x66,0x67, 0x68,0x69,0x6a,0x6b, 0x6c,0x6d,0x6e,0x6f,
147         0x70,0x71,0x72,0x73, 0x74,0x75,0x76,0x77, 0x78,0x79,0x7a,0x00, 0x00,0x00,0x00,0x00,
148         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
149         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
150         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
151         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
152         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
153         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x2a,0x2b, 0x3c,0x3d,0x3e,0x3f,
154         0x60,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
155         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x7b, 0x7c,0x7d,0x7e,0x00,
156         0x00,0x00,0x5f,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
157         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00
158 };
159
160 static const int key_tbl_k[256] = {
161         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x0d,0x00,0x00,
162         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
163         0x20,0x00,0x00,0x00, 0x0b,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x12,0x16,0x00,
164         0xdc,0xc7,0xcc,0xb1, 0xb3,0xb4,0xb5,0xd4, 0xd5,0xd6,0x00,0x00, 0x00,0x00,0x00,0x00,
165         0x00,0xc1,0xba,0xbf, 0xbc,0xb2,0xca,0xb7, 0xb8,0xc6,0xcf,0xc9, 0xd8,0xd3,0xd0,0xd7,
166         0xbe,0xc0,0xbd,0xc4, 0xb6,0xc5,0xcb,0xc3, 0xbb,0xdd,0xc2,0x00, 0x00,0x00,0x00,0x00,
167         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
168         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
169         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
170         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
171         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
172         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0xb9,0xda, 0xc8,0xce,0xd9,0xd2,
173         0xde,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
174         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xdf, 0xb0,0xd1,0xcd,0x00,
175         0x00,0x00,0xdb,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
176         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00
177 };
178
179 static const int key_tbl_ks[256] = {
180         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x0d,0x00,0x00,
181         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
182         0x20,0x00,0x00,0x00, 0x0c,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x12,0x16,0x00,
183         0xa6,0x00,0x00,0xa7, 0xa9,0xaa,0xab,0xac, 0xad,0xae,0x00,0x00, 0x00,0x00,0x00,0x00,
184         0x00,0x00,0x00,0x00, 0x00,0xa8,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
185         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0xaf,0x00, 0x00,0x00,0x00,0x00,
186         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
187         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
188         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
189         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
190         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
191         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0xa4,0x00,0xa1,0xa5,
192         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
193         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xa2, 0x00,0xa3,0x00,0x00,
194         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
195         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00
196 };
197
198 static const int key_tbl_g[256] = {
199         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x0d,0x00,0x00,
200         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
201         0x20,0x00,0x00,0x00, 0x0c,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x12,0x16,0x00,
202         0x8a,0xe9,0x90,0x91, 0x92,0x93,0xec,0xe0, 0xf2,0xf1,0x00,0x00, 0x00,0x00,0x00,0x00,
203         0x00,0x88,0xed,0xe4, 0xef,0x99,0xfd,0x9d, 0xfe,0xf9,0xe5,0x9b, 0xf4,0xf5,0x89,0x9e,
204         0xf7,0x8b,0xf6,0x9f, 0x97,0x94,0x95,0xfb, 0x98,0x96,0xe1,0x00, 0x00,0x00,0x00,0x00,
205         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
206         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
207         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
208         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
209         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
210         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x81,0x82, 0x9c,0xf0,0x9a,0x80,
211         0xe7,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
212         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x84, 0x00,0x85,0xfc,0x00,
213         0x00,0x00,0x83,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
214         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00
215 };
216
217 static const int key_tbl_c[256] = {
218         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x0d,0x00,0x00,
219         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
220         0x20,0x00,0x00,0x00, 0x0b,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x12,0x16,0x00,
221         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
222         0x00,0x01,0x02,0x03, 0x04,0x05,0x06,0x07, 0x08,0x09,0x0a,0x0b, 0x0c,0x0d,0x0e,0x0f,
223         0x10,0x11,0x12,0x13, 0x14,0x15,0x16,0x17, 0x18,0x19,0x1a,0x00, 0x00,0x00,0x00,0x00,
224         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
225         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
226         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
227         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
228         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
229         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
230         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
231         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
232         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
233         0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00
234 };
235
236 //memo: how to request the display size changing
237 //emu->change_screen_size(TV_SCREEN_WIDTH, TV_SCREEN_HEIGHT, -1, -1, TV_WINDOW_WIDTH, TV_WINDOW_HEIGHT);
238 //emu->change_screen_size(SCREEN_WIDTH, SCREEN_HEIGHT, -1, -1, WINDOW_WIDTH, WINDOW_HEIGHT);
239
240 void IO::initialize()
241 {
242         // load font
243         FILEIO* fio = new FILEIO();
244         if(fio->Fopen(emu->bios_path(_T("FONT.ROM")), FILEIO_READ_BINARY)) {
245                 fio->Fread(font, sizeof(font), 1);
246                 fio->Fclose();
247         }
248         delete fio;
249         
250         // init timer
251         emu->get_host_time(&cur_time);
252         register_event(this, EVENT_1SEC, 1000000, true, &register_id_1sec);
253         
254         // init fifo
255         key_buf = new FIFO(20);
256         cmd_buf = new FIFO(256);
257         rsp_buf = new FIFO(256);
258         
259         // wram
260         memset(wram, 0, 0x200);
261         for(int i = 0; i < 12; i++) {
262                 strcpy((char*)wram + udk_ofs[i], udk_ini[i]);
263         }
264         for(int i = 0; i < 0x200; i++) {
265                 if(wram[i] == '^') {
266                         wram[i] = 13;
267                 }
268         }
269         memcpy(udc, font, sizeof(udc));
270         
271         // cmt
272         cmt_fio = new FILEIO();
273         cmt_play = cmt_rec = false;
274         
275         // video
276         register_frame_event(this);
277         register_vline_event(this);
278 }
279
280 void IO::release()
281 {
282         close_tape();
283         delete cmt_fio;
284         
285         key_buf->release();
286         delete key_buf;
287         cmd_buf->release();
288         delete cmd_buf;
289         rsp_buf->release();
290         delete rsp_buf;
291 }
292
293 void IO::reset()
294 {
295         // registers
296         memset(rregs, 0, sizeof(rregs));
297         memset(wregs, 0, sizeof(wregs));
298         
299         // t6834
300         cmd_buf->clear();
301         rsp_buf->clear();
302         sub_int = 0;
303         
304         // keyboard
305         key_buf->clear();
306         ctrl = shift = kana = graph = brk = false;
307         stick = 0x30;
308         strig = strig1 = 0xff;
309         
310         // data recorder
311         close_tape();
312         cmt_mode = false;
313         
314         // video
315         memset(lcd, 0, sizeof(lcd));
316         locate_on = cursor_on = udk_on = false;
317         locate_x = locate_y = cursor_x = cursor_y = cursor_blink = 0;
318         scroll_min = 0;
319         scroll_max = 4;
320         
321         // beep
322         register_id_beep = -1;
323 }
324
325 void IO::event_callback(int event_id, int err)
326 {
327         if(event_id == EVENT_BEEP) {
328                 register_id_beep = -1;
329                 d_beep->write_signal(SIG_BEEP_ON, 0, 0);
330                 rregs[4] = (wregs[4] &= ~2);
331         } else if(event_id == EVENT_CMT) {
332                 sub_int |= 2;
333                 update_intr();
334         } else if(event_id == EVENT_1SEC) {
335                 if(cur_time.initialized) {
336                         cur_time.increment();
337                 } else {
338                         emu->get_host_time(&cur_time);  // resync
339                         cur_time.initialized = true;
340                 }
341         }
342 }
343
344 void IO::event_frame()
345 {
346         cursor_blink++;
347 }
348
349 void IO::event_vline(int v, int clock)
350 {
351         vblank = !(v < 192);
352 }
353
354 void IO::write_io8(uint32 addr, uint32 data)
355 {
356 //      emu->out_debug_log("OUT\t%4x, %2x\n", addr, data);
357         switch(addr & 0xff) {
358         case 0x80:
359                 font_code = data;
360                 break;
361         case 0xf0:
362 //              d_mem->write_signal(0, data, 0xff);
363         case 0xf1:
364         case 0xf2:
365         case 0xf3:
366         case 0xf6:
367         case 0xf7:
368                 wregs[addr & 7] = data;
369                 break;
370         case 0xf4:
371                 rregs[4] = wregs[4] = data;
372                 // cmt
373                 cmt_mode = ((data & 0x0c) == 8);
374 //              if(cmt_mode && (wregs[5] & 4)) {
375 //                      recv_from_cmt();
376 //              }
377                 // beep
378                 if((data & 0x0e) == 0x0e) {
379                         double freq = 192000.0 / (wregs[2] | (wregs[3] << 8));
380                         d_beep->set_frequency(freq);
381                         d_beep->write_signal(SIG_BEEP_ON, 1, 1);
382                         // temporary patch: register the event to stop
383                         int intv = ram[0x450] * 50000;
384                         if(register_id_beep != -1) {
385                                 cancel_event(this, register_id_beep);
386                         }
387                         register_event(this, EVENT_BEEP, intv, false, &register_id_beep);
388                 } else {
389                         d_beep->write_signal(SIG_BEEP_ON, 0, 1);
390                 }
391                 break;
392         case 0xf5:
393                 wregs[5] = data;
394                 if(data & 1) {
395                         ack_from_sub();
396                 }
397                 if(data & 2) {
398                         send_to_sub();
399                 }
400                 if(data & 4) {
401                         recv_from_cmt();
402                 }
403                 if(data & 8) {
404                         send_to_cmt();
405                 }
406 //              if(data & 0x20) {
407 //                      print(prt_data);
408 //              }
409                 break;
410         }
411 }
412
413 uint32 IO::read_io8(uint32 addr)
414 {
415         uint32 val = 0xff;
416         
417         switch(addr & 0xff) {
418         case 0x80:
419         case 0x81:
420         case 0x82:
421         case 0x83:
422         case 0x84:
423         case 0x85:
424         case 0x86:
425         case 0x87:
426         case 0x88:
427         case 0x89:
428         case 0x8a:
429         case 0x8b:
430         case 0x8c:
431                 val = ((addr & 0x0f) < 8) ? udc[(font_code << 3) | (addr & 7)] : 0;
432                 break;
433         case 0x90:
434                 val =  vblank ? 0x80 : 0;
435                 break;
436         case 0xf0:
437         case 0xf1:
438         case 0xf3:
439         case 0xf4:
440         case 0xf5:
441         case 0xf7:
442                 val = rregs[addr & 7];
443                 break;
444         case 0xf2:
445                 if(wregs[5] & 4) {
446                         rregs[2] |= 2;
447                 } else {
448                         rregs[2] &= 0xfd;
449                 }
450                 val = rregs[2] | 2;
451                 break;
452         case 0xf6:
453                 if(cmt_mode) {
454                         rregs[6] |= 5;
455                 }
456                 val = rregs[6];
457                 break;
458         }
459 //      emu->out_debug_log("IN\t%4x = %2x\n", addr, val);
460         return val;
461 }
462
463 void IO::update_intr()
464 {
465         if(!key_buf->empty()) {
466                 rregs[0] = 0;
467                 rregs[1] = key_buf->read();
468                 rregs[2] |= 1;
469                 d_cpu->write_signal(SIG_NSC800_RSTA, 1, 1);
470         } else if(brk) {
471                 rregs[0] = 0x80;
472                 rregs[1] = 5;
473                 rregs[2] |= 1;
474                 brk = false;
475                 d_cpu->write_signal(SIG_NSC800_RSTA, 1, 1);
476         } else if(sub_int & 1) {
477                 recv_from_sub();
478                 sub_int &= ~1;
479                 d_cpu->write_signal(SIG_NSC800_RSTA, 1, 1);
480         } else if(sub_int & 2) {
481                 sub_int &= ~2;
482                 d_cpu->write_signal(SIG_NSC800_RSTB, 1, 1);
483         }
484 }
485
486 // ----------------------------------------------------------------------------
487 // video
488 // ----------------------------------------------------------------------------
489
490 void IO::draw_screen()
491 {
492         scrntype cd = RGB_COLOR(48, 56, 16);
493         scrntype cb = RGB_COLOR(160, 168, 160);
494         
495         for(int y = 0; y < 4; y++) {
496                 int py = y * 8;
497                 for(int x = 0; x < 20; x++) {
498                         int px = x * 6;
499                         if(cursor_on && (cursor_blink & 0x20) && cursor_x == x && cursor_y == y) {
500                                 for(int l = 0; l < 8; l++) {
501                                         scrntype* dest = emu->screen_buffer(py + l);
502                                         dest += px;
503                                         dest[0] = dest[1] = dest[2] = dest[3] = dest[4] = dest[5] = (l < 7) ? cb : cd;
504                                 }
505                         } else {
506                                 for(int l = 0; l < 8; l++) {
507                                         uint8* src = &lcd[py + l][px];
508                                         scrntype* dest = emu->screen_buffer(py + l);
509                                         dest += px;
510                                         dest[0] = src[0] ? cd : cb;
511                                         dest[1] = src[1] ? cd : cb;
512                                         dest[2] = src[2] ? cd : cb;
513                                         dest[3] = src[3] ? cd : cb;
514                                         dest[4] = src[4] ? cd : cb;
515                                         dest[5] = src[5] ? cd : cb;
516                                 }
517                         }
518                 }
519         }
520 }
521
522 void IO::draw_font(int x, int y, uint8 code)
523 {
524         if(x < 20 && y < 4) {
525                 int px = x * 6;
526                 int py = y * 8;
527                 int ofs = code << 3;
528                 for(int l = 0; l < 8; l++) {
529                         uint8 pat = udc[ofs + l];
530                         lcd[py + l][px + 0] = (pat & 0x80) ? 0xff : 0;
531                         lcd[py + l][px + 1] = (pat & 0x40) ? 0xff : 0;
532                         lcd[py + l][px + 2] = (pat & 0x20) ? 0xff : 0;
533                         lcd[py + l][px + 3] = (pat & 0x10) ? 0xff : 0;
534                         lcd[py + l][px + 4] = (pat & 0x08) ? 0xff : 0;
535                         lcd[py + l][px + 5] = (pat & 0x04) ? 0xff : 0;
536                 }
537         }
538 }
539
540 void IO::draw_udk()
541 {
542         for(int i = 0, x = 0; i < 5; i++) {
543                 int ofs = udk_ofs[i + (shift ? 6 : 0)];
544                 draw_font(x++, 3, 0x83);
545                 for(int j = 0; j < 3; j++) {
546                         draw_font(x++, 3, wram[ofs++]);
547                 }
548         }
549 }
550
551 #define draw_point(x, y, c) { if((x) < 120 && (y) < 32) lcd[y][x] = c; }
552
553 void IO::draw_line(int sx, int sy, int ex, int ey)
554 {
555         int next_x = sx, next_y = sy;
556         int delta_x = abs(ex - sx) * 2;
557         int delta_y = abs(ey - sy) * 2;
558         int step_x = (ex < sx) ? -1 : 1;
559         int step_y = (ey < sy) ? -1 : 1;
560         
561         if(delta_x > delta_y) {
562                 int frac = delta_y - delta_x / 2;
563                 while(next_x != ex) {
564                         if(frac >= 0) {
565                                 next_y += step_y;
566                                 frac -= delta_x;
567                         }
568                         next_x += step_x;
569                         frac += delta_y;
570                         draw_point(next_x, next_y, 0xff);
571                 }
572         } else {
573                 int frac = delta_x - delta_y / 2;
574                 while(next_y != ey) {
575                         if(frac >= 0) {
576                                 next_x += step_x;
577                                 frac -= delta_y;
578                         }
579                         next_y += step_y;
580                         frac += delta_x;
581                         draw_point(next_x, next_y, 0xff);
582                 }
583         }
584         draw_point(sx, sy, 0xff);
585         draw_point(ex, ey, 0xff);
586 }
587
588 void IO::draw_circle(int x, int y, int r)
589 {
590 #if 0
591         // high accuracy
592         double xlim = sqrt((double)(r * r) / 2);
593         
594         for(int cx = 0, cy = r; cx <= xlim ; cx++) {
595                 double d1 = (cx * cx + cy * cy) - r * r;
596                 double d2 = (cx * cx + (cy - 1) * (cy - 1)) - r * r;
597                 if(abs(d1) > abs(d2)) {
598                         cy--;
599                 }
600                 draw_point(cx + x, cy + y, 0xff);
601                 draw_point(cx + x, -cy + y, 0xff);
602                 draw_point(-cx + x, cy + y, 0xff);
603                 draw_point(-cx + x, -cy + y, 0xff);
604                 draw_point(cy + x, cx + y, 0xff);
605                 draw_point(cy + x, -cx + y, 0xff);
606                 draw_point(-cy + x, cx + y, 0xff);
607                 draw_point(-cy + x, -cx + y, 0xff);
608         }
609 #else
610         // high speed
611         int cx = 0, cy = r;
612         int d = 2 - 2 * r;
613         
614         draw_point(cx + x, cy + y, 0xff);
615         draw_point(cx + x, -cy + y, 0xff);
616         draw_point(cy + x, cx + y, 0xff);
617         draw_point(-cy + x, cx + y, 0xff);
618         while(1) {
619                 if(d > -cy) {
620                         cy--;
621                         d += 1 - 2 * cy;
622                 }
623                 if(d <= cx) {
624                         cx++;
625                         d += 1 + 2 * cx;
626                 }
627                 if(!cy) {
628                         return;
629                 }
630                 draw_point(cx + x, cy + y, 0xff);
631                 draw_point(-cx + x, cy + y, 0xff);
632                 draw_point(-cx + x, -cy + y, 0xff);
633                 draw_point(cx + x, -cy + y, 0xff);
634         }
635 #endif
636 }
637
638 void IO::line_clear(int y)
639 {
640         if(y < 4) {
641                 for(int l = y * 8; l < (y + 1) * 8; l++) {
642                         memset(lcd[l], 0, 120);
643                 }
644         }
645 }
646
647 void IO::scroll()
648 {
649         if(scroll_min <= scroll_max && scroll_max <= 4) {
650                 for(int l = scroll_min * 8; l < (scroll_max - 1) * 8; l++) {
651                         memcpy(lcd[l], lcd[l + 8], 120);
652                 }
653                 for(int l = (scroll_max - 1) * 8; l < scroll_max * 8; l++) {
654                         memset(lcd[l], 0, 120);
655                 }
656         }
657 }
658
659 // ----------------------------------------------------------------------------
660 // keyboard
661 // ----------------------------------------------------------------------------
662
663 void IO::key_down(int code)
664 {
665         int fctn, ptr;
666         
667         switch(code) {
668         case 0x10:
669                 shift = true;
670                 if(udk_on) {
671                         draw_udk();
672                 }
673                 break;
674         case 0x11:
675                 ctrl = true;
676                 break;
677         case 0x12:
678                 if(graph) {
679                         graph = kana = false;
680                 } else {
681                         graph = true;
682                 }
683                 break;
684         case 0x13:
685                 brk = true;
686                 update_intr();
687                 break;
688         case 0x15:
689                 if(kana) {
690                         graph = kana = false;
691                 } else {
692                         kana = true;
693                 }
694                 break;
695         case 0x20:
696                 strig1 = 0;
697                 goto strig_key;
698         case 0x25:      // left
699                 stick = 0x37;
700                 code = 0x1d;
701                 goto strig_key;
702         case 0x26:      // up
703                 stick = 0x31;
704                 code = 0x1e;
705                 goto strig_key;
706         case 0x27:      // right
707                 stick = 0x32;
708                 code = 0x1c;
709                 goto strig_key;
710         case 0x28:      // down
711                 stick = 0x36;
712                 code = 0x1f;
713 strig_key:
714                 if(!key_buf->full()) {
715                         key_buf->write(code);
716                         update_intr();
717                 }
718                 break;
719         case 0x70:      // F1
720                 fctn = shift ? 6 : 0;
721                 goto fkey;
722         case 0x71:      // F2
723                 fctn = shift ? 7 : 1;
724                 goto fkey;
725         case 0x72:      // F3
726                 fctn = shift ? 8 : 2;
727                 goto fkey;
728         case 0x73:      // F4
729                 fctn = shift ? 9 : 3;
730                 goto fkey;
731         case 0x74:      // F5
732                 fctn = shift ? 10 : 4;
733                 goto fkey;
734         case 0x75:      // F6
735                 strig = 0;
736                 fctn = shift ? 11 : 5;
737                 goto fkey;
738         case 0x76:      // F7
739                 fctn = 6;
740                 goto fkey;
741         case 0x77:      // F8
742                 fctn = 7;
743                 goto fkey;
744         case 0x78:      // F9
745                 fctn = 8;
746                 goto fkey;
747         case 0x79:      // F10
748                 fctn = 9;
749                 goto fkey;
750         case 0x7a:      // F11
751                 fctn = 10;
752                 goto fkey;
753         case 0x7b:      // F12
754                 fctn = 11;
755 fkey:
756                 ptr = udk_ofs[fctn] + 3;
757                 for(;;) {
758                         uint8 val = wram[ptr++];
759                         if(!val) {
760                                 break;
761                         }
762                         if(!key_buf->full()) {
763                                 key_buf->write(val);
764                         }
765                 }
766                 if(!key_buf->empty()) {
767                         update_intr();
768                 }
769                 break;
770         default:
771                 if(!key_buf->full()) {
772                         uint8 val = 0;
773                         if(ctrl) {
774                                 val = key_tbl_c[code];
775                         } else if(kana) {
776                                 if(shift) {
777                                         val = key_tbl_ks[code];
778                                 } else {
779                                         val = key_tbl_k[code];
780                                 }
781                         } else if(graph) {
782                                 val = key_tbl_g[code];
783                         } else {
784                                 if(shift) {
785                                         val = key_tbl_s[code];
786                                 } else {
787                                         val = key_tbl[code];
788                                 }
789                         }
790                         if(val) {
791                                 key_buf->write(val);
792                                 update_intr();
793                         }
794                 }
795         }
796 }
797
798 void IO::key_up(int code)
799 {
800         switch(code) {
801         case 0x08:      // bs->left
802                 stick = 0x30;
803                 break;
804         case 0x10:
805                 shift = false;
806                 if(udk_on) {
807                         draw_udk();
808                 }
809                 break;
810         case 0x11:
811                 ctrl = false;
812                 break;
813         case 0x20:
814                 strig1 = 0xff;
815                 break;
816         case 0x25:      // left
817         case 0x26:      // up
818         case 0x27:      // right
819         case 0x28:      // down
820                 stick = 0x30;
821                 break;
822         case 0x75:      // F6
823                 strig = 0xff;
824                 break;
825         }
826 }
827
828 // ----------------------------------------------------------------------------
829 // cmt
830 // ----------------------------------------------------------------------------
831
832 void IO::play_tape(_TCHAR* file_path)
833 {
834         close_tape();
835         if(cmt_fio->Fopen(file_path, FILEIO_READ_BINARY)) {
836                 cmt_fio->Fseek(0, FILEIO_SEEK_END);
837                 cmt_len = min(cmt_fio->Ftell(), CMT_BUF_SIZE);
838                 cmt_fio->Fseek(0, FILEIO_SEEK_SET);
839                 memset(cmt_buf, 0, sizeof(cmt_buf));
840                 cmt_fio->Fread(cmt_buf, cmt_len, 1);
841                 cmt_fio->Fclose();
842                 cmt_ptr = 0;
843                 cmt_play = true;
844                 // receive first byte
845                 if(cmt_mode && (wregs[5] & 4)) {
846                         recv_from_cmt();
847                 }
848         }
849 }
850
851 void IO::rec_tape(_TCHAR* file_path)
852 {
853         close_tape();
854         if(cmt_fio->Fopen(file_path, FILEIO_READ_WRITE_NEW_BINARY)) {
855                 _tcscpy_s(rec_file_path, _MAX_PATH, file_path);
856                 cmt_ptr = 0;
857                 cmt_rec = true;
858         }
859 }
860
861 void IO::close_tape()
862 {
863         if(cmt_fio->IsOpened()) {
864                 if(cmt_rec && cmt_ptr) {
865                         cmt_fio->Fwrite(cmt_buf, cmt_ptr, 1);
866                 }
867                 cmt_fio->Fclose();
868         }
869         cmt_play = cmt_rec = false;
870 }
871
872 void IO::send_to_cmt()
873 {
874         if(cmt_rec && cmt_mode) {
875                 cmt_buf[cmt_ptr++] = wregs[7];
876                 if(!(cmt_ptr &= (CMT_BUF_SIZE - 1))) {
877                         cmt_fio->Fwrite(cmt_buf, sizeof(cmt_buf), 1);
878                 }
879         }
880 }
881
882 void IO::recv_from_cmt()
883 {
884         if(cmt_play && cmt_mode) {
885                 rregs[6] |= 2;
886                 rregs[7] = (cmt_ptr < cmt_len) ? cmt_buf[cmt_ptr++] : 0;
887                 // register event for rstb
888                 register_event(this, EVENT_CMT, 2000, false, NULL);
889         }
890 }
891
892 // ----------------------------------------------------------------------------
893 // sub cpu
894 // ----------------------------------------------------------------------------
895
896 void IO::send_to_sub()
897 {
898         // send command
899         if(cmd_buf->empty()) {
900                 if(locate_on && (wregs[1] & 0x7f) != 0x24 && 0x20 <= wregs[1] && wregs[1] < 0x80) {
901                         cursor_x++;
902                         draw_font(cursor_x, cursor_x, wregs[1]);
903                 } else {
904                         if((wregs[1] & 0x7f) < 0x47) {
905                                 cmd_buf->write(wregs[1] & 0x7f);
906                         }
907                         locate_on = 0;
908                 }
909         } else {
910                 cmd_buf->write(wregs[1]);
911                 if(cmd_buf->count() == 2) {
912                         uint8 cmd_type = cmd_buf->read_not_remove(0);
913                         if(cmd_type == 7 && wregs[1] > 4) {
914                                 cmd_buf->clear();
915                                 cmd_buf->write(wregs[1] & 0x7f);
916                         } else if(cmd_type == 0x0c && wregs[1] == 0xb0) {
917                                 memset(lcd, 0, sizeof(lcd));
918                                 cmd_buf->clear();
919                                 cmd_buf->write(wregs[1] & 0x7f);
920                         }
921                 }
922         }
923         // check cmd length
924         if(!cmd_buf->empty()) {
925                 uint8 cmd_type = cmd_buf->read_not_remove(0);
926                 uint8 cmd_len = sub_cmd_len[cmd_type];
927                 if(cmd_len & 0x80) {
928                         if((cmd_len & 0x7f) < cmd_buf->count() && !wregs[1]) {
929                                 cmd_len = cmd_buf->count();
930                         }
931                 }
932                 if(cmd_buf->count() == cmd_len) {
933                         // process command
934                         rsp_buf->clear();
935                         process_sub();
936                         cmd_buf->clear();
937                         if(rsp_buf->count()) {
938                                 sub_int |= 1;
939                                 update_intr();
940                         }
941 //                      emu->out_debug_log("CMD TYPE = %2x, LEN = %d RSP=%d\n", cmd_type, cmd_len, rsp_buf->count());
942                 }
943         }
944 }
945
946 void IO::recv_from_sub()
947 {
948         rregs[0] = 0x40;
949         rregs[1] = rsp_buf->read_not_remove(0);
950         rregs[2] |= 1;
951 }
952
953 void IO::ack_from_sub()
954 {
955         rsp_buf->read();
956         rregs[2] &= 0xfe;
957         if(!rsp_buf->empty()) {
958                 sub_int |= 1;
959                 update_intr();
960         }
961 }
962
963 void IO::process_sub()
964 {
965         static const uint8 dow[8] = {128, 192, 224, 240, 248, 252, 254, 255};
966         uint8 val;
967         uint16 addr;
968         int sx, sy, ex, ey, cr, i;
969         
970         uint8 cmd_type = cmd_buf->read();
971         switch(cmd_type & 0x7f) {
972         case 0x00:      // unknown
973                 break;
974         case 0x01:      // TimeCall
975                 rsp_buf->write((cur_time.year >> 8) & 0xff);
976                 rsp_buf->write(cur_time.year & 0xff);
977                 rsp_buf->write(cur_time.month);
978                 rsp_buf->write(cur_time.day);
979                 rsp_buf->write(dow[cur_time.day_of_week]);
980                 rsp_buf->write(cur_time.hour);
981                 rsp_buf->write(cur_time.minute);
982                 rsp_buf->write(cur_time.second);
983                 break;
984         case 0x02:      // Stick
985                 rsp_buf->write(stick);
986                 break;
987         case 0x03:      // Strig
988                 rsp_buf->write(strig);
989                 break;
990         case 0x04:      // Strig1
991                 rsp_buf->write(strig1);
992                 break;
993         case 0x05:      // RamRead
994                 addr = cmd_buf->read();
995                 addr |= cmd_buf->read() << 8;
996                 if(addr == 0xc00e) {
997                         val = 0x0a;
998                 } else if(addr == 0xd000) {
999                         val = 0x30;
1000                 } else if(WRAM_OFS_UDC0 <= addr && addr < WRAM_OFS_UDC1) {
1001                         val = udc[FONT_OFS_UDC0 + (addr - WRAM_OFS_UDC0)];
1002                 } else if(WRAM_OFS_UDC1 <= addr && addr < WRAM_OFS_KBUF) {
1003                         val = udc[FONT_OFS_UDC1 + (addr - WRAM_OFS_UDC1)];
1004                 } else {
1005                         val = wram[addr & 0x7ff];
1006                 }
1007                 rsp_buf->write(val);
1008                 break;
1009         case 0x06:      // RamWrite
1010                 val = cmd_buf->read();
1011                 addr = cmd_buf->read();
1012                 addr |= cmd_buf->read() << 8;
1013                 if(WRAM_OFS_UDC0 <= addr && addr < WRAM_OFS_UDC1) {
1014                         udc[FONT_OFS_UDC0 + (addr - WRAM_OFS_UDC0)] = val;
1015                 } else if(WRAM_OFS_UDC1 <= addr && addr < WRAM_OFS_KBUF) {
1016                         udc[FONT_OFS_UDC1 + (addr - WRAM_OFS_UDC1)] = val;
1017                 } else {
1018                         wram[addr & 0x7ff] = val;
1019                 }
1020                 break;
1021         case 0x07:      // ScrollSet
1022                 scroll_min = cmd_buf->read();
1023                 scroll_max = cmd_buf->read() + 1;
1024                 break;
1025         case 0x08:      // ScrollExec
1026                 scroll();
1027                 break;
1028         case 0x09:      // LineClear
1029                 val = cmd_buf->read();
1030                 line_clear(val);
1031                 break;
1032         case 0x0a:      // TimeSet
1033                 cur_time.second = cmd_buf->read();
1034                 cur_time.minute = cmd_buf->read();
1035                 cur_time.hour = cmd_buf->read();
1036                 cmd_buf->read(); // day of week
1037                 cur_time.day = cmd_buf->read();
1038                 cur_time.month = cmd_buf->read();
1039                 cur_time.year = cmd_buf->read();
1040                 cur_time.year |= cmd_buf->read() << 8;
1041                 cur_time.update_year();
1042                 cur_time.update_day_of_week();
1043                 // restart event
1044                 cancel_event(this, register_id_1sec);
1045                 register_event(this, EVENT_1SEC, 1000000, true, &register_id_1sec);
1046                 break;
1047         case 0x0b:      // CalcDay
1048                 break;
1049         case 0x0c:      // AlarmSet
1050                 for(i = 0; i < 8; i++) {
1051                         alarm[i] = cmd_buf->read();
1052                 }
1053                 break;
1054         case 0x0d:      // BuzzerOff
1055 //              d_beep->write_signal(SIG_BEEP_ON, 0, 0);
1056                 break;
1057         case 0x0e:      // BuzzerOn
1058 //              d_beep->write_signal(SIG_BEEP_ON, 1, 1);
1059                 break;
1060         case 0x0f:      // TrfLine
1061                 sy = cmd_buf->read();
1062                 for(i = 0; i < 120; i++) {
1063                         if(sy < 32) {
1064                                 rsp_buf->write(lcd[sy][i]);
1065                         } else {
1066                                 rsp_buf->write(0);
1067                         }
1068                 }
1069                 break;
1070         case 0x10:      // TestPoint
1071                 sx = cmd_buf->read();
1072                 sy = cmd_buf->read();
1073                 if(sx < 120 && sy < 32) {
1074                         rsp_buf->write(lcd[sy][sx]);
1075                 } else {
1076                         rsp_buf->write(0);
1077                 }
1078                 break;
1079         case 0x11:      // Pset
1080                 sx = cmd_buf->read();
1081                 sy = cmd_buf->read();
1082                 draw_point(sx, sy, 0xff);
1083                 break;
1084         case 0x12:      // Preset
1085                 sx = cmd_buf->read();
1086                 sy = cmd_buf->read();
1087                 draw_point(sx, sy, 0);
1088                 break;
1089         case 0x13:      // Peor
1090                 sx = cmd_buf->read();
1091                 sy = cmd_buf->read();
1092                 if(sx < 120 && sy < 32) {
1093                         lcd[sy][sx] = ~lcd[sy][sx];
1094                 }
1095                 break;
1096         case 0x14:      // Line
1097                 sx = cmd_buf->read();
1098                 sy = cmd_buf->read();
1099                 ex = cmd_buf->read();
1100                 ey = cmd_buf->read();
1101                 draw_line(sx, sy, ex, ey);
1102                 break;
1103         case 0x15:      // Circle
1104                 sx = cmd_buf->read();
1105                 sy = cmd_buf->read();
1106                 cr = cmd_buf->read();
1107                 draw_circle(sx, sy, cr);
1108                 break;
1109         case 0x16:      // UDKWrite
1110                 val = cmd_buf->read();
1111                 for(i = 0; i < udk_size[val]; i++) {
1112                         wram[udk_ofs[val] + i] = cmd_buf->read();
1113                 }
1114                 break;
1115         case 0x17:      // UDKRead
1116                 val = cmd_buf->read();
1117                 for(i = 0; i < udk_size[val]; i++) {
1118                         uint8 code = wram[udk_ofs[val] + i];
1119                         rsp_buf->write(code);
1120                         if(!code) {
1121                                 break;
1122                         }
1123                 }
1124                 break;
1125         case 0x18:      // UDKOn
1126         case 0x19:      // UDKOff
1127                 break;
1128         case 0x1a:      // UDCWrite
1129                 addr = cmd_buf->read() << 3;
1130                 for(i = 0; i < 8; i++) {
1131                         udc[addr + i] = cmd_buf->read();
1132                 }
1133                 break;
1134         case 0x1b:      // UDCRead
1135                 addr = cmd_buf->read() << 3;
1136                 for(i = 0; i < 8; i++) {
1137                         rsp_buf->write(udc[addr + i]);
1138                 }
1139                 break;
1140         case 0x1c:      // UDCInit
1141                 memcpy(udc, font, sizeof(udc));
1142                 break;
1143         case 0x1d:      // StartPgmWrite
1144                 break;
1145         case 0x1e:      // SPWriteCont
1146                 break;
1147         case 0x1f:      // SPOn
1148                 break;
1149         case 0x20:      // SPOff
1150                 break;
1151         case 0x21:      // StartPgmRead
1152                 for(i = 0; i < 128; i++) {
1153                         rsp_buf->write(0);
1154                 }
1155                 break;
1156         case 0x22:      // OnStat
1157                 rsp_buf->write(4);      // 0x41 ?
1158                 break;
1159         case 0x23:      // OFFReq
1160                 break;
1161         case 0x24:      // Locate
1162                 sx = cmd_buf->read();
1163                 sy = cmd_buf->read();
1164                 val = cmd_buf->read();
1165                 locate_on = (locate_x != sx || locate_y != sy);
1166                 locate_x = cursor_x = sx;
1167                 locate_y = cursor_y = sy;
1168                 if(val) {
1169                         draw_font(sx, sy, val);
1170                 }
1171                 break;
1172         case 0x25:      // CursOn
1173                 cursor_on = true;
1174                 break;
1175         case 0x26:      // CursOff
1176                 cursor_on = false;
1177                 break;
1178         case 0x27:      // TestKey
1179         case 0x28:      // TestChr
1180                 rsp_buf->write(0);
1181                 break;
1182         case 0x29:      // InitSec
1183         case 0x2a:      // InitDate
1184         case 0x2b:      // ScrOff
1185         case 0x2c:      // ScrOn
1186                 break;
1187         case 0x2d:      // KeyBufferClear
1188                 key_buf->clear();
1189                 break;
1190         case 0x2e:      // ClsScr
1191                 memset(lcd, 0, sizeof(lcd));
1192                 break;
1193         case 0x2f:      // Home
1194                 cursor_x = cursor_y = 0;
1195                 break;
1196         case 0x30:      // UDKOn
1197                 udk_on = true;
1198                 draw_udk();
1199                 break;
1200         case 0x31:      // UDKOff
1201                 udk_on = false;
1202                 line_clear(3);
1203                 break;
1204         case 0x36:      // AlarmRead
1205                 for(i = 0; i < 8; i++) {
1206                         rsp_buf->write(alarm[i]);
1207                 }
1208                 break;
1209         case 0x37:      // BuzzZero
1210                 rsp_buf->write(0);
1211                 break;
1212         case 0x40:
1213                 memset(wram, 0, 0x200);
1214                 for(i = 0; i < 12; i++) {
1215                         strcpy((char*)wram + udk_ofs[i], udk_ini[i]);
1216                 }
1217                 for(i = 0; i < 0x200; i++) {
1218                         // CR
1219                         if(wram[i] == '^') {
1220                                 wram[i] = 13;
1221                         }
1222                 }
1223                 break;
1224         case 0x42:      // ReadCar
1225                 for(i = 0; i < 8; i++) {
1226                         rsp_buf->write(0);
1227                 }
1228                 break;
1229         case 0x43:      // ScanR
1230         case 0x44:      // ScanL
1231                 rsp_buf->write(0);
1232                 rsp_buf->write(0);
1233                 break;
1234         case 0x45:      // TimeChk
1235         case 0x46:      // AlmChk
1236                 rsp_buf->write(0);
1237                 break;
1238         }
1239 }
1240
1241 #define STATE_VERSION   1
1242
1243 void IO::save_state(FILEIO* state_fio)
1244 {
1245         state_fio->FputUint32(STATE_VERSION);
1246         state_fio->FputInt32(this_device_id);
1247         
1248         state_fio->Fwrite(rregs, sizeof(rregs), 1);
1249         state_fio->Fwrite(wregs, sizeof(wregs), 1);
1250         cur_time.save_state((void *)state_fio);
1251         state_fio->FputInt32(register_id_1sec);
1252         cmd_buf->save_state((void *)state_fio);
1253         rsp_buf->save_state((void *)state_fio);
1254         state_fio->FputUint8(sub_int);
1255         state_fio->Fwrite(wram, sizeof(wram), 1);
1256         state_fio->Fwrite(alarm, sizeof(alarm), 1);
1257         key_buf->save_state((void *)state_fio);
1258         state_fio->FputBool(ctrl);
1259         state_fio->FputBool(shift);
1260         state_fio->FputBool(kana);
1261         state_fio->FputBool(graph);
1262         state_fio->FputBool(brk);
1263         state_fio->FputUint8(stick);
1264         state_fio->FputUint8(strig);
1265         state_fio->FputUint8(strig1);
1266         state_fio->FputBool(cmt_play);
1267         state_fio->FputBool(cmt_rec);
1268         state_fio->FputBool(cmt_mode);
1269         state_fio->Fwrite(rec_file_path, sizeof(rec_file_path), 1);
1270         if(cmt_rec && cmt_fio->IsOpened()) {
1271                 int length_tmp = (int)cmt_fio->Ftell();
1272                 cmt_fio->Fseek(0, FILEIO_SEEK_SET);
1273                 state_fio->FputInt32(length_tmp);
1274                 while(length_tmp != 0) {
1275                         uint8 buffer_tmp[1024];
1276                         int length_rw = min(length_tmp, sizeof(buffer_tmp));
1277                         cmt_fio->Fread(buffer_tmp, length_rw, 1);
1278                         state_fio->Fwrite(buffer_tmp, length_rw, 1);
1279                         length_tmp -= length_rw;
1280                 }
1281         } else {
1282                 state_fio->FputInt32(0);
1283         }
1284         state_fio->FputInt32(cmt_len);
1285         state_fio->FputInt32(cmt_ptr);
1286         state_fio->Fwrite(cmt_buf, sizeof(cmt_buf), 1);
1287         state_fio->FputBool(vblank);
1288         state_fio->FputUint8(font_code);
1289         state_fio->Fwrite(udc, sizeof(udc), 1);
1290         state_fio->Fwrite(lcd, sizeof(lcd), 1);
1291         state_fio->FputBool(locate_on);
1292         state_fio->FputBool(cursor_on);
1293         state_fio->FputBool(udk_on);
1294         state_fio->FputInt32(locate_x);
1295         state_fio->FputInt32(locate_y);
1296         state_fio->FputInt32(cursor_x);
1297         state_fio->FputInt32(cursor_y);
1298         state_fio->FputInt32(cursor_blink);
1299         state_fio->FputInt32(scroll_min);
1300         state_fio->FputInt32(scroll_max);
1301         state_fio->FputInt32(register_id_beep);
1302 }
1303
1304 bool IO::load_state(FILEIO* state_fio)
1305 {
1306         close_tape();
1307         
1308         if(state_fio->FgetUint32() != STATE_VERSION) {
1309                 return false;
1310         }
1311         if(state_fio->FgetInt32() != this_device_id) {
1312                 return false;
1313         }
1314         state_fio->Fread(rregs, sizeof(rregs), 1);
1315         state_fio->Fread(wregs, sizeof(wregs), 1);
1316         if(!cur_time.load_state((void *)state_fio)) {
1317                 return false;
1318         }
1319         register_id_1sec = state_fio->FgetInt32();
1320         if(!cmd_buf->load_state((void *)state_fio)) {
1321                 return false;
1322         }
1323         if(!rsp_buf->load_state((void *)state_fio)) {
1324                 return false;
1325         }
1326         sub_int = state_fio->FgetUint8();
1327         state_fio->Fread(wram, sizeof(wram), 1);
1328         state_fio->Fread(alarm, sizeof(alarm), 1);
1329         if(!key_buf->load_state((void *)state_fio)) {
1330                 return false;
1331         }
1332         ctrl = state_fio->FgetBool();
1333         shift = state_fio->FgetBool();
1334         kana = state_fio->FgetBool();
1335         graph = state_fio->FgetBool();
1336         brk = state_fio->FgetBool();
1337         stick = state_fio->FgetUint8();
1338         strig = state_fio->FgetUint8();
1339         strig1 = state_fio->FgetUint8();
1340         cmt_play = state_fio->FgetBool();
1341         cmt_rec = state_fio->FgetBool();
1342         cmt_mode = state_fio->FgetBool();
1343         state_fio->Fread(rec_file_path, sizeof(rec_file_path), 1);
1344         int length_tmp = state_fio->FgetInt32();
1345         if(cmt_rec) {
1346                 cmt_fio->Fopen(rec_file_path, FILEIO_READ_WRITE_NEW_BINARY);
1347                 while(length_tmp != 0) {
1348                         uint8 buffer_tmp[1024];
1349                         int length_rw = min(length_tmp, sizeof(buffer_tmp));
1350                         state_fio->Fread(buffer_tmp, length_rw, 1);
1351                         if(cmt_fio->IsOpened()) {
1352                                 cmt_fio->Fwrite(buffer_tmp, length_rw, 1);
1353                         }
1354                         length_tmp -= length_rw;
1355                 }
1356         }
1357         cmt_len = state_fio->FgetInt32();
1358         cmt_ptr = state_fio->FgetInt32();
1359         state_fio->Fread(cmt_buf, sizeof(cmt_buf), 1);
1360         vblank = state_fio->FgetBool();
1361         font_code = state_fio->FgetUint8();
1362         state_fio->Fread(udc, sizeof(udc), 1);
1363         state_fio->Fread(lcd, sizeof(lcd), 1);
1364         locate_on = state_fio->FgetBool();
1365         cursor_on = state_fio->FgetBool();
1366         udk_on = state_fio->FgetBool();
1367         locate_x = state_fio->FgetInt32();
1368         locate_y = state_fio->FgetInt32();
1369         cursor_x = state_fio->FgetInt32();
1370         cursor_y = state_fio->FgetInt32();
1371         cursor_blink = state_fio->FgetInt32();
1372         scroll_min = state_fio->FgetInt32();
1373         scroll_max = state_fio->FgetInt32();
1374         register_id_beep = state_fio->FgetInt32();
1375         return true;
1376 }
1377