• Please review our updated Terms and Rules here

6502 branch at page boundaries

I have been looking at an old listing of FIG Forth for the 6502. I mentions the issue and stated it was best to pad with two nops.
I suspect the feature I was looking at was on pre-1975 processors. Since I have none that old to try it on, it is likely a non-issue.
I do recall a demonstration of the problem years ago at an early Forth meeting.
I got side tracked on updating a 6502 disassembler I'd written years ago, for another project.
Dwight
This was to work around the indirect jump bug mentioned above - the first entry in each dictionary entry was an pointer to the code. NEXT would do an indirect JMP (W) through that pointer. And, the figForth listing doesn't take into account the case where the built-in words would cross a page boundary. John B. Matthews wrote a macro in his update of figForth for Apple ProDOS to explicitly test for page crossings and throw an assembler error if it occurred (macro NAME):


This would affect all NMOS 6502s. The only bug that caused a re-spin of the silicon was the ROR bug in the first 6502s.
 
This was to work around the indirect jump bug mentioned above
Correct, this has nothing to do with branches. Fig Forth uses the JMP Indirect capability for its NEXT routine, and in the original listing it's on the developer to properly pad the built in dictionary to make sure none of them started on $xxFF. Basically, you needed to scan the assembler listing for anything suspicious, and fix them individually until it came up clean.

Fig Forth uses zero page RAM to store the JMP (xxxx) instruction, because it modifies the actual arguments to JMP. Zero page is used because it's guaranteed to be RAM on a 6502, whereas the rest can be mostly ROM.

This is what the FIG listing says:
Code:
;    
;    The following offset adjusts all code fields to avoid an
;    address ending $XXFF. This must be checked and altered on
;    any alteration , for the indirect jump at W-1 to operate !
;    
          .ORIGIN *+2

But that offset can be anywhere.
 
Yes, that's what I found.

Of course, the assembler should be able to do all of the 'magic' itself if the right pseudo-ops were included...

Dave
 
the assembler should be able to do all of the 'magic' itself if the right pseudo-ops were included...
How so?

To be clear, the JMP bug is when you do, say, JMP $CCFF. Rather than pulling the address from $CCFF and $CD00, it pulls the address from $CCFF and $CC00. There's no problem with the contents of the address ending in FF.

So if you're coding: JMP (LABEL), and the assembler knows that LABEL evaluates to $xxFF, at best the assembler should spit out an error/warning about this. I can't see the assembler blindly inserting gaps in the program to tweak the address. Make the developer choose where to put things.

With regards to Fig Forth, the system is dynamically creating the JMP instruction (this is, technically, "self modifying code"), so that's why its a concern as to where the Code Field Addresses land in the source assembly, since those address are what shoved into that JMP instruction.
 
What you do is to add a bit of macro code to the TARGETs of the indirect jump to ensure that the word definition itself can't lie at this erroneous address.

The user has access to the assembler's location counter as it is being accessed, so you do a little bit of maths on the provided location counter (along with any other local labels as necessary) and insert some dummy NOPs (or other pad bytes) if required.

However, this does involve including macro expansion code before each word.

This sort of thing is inherent in assembler pseudo-ops such as .EVEN, .ALIGN n etc. (depending upon your assembler).

I am not saying that the assembler is smart enough to do it all on its own. It needs a little help from a human - and the assumption that MACROS are supported by the assembler (of course).

Dave
 
Check out the macros John wrote in the ProDOS port. His simply flags destination page crossing as an error but it would be easy to add a NOP to move the label across the boundary. But this only works on known labels. During compilation you’d have to add a little logic to skip over page crossings. All very doable
 
In the case of Forth you already have a header for each WORD definition - so that is easily accommodated.

For other assembly code - the coder has to be aware of the problem and specifically include code at the targets of the indirect jumps (as long as they are pre-known of course).

Suitable comments of course...

Dave
 
