0a91d1df4417c3a736549c8b68bacef0ffb1897a
[fw/sdcc] / device / lib / ds400 / ds400rom.c
1 // Interface to the DS80C400 ROM functions. Largely based on code released
2 // by Dallas, hence the following copyright.
3
4 // ---------------------------------------------------------------------------
5 //  Copyright (C) 2003 Dallas Semiconductor Corporation, All Rights Reserved.
6 // 
7 //  Permission is hereby granted, free of charge, to any person obtaining a
8 //  copy of this software and associated documentation files (the "Software"),
9 //  to deal in the Software without restriction, including without limitation
10 //  the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 //  and/or sell copies of the Software, and to permit persons to whom the
12 //  Software is furnished to do so, subject to the following conditions:
13 //
14 //  The above copyright notice and this permission notice shall be included
15 //  in all copies or substantial portions of the Software.
16 //
17 //  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 //  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 //  MERCHANTABILITY,  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 //  IN NO EVENT SHALL DALLAS SEMICONDUCTOR BE LIABLE FOR ANY CLAIM, DAMAGES
21 //  OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 //  ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 //  OTHER DEALINGS IN THE SOFTWARE.
24 //
25 //  Except as contained in this notice, the name of Dallas Semiconductor
26 //  shall not be used except as stated in the Dallas Semiconductor
27 //  Branding Policy.
28 // ---------------------------------------------------------------------------
29
30 #include <stdio.h>
31 #include <ds400rom.h>
32
33 // Register bank 3 equates.
34 #define R0_B3     0x18
35 #define R1_B3     0x19
36 #define R2_B3     0x1A
37 #define R3_B3     0x1B
38 #define R4_B3     0x1C
39 #define R5_B3     0x1D
40 #define R6_B3     0x1E
41 #define R7_B3     0x1F
42
43
44 // The top of the redirect function table in RAM.
45 #define CALL_TABLE_TOP  256
46     
47 // The bank the ROM is stored in.  Should be 0FFh for production
48 // 400's.  Change this value when running with a debug ROM.
49
50 #define ROM_BANK        0xFF
51
52 // The address of the ROM export table is stored
53 // at (ROM_BANK << 16) | ROM_EXPORTTABLE_OFFS
54
55 #define ROM_EXPORTTABLE_OFFS    2
56
57 //
58 // Each entry in the ROM export table is 3 bytes.
59 //
60 #define ROMXT_ENTRYSIZE      3
61
62 //
63 // The number of functions in the ROM export table is stored
64 // first in the export table.
65 //
66 #define ROMXT_NUMFUNCTIONS     (0 * ROMXT_ENTRYSIZE)
67
68 //
69 // ROM EXPORT TABLE FUNCTIONS (denoted with ROMXT)
70 //
71
72 // UTILITY functions 
73 #define ROMXT_CRC16                     (1 * ROMXT_ENTRYSIZE) //
74 #define ROMXT_MEM_CLEAR_16              (2 * ROMXT_ENTRYSIZE) //
75 #define ROMXT_MEM_COPY_16               (3 * ROMXT_ENTRYSIZE) //
76 #define ROMXT_MEM_COMPARE               (4 * ROMXT_ENTRYSIZE) //
77 #define ROMXT_ADD_DPTR1_16              (5 * ROMXT_ENTRYSIZE) // not implemented for C compiler
78 #define ROMXT_ADD_DPTR2_16              (6 * ROMXT_ENTRYSIZE) // not implemented for C compiler
79 #define ROMXT_SUB_DPTR1_16              (7 * ROMXT_ENTRYSIZE) // not implemented for C compiler
80 #define ROMXT_SUB_DPTR2_16              (8 * ROMXT_ENTRYSIZE) // not implemented for C compiler
81 #define ROMXT_GETPSEUDORANDOM           (9 * ROMXT_ENTRYSIZE) //
82
83 // MEMORY MGR
84 #define ROMXT_KERNELMALLOC              (10 * ROMXT_ENTRYSIZE) // not exposed
85 #define ROMXT_KERNELFREE                (11 * ROMXT_ENTRYSIZE) // not exposed
86 #define ROMXT_MM_MALLOC                 (12 * ROMXT_ENTRYSIZE) // exposed as redirected function
87 #define ROMXT_MM_MALLOC_DIRTY           (13 * ROMXT_ENTRYSIZE) // exposed as redirected function
88 #define ROMXT_MM_FREE                   (14 * ROMXT_ENTRYSIZE) // exposed as redirected function
89 #define ROMXT_MM_DEREF                  (15 * ROMXT_ENTRYSIZE) // exposed as redirected function
90 #define ROMXT_GETFREERAM                (16 * ROMXT_ENTRYSIZE) // exposed as redirected function
91
92 // SOCKET functions
93 #define ROMXT_ROM_SOCKET                (17 * ROMXT_ENTRYSIZE) //
94 #define ROMXT_ROM_CLOSESOCKET           (18 * ROMXT_ENTRYSIZE) //
95 #define ROMXT_ROM_SENDTO                (19 * ROMXT_ENTRYSIZE) //
96 #define ROMXT_ROM_RECVFROM              (20 * ROMXT_ENTRYSIZE) //
97 #define ROMXT_ROM_CONNECT               (21 * ROMXT_ENTRYSIZE) //
98 #define ROMXT_ROM_BIND                  (22 * ROMXT_ENTRYSIZE) //
99 #define ROMXT_ROM_LISTEN                (23 * ROMXT_ENTRYSIZE) //
100 #define ROMXT_ROM_ACCEPT                (24 * ROMXT_ENTRYSIZE) //
101 #define ROMXT_ROM_RECV                  (25 * ROMXT_ENTRYSIZE) //
102 #define ROMXT_ROM_SEND                  (26 * ROMXT_ENTRYSIZE) //
103 #define ROMXT_ROM_GETSOCKOPT            (27 * ROMXT_ENTRYSIZE) //
104 #define ROMXT_ROM_SETSOCKOPT            (28 * ROMXT_ENTRYSIZE) //
105 #define ROMXT_ROM_GETSOCKNAME           (29 * ROMXT_ENTRYSIZE) //
106 #define ROMXT_ROM_GETPEERNAME           (30 * ROMXT_ENTRYSIZE) //
107 #define ROMXT_ROM_CLEANUP               (31 * ROMXT_ENTRYSIZE) //
108 #define ROMXT_ROM_AVAIL                 (32 * ROMXT_ENTRYSIZE) //
109 #define ROMXT_ROM_JOIN                  (33 * ROMXT_ENTRYSIZE) //
110 #define ROMXT_ROM_LEAVE                 (34 * ROMXT_ENTRYSIZE) //
111 #define ROMXT_ROM_PING                  (35 * ROMXT_ENTRYSIZE) //
112 #define ROMXT_ROM_GETNETWORKPARAMS      (36 * ROMXT_ENTRYSIZE) //
113 #define ROMXT_ROM_SETNETWORKPARAMS      (37 * ROMXT_ENTRYSIZE) //
114 #define ROMXT_ROM_GETIPV6PARAMS         (38 * ROMXT_ENTRYSIZE) //
115 #define ROMXT_ROM_GETETHERNETSTATUS     (39 * ROMXT_ENTRYSIZE) //
116 #define ROMXT_ROM_GETTFTPSERVER         (40 * ROMXT_ENTRYSIZE) //
117 #define ROMXT_ROM_SETTFTPSERVER         (41 * ROMXT_ENTRYSIZE) //
118 #define ROMXT_ETH_PROCESSINTERRUPT      (42 * ROMXT_ENTRYSIZE) // not implemented for C compiler
119 #define ROMXT_ARP_GENERATEREQUEST       (43 * ROMXT_ENTRYSIZE) // not implemented for C compiler
120 #define ROMXT_NET_ETH0_MAC_ID           (44 * ROMXT_ENTRYSIZE) //
121
122 // DHCP functions
123 #define ROMXT_DHCP_INIT                 (45 * ROMXT_ENTRYSIZE) //
124 #define ROMXT_DHCP_SETUP                (46 * ROMXT_ENTRYSIZE) // not implemented for C compiler
125 #define ROMXT_DHCP_STARTUP              (47 * ROMXT_ENTRYSIZE) // not implemented for C compiler
126 #define ROMXT_DHCP_RUN                  (48 * ROMXT_ENTRYSIZE) // not implemented for C compiler
127 #define ROMXT_DHCP_STATUS               (49 * ROMXT_ENTRYSIZE) //
128 #define ROMXT_DHCP_STOP                 (50 * ROMXT_ENTRYSIZE) //
129 #define ROMXT_DHCPNOTIFY                (51 * ROMXT_ENTRYSIZE) // empty redirect stub, not implemented
130
131 // TFTP functions
132 #define ROMXT_TFTP_INIT                 (52 * ROMXT_ENTRYSIZE) //
133 #define ROMXT_TFTP_FIRST                (53 * ROMXT_ENTRYSIZE) //
134 #define ROMXT_TFTP_NEXT                 (54 * ROMXT_ENTRYSIZE) //
135 #define ROMXT_TFTP_MSG                  (55 * ROMXT_ENTRYSIZE) //
136
137 // SCHEDULER functions
138 #define ROMXT_TASK_GENESIS              (56 * ROMXT_ENTRYSIZE) //
139 #define ROMXT_TASK_GETCURRENT           (57 * ROMXT_ENTRYSIZE) //
140 #define ROMXT_TASK_GETPRIORITY          (58 * ROMXT_ENTRYSIZE) //
141 #define ROMXT_TASK_SETPRIORITY          (59 * ROMXT_ENTRYSIZE) //
142 #define ROMXT_TASK_FORK                 (60 * ROMXT_ENTRYSIZE) //
143 #define ROMXT_TASK_KILL                 (61 * ROMXT_ENTRYSIZE) //
144 #define ROMXT_TASK_SUSPEND              (62 * ROMXT_ENTRYSIZE) //
145 #define ROMXT_TASK_SLEEP                (63 * ROMXT_ENTRYSIZE) //
146 #define ROMXT_TASK_SIGNAL               (64 * ROMXT_ENTRYSIZE) //
147 #define ROMXT_ROM_TASK_SWITCH_IN        (65 * ROMXT_ENTRYSIZE) // empty redirect stub, not implemented
148 #define ROMXT_ROM_TASK_SWITCH_OUT       (66 * ROMXT_ENTRYSIZE) // empty redirect stub, not implemented
149 #define ROMXT_ENTERCRITSECTION          (67 * ROMXT_ENTRYSIZE) //
150 #define ROMXT_LEAVECRITSECTION          (68 * ROMXT_ENTRYSIZE) //
151
152 // INIT functions
153 #define ROMXT_ROM_INIT                  (69 * ROMXT_ENTRYSIZE) //
154 #define ROMXT_ROM_COPYIVT               (70 * ROMXT_ENTRYSIZE) //
155 #define ROMXT_ROM_REDIRECT_INIT         (71 * ROMXT_ENTRYSIZE) //
156 #define ROMXT_MM_INIT                   (72 * ROMXT_ENTRYSIZE) //
157 #define ROMXT_KM_INIT                   (73 * ROMXT_ENTRYSIZE) //
158 #define ROMXT_OW_INIT                   (74 * ROMXT_ENTRYSIZE) //
159 #define ROMXT_NETWORK_INIT              (75 * ROMXT_ENTRYSIZE) //
160 #define ROMXT_ETH_INIT                  (76 * ROMXT_ENTRYSIZE) //
161 #define ROMXT_INIT_SOCKETS              (77 * ROMXT_ENTRYSIZE) //
162 #define ROMXT_TICK_INIT                 (78 * ROMXT_ENTRYSIZE) //
163
164 // Timer Interrupt vectors
165 #define ROMXT_WOS_TICK                  (79 * ROMXT_ENTRYSIZE) // not implemented for C compiler
166 #define ROMXT_BLOB                      (80 * ROMXT_ENTRYSIZE) // not implemented for C compiler
167
168 // Maintenance functions
169 #define ROMXT_WOS_IOPOLL                (81 * ROMXT_ENTRYSIZE) // not implemented for C compiler
170 #define ROMXT_IP_PROCESSRECEIVEQUEUES   (82 * ROMXT_ENTRYSIZE) // not implemented for C compiler
171 #define ROMXT_IP_PROCESSOUTPUT          (83 * ROMXT_ENTRYSIZE) // not implemented for C compiler
172 #define ROMXT_TCP_RETRYTOP              (84 * ROMXT_ENTRYSIZE) // not implemented for C compiler
173 #define ROMXT_ETH_PROCESSOUTPUT         (85 * ROMXT_ENTRYSIZE) // not implemented for C compiler
174 #define ROMXT_IGMP_GROUPMAINTAINENCE    (86 * ROMXT_ENTRYSIZE) // not implemented for C compiler
175 #define ROMXT_IP6_PROCESSRECEIVEQUEUES  (87 * ROMXT_ENTRYSIZE) // not implemented for C compiler
176 #define ROMXT_IP6_PROCESSOUTPUT         (88 * ROMXT_ENTRYSIZE) // not implemented for C compiler
177 #define ROMXT_PARAMBUFFER               (89 * ROMXT_ENTRYSIZE) // not implemented for C compiler
178 #define ROMXT_RAM_TOP                   (90 * ROMXT_ENTRYSIZE) // not implemented for C compiler
179 #define ROMXT_BOOT_MEMBEGIN             (91 * ROMXT_ENTRYSIZE) // not implemented for C compiler
180 #define ROMXT_BOOT_MEMEND               (92 * ROMXT_ENTRYSIZE) // not implemented for C compiler
181
182 // 1-Wire
183 #define ROMXT_OWM_FIRST                 (93 * ROMXT_ENTRYSIZE) //
184 #define ROMXT_OWM_NEXT                  (94 * ROMXT_ENTRYSIZE) //
185 #define ROMXT_OWM_RESET                 (95 * ROMXT_ENTRYSIZE) //
186 #define ROMXT_OWM_BYTE                  (96 * ROMXT_ENTRYSIZE) //
187 #define ROMXT_OWM_SEARCH                (97 * ROMXT_ENTRYSIZE) // not implemented for C compiler
188 #define ROMXT_OW_ROMID                  (98 * ROMXT_ENTRYSIZE) //
189
190 // Misc, extras, late additions
191 #define ROMXT_AUTOBAUD                  (99 * ROMXT_ENTRYSIZE)
192 #define ROMXT_TFTP_CLOSE                (100 * ROMXT_ENTRYSIZE)
193
194
195 #define ROMRT_ENTRYSIZE  3
196
197 //
198 // ROM REDIRECT TABLE FUNCTIONS (denoted with ROMRT)
199 //
200 #define ROMRT_KERNELMALLOC                  ( 1 * ROMRT_ENTRYSIZE)
201 #define ROMRT_KERNELFREE                    ( 2 * ROMRT_ENTRYSIZE)
202 #define ROMRT_MALLOC                        ( 3 * ROMRT_ENTRYSIZE)
203 #define ROMRT_FREE                          ( 4 * ROMRT_ENTRYSIZE)
204 #define ROMRT_MALLOCDIRTY                   ( 5 * ROMRT_ENTRYSIZE)
205 #define ROMRT_DEREF                         ( 6 * ROMRT_ENTRYSIZE)
206 #define ROMRT_GETFREERAM                    ( 7 * ROMRT_ENTRYSIZE)
207 #define ROMRT_GETTIMEMILLIS                 ( 8 * ROMRT_ENTRYSIZE)
208 #define ROMRT_GETTHREADID                   ( 9 * ROMRT_ENTRYSIZE)
209 #define ROMRT_THREADRESUME                  (10 * ROMRT_ENTRYSIZE)
210 #define ROMRT_THREADIOSLEEP                 (11 * ROMRT_ENTRYSIZE)
211 #define ROMRT_THREADIOSLEEPNC               (12 * ROMRT_ENTRYSIZE)
212 #define ROMRT_THREADSAVE                    (13 * ROMRT_ENTRYSIZE)
213 #define ROMRT_THREADRESTORE                 (14 * ROMRT_ENTRYSIZE)
214 #define ROMRT_SLEEP                         (15 * ROMRT_ENTRYSIZE)
215 #define ROMRT_GETTASKID                     (16 * ROMRT_ENTRYSIZE)
216 #define ROMRT_INFOSENDCHAR                  (17 * ROMRT_ENTRYSIZE)
217 #define ROMRT_IP_COMPUTECHECKSUM_SOFTWARE   (18 * ROMRT_ENTRYSIZE)
218 #define ROMRT_0                             (19 * ROMRT_ENTRYSIZE) // undefined
219 #define ROMRT_DHCPNOTIFY                    (20 * ROMRT_ENTRYSIZE)
220 #define ROMRT_ROM_TASK_CREATE               (21 * ROMRT_ENTRYSIZE)
221 #define ROMRT_ROM_TASK_DUPLICATE            (22 * ROMRT_ENTRYSIZE)
222 #define ROMRT_ROM_TASK_DESTROY              (23 * ROMRT_ENTRYSIZE)
223 #define ROMRT_ROM_TASK_SWITCH_IN            (24 * ROMRT_ENTRYSIZE)
224 #define ROMRT_ROM_TASK_SWITCH_OUT           (25 * ROMRT_ENTRYSIZE)
225 #define ROMRT_OWIP_READCONFIG               (26 * ROMRT_ENTRYSIZE)
226 #define ROMRT_SETMACID                      (27 * ROMRT_ENTRYSIZE)
227 #define ROMRT_UNDEREF                       (28 * ROMRT_ENTRYSIZE)
228
229
230 #define GETC            \
231     clr  a              \
232     movc a, @a+dptr
233     
234
235 // expects function number in R6_B3 (low byte) & R7_B3 (high byte)
236 void _romcall(void) _naked
237 {
238 _asm    
239       push  dpx                               ; dptr0 preserved here
240       push  dph
241       push  dpl
242
243       ; point to the address of the table               
244       mov   dptr, #(ROM_BANK << 16 | ROM_EXPORTTABLE_OFFS)
245
246       push  acc                               ; acc preserved here
247       push  b                                 ; b preserved here
248       inc   dptr
249       GETC                                    ; get the address of the table
250       push  acc
251       inc   dptr
252       GETC
253       add   a, R6_B3                          ; add function offset to the table
254       mov   dpl, a
255       pop   acc
256       addc  a, R7_B3
257       mov   dph, a
258
259       ;
260       ; dpx is the same, all in the same bank
261       ;
262       inc   dptr                              ; get the target address of the function we want
263       GETC
264       mov   b, a
265       inc   dptr
266       GETC
267       mov   R3_B3, a
268       mov   R4_B3, b
269       mov   R5_B3, dpx                        ; high byte does not change
270       pop   b                                 ; b restored here
271       pop   acc                               ; acc restored here
272       pop   dpl                               ; dptr0 preserved here
273       pop   dph
274       pop   dpx
275       push  R3_B3                             ; push the target address
276       push  R4_B3
277       push  R5_B3
278       ret                                     ; this is not a ret, it is a call!
279         
280       ; the called function ends with a ret which will return to our original caller.
281 _endasm ;
282 }
283
284 // expects function number in R6_B3 (low byte) & R7_B3 (high byte)
285 void _romredirect(void) _naked
286 {
287 _asm
288       push  dpx
289       push  dph
290       push  dpl
291       push  acc
292       ; dptr = CALL_TABLE_TOP + function offset.
293       mov   a, #(CALL_TABLE_TOP & 0xff)
294       add   a, R6_B3                          ; add function offset to the table
295       mov   dpl, a
296       mov   a, #((CALL_TABLE_TOP >> 8) & 0xff)
297       addc  a, R7_B3
298       mov   dph, a
299       mov   dpx, #((CALL_TABLE_TOP >> 16) & 0xff)
300       movx  a, @dptr                      ; read high byte
301       mov   R5_B3, a
302       inc   dptr
303       movx  a, @dptr                      ; read mid byte
304       mov   R4_B3, a
305       inc   dptr
306       movx  a, @dptr                      ; read low byte
307       mov   R3_B3, a
308       pop   acc                 ; restore acc and dptr
309       pop   dpl
310       pop   dph
311       pop   dpx
312       push  R3_B3               ; push low byte of target address
313       push  R4_B3
314       push  R5_B3               ; push high byte of target address
315       ret                       ; this is not a ret, it is a call!
316
317       ; the called function ends with a ret which will return to our original caller.
318 _endasm;        
319 }
320
321
322 // This macro is invalid for the standard C preprocessor, since it
323 // includes a hash character in the expansion, hence the SDCC specific
324 // pragma.
325 #pragma sdcc_hash +
326 #define ROMCALL(x) \
327         mov     R6_B3, #(x & 0xff)              \
328         mov     R7_B3, #((x >> 8) & 0xff)       \
329         lcall   __romcall
330
331 #define ROMREDIRECT(x) \
332         mov     R6_B3, #(x & 0xff)              \
333         mov     R7_B3, #((x >> 8) & 0xff)       \
334         lcall   __romredirect
335
336
337 // DSS_rom_init: the ds400 ROM_INIT ROM function.
338 unsigned char DSS_rom_init(void xdata *loMem,
339                        void xdata *hiMem) _naked
340 {    
341     // shut compiler up about unused parameters.
342     loMem;
343     hiMem;
344     
345 _asm
346         ; load params.
347         ; loMem is already in DPTR.
348         mov     r2, dpx
349         mov     r1, dph
350         mov     r0, dpl
351         ; hiMem is in _DSS_rom_init_PARM_2
352         mov     dptr, #_DSS_rom_init_PARM_2
353         mov     r5, dpx
354         mov     r4, dph
355         mov     r3, dpl
356
357         ROMCALL(ROMXT_ROM_INIT)
358
359         ; result is in acc, move to dpl for C convention.
360         mov     dpl, a
361         ret
362 _endasm ;
363 }
364
365 // DSS_gettimemillis: note that the ROM actually returns 5 bytes of time,
366 // we're discarding the high byte here.
367 unsigned long DSS_gettimemillis(void) _naked
368 {
369 _asm    
370     ; no parameters to load. 
371     ROMREDIRECT(ROMRT_GETTIMEMILLIS)
372    ; results in r4 - r0, return in DPTR/B
373    mov dpl, r0
374    mov dph, r1
375    mov dpx, r2
376    mov b, r3
377    ret
378 _endasm;
379 }
380
381 unsigned char DSS_getthreadID(void) _naked
382 {
383 _asm    
384     ; no parameters to load. 
385     ROMREDIRECT(ROMRT_GETTHREADID)
386    ; results in acc, return in dpl
387    mov dpl, a
388    ret
389 _endasm;    
390 }
391
392
393
394 // Various utility functions.
395
396 // Return the start of the XI_SEG. Really just a workaround for the
397 // fact that the linker defined symbol (s_XISEG) isn't directly accessible
398 // from C due to the lack of a leading underscore, and I'm too lazy to hack 
399 // the linker.
400 static void xdata *_xisegStart(void) _naked
401 {
402 _asm    
403         mov     dptr, #(s_XISEG)
404         ret
405 _endasm;
406 }
407
408 // Return the length of the XI_SEG. Really just a workaround for the
409 // fact that the linker defined symbol (l_XISEG) isn't directly accessible
410 // from C due to the lack of a leading underscore, and I'm too lazy to hack 
411 // the linker.
412 static unsigned  _xisegLen(void) _naked
413 {
414 _asm    
415         mov     dptr, #(l_XISEG)
416         ret
417 _endasm;
418 }
419
420 // Returns the address of the first byte available for heap memory, 
421 // i.e. the first byte following the XI_SEG.
422 static void xdata *_firstHeapByte(void)
423 {
424     unsigned char xdata *start;
425     
426     start = (unsigned char xdata *) _xisegStart();      
427     start += _xisegLen();
428
429     return (void xdata *)start;
430 }
431
432 // A simple wrapper for ROM_INIT which allocates all available RAM in the CE0 area
433 // to the heap.
434
435 // The last addressible byte of the CE0 area. 
436 #define CE0_END 0xfffff
437
438 unsigned char romInit(unsigned char noisy)
439 {
440     void xdata *heapStart;
441     void xdata *heapEnd;
442     unsigned long heapLen; 
443     unsigned char rc;
444     
445     heapStart = _firstHeapByte();
446     heapEnd = (void xdata *)CE0_END;
447
448     rc = DSS_rom_init(heapStart, heapEnd);
449     
450     if (noisy)
451     {
452         if (rc)
453         {
454             printf("error: rom_init returns %d\n", (int)rc);
455         }
456         else
457         {
458             heapLen = CE0_END - (unsigned long)heapStart;
459             printf("Heap starts at %p, length %luK\n", heapStart, heapLen / 1024);
460         }
461     }
462     return rc;
463 }
464
465 // Install an interrupt handler.
466 void installInterrupt(void (*isrPtr)(void), unsigned char offset)
467 {
468     unsigned char xdata * vectPtr = (unsigned char xdata *) offset;
469     unsigned long isr = (unsigned long)isrPtr;
470
471     *vectPtr++ = 0x02;
472     *vectPtr++ = (unsigned char)(isr >> 16);
473     *vectPtr++ = (unsigned char)(isr >> 8);
474     *vectPtr = (unsigned char)isr;
475 }