SuperCPU Illuminated - Part 3
Well, so far we know how to recognize the SuperCPU and we also know that the 65816 has
Native and Emulation modes. We've also learned how to use 16 bit registers. In
this part of the tutorial, we'll show you some additional and more complex theories and
excercises.
Modes, Modes and More Modes
The SuperCPU turns the C64 into a super multi-mode machine. Since there aren't just
1 MHz and 20 MHz modes for the SuperCPU, but also several diverse optimization modes, you
can cut out the CPU, make only certian areas of memory available, and thusly speed up you
programm run time. Check to see which mode the SuperCPU is in (Turbo or normal).
Just so you don't forget these things, they are summarized again for you here: Table 1. All registers which must be described correspond to a
specific word, are write sensitive, and already know what to do when they are set.
Other than these, the processor has two modes: Native and Emulation. To switch
between them, there's a new flag: the E flag. In Native mode you can switch back and
forth between 8 bit and 16 bit memory modes. For this we have the commands REP and
SEP. The assembler must be divided then, according to bit width, because it needs to
know how to compile the code. Here's and overview: Table 2.
Other Vectors
In the last tutorial we always entered the command SEI before going into Native mode in
order to prevent an interrupt while the processor was working. If an interrupt were to
occur, the system would crash - but why? As we showed earlier, the jump vectors are
located in a different place in memory in Native mode, including those for the IRQ.
The interrupt routine was in ROM shortly before it had the opportunity to omit the favored
vector at $0314/$0315. The actual IRQ vector ist at $FFFE/$FFFF, to which the
processor always jumps when it gets and interrupt. The address $FF48, is a ROM
routine where the register and its status are saved and then examined to see if it is an
IRQ or BRK interrupt. Correspondingly, $0314/$0315 or $0316/$0317 will be branched out. In
the Native mode of the 65816, however, all the vectors are positioned somewhat
differently. The developers wanted to provide the option for the Emulation and
Native modes to be able to write some interrupt routines. Table 3
shows how the vectors are positioned.
Something New
There's something new here too. As you can see, the vector for the IRQ is located at
$FFEE/$FFEF in Native mode. The number combination $E5/$4C is located in ROM; this
will jump you to $4CE5 with an IRQ. Do you always have to put your IRQ routines
there? Of course not. It is possible, as was already stated, to protect
against IRQ's during the running of a program in Native mode.
This is also true when you switch to Native mode from WITHIN an IRQ routine, and then when
you switch back because no new IRQ's will be executed while the original one is being
executed - and if new ones do come, they must wait until the original is done. This
is the solution which you'd use most often when you want to enter demos or games in Native
routines, most of which will work inside the IRQ routine. If you want to use Native
mode in your main programs, however, the IRQ must be shut off. This isn't a problem
most of the time, because at 20 MHz and 16 bits the time that the IRQ is shut off is not
very long. But what if the IRQ is the next thing to be executed? In this case
the ROM must be deactivated and a new IRQ routine must be written, and the vector at
$FFEE/$FFEF must be in this routine. This raises a few questions: What
happens, for example, if at the moment of an IRQ, 16 bit mode is activated, but the IRQ
switches to 8 bit mode? These and other issues (how to put 16 bit words on a stack,
for example) will be dealt with in another part of this tutorial.
Top Cops
There are now some new interrupts available: for example the "COP"
interrupt. This interrupt exists to give control over to a COProcessor. There is a
special COP command which is followed by a number. So if a coprocessor were
available, you could communicate with it and give it a specific job to do. Nothing's
been heard about such a coprocessor, though. So are the COP command and the vector
belonging to it totally senseless? No, because why would a coprocessor have to be
there to take care of special jobs? You can also use the COP command to call
subroutines. A COP interrupt would be released, and the program counter would be
saved from the stack. From it you would get the parameter, execute a routine, and
switch back to the program with RTI (ReTurn from Interrupt)!
It's also striking that the Native mode has no reset vector. This means that the
65816 switches into 16 bit mode as soon as it recieves a reset signal, and then jumps to
the corresponding vector. For the BRK command (the command which erases this
interrupt) there is no vector in Emulation mode, because the of the existance of the Break
flag. It is no longer possible to check the Break flag in Native mode, nor is it
necessary, as there are some new vectors. ABORT deals with a better type of NMI - the
processor can recieve this signal from outside, carries out the current command, and then
branches out by way of the ABORT vector. The developers of cartridges like the
Action Replay surely would have loved it if the 6510 had such an interrupt!
More About 16 Bits
In order to make the memory and Index registers in 8 and 16 bit totally independent from
one another there are several diverse combination possibilities. It's interesting,
at the very least, to work with commands like TAX, TAY, TXA, TYA, or TXS, TSX.
Just like the load commands (LDA, LDX, LDY), the transfer commands affect the N (Negative)
and the Z (Zero) flags. (TXS has no affect on the flags, so you don't need to check
up on it.)
But what happens when a TAY is executed if the memory is in 16 bit mode and the Index
register size is 8 bit? The first rule about this, is that the type of
transfer is always dependent on the destination register. In this case, only the
lower 8 bits of the 16 bit memory will be transfered to the Y register. A second
rule is as follows: as long as the Index registers are set to 8 bit, the Highbyte is
always 0, until you switch back to 16 bit mode. Then the 8 bit contains the
Lowbyte of the Index register, which it had before. Listing
3.1 shows what happens. In this example, the word which is at the address
labeled DATA2 will be $0033 - only the lower 8 bits will be transferred, because the
Highbyte is set to 0.
Transfers
Memory works differently. When the memory's width is switched from 16 to 8 bits, the
former Highbyte becomes "hidden" memory B. You can't get at this memory
again without somehow changing the mode, and entering the command XBA (eXchange B and A). Listing 3.2 shows the behavior of the memory. After
execution, the word $7F33 or $33, $7F in Lowbyte/Highbyte succession are located in memory
at Result and Result+1. In other words: the Highbyte of memory, $7F, stays in 8 bit mode
despite the mode switching.
If you try to transfer a 16 bit Index register to memory while it is being switched to 8
bit, Listing 3.3 will show you what happens. The
result is $33FF, and it's clear that the inactive Highbyte of memory stays totally
undisturbed - the Highbyte of the Y register will not be transferred. The rule that
a transfer is always directed to the destination register is valid here as well - the
hidden B memory is not changed.
If you transfer in the other direction, that is, from 8 bit to 16 bit registers, you must
be clear about what happens. If you transfer the memory in 8 bit mode to an Index
register which is in 16 bit mode, both 8 bit memories (i.e. the hidden memory as the
Highbyte) will be transferred! The result, saved as Result in Listing 3.4 is $7FFF, and it's evident that not only the 8
bit memory A is transferred to the Lowbyte of the 16 bit Index register, but the hidden B
memory is also transferred (and with it the Highbyte of the Index register). This
means that we can generate a 16 bit index with the memory in 8 bit mode, and transfer the
entire byte index, byte by byte, to the Index register without having to switch the memory
to 16 bit mode first. But be careful: You shouldn't transfer an unknown Highbyte (B
memory) to an Index register!
When transferring an 8 bit register to 16 bit memory, the contents of the Index register
go to the Lowbyte in memory, while the Highbyte will be set to 0. This corresponds
to the fact that when you switch the Index registers from 8 to 16 bit, the Highbyte gets
set to 0. In Listing 3.5 a result of $0033 is
yielded.
Now a few more words about the transfer of X to the stackpointer (the TXS command) and
the other direction as well (TSX). The stackpointer of the 65815 is 16 bit, which
means that the stack doesn't have to inevitably be located at $0100! It can be
anywhere within the 64K, and can of course be larger than 256 bytes. As a result of
this, the transfer correctly gets to its destination. If you transfer the 16 bit
stackpointer to an 8 bit index register, the lowbyte is now there.
It won't disturb anything else if you leave the stack at a default location of $0100.
If you want to put the stack somewhere else or, for example, use it for an
interrupt routine, you must create a new stack. This only works in Native mode,
though! You just switch the Index registers to 16 bit mode, load the X register with
a 16 bit word (the new address of the stackpointer should be presented, and then a TXS is
executed), and the stack is located somewhere else. As usual, you should be aware of
the processor mode. If you were to switch back to Emulation mode, the Highbyte would
get set to $01 again!
So, to conclude, here's a little surprise: As well as the known transfer commands
the 65816 offers the commands TXY and TYX, which you can use to directly transfer words
back and forth between the Index registers, without having to transfer to memory!
The longer you use and play around with 16 bit mode, you will understand how much power
there is in the SuperCPU. As an old 6502 miser you probably never would have thought
about things like stack transfers from 16 to 8 bit. But now we know the background
of the processor, which will be helpful not only when programming but also when debugging.
The information from the second part of this tutorial has been strengthened
and expanded on; play around and experiment with the power! Next time, we'll further
explore some great abilities of the 65816 processor!
[Table 1]---> Complete V2 SuperCPU Memory Locations Register Function $D074 VIC Bank 2 Optimisation-Mode, only $8000-$C000 is mirrored $D075 VIC Bank 1 Optimisation-Mode, only $4000-$8000 is mirrored $D076 Screen RAM Optimisation-Mode, only $0400-$0800 is mirrored $D077 NO Optimisation, all memory is mirrored (default) $D07A switch to 1 MHz via software $D07B switch to 20 MHz via software $D07E fade in SuperCPU-Register in I/O region (for Optimisation) $D07F fade out SuperCPU-Register in I/O region (for Optimisation) $D0B8 Bit 6 =1: CPU is in 1MHz mode =0: CPU is in Turbo mode $D0BC Bit 7 =1: SuperCPU present =0: normal C64
[Table 2]turn Native mode on: CLC XCE turn Emulation mode on: SEC XCE 16 Bit memory: REP #%00100000 or REP #$20 8 Bit memory: SEP #%00100000 or SEP #$20 16 Bit Index register: REP #%00010000 or REP #$10 8 Bit Index register: REP #%00010000 or SEP #$10 16 Bit memory and Index register: REP #%00110000 or REP #$30 8 Bit memory and Index register: SEP #%00110000 or SEP #$30 Assembler should assemble 16 Bit A: £al (Memory Long) Assembler should assemble 16 Bit X/Y: £rl (Register Long) Assembler should assemble 8 Bit A: £as (Memory Short) Assembler should assemble 8 Bit X/Y: £rs (Register Short) Only for F8-Assblaster !
[Table 3]Vector Emulation Mode Native Mode IRQ $FFFE/$FFFF $FFEE/$FFEF RESET $FFFC/$FFFD - NMI $FFFA/$FFFB $FFEA/$FFEB ABORT $FFF8/$FFF9 $FFE8/$FFE9 BRK - $FFE6/$FFE7 COP $FFF4/$FFF5 $FFE4/$FFE5
© 1999 GO64 Redax & Count Zero/SCS*TRC for all HTML Stuff