Jump to content
IGNORED

Mirrored memory


jbs30000

Recommended Posts

In the case of the RAM, the mirroring let them use the same 128 bytes as both Zero Page RAM and Stack RAM.

 

Zero Page is anything with a $00xx address while the stack is $01xx. Stack usage starts at $01ff and works its way down, which is why the 128 bytes are in the latter half of the page.

Link to comment
Share on other sites

Thank you all very much. And I see my question was answered fully in your thread jdrose. I'm kind of embarrassed now. Oops.

Why? It's not like the other thread had "mirror" in its title! :) And since this new thread is about mirrored memory, it might as well contain an answer, too.

 

THE 6507 PROCESSOR

 

The 6507 chip has only 13 address pins-- A0 through A12-- so the usable addresses are an 8K block from $0000 through $1FFF. Internally the 6507 still uses 16-bit addresses, but since there are no pins for A13 through A15, any attempt to access $2000 through $FFFF will actually access $0000 through $1FFF:

 

$E000 - $FFFF = 8K mirror of $0000 - $1FFF

$C000 - $DFFF = 8K mirror of $0000 - $1FFF

$A000 - $BFFF = 8K mirror of $0000 - $1FFF

$8000 - $9FFF = 8K mirror of $0000 - $1FFF

$6000 - $7FFF = 8K mirror of $0000 - $1FFF

$4000 - $5FFF = 8K mirror of $0000 - $1FFF

$2000 - $3FFF = 8K mirror of $0000 - $1FFF

$0000 - $1FFF = 8K of addressable memory

 

The cartridge slot, 6532 RIOT chip, and TIA chip have addresses within the 8K memory block at $0000 - $1FFF, so they have mirrors in the other 8K memory blocks. For simplicity, only mirrors within $0000 - $1FFF will be listed below, with the others being understood.

 

THE CARTRIDGE SLOT

 

The 2600's 4K cartridge slot has 12 address lines-- A0 through A11. A12 acts as a chip select and is wired as 1, so the addresses are %xxx1 ???? ???? ????, where "x" is "don't care" and "?" can be 0 or 1, giving addresses of $1000 - $1FFF.

 

If a cartridge has only 2K, then A11 isn't connected, in which case the addresses are %xxx1 x??? ???? ????:

 

$1800 - $1FFF = 2K mirror of $1000 - $17FF

$1000 - $17FF = 2K of addressable ROM

 

If a cartridge includes the 128-byte SARA chip for extra RAM, the SARA chip uses A7 for the R/W line:

 

$1100 - $1FFF = 3.75K of addressable ROM

$1080 - $10FF = 128 bytes of SARA RAM read addresses

$1000 - $107F = 128 bytes of SARA RAM write addresses

 

There are other cartridge formats that add extra RAM, but I won't try to list their mappings.

 

THE 6532 RIOT CHIP

 

The 6532 RIOT chip has only seven (7) address pins-- A0 through A6. The chip selects are connected to A12 (which must be 0) and A7 (which must be 1). There is also a RAM select, which is connected to A9.

 

To read or write the RIOT RAM, the RAM select (A9) must be 0, giving addresses of %xxx0 xx0x 1??? ????:

 

$0D80 - $0DFF = mirror of the RIOT RAM

$0C80 - $0CFF = mirror of the RIOT RAM

$0980 - $09FF = mirror of the RIOT RAM

$0880 - $08FF = mirror of the RIOT RAM

$0580 - $05FF = mirror of the RIOT RAM

$0480 - $04FF = mirror of the RIOT RAM

$0180 - $01FF = mirror of the RIOT RAM (used by the 6507 for its stack memory)

$0080 - $00FF = 128 bytes of RIOT RAM

 

To access the RIOT's I/O or timer functions, the RAM select (A9) must be 1, theoretically giving addresses of %xxx0 xx1x 1??? ????. However, the RIOT's I/O and timer functions don't use all seven address pins.

 

To access the I/O functions, A2 must be 0, and only A0 and A1 (and A2) are used for addresses, so the I/O addresses are %xxx0 xx1x 1xxx x0??:

 