The SYM2 was intended to be a less expansive version of the SYM1. It is clearly not as flexible as the SYM1. The board I have is likely an early prototype. It has some ugly design errors that keep it from being useful for my intended purposes. It does boot and run the monitor. The major issue I see so far is that it didn't properly select where the RAM goes.I see repeated blocks of it scattered through the memory map, especially in the lower half of memory.
I'm not one that objects to keeping it exactly as it came from the manufacture. Being useful has got higher priority to me. I'll be adding a 74LS27 to properly select the RAM address range. It is not a good idea to have things like the stack scattered at different memory locations. The same for page0.
I don't have a schematic for it so I've been tracing connection ( a real pain as the meter I have doesn't have a beeper ).
I wanted to use it fro the EPROM board that I have. The code on it is intended to run on a AIM65 so I'll need to deal with that ( I do have a AM65 though ).
I've not figured out the EPROM board but I suspect it is intended to program 2716 and 2732 at least.
 
I'm not one that objects to keeping it exactly as it came from the manufacture. Being useful has got higher priority to me. I'll be adding a 74LS27 to properly select the RAM address range. It is not a good idea to have things like the stack scattered at different memory locations. The same for page0.

FWIW, partial decoding like that is pretty common on minimal computer designs. It's not really actually a problem unless you mistake the "shadows" for more usable memory.
 
>>> It's not really actually a problem unless you mistake the "shadows" for more usable memory.

On the Sinclair MK14 computer, things were partially decoded permanently. This resulted in some programmers using different addresses for things like the keyboard and display.

One if the later 'hacks' was to add more memory to the machine. In order to fill it to the maximum, you had to fully decode all of the devices. This could result in some software now misbehaving.

There was an 'official' address for devices. But, sometimes, these official addresses were ignored and one of the 'shadows' used. This is where the compatability problems started.

Dave
 
>>> It's not really actually a problem unless you mistake the "shadows" for more usable memory.

On the Sinclair MK14 computer, things were partially decoded permanently. This resulted in some programmers using different addresses for things like the keyboard and display.

One if the later 'hacks' was to add more memory to the machine. In order to fill it to the maximum, you had to fully decode all of the devices. This could result in some software now misbehaving.

There was an 'official' address for devices. But, sometimes, these official addresses were ignored and one of the 'shadows' used. This is where the compatability problems started.

Dave
I also have a SYM-1.It fully decodes the RAM address. Like most 6502 ROM setups it does doubly decodes parts of the ROM to the reset vectors.
There is no funny business there.
I see no valid reason to have the RAM decoded at all addresses other than that specific to ROM or I/O. I especially don't think page 0 and page 1 should no be scattered across the addresses.
The SYM-2 should not do anything different than the SYM-1 without purpose. If the purpose was to to make it easy to crash the system, poorly addressed locations would make it more likely. I'd like to see some documentation on the SYM-2 but have only found documentation for the SYM-1. There is nothing about scattering page 0 on purpose. It is properly decoded.
Dwight
 
I see no valid reason to have the RAM decoded at all addresses other than that specific to ROM or I/O. I especially don't think page 0 and page 1 should no be scattered across the addresses.
The SYM-2 should not do anything different than the SYM-1 without purpose. If the purpose was to to make it easy to crash the system, poorly addressed locations would make it more likely. I'd like to see some documentation on the SYM-2 but have only found documentation for the SYM-1. There is nothing about scattering page 0 on purpose. It is properly decoded.

I'm a little unclear why partial decoding is going to "make it easy to crash the system"? I mean, obviously there are downsides to the practice; on any computer that has an available bus it wastes address space that could be used for expansion, and it also has the potential to create backwards compatibility issues if programmers elect to use a mirror in place of the "official" address for whatever reason and you later revise the hardware to impose fuller decoding later. (I think in theory this applies to, say, the Commodore PET, because it uses *very* partial decoding for its I/O area that not only allows every chip to be addressed at multiple addresses it allows multiple chips to be activated at once, and CRTC and non-CRTC PETs end up with a different total bitmap of shadow'ed addresses...)...

But in a vacuum, if you're talking about a simple single-board fixed configuration machine with X amount of RAM it seems like a reasonable expectation that any software that inadvertently runs outside of the valid RAM footprint is going to crash regardless of whether there's a shadow of the real memory or empty space there? That a second copy of the zero page exists one byte past the end of real memory is only going to be a problem if you write software that's manipulating some data structure in high memory and because of poor bounds checking you keep writing past the end of the object?

Anyway, this is all theoretical, really; in this particular case this sure reads like this (particular?) SYM2 computer has a hardware bug. Scanning the manual of the SYM1 I agree, it does read like its 4K of onboard RAM sockets are fully decoded. It seems like there's almost no documentation out there for this beast(*) but what there is claims it should be compatible with hardware add-ons with its predecessor so by all means fix it.

(* Have you managed to find *any* manuals for the SYM2? I'm guessing this must have come out near the end of the company's life. Bitsavers has nothing but tumbleweeds...)

On the Sinclair MK14 computer, things were partially decoded permanently. This resulted in some programmers using different addresses for things like the keyboard and display.

On the other end of the sophistication spectrum I know a number of Macintosh models used really sloppy decoding internally, with shadows of RAM and ROM all over the place. It's even my vague recollection that some '030/'040 models with multiple SIMM banks actually relied on using the CPU's built-in MMU to assemble linear memory address space because the socket banks were permanently separated by fixed offsets that would be filled with blocks of repeated memory when used with less-than-maximum-size SIMMs. (The thinking being the MMU was there, why not use it and save a few transistors in the memory controller?)

The TRS-80 Model I/III annoyingly wastes an entire 1K of address space for keyboard scanning; it *should* "only" waste 256 bytes, but they didn't fully decode the 1K boundary they dropped it into. I've been sketching out a TRS-80 semi-clone and I'm wondering how much incompatibility it'd cause if I cut down that window; I gather there is at least some software that's pretty careless about treating the entire block as free game for scanning, not just the bottom 1/4k.
 
Back
Top