diff options
Diffstat (limited to 'www/notes.t')
-rw-r--r-- | www/notes.t | 411 |
1 files changed, 411 insertions, 0 deletions
diff --git a/www/notes.t b/www/notes.t new file mode 100644 index 0000000000..71e40651d1 --- /dev/null +++ b/www/notes.t | |||
@@ -0,0 +1,411 @@ | |||
1 | #define _PAGE_ Jukebox notes | ||
2 | #include "head.t" | ||
3 | |||
4 | <h2>Exception vectors</h2> | ||
5 | |||
6 | <p>The first 0x200 bytes of the image appears to be the exception vector table. | ||
7 | The vectors are explained on pages 54 and 70-71 in the SH-1 Hardware Manual, | ||
8 | |||
9 | <p>Here's the vector table for v5.03a: | ||
10 | |||
11 | <table border=1><tr> | ||
12 | <th>Vector</th><th>Address</th><th>Description/interrupt source</th> | ||
13 | <tr><td> 0</td><td>09000200</td><td>Power-on reset PC</td></tr> | ||
14 | <tr><td> 1</td><td>0903f2bc</td><td>Power-on reset SP</td></tr> | ||
15 | <tr><td> 2</td><td>09000200</td><td>Manual reset PC</td></tr> | ||
16 | <tr><td> 3</td><td>0903f2bc</td><td>Manual reset SP</td></tr> | ||
17 | <tr><td> 11</td><td>09000cac</td><td>NMI</td></tr> | ||
18 | <tr><td> 64</td><td>0900c060</td><td>IRQ0</td></tr> | ||
19 | <tr><td> 70</td><td>09004934</td><td>IRQ6</td></tr> | ||
20 | <tr><td> 78</td><td>09004a38</td><td>DMAC3 DEI3</td></tr> | ||
21 | <tr><td> 80</td><td>0900dfd0</td><td>ITU0 IMIA0</td></tr> | ||
22 | <tr><td> 88</td><td>0900df60</td><td>ITU2 IMIA2</td></tr> | ||
23 | <tr><td> 90</td><td>0900df60</td><td>ITU2 OVI2</td></tr> | ||
24 | <tr><td>104</td><td>09004918</td><td>SCI1 ERI1</td></tr> | ||
25 | <tr><td>105</td><td>090049e0</td><td>SCI1 Rxl1</td></tr> | ||
26 | <tr><td>109</td><td>09010270</td><td>A/D ITI</td></tr> | ||
27 | </table> | ||
28 | |||
29 | <p>From the use of address 0x0903f2bc as stack pointer, we can deduce | ||
30 | that the DRAM is located at address 0x09000000. | ||
31 | This is backed by the HW manual p102, which says that DRAM can only be at put on CS1, which is either 0x01000000 (8-bit) or 0x09000000 (16-bit). | ||
32 | |||
33 | <p>The vector table also corresponds with the fact that there is code at address 0x200 of the image file. 0x200 is thus the starting point for all code. | ||
34 | |||
35 | <h2>Port pins</h2> | ||
36 | <p><table><tr valign="top"><td> | ||
37 | |||
38 | <p>Port A pin function configuration summary: | ||
39 | <table border=1> | ||
40 | <tr><th>Pin</th><th>Function</th><th>Input/output</th><th>Initial value</th><th>Used for</th></tr> | ||
41 | <tr><td>PA0</td><td>i/o</td><td>Input</td><td></td><td>DC adapter detect</td></tr> | ||
42 | <tr><td>PA1</td><td>/RAS</td><td>Output</td><td></td><td>DRAM</td></tr> | ||
43 | <tr><td>PA2</td><td>/CS6</td><td>Output</td><td></td><td>IDE</td></tr> | ||
44 | <tr><td>PA3</td><td>/WAIT</td></tr> | ||
45 | <tr><td>PA4</td><td>/WR</td><td>Output</td><td></td><td>DRAM+Flash</td></tr> | ||
46 | <tr><td>PA5</td><td>i/o</td><td>Input</td><td></td><td>Key: ON</td></tr> | ||
47 | <tr><td>PA6</td><td>/RD</td><td>Output</td><td></td><td>IDE</td></tr> | ||
48 | <tr><td>PA7</td><td>i/o</td><td>Output</td><td>0</td></tr> | ||
49 | <tr><td>PA8</td><td>i/o</td><td>Output</td><td>0</td></tr> | ||
50 | <tr><td>PA9</td><td>i/o</td><td>Output</td><td>1</td></tr> | ||
51 | <tr><td>PA10</td><td>i/o</td><td>Output</td></tr> | ||
52 | <tr><td>PA11</td><td>i/o</td><td>Input</td><td></td><td>Key: STOP</td></tr> | ||
53 | <tr><td>PA12</td><td>/IRQ0</td></tr> | ||
54 | <tr><td>PA13</td><td>i/o</td></tr> | ||
55 | <tr><td>PA14</td><td>i/o</td></tr> | ||
56 | <tr><td>PA15</td><td>i/o</td><td>Input</td><td></td><td>USB cable detect</td></tr> | ||
57 | </table> | ||
58 | |||
59 | </td><td> | ||
60 | |||
61 | <p>Port B pin function configuration summary: | ||
62 | <table border=1> | ||
63 | <tr><th>Pin</th><th>Function</th><th>Input/output</th><th>Initial value</th><th>Used for</th></tr> | ||
64 | <tr><td>PB0</td><td>i/o</td><td>Output</td><td></td><td>LCD</td></tr> | ||
65 | <tr><td>PB1</td><td>i/o</td><td>Output</td><td></td><td>LCD</td></tr> | ||
66 | <tr><td>PB2</td><td>i/o</td><td>Output</td><td></td><td>LCD</td></tr> | ||
67 | <tr><td>PB3</td><td>i/o</td><td>Output</td><td></td><td>LCD</td></tr> | ||
68 | <tr><td>PB4</td><td>i/o</td><td>Input</td></tr> | ||
69 | <tr><td>PB5</td><td>i/o</td><td>Output</td><td>1</td><td>I˛C data</td></tr> | ||
70 | <tr><td>PB6</td><td>i/o</td><td>Output</td><td>0</td></tr> | ||
71 | <tr><td>PB7</td><td>i/o</td><td>Output</td><td></td><td>I˛C clock</td></tr> | ||
72 | <tr><td>PB8</td><td>i/o</td></tr> | ||
73 | <tr><td>PB9</td><td>TxD0</td><td>Output</td><td></td><td>MPEG</td></tr> | ||
74 | <tr><td>PB10</td><td>RxD1</td><td>Input</td></td><td></td><td>Remote</td></tr> | ||
75 | <tr><td>PB11</td><td>TxD1</td><td>Output</td><td></td><td>Remote?</td></tr> | ||
76 | <tr><td>PB12</td><td>SCK0</td><td>Output</td><td></td><td>MPEG</td></tr> | ||
77 | <tr><td>PB13</td><td>i/o</td></tr> | ||
78 | <tr><td>PB14</td><td>/IRQ6</td><td>Input</td></tr> | ||
79 | <tr><td>PB15</td><td>i/o</td><td>Input</td></tr> | ||
80 | </table> | ||
81 | |||
82 | |||
83 | </td></tr></table> | ||
84 | |||
85 | <p>Port C pin function configuration summary: | ||
86 | <table border=1> | ||
87 | <tr><th>Pin</th><th>Function</th><th>Input/output</th><th>Used for</th></tr> | ||
88 | <tr><td>PC0</td><td>i/o</td><td>Input</td><td>Key: - / PREV</td></tr> | ||
89 | <tr><td>PC1</td><td>i/o</td><td>Input</td><td>Key: MENU</td></tr> | ||
90 | <tr><td>PC2</td><td>i/o</td><td>Input</td><td>Key: + / NEXT</td></tr> | ||
91 | <tr><td>PC3</td><td>i/o</td><td>Input</td><td>Key: PLAY</td></tr> | ||
92 | <tr><td>PC4</td><td>i/o</td><td>Input</td></tr> | ||
93 | <tr><td>PC5</td><td>i/o</td><td>Input</td></tr> | ||
94 | <tr><td>PC6</td><td>i/o</td><td>Input</td></tr> | ||
95 | <tr><td>PC7</td><td>i/o</td><td>Input</td></tr> | ||
96 | </table> | ||
97 | |||
98 | |||
99 | <h2>Labels</h2> | ||
100 | <p>Note: Everything is about v5.03a. | ||
101 | |||
102 | <ul> | ||
103 | <li>0x0200: Start point | ||
104 | <li>0x383d: Text: "Archos Jukebox hard drive is not bootable! Please insert a bootable floppy and press any key to try again" :-) | ||
105 | <li>0xc390: Address of "Update" string shown early on LCD. | ||
106 | <li>0xc8c0: Start of setup code | ||
107 | <li>0xc8c8: DRAM setup | ||
108 | <li>0xc4a0: Serial port 1 setup | ||
109 | <li>0xc40a: Port configuration setup | ||
110 | <li>0xe3bc: Character set conversion table | ||
111 | <li>0xfcd0: ITU setup | ||
112 | <li>0xc52a: Memory area #6 setup | ||
113 | <li>0x114b0: Start of menu strings | ||
114 | </ul> | ||
115 | |||
116 | |||
117 | <h2>Setup</h2> | ||
118 | |||
119 | <p>The startup code at 0x200 (0x09000200) naturally begins with setting up the system. | ||
120 | |||
121 | <h3>Vector Base Register</h3> | ||
122 | |||
123 | <p>The first thing the code does is setting the VBR, Vector Base Register, | ||
124 | and thus move the exception vector table from the internal ROM at address 0 | ||
125 | to the DRAM at address 0x09000000: | ||
126 | |||
127 | <pre> | ||
128 | 0x00000200: mov.l @(0x02C,pc),r1 ; 0x0000022C (0x09000000) | ||
129 | 0x00000202: ldc r1,vbr | ||
130 | </pre> | ||
131 | |||
132 | <h3>Stack</h3> | ||
133 | |||
134 | <p>The next instruction loads r15 with the contents of 0x228, which is 0x0903f2bc. This is the stack pointer, which is used all over the code. | ||
135 | |||
136 | <pre> | ||
137 | 0x00000204: mov.l @(0x024,pc),r15 ; 0x00000228 (0x0903F2BC) | ||
138 | </pre> | ||
139 | |||
140 | <p>After that the code jumps to the hardware setup at 0xc8c0. | ||
141 | <pre> | ||
142 | 0x00000206: mov.l @(0x01C,pc),r0 ; 0x00000220 (0x0900C8C0) | ||
143 | 0x00000208: jsr @r0 | ||
144 | </pre> | ||
145 | |||
146 | <h3>DRAM controller</h3> | ||
147 | |||
148 | <p>First up is DRAM setup, at 0xc8c8. It sets the memory controller registers: | ||
149 | |||
150 | <pre> | ||
151 | 0x0000C8C8: mov.l @(0x068,pc),r2 ; 0x0000C930 (0x05FFFFA8) | ||
152 | 0x0000C8CA: mov.w @(0x05A,pc),r1 ; 0x0000C924 (0x1E00) | ||
153 | 0x0000C8CC: mov.l @(0x068,pc),r7 ; 0x0000C934 (0x0F0001C0) | ||
154 | 0x0000C8CE: mov.w r1,@r2 ; 0x1e00 -> DCR | ||
155 | 0x0000C8D0: mov.l @(0x068,pc),r2 ; 0x0000C938 (0x05FFFFAC) | ||
156 | 0x0000C8D2: mov.w @(0x054,pc),r1 ; 0x0000C926 (0x5AB0) | ||
157 | 0x0000C8D4: mov.w r1,@r2 ; 0x5ab0 -> RCR | ||
158 | 0x0000C8D6: mov.l @(0x068,pc),r2 ; 0x0000C93C (0x05FFFFB2) | ||
159 | 0x0000C8D8: mov.w @(0x050,pc),r1 ; 0x0000C928 (0x9605) | ||
160 | 0x0000C8DA: mov.w r1,@r2 ; 0x9505 -> RTCOR | ||
161 | 0x0000C8DC: mov.l @(0x064,pc),r2 ; 0x0000C940 (0x05FFFFAE) | ||
162 | 0x0000C8DE: mov.w @(0x04C,pc),r1 ; 0x0000C92A (0xA518) | ||
163 | 0x0000C8E0: mov.w r1,@r2 ; 0xa518 -> RTCSR | ||
164 | </pre> | ||
165 | |||
166 | <h3>Serial port 0</h3> | ||
167 | |||
168 | <p>Code starting at 0x483c. | ||
169 | |||
170 | <p>As C code: | ||
171 | |||
172 | <table border><tr><td bgcolor="#a0d6e8"> | ||
173 | <pre> | ||
174 | void setup_sci0(void) | ||
175 | { | ||
176 | /* set PB12 to output */ | ||
177 | PBIOR |= 0x1000; | ||
178 | | ||
179 | /* Disable serial port */ | ||
180 | SCR0 = 0x00; | ||
181 | | ||
182 | /* Syncronous, 8N1, no prescale */ | ||
183 | SMR0 = 0x80; | ||
184 | | ||
185 | /* Set baudrate 1Mbit/s */ | ||
186 | BRR0 = 0x03; | ||
187 | | ||
188 | /* use SCK as serial clock output */ | ||
189 | SCR0 = 0x01; | ||
190 | | ||
191 | /* Clear FER and PER */ | ||
192 | SSR0 &= 0xe7; | ||
193 | | ||
194 | /* Set interrupt D priority to 0 */ | ||
195 | IPRD &= 0x0ff0; | ||
196 | | ||
197 | /* set IRQ6 and IRQ7 to edge detect */ | ||
198 | ICR |= 0x03; | ||
199 | | ||
200 | /* set PB15 and PB14 to inputs */ | ||
201 | PBIOR &= 0x7fff; | ||
202 | PBIOR &= 0xbfff; | ||
203 | | ||
204 | /* set IRQ6 prio 8 and IRQ7 prio 0 */ | ||
205 | IPRB = ( IPRB & 0xff00 ) | 0x80; | ||
206 | | ||
207 | /* Enable Tx (only!) */ | ||
208 | SCR0 = 0x20; | ||
209 | } | ||
210 | </pre> | ||
211 | </td></tr></table> | ||
212 | |||
213 | |||
214 | <h3>Serial port 1</h3> | ||
215 | |||
216 | <p>Code starting at 0x47a0. | ||
217 | |||
218 | <p>As C code: | ||
219 | |||
220 | <table border><tr><td bgcolor="#a0d6e8"> | ||
221 | <pre> | ||
222 | #define SYSCLOCK 12000000 | ||
223 | #define PRIORITY 8 | ||
224 | | ||
225 | void setup_sci1(int baudrate) | ||
226 | { | ||
227 | /* Disable serial port */ | ||
228 | SCR1 = 0; | ||
229 | | ||
230 | /* Set PB11 to Tx and PB10 to Rx */ | ||
231 | PBCR1 = (PBCR1 & 0xff0f) | 0xa0; | ||
232 | | ||
233 | /* Asynchronous, 8N1, no prescaler */ | ||
234 | SMR1 = 0; | ||
235 | | ||
236 | /* Set baudrate */ | ||
237 | BRR1 = SYSCLOCK / (baudrate * 32) - 1; | ||
238 | | ||
239 | /* Clear FER and PER */ | ||
240 | SSR1 &= 0xe7; | ||
241 | | ||
242 | /* Set interrupt priority to 8 */ | ||
243 | IPRE = (IPRE & 0x0fff) | (PRIORITY << 12); | ||
244 | | ||
245 | /* Enable Rx, Tx and Rx interrupt */ | ||
246 | SCR1 = 0x70; | ||
247 | } | ||
248 | </pre> | ||
249 | </td></tr></table> | ||
250 | |||
251 | <h3>Pin configuration</h3> | ||
252 | |||
253 | <p>Starting at 0xc40a: | ||
254 | |||
255 | <p><tt>CASCR = 0xafff</tt>: Column Address Strobe Pin Control Register. Set bits CASH MD1 and CASL MD1. | ||
256 | |||
257 | <h4>Port A</h4> | ||
258 | <br><tt>PACR1 = 0x0102</tt>: Set pin functions | ||
259 | <br><tt>PACR2 = 0xbb98</tt>: Set pin functions | ||
260 | <br><tt>PAIOR &= 0xfffe</tt>: PA0 is input | ||
261 | <br><tt>PAIOR &= 0xffdf</tt>: PA5 is input | ||
262 | <br><tt>PADR &= 0xff7f</tt>: Set pin PA7 low | ||
263 | <br><tt>PAIOR |= 0x80</tt>: PA7 is output | ||
264 | <br><tt>PAIOR |= 0x100</tt>: PA8 is output | ||
265 | <br><tt>PADR |= 0x200</tt>: Set pin PA9 high | ||
266 | <br><tt>PAIOR |= 0x200</tt>: PA9 is output | ||
267 | <br><tt>PAIOR |= 0x400</tt>: PA10 is output | ||
268 | <br><tt>PAIOR &= 0xf7ff</tt>: PA11 is input | ||
269 | <br><tt>PAIOR &= 0xbfff</tt>: PA14 is input | ||
270 | <br><tt>PAIOR = 0x7fff</tt>: PA15 is input | ||
271 | <br><tt>PADR &= 0xfeff</tt>: Set pin PA8 low | ||
272 | |||
273 | <h4>Port B</h4> | ||
274 | <br><tt>PBCR1 = 0x12a8</tt>: Set pin functions | ||
275 | <br><tt>PBCR2 = 0x0000</tt>: Set pin functions | ||
276 | <br><tt>PBDR &= 0xffef</tt>: Set pin PB4 low | ||
277 | <br><tt>PBIOR &= 0xffef</tt>: PB4 is input | ||
278 | <br><tt>PBIOR |= 0x20</tt>: PB5 is output | ||
279 | <br><tt>PBIOR |= 0x40</tt>: PA6 is output | ||
280 | <br><tt>PBDR &= 0xffbf</tt>: Set pin PB6 low | ||
281 | <br><tt>PBDR |= 0x20</tt>: Set pin PB5 high | ||
282 | |||
283 | <h3>ITU (Integrated Timer Pulse Unit)</h3> | ||
284 | |||
285 | <p>Starting at 0xfcd0: | ||
286 | |||
287 | <p><tt>TSNC &= 0xfe</tt>: The timer counter for channel 0 (TCNT0) operates independently of other channels | ||
288 | <br><tt>TMDR &= 0xfe</tt>: Channel 0 operates in normal (not PWM) mode | ||
289 | <br><tt>GRA0 = 0x1d4c</tt>: | ||
290 | <br><tt>TCR0 &= 0x67; TCR0 |= 0x23</tt>: TCNT is cleared by general register A (GRA) compare match or input capture. Counter clock = f/8 | ||
291 | <br><tt>TIOR0 = 0x88</tt>: Compare disabled | ||
292 | <br><tt>TIER0 = 0xf9</tt>: Enable interrupt requests by IMFA (IMIA) | ||
293 | <br><tt>IPRC &= 0xff0f; IPRC |= 0x30</tt>: Set ITU0 interrupt priority level 3. | ||
294 | <br><tt>TSTR |= 0x01</tt>: Start TCNT0 | ||
295 | |||
296 | <h3>Memory area #6 ?</h3> | ||
297 | |||
298 | <p>From 0xc52a: | ||
299 | |||
300 | <p><tt>PADR |= 0x0200</tt>: Set PA13 high | ||
301 | <br><tt>WCR1 = 0x40ff</tt>: Enable /WAIT support for memory area 6. Hmmm, what's on CS6? | ||
302 | <br><tt>WCR1 &= 0xfdfd</tt>: Turn off RW5 (was off already) and WW1 (enable short address output cycle). | ||
303 | <br><tt>WCR3 &= 0xe7ff</tt>: Turn off A6LW1 and A6LW0; 1 wait state for CS6. | ||
304 | <br><tt>ICR |= 0x80</tt>: Interrupt is requested on falling edge of IRQ0 input | ||
305 | |||
306 | <h2>Remote control</h2> | ||
307 | <p>Tjerk Schuringa reports: | ||
308 | "Finally got that extra bit going on my bitpattern generator. So far I fed only | ||
309 | simple characters to my jukebox, and this is the result: | ||
310 | |||
311 | <pre> | ||
312 | START D0 1 2 3 4 5 6 7 STOP FUNCTION | ||
313 | 0 0 0 0 0 0 1 1 1 1 VOL- (the one I got already) | ||
314 | 0 0 0 0 1 0 1 1 VOL+ (figures) | ||
315 | 0 0 0 1 0 0 1 1 + | ||
316 | 0 0 1 0 0 0 1 1 - | ||
317 | 0 1 0 0 0 0 1 1 STOP | ||
318 | 1 0 0 0 0 0 1 1 PLAY | ||
319 | </pre> | ||
320 | |||
321 | <p>I also found that "repeat" functions (keep a button depressed) needs to be | ||
322 | faster than 0.5 s. If it is around 1 second or more it is interpreted as a | ||
323 | seperate keypress. So far I did not get the "fast forward" function because the | ||
324 | fastest I can get is 0.5 s. | ||
325 | |||
326 | <p>Very important: the baudrate is indeed 9600 baud! These pulses are fed to the | ||
327 | second ring on the headphone jack, and (if I understood correctly) go to RxD1 | ||
328 | of the SH1." | ||
329 | |||
330 | <h2>LCD display</h2> | ||
331 | |||
332 | <p>The Recorder uses a Shing Yih Technology G112064-30 graphic LCD display with 112x64 pixels. The controller is a Solomon SSD1815Z. | ||
333 | |||
334 | <p>It's not yet known what display/controller the Jukebox has, but I'd be surprised if it doesn't use a similar controller. | ||
335 | |||
336 | <p>Starting at 0xE050, the code flicks PB2 and PB3 a great deal and then some with PB1 and PB0. Which gives us the following connections: | ||
337 | |||
338 | <table border><tr><th>CPU pin</th><th>LCD pin</th></tr> | ||
339 | <tr><td>PB0</td><td>DC</td></tr> | ||
340 | <tr><td>PB1</td><td>CS1</td></tr> | ||
341 | <tr><td>PB2</td><td>SCK</td></tr> | ||
342 | <tr><td>PB3</td><td>SDA</td></tr> | ||
343 | </table> | ||
344 | |||
345 | <p>The Recorder apparently has the connections this way (according to Gary Czvitkovicz): | ||
346 | <table border><tr><th>CPU pin</th><th>LCD pin</th></tr> | ||
347 | <tr><td>PB0</td><td>SDA</td></tr> | ||
348 | <tr><td>PB1</td><td>SCK</td></tr> | ||
349 | <tr><td>PB2</td><td>DC</td></tr> | ||
350 | <tr><td>PB3</td><td>CS1</td></tr> | ||
351 | </table> | ||
352 | |||
353 | <a name="charsets"><p>The charsets: | ||
354 | |||
355 | <p><table border=0><tr> | ||
356 | <td><img src="codes_old.png" width=272 height=272><br> | ||
357 | <small>Old LCD charset (before v4.50)</small></td> | ||
358 | <td><img src="codes_new.png" width=272 height=272><br> | ||
359 | <small>New LCD charset (after v4.50)</small></td></tr></table> | ||
360 | |||
361 | |||
362 | <h3>Code</h3> | ||
363 | |||
364 | <p>This C snippet write a byte to the Jukebox LCD controller. | ||
365 | The 'data' flag inticates if the byte is a command byte or a data byte. | ||
366 | |||
367 | <table border><tr><td bgcolor="#a0d6e8"> | ||
368 | <pre> | ||
369 | #define DC 1 | ||
370 | #define CS1 2 | ||
371 | #define SDA 4 | ||
372 | #define SCK 8 | ||
373 | | ||
374 | void lcd_write(int byte, int data) | ||
375 | { | ||
376 | int i; | ||
377 | char on,off; | ||
378 | | ||
379 | PBDR &= ~CS1; /* enable lcd chip select */ | ||
380 | | ||
381 | if ( data ) { | ||
382 | on=~(SDA|SCK); | ||
383 | off=SCK|DC; | ||
384 | } | ||
385 | else { | ||
386 | on=~(SDA|SCK|DC); | ||
387 | off=SCK; | ||
388 | } | ||
389 | /* clock out each bit, MSB first */ | ||
390 | for (i=0x80;i;i>>=1) | ||
391 | { | ||
392 | PBDR &= on; | ||
393 | if (i & byte) | ||
394 | PBDR |= SDA; | ||
395 | PBDR |= off; | ||
396 | } | ||
397 | | ||
398 | PBDR |= CS1; /* disable lcd chip select */ | ||
399 | } | ||
400 | </pre> | ||
401 | </td></tr></table> | ||
402 | |||
403 | <h2>Firmware size</h2> | ||
404 | |||
405 | <p>Joachim Schiffer found out that firmware files have to be at least 51200 | ||
406 | bytes to be loaded by newer firmware ROMs. | ||
407 | So my "first program" only works on players with older firmware in ROM | ||
408 | (my has 3.18). Joachim posted a | ||
409 | <a href="mail/jukebox-archive-2001-12/att-0087/01-AJBREC.ajz">padded version</a> that works everywhere. | ||
410 | |||
411 | #include "foot.t" | ||