$0Fxx, $0Exx, $0Bxx, $0Axx, $07xx, $06xx, $03xx = same mirrors as $02xx shown below

$02F8 - $02FB = mirror of $0280 - $0283

$02F0 - $02F3 = mirror of $0280 - $0283

$02E8 - $02EB = mirror of $0280 - $0283

$02E0 - $02E3 = mirror of $0280 - $0283

$02D8 - $02DB = mirror of $0280 - $0283

$02D0 - $02D3 = mirror of $0280 - $0283

$02C8 - $02CB = mirror of $0280 - $0283

$02C0 - $02C3 = mirror of $0280 - $0283

$02B8 - $02BB = mirror of $0280 - $0283

$02B0 - $02B3 = mirror of $0280 - $0283

$02A8 - $02AB = mirror of $0280 - $0283

$02A0 - $02A3 = mirror of $0280 - $0283

$0298 - $029B = mirror of $0280 - $0283

$0290 - $0293 = mirror of $0280 - $0283

$0288 - $028B = mirror of $0280 - $0283

$0283 = data-direction control for I/O register B

$0282 = I/O register B

$0281 = data-direction control for I/O register A

$0280 = I/O register A

 

To access the timer functions, A2 must be 1, and only A0, A1, A3, and A4 (and A2) are used for addresses-- although A1, A3, and A4 aren't always used.

 

To set (write) the timer, A4 must be 1, A3 enables or disables the timer interrupt, and A0 and A1 select the timer interval, so the addresses are %xxx0 xx1x 1xx1 ?1??:

 

$0Fxx, $0Exx, $0Bxx, $0Axx, $07xx, $06xx, $03xx = same mirrors as $02xx shown below

$02FC - $02FF = mirror of $029C - $029F

$02F4 - $02F7 = mirror of $0294 - $0297

$02DC - $02DF = mirror of $029C - $029F

$02D4 - $02D7 = mirror of $0294 - $0297

$02BC - $02BF = mirror of $029C - $029F

$02B4 - $02B7 = mirror of $0294 - $0297

$029F = enable the timer interrupt and set the timer using the 1024-cycle interval

$029E = enable the timer interrupt and set the timer using the 64-cycle interval

$029D = enable the timer interrupt and set the timer using the 8-cycle interval

$029C = enable the timer interrupt and set the timer using the 1-cycle interval

$0297 = disable the timer interrupt and set the timer using the 1024-cycle interval

$0296 = disable the timer interrupt and set the timer using the 64-cycle interval

$0295 = disable the timer interrupt and set the timer using the 8-cycle interval

$0294 = disable the timer interrupt and set the timer using the 1-cycle interval

 

To read the timer, A0 must be 0, A3 enables or disables the timer interrupt, and A1 and A4 aren't used, so the addresses are %xxx0 xx1x 1xxx ?1x0:

 

$0Fxx, $0Exx, $0Bxx, $0Axx, $07xx, $06xx, $03xx = same mirrors as $02xx shown below

$02Ax - $02Fx = same mirrors as $029x shown below

$029E, $029C, $0296, $0294 = mirrors of $028E, $028C, $0286, and $0284

$028E = mirror of $028C

$028C = enable the timer interrupt and read the timer

$0286 = mirror of $0284

$0284 = disable the timer interrupt and read the timer

 

To read the timer interrupt flag and PA7 interrupt flag, A0 must be 1, and A1, A3, and A4 aren't used, so the addresses are %xxx0 xx1x 1xxx x1x1:

 

$0Fxx, $0Exx, $0Bxx, $0Axx, $07xx, $06xx, $03xx = same mirrors as $02xx shown below

$029x - $02Fx = same mirrors as $028x shown below

$028F, $028D, $0287 = mirrors of $0285

$0285 = read the interrupt flags

 

To set (write) the PA7 edge-detect control, A4 must be 0, A0 selects positive or negative edge-detect, A1 enables or disables the PA7 interrupt, and A3 isn't used, so the addresses are %xxx0 xx1x 1xx0 x1??:

 

