Selecting the Execute/Reset menu item causes the 6809 to pick up the vector from the ROM at $FFFE and enter the PSYMON monitor in ROM. No register information is retained by the 6809's RESET operation, so if RESET is asserted in the midst of a program, there is generally no way to recover. The single exception to this is if RESET is asserted when the FLEX prompt (+++) is showing, typing W will "warmstart" FLEX without any harm done, assuming you have not modified anything that FLEX depends on using PSYMON's low-level tools such as memory examine and change.
If after a RESET, W fails to properly restart FLEX, try this: Execute RESET again, and type...
G CD00
...at the monitor prompt (-->). This coldstarts FLEX, re-initializing various internal FLEX states such as the output character routines. If that doesn't work, you'll need to restart the emulator to get FLEX going again. At this point, I would not advise FLUSHing the VDisks, because if FLEX is unstable, you don't know what went on with them, either.
A good rule is not to RESET the CPU when any disk activity is occurring.
Selecting the Execute/NMI menu item causes the 6809 to set the "E" bit in the condition codes, stack all of the CPU registers, and pick up the vector from the ROM at $FFFC. This enters the PSYMON monitor NMI service, which proceeds to dump the CPU registers and display a command prompt. At this time you can use any monitor service to examine or change program memory and/or CPU registers. When you are ready to restart, typing G
PSYMON allows you to change the NMI vector indirectly. You can't actually change the value in the ROM at $FFFC, however PSYMON's NMI service picks up a jump vector from $F3FC, which is user RAM and may be modified. Because of this, you can create your own custom NMI service, if you are so inclined. Personally, I use NMI for debugging. PSYMON's classic "dump-the-registers & let-me-meddle" service is ideal for that, and if your needs are similar to mine you may never need to make a custom NMI service at all. However, if you need to, you definitely can.
To see how this works, use the MON command to enter PSYMON from the FLEX prompt, change $F3FC from $FE8E, which is the address of the normal interrupt service routine in PSYMON, to $0100. Then put an RTI instruction ($3B) at $0100, and type W to restart FLEX. Normal command processing is in effect. Now select NMI from the Execute menu, and unlike previously, nothing will appear to happen. But something did — the NMI was taken, it headed off to $0100, where it encountered the return from interrupt instruction, and went right back to what it was doing.
At this point, you'll want to either use the Mon command again, which causes PSYMON to reset the NMI vector, or use RESET and go back and change the value at $F3FC from $0100 back to $FE8E so that PSYMON's NMI service will work again. If you don't do this, and cause another NMI after $0100 has been written over by any application, you're going to experience a 6809 crash, just like the real thing. You'll probably have to use the Execute/Hard Restart menu selection to get going again.
ReFLEX offers a facility to provide a fairly regular source of interrupts to the 6809's IRQ input.
The interrupt rate may be set via the Execute/IRQ Timing menu item, which specifies how many 6809 instructions are to go by (multiplied by 20) before an interrupt is generated.
The interrupt capability is not based upon a timer, as Win95 offers only a timer with a minimum interval of 55 mS and an interval granularity of 55 mS. The "count of instructions" interrupt mechanism that is implemented for the emulator offers an effective granularity of 20 instructions, or about 100 uS for a 1 MHz equivalent machine.
There's a catch, though (isn't there always?) Because the emulator runs faster or slower depending on the speed of the Host computer, the settings for a particular interrupt rate will vary across machines. For instance, the game RB.CMD that I supply as a graphics demonstration was designed around a 16.66 ms interrupt. I've provided a default interrupt rate (1200*) that approximates this for my 133 MHz Micron Pentium. On your machine, the game will almost certainly run too fast, or too slow - and you'll need to adjust the interrupt rate accordingly. You can get "in the ballpark" just by using a ratio between my CPU speed and yours; for instance, if you have a P166, then the ratio of 166/133=1.25 applies, and so your setting would be 1.25*1200=1497.
* | As a point of interest, the average 6809 instruction length at 1 MHz is 4.5 uS (that's an average of all the 6809 instruction cycle times, there's no other way to get even close because instruction usage varies in every program). On a Micron P133, I have to use a value of 1200 to set my interrupt rate to 16.666666 mS. This rate gives an approximate instruction execution time which is .6944 uS per instruction (1.44 MHz average instruction execution rate), or 24,000 instructions in 16.666666 mS. That's about .1543 uS per clock cycle (.6944/4.5), which is an instruction clock of 6.48 MHz (1/.1543 uS), and a chip clock of 25.9 MHz (4 x 6.48 MHz). That's your basic fast 6809! |
The application is not multithreaded for the emulation code, so multiple processors shouldn't affect the timing. MMX CPUs likewise shouldn't affect it a great deal as the emulation deals almost exclusively with 8 and 16 bit data items under a large memory model.
What will affect the timing are differences in memory architecture, cache mechanisms, available memory, and for operations that use graphics or large amounts of text manipulation, the display adaptor. If you're looking for a particular interrupt rate, you should be able to get close but you'll have to create a test program, determine the approximate number of instructions per second your machine runs the emulation at, and use that number to set the Execute/IRQ Timing value accordingly.
There is a hidden benefit here, and that is that with an interrupt rate like this, as the emulation slows down due to system factors, the interrupt rate slows in exact proportion, so your program won't be overrun (or at least, it's no more likely to do so that it would be in a real machine.
Interrupts are managed by an emulated 6522 VIA, using its IERG, IFRG and T2CL registers. This is essentially similar to managing the VIA's T2 timer in real hardware, with the exception that the actual timer value is set from the Execute/IRQ Timing menu item, which is necessary because of the extreme difference in Host processor speeds and the lack of any but the most primitive timer facilities in Win95.
A very serious consequence of this is that you cannot vary the IRQ rate under program control.
The following table describes the various actions available to your programs to control IRQ interrupts:
Access | Item | Program Action | Effect |
---|---|---|---|
$E04E | VIA2+IERG | Write $40 | T2 |
$E04E | VIA2+IERG | Write $C0 | T2 Interrupt On |
$E04D | VIA2+IFRG | Read: b7=IRQ, b6=T2 flag | 1 = T2 timer fired |
$E048 | VIA2+T2CL | Read | Turn off T2 flag |
$F3F8 | PSYMON IRQ Vector | Write address of IRQ service | Link your IRQ service |
CC b4 | CPU IRQ Bit | Set | Interrupts masked |
CC b4 | CPU IRQ Bit | Clear | Interrupts enabled |
There are two VIA's. VIA 1 is at $E030-$E03F, VIA 2 is at $E040-$E04F.
Address | Register | Function |
---|---|---|
$0 | DATB | B data register in and out |
$1 | DATA | A data register in and out |
$2 | DDRB | B data direction register |
$3 | DDRA | A data direction register |
$4 | T1CL | Timer 1 counter low byte |
$5 | T1CH | Timer 1 counter high byte |
$6 | T1LL | Timer 1 latch low byte |
$7 | T1LH | Timer 1 latch high byte |
$8 | T2CL | Timer 2 counter low byte |
$9 | T2CH | Timer 2 counter high byte |
$A | SFTR | Shift register |
$B | ACRG | Auxiliary control register |
$C | PCRG | Peripheral control register |
$D | IFRG | Interrupt flag register |
$E | IERG | Interrupt enable register |
$F | DXTA | A data output only, no handshake |
Below are minimal interrupt service routines. To use them, follow this procedure:
PSYIRQ EQU $F3F8 VIA2 EQU $E040 IERG EQU $E T2CL EQU $8 IN_BIT EQU $10 IY_MSK EQU 255-IN_BIT I_INIT PSHS D SAVE REGS USED LDD #I_SVC POINT TO INTERRUPT SERVICE STD >PSYIRQ INSTALL VECTOR TO PSYMON PULS D,PC RETURN TO CALLER, REGS INTACT I_ON PSHS A SAVE REGS USED LDA #%11000000 TURN ON IS B7=1, T2 FLAG IS B6 STA >VIA2+IERG HIT VIA, TURN T2 INTERRUPTS ON ANDCC #IY_MSK ALLOW IRQ'S PULS A,PC RESTORE & EXIT I_OFF PSHS A SAVE REGS USED ORCC #IN_BIT DISALLOW IRQ'S LDA #%01000000 TURN OFF IS B7=0, T2 FLAG IS B6 STA >VIA2+IERG HIT VIA, TURN T2 INTERRUPTS OFF LDA >VIA2+T2CL MAKE SURE LAST POTENTIAL IRQ IS ACK'ED PULS A,PC RESTORE & RETURN * * REMEMBER: THE IRQ INTERRUPT STACKS EVERYTHING, SO YOU'LL * NEED TO ALWAYS HAVE ROOM FOR ALL THE CPU * REGISTERS ON THE STACK WHEN USING IRQ SERVICING, * PLUS ANY REGISTERS YOU SAVE LOCALLY ON THE STACK * WITHIN THE IRQ SERVICE. * I_SVC LDA >VIA2+T2CL "ACK" INTERRUPT & DROP T2 IRQ FLAG * * HERE IS WHERE YOU INSERT YOUR CUSTOM INTERRUPT CODE * RTI RETURN FROM IRQ SERVICE
Please consider supporting my Reflex efforts via a small PayPal donation. |