OSDN Git Service

[VM][General][WIP] Start to merge upstream 2018-10-14.Open branch upstream_20181014 .
[csp-qt/common_source_project-fm7.git] / source / src / vm / yalky / io.cpp
1 /*
2         Yuasa Kyouiku System YALKY Emulator 'eYALKY'
3
4         Author : Takeda.Toshiya
5         Date   : 2016.03.28-
6
7         [ i/o ]
8 */
9
10 #include "io.h"
11 #include "../datarec.h"
12 #include "../i8080.h"
13 #include "../i8155.h"
14
15 #define EVENT_COUNTER   0
16
17 namespace YALKY {
18
19 /*
20 SID     <- DATA RECORDER SIGNAL (NEGATIVE, L H L H L L H H ...)
21 RST5    <- DATA RECORDER SIGNAL (POSITIVE, H L H L H H L L ...)
22 RST7    <- I8156 TIMER OUT (3MHz ???, OSC = 6MHz)
23
24 PA0     <- KEYBOARD DATA
25 PA1     <- KEYBOARD DATA
26 PA2     <- KEYBOARD DATA
27 PA3     <- KEYBOARD DATA
28 PA4     <- KEYBOARD DATA
29 PA5     <- DATA RECORDER SIGNAL (0 = NO SIGNAL)
30 PA6     <- COUNTER (4520) QB2
31 PA7     <- MODEL TYPE ??? (H = PM-1001)
32
33 PB0     -> 7948 Pin #6
34 PB1     -> FONT ROM (2364) A12, FONT BANK SWITCH
35 PB2     -> 7945 Pin #1
36 PB3     -> LED
37 PB4     -> COUNTER (4520) RESET B
38 PB5     -> DATA RECORDER H = FAST FORWARD or REC ???
39 PB6     -> DATA RECORDER H = PLAY, L = STOP
40 PB7     -> DATA RECORDER H = FAST REWIND
41
42 PC0     -> KEYBOARD COLUMN
43 PC1     -> KEYBOARD COLUMN
44 PC2     -> KEYBOARD COLUMN
45 PC3     -> ???
46 PC4     -> ???
47
48         PA0     PA1     PA2     PA3     PA4
49 PC0     0       1       2       3       4
50 PC1     5       6       7       8       9
51 PC2     POINT   CLEAR   MARK    BACK    SET
52 */
53
54 void IO::initialize()
55 {
56         // load font rom image
57         FILEIO* fio = new FILEIO();
58         if(fio->Fopen(create_local_path(_T("FONT.ROM")), FILEIO_READ_BINARY)) {
59                 fio->Fread(font, sizeof(font), 1);
60                 fio->Fclose();
61         }
62         delete fio;
63         
64         key_stat = emu->get_key_buffer();
65         pb = pc = 0xff;
66         prev_clock = 0;
67         
68         register_frame_event(this);
69         register_id = -1;
70         adjust_event_timing();
71 }
72
73 void IO::reset()
74 {
75         div_counter = counter = 0;
76         posi_counter = nega_counter = 0;
77         drec_in = drec_toggle = false;
78 }
79
80 void IO::adjust_event_timing()
81 {
82         if(register_id != -1) {
83                 cancel_event(this, register_id);
84         }
85         double freq = d_drec->get_ave_hi_freq() * 1.4;
86         register_event(this, EVENT_COUNTER, 1000000.0 / freq, true, &register_id);
87 }
88
89 void IO::write_io8(uint32_t addr, uint32_t data)
90 {
91         switch(addr & 0xff) {
92         case 0x00:
93         case 0x01:
94         case 0x02:
95         case 0x03:
96         case 0x04:
97         case 0x05:
98         case 0x06:
99         case 0x07:
100                 d_pio->write_io8(addr, data);
101                 break;
102         }
103 }
104
105 uint32_t IO::read_io8(uint32_t addr)
106 {
107         switch(addr & 0xff) {
108         case 0x00:
109         case 0x01:
110         case 0x02:
111         case 0x03:
112         case 0x04:
113         case 0x05:
114         case 0x06:
115         case 0x07:
116                 return d_pio->read_io8(addr);
117         }
118         return 0xff;
119 }
120
121 void IO::write_signal(int id, uint32_t data, uint32_t mask)
122 {
123         switch(id) {
124         case SIG_IO_PORT_B:
125                 {
126                         uint8_t prev = pb;
127                         pb &= ~mask;
128                         pb |= data & mask;
129                         
130                         if((prev & 0x10) && !(pb & 0x10)) {
131                                 adjust_event_timing();
132                                 counter = 1;//0;
133                                 update_counter();
134                         }
135                         if(!(prev & 0x80) && (pb & 0x80)) {
136                                 d_drec->set_ff_rew(-1);
137                         } else if((prev & 0x80) && !(pb & 0x80)) {
138                                 d_drec->set_ff_rew(0);
139                         }
140                         if(!(prev & 0x40) && (pb & 0x40)) {
141                                 d_drec->set_remote(true);
142                         } else if((prev & 0x40) && !(pb & 0x40)) {
143                                 d_drec->set_remote(false);
144                         }
145                 }
146                 break;
147                 
148         case SIG_IO_PORT_C:
149                 {
150                         uint8_t prev = pc;
151                         pc &= ~mask;
152                         pc |= data & mask;
153                         update_key();
154                 }
155                 break;
156                 
157         case SIG_IO_DREC_EAR:
158                 {
159                         bool prev_in = drec_in;
160                         bool prev_toggle = drec_toggle;
161                         
162                         drec_in = ((data & mask) != 0);
163                         
164                         if(drec_in) {
165                                 posi_counter++;
166                         } else {
167                                 nega_counter++;
168                         }
169                         if(!prev_in && drec_in) {
170                                 if(prev_clock == 0 || get_passed_usec(prev_clock) > 1000000.0 / d_drec->get_ave_hi_freq() * 6) {
171                                         div_counter = 0;
172                                         drec_toggle = false;
173                                 }
174                                 prev_clock = get_current_clock();
175                                 
176                                 if(++div_counter & 1) {
177                                         drec_toggle = !drec_toggle;
178                                 }
179                         }
180                         if(!prev_toggle && drec_toggle) {
181                                 if(counter >= 8) {
182                                         adjust_event_timing();
183                                         counter = 1;
184                                         update_counter();
185                                 }
186                         }
187                         d_cpu->write_signal(SIG_I8085_SID, !drec_toggle ? 0xffffffff : 0, 1);   // negative
188                         d_cpu->write_signal(SIG_I8085_RST5, drec_toggle ? 0xffffffff : 0, 1);   // positive
189                 }
190                 break;
191         }
192 }
193
194 void IO::event_callback(int event_id, int err)
195 {
196         update_counter();
197         counter++;
198 }
199
200 void IO::update_counter()
201 {
202         d_pio->write_signal(SIG_I8155_PORT_A, (counter >= 4) ? 0xffffffff : 0, 0x40);
203 }
204
205 void IO::event_frame()
206 {
207         if((posi_counter + nega_counter) > ((pb & 0x80) ? DATAREC_FAST_REW_SPEED : 1) * 10) {
208                 int ratio = (100 * posi_counter) / (posi_counter + nega_counter);
209                 posi_counter = nega_counter = 0;
210                 d_pio->write_signal(SIG_I8155_PORT_A, (ratio > 40 && ratio < 60) ? 0xffffffff : 0, 0x20);
211         } else {
212                 d_pio->write_signal(SIG_I8155_PORT_A, 0, 0x20);
213         }
214         update_key();
215 }
216
217 void IO::update_key()
218 {
219         uint8_t value = 0xff;
220         
221         if(!(pc & 0x01)) {
222                 if(key_stat[0x30] || key_stat[0x60]) value &= ~0x01;    // 0
223                 if(key_stat[0x31] || key_stat[0x61]) value &= ~0x02;    // 1
224                 if(key_stat[0x32] || key_stat[0x62]) value &= ~0x04;    // 2
225                 if(key_stat[0x33] || key_stat[0x63]) value &= ~0x08;    // 3
226                 if(key_stat[0x34] || key_stat[0x64]) value &= ~0x10;    // 4
227         }
228         if(!(pc & 0x02)) {
229                 if(key_stat[0x35] || key_stat[0x65]) value &= ~0x01;    // 5
230                 if(key_stat[0x36] || key_stat[0x66]) value &= ~0x02;    // 6
231                 if(key_stat[0x37] || key_stat[0x67]) value &= ~0x04;    // 7
232                 if(key_stat[0x38] || key_stat[0x68]) value &= ~0x08;    // 8
233                 if(key_stat[0x39] || key_stat[0x69]) value &= ~0x10;    // 9
234         }
235         if(!(pc & 0x04)) {
236                 if(key_stat[0xbe] || key_stat[0x6e]) value &= ~0x01;    // DECIMAL POINT
237                 if(key_stat[0x43] || key_stat[0x08]) value &= ~0x02;    // CLEAR -> C or BACK SPACE
238                 if(key_stat[0x4d] || key_stat[0x20]) value &= ~0x04;    // MARK  -> M or SPACE
239                 if(key_stat[0x42] || key_stat[0x1b]) value &= ~0x08;    // BACK  -> B or ESC
240                 if(key_stat[0x53] || key_stat[0x0d]) value &= ~0x10;    // SET   -> S or ENTER
241         }
242         d_pio->write_signal(SIG_I8155_PORT_A, value, 0x1f);
243 }
244
245 void IO::draw_screen()
246 {
247         scrntype_t cd = RGB_COLOR(0, 255, 0);
248         scrntype_t cb = RGB_COLOR(0, 0, 0);
249         
250         for(int y = 0; y < 16; y++) {
251                 for(int x = 0; x < 32; x++) {
252                         uint8_t code = vram[x + y * 32];
253 //                      uint8_t attr = vram[x + y * 32 + 512];
254                         
255                         for(int l = 0; l < 16; l++) {
256                                 scrntype_t* dst = emu->get_screen_buffer(y * 16 + l) + x * 8;
257                                 uint8_t pattern = font[(code * 16 + l) | ((pb & 2) ? 0x1000 : 0)];
258                                 
259                                 dst[0] = (pattern & 0x80) ? cd : cb;
260                                 dst[1] = (pattern & 0x40) ? cd : cb;
261                                 dst[2] = (pattern & 0x20) ? cd : cb;
262                                 dst[3] = (pattern & 0x10) ? cd : cb;
263                                 dst[4] = (pattern & 0x08) ? cd : cb;
264                                 dst[5] = (pattern & 0x04) ? cd : cb;
265                                 dst[6] = (pattern & 0x02) ? cd : cb;
266                                 dst[7] = (pattern & 0x01) ? cd : cb;
267                         }
268                 }
269         }
270 }
271
272 #define STATE_VERSION   2
273
274 bool IO::process_state(FILEIO* state_fio, bool loading)
275 {
276         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
277                 return false;
278         }
279         if(!state_fio->StateCheckInt32(this_device_id)) {
280                 return false;
281         }
282         state_fio->StateValue(pb);
283         state_fio->StateValue(pc);
284         state_fio->StateValue(div_counter);
285         state_fio->StateValue(counter);
286         state_fio->StateValue(posi_counter);
287         state_fio->StateValue(nega_counter);
288         state_fio->StateValue(drec_in);
289         state_fio->StateValue(drec_toggle);
290         state_fio->StateValue(prev_clock);
291         state_fio->StateValue(register_id);
292         return true;
293 }
294
295 }