$0Fxx, $0Exx, $0Bxx, $0Axx, $07xx, $06xx, $03xx = same mirrors as $02xx shown below

$02Ax, $02Cx, $02Ex = same mirrors as $028x shown below

$028C - $028F = mirrors of $0284 - $0287

$0287 = enable the PA7 interrupt and select positive edge-detect

$0286 = enable the PA7 interrupt and select negative edge-detect

$0285 = disable the PA7 interrupt and select positive edge-detect

$0284 = disable the PA7 interrupt and select negative edge-detect

 

As seen above, the RIOT's mirrors are rather complex. Where any mirrors seem to conflict with other mirrors, the R/W and RAM select lines determine which mirrors will be in effect.

 

THE TIA CHIP

 

The TIA chip has only six (6) address pins-- A0 through A5. The chip selects are connected to A12 (which must be 0) and A7 (which must be 0).

 

The TIA's write registers use all six address pins, so the addresses are %xxx0 xxxx 0x?? ????:

 

$01xx - $0Fxx = same mirrors as $00xx shown below

$0040 - $007F = mirror of $0000 - $003F

$002D - $003F = not used

$002C = CXCLR (clear collision latches)

$002B = HMCLR (clear horizontal motion registers)

$002A = HMOVE (apply horizontal motion)

$0029 = RESMP1 (reset missile 1 to player 1)

$0028 = RESMP0 (reset missile 0 to player 0)

$0027 = VDELBL (vertical delay ball)

$0026 = VDELP1 (vertical delay player 1)

$0025 = VDELP0 (vertical delay player 0)

$0024 = HMBL (horizontal motion ball)

$0023 = HMM1 (horizontal motion missile 1)

$0022 = HMM0 (horizontal motion missile 0)

$0021 = HMP1 (horizontal motion player 1)

$0020 = HMP0 (horizontal motion player 0)

$001F = ENABL (enable ball graphics)

$001E = ENAM1 (enable missile 1 graphics)

$001D = ENAM0 (enable missile 0 graphics)

$001C = GRP1 (graphics player 1)

$001B = GRP0 (graphics player 0)

$001A = AUDV1 (audio volume 1)

$0019 = AUDV0 (audio volume 0)

$0018 = AUDF1 (audio frequency 1)

$0017 = AUDF0 (audio frequency 0)

$0016 = AUDC1 (audio control 1)

$0015 = AUDC0 (audio control 0)

$0014 = RESBL (reset ball)

$0013 = RESM1 (reset missile 1)

$0012 = RESM0 (reset missile 0)

$0011 = RESP1 (reset player 1)

$0010 = RESP0 (reset player 0)

$000F = PF2 (playfield register byte 2)

$000E = PF1 (playfield register byte 1)

$000D = PF0 (playfield register byte 0)

$000C = REFP1 (reflect player 1)

$000B = REFP0 (reflect player 0)

$000A = CTRLPF (control playfield ball size and reflect)

$0009 = COLUBK (color-lum background)

$0008 = COLUPF (color-lum playfield)

$0007 = COLUP1 (color-lum player 1)

$0006 = COLUP0 (color-lum player 0)

$0005 = NUSIZ1 (number-size player-missile 1)

$0004 = NUSIZ0 (number-size player-missile 0)

$0003 = RSYNC (reset horizontal sync counter)

$0002 = WSYNC (wait for leading edge of horizontal blank)

$0001 = VBLANK (vertical blank set-clear)

$0000 = VSYNC (vertical sync set-clear)

 

The TIA's read registers do not use A4 and A5, so the addresses are %xxx0 xxxx 0xxx ????:

 

$01xx - $0Fxx = same mirrors as $00xx shown below

$001x - $007x = mirrors of $0000 - $000F

$000E - $000F = not used

$000D = INPT5 (input port 5, trigger 1)

$000C = INPT4 (input port 4, trigger 0)

$000B = INPT3 (input port 3, pot 3)

$000A = INPT2 (input port 2, pot 2)

$0009 = INPT1 (input port 1, pot 1)

