1 /*
2 * ============================================================================
3 * Title: Demo Recorder
4 * Author: J. Zbiciak
5 * ============================================================================
6 * This module implements a "demo recorder", which records updates to GRAM,
7 * BACKTAB and the PSG to a file. Currently it does not record Intellivoice.
8 *
9 * The output file can be fed through a post-processor, which then reformats
10 * and compresses the data, for use in a demo-player on a real Intellivision.
11 *
12 * Rather than snoop the bus for everything or implement a "tickable"
13 * interface, the demo recorder gets ticked by the STIC directly, and the
14 * STIC hands the demo recorder its current vision of the STIC control
15 * registers, BACKTAB and GRAM. The demo recorder then only has to snoop
16 * the PSG registers.
17 *
18 * ============================================================================
19 */
20
21 #include "config.h"
22 #include "periph/periph.h"
23 #include "gfx/gfx.h"
24 #include "snd/snd.h"
25 #include "periph/periph.h"
26 #include "demo/demo.h"
27 #include "ay8910/ay8910.h"
28 #include "stic/stic.h"
29
30 /* ======================================================================== */
31 /* SIGBIT_PSG -- Significant bits in PSG registers. */
32 /* SIGBIT_STIC -- Significant bits in STIC registers. */
33 /* STIC_REGS -- List of STIC register numbers to examine. */
34 /* ======================================================================== */
35 LOCAL const uint16_t sigbit_psg [14] =
36 {
37 0x00FF, 0x00FF, 0x00FF, 0x00FF, /* Lower 8 bits of channel periods. */
38 0x000F, 0x000F, 0x000F, /* Upper 4 bits of channel periods. */
39 0x00FF, /* Upper 8 bits of envelope period. */
40 0x003F, /* Channel enables. */
41 0x001F, /* Noise period. */
42 0x000F, /* Envelope characteristics */
43 0x003F, 0x003F, 0x003F /* Volume controls. */
44 };
45
46 LOCAL const uint16_t sigbit_stic[0x40] =
47 {
48 /* MOB X Registers 0x00 - 0x07 */
49 0x07FF, 0x07FF, 0x07FF, 0x07FF, 0x07FF, 0x07FF, 0x07FF, 0x07FF,
50
51 /* MOB Y Registers 0x08 - 0x0F */
52 0x0FFF, 0x0FFF, 0x0FFF, 0x0FFF, 0x0FFF, 0x0FFF, 0x0FFF, 0x0FFF,
53
54 /* MOB A Registers 0x10 - 0x17 */
55 0x3FFF, 0x3FFF, 0x3FFF, 0x3FFF, 0x3FFF, 0x3FFF, 0x3FFF, 0x3FFF,
56
57 /* MOB C Registers 0x18 - 0x1F */
58 0x03FE, 0x03FD, 0x03FB, 0x03F7, 0x03EF, 0x03DF, 0x03BF, 0x037F,
59
60 /* Display enable, Mode select 0x20 - 0x21 */
61 0x0000, 0x0000,
62
63 /* Unimplemented registers 0x22 - 0x27 */
64 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
65
66 /* Color stack, border color 0x28 - 0x2C */
67 0x000F, 0x000F, 0x000F, 0x000F, 0x000F,
68
69 /* Unimplemented registers 0x2D - 0x2F */
70 0x0000, 0x0000, 0x0000,
71
72 /* Horiz delay, vertical delay, border extension 0x30 - 0x32 */
73 0x0007, 0x0007, 0x0003,
74
75 /* Unimplemented registers 0x33 - 0x3F */
76 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
77 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
78 };
79
80 LOCAL const int stic_regs[32] =
81 {
82 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
83 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
84 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
85 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x30, 0x31, 0x32,
86 };
87
88
89 /* ======================================================================== */
90 /* DEMO_BUF -- Buffer we construct each frame in. */
91 /* */
92 /* Frame format: */
93 /* */
94 /* 4 bytes 0x2A3A4A5A Frame header */
95 /* 4 bytes Bitmap of changed STIC registers */
96 /* 8 bytes Bitmap of changed GRAM cards */
97 /* 30 bytes Bitmap of changed BTAB cards */
98 /* 2 bytes Bitmap of changed PSG0 registers */
99 /* 2 bytes Bitmap of changed PSG1 registers */
100 /* N bytes STIC register values (2 bytes each) */
101 /* N bytes GRAM tiles (8 bytes each) */
102 /* N bytes BTAB cards (2 bytes each) */
103 /* N bytes PSG0 registers (1 byte each) */
104 /* N bytes PSG1 registers (1 byte each) */
105 /* */
106 /* ======================================================================== */
107 LOCAL uint8_t demo_buf[54 + 32*2 + 64*8 + 240*2 + 16 + 16];
108
109 #define EMIT_32(buf, word) do {\
110 buf[0] = ((word) >> 0) & 0xFF; \
111 buf[1] = ((word) >> 8) & 0xFF; \
112 buf[2] = ((word) >> 16) & 0xFF; \
113 buf[3] = ((word) >> 24) & 0xFF; \
114 buf += 4; \
115 } while (0)
116
117 #define EMIT_16(buf, word) do {\
118 buf[0] = ((word) >> 0) & 0xFF; \
119 buf[1] = ((word) >> 8) & 0xFF; \
120 buf += 2; \
121 } while (0)
122
123 #define EMIT_8(buf, word) *(buf)++ = word;
124
125
126 /* ======================================================================== */
127 /* DEMO_TICK -- Called from STIC_TICK at the start of VBlank. */
128 /* ======================================================================== */
demo_tick(demo_t * demo,stic_t * stic)129 void demo_tick
130 (
131 demo_t *demo,
132 stic_t *stic
133 )
134 {
135 int i, j, c;
136 uint32_t stic_chg = { 0 };
137 uint32_t gram_chg[2] = { 0, 0 };
138 uint32_t btab_chg[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
139 uint32_t psg0_chg = { 0 };
140 uint32_t psg1_chg = { 0 };
141 uint32_t mask;
142 uint8_t *buf;
143
144
145 /* -------------------------------------------------------------------- */
146 /* Scan the STIC registers and look for changes. Ignore "dontcares". */
147 /* Note: We encode FGBG/CSTK and VidEn in extra bits of the border */
148 /* extension register, 0x32. */
149 /* -------------------------------------------------------------------- */
150 for (i = 0; i < 32; i++)
151 {
152 int reg = stic_regs[i];
153 uint32_t stic_reg = stic->raw[reg] & sigbit_stic[reg];
154
155 if (i == 31) /* last reg is 0x32 */
156 {
157 stic_reg |= stic->vid_enable ? 4 : 0;
158 stic_reg |= stic->mode << 3;
159 }
160
161 if (stic_reg != demo->stic[i])
162 {
163 stic_chg |= 1 << i;
164 demo->stic[i] = stic_reg;
165 }
166 }
167
168 /* -------------------------------------------------------------------- */
169 /* Scan the GRAM image and find out what changed. */
170 /* -------------------------------------------------------------------- */
171 for (i = 0; i < 512; i++)
172 {
173 if (stic->gmem[0x800 + i] != demo->gram[i])
174 {
175 c = i >> 3;
176 gram_chg[c >> 5] |= 1 << (c & 31);
177 }
178 }
179 memcpy(demo->gram, stic->gmem + 0x800, 512 * sizeof(stic->gmem[0]));
180
181 /* -------------------------------------------------------------------- */
182 /* Scan the BACKTAB and find what's changed. Ignore "dontcare" bits. */
183 /* -------------------------------------------------------------------- */
184 mask = stic->mode ? 0x3FFF : 0x39FF;
185
186 for (i = 0; i < 240; i++)
187 {
188 uint32_t demo_btab = demo->btab[i];
189 uint32_t stic_btab = stic->btab[i];
190
191 stic_btab &= (stic_btab & 0x800) ? mask : 0x3FFF;
192
193 if (stic_btab != demo_btab)
194 {
195 btab_chg[i >> 5] |= 1 << (i & 31);
196 demo->btab[i] = stic_btab;
197 }
198 }
199
200 /* -------------------------------------------------------------------- */
201 /* Scan the PSG registers and see what's changed. */
202 /* -------------------------------------------------------------------- */
203 for (i = 0; i < 14; i++)
204 {
205 uint32_t psg0_reg = demo->psg0 ? demo->psg0->reg[i] & sigbit_psg[i] : 0;
206 uint32_t psg1_reg = demo->psg1 ? demo->psg1->reg[i] & sigbit_psg[i] : 0;
207
208 if (demo->psg0_reg[i] != psg0_reg)
209 {
210 demo->psg0_reg[i] = psg0_reg;
211 psg0_chg |= 1 << i;
212 }
213
214 if (demo->psg1_reg[i] != psg1_reg)
215 {
216 demo->psg1_reg[i] = psg1_reg;
217 psg1_chg |= 1 << i;
218 }
219 }
220
221 if (demo->psg0 && demo->psg0->demo_env_hit)
222 {
223 demo->psg0->demo_env_hit = 0;
224 psg0_chg |= 1 << 10;
225 }
226
227 if (demo->psg1 && demo->psg1->demo_env_hit)
228 {
229 demo->psg1->demo_env_hit = 0;
230 psg1_chg |= 1 << 10;
231 }
232
233 /* -------------------------------------------------------------------- */
234 /* Encode the frame. */
235 /* Frame format: */
236 /* */
237 /* 4 bytes 0x2A3A4A5A Frame header */
238 /* 4 bytes Bitmap of changed STIC registers */
239 /* 8 bytes Bitmap of changed GRAM cards */
240 /* 30 bytes Bitmap of changed BTAB cards */
241 /* 2 bytes Bitmap of changed PSG0 registers */
242 /* 2 bytes Bitmap of changed PSG1 registers */
243 /* */
244 /* N bytes STIC register values (2 bytes each) */
245 /* N bytes GRAM tiles (8 bytes each) */
246 /* N bytes BTAB cards (2 bytes each) */
247 /* N bytes PSG0 registers (1 byte each) */
248 /* N bytes PSG1 registers (1 byte each) */
249 /* -------------------------------------------------------------------- */
250 buf = demo_buf;
251
252 EMIT_32(buf, 0x2A3A4A5A);
253 EMIT_32(buf, stic_chg);
254 EMIT_32(buf, gram_chg[0]);
255 EMIT_32(buf, gram_chg[1]);
256 for (i = 0; i < 7; i++)
257 EMIT_32(buf, btab_chg[i]);
258 EMIT_16(buf, btab_chg[7]);
259 EMIT_16(buf, psg0_chg);
260 EMIT_16(buf, psg1_chg);
261
262 for (i = 0; i < 32; i++)
263 if ((stic_chg >> i) & 1)
264 EMIT_16(buf, demo->stic[i]);
265
266 for (i = 0; i < 64; i++)
267 if ((gram_chg[i >> 5] >> (i & 31)) & 1)
268 for (j = 0; j < 8; j++)
269 EMIT_8(buf, demo->gram[i*8 + j]);
270
271 for (i = 0; i < 240; i++)
272 if ((btab_chg[i >> 5] >> (i & 31)) & 1)
273 EMIT_16(buf, demo->btab[i]);
274
275 for (i = 0; i < 14; i++)
276 if ((psg0_chg >> i) & 1)
277 EMIT_8(buf, demo->psg0_reg[i]);
278
279 for (i = 0; i < 14; i++)
280 if ((psg1_chg >> i) & 1)
281 EMIT_8(buf, demo->psg1_reg[i]);
282
283 assert((size_t)(buf - demo_buf) <= sizeof(demo_buf));
284
285 fwrite(demo_buf, 1, buf - demo_buf, demo->f);
286
287 return;
288 }
289
290
291 /* ======================================================================== */
292 /* DEMO_INIT -- Initialize the demo recorder. */
293 /* ======================================================================== */
demo_init(demo_t * demo,char * demo_file,ay8910_t * psg0,ay8910_t * psg1)294 int demo_init
295 (
296 demo_t *demo,
297 char *demo_file,
298 ay8910_t *psg0,
299 ay8910_t *psg1
300 )
301 {
302 memset(demo, 0, sizeof(*demo));
303
304 if (!(demo->f = fopen(demo_file, "wb")))
305 {
306 perror("fopen()");
307 fprintf(stderr, "Could not open demo file '%s' for writing.\n",
308 demo_file);
309
310 return -1;
311 }
312
313 demo->psg0 = psg0;
314 demo->psg1 = psg1;
315
316 return 0;
317 }
318
319 /* ======================================================================== */
320 /* DEMO_DTOR -- Shut down the demo recorder. */
321 /* ======================================================================== */
demo_dtor(demo_t * demo)322 void demo_dtor(demo_t *demo)
323 {
324 if (demo && demo->f)
325 fclose(demo->f);
326 }
327
328 /* ======================================================================== */
329 /* This program is free software; you can redistribute it and/or modify */
330 /* it under the terms of the GNU General Public License as published by */
331 /* the Free Software Foundation; either version 2 of the License, or */
332 /* (at your option) any later version. */
333 /* */
334 /* This program is distributed in the hope that it will be useful, */
335 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
336 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */
337 /* General Public License for more details. */
338 /* */
339 /* You should have received a copy of the GNU General Public License along */
340 /* with this program; if not, write to the Free Software Foundation, Inc., */
341 /* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
342 /* ======================================================================== */
343 /* Copyright (c) 2005-+Inf, Joseph Zbiciak */
344 /* ======================================================================== */
345