[project @ 1996-07-25 20:43:49 by partain]
[ghc-hetmet.git] / ghc / runtime / main / StgStartup.lhc
1 %/****************************************************************
2 %*                                                              *
3 %*   Basic Continuations required by the STG Machine runtime    *
4 %*                                                              *
5 %****************************************************************/
6
7
8 First continuation called by the mini-interpreter is
9 evaluateTopClosure.  It has to set up return and jump to the user's
10 @main@ closure.  If @errorIO@ is called, we will be back here, doing
11 the same thing for the specified continuation.
12
13 \begin{code}
14 #define MAIN_REG_MAP        /* STG world */
15 #include "rtsdefs.h"
16
17 #if 0
18 #ifdef PAR
19 #include "Statistics.h"
20 #endif
21 #endif
22
23 /* ptr to the user's "main" closure (or "errorIO" arg closure),
24    to which we hope to be linked
25 */
26 extern P_ TopClosure;
27
28 EXTFUN(stopThreadDirectReturn);
29 UNVECTBL(,vtbl_stopStgWorld,stopThreadDirectReturn)
30
31 /* Well, we have to put the ArrayOfData and ArrayOfPtrs info tables
32    somewhere...
33 */
34
35 /* Array of data -- mutable */
36 STATICFUN(ArrayOfData_entry)
37 {
38     FB_
39     /* Don't wrap the calls; we're done with STG land */
40     fflush(stdout);
41     fprintf(stderr, "Entered a primitive array (of data)---this shouldn't happen!\n");
42     abort();
43     FE_
44 }
45
46 DATA_ITBL(ArrayOfData_info,ArrayOfData_entry,UpdErr,0,INFO_OTHER_TAG,,,const,IF_,ARR_K,"DATA-ARRAY","ARRAY");
47 /* ToDo: could put a useful tag in there!!! */
48
49 /* Array of pointers -- mutable */
50 STATICFUN(ArrayOfPtrs_entry)
51 {
52     FB_
53     /* Don't wrap the calls; we're done with STG land */
54     fflush(stdout);
55     fprintf(stderr, "Entered a primitive array (of pointers)---this shouldn't happen!\n");
56     abort();
57     FE_
58 }
59
60 MUTUPLE_ITBL(ArrayOfPtrs_info,ArrayOfPtrs_entry,UpdErr,0,INFO_OTHER_TAG,,,const,IF_,ARR_K,"PTR-ARRAY(mut)","ARRAY");
61 /* ToDo: could put a useful tag in there!!! */
62
63 STATICFUN(FullSVar_entry)
64 {
65     FB_
66     /* Don't wrap the calls; we're done with STG land */
67     fflush(stdout);
68     fprintf(stderr, "Entered a full SVar---this shouldn't happen!\n");
69     abort();
70     FE_
71 }
72
73 MUTUPLE_ITBL(FullSVar_info,FullSVar_entry,UpdErr,0,INFO_OTHER_TAG,,,const,IF_,ARR_K,"FullSVar","ARRAY");
74 /* ToDo: could put a useful tag in there!!! */
75
76 STATICFUN(EmptySVar_entry)
77 {
78     FB_
79     /* Don't wrap the calls; we're done with STG land */
80     fflush(stdout);
81     fprintf(stderr, "Entered an empty SVar---this shouldn't happen!\n");
82     abort();
83     FE_
84 }
85
86 MUTUPLE_ITBL(EmptySVar_info,EmptySVar_entry,UpdErr,0,INFO_OTHER_TAG,,,const,IF_,ARR_K,"EmptySVar","ARRAY");
87 /* ToDo: could put a useful tag in there!!! */
88
89 /* Array of pointers -- immutable */
90 STATICFUN(ImMutArrayOfPtrs_entry)
91 {
92     FB_
93     /* Don't wrap the calls; we're done with STG land */
94     fflush(stdout);
95     fprintf(stderr, "Entered a primitive array (immutable, pointers)---this shouldn't happen!\n");
96     abort();
97     FE_
98 }
99
100 IMMUTUPLE_ITBL(ImMutArrayOfPtrs_info,ImMutArrayOfPtrs_entry,UpdErr,0,INFO_OTHER_TAG,,,const,IF_,ARR_K,"PTR-ARRAY(immut)","ARRAY");
101 /* ToDo: could put a useful tag in there!!! */
102
103 /* (end of Array whatnot) */
104
105 /* Question for Will: There seem to be a lot of these static things
106 now - worth putting them in a file by themselves?? [ADR] */
107
108
109 #if !defined(PAR) /* && !defined(GRAN) */
110
111 /* Ditto for Foreign Objectr entry point and info tables. [ADR]
112
113    BTW Will, I copied most of this blindly from above - what's with
114    this TAG stuff? And what kind of description/ type is wanted here?
115 */
116
117 STATICFUN(ForeignObj_entry)
118 {
119     FB_
120     /* Don't wrap the calls; we're done with STG land */
121     fflush(stdout);
122     fprintf(stderr, "Compiler bug: Entered a ForeignObj---this shouldn't happen!\n");
123     abort();
124     FE_
125 }
126
127 ForeignObj_ITBL(ForeignObj_info,ForeignObj_entry,UpdErr,0,INFO_OTHER_TAG,,,const,EF_,ForeignObj_K,"FOREIGN OBJ","ForeignObj");
128
129 /* End of ForeignObj stuff */
130
131 /* Ditto for the unused Stable Pointer info table. [ADR]
132 */
133
134 void raiseError PROTO((StgStablePtr));
135 extern StgStablePtr errorHandler; /* NB: prone to magic-value-ery (WDP 95/12) */
136
137 /* Unused Stable Pointer (ie unused slot in a stable pointer table) */
138 STATICFUN(UnusedSP_entry)
139 {
140     FB_
141     (void) SAFESTGCALL1(I_,(void *, FILE *),fflush,stdout);
142     (void) SAFESTGCALL2(I_,(void *, FILE *, char *),fprintf,stderr, "Entered an unused Stable Pointer---this shouldn't happen!\n(This could be program error (using stable pointer after freeing) or compiler bug.)\n");
143
144     (void) STGCALL1(void,(void *, StgStablePtr), raiseError, errorHandler);
145     FE_
146 }
147
148 STATIC_ITBL(UnusedSP_info,UnusedSP_entry,UpdErr,0,INFO_OTHER_TAG,0,0,const,IF_,CON_K,"UNUSED STABLE PTR","USP");
149
150 SET_STATIC_HDR(UnusedSP_closure,UnusedSP_info,CC_SUBSUMED,,ED_RO_)
151 };
152
153 /* Entry point and Info table for Stable Pointer Table. */
154
155 STATICFUN(EmptyStablePointerTable_entry)
156 {
157     FB_
158     /* Don't wrap the calls; we're done with STG land */
159     fflush(stdout);
160     fprintf(stderr, "Entered *empty* stable pointer table---this shouldn't happen!\n");
161     abort();
162     FE_
163 }
164
165 STATICFUN(StablePointerTable_entry)
166 {
167     FB_
168     /* Don't wrap the calls; we're done with STG land */
169     fflush(stdout);
170     fprintf(stderr, "Entered the stable pointer table---this shouldn't happen!\n");
171     abort();
172     FE_
173 }
174
175 STATIC_ITBL(EmptyStablePointerTable_info,EmptyStablePointerTable_entry,UpdErr,0,INFO_OTHER_TAG,0,0,const,IF_,SPT_K,"SP_TABLE","SP_TABLE");
176 /* ToDo: could put a useful tag in there!!! */
177
178 DYN_ITBL(StablePointerTable_info,StablePointerTable_entry,UpdErr,0,INFO_OTHER_TAG,0,0,const,IF_,SPT_K,"SP_TABLE","SP_TABLE");
179 /* ToDo: could put a useful tag in there!!! */
180
181
182 /* To ease initialisation of the heap, we start with an empty stable
183    pointer table.  When we try to create the first stable pointer, the
184    overflow will trigger creation of a table of useful size.
185 */
186
187 SET_STATIC_HDR(EmptySPTable_closure,EmptyStablePointerTable_info,CC_SUBSUMED,,ED_RO_)
188 , (W_) DYN_VHS + 0 + 1 + 0  /* size = DYN_VHS + n + 1 + n with n = 0 */
189 , (W_) 0   /* number of ptrs */
190 , (W_) 0   /* top of stack */
191 };
192
193 /* End of SP stuff */
194 #endif /* !PAR */
195
196
197 /* the IoWorld token to start the whole thing off */
198 /* Question: this is just an amusing hex code isn't it
199    -- or does it mean something? ADR */
200 P_ realWorldZh_closure = (P_) 0xbadbadbaL;
201 P_ GHCbuiltins_void_closure = (P_) 0xbadbadbaL;
202
203 SET_STATIC_HDR(WorldStateToken_closure,GHCbase_SZh_static_info,CC_SUBSUMED/*harmless*/,,ED_RO_)
204 , (W_) 0xbadbadbaL
205 };
206
207 #ifndef CONCURRENT
208
209 STGFUN(startStgWorld)
210 {
211     FB_
212     /* At this point we are in the threaded-code world.
213
214        TopClosure points to a closure of type PrimIO (), which should be
215        performed (by applying it to the state of the world).
216
217        The smInfo storage-management info block is assumed to be
218        up to date, and is used to load the STG registers.
219     */
220
221     RestoreAllStgRegs();    /* inline! */
222
223     /* ------- STG registers are now valid! -------------------------*/
224
225     /* Put a suitable return address on the B stack */
226     RetReg = (StgRetAddr) UNVEC(stopThreadDirectReturn,vtbl_stopStgWorld); 
227
228     /* Put an IoWorld token on the A stack */
229     SpA -= AREL(1);
230     *SpA = (P_) WorldStateToken_closure;
231
232     Node = (P_) TopClosure; /* Point to the closure for main/errorIO-arg */
233     ENT_VIA_NODE();
234     InfoPtr=(D_)(INFO_PTR(Node));
235     JMP_(ENTRY_CODE(InfoPtr));
236     FE_
237 }
238 #endif  /* ! CONCURRENT */
239
240 \end{code}
241
242 %************************************************************************
243 %*                                                                      *
244 \subsection[thread-return]{Polymorphic end-of-thread code}
245 %*                                                                      *
246 %************************************************************************
247
248 \begin{code}
249
250 /* 
251    Here's the polymorphic return for the end of a thread.
252
253    NB: For direct returns to work properly, the name of the routine must be
254    the same as the name of the vector table with vtbl_ removed and DirectReturn
255    appended.  This is all the mangler understands.
256 */
257
258 const W_
259 vtbl_stopThread[] = {
260   /* at least "MAX_VECTORED_RTN" elements (see GhcConstants.lh) */
261   (W_) stopThreadDirectReturn,
262   (W_) stopThreadDirectReturn,
263   (W_) stopThreadDirectReturn,
264   (W_) stopThreadDirectReturn,
265   (W_) stopThreadDirectReturn,
266   (W_) stopThreadDirectReturn,
267   (W_) stopThreadDirectReturn,
268   (W_) stopThreadDirectReturn
269 };
270
271 STGFUN(stopThreadDirectReturn)
272 {
273     FB_
274     /* The final exit.
275
276        The top-top-level closures (e.g., "main") are of type "IO ()".
277        When entered, they perform an IO action and return a () --
278        essentially, TagReg is set to 1.  Here, we don't need to do
279        anything with that.
280
281        We just tidy up the register stuff (real regs in *_SAVE, then 
282        *_SAVE -> smInfo locs).
283     */
284
285 #ifdef CONCURRENT
286     SET_TASK_ACTIVITY(ST_OVERHEAD);
287 #endif
288
289     SaveAllStgRegs();   /* inline! */
290
291 #ifdef CONCURRENT
292     EndThread();
293 #else
294     RESUME_(miniInterpretEnd);
295 #endif
296     FE_
297 }
298
299 \end{code}  
300
301 \begin{code}
302 I_ ErrorIO_call_count = 0;
303
304 #ifdef CONCURRENT
305 EXTFUN(EnterNodeCode);
306
307 STGFUN(ErrorIO_innards)
308     /* Assumes that "TopClosure" has been set already */
309 {
310     FB_
311     if (ErrorIO_call_count >= 16 /* MAGIC CONSTANT */ ) {
312         /* Don't wrap the calls; we're done with STG land */
313         fflush(stdout);
314         fprintf(stderr, "too many nested calls to `error'\n");
315         EXIT(EXIT_FAILURE);
316     }
317     ErrorIO_call_count++; /* NB: undo later if decide to let someone else handle it */
318
319     /* Unlock all global closures held by this thread! (ToDo) --JSM */
320
321     switch(TSO_TYPE(CurrentTSO)) {
322     case T_MAIN:
323         /* Re-initialize stack pointers (cf. NewThread) */
324 #ifdef PAR
325         SpB = SuB = STKO_BSTK_BOT(StkOReg) + BREL(1);
326         SuA = STKO_ASTK_BOT(StkOReg) + AREL(1);
327 #else
328         SuA = stackInfo.botA + AREL(1);
329         SuB = stackInfo.botB + BREL(1);
330         /* HWL */
331         /* 
332         SpB = SuB = STKO_BSTK_BOT(StkOReg) + BREL(1);
333         SuA = STKO_ASTK_BOT(StkOReg) + AREL(1);
334         */
335    
336 #endif
337         break;
338
339     case T_REQUIRED:
340         /* Re-initialize stack pointers (cf. NewThread) */
341         SpB = SuB = STKO_BSTK_BOT(StkOReg) + BREL(1);
342         SuA = STKO_ASTK_BOT(StkOReg) + AREL(1);
343         break;
344
345     case T_ADVISORY:
346         ErrorIO_call_count--; /* undo the damage, as someone else will deal with it */
347         /* Let the main thread eventually handle it */
348         JMP_(stopThreadDirectReturn);
349
350     case T_FAIL:
351         EXIT(EXIT_FAILURE);
352
353     default:
354         /* Don't wrap the calls; we're done with STG land */
355         fflush(stdout);
356         fprintf(stderr,"ErrorIO: %lx unknown\n", TSO_TYPE(CurrentTSO));
357         EXIT(EXIT_FAILURE);
358     }
359
360     /* Finish stack setup as if for a top-level task and enter the error node */
361
362     SpA = SuA - AREL(1);
363
364     *SpA = (P_) WorldStateToken_closure;
365
366     STKO_LINK(StkOReg) = Prelude_Z91Z93_closure;
367     STKO_RETURN(StkOReg) = NULL;
368
369 #ifdef TICKY_TICKY
370     STKO_ADEP(StkOReg) = STKO_BDEP(StkOReg) = 0;
371 #endif
372
373     /* Go! */
374     Node = (P_) TopClosure;
375     RetReg = (StgRetAddr) UNVEC(stopThreadDirectReturn,vtbl_stopStgWorld);
376     JMP_(EnterNodeCode);
377
378     FE_
379 }
380 \end{code}
381
382 We cannot afford to call @error@ too many times
383 (e.g., \tr{error x where x = error x}), so we keep count.
384
385 \begin{code}
386 #else   /* !CONCURRENT */
387
388 StgFunPtr
389 ErrorIO_innards(STG_NO_ARGS)
390     /* Assumes that "TopClosure" has been set already */
391 {
392     FB_
393     if (ErrorIO_call_count >= 16 /* MAGIC CONSTANT */ ) {
394         /* Don't wrap the calls; we're done with STG land */
395         fflush(stdout);
396         fprintf(stderr, "too many nested calls to `error'\n");
397         EXIT(EXIT_FAILURE);
398     }
399     ErrorIO_call_count++;
400
401     /* Copy the heap-related registers into smInfo.  (Other registers get
402        saved in this process, but we aren't interested in them.)
403
404        Get a new stack (which re-initialises the smInfo stack stuff),
405        and start the world again.
406     */
407     /* ToDo: chk this has been handled in parallel world */
408
409     SaveAllStgRegs();   /* inline! */
410
411     if (! initStacks( &StorageMgrInfo )) {
412         /* Don't wrap the calls; we're done with STG land */
413         fflush(stdout);
414         fprintf(stderr, "initStacks failed!\n");
415         EXIT(EXIT_FAILURE);
416     }
417
418     JMP_( startStgWorld );
419     FE_
420 }
421
422 #endif  /* !CONCURRENT */
423 \end{code}  
424
425 \begin{code}
426 #if defined(PAR) || defined(GRAN) 
427
428 STATICFUN(RBH_Save_0_entry)
429 {
430   FB_
431   fprintf(stderr,"Oops, entered an RBH save\n");
432   EXIT(EXIT_FAILURE);
433   FE_
434 }
435
436 STATICFUN(RBH_Save_1_entry)
437 {
438   FB_
439   fprintf(stderr,"Oops, entered an RBH save\n");
440   EXIT(EXIT_FAILURE);
441   FE_
442 }
443
444 STATICFUN(RBH_Save_2_entry)
445 {
446   FB_
447   fprintf(stderr,"Oops, entered an RBH save\n");
448   EXIT(EXIT_FAILURE);
449   FE_
450 }
451
452 SPEC_N_ITBL(RBH_Save_0_info,RBH_Save_0_entry,UpdErr,0,INFO_OTHER_TAG,2,0,,IF_,INTERNAL_KIND,"RBH-SAVE","RBH_Save_0");
453 SPEC_N_ITBL(RBH_Save_1_info,RBH_Save_1_entry,UpdErr,0,INFO_OTHER_TAG,2,1,,IF_,INTERNAL_KIND,"RBH-SAVE","RBH_Save_1");
454 SPEC_N_ITBL(RBH_Save_2_info,RBH_Save_2_entry,UpdErr,0,INFO_OTHER_TAG,2,2,,IF_,INTERNAL_KIND,"RBH-SAVE","RBH_Save_2");
455
456 #endif /* PAR || GRAN */
457 \end{code}
458
459
460 %/****************************************************************
461 %*                                                              *
462 %*              Other Bits and Pieces                           *
463 %*                                                              *
464 %****************************************************************/
465
466 \begin{code}
467 /* If we don't need the slow entry code for a closure, we put in a
468    pointer to this in the closure's slow entry code pointer instead.
469  */
470
471 STGFUN(__std_entry_error__) {
472     FB_
473     /* Don't wrap the calls; we're done with STG land */
474     fflush(stdout);
475     fprintf(stderr, "Called non-existent slow-entry code!!!\n");
476     abort();
477     JMP_(0);
478     FE_
479 }
480
481 /* entry code */
482 STGFUN(STK_STUB_entry) {
483     FB_
484     /* Don't wrap the calls; we're done with STG land */
485     fflush(stdout);
486     fprintf(stderr, "Entered from a stubbed stack slot!\n");
487     abort();
488     JMP_(0);
489     FE_
490 }
491
492 /* info table */
493 STATIC_ITBL(STK_STUB_info,STK_STUB_entry,UpdErr,0,INFO_OTHER_TAG,0,0,const,EF_,INTERNAL_KIND,"STK_STUB","STK_STUB");
494
495 /* closure */
496 SET_STATIC_HDR(STK_STUB_closure,STK_STUB_info,CC_SUBSUMED,,EXTDATA_RO)
497   , (W_)0, (W_)0
498 };
499 \end{code}
500
501 %/****************************************************************
502 %*                                                              *
503 %*              Some GC info tables                           *
504 %*                                                              *
505 %****************************************************************/
506
507 These have to be in a .lhc file, so they will be reversed correctly.
508
509 \begin{code}
510 #include "../storage/SMinternal.h"
511
512 #if defined(_INFO_COPYING)
513
514 STGFUN(Caf_Evac_Upd_entry) {
515     FB_
516     /* Don't wrap the calls; we're done with STG land */
517     fflush(stdout);
518     fprintf(stderr,"Entered Caf_Evac_Upd %lx: Should never occur!\n", (W_) Node);
519     abort();
520     FE_
521 }
522
523 CAF_EVAC_UPD_ITBL(Caf_Evac_Upd_info,Caf_Evac_Upd_entry,const/*not static*/);
524
525 #if defined(GCgn)
526
527 STGFUN(Forward_Ref_New_entry) {
528     FB_
529     /* Don't wrap the calls; we're done with STG land */
530     fflush(stdout);
531     fprintf(stderr,"Entered Forward_Ref_New %lx: Should never occur!\n", (W_) Node);
532     EXIT(EXIT_FAILURE); /* abort(); */
533     FE_
534 }
535 FORWARDREF_ITBL(Forward_Ref_New_info,Forward_Ref_New_entry,const/*not static*/,_Evacuate_Old_Forward_Ref);
536
537 STGFUN(Forward_Ref_Old_entry) {
538     FB_
539     /* Don't wrap the calls; we're done with STG land */
540     fflush(stdout);
541     fprintf(stderr,"Entered Forward_Ref_Old %lx: Should never occur!\n", (W_) Node);
542     EXIT(EXIT_FAILURE); /*    abort(); */
543     FE_
544 }
545 FORWARDREF_ITBL(Forward_Ref_Old_info,Forward_Ref_Old_entry,const/*not static*/,_Evacuate_New_Forward_Ref);
546
547 STGFUN(OldRoot_Forward_Ref_entry) {
548     FB_
549     /* Don't wrap the calls; we're done with STG land */
550     fflush(stdout);
551     fprintf(stderr,"Entered OldRoot_Forward_Ref %lx: Should never occur!\n", (W_) Node);
552     EXIT(EXIT_FAILURE); /*    abort(); */
553     FE_
554 }
555 FORWARDREF_ITBL(OldRoot_Forward_Ref_info,OldRoot_Forward_Ref_entry,const/*not static*/,_Evacuate_OldRoot_Forward);
556 #else /* ! GCgn */
557
558 STGFUN(Forward_Ref_entry) {
559     FB_
560     /* Don't wrap the calls; we're done with STG land */
561     fflush(stdout);
562     fprintf(stderr,"Entered Forward_Ref %lx: Should never occur!\n", (W_) Node);
563     EXIT(EXIT_FAILURE); /*    abort(); */
564     FE_
565 }
566 FORWARDREF_ITBL(Forward_Ref_info,Forward_Ref_entry,const/*not static*/,_Evacuate_Forward_Ref);
567 #endif /* ! GCgn */
568
569 #endif /* _INFO_COPYING */
570
571 #if defined(GCgn)
572 OLDROOT_ITBL(OldRoot_info,Ind_Entry,const,EF_);
573 #endif /* GCgn */
574 \end{code}
575
576
577 %/***************************************************************
578 %*                                                              *
579 %*              Cost Centre stuff ...                           *
580 %*                                                              *
581 %****************************************************************/
582
583 For cost centres we need prelude cost centres and register routine.
584
585 N.B. ALL prelude cost centres should be declared here as none will
586      be declared when the prelude is compiled.
587
588 ToDo: Explicit cost centres in prelude for Input and Output costs.
589
590 \begin{code}
591 #if defined(PROFILING)
592
593 STGFUN(startCcRegisteringWorld)
594 {
595     FB_
596     /* 
597      * We used to push miniInterpretEnd on the register stack, but
598      * miniInterpretEnd must only be entered with the RESUME_ macro,
599      * whereas the other addresses on the register stack must only be
600      * entered with the JMP_ macro.  Now, we push NULL and test for 
601      * it explicitly at each pop.
602      */
603     PUSH_REGISTER_STACK(NULL);
604     JMP_(_regMain);
605     FE_
606 }
607
608 CC_DECLARE(CC_CAFs,  "CAFs_in_...",  "PRELUDE", "PRELUDE", CC_IS_CAF,/*not static*/);
609 CC_DECLARE(CC_DICTs, "DICTs_in_...", "PRELUDE", "PRELUDE", CC_IS_DICT,/*not static*/);
610
611 START_REGISTER_PRELUDE(_regPrelude);
612 REGISTER_CC(CC_CAFs);
613 REGISTER_CC(CC_DICTs);
614 END_REGISTER_CCS()
615 \end{code}
616
617 We also need cost centre declarations and registering routines for other
618 built-in prelude-like modules.
619
620 ToDo: What built-in prelude-like modules exist ?
621
622 \begin{code}
623 START_REGISTER_PRELUDE(_regByteOps);    /* used in Glasgow tests only? */
624 END_REGISTER_CCS()
625
626 /* _regPrelude is above */
627
628 START_REGISTER_PRELUDE(_regPreludeArray);
629 END_REGISTER_CCS()
630
631 START_REGISTER_PRELUDE(_regPreludeCore);
632 END_REGISTER_CCS()
633
634 START_REGISTER_PRELUDE(_regPreludeDialogueIO);
635 END_REGISTER_CCS()
636
637 START_REGISTER_PRELUDE(_regPreludeGlaMisc);
638 END_REGISTER_CCS()
639
640 START_REGISTER_PRELUDE(_regPreludeGlaST);
641 END_REGISTER_CCS()
642
643 START_REGISTER_PRELUDE(_regPreludeIOError);
644 END_REGISTER_CCS()
645
646 START_REGISTER_PRELUDE(_regPreludePS);
647 END_REGISTER_CCS()
648
649 START_REGISTER_PRELUDE(_regPreludePrimIO);
650 END_REGISTER_CCS()
651
652 START_REGISTER_PRELUDE(_regPreludeStdIO);
653 END_REGISTER_CCS()
654 #endif
655 \end{code}