Forums

Sega Master System / Mark III / Game Gear
SG-1000 / SC-3000 / SF-7000 / OMV
Home - Forums - Games - Scans - Maps - Cheats - Credits
Music - Videos - Development - Hacks - Translations - Homebrew

View topic - Any other Z80 I/O Mirrors?

Reply to topic
Author Message
  • Joined: 14 Oct 2006
  • Posts: 256
  • Location: NYC
Reply with quote
Any other Z80 I/O Mirrors?
Post Posted: Thu Nov 02, 2006 5:02 am
In Charles MacDonald's smstech-20021112.txt he states that inputs are mirrored at $C0 and $C1. The VDP control is also mirrored at $BD. I was wondering if there are any other significant Z80 I/O mirrors?
  View user's profile Send private message Visit poster's website
  • Joined: 18 Sep 1999
  • Posts: 498
  • Location: Portland, Oregon USA
Reply with quote
Post Posted: Thu Nov 02, 2006 7:12 am
Yes, there are other mirrors. Here's how I/O ports actually work for the SMS and SMS2 (GG is slightly different):

Only bits 0, 6, 7 of the I/O port number is decoded in the SMS. This means that all even number ports between $00 and $3E are the same. Likewise for $40 through $7E, $80 through $BE, and $C0 through $FE.

Similarly, all odd-numbered ports between $01 and $3F are the same, as are $41 through $7F, $81 through $BF, and $C1 through $FF.

--
Eric R. Quinn
  View user's profile Send private message Visit poster's website
  • Joined: 25 Dec 2005
  • Posts: 607
  • Location: São Paulo - Brazil
Reply with quote
Post Posted: Thu Nov 02, 2006 3:31 pm
I was wondering, about mirrors:

