[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: 65816 Loop Question



    Thank you for the answer.  It does make sense that I understood
completely.

    You use two words -- Direct and Indirect.  Indirect is like pointer.

    If we say -- Direct Direct, it can mean to access inside 64KB.

    If we say -- Direct Indirect, it can mean to access inside and outside
64KB.  It looks neat.

    It is possible to program MS Windows 3.1 with 16 bits on Apple IIgs from
scratch by using 65816 instead of x86 microprocessor.  It means to replace
GS/OS routine functions and subroutine functions in bank $FC-$FF.  Apple
IIgs might have new operating system however it does not look like real
emulator because we have to reinvent from scratch!  It is what I am doing my
projects.  Interesting...

--
Yours Truly,

Bryan Parkoff
BParkoff@satx.rr.com
"David Empson" <dempson@actrix.gen.nz> wrote in message
1faf9wz.1jevr4pvxu9djN%dempson@actrix.gen.nz">news:1faf9wz.1jevr4pvxu9djN%dempson@actrix.gen.nz...
> Bryan Parkoff <BParkoff@satx.rr.com> wrote:
>
> > 65816 Loop Question
> >
> >     I understand that 6502 and/or 65C02 can only limit up to 64KB.  The
loop
> > can only cycle from $0000 through $FFFF.  If it tries to cycle from
$FF00
> > through $1000F, it will only cycle from $FF00 through $000F.
>
> That isn't even a valid concept on the 6502/65C02.  The CPU's address
> bus is 16 bits, which means it is only able to directly address memory
> locations in the range $0000 to $FFFF (64 KB).
>
> Bank switching operates by replacing portions of the 64 KB address
> space, but as you say, that is a different matter.
>
> >     Do 65816 have access to cycle the loop beyond 64KB without needing
to
> > use bank address switching?
>
> It depends on the CPU mode settings and the addressing mode of the
> instruction used.
>
> The CPU can be operating in emulation or native mode.
>
> In emulation mode, it behaves like a 65C02 with some extra registers and
> instructions, and somewhat limited ability to use memory beyond 64 KB
> (e.g. you cannot execute code outside bank 0 unless interrupts are
> disabled, but accessing data is no problem).  The X and Y index
> registers are stuck at 8 bits in emulation mode.
>
> In native mode, the full address space of the CPU (16 MB) can be used
> safely for code, and the X and Y index registers can be set to either 8
> or 16 bits.
>
> The relevant addressing modes are as follows, with examples in each
> case.
>
> LDA $nn,X      Direct Indexed
> LDA $nnnn,X    Absolute Indexed
> LDA $nnnnnn,X  Absolute Long Indexed
> LDA ($nn),Y    Direct Indirect Indexed (post-indexed indirect)
> LDA ($nn,X)    Direct Indexed Indirect (pre-indexed indirect)
> LDA [$nn],Y    Direct Indirect Long Indexed (post-indexed indirect long)
>
> The "Absolute long indexed" and "Direct indirect long indexed" modes
> only exist on the 65816.
>
> All "direct" modes are known as "zero page" modes on the 6502/65C02.  On
> the 65816, the 16-bit D register is used to set the base address of the
> direct page, so it can start anywhere within the first 64 KB of the 16
> MB address space.  This means that the D register is added at some point
> in the calculation of the effective address.  If the D register is set
> to zero, then the direct modes behave just like the zero page modes of
> the 65C02.
>
> All of the plain "indexed" modes (Direct Indexed, Absolute Indexed or
> Absolute Long Indexed) operate by adding an index register to the
> specified base address to determine the address to be accessed.
>
> The Direct Indirect Indexed mode operates by fetching the contents of
> two consecutive direct page locations, treating them as a 16-bit
> pointer, then adding the Y index register to form an absolute address
> which is to be accessed.
>
> The Direct Indexed Indirect mode operates by adding the X index register
> to the specified base address, fetching two consecutive direct page
> locations from that address, and using them as an absolute address which
> is to be accessed.
>
> The Direct Indirect Long Indexed mode operates by fetching the contents
> of three consecutive direct page locations, treating them as a 24-bit
> pointer, then adding the Y index register to form an absolute long
> address which is to be accessed.
>
> For all 'Direct' modes, the D register is added just before the contents
> of the direct page memory location is accessed, i.e. after adding the
> index register to the base address for 'Direct Indexed' and 'Direct
> Indexed Indirect' modes, or before fetching the pointer for 'Direct
> Indirect Indexed' and 'Direct Indirect Long Indexed' modes.
>
> Indexing on direct page addresses are limited in two ways:
>
> - The effective address of the direct page location is always limited to
> the first 64 KB.
>
> - If the CPU is running in emulation mode, the calculation of the direct
> page address is limited to 8 bits, i.e. only the 256 bytes starting at
> the D register can be accessed.  (If the D register is $FF01 or higher,
> the address calculation will also wrap around to $0000.)
>
> If the CPU is running in native mode, direct page indexing can
> potentially access the first 64 KB.
>
> Indexing on absolute addresses (including the Direct Indirect Indexed
> mode) uses the data bank register (B) to determine which bank is to be
> accessed.  This register is normally set to zero while in emulation
> mode, but this isn't required.
>
> In emulation mode, the absolute address calculation is limited to 16
> bits, so the address will wrap around within a 64 KB bank.
>
> In native mode, the absolute address calculation can cross the bank
> boundary.
>
> Indexing on absolute long addresses (including the Direct Indirect Long
> Indexed mode) is always able to cross a bank boundary.
>
> In summary:
>
> - If the CPU is running in emulation mode and you use 6502/65C02
> addressing modes, then you can only access 64 KB, just like the
> 6502/65C02.
>
> - If the CPU is running in native mode, you can cross the bank boundary
> for 'absolute indexed' and 'direct indirect indexed' modes.  Since X/Y
> can be set to 16 bits, this allows you to access up to 64 KB of data
> starting at a specified 24-bit base address, which must start within the
> current data bank.
>
> - If you use 65816 "long" addressing modes in either emulation or native
> mode, you can access the entire 16 MB address space and don't need to
> worry about bank boundaries.  You can only access 64 KB from a given
> base address, because the index registers are limited to 16 bits, but
> you can modify the base address as necessary.
>
> Code execution is always limited to the current 64 KB bank.  The only
> way to change banks is with a JML (long jump), JSL (long call) or RTL
> (long return).  Interrupts and RTI can also switch banks in native mode.
>
> > I would love to see that the cycle will execute from $00/F000 through
> > $02/A000.
>
> That particular example would be rather unwise, because bank 1 is the
> equivalent of IIe's auxiliary memory, so it has I/O locations in
> $01/C000-CFFF and has special rules for using $01/0000-$01/07FF and
> $01/D000-$01/FFFF (as well as some parts of the RAM in the
> $01/0800-$01/BFFF area).
>
> It is also worth noting that you must use the IIgs Memory Manager
> toolset if you want to make use of any RAM outside bank 0 and 1, so that
> you don't step on RAM being used by other software.
>
> In general, your application should not assume it can allocate specific
> memory addresses in banks 2 and higher - you should ask the memory
> manager for the amoount of memory you require without specifying the
> address, and then do any appropriate address calculations in software.
>
> If you are writing a native application (running under ProDOS-16 or
> GS/OS), then you also have to use the Memory Manager for banks 0 and 1.
>
> Assume you have requested a memory block which is $01B000 bytes in
> length, and the Memory Manager happens to allocate memory starting at
> $02F000 (through to $04AFFF), you would typically set up three direct
> page locations to hold the base address ($02F000) and use the direct
> indirect long indexed mode to access the memory.
>
> In this case, you would be able to access $02F000 through $03EFFF by
> simply incrementing the Y register from $0000 through to $FFFF.  I you
> wanted to access memory beyond this point, you would have to modify the
> pointer by adding one to its bank byte, then continuing with Y register
> values from $0000 through to $AFFF.
>
> e.g. the following code will clear a block of memory which is larger
> than 64 KB.  (This is the first Apple II code I've written for several
> years, so I might be a little rusty.)
>
> ClearMyHand:
>
> ; Need initial code to set up for using the Memory Manager, and passing
> ; parameters to the _NewHandle call in order to allocate memory.
> ; Assume this call has returned a handle, which has been stored in
> ; a 4-byte direct page variable called MyHand.  In addition, the amount
> ; of memory allocated has been stored in MyHandSize.
>
> ; The CPU is currently in native mode, with A and X/Y all set to 16-bit
> ; mode.
>
> ; Lock the handle so that the memory won't move
>
>            lda MyHand+2
>            pha
>            lda MyHand
>            pha
>            _HLock
>
> ; Dereference the handle to get a pointer to its base address
>
>            ldy #$0002
>            lda [MyHand],y
>            sta MyPtr+2
>            lda [MyHand]
>            sta MyPtr
>
> ; Set up the X register with the number of banks we need to clear
>
>            ldx MyHandSize+2
>            beq BanksDone
>
> ; Set up the Y register as the index into the bank, and A with the
> ; value to be stored.
>
>            ldy #$0000
>            tya
>
> ; Loop to clear each bank.  A is 16 bits, so Y is incremented by 2
> ; after each store.
>
> BankLoop:  sta [MyPtr],y
>            iny
>            iny
>            bne BankLoop
>
> ; Update the pointer for the next bank, and keep going if we have
> ; more banks to follow.
>
>            inc MyPtr+2
>            dex
>            bne BankLoop
>
> ; We've finished processing complete banks.  Now do the last partial
> ; bank, checking specially for an odd number of bytes.
>
> BanksDone: lda MyHandSize
>            lsr                ; A has number of words to clear
>            beq NoWords
>            php                ; Save the carry flag for later
>            tax                ; Set X to the number of words to clear
>            lda #$0000         ; Reinstate the zero value being stored
>
> WordLoop:  sta [MyPtr],y
>            iny
>            iny
>            dex
>            bne WordLoop
>            plp
>
> ; If carry is set, we have an odd number of bytes, so we have to
> ; set the accumulator to 8-bit mode for the last byte.
>
> NoWords:   bcc NoOddByte
>            lda #$0000         ; Reinstate the zero value being stored
>            sep #$40           ; Set the M flag (8 bit accumulator)
>            sta [MyPtr],y
>            rep #$40           ; Clear the M flag (16 bit accumulator)
> NoOddByte:
>
> ; Unlock the handle again
>
>            lda MyHand+2
>            pha
>            lda MyHand
>            pha
>            _HUnlock
>
> ; Done!
>            rts
>
> --
> David Empson
> dempson@actrix.gen.nz
>