$0008 = INPT0 (input port 0, pot 0)

$0007 = CXPPMM (collision of players and missiles)

$0006 = CXBLPF (collision of ball with playfield)

$0005 = CXM1FB (collision of missile 1 with playfield-ball)

$0004 = CXM0FB (collision of missile 0 with playfield-ball)

$0003 = CXP1FB (collision of player 1 with playfield-ball)

$0002 = CXP0FB (collision of player 0 with playfield-ball)

$0001 = CXM1P (collision of missile 1 with players)

$0000 = CXM0P (collision of missile 0 with players)

 

As with the RIOT mirrors, some TIA mirrors seem to conflict, but the R/W line determines which mirrors will be in effect.

  • Like 4
Link to comment
Share on other sites

Ouch, I think my head exploded trying to read that. :o .

 

Let me ask two questions that may help me understand better.

  1. Does a change in one location make a change in all the mirror locations (including the original if you change a mirror value)?
  2. Is only one location active at a time, or is the original and all its mirrors active at the same time?

Link to comment
Share on other sites

  1. Does a change in one location make a change in all the mirror locations (including the original if you change a mirror value)?
  2. Is only one location active at a time, or is the original and all its mirrors active at the same time?

There's only one physical location which responds to different addresses because the value of some of the address bits is ignored. So changes affect all mirrors.

I use these documents (by Chris Wilkson) as reference for the 2600 memory map:

mem_map_1.txt

mem_map_2.txt

riot_map.txt

tia_map.txt

  • Like 1
Link to comment
Share on other sites

I know my lengthy post was overkill, but my main reason for wanting to post all that was because I've never seen a detailed description of the RIOT's mapping. That is, the datasheets for the 6532 do show which address lines are used for the different functions, but I haven't seen any 2600-specific documents that show what the different RIOT mirrors are on the 2600, aside from listing blocks of memory and saying they're mirrors of some other block of memory. But those maps don't account for the address pins that get ignored by the different RIOT functions, so they're a bit misleading.

 

One thing to note is that "mirror" in this case isn't the same as how it's defined in other situations. "Mirror address" and "shadow address" often refer to different physical memory locations that contain the same values as some other memory location, but in this case the mirror addresses aren't different locations-- they actually access the same location because of the missing or ignored address pins.

Link to comment
Share on other sites

I get it now. But out of curiosity, what did you mean when you said,

And some bankswitching schemes use accesses to $0000 through $003F to trigger bank switching, which necessitates "relocating" the TIA read and write addresses to $0040 through $007F.

?

