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