Jump to content

Photo

Mirrored memory


14 replies to this topic

#1 jbs30000 OFFLINE  

jbs30000

    Moonsweeper

  • 464 posts

Posted Sat Jan 7, 2012 6:13 AM

Out of curiosity, looking at a memory map of the 2600, what are the mirrored addresses for? Thank you.

#2 GroovyBee OFFLINE  

GroovyBee

    Games Developer

  • 7,978 posts
  • Busy bee!
  • Location:North, England

Posted Sat Jan 7, 2012 6:22 AM

It is due to the fact that TIA and RIOT are partially address decoded. By that I mean that not all address lines are taken into account. It was probably done that way as a cost saving measure.

#3 SpiceWare OFFLINE  

SpiceWare

    Quadrunner

  • 8,339 posts
  • Medieval Mayhem
  • Location:Planet Houston

Posted Sat Jan 7, 2012 9:44 AM

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.

#4 jdrose OFFLINE  

jdrose

    Chopper Commander

  • 119 posts

Posted Sat Jan 7, 2012 4:01 PM

There are answers in this thread that may help you understand mirrored addresses better.

http://www.atariage....00-programming/

#5 jbs30000 OFFLINE  

jbs30000

    Moonsweeper

  • Topic Starter
  • 464 posts

Posted Sat Jan 7, 2012 5:06 PM

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

#6 SeaGtGruff OFFLINE  

SeaGtGruff

    Quadrunner

  • 5,455 posts
  • Location:Georgia, USA

Posted Sun Jan 8, 2012 3:01 AM

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.

#7 jbs30000 OFFLINE  

jbs30000

    Moonsweeper

  • Topic Starter
  • 464 posts

Posted Sun Jan 8, 2012 5:17 AM

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

Let me ask two questions that may help me understand better.
  • Does a change in one location make a change in all the mirror locations (including the original if you change a mirror value)?
  • Is only one location active at a time, or is the original and all its mirrors active at the same time?


#8 alex_79 OFFLINE  

alex_79

    Moonsweeper

  • 393 posts
  • Location:Italy

Posted Sun Jan 8, 2012 6:17 AM

  • Does a change in one location make a change in all the mirror locations (including the original if you change a mirror value)?
  • 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:
Attached File  mem_map_1.txt   27.36KB   85 downloads
Attached File  mem_map_2.txt   1.75KB   76 downloads
Attached File  riot_map.txt   6.05KB   90 downloads
Attached File  tia_map.txt   3.56KB   94 downloads

#9 jbs30000 OFFLINE  

jbs30000

    Moonsweeper

  • Topic Starter
  • 464 posts

Posted Sun Jan 8, 2012 6:19 AM

I was just in the middle of editing that post because I thought I figured it out, but I guess I didn't. Thank you for the maps.

#10 SeaGtGruff OFFLINE  

SeaGtGruff

    Quadrunner

  • 5,455 posts
  • Location:Georgia, USA

Posted Sun Jan 8, 2012 10:50 AM

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.

#11 jbs30000 OFFLINE  

jbs30000

    Moonsweeper

  • Topic Starter
  • 464 posts

Posted Sun Jan 8, 2012 1:10 PM

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.

?

#12 SeaGtGruff OFFLINE  

SeaGtGruff

    Quadrunner

  • 5,455 posts
  • Location:Georgia, USA

Posted Sun Jan 8, 2012 10:00 PM

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.

#13 jbs30000 OFFLINE  

jbs30000

    Moonsweeper

  • Topic Starter
  • 464 posts

Posted Sun Jan 8, 2012 11:20 PM

Good info. Once I eventually master 4K (hey, it'll happen :D ) this will be good for studying up on bank switching.

#14 Andrew Davie OFFLINE  

Andrew Davie

    Stargunner

  • 1,586 posts
  • Dr.Boo
  • Location:Tasmania

Posted Tue Jan 10, 2012 5:06 AM

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

#15 SeaGtGruff OFFLINE  

SeaGtGruff

    Quadrunner

  • 5,455 posts
  • Location:Georgia, USA

Posted Tue Jan 10, 2012 11:09 AM


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?




0 user(s) are browsing this forum

0 members, 0 guests, 0 anonymous users