There are two bankswitching schemes commonly called 3E and 3F because those zero-page addresses are used as hotspots to trigger a bank switch. The original version was 3F, also called Tigervision because it was used by Tigervision, and there is an extended version of 3F, as well as 3E. (I'm no expert on these schemes, so this information may contain errors.) I'm not sure if extended 3F and 3E are the same, or separate schemes, but 3E adds extra RAM, whereas 3F and extended 3F don't necessarily add extra RAM.

 

Anyway, these bankswitching schemes divide the 4K cartridge area into two 2K slots. The upper 2K area ($1800 - $1FFF) always points to the last 2K of the cartridge ROM, but the lower 2K area ($1000 - $17FF) can be selected from several 2K banks by writing the desired bank number into address $3F. I think the original version had four 2K banks, for a total cartridge size of 8K, whereas the extended version allows up to 256 2K banks, for a total cartridge size of 512K.

 

The 3E version still uses address $3F to select between different 2K ROM banks, but it also allows you to select between different 1K banks of extra RAM by writing the desired RAM bank number into address $3E.

 

The TIA write addresses are $00 - $2C, and the TIA read addresses are $0 - $D, so even though $3E and $3F fall within the memory area that's normally associated with the TIA chip, they don't actually correspond to any addresses or mirrors that are used by the TIA read or write registers. So in theory it should be safe to use $3E and $3F as bankswitching hotspots without interfering with the TIA addresses and mirrors.

 

However, it's my understanding that any access below $40 (i.e., from $00 - $3F) can trigger a bank switch in these schemes-- although this might not be true for all cartridges that use 3E or 3F bankswitching (I don't know). For this reason, the TIA addresses are usually (or always?) relocated to $40 - $7F when using 3E or 3F bankswitching. That is, $40 - $6C are used for the TIA write registers, and either $40 - $4D or $70 - $7D are used for the TIA read registers. Since these are mirrors of the "real" TIA addresses, accessing them is the same (from the TIA's point of view) as accessing $00 - $2C and $00 - $0D.

 

In fact, the DASM assembler recognizes three special labels to help you relocate the TIA addresses, known as TIA_BASE_ADDRESS, TIA_BASE_READ_ADDRESS, and TIA_BASE_WRITE_ADDRESS. If you're using DASM to assemble your 2600 programs, and you want to use 3E or 3F bankswitching, all you have to do is define one or more of these labels to the address where you want the TIA read and write registers to start from, and DASM will automatically relocate the labels for the TIA read and write registers as indicated. You must define these labels *before* including the "vcs.h" header file, as shown in the following examples:

 

 processor 6502

TIA_BASE_ADDRESS = $40

 include "vcs.h"

This example will relocate the labels for the TIA read registers to $40 - $4D, and relocate the labels for the TIA write addresses to $40 - $6C.

 

 processor 6502

TIA_BASE_WRITE_ADDRESS = $40
TIA_BASE_READ_ADDRESS = $70

 include "vcs.h"

This example will relocate the labels for the TIA write registers to $40 - $6C, and relocate the labels for the TIA read addresses to $70 - $7D.

 

If you don't define these labels in your program, DASM will assume they're set to $0, such that the labels for the TIA write registers will be set to $00 - $2C, and the labels for the TIA read registers will be set to $00 - $0D.

Link to comment
Share on other sites

 

In fact, the DASM assembler recognizes three special labels to help you relocate the TIA addresses, known as TIA_BASE_ADDRESS, TIA_BASE_READ_ADDRESS, and TIA_BASE_WRITE_ADDRESS. If you're using DASM to assemble your 2600 programs, and you want to use 3E or 3F bankswitching, all you have to do is define one or more of these labels to the address where you want the TIA read and write registers to start from, and DASM will automatically relocate the labels for the TIA read and write registers as indicated. You must define these labels *before* including the "vcs.h" header file, as shown in the following examples:

 

 processor 6502

TIA_BASE_ADDRESS = $40

 include "vcs.h"

This example will relocate the labels for the TIA read registers to $40 - $4D, and relocate the labels for the TIA write addresses to $40 - $6C.

 

 

Good info, but just to clarify; it is not DASM which recognises these labels.

It's the conditional code inside vcs.h which does all the magic relocation. Have a look/read of vcs.h; I recall it being well commented, explaining what happens.

Cheers

A

Link to comment
Share on other sites

In fact, the DASM assembler recognizes three special labels to help you relocate the TIA addresses, known as TIA_BASE_ADDRESS, TIA_BASE_READ_ADDRESS, and TIA_BASE_WRITE_ADDRESS. If you're using DASM to assemble your 2600 programs, and you want to use 3E or 3F bankswitching, all you have to do is define one or more of these labels to the address where you want the TIA read and write registers to start from, and DASM will automatically relocate the labels for the TIA read and write registers as indicated. You must define these labels *before* including the "vcs.h" header file, as shown in the following examples:

 

 processor 6502

TIA_BASE_ADDRESS = $40

 include "vcs.h"

This example will relocate the labels for the TIA read registers to $40 - $4D, and relocate the labels for the TIA write addresses to $40 - $6C.

 

 

Good info, but just to clarify; it is not DASM which recognises these labels.

It's the conditional code inside vcs.h which does all the magic relocation. Have a look/read of vcs.h; I recall it being well commented, explaining what happens.

Cheers

A

Eek, you are right of course! I was looking at an assembly listing, and the first thing in it were all the lines from the "vsc.h" header file. So as long as you're using that file, it should work the same way with other assemblers, right?

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...