6502.org http://forum.6502.org/ |
|
PLD Coding for 65816 Memory Map - Are these equivalent? http://forum.6502.org/viewtopic.php?f=10&t=7122 |
Page 1 of 6 |
Author: | tmr4 [ Sat May 14, 2022 6:52 pm ] |
Post subject: | PLD Coding for 65816 Memory Map - Are these equivalent? |
I'm trying to code the following memory map for the PLD address decoder for my 65816: Code: RAM $0000-$FEFF ROM $FF00-$1FFFF I/O $20000-$200FF EXRAM $20100-$7FFFF It wouldn't fit within my PLD with the following logic: Code: FIELD Address = [A18..A8]; RAM = Address:[0000..FFFF]; ROM = Address:[FF00..1FFFF]; EXRAM = Address:[20000..7FFFF]; IO = Address:[20000..200FF]; !RAM_CS = (RAM & !ROM) # (EXRAM & !IO); !ROM_CS = ROM & RW; !IO_CS = IO; But the following logic does work: Code: FIELD Address = [A18..A8]; ROM = Address:[FF00..1FFFF]; IO = Address:[20000..200FF]; !ROM_CS = ROM & RW; !IO_CS = IO; !RAM_CS = ROM_CS & IO_CS; Are the two expressions for RAM_CS equivalent? The second one does work in my build so far, but my operating system is still a bit basic. Edit (5/17/2022): For those finding this in the future, the straightforward: Code: FIELD Address = [A18..A8]; RAM = Address:[0000..FEFF]; ROM = Address:[FF00..1FFFF]; IO = Address:[20000..200FF]; EXRAM = Address:[20100..7FFFF]; !RAM_CS = RAM # EXRAM; !ROM_CS = ROM & RW; !IO_CS = IO; will compile in WINCUPL with the Quine-McCluskey minimization option enabled. Read further in this post for background and details. |
Author: | akohlbecker [ Sat May 14, 2022 8:41 pm ] |
Post subject: | Re: PLD Coding for 65816 Memory Map - Are these equivalent? |
Hey! Fun problem to work through, hope this helps. From the first logic we get, using DeMorgan's law: RAM_CS = !(RAM & !ROM) & !(EXRAM & !IO) We can apply the law to each group as well, which gives: RAM_CS = (!RAM # ROM) & (!EXRAM # IO) Or, because distributivity works in boolean logic, RAM_CS = !RAM&!EXRAM # ROM&!EXRAM # !RAM&IO # ROM&IO From your memory map !RAM&!EXRAM is equal to a subset of ROM [10000..1FFFF] ROM&!EXRAM is equal to ROM !RAM&IO is equal to IO ROM&IO is always false so RAM_CS = [10000..1FFFF] # ROM # IO # 0 = ROM # IO (we can ignore the subset of ROM ORed with ROM) From your second logic !RAM_CS = ROM_CS & IO_CS gives you RAM_CS = !ROM_CS # !IO_CS = (ROM & RW) # IO So they're not strictly equivalent. The second one also activates the RAM when you're writing to ROM space, which you might not want because your RAM doesn't occupy the whole ROM space. |
Author: | BigDumbDinosaur [ Sat May 14, 2022 9:08 pm ] |
Post subject: | Re: PLD Coding for 65816 Memory Map - Are these equivalent? |
tmr4 wrote: I'm trying to code the following memory map for the PLD address decoder for my 65816: What type of PLD is this you are programming? That matters if we are going to help you figure out your problem. Also, could you please post the entire source code, not just fragments? You should be aware that placing I/O hardware at an extended address as you are doing will probably complicate your firmware in several ways. Assuming I/O is interrupt-driven, you would be forced to use long addressing for all I/O accesses within the interrupt handler (ISR). That will negatively affect performance because inter-bank accesses require one more clock cycle per access than do accesses using 16-bit (absolute) addressing. In particular, long accesses using R-M-W instructions will incur multiple clock cycle “penalties” per instruction. As described here, succinctness is a primary goal in ISRs—time spent processing IRQs is time not available to process foreground tasks. The fewer addressing shenanigans required to access I/O and runtime data structures, the more performance you will achieve at any given Ø2 rate. Alternatively, you could split your ISR between bank $00 and the I/O bank and JML to the rest of the ISR. The single long jump would be less “expensive” than repeated long accesses. However, since the ISR's preamble must be in bank $00, you may find firmware development to be too convoluted. Either way, I recommend you give this more thought before committing to a particular memory map. |
Author: | tmr4 [ Sat May 14, 2022 9:27 pm ] |
Post subject: | Re: PLD Coding for 65816 Memory Map - Are these equivalent? |
akohlbecker wrote: So they're not strictly equivalent. The second one also activates the RAM when you're writing to ROM space, which you might not want because your RAM doesn't occupy the whole ROM space. Thanks Adrien. Very interesting analysis. I always struggle getting my head around those equivalencies. I'm not sure I understand your last point. Physically my RAM does occupy the entire ROM space as I'm using 256k ROM and 512k RAM, both directly wired to the address bus. Thus, as you point out, a write to ROM would also write to RAM, but from a system perspective would be nonconsequential since nothing is expected in the overlapping region. Better still, in my system, writes to ROM would be an error. I hope I don't have any of those. |
Author: | tmr4 [ Sat May 14, 2022 10:03 pm ] |
Post subject: | Re: PLD Coding for 65816 Memory Map - Are these equivalent? |
BigDumbDinosaur wrote: What type of PLD is this you are programming? I'm using an ATF22V10C. BigDumbDinosaur wrote: Also, could you please post the entire source code, not just fragments? My complete code in the second case is: Code: Device g22V10 ; /* Input */ Pin 1 = CLK; Pin 2 = RW; Pin [3..10] = [A15..A8]; Pin 11 = A16; Pin 22 = A17; Pin 13 = VIA_IRQ1; Pin 14 = A18; Pin 15 = ACIAs_IRQ; /* Output */ Pin 16 = CLKB; Pin 17 = WE; Pin 18 = ROM_CS; Pin 19 = RAM_CS; Pin 20 = OE; Pin 21 = IO_CS; Pin 23 = IRQ; /* Local Variables */ FIELD Address = [A18..A8]; /* Logic */ ROM = Address:[FF00..1FFFF]; IO = Address:[20000..200FF]; CLKB = !CLK; !WE = CLK & !RW; !OE = CLK & RW; !ROM_CS = ROM & RW; !IO_CS = IO; !RAM_CS = ROM_CS & IO_CS; IRQ = VIA_IRQ1 & ACIAs_IRQ; I'm using WINCUPL and the TL866II+ programmer. BigDumbDinosaur wrote: You should be aware that placing I/O hardware at an extended address as you are doing will probably complicate your firmware in several ways. Assuming I/O is interrupt-driven, you would be forced to use long addressing for all I/O accesses within the interrupt handler (ISR). Some of my I/O is interrupt driven. My ISR is in ROM located in the page $FF00. I placed I/O in bank 2 because that's where I'm currently placing RW data. Thus, by setting the data bank register to 2 I can address both my data and I/O with 16-bit absolute address. I figured I'd use another address mode for banks above that, but I'll admit I haven't given it much thought. At this point even three banks of memory seems like a luxury. Honestly, I have on my to do list some of your posts on the subject, so I have a lot more learning to do. BigDumbDinosaur wrote: Either way, I recommend you give this more thought before committing to a particular memory map. Yes, this is a work in progress. I'm not wedded to a particular scheme yet. So far I've just converted my hardware related code from the 6502. As I convert my Forth related code I'm sure I'll come across things that require more consideration. |
Author: | akohlbecker [ Sat May 14, 2022 10:30 pm ] |
Post subject: | Re: PLD Coding for 65816 Memory Map - Are these equivalent? |
tmr4 wrote: akohlbecker wrote: So they're not strictly equivalent. The second one also activates the RAM when you're writing to ROM space, which you might not want because your RAM doesn't occupy the whole ROM space. Thanks Adrien. Very interesting analysis. I always struggle getting my head around those equivalencies. I'm not sure I understand your last point. Physically my RAM does occupy the entire ROM space as I'm using 256k ROM and 512k RAM, both directly wired to the address bus. Thus, as you point out, a write to ROM would also write to RAM, but from a system perspective would be nonconsequential since nothing is expected in the overlapping region. Better still, in my system, writes to ROM would be an error. I hope I don't have any of those. I was looking at this specifically: Code: RAM = Address:[0000..FFFF]; ROM = Address:[FF00..1FFFF]; RAM is overlapping ROM between FF00 and FFFF. Which I didn't think through fully to realize you were overlaying them on top of each other in the chip select definitions below. For clarity/safety you might want to write RAM = Address:[0000..FEFF]. Even though it works in this file, since you're doing RAM & !ROM for RAM_CS, you're one mistake away (forgetting to &!ROM) from enabling both chip selects at the same time. Same thing for EXRAM = Address:[20100..7FFFF]. Then you can also do !RAM_CS = RAM # EXRAM which is easier to read |
Author: | akohlbecker [ Sat May 14, 2022 10:34 pm ] |
Post subject: | Re: PLD Coding for 65816 Memory Map - Are these equivalent? |
Also agree that putting I/O in bank 0 is the way to go; I use the end of the core RAM space for this in my design. Attachment: EDIT: Although, with changing the data bank register that might work. Sorry it is late I missed that part of your message. So if data is in bank 2, what are you putting in bank 0 besides the direct page? Stack? |
Author: | BigDumbDinosaur [ Sat May 14, 2022 10:46 pm ] |
Post subject: | Re: PLD Coding for 65816 Memory Map - Are these equivalent? |
tmr4 wrote: BigDumbDinosaur wrote: What type of PLD is this you are programming? I'm using an ATF22V10C. All the more reason to be conservative with your memory map. The 22V10 doesn't have a lot of logic resources. The more granular your hardware decoding becomes, the greater the likelihood of coming up with a design that won't fit. Quote: My complete code in the second case is...I'm using WINCUPL and the TL866II+ programmer. What is the purpose of the CLKB output? Here are some observations, in no particular order:
Quote: Some of my I/O is interrupt driven. Some? Why not all of it? The 816, like the 8-bit 6502 family, has excellent interrupt performance. Why not take advantage of that? Quote: My ISR is in ROM located in the page $FF00. That only gives you 256 bytes in which to stuff the ISR, along with the hardware vectors, and the reset front end. I think you will regret that choice once you get serious about writing reasonably-comprehensive firmware. Something else to consider is this: if an application is running in any bank other than the one in which the firmware is visible and if the firmware API is accessed as a set of subroutines, the application will be using JSL — RTL to call APIs. Those two are some of the slowest instructions in the 816's ISA. The alternative method for calling APIs, and the one I am using, is to use COP and an API index as COP’s signature, a method that is bank-agnostic and as fast as JSL — RTL. Quote: I placed I/O in bank 2 because that's where I'm currently placing RW data. Thus, by setting the data bank register to 2 I can address both my data and I/O with 16-bit absolute address. Yes, that will work. However, if you decided to use the 816’s stack relative addressing mode, it will be accessing bank $00—the data bank register (DB) will not be a factor in generating the effective address. Quote: I figured I'd use another address mode for banks above that, but I'll admit I haven't given it much thought. At this point even three banks of memory seems like a luxury. Honestly, I have on my to do list some of your posts on the subject, so I have a lot more learning to do. While use of a PLD in place of discrete logic does confer flexibility, as well as greatly reduce chip count, the 816 itself knows nothing about all that. You should arrange the memory map to minimize cross-bank accesses as much as possible. When cross-bank accesses become necessary, the [<dp>] and [<dp>],Y addressing modes are your friend. |
Author: | tmr4 [ Sat May 14, 2022 11:06 pm ] |
Post subject: | Re: PLD Coding for 65816 Memory Map - Are these equivalent? |
akohlbecker wrote: For clarity/safety you might want to write RAM = Address:[0000..FEFF]. The problem is this requires more product term than the PLD pin provides. That's why I've used the overlapping range with logic to exclude the ROM range from RAM. |
Author: | tmr4 [ Sat May 14, 2022 11:10 pm ] |
Post subject: | Re: PLD Coding for 65816 Memory Map - Are these equivalent? |
akohlbecker wrote: So if data is in bank 2, what are you putting in bank 0 besides the direct page? Stack? Direct page, return stack and Forth data stack and likely multiple instances of them. But this is just a thought at this point. Much like the 6502 zero page, it seems a waste to use the 65816 bank 0 for normal data and code. |
Author: | Dr Jefyll [ Sun May 15, 2022 12:03 am ] |
Post subject: | Re: PLD Coding for 65816 Memory Map - Are these equivalent? |
Hmm, several new posts. I'm falling behind! But... akohlbecker wrote: Also agree that putting I/O in bank 0 is the way to go ... can either of you clarify this preference for I/O being in Bank $00? I do see why I might choose Bank $00 for I/O because of hardware issues. For example, maybe I intend to use an 8-input NOR gate to decode the bank address, in which case banks other than $00 don't go with the flow -- $00 is very clearly preferred because it agrees with how I want the hardware arranged.But I don't see much value in choosing Bank $00 for I/O because of software issues, even in the context of an ISR. BigDumbDinosaur wrote: you would be forced to use long addressing for all I/O accesses within the interrupt handler (ISR). That will negatively affect performance because inter-bank accesses require one more clock cycle per access than do accesses using 16-bit (absolute) addressing. It's true that long accesses incur a penalty, and of course we'd prefer to avoid that. But I'm doubtful that having I/O appear in Bank $00 is of much use for avoiding that penalty. The Program Bank Register PBR gets pushed to stack when an interrupt is recognized, and also a new value (ie, $00) written to it. This is crucial. The Data Bank Register DBR does not get pushed to stack (booboo edited as per your correction, tmr4 -- thx), and -- more to the point -- neither is a new value written to it -- DBR remains unchanged from the value it had prior to the interrupt. So, if the ISR explicitly updates DBR then the penalty can be avoided. Or, the DBR update becomes unnecessary if we make a rule that the foreground code must disable interrupts anytime it wants to use a DBR value other than $00, but this is an unappealing compromise. That's why I say having I/O appear in Bank $00 isn't a very useful shortcut for avoiding the penalty I'm drawing a blank on your suggestion to "split your ISR between bank $00 and the I/O bank and JML to the rest of the ISR." Like an interrupt, JML fails to update DBR. And can you supply a reference for your statement that long accesses using R-M-W instructions will incur multiple clock cycle penalties per instruction? Long address modes do mean the instruction will include a three-byte address, and certainly it costs an extra cycle to fetch that additional byte. But AFAIK the penalty only applies once, even in the case of a R-M-W -- Jeff |
Author: | tmr4 [ Sun May 15, 2022 12:10 am ] | ||
Post subject: | Re: PLD Coding for 65816 Memory Map - Are these equivalent? | ||
Thanks for the review and comments. I still have a lot to consider. In answer to your questions: BigDumbDinosaur wrote: What is the purpose of the CLKB output? It provides the inverted clock signal needed by the bank address latch and data bus buffer. Using the PLD for this saves a chip in my build. I've attached an image of the breadboard version (btw - I got the 64k, 12 ns RAM version of this up to 10 MHz before I started seeing stability issues). Ultimately I plan on a small handheld unit. BigDumbDinosaur wrote:
I've tried a number of ways to express the logic but the second method was the only one I got to work for a single page of ROM at the end of bank 0. I could get the wider ROM range of $F000-$FFFF to work with RAM of $0000-$EFFF, but I don't need that much ROM in bank 0. I'll see if some of Adrien's other suggestions work though. I'm definitely a novice on WINCUPL. BigDumbDinosaur wrote:
Looks like I picked up some bad coding practices on the web. I guess it's easy to do. There are so few examples of concise coding for address decoders. Lots of bad stuff though, like where they do all of WINCUPL work on a spreadsheet and then import it. BigDumbDinosaur wrote: Quote: Some of my I/O is interrupt driven. Some? Why not all of it? The 816, like the 8-bit 6502 family, has excellent interrupt performance. Why not take advantage of that? I'm using the 65C51 and the transmitter can't be interrupt driven. BigDumbDinosaur wrote: Quote: My ISR is in ROM located in the page $FF00. That only gives you 256 bytes in which to stuff the ISR, along with the hardware vectors, and the reset front end. I think you will regret that choice once you get serious about writing reasonably-comprehensive firmware. My reset front end is in bank 1. I long jump to it from page $FF00. As I've seen you advise, my ISR is short. BigDumbDinosaur wrote: Something else to consider is this: if an application is running in any bank other than the one in which the firmware is visible and if the firmware API is accessed as a set of subroutines, the application will be using JSL — RTL to call APIs. Those two are some of the slowest instructions in the 816's ISA. The alternative method for calling APIs, and the one I am using, is to use COP and an API index as COP’s signature, a method that is bank-agnostic and as fast as JSL — RTL. Thanks. I'll keep this in mind. Right now I'm very far from fully using much of either bank 1 or 2. My 6502 hardware and Forth primitives use less than 9k of ROM and my Forth code and dictionary probably use an equal amount of RAM. I expect that to go down with the 65816. BigDumbDinosaur wrote: Quote: I placed I/O in bank 2 because that's where I'm currently placing RW data. Thus, by setting the data bank register to 2 I can address both my data and I/O with 16-bit absolute address. Yes, that will work. However, if you decided to use the 816’s stack relative addressing mode, it will be accessing bank $00—the data bank register (DB) will not be a factor in generating the effective address. Yes, I still have a lot to think about along those lines. BigDumbDinosaur wrote: Quote: I figured I'd use another address mode for banks above that, but I'll admit I haven't given it much thought. At this point even three banks of memory seems like a luxury. Honestly, I have on my to do list some of your posts on the subject, so I have a lot more learning to do. While use of a PLD in place of discrete logic does confer flexibility, as well as greatly reduce chip count, the 816 itself knows nothing about all that. You should arrange the memory map to minimize cross-bank accesses as much as possible. When cross-bank accesses become necessary, the [<dp>] and [<dp>],Y addressing modes are your friend. I think I was hoping to rely on one of the busted myths form your 65816 Facts and Myths post, that the 65816 banks could be addressed as a whole. I haven't considered it much beyond that, so it's currently just an idea (hope?) that I'm hanging onto right now.
|
Author: | tmr4 [ Sun May 15, 2022 12:13 am ] |
Post subject: | Re: PLD Coding for 65816 Memory Map - Are these equivalent? |
Dr Jefyll wrote: Program Bank Register PBR and Data Bank Register DBR both get pushed to stack when an interrupt is recognized, but according to the doc I've seen so far only PBR gets a new value (ie, $00) written to it, whereas DBR remains unchanged. I'm really new to the game here, but I thought only the program bank register was pushed to the stack on an interrupt. |
Author: | Dr Jefyll [ Sun May 15, 2022 12:25 am ] |
Post subject: | Re: PLD Coding for 65816 Memory Map - Are these equivalent? |
tmr4 wrote: I'm really new to the game here, but I thought only the program bank register was pushed to the stack on an interrupt. Doh -- sorry, you're right; DBR doesn't get pushed. My mistake; comes with typing in a hurry. However, I did and still do mean to say that, unlike PBR, DBR does not get a new value placed in it when an interrupt occurs. This is central to my post.-- Jeff |
Author: | tmr4 [ Sun May 15, 2022 12:33 am ] |
Post subject: | Re: PLD Coding for 65816 Memory Map - Are these equivalent? |
Dr Jefyll wrote: However, I did and still do mean to say that, unlike PBR, DBR does not get a new value placed in it when an interrupt occurs. This is central to my post. Yes and that's what my current system relies on. DBR is set to bank 2 on start up and with I/O in bank 2 I don't need to change it again, either in the ISR or in my other code. Still to be considered though is what I do when I exceed bank 2 for data. Still thinking about that. |
Page 1 of 6 | All times are UTC |
Powered by phpBB® Forum Software © phpBB Group http://www.phpbb.com/ |