Jump to content
Pixelboy

New ColecoVision PCB design project

Recommended Posts

I still don't understand how trying to access to 6000-6FFF will ask the cartridge to switch banks, but if it works as stated, it can be interresting for a project I would like to do... maybe in 2 years if I can't do anything good next year.

 

Any progress with this project of new pcbs?

Share this post


Link to post
Share on other sites

I still don't understand how trying to access to 6000-6FFF will ask the cartridge to switch banks, but if it works as stated, it can be interresting for a project I would like to do... maybe in 2 years if I can't do anything good next year.

 

Any progress with this project of new pcbs?

A prototype run was done, and another will be ordered soon.

 

As for the banking, the PLD checks to see if all chip selects and A12-A14 are all high and A11 is low, then switches banks based on the value of A10 and A9, or something like that. That translates to accesses in 6000-6FFF range.

Share this post


Link to post
Share on other sites

I still don't understand how trying to access to 6000-6FFF will ask the cartridge to switch banks, but if it works as stated, it can be interresting for a project I would like to do... maybe in 2 years if I can't do anything good next year.

 

Any progress with this project of new pcbs?

A prototype run was done, and another will be ordered soon.

 

As for the banking, the PLD checks to see if all chip selects and A12-A14 are all high and A11 is low, then switches banks based on the value of A10 and A9, or something like that. That translates to accesses in 6000-6FFF range.

I'd like to add that Daniel Vik (dvik) will be helping us with a test program that will validate the bankswitching and EEPROM I/O functionalities, but he's pretty busy right now, so it's going to take several more weeks before this test program is ready. The routines written for this test program will likely be made public for other homebrewers, so that they can take advantage of this new PCB. :)

Share this post


Link to post
Share on other sites

As for the banking, the PLD checks to see if all chip selects and A12-A14 are all high and A11 is low, then switches banks based on the value of A10 and A9, or something like that. That translates to accesses in 6000-6FFF range.

Well, that's kind of clever.

 

And as I recall, the entire 6000-7FFF range is multiple mirrors of the 1K RAM, so this wouldn't even be a problem when using expanded RAM.

Share this post


Link to post
Share on other sites

As for the banking, the PLD checks to see if all chip selects and A12-A14 are all high and A11 is low, then switches banks based on the value of A10 and A9, or something like that. That translates to accesses in 6000-6FFF range.

Well, that's kind of clever.

 

And as I recall, the entire 6000-7FFF range is multiple mirrors of the 1K RAM, so this wouldn't even be a problem when using expanded RAM.

I'm just hoping it won't be too difficult to make 64K games (or access the EEPROM) in C language. The EEPROM I/O can probably be encapsulated in a couple of library routines, but the concept of bankswitching in C is still pretty vague to me. I'll learn all this stuff in detail when the proper time comes, of course. I already have a couple of 64K projects planned, the first of which is a CV version of Boxxle. :)

Share this post


Link to post
Share on other sites

C doesn't know jack about bank switching.

 

You have to know where your banks are, make sure the code for each bank goes to the right part of the image (linker scripts), then you need to make some way to go back and forth between the banks.

 

If the whole of ROM is swapping out, then you either need "trampoline" code in RAM (of which the CV only has 1K to begin with), or you need to have certain parts of ROM be the same in all banks.

 

This is why the 7800-style bank switching is so good: one static 16K area, and another 16K area which contains the current bank. Then you get a whole 16K for the code that sticks around, which can call code or access data in other banks as necessary. This works best for games in which there isn't any inter-dependency between banks, such as games with lots of levels or RPGs with lots of areas.

 

The other benefit of this style of bank switching is that you can extend it as far as 4 megabytes by just adding more bank address latches.

 

 

In any case, there's still a basic problem in that since the CV never had bank switching back in the day, you will get no emulator support unless you add it yourself. Emulators are important because they make your development cycle so much faster, especially with their zero load times. Even with a decent dev cart that has been built with some way to load it, still takes time to reload after you make a change. And the more ROM you're filling, the more stuff you have to debug, which means that many more reload cycles. That's the real reason I gave up on trying to make a game that would break the 32K barrier.

Share this post


Link to post
Share on other sites

