1.5
Nintendo 64 Developers Newsletters will be published periodically, as needed. These feature software and hardware system anomalies, which have been discovered, and their solutions and/or work-arounds. Development tips will also be included.
There is no RESET switch on the current emulation boards, but a pseudo-NMI can be generated by executing a RESET program (see Nintendo 64 Developer News 1.2, "Tip: Handling Console Reset").
In addition, the NMI wait time on current emulation boards is 0.5 seconds or more (around several seconds).
Therefore, if processing in the RCP is not terminated after the pre-NMI is generated, processing in the RCP will continue to be executed even after a RESET. In the worst case, this will have a detrimental effect on the CPU's boot sequence, inevitably causing the CPU to hang up. In order to avoid this situation, it is necessary to terminate any processing being executed in the RCP after a pre-NMI has been generated.
Each thread senses the generation of a pre-NMI by means of an OS_EVENT_PRENMI message, and the necessary processing is performed.
static void gameproc (void *argv) { . . . while (1) { . . . switch (msg->gen.type) { . . . if (pendingGFX < 2) { createGfxTask(&glnfo[drawbuffer]); pendingGFX++; drawbuffer ^=1; /* switch the drawbuffer */ } . . . case (OS_SC_PRE_NMI_MSG): /* stop creation of graphics tasks */ pendingGFX += 2; break;
By not creating any new GFX tasks after the pre-NMI is generated, the drawing of new screens can be stopped, and the screen can be interrupted.
In addition, by making the pre-NMI processing portion as follows:
case (OS_SC_PRE_NMI_MSG): /* stop creation of graphics tasks */ pendingGFX += 2; osViBlack(TRUE); break;
The screen can be deleted (cleared to black) at the same time that the pre-NMI is generated, after resetting Yscale value to 1. Other processing is also possible in which the screen is gradually cleared by decreasing the brightness of the screen in the step-wise fashion, etc. All of this screen clearing processing is to avoid giving the user an uneasy feeling and, at the same time, it is necessary on the system level to stop the execution of tasks in the RCP by not creating any new tasks (the pendingGFX +=2 line in the above sample corresponds with this).
static void _amMain (void *arg) { . . . while (!done) { . . . switch (msg->gen.type) { . . . case (OS_SC_PRE_NMI_MSG): /* what should we really do here? quit? ramp down volume? */ alSeqpStop(seqp) ; alSeqpDelete(seqp) ; done = 1; break ; . . . } } alClose(&_am.g); }
It is possible to stop sound in the same way as graphics by not performing any new processing after generating a pre-NMI. In the above case, the procedure
alSeqpStop -> alSeqpDeletewas used because a standard MIDI sequence player is being used, but if a compact MIDI player is being used, sound would be stopped using the procedure
alCSPStop -> alCSPDeletewhile if synthesizer voice is being used by a sound effect, the sound effect would be stopped using the procedure
alStopVoice -> alSynDelete(however, alSynDelete cannot be implemented at the current time).
Caution is required when using alSeqpDelete and alCSPDelete, since there is a system anomaly in the N64 OS up to revision 2.0e which makes it possible that the interrupt would continue to be masked. Because of this, either use patch 1.01, or use OS 2.0g or later, when using these functions.
Processing is also possible which gradually diminishes the sound in the same way as the screen by decreasing the volume in a stepwise fashion. However, stop the execution of new audio tasks when the volume reaches 0.