1 /* timings.c: Timing routines
2 Copyright (c) 2003 Philip Kendall
3 Copyright (c) 2016 Stuart Brady
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18
19 Author contact information:
20
21 E-mail: philip-fuse@shadowmagic.org.uk
22
23 */
24
25 #include "config.h"
26
27 #include <string.h>
28
29 #include "internals.h"
30
31 typedef struct timings_frame_t {
32 /* Line timings in tstates */
33 libspectrum_word left_border, horizontal_screen, right_border,
34 horizontal_retrace;
35
36 /* Frame timings in lines */
37 libspectrum_word top_border, vertical_screen, bottom_border,
38 vertical_retrace;
39
40 /* How long does an interrupt last in tstates */
41 libspectrum_word interrupt_length;
42
43 /* How long after interrupt is the top-level pixel of the main screen
44 displayed */
45 libspectrum_dword top_left_pixel;
46 } timings_frame_t;
47
48 static const timings_frame_t timings_frame_ferranti_5c_6c =
49 {
50 24, 128, 24, 48, /* Horizontal, 224 clocks per line */
51 48, 192, 48, 24, /* Vertical, 312 lines per frame */
52 32, 14336
53 };
54
55 static const timings_frame_t timings_frame_ferranti_60hz =
56 {
57 24, 128, 24, 48, /* Horizontal, 224 clocks per line */
58 24, 192, 25, 23, /* Vertical, 264 lines per frame */
59 32, 8960
60 };
61
62 static const timings_frame_t timings_frame_ferranti_7c =
63 {
64 24, 128, 24, 52, /* Horizontal, 228 clocks per line */
65 48, 192, 48, 23, /* Vertical, 311 lines per frame */
66 36, 14362
67 };
68
69 static const timings_frame_t timings_frame_amstrad_asic =
70 {
71 24, 128, 24, 52, /* Horizontal, 228 clocks per line */
72 48, 192, 48, 23, /* Vertical, 311 lines per frame */
73 32, 14365
74 };
75
76 static const timings_frame_t timings_frame_timex_scld_50hz =
77 {
78 24, 128, 24, 48, /* Horizontal, 224 clocks per line */
79 48, 192, 48, 24, /* Vertical, 312 lines per frame */
80 32, 14321
81 };
82
83 static const timings_frame_t timings_frame_timex_scld_60hz =
84 {
85 24, 128, 24, 48, /* Horizontal, 224 clocks per line */
86 24, 192, 25, 21, /* Vertical, 262 lines per frame */
87 32, 9169
88 };
89
90 static const timings_frame_t timings_frame_se =
91 {
92 24, 128, 24, 48, /* Horizontal, 224 clocks per line */
93 47, 192, 48, 25, /* Vertical, 312 lines per frame */
94 32, 14336
95 };
96
97 static const timings_frame_t timings_frame_pentagon =
98 {
99 36, 128, 28, 32, /* Horizontal, 224 clocks per line */
100 64, 192, 48, 16, /* Vertical 320 lines per frame */
101 36, 17988
102 };
103
104 static const timings_frame_t timings_frame_scorpion =
105 {
106 24, 128, 32, 40, /* Horizontal, 224 clocks per line */
107 48, 192, 48, 24, /* Vertical, 312 lines per frame */
108 36, 14336
109 };
110
111 /* The frame timings of a machine */
112 typedef struct timings_t {
113
114 /* Processor speed in Hz */
115 libspectrum_dword processor_speed;
116
117 /* AY clock speed in Hz */
118 libspectrum_dword ay_speed;
119
120 const timings_frame_t *frame_timings;
121
122 } timings_t;
123
124 /* The actual data from which the full timings are constructed */
125 static const timings_t base_timings[] = {
126
127 /* 48K */
128 { 3500000, 0, &timings_frame_ferranti_5c_6c },
129 /* TC2048 */
130 { 3500000, 0, &timings_frame_timex_scld_50hz },
131 /* 128K */
132 { 3546900, 1773400, &timings_frame_ferranti_7c },
133 /* +2 */
134 { 3546900, 1773400, &timings_frame_ferranti_7c },
135 /* Pentagon */
136 { 3584000, 1792000, &timings_frame_pentagon },
137 /* +2A */
138 { 3546900, 1773400, &timings_frame_amstrad_asic },
139 /* +3 */
140 { 3546900, 1773400, &timings_frame_amstrad_asic },
141 /* Unknown machine */
142 { 0, 0, NULL },
143 /* 16K */
144 { 3500000, 0, &timings_frame_ferranti_5c_6c },
145 /* TC2068 */
146 { 3500000, 1750000, &timings_frame_timex_scld_50hz },
147 /* Scorpion */
148 { 3500000, 1750000, &timings_frame_scorpion },
149 /* +3e */
150 { 3546900, 1773400, &timings_frame_amstrad_asic },
151 /* SE */
152 { 3500000, 1750000, &timings_frame_se },
153 /* TS2068 */
154 { 3528000, 1764000, &timings_frame_timex_scld_60hz },
155 /* Pentagon 512K */
156 { 3584000, 1792000, &timings_frame_pentagon },
157 /* Pentagon 1024K */
158 { 3584000, 1792000, &timings_frame_pentagon },
159 /* 48K NTSC */
160 { 3527500, 0, &timings_frame_ferranti_60hz },
161 /* 128Ke */
162 { 3546900, 1773400, &timings_frame_amstrad_asic },
163 };
164
165 libspectrum_dword
libspectrum_timings_processor_speed(libspectrum_machine machine)166 libspectrum_timings_processor_speed( libspectrum_machine machine )
167 {
168 return base_timings[ machine ].processor_speed;
169 }
170
171 libspectrum_dword
libspectrum_timings_ay_speed(libspectrum_machine machine)172 libspectrum_timings_ay_speed( libspectrum_machine machine )
173 {
174 return base_timings[ machine ].ay_speed;
175 }
176
177 libspectrum_word
libspectrum_timings_left_border(libspectrum_machine machine)178 libspectrum_timings_left_border( libspectrum_machine machine )
179 {
180 const timings_frame_t *f = base_timings[ machine ].frame_timings;
181 if( !f ) return 0;
182 return f->left_border;
183 }
184
185 libspectrum_word
libspectrum_timings_horizontal_screen(libspectrum_machine machine)186 libspectrum_timings_horizontal_screen( libspectrum_machine machine )
187 {
188 const timings_frame_t *f = base_timings[ machine ].frame_timings;
189 if( !f ) return 0;
190 return f->horizontal_screen;
191 }
192
193 libspectrum_word
libspectrum_timings_right_border(libspectrum_machine machine)194 libspectrum_timings_right_border( libspectrum_machine machine )
195 {
196 const timings_frame_t *f = base_timings[ machine ].frame_timings;
197 if( !f ) return 0;
198 return f->right_border;
199 }
200
201 libspectrum_word
libspectrum_timings_horizontal_retrace(libspectrum_machine machine)202 libspectrum_timings_horizontal_retrace( libspectrum_machine machine )
203 {
204 const timings_frame_t *f = base_timings[ machine ].frame_timings;
205 if( !f ) return 0;
206 return f->horizontal_retrace;
207 }
208
209 libspectrum_word
libspectrum_timings_top_border(libspectrum_machine machine)210 libspectrum_timings_top_border( libspectrum_machine machine )
211 {
212 const timings_frame_t *f = base_timings[ machine ].frame_timings;
213 if( !f ) return 0;
214 return f->top_border;
215 }
216
217 libspectrum_word
libspectrum_timings_vertical_screen(libspectrum_machine machine)218 libspectrum_timings_vertical_screen( libspectrum_machine machine )
219 {
220 const timings_frame_t *f = base_timings[ machine ].frame_timings;
221 if( !f ) return 0;
222 return f->vertical_screen;
223 }
224
225 libspectrum_word
libspectrum_timings_bottom_border(libspectrum_machine machine)226 libspectrum_timings_bottom_border( libspectrum_machine machine )
227 {
228 const timings_frame_t *f = base_timings[ machine ].frame_timings;
229 if( !f ) return 0;
230 return f->bottom_border;
231 }
232
233 libspectrum_word
libspectrum_timings_vertical_retrace(libspectrum_machine machine)234 libspectrum_timings_vertical_retrace( libspectrum_machine machine )
235 {
236 const timings_frame_t *f = base_timings[ machine ].frame_timings;
237 if( !f ) return 0;
238 return f->vertical_retrace;
239 }
240
241 libspectrum_word
libspectrum_timings_interrupt_length(libspectrum_machine machine)242 libspectrum_timings_interrupt_length( libspectrum_machine machine )
243 {
244 const timings_frame_t *f = base_timings[ machine ].frame_timings;
245 if( !f ) return 0;
246 return f->interrupt_length;
247 }
248
249 libspectrum_word
libspectrum_timings_top_left_pixel(libspectrum_machine machine)250 libspectrum_timings_top_left_pixel( libspectrum_machine machine )
251 {
252 const timings_frame_t *f = base_timings[ machine ].frame_timings;
253 if( !f ) return 0;
254 return f->top_left_pixel;
255 }
256
257 libspectrum_word
libspectrum_timings_tstates_per_line(libspectrum_machine machine)258 libspectrum_timings_tstates_per_line( libspectrum_machine machine )
259 {
260 const timings_frame_t *f = base_timings[ machine ].frame_timings;
261 if( !f ) return 0;
262 return f->left_border + f->horizontal_screen + f->right_border +
263 f->horizontal_retrace;
264 }
265
266 libspectrum_word
libspectrum_timings_lines_per_frame(libspectrum_machine machine)267 libspectrum_timings_lines_per_frame( libspectrum_machine machine )
268 {
269 const timings_frame_t *f = base_timings[ machine ].frame_timings;
270 if( !f ) return 0;
271 return f->top_border + f->vertical_screen + f->bottom_border +
272 f->vertical_retrace;
273 }
274
275 libspectrum_dword
libspectrum_timings_tstates_per_frame(libspectrum_machine machine)276 libspectrum_timings_tstates_per_frame( libspectrum_machine machine )
277 {
278 const timings_frame_t *f = base_timings[ machine ].frame_timings;
279 if( !f ) return 0;
280 return libspectrum_timings_tstates_per_line( machine ) *
281 ( (libspectrum_dword)libspectrum_timings_lines_per_frame( machine ) );
282 }
283