C doesn't know jack about bank switching.

 

You have to know where your banks are, make sure the code for each bank goes to the right part of the image (linker scripts), then you need to make some way to go back and forth between the banks.

I see, so it's a pretty "manual" process, where you have to plan and code everything yourself...

 

If the whole of ROM is swapping out, then you either need "trampoline" code in RAM (of which the CV only has 1K to begin with), or you need to have certain parts of ROM be the same in all banks.

 

This is why the 7800-style bank switching is so good: one static 16K area, and another 16K area which contains the current bank. Then you get a whole 16K for the code that sticks around, which can call code or access data in other banks as necessary. This works best for games in which there isn't any inter-dependency between banks, such as games with lots of levels or RPGs with lots of areas.

The PLD used in our PCB will implement a "16K fixed + 16K bankswitched" system. Also, Opcode's MegaCart also implements this same system already, although the bankswitching method is probably a little different.

 

In any case, there's still a basic problem in that since the CV never had bank switching back in the day, you will get no emulator support unless you add it yourself. Emulators are important because they make your development cycle so much faster, especially with their zero load times. Even with a decent dev cart that has been built with some way to load it, still takes time to reload after you make a change. And the more ROM you're filling, the more stuff you have to debug, which means that many more reload cycles. That's the real reason I gave up on trying to make a game that would break the 32K barrier.

The MegaCart is already supported by blueMSX, and I'm sure I can convince Daniel Vik to add support for our own bankswitching system once the PCB prototype has been fully validated. It's safe to say that all this is going to be a long process, but quite worth the effort. :)

Share this post


Link to post
Share on other sites

Just out of curiosity, what happens with the mapper when you issue the following instruction sequence:

LD A,60H

OUT (0BEH),A

 

Load 60h to the VDP data port...

Share this post


Link to post
Share on other sites

Just out of curiosity, what happens with the mapper when you issue the following instruction sequence:

LD A,60H

OUT (0BEH),A

 

Load 60h to the VDP data port...

Depends what address appears on the address bus during that operation,

 

If it's 0BEH, then nothing will happen.

Share this post


Link to post
Share on other sites

Just out of curiosity, what happens with the mapper when you issue the following instruction sequence:

LD A,60H

OUT (0BEH),A

 

Load 60h to the VDP data port...

Depends what address appears on the address bus during that operation,

 

If it's 0BEH, then nothing will happen.

 

That should place 60BEH on the address bus...

Share this post


Link to post
Share on other sites

Just out of curiosity, what happens with the mapper when you issue the following instruction sequence:

LD A,60H

OUT (0BEH),A

 

Load 60h to the VDP data port...

Depends what address appears on the address bus during that operation,

 

If it's 0BEH, then nothing will happen.

 

That should place 60BEH on the address bus...

That's good to know - the issue can be worked around if it's limited to 60xxH, but if it's not, more address decoding may be needed.

 

Can you tell me what port addresses may be hit in the 6000H-7FFFH range during normal Coleco programming?

Share this post


Link to post
Share on other sites

Just out of curiosity, what happens with the mapper when you issue the following instruction sequence:

LD A,60H

OUT (0BEH),A

 

Load 60h to the VDP data port...

Depends what address appears on the address bus during that operation,

 

If it's 0BEH, then nothing will happen.

 

That should place 60BEH on the address bus...

That's good to know - the issue can be worked around if it's limited to 60xxH, but if it's not, more address decoding may be needed.

 

Can you tell me what port addresses may be hit in the 6000H-7FFFH range during normal Coleco programming?

 

Actually in my example 60H is the data, but the Z80 will also use it as the upper 8 bits for the address. So trying to load 60H-7FH to the VDP data port will probably confuse the mapper. And there are other ways to confuse the mapper with your current scheme. I believe the only safe way to implement a mapper like that is to stay in the cartridge range, because you get the chip select lines already decoded, and you can make sure that you are getting a memory access and no memory refresh is happening...

Share this post


Link to post
Share on other sites

Just out of curiosity, what happens with the mapper when you issue the following instruction sequence:

LD A,60H

OUT (0BEH),A

 

Load 60h to the VDP data port...

Depends what address appears on the address bus during that operation,

 

