2 Skelton for retropc emulator
4 Author : Takeda.Toshiya
12 #define EVENT_DISPLAY 0
13 #define EVENT_HSYNC_S 1
14 #define EVENT_HSYNC_E 2
16 void HD46505::initialize()
18 memset(regs, 0, sizeof(regs));
19 memset(regs_written, 0, sizeof(regs_written));
22 register_frame_event(this);
23 register_vline_event(this);
30 vblank = vsync = hsync = true;
32 // memset(regs, 0, sizeof(regs));
35 // initial settings for 1st frame
37 hz_total = (CHARS_PER_LINE > 54) ? CHARS_PER_LINE : 54;
41 hz_disp = (hz_total > 80) ? 80 : 40;
42 hs_start = hz_disp + 4;
43 hs_end = hs_start + 4;
45 vt_total = LINES_PER_FRAME;
46 vt_disp = (SCREEN_HEIGHT > LINES_PER_FRAME) ? (SCREEN_HEIGHT >> 1) : SCREEN_HEIGHT;
47 vs_start = vt_disp + 16;
48 vs_end = vs_start + 16;
50 timing_changed = false;
53 #if defined(HD46505_CHAR_CLOCK)
55 next_char_clock = HD46505_CHAR_CLOCK;
56 #elif defined(HD46505_HORIZ_FREQ)
58 next_horiz_freq = HD46505_HORIZ_FREQ;
62 void HD46505::write_io8(uint32_t addr, uint32_t data)
66 if(ch < 10 && regs[ch] != data) {
67 timing_changed = true;
70 regs_written[ch] = true;
77 uint32_t HD46505::read_io8(uint32_t addr)
80 return (12 <= ch && ch < 18) ? regs[ch] : 0xff;
86 void HD46505::event_pre_frame()
89 if(regs_written[0] && regs_written[1] && regs_written[2] && regs_written[3] && regs_written[4] && regs_written[5] && regs_written[6] && regs_written[7] && regs_written[9]) {
90 int ch_height = (regs[9] & 0x1f) + 1;
92 hz_total = regs[0] + 1;
95 hs_end = hs_start + (regs[3] & 0x0f);
97 int new_vt_total = ((regs[4] & 0x7f) + 1) * ch_height + (regs[5] & 0x1f);
98 vt_disp = (regs[6] & 0x7f) * ch_height;
99 vs_start = ((regs[7] & 0x7f) + 1) * ch_height;
100 vs_end = vs_start + ((regs[3] & 0xf0) ? (regs[3] >> 4) : 16);
102 if(vt_total != new_vt_total) {
103 vt_total = new_vt_total;
104 set_lines_per_frame(vt_total);
106 timing_changed = false;
108 #if defined(HD46505_CHAR_CLOCK)
110 #elif defined(HD46505_HORIZ_FREQ)
115 #if defined(HD46505_CHAR_CLOCK)
116 if(char_clock != next_char_clock) {
117 char_clock = next_char_clock;
118 frames_per_sec = char_clock / (double)vt_total / (double)hz_total;
120 frames_per_sec *= 2; // interlace mode
122 set_frames_per_sec(frames_per_sec);
124 #elif defined(HD46505_HORIZ_FREQ)
125 if(horiz_freq != next_horiz_freq) {
126 horiz_freq = next_horiz_freq;
127 frames_per_sec = horiz_freq / (double)vt_total;
129 frames_per_sec *= 2; // interlace mode
131 set_frames_per_sec(frames_per_sec);
136 void HD46505::update_timing(int new_clocks, double new_frames_per_sec, int new_lines_per_frame)
138 cpu_clocks = new_clocks;
139 #if !defined(HD46505_CHAR_CLOCK) && !defined(HD46505_HORIZ_FREQ)
140 frames_per_sec = new_frames_per_sec;
143 // update event clocks
147 void HD46505::event_frame()
149 // update envet clocks after update_timing() is called
150 if(disp_end_clock == 0 && vt_total != 0) {
151 disp_end_clock = (int)((double)cpu_clocks * (double)hz_disp / frames_per_sec / (double)vt_total / (double)hz_total);
152 hs_start_clock = (int)((double)cpu_clocks * (double)hs_start / frames_per_sec / (double)vt_total / (double)hz_total);
153 hs_end_clock = (int)((double)cpu_clocks * (double)hs_end / frames_per_sec / (double)vt_total / (double)hz_total);
157 void HD46505::event_vline(int v, int clock)
159 // if vt_disp == 0, raise vblank for one line
160 bool new_vblank = ((v < vt_disp) || (v == 0 && vt_disp == 0));
163 if(outputs_disp.count) {
164 set_display(new_vblank);
165 if(new_vblank && hz_disp < hz_total) {
166 register_event_by_clock(this, EVENT_DISPLAY, disp_end_clock, false, NULL);
171 set_vblank(new_vblank); // active low
174 set_vsync(vs_start <= v && v < vs_end);
177 if(outputs_hsync.count && hs_start < hs_end && hs_end < hz_total) {
179 register_event_by_clock(this, EVENT_HSYNC_S, hs_start_clock, false, NULL);
180 register_event_by_clock(this, EVENT_HSYNC_E, hs_end_clock, false, NULL);
184 void HD46505::event_callback(int event_id, int err)
186 if(event_id == EVENT_DISPLAY) {
188 } else if(event_id == EVENT_HSYNC_S) {
190 } else if(event_id == EVENT_HSYNC_E) {
195 void HD46505::set_display(bool val)
198 write_signals(&outputs_disp, val ? 0xffffffff : 0);
203 void HD46505::set_vblank(bool val)
206 write_signals(&outputs_vblank, val ? 0xffffffff : 0);
211 void HD46505::set_vsync(bool val)
214 write_signals(&outputs_vsync, val ? 0xffffffff : 0);
219 void HD46505::set_hsync(bool val)
222 write_signals(&outputs_hsync, val ? 0xffffffff : 0);
227 #define STATE_VERSION 3
229 void HD46505::save_state(FILEIO* state_fio)
231 state_fio->FputUint32(STATE_VERSION);
232 state_fio->FputInt32(this_device_id);
234 state_fio->Fwrite(regs, sizeof(regs), 1);
235 state_fio->Fwrite(regs_written, sizeof(regs_written), 1);
236 state_fio->FputInt32(ch);
237 state_fio->FputBool(timing_changed);
238 state_fio->FputInt32(cpu_clocks);
239 #if defined(HD46505_CHAR_CLOCK)
240 state_fio->FputDouble(char_clock);
241 state_fio->FputDouble(next_char_clock);
242 #elif defined(HD46505_HORIZ_FREQ)
243 state_fio->FputDouble(horiz_freq);
244 state_fio->FputDouble(next_horiz_freq);
246 state_fio->FputDouble(frames_per_sec);
247 state_fio->FputInt32(hz_total);
248 state_fio->FputInt32(hz_disp);
249 state_fio->FputInt32(hs_start);
250 state_fio->FputInt32(hs_end);
251 state_fio->FputInt32(vt_total);
252 state_fio->FputInt32(vt_disp);
253 state_fio->FputInt32(vs_start);
254 state_fio->FputInt32(vs_end);
255 state_fio->FputInt32(disp_end_clock);
256 state_fio->FputInt32(hs_start_clock);
257 state_fio->FputInt32(hs_end_clock);
258 state_fio->FputBool(display);
259 state_fio->FputBool(vblank);
260 state_fio->FputBool(vsync);
261 state_fio->FputBool(hsync);
264 bool HD46505::load_state(FILEIO* state_fio)
266 if(state_fio->FgetUint32() != STATE_VERSION) {
269 if(state_fio->FgetInt32() != this_device_id) {
272 state_fio->Fread(regs, sizeof(regs), 1);
273 state_fio->Fread(regs_written, sizeof(regs_written), 1);
274 ch = state_fio->FgetInt32();
275 timing_changed = state_fio->FgetBool();
276 cpu_clocks = state_fio->FgetInt32();
277 #if defined(HD46505_CHAR_CLOCK)
278 char_clock = state_fio->FgetDouble();
279 next_char_clock = state_fio->FgetDouble();
280 #elif defined(HD46505_HORIZ_FREQ)
281 horiz_freq = state_fio->FgetDouble();
282 next_horiz_freq = state_fio->FgetDouble();
284 frames_per_sec = state_fio->FgetDouble();
285 hz_total = state_fio->FgetInt32();
286 hz_disp = state_fio->FgetInt32();
287 hs_start = state_fio->FgetInt32();
288 hs_end = state_fio->FgetInt32();
289 vt_total = state_fio->FgetInt32();
290 vt_disp = state_fio->FgetInt32();
291 vs_start = state_fio->FgetInt32();
292 vs_end = state_fio->FgetInt32();
293 disp_end_clock = state_fio->FgetInt32();
294 hs_start_clock = state_fio->FgetInt32();
295 hs_end_clock = state_fio->FgetInt32();
296 display = state_fio->FgetBool();
297 vblank = state_fio->FgetBool();
298 vsync = state_fio->FgetBool();
299 hsync = state_fio->FgetBool();