(Suppose A and A')
1. If you write A', is the new value mirrored at A ?
2. Is the write and mirror operation atomic ?

I thought at first (if 1. doesn't apply) that mirrors help solve classic exchange problems, like:

(Suppose A,B,A',B' and I want to exchange A and B)

B' <-- A
A <-- B
B <-- B'
  View user's profile Send private message
  • Site Admin
  • Joined: 19 Oct 1999
  • Posts: 14770
  • Location: London
Reply with quote
Post Posted: Thu Nov 02, 2006 4:17 pm
The "mirrors" are a physical thing. Think of the bits in the address. If the chip only looks at bits 0, 6 and 7 then %11000001 and %11001001 look the same because all it sees is %11-----1 in both cases.

Thus, reading or writing to/from any mirrored address is equivalent no matter which address you use for either part.

A few things to note:

1. On the SMS, most I/O ports are not simple read/write - generally you don't read back what you wrote, regardless of mirrors.
2. A notable use of mirroring in memory is that writing to paging registers (eg. $ffff) is simultaneously writing to a mirror of RAM - $ffff is a mirror of $dfff. However, the paging hardware only responds to writes to $ffff. So, you can write to $ffff and read back from $ffff or $dfff. But writing to $dfff won't affect paging. Confusing, huh? The same goes for "reading back" the 3D glasses "register".
3. Mirroring is also why overdumps generally have the same data repeated multiple times.

Also, it's not an "operation" - it's no more or less atomic than using non-mirrored addresses. Non-standard I/O address usage just hurts emulator compatibility, which is why an emulator ought to handle it, which is simple enough - address &= 0x3e will set all the unused bits. Most of the standard addresses (3e/3f/7e/7f/be/bf) have those middle 5 bits set, the others (dc/dd) can be changed in the source (to fe/ff), and the GG I/O ports are a special case anyway.
  View user's profile Send private message Visit poster's website
  • Joined: 25 Dec 2005
  • Posts: 607
  • Location: São Paulo - Brazil
Reply with quote
Post Posted: Thu Nov 02, 2006 5:43 pm
Thanks for the info Maxim.
I didn't get confused about the paging info =)
I used the word operation 'cause I thought of 2 sequential/concurrent actions, like:

[Entering critical region]
Write to the address
Copy to mirror
[Leaving critical region]

If I understood what you said, you just write to an address and take for granted the mirroring right (next opcode can just read the mirror) ?
So, can't we say that, inside the chip, the above procedure is atomic ?
  View user's profile Send private message
  • Site Admin
  • Joined: 08 Jul 2001
  • Posts: 8675
  • Location: Paris, France
Reply with quote
Post Posted: Thu Nov 02, 2006 6:24 pm
Niloctronic, the key to understand is Maxim's first sentence:
Quote
The "mirrors" are a physical thing. Think of the bits in the address. If the chip only looks at bits 0, 6 and 7 then %11000001 and %11001001 look the same because all it sees is %11-----1 in both cases.

There's no such thing as 'copy to mirror'. Qualifying the operation as 'atomic' doesn't apply since there's only one reading/writing done. It's just some address bits that get maskedout because they are physically unconnected.
  View user's profile Send private message Visit poster's website
  • Joined: 25 Dec 2005
  • Posts: 607
  • Location: São Paulo - Brazil
Reply with quote
Post Posted: Thu Nov 02, 2006 7:58 pm
Bock wrote
There's no such thing as 'copy to mirror'. Qualifying the operation as 'atomic' doesn't apply since there's only one reading/writing done. It's just some address bits that get maskedout because they are physically unconnected.

Ok guys, summing up: the chip can manipulate the address line to write once in more than one byte of RAM, right ? Well, enough of theory heh.

Tks again.
  View user's profile Send private message
  • Site Admin
  • Joined: 19 Oct 1999
  • Posts: 14770
  • Location: London
Reply with quote
Post Posted: Thu Nov 02, 2006 10:00 pm
Niloctronic wrote
Ok guys, summing up: the chip can manipulate the address line to write once in more than one byte of RAM, right ?

Wrong :)

Let's say I have three switches in front of me that control lightbulbs. That gives me a total of 8 different light combinations.

The light bulbs are in a different room, where my chef is waiting to see what kind of food to cook me. (Hey, why not.) However, what I don't know is, he is only looking at bulbs 2 and 3; he doesn't care about bulb 1.

So, if I want dish 011, I press switches 2 and 2, but not 1. He sees 2 lights and cooks me a dish appropriately.

Later, I decide to try dish 111, so I press all 3 switches. He still sees 2 lights and gives me the same dish.

From his point of view, there are 2 bulbs and 4 possible dishes. From my point of view, there are 3 switches, and 8 possible combinations, but the first 4 are mirrors of the second 4.

000 Dish A
001 Dish B
010 Dish C
011 Dish D
100 Dish A
101 Dish B
110 Dish C
111 Dish D

One of the bits is simply not connected and as a result, mirroring appears. Now consider if my switches are the CPU's address bus and the dishes are bytes of RAM (hey, my example is getting strained now); writing to 000 will work the same as writing to 100, and likewise for reading, no matter the order; there's still only 4 bytes of RAM in total, they just all have 2 effective addresses where they can be written.
  View user's profile Send private message Visit poster's website
  • Joined: 14 Aug 2000
  • Posts: 748
  • Location: Adelaide, Australia
Reply with quote
shell game
Post Posted: Fri Nov 03, 2006 1:37 am
I'll take what's behind Dish D!

Can I buy a vowel too?


For clarity, I've listed all the port numbers that can be used by a games/software programmer for the corresponding tasks in the SMS (generated with xls) below. The ports in each list will have the same effect when used.

Slot Enable Port (officially 0x3E):
0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x1E, 0x20, 0x22, 0x24, 0x26, 0x28, 0x2A, 0x2C, 0x2E, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3A, 0x3C, 0x3E

Joypad Port Control Port (officially 0x3F):
0x01, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0F, 0x11, 0x13, 0x15, 0x17, 0x19, 0x1B, 0x1D, 0x1F, 0x21, 0x23, 0x25, 0x27, 0x29, 0x2B, 0x2D, 0x2F, 0x31, 0x33, 0x35, 0x37, 0x39, 0x3B, 0x3D, 0x3F

VDP / PSG Port (officially 0x7E):
0x40, 0x42, 0x44, 0x46, 0x48, 0x4A, 0x4C, 0x4E, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5A, 0x5C, 0x5E, 0x60, 0x62, 0x64, 0x66, 0x68, 0x6A, 0x6C, 0x6E, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7A, 0x7C, 0x7E

VDP / PSG Port (officially 0-x7F):
0x41, 0x43, 0x45, 0x47, 0x49, 0x4B, 0x4D, 0x4F, 0x51, 0x53, 0x55, 0x57, 0x59, 0x5B, 0x5D, 0x5F, 0x61, 0x63, 0x65, 0x67, 0x69, 0x6B, 0x6D, 0x6F, 0x71, 0x73, 0x75, 0x77, 0x79, 0x7B, 0x7D, 0x7F

VDP Data Port (Officially 0xBE):
0x80, 0x82, 0x84, 0x86, 0x88, 0x8A, 0x8C, 0x8E, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9A, 0x9C, 0x9E, 0xA0, 0xA2, 0xA4, 0xA6, 0xA8, 0xAA, 0xAC, 0xAE, 0xB0, 0xB2, 0xB4, 0xB6, 0xB8, 0xBA, 0xBC, 0xBE

VDP Command Port (officially 0xBF)
0x81, 0x83, 0x85, 0x87, 0x89, 0x8B, 0x8D, 0x8F, 0x91, 0x93, 0x95, 0x97, 0x99, 0x9B, 0x9D, 0x9F, 0xA1, 0xA3, 0xA5, 0xA7, 0xA9, 0xAB, 0xAD, 0xAF, 0xB1, 0xB3, 0xB5, 0xB7, 0xB9, 0xBB, 0xBD, 0xBF

Joypad 1 Port Status Port (officially 0xDC)
0xC0, 0xC2, 0xC4, 0xC6, 0xC8, 0xCA, 0xCC, 0xCE, 0xD0, 0xD2, 0xD4, 0xD6, 0xD8, 0xDA, 0xDC, 0xDE, 0xE0, 0xE2, 0xE4, 0xE6, 0xE8, 0xEA, 0xEC, 0xEE, 0xF0, 0xF2, 0xF4, 0xF6, 0xF8, 0xFA, 0xFC, 0xFE

Joypad 2 Port Status Port (officially 0xDD):
0xC1, 0xC3, 0xC5, 0xC7, 0xC9, 0xCB, 0xCD, 0xCF, 0xD1, 0xD3, 0xD5, 0xD7, 0xD9, 0xDB, 0xDD, 0xDF, 0xE1, 0xE3, 0xE5, 0xE7, 0xE9, 0xEB, 0xED, 0xEF, 0xF1, 0xF3, 0xF5, 0xF7, 0xF9, 0xFB, 0xFD, 0xFF

asynchronous.
  View user's profile Send private message
  • Joined: 14 Oct 2006
  • Posts: 256
  • Location: NYC
Reply with quote
Post Posted: Fri Nov 03, 2006 4:44 am
Thanks for the information, guys!
  View user's profile Send private message Visit poster's website
  • Site Admin
  • Joined: 19 Oct 1999
  • Posts: 14770
  • Location: London
Reply with quote
Post Posted: Fri Nov 03, 2006 7:18 am
Wow, that seems like an inefficient way to do the logic :)