If it's 0BEH, then nothing will happen.

 

That should place 60BEH on the address bus...

That's good to know - the issue can be worked around if it's limited to 60xxH, but if it's not, more address decoding may be needed.

 

Can you tell me what port addresses may be hit in the 6000H-7FFFH range during normal Coleco programming?

 

Actually in my example 60H is the data, but the Z80 will also use it as the upper 8 bits for the address. So trying to load 60H-7FH to the VDP data port will probably confuse the mapper. And there are other ways to confuse the mapper with your current scheme. I believe the only safe way to implement a mapper like that is to stay in the cartridge range, because you get the chip select lines already decoded, and you can make sure that you are getting a memory access and no memory refresh is happening...

But that means that we cannot use a simple PLD as there are way too many address and chip select lines to decode. Going to a CPLD means SMT (or socketed PLCC, but that's not appealing) and a large board. It also makes the board way too expensive and most won't be able to assemble it.

 

If 60H-7FH to certain ports will cause problems, can you give a rundown of which ports are used in normal programming so maybe we can just decode some of the lower address bits?

Share this post


Link to post
Share on other sites

If 60H-7FH to certain ports will cause problems, can you give a rundown of which ports are used in normal programming so maybe we can just decode some of the lower address bits?

Let's keep in mind that this PCB will be used for future games only (where bankswitching and EEPROM usage is concerned, that is, regular 32K games will not be a problem) so we can define special rules as needed to make this work, rules which homebrew programmers will have to adhere to when they program games specifically for this proposed cartridge hardware setup.

 

EDIT: Of course, there's the issue of The Black Onyx, which is a regular 32K game with the planned addition of EEPROM access, so it should be considered in this current discussion...

Edited by Pixelboy

Share this post


Link to post
Share on other sites

Just out of curiosity, what happens with the mapper when you issue the following instruction sequence:

LD A,60H

OUT (0BEH),A

 

Load 60h to the VDP data port...

 

That should place 60BEH on the address bus...

According to the "Z80 Documented" file, that is correct. The A register will appear as the high 8 bits.

 

It is possible to avoid this by using OUT ( C ),A, in which case the B register will be the high 8 bits. But you would have to do this to almost every I/O access. And it's a lot more register usage.

 

And this is a problem with every I/O port, so it could get to be a true pain in the butt. The VDP data is the worst though, because you need to be able to write any byte to it. Ported SG-1000 games are really bad about writing to the VDP port any old time they feel like it, rather than keeping it to a few subroutines.

 

 

 

 

(Note: stupid BB editor wants to convert ( C ) to a copyright symbol: ©. And there seems to be no way to turn that off.)

Share this post


Link to post
Share on other sites

Just out of curiosity, what happens with the mapper when you issue the following instruction sequence:

LD A,60H

OUT (0BEH),A

 

Load 60h to the VDP data port...

 

That should place 60BEH on the address bus...

According to the "Z80 Documented" file, that is correct. The A register will appear as the high 8 bits.

 

It is possible to avoid this by using OUT ( C ),A, in which case the B register will be the high 8 bits. But you would have to do this to almost every I/O access. And it's a lot more register usage.

 

And this is a problem with every I/O port, so it could get to be a true pain in the butt. The VDP data is the worst though, because you need to be able to write any byte to it. Ported SG-1000 games are really bad about writing to the VDP port any old time they feel like it, rather than keeping it to a few subroutines.

 

 

 

 

(Note: stupid BB editor wants to convert ( C ) to a copyright symbol: ©. And there seems to be no way to turn that off.)

The fact that existing games do it is irrelevant, as long as future games do not. The board as designed will only require special port access if using EEPROM access and/or bankswitching. But as I am not a Coleco programmer, I don't know how much of a pain it would be to require port access using the method you described.

Share this post


Link to post
Share on other sites

There is also the problem with memory refresh... The Z80 put stuff on the address bus during memory fresh cycles. The only way to ignore those cycles is using the RFSH line which the cartridge port doesn't have.

Share this post


Link to post
Share on other sites

There is also the problem with memory refresh... The Z80 put stuff on the address bus during memory fresh cycles. The only way to ignore those cycles is using the RFSH line which the cartridge port doesn't have.

What does it put there, and is it limited to RAM addresses? We are already blocking out the actual RAM addresses.

Share this post


Link to post
Share on other sites

There is also the problem with memory refresh... The Z80 put stuff on the address bus during memory fresh cycles. The only way to ignore those cycles is using the RFSH line which the cartridge port doesn't have.

What does it put there, and is it limited to RAM addresses? We are already blocking out the actual RAM addresses.

 

During opcode fetch cycle the R register is incremented and during memory refresh cycle it is put in the address bus. That means the whole memory address range is refreshed. That is why you need to check for the RFSH line for memory decoding, so that memories aren't selected during refreshes (unless it is a DRAM).

 

[EDIT:] My mistake, actually R is used as the lower 7 bits of the address, I is used for the upper 8 bits, so as long as you load I with 0 and don't change it you should be fine...

 

However I believe you would still have a problem with decoding address lines without a memory or I/O request signal because in this case you would be also decoding address transitions, which would lead to "incorrect" decodings.

Share this post


Link to post
Share on other sites

There is also the problem with memory refresh... The Z80 put stuff on the address bus during memory fresh cycles. The only way to ignore those cycles is using the RFSH line which the cartridge port doesn't have.

What does it put there, and is it limited to RAM addresses? We are already blocking out the actual RAM addresses.

 

During opcode fetch cycle the R register is incremented and during memory refresh cycle it is put in the address bus. That means the whole memory address range is refreshed. That is why you need to check for the RFSH line for memory decoding, so that memories aren't selected during refreshes (unless it is a DRAM).

 

[EDIT:] My mistake, actually R is used as the lower 7 bits of the address, I is used for the upper 8 bits, so as long as you load I with 0 and don't change it you should be fine...

 

However I believe you would still have a problem with decoding address lines without a memory or I/O request signal because in this case you would be also decoding address transitions, which would lead to "incorrect" decodings.

The board will have a glitch filter (RC delay into edge-triggered clock) that should prevent any spurious address due to address changes. This is the same sort of thing used for 2600 bankswitch boards (because we have the same problem.)

Share this post


Link to post
Share on other sites

There is also the problem with memory refresh... The Z80 put stuff on the address bus during memory fresh cycles. The only way to ignore those cycles is using the RFSH line which the cartridge port doesn't have.

What does it put there, and is it limited to RAM addresses? We are already blocking out the actual RAM addresses.

 

During opcode fetch cycle the R register is incremented and during memory refresh cycle it is put in the address bus. That means the whole memory address range is refreshed. That is why you need to check for the RFSH line for memory decoding, so that memories aren't selected during refreshes (unless it is a DRAM).

 

[EDIT:] My mistake, actually R is used as the lower 7 bits of the address, I is used for the upper 8 bits, so as long as you load I with 0 and don't change it you should be fine...

 

However I believe you would still have a problem with decoding address lines without a memory or I/O request signal because in this case you would be also decoding address transitions, which would lead to "incorrect" decodings.

The board will have a glitch filter (RC delay into edge-triggered clock) that should prevent any spurious address due to address changes. This is the same sort of thing used for 2600 bankswitch boards (because we have the same problem.)

Alright, so Bruce submitted a work-around for the first issue Eduardo raised (using OUT ( C ),A which could be a bit of a pain software-wise, but should work), and there's another work-around to the memory refresh issue (keeping I at zero), and Fred has his glitch filter. Am I wrong in assuming everything is okay?

Share this post


Link to post
Share on other sites

There is also the problem with memory refresh... The Z80 put stuff on the address bus during memory fresh cycles. The only way to ignore those cycles is using the RFSH line which the cartridge port doesn't have.

What does it put there, and is it limited to RAM addresses? We are already blocking out the actual RAM addresses.

 

During opcode fetch cycle the R register is incremented and during memory refresh cycle it is put in the address bus. That means the whole memory address range is refreshed. That is why you need to check for the RFSH line for memory decoding, so that memories aren't selected during refreshes (unless it is a DRAM).

 

[EDIT:] My mistake, actually R is used as the lower 7 bits of the address, I is used for the upper 8 bits, so as long as you load I with 0 and don't change it you should be fine...

 

However I believe you would still have a problem with decoding address lines without a memory or I/O request signal because in this case you would be also decoding address transitions, which would lead to "incorrect" decodings.

The board will have a glitch filter (RC delay into edge-triggered clock) that should prevent any spurious address due to address changes. This is the same sort of thing used for 2600 bankswitch boards (because we have the same problem.)

Alright, so Bruce submitted a work-around for the first issue Eduardo raised (using OUT ( C ),A which could be a bit of a pain software-wise, but should work), and there's another work-around to the memory refresh issue (keeping I at zero), and Fred has his glitch filter. Am I wrong in assuming everything is okay?

 

Actually the workaround should be to use OUT ©,A and make B = 0 or some known safe value, because B will be placed on the address bus upper 8 bits. With that you would be loosing 2 registers during I/O access, and that is the hard part IMHO.

In addittion to that you need to think how you are going to tell your C compiler to do that...

Why don't you use the cartridge memory area for decoding, it is safer. If you want to go with small PLDs, use a 74LS21 to help with decoding. You get 2 4 ports ANDs, you can use one to decode all 4 CS lines, and the other to decode 4 address lines, thus saving you a lot of PLD ports. Oh, and you save the filter, because have you even assembled a cartridge? The more components you use, the longer it takes to assemble, and it is a pain to solder a board full of capacitors and resistors... Can't you use a bigger PLD, Atmel has several such PLDs in DIP format...

Share this post


Link to post
Share on other sites

Why don't you use the cartridge memory area for decoding, it is safer. If you want to go with small PLDs, use a 74LS21 to help with decoding. You get 2 4 ports ANDs, you can use one to decode all 4 CS lines, and the other to decode 4 address lines, thus saving you a lot of PLD ports. Oh, and you save the filter, because have you even assembled a cartridge? The more components you use, the longer it takes to assemble, and it is a pain to solder a board full of capacitors and resistors... Can't you use a bigger PLD, Atmel has several such PLDs in DIP format...

As I said in the private conversation currently going on with you and Batari, I'm willing to entertain suggestions for alternate ways to implement the bankswitching and EEPROM I/O. We just need to continue this conversation and see where it takes us...

Share this post


Link to post
Share on other sites

Why don't you use the cartridge memory area for decoding, it is safer. If you want to go with small PLDs, use a 74LS21 to help with decoding. You get 2 4 ports ANDs, you can use one to decode all 4 CS lines, and the other to decode 4 address lines, thus saving you a lot of PLD ports. Oh, and you save the filter, because have you even assembled a cartridge? The more components you use, the longer it takes to assemble, and it is a pain to solder a board full of capacitors and resistors... Can't you use a bigger PLD, Atmel has several such PLDs in DIP format...

As I said in the private conversation currently going on with you and Batari, I'm willing to entertain suggestions for alternate ways to implement the bankswitching and EEPROM I/O. We just need to continue this conversation and see where it takes us...

 

Good, good, lets do it.

Share this post


Link to post
Share on other sites

The fact that existing games do it is irrelevant, as long as future games do not. The board as designed will only require special port access if using EEPROM access and/or bankswitching. But as I am not a Coleco programmer, I don't know how much of a pain it would be to require port access using the method you described.

If the code is organized properly, sure. But here is something to consider:

 

The ColecoVision contains a ROM chip (which most folks refer to as the "BIOS"). It has a lot of code in it (which in my opinion is of rather low quality, but that's not important). All of that code wants to talk to the VDP, PSG, and joystick selects using OUT (xxx),A instructions.*

 

Summary: one of the most important "rules" will have to be "don't use the ROM."

 

As to how much of a pain it will be, as long as the code is written such as to keep I/O access to a few subroutines, the extra saving and restoring of registers shouldn't be much of a problem. But if someone wants to port SG-1000 or MSX code that contains VDP writes all through the code (somewhat unlikely given the lack of RAM), that could be a big problem.

 

It's also possible that it could be a big pain simply because you lose use of one of the register pairs (BC), which is primarily used as a counter.

 

 

 

* Note that this problem also applies to IN A,(xxx) as well!

Share this post


Link to post
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.

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...