What are common mistakes for beginners?
What are common mistakes for beginners?
In a different thread Garthwilson commented how there are common mistakes made by beginners when designing their own systems. I'm wondering what I should be looking for myself.
Garthwilson said to Put capacitors as close to the IC that needs them as possible.
what else would be obvious to the experience people that us rookies wouldn't see right away?
Also, as I think about some of the design decisions made and I'm not sure I understand why so here are a few questions of my own:
Why are the memory mapped devices typically in the high-end RAM areas (just below ROM)? I would think having as much contiguous memory for the programs as possible would be more beneficial so sticking the device mappings in 0200 - 02FF strikes me as the better location (just above the stack area).
How fast should I be able to get a W65C02 chip to go in a breadboard? Related to that, how fast would a motherboard go before timing issues arise (assuming a less than ideal design)? I'm asking because it seams most hobby systems don't go much beyond 4MHz on chips that can go at around 14MHz. I would think in this case faster is better. I am myself hoping for over 10MHz after I get off the breadboard.
When just starting out (and not sure how far I will go) what are the essential tools?
- soldering iron (for everything after the breadboard)
- EEPROM writer
- ?
I ran across an old analog oscilloscope (that I now have access to) but I'm not sure how fast it is (or if it even works). How fast would it need to be to be of use initially (assuming a 2MHz system initially)?
Garthwilson said to Put capacitors as close to the IC that needs them as possible.
what else would be obvious to the experience people that us rookies wouldn't see right away?
Also, as I think about some of the design decisions made and I'm not sure I understand why so here are a few questions of my own:
Why are the memory mapped devices typically in the high-end RAM areas (just below ROM)? I would think having as much contiguous memory for the programs as possible would be more beneficial so sticking the device mappings in 0200 - 02FF strikes me as the better location (just above the stack area).
How fast should I be able to get a W65C02 chip to go in a breadboard? Related to that, how fast would a motherboard go before timing issues arise (assuming a less than ideal design)? I'm asking because it seams most hobby systems don't go much beyond 4MHz on chips that can go at around 14MHz. I would think in this case faster is better. I am myself hoping for over 10MHz after I get off the breadboard.
When just starting out (and not sure how far I will go) what are the essential tools?
- soldering iron (for everything after the breadboard)
- EEPROM writer
- ?
I ran across an old analog oscilloscope (that I now have access to) but I'm not sure how fast it is (or if it even works). How fast would it need to be to be of use initially (assuming a 2MHz system initially)?
Quote:
Why are the memory mapped devices typically in the high-end RAM areas (just below ROM)? I would think having as much contiguous memory for the programs as possible would be more beneficial so sticking the device mappings in 0200 - 02FF strikes me as the better location (just above the stack area).
My next SBC's will use programmable logic for address decoding and I plan to use the $02xx page for my IO; for the same reason, to keep memory as contiguous as possible.
Quote:
How fast should I be able to get a W65C02 chip to go in a breadboard? Related to that, how fast would a motherboard go before timing issues arise (assuming a less than ideal design)? I'm asking because it seams most hobby systems don't go much beyond 4MHz on chips that can go at around 14MHz. I would think in this case faster is better. I am myself hoping for over 10MHz after I get off the breadboard.
Quote:
Garthwilson said to Put capacitors as close to the IC that needs them as possible.
Quote:
I ran across an old analog oscilloscope (that I now have access to) but I'm not sure how fast it is (or if it even works). How fast would it need to be to be of use initially (assuming a 2MHz system initially)?
Smilingphoenix gave me this advice in another thread:
Quote:
For a square wave to look even reasonable on a scope, the scope needs a bandwidth of at least 10 times the square waves frequency. On my 30MHz scope, a 14.318MHz signal looks vaugely sinusoidial! You need a 150MHz scope for a 14MHz square wave to look square.
Daryl
-
Wally Daniels
- Posts: 53
- Joined: 30 Aug 2002
- Location: Windsor Forks, N.S. Canada
Re: What are common mistakes for beginners?
Lost wrote:
Garthwilson said to Put capacitors as close to the IC that needs them as possible.
Quote:
Why are the memory mapped devices typically in the high-end RAM areas (just below ROM)? I would think having as much contiguous memory for the programs as possible would be more beneficial so sticking the device mappings in 0200 - 02FF strikes me as the better location (just above the stack area).
way of (re) loading High ROM such as a ROM emulator it can be handy
to use RAM in the ROM area when building your basic OS. For example
the 27C256 is an 8X32K ROM and is almost a drop in for it's RAM equiv
the 62256 ( or equiv ) just A14, R/W and.......Vpp I think need to be
manipulated. As well two '256' devices can conveniently give you lots
of Room for RAM & ROM space. I/O can be added with alittle glue logic.
Really I think most designers simply add RAM in the Low are because
of the Stack & lets not forget Zero Page :-) not to mention tradition !
Quote:
How fast should I be able to get a W65C02 chip to go in a breadboard?
a clock source that can be scaled up easily. That way you can start low
say with 1Mhz and move up. You might be suprised. It would be a neat
experiment.
I can tell you that you can easily reach 8Mhz with wire wrap. I have not
gone much beyond this because of the chips I am using.
- W
I fail utterly to see how placing I/O in page 2 will give you more contiguous amounts of RAM. Indeed, it has precisely the opposite effect.
You'll end up with a system with RAM from $0000-$01FF, then a 256 byte gap, then $0300-$xxxx.
The reason I/O is usually placed just beneath the ROM is because that produces the most contiguous amount of RAM possible. It takes extra logic (read, extra gates, extra transistors, extra money) to do memory decoding that is not on a power of two boundary, or to remap some RAM pages elsewhere.
For example, placing ROM at $C000-$FFFF, and I/O from $8000-$BFFF, with RAM at $0000-$7FFF takes only a handful of gates. This costs pennies. "OK," you might say, "but now you have lost 16KiB to I/O space!" Very true. There are four major ways to handle this problem, and to do it right, every one requires some form of programmable logic, just to keep propegation delays under control.
1) Deal with it as it is. Use software to swap memory in and out of the address space as you need it. Machine language compiled with a "virtual memory aware" language compiler would enable this to occur without you ever having to think about it. It would probably be fast enough for most tasks as well.
2) Introduce additional RAM banks that overlap each other in $0000-$7FFF. This is how most Apple IIs and Atari systems worked. Here, you'd use a control register in I/O space to select which chunk of 32KiB you'd like to see at any given time. More advanced forms of this will break the 32KiB into (say) 4 8KiB "pages", with each page containing its own upper address bits.
3) Add address decoding logic that switches I/O space out of the address space. Since the 6502 lacks dedicated I/O instructions, this takes some creativity. Here are some ideas I've come up with off the top of my head just now:
3A - Set a bit in a control register in I/O space that, when set, remains set for something like 1024 (or so) clock cycles. While this bit is set, you have access to underlying RAM. Once the bit resets, I/O space will return. Not suitable for storing or executing code, unless you reset that bit periodically via an interrupt of some kind. It'd still be useful for storing non-executable data though.
3B - Detect when a BRK instruction is executed (if (sync==0) && (d0-d7 == 0) && (phi2 == 1)), and upon doing so, force I/O (and, if applicable, ROM) to come back into the memory space.
3C - Code running in $0000-$3FFF sees I/O at $8000-$9FFF, while code running at $4000-$7FFF sees I/O at $A000-$BFFF. Code running in $8000-$BFFF never sees I/O at all. This takes some trickery to implement though. Not recommended.
3D - Create a single-port mirror for an I/O register dedicated to controlling memory configuration. For example, the Commodore 128 had a set of registers at $FF00-$FF05 IIRC, which were decoded expressly for the purposes of allowing the CPU to recover its I/O registers once they were switched out. Commodore 64 and Plus/4 had a somewhat similar solution.
3E -- Always keep I/O space in memory, but let it float about the address space. This can be done by allocating one byte of I/O space to holding the "current I/O page", which is used to compare against A8-A15. This way, you can place the I/O at $0200-$02FF, but if you need to access RAM in that area, you can just move it out of the way by rewriting that register temporarily.
4. And finally, use a different CPU -- the 65816 comes to mind -- which offers a larger address space and the instructions needed to access it, wihch makes cheaper address decoding techniques viable again, and supports a 16MB address space.
Note, however, that the 65816 has a quirk -- when it boots up, it tries to fetch vectors from $00FFFx, not $FFFFFx. Because of this, you must use, at a minimum, an address decoder that properly handles at least 9 bits of address lines. Ouch!! Not cheap, not fast, and not pretty. It is possible to apply option 3E to the decoding of ROM addresses, of course, but again, I'd rather the CPU just not force me to have to segment my memory space into non-contiguous chunks in the first place.
These are some of the options you have available, and I hope I've answered your question.
You'll end up with a system with RAM from $0000-$01FF, then a 256 byte gap, then $0300-$xxxx.
The reason I/O is usually placed just beneath the ROM is because that produces the most contiguous amount of RAM possible. It takes extra logic (read, extra gates, extra transistors, extra money) to do memory decoding that is not on a power of two boundary, or to remap some RAM pages elsewhere.
For example, placing ROM at $C000-$FFFF, and I/O from $8000-$BFFF, with RAM at $0000-$7FFF takes only a handful of gates. This costs pennies. "OK," you might say, "but now you have lost 16KiB to I/O space!" Very true. There are four major ways to handle this problem, and to do it right, every one requires some form of programmable logic, just to keep propegation delays under control.
1) Deal with it as it is. Use software to swap memory in and out of the address space as you need it. Machine language compiled with a "virtual memory aware" language compiler would enable this to occur without you ever having to think about it. It would probably be fast enough for most tasks as well.
2) Introduce additional RAM banks that overlap each other in $0000-$7FFF. This is how most Apple IIs and Atari systems worked. Here, you'd use a control register in I/O space to select which chunk of 32KiB you'd like to see at any given time. More advanced forms of this will break the 32KiB into (say) 4 8KiB "pages", with each page containing its own upper address bits.
3) Add address decoding logic that switches I/O space out of the address space. Since the 6502 lacks dedicated I/O instructions, this takes some creativity. Here are some ideas I've come up with off the top of my head just now:
3A - Set a bit in a control register in I/O space that, when set, remains set for something like 1024 (or so) clock cycles. While this bit is set, you have access to underlying RAM. Once the bit resets, I/O space will return. Not suitable for storing or executing code, unless you reset that bit periodically via an interrupt of some kind. It'd still be useful for storing non-executable data though.
3B - Detect when a BRK instruction is executed (if (sync==0) && (d0-d7 == 0) && (phi2 == 1)), and upon doing so, force I/O (and, if applicable, ROM) to come back into the memory space.
3C - Code running in $0000-$3FFF sees I/O at $8000-$9FFF, while code running at $4000-$7FFF sees I/O at $A000-$BFFF. Code running in $8000-$BFFF never sees I/O at all. This takes some trickery to implement though. Not recommended.
3D - Create a single-port mirror for an I/O register dedicated to controlling memory configuration. For example, the Commodore 128 had a set of registers at $FF00-$FF05 IIRC, which were decoded expressly for the purposes of allowing the CPU to recover its I/O registers once they were switched out. Commodore 64 and Plus/4 had a somewhat similar solution.
3E -- Always keep I/O space in memory, but let it float about the address space. This can be done by allocating one byte of I/O space to holding the "current I/O page", which is used to compare against A8-A15. This way, you can place the I/O at $0200-$02FF, but if you need to access RAM in that area, you can just move it out of the way by rewriting that register temporarily.
4. And finally, use a different CPU -- the 65816 comes to mind -- which offers a larger address space and the instructions needed to access it, wihch makes cheaper address decoding techniques viable again, and supports a 16MB address space.
Note, however, that the 65816 has a quirk -- when it boots up, it tries to fetch vectors from $00FFFx, not $FFFFFx. Because of this, you must use, at a minimum, an address decoder that properly handles at least 9 bits of address lines. Ouch!! Not cheap, not fast, and not pretty. It is possible to apply option 3E to the decoding of ROM addresses, of course, but again, I'd rather the CPU just not force me to have to segment my memory space into non-contiguous chunks in the first place.
These are some of the options you have available, and I hope I've answered your question.
kc5tja wrote:
I fail utterly to see how placing I/O in page 2 will give you more contiguous amounts of RAM. Indeed, it has precisely the opposite effect.
You'll end up with a system with RAM from $0000-$01FF, then a 256 byte gap, then $0300-$xxxx.
You'll end up with a system with RAM from $0000-$01FF, then a 256 byte gap, then $0300-$xxxx.
I also agree that bank switching is also a common practice that can effectively increase useable RAM.
My SBC-3 (65816 based) will have IO at $02xx and 512k of RAM. From $000300 to $07FFFF will be contiguous G.P. RAM. Yes, I know the 65816 can place the stack anywhere, and that zero page can effectively be moved as well, I am choosing to keep the traditional locations reserved for their purposes.
That is my current line of thinking. I hope that clears up my original comments.
Daryl
So many options.
kc5tja wrote:
I fail utterly to see how placing I/O in page 2 will give you more contiguous amounts of RAM. Indeed, it has precisely the opposite effect.
You'll end up with a system with RAM from $0000-$01FF, then a 256 byte gap, then $0300-$xxxx.
You'll end up with a system with RAM from $0000-$01FF, then a 256 byte gap, then $0300-$xxxx.
0000-00FF is the zero page and acts as special purpose registers
0100-01FF is the processor stack (on 6502) and can't be moved
If I stick all the device I/O at 0200-02FF AND I use all remaining addressing for RAM and ROM, then I think I get more flexibility for RAM/ROM tradeoffs. I can:
1) use a very small boot ROM (say 4K)
2) use a large ROM (say 32K)
3) or something in-between (like 16K)
and all the memory in between is contiguous and can be used for loading and running programs without having to worry about making sure holes are left for the I/O area.
Of course these assumptions may result in significantly more cost and/or complexity than I am not ready to deal with. Which is why I asked.
So, thank you for your answer.
kc5tja wrote:
...
These are some of the options you have available, and I hope I've answered your question.
These are some of the options you have available, and I hope I've answered your question.
-
smilingphoenix
- Posts: 43
- Joined: 20 May 2006
- Location: Brighton, England
When I was at university, some of my clever fellows realised that it was possible to add write-only I/O devices to a system without losing any of the memory map. Simply enable the ROM for read accesses only and then re-use the same addresses for your write registers. Since the ROM was a 16k device, their address decoding could be equally simple and sloppy with no loss of memory map.
If you are looking at possible spaces for I/O, you could always do what Acorn did with the BBC micro and use the address range FC00 - FEFF. This gave them a 15k ROM, 3/4K of I/O space and then a 256 byte ROM block which was only used for interrupt and MOS vectors. Incidently, if you put the Beeb's MOS rom in another system, the "missing" 3/4k holds all the credits for the system designers.
If you are looking at possible spaces for I/O, you could always do what Acorn did with the BBC micro and use the address range FC00 - FEFF. This gave them a 15k ROM, 3/4K of I/O space and then a 256 byte ROM block which was only used for interrupt and MOS vectors. Incidently, if you put the Beeb's MOS rom in another system, the "missing" 3/4k holds all the credits for the system designers.
Shift to the left, shift to the right,
mask in, mask out,
BYTE! BYTE! BYTE!
mask in, mask out,
BYTE! BYTE! BYTE!
smilingphoenix wrote:
When I was at university, some of my clever fellows realised that it was possible to add write-only I/O devices to a system without losing any of the memory map. Simply enable the ROM for read accesses only and then re-use the same addresses for your write registers. Since the ROM was a 16k device, their address decoding could be equally simple and sloppy with no loss of memory map.
...
...
Gapter wrote:
smilingphoenix wrote:
When I was at university, some of my clever fellows realised that it was possible to add write-only I/O devices to a system without losing any of the memory map. Simply enable the ROM for read accesses only and then re-use the same addresses for your write registers. Since the ROM was a 16k device, their address decoding could be equally simple and sloppy with no loss of memory map.
...
...
I'd say that this is suitable, at best, for devices running 3MHz or slower.
A CPLD version of this will go faster, but I predict that you'll end up dedicating a large amount of CPLD logic to this task.
- GARTHWILSON
- Forum Moderator
- Posts: 8773
- Joined: 30 Aug 2002
- Location: Southern California
- Contact:
kc5tja wrote:
SYNC (which is active-low, BTW) is asserted ONLY for the opcode byte; it is deasserted for the operand bytes that may follow. Therefore, it is possible to use this, but the logic involved will need to be aware of which opcode is being fetched, so that it can "remember" the SYNC state for the appropriate number of operand bytes.
65c02 datasheet wrote:
...The SYNC output is provided to identify those cycles whitch the microprocessor is fetching an OpCode. The SYNC line goes _high_ during the clock cycle of an OpCode fetch... ...In this manner, the SYNC signal can be used to control RDY to cause single_instruction_execution_.
OK, let's devide ROM into 2 sections. SHARED ROM share address space with I/O.
Code: Select all
+----------------+
| NONSHARED ROM |
| |
+----------------+
| SHARED ROM |
| |
+----------------+
| |can't access I/O for read
- Instructions from nonshared ROM:
can access I/O
can call soubrotines from shared ROM
can't access data from shared ROM
How to implement 'memory bank' switching?
Additional signals:
1. SYNC _rising_edge_ (with some delay) gives us signal that indicates opcode fetch - SYNC_S
2. Decoder gives us signal that indicates wich area (SHARED-1, NONSHARED-0) selected - SRA_S
may be like this:
Code: Select all
JK flip-flop
SRA_S +--------+
--------------------| J Q |------ ROM bank --
| |
SYNC_S | |
--------------------| clock |
| |
SRA_S |\NOT | _ |
-------| >o---------| K Q |------ I/O bank --
|/ +--------+-
smilingphoenix
- Posts: 43
- Joined: 20 May 2006
- Location: Brighton, England
If you want to use SYNC to determine whether to select ROM or I/O, you don't need to decode the instruction and work out how long the operand is. Simply assume that all instructions are three fetch cycles long. Any shorter instructions are either 1-byte long, in which case they only perform internal or stack operations, or 2 bytes long, in which case they are performing internal or page zero operations on the third cycle. After the third cycle, an instruction will be performing stack, page zero or data read/write cycles. The first two cases don't concern us, because they are not in ROM, and the third case is what we are interested in.
Deciding if a cycle is a code cycle or a data cycle only requires one IC, a basic 4 bit shift register with reset. Use the SYNC signal to reset the shift register. Hold the shift register serial input high. Use the falling edge of phase 2 or the rising edge of phase 1 to clock the shift register. When a 1 appears on the appropriate output, it indicates that code fetches are finished and subsequent cycles are data cycles and should access I/O instead of ROM.
This method does, of course, not allow for any data to be stored in the ROM. However, there is no reason why part of the I/O space should not be a second ROM, which of course could only contain data and not code.
I originally concieved this idea for switching two RAM areas, one that would only contain code and another that would contain data, allowing a full-featured assembler to be written for my acorn atom while still leaving a reasonable ammount of RAM free for the source code and assembler output. It never got implemented because I got one of those dreaded PCs and suddenly had lots of RAM available.
At one time, squeasing as much as possible into the limited address space of a 6502 was required, which is why ideas such as this one, paged RAM and the like were created. Nowadays, anything that requires this ammount of address space should really use a processor with a larger address range, such as the 65C816, so I guess this idea is somewhat academic.
Deciding if a cycle is a code cycle or a data cycle only requires one IC, a basic 4 bit shift register with reset. Use the SYNC signal to reset the shift register. Hold the shift register serial input high. Use the falling edge of phase 2 or the rising edge of phase 1 to clock the shift register. When a 1 appears on the appropriate output, it indicates that code fetches are finished and subsequent cycles are data cycles and should access I/O instead of ROM.
This method does, of course, not allow for any data to be stored in the ROM. However, there is no reason why part of the I/O space should not be a second ROM, which of course could only contain data and not code.
I originally concieved this idea for switching two RAM areas, one that would only contain code and another that would contain data, allowing a full-featured assembler to be written for my acorn atom while still leaving a reasonable ammount of RAM free for the source code and assembler output. It never got implemented because I got one of those dreaded PCs and suddenly had lots of RAM available.
At one time, squeasing as much as possible into the limited address space of a 6502 was required, which is why ideas such as this one, paged RAM and the like were created. Nowadays, anything that requires this ammount of address space should really use a processor with a larger address range, such as the 65C816, so I guess this idea is somewhat academic.
Shift to the left, shift to the right,
mask in, mask out,
BYTE! BYTE! BYTE!
mask in, mask out,
BYTE! BYTE! BYTE!