9 - CPU Control

9.1 - RESET

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.

9.2 - NMI

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 will return from the interrupt with the registers as they were when the NMI occurred (unless you change a register value using PSYMON, of course).

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.

9.3 - IRQ

ReFLEX offers a facility to provide a fairly regular source of interrupts to the 6809's IRQ input.

Note: The emulator's version of FLEX is not at this point configured to respond to an IRQ, so you must turn off interrupts when FLEX or a FLEX utility command is running unless you have defined a service that will not be disturbed by operations within FLEX and the various utility commands FLEX runs. Remember that some UC's destroy memory in the $C100 area, and others run in low user memory. I would suggest using the higher areas for your IRQ service if you want it to be safe, or using the FLEX memend info and controls to move the end of memory down past your service. However, not all FLEX commands properly pay attention to memend! For this reason, I again suggest using high memory if you expect your IRQ service to run concurrently with FLEX. The $E800-$F37F range is ideal.

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.

9.3.1 - The IRQ Interrupt Mechanism

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
Note: The emulation of the 6522 VIAs is only complete to the degree required for the interrupt and graphics emulations to function.

Below are minimal interrupt service routines. To use them, follow this procedure:

  1. Call I_INIT
  2. Call I_ON
    • Interrupts begin now, I_SVC is called regularly. Go about your business in the main program until you are ready to stop interrupt servicing.
    • In sections of your code where you can't be disturbed, mask the interrupt by setting the "I" bit in the 6809's CC register. In that case, remember to unmask the interrupts again when its ok to do so.
  3. Call I_OFF. You can now change the interrupt service routines, if needed, or you can turn them back on by calling I_ON. Note that it is generally not sufficient to just mask the I bit in the condition codes; before returning to FLEX, call I_OFF. You don't want FLEX to jump into your custom IRQ service, generally speaking. The exception to that is, of course, things like print spooling (which is not implemented).
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
Keyboard Navigation
, Previous Page . Next Page t TOC i Index g Glossary

Valid HTML 4.01 Loose
 

This manual was generated with wtfm
wtfm uses aa_macro and SqLite
aa_macro uses python 2.7
Please consider supporting my Reflex efforts via a small PayPal donation.