if (GG_mode && port_number<=6)
{
  ...
}
else switch (port_number & 0x3e)
{
  case 0x3e & 0x3e: port_3e(data); break;
  case 0x3f & 0x3e: port_3f(data); break;
  case 0x7e & 0x3e: port_7e(data); break;
  case 0x7f & 0x3e: port_7f(data); break;
  case 0xbe & 0x3e: port_be(data); break;
  case 0xbf & 0x3e: port_bf(data); break;
  case 0xdc & 0x3e: port_dc(data); break;
  case 0xdd & 0x3e: port_dd(data); break;
}
ought to cover everything. (Most of the "& 0x3e"s are unnecessarym but I added them for elegance, and they'll be calculated at compile-time anyway. Maybe not in VB, though...)
  View user's profile Send private message Visit poster's website
  • Joined: 18 Sep 1999
  • Posts: 498
  • Location: Portland, Oregon USA
Reply with quote
Post Posted: Fri Nov 03, 2006 6:40 pm
Oops. You made a small mistake Maxim. The code should read:

if (GG_mode && port_number<=6)
{
  ...
}
else switch (port_number | 0x3e)
{
  case 0x3e | 0x3e: port_3e(data); break;
  case 0x3f | 0x3e: port_3f(data); break;
  case 0x7e | 0x3e: port_7e(data); break;
  case 0x7f | 0x3e: port_7f(data); break;
  case 0xbe | 0x3e: port_be(data); break;
  case 0xbf | 0x3e: port_bf(data); break;
  case 0xdc | 0x3e: port_fe(data); break;
  case 0xdd | 0x3e: port_ff(data); break;
}


-OR-

if (GG_mode && port_number<=6)
{
  ...
}
else switch (port_number & 0xc1)
{
  case 0x3e & 0xc1: port_00(data); break;
  case 0x3f & 0xc1: port_01(data); break;
  case 0x7e & 0xc1: port_40(data); break;
  case 0x7f & 0xc1: port_41(data); break;
  case 0xbe & 0xc1: port_80(data); break;
  case 0xbf & 0xc1: port_81(data); break;
  case 0xdc & 0xc1: port_c0(data); break;
  case 0xdd & 0xc1: port_c1(data); break;
}


You were masking the wrong bits with the AND operation. (As evidenced by the fact that 0x3e & 0x3e == 0x7e & 0x3e == 0xbe & 0x3e == 0xdc &0x3e == 0x3e, and 0x3f & 0x3e == 0x7f & 0x3e == 0xbf & 0x3e == 0x3e, and 0xdd &0x3e == 0x1c)

For what it's worth MesaDX uses the top style.

--
Eric R. Quinn
  View user's profile Send private message Visit poster's website
  • Joined: 28 Sep 1999
  • Posts: 1198
Reply with quote
Post Posted: Fri Nov 03, 2006 7:32 pm
Eric R. Quinn wrote
Oops. You made a small mistake Maxim. The code should read:


I see what you mean, but isn't this simple enough?

switch(port & 0xC1)
{
case 0x00:
case 0x01:
case 0x40:
case 0x41:
case 0x80:
case 0x81:
case 0xC0:
case 0xC1:
}

I've never seen the syntax you guys are using in the case statements before. :P
  View user's profile Send private message Visit poster's website
  • Site Admin
  • Joined: 19 Oct 1999
  • Posts: 14770
  • Location: London
Reply with quote
Post Posted: Fri Nov 03, 2006 9:56 pm
Grr. I ought to have thought a bit more thoroughly.

Charles: I was aiming to have the "official" port numbers line up on the left of each case handler; however, the last 2 ($dc and $dd) are the only two "official" values that aren't already ORe with $3e. So I could write $fe and $ff there (potentially confusing), or do the ORing explicitly (since the calculation is done at compile time). From there, it's one more step to ad the ORing to all of them, just for "elegance" (and having everything lining up vertically).
  View user's profile Send private message Visit poster's website
  • Site Admin
  • Joined: 08 Jul 2001
  • Posts: 8675
  • Location: Paris, France
Reply with quote
Post Posted: Sat Nov 04, 2006 12:34 am
As a matter of style, I would use "official" port values (as Maxim mentionned) along with ~0x3E (==0xC1 but readable).

Not how SG-1000/SC-3000/SF-7000 also use other ports. For simplicity of coding, one could use a table of 256 function pointers and initialize depending on the emulated system (Not so cache friendly).
  View user's profile Send private message Visit poster's website
  • Joined: 08 Dec 2005
  • Posts: 488
  • Location: Melbourne, Australia
Reply with quote
Post Posted: Sun Nov 05, 2006 2:15 pm
Charles MacDonald wrote
I see what you mean, but isn't this simple enough?

switch(port & 0xC1)



That's what I have been using. If the SMS only looks at address lines 7, 6 and 1, it makes sense to me for an emulator to do exactly that, and not worry about "official" port addresses.

Eric R. Quinn wrote
Here's how I/O ports actually work for the SMS and SMS2 (GG is slightly different)


How is the GG different? I am aware of bits 7 and 6 of port 0x00 being used for the start button and region detection, but I also read that the GG uses ports 0x01-0x06 for different reasons than the SMS. Does anyone know what these other ports are used for? Are these GG-specific ports mirrored anywhere?
  View user's profile Send private message Visit poster's website
  • Joined: 14 Oct 2006
  • Posts: 256
  • Location: NYC
Reply with quote
Post Posted: Sun Nov 05, 2006 9:06 pm
Public Function inn(port As Long) As Long 'Read from a Z80 Port.

  If port& = &H0& And IsGameGear Then 'game gear controller (for start button).
    Call JoystickInput
    If MovieRecording Then Put #3, , ggcontroller
    If MoviePlaying Then Get #3, , ggcontroller: Call MoviePlayEnd
    inn = ggcontroller
    Exit Function
  End If

  Select Case port&
    'Vertical Port.
    Case &H40&, &H42&, &H44&, &H46&, &H48&, &H4A&, &H4C&, &H4E&, &H50&, &H52&, &H54&, &H56&, &H58&, &H5A&, &H5C&, &H5E&, &H60&, &H62&, &H64&, &H66&, &H68&, &H6A&, &H6C&, &H6E&, &H70&, &H72&, &H74&, &H76&, &H78&, &H7A&, &H7C&, &H7E&
      inn = vdp.getVCount
    'controller 1 and some of controller 2.
    Case &HC0&, &HC2&, &HC4&, &HC6&, &HC8&, &HCA&, &HCC&, &HCE&, &HD0&, &HD2&, &HD4&, &HD6&, &HD8&, &HDA&, &HDC&, &HDE&, &HE0&, &HE2&, &HE4&, &HE6&, &HE8&, &HEA&, &HEC&, &HEE&, &HF0&, &HF2&, &HF4&, &HF6&, &HF8&, &HFA&, &HFC&, &HFE&
      Call JoystickInput
      If MovieRecording Then Put #3, , controller1
      If MoviePlaying Then Get #3, , controller1: Call MoviePlayEnd
      inn = controller1
    'rest of controller 2.
    Case &HC1&, &HC3&, &HC5&, &HC7&, &HC9&, &HCB&, &HCD&, &HCF&, &HD1&, &HD3&, &HD5&, &HD7&, &HD9&, &HDB&, &HDD&, &HDF&, &HE1&, &HE3&, &HE5&, &HE7&, &HE9&, &HEB&, &HED&, &HEF&, &HF1&, &HF3&, &HF5&, &HF7&, &HF9&, &HFB&, &HFD&, &HFF&
      Call JoystickInput
      If MovieRecording Then Put #3, , controller2
      If MoviePlaying Then Get #3, , controller2: Call MoviePlayEnd
      inn = controller2
    'VDP Data Port.
    Case &H80&, &H82&, &H84&, &H86&, &H88&, &H8A&, &H8C&, &H8E&, &H90&, &H92&, &H94&, &H96&, &H98&, &H9A&, &H9C&, &H9E&, &HA0&, &HA2&, &HA4&, &HA6&, &HA8&, &HAA&, &HAC&, &HAE&, &HB0&, &HB2&, &HB4&, &HB6&, &HB8&, &HBA&, &HBC&, &HBE&
      inn = vdp.dataread
    'VDP Control Port.
    Case &H81&, &H83&, &H85&, &H87&, &H89&, &H8B&, &H8D&, &H8F&, &H91&, &H93&, &H95&, &H97&, &H99&, &H9B&, &H9D&, &H9F&, &HA1&, &HA3&, &HA5&, &HA7&, &HA9&, &HAB&, &HAD&, &HAF&, &HB1&, &HB3&, &HB5&, &HB7&, &HB9&, &HBB&, &HBD&, &HBF&
      inn = vdp.controlread
    Case Else
      inn = 255&
  End Select

  Exit Function

End Function

Yes, this is where you cringe.
  View user's profile Send private message Visit poster's website
  • Site Admin
  • Joined: 19 Oct 1999
  • Posts: 14770
  • Location: London
Reply with quote
Post Posted: Sun Nov 05, 2006 10:08 pm
You'll need some better handling of the GG ports (01-05?), for some GG games to run. It may be that this explicit mega-case is faster - you should see what difference it makes if you do the bitwise operations to reduce the jump table to less entries. Or does VB not have bitwise operations?
  View user's profile Send private message Visit poster's website
  • Joined: 14 Oct 2006
  • Posts: 256
  • Location: NYC
Reply with quote
Post Posted: Sun Nov 05, 2006 10:42 pm
You use And's and Or's for bitwise operations, the whole thing is a mess (Visual Basic). I haven't bothered with *any* Game Gear stuff yet, only the Start button. I suppose I could add it back into the Case now, I don't remember why I took it out.
  View user's profile Send private message Visit poster's website
Reply to topic



Back to the top of this page

Back to SMS Power!