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