6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sun Nov 24, 2024 10:42 am

All times are UTC




Post new topic Reply to topic  [ 8 posts ] 
Author Message
PostPosted: Sat Mar 09, 2024 9:30 pm 
Offline

Joined: Tue Apr 12, 2016 6:30 pm
Posts: 13
Hi all,

I’m working a project that is based on an existing TTL logic-based design, where a 6502 shares a data bus with a 6522 and a ROM chip. It then shares this bus with external peripherals with an old DM8304 bidirectional buffer acting as gatekeeper which is controlled by other logic.

I’m trying to incorporate the same setup, but connecting a FPGA on this shared bus, mainly for its onboard SDRAM. The FPGA handles the glue logic throughout the system, including the signal to let the data pass between it and the shared bus.

But I’m not getting stellar results. Rather, when this “dm8304 enable” signal is active on the ‘02’s write, I’m only getting 8’bZ on my FPGA’s i/o.

In my FPGA, I’m doing a bidirectional bus this way (in Verilog):

inout wire [7:0] data;

assign data = (r_w) ? data_to_cpu : 8’bZ;
assign data_from_cpu = data;

I’ve also tried using the FPGA’s primitives to handle the bidirectional transactions.

My question is, should it be ok for my FPGA to be hooked directly to this external shared bus, and acting internally as the 8304 (or74245) and passing the data through in a tri-state manner? Or is it better practice to use an actual bidirectional buffer chip between this data bus and my FPGA’s GPIO, which the FPGA can control?

For this setup, my external chips are a WDC 65c02 and a WDC 65c22, operating at 3.3v, the same as the FPGA (iCESugar-Pro (Lattice ECP5)).

Thanks!

PS: I’ve tried creating a bin file through both Lattice Diamond and the Yosys/nextpnr/ecppack tool chain with similar results.


Top
 Profile  
Reply with quote  
PostPosted: Sat Mar 09, 2024 11:33 pm 
Offline

Joined: Mon Sep 17, 2018 2:39 am
Posts: 138
Hi!

czuhars wrote:
Hi all,

I’m working a project that is based on an existing TTL logic-based design, where a 6502 shares a data bus with a 6522 and a ROM chip. It then shares this bus with external peripherals with an old DM8304 bidirectional buffer acting as gatekeeper which is controlled by other logic.

I’m trying to incorporate the same setup, but connecting a FPGA on this shared bus, mainly for its onboard SDRAM. The FPGA handles the glue logic throughout the system, including the signal to let the data pass between it and the shared bus.

But I’m not getting stellar results. Rather, when this “dm8304 enable” signal is active on the ‘02’s write, I’m only getting 8’bZ on my FPGA’s i/o.

In my FPGA, I’m doing a bidirectional bus this way (in Verilog):

inout wire [7:0] data;

assign data = (r_w) ? data_to_cpu : 8’bZ;
assign data_from_cpu = data;

I’ve also tried using the FPGA’s primitives to handle the bidirectional transactions.

My question is, should it be ok for my FPGA to be hooked directly to this external shared bus, and acting internally as the 8304 (or74245) and passing the data through in a tri-state manner? Or is it better practice to use an actual bidirectional buffer chip between this data bus and my FPGA’s GPIO, which the FPGA can control?

For this setup, my external chips are a WDC 65c02 and a WDC 65c22, operating at 3.3v, the same as the FPGA (iCESugar-Pro (Lattice ECP5)).

Thanks!

PS: I’ve tried creating a bin file through both Lattice Diamond and the Yosys/nextpnr/ecppack tool chain with similar results.


You don't use bidirectional signals in a FPGA, as those are not supported in the internal fabric. You use two separate busses, one for input and one for output. And then, you use bidirectional I/O pins in the FPGA, that should have control signals for enabling/disabling the output buffer.

You should read your FPGA manual on how to instantiate the bidirectional I/O. According to the manual at https://www.latticesemi.com/-/media/Lat ... t_id=50464 , you need to instantiate a "BB" component, the example in page 23 is:

Code:
BB buf7 (.I(Q_out7), .T(Q_tri7), .O(buf_Data7), .B(Data[7]));


There, 'T' is the "tri-state' input, 'I' the input from the FPGA to the pin, 'O' the output to the FPGA from the pin, and 'B' is the actual FPGA pin.

Have Fun!


Top
 Profile  
Reply with quote  
PostPosted: Sun Mar 10, 2024 7:58 am 
Offline

Joined: Tue Sep 03, 2002 12:58 pm
Posts: 336
dmsc wrote:
You don't use bidirectional signals in a FPGA, as those are not supported in the internal fabric. You use two separate busses, one for input and one for output. And then, you use bidirectional I/O pins in the FPGA, that should have control signals for enabling/disabling the output buffer.


That's what czuhars has. There are no tristate signals in the internal logic; only on the I/O signals. data_to_cpu and data_from_cpu are the separate busses you're talking about.

And while you can explicitly instantiate tristate I/O primitives, you shouldn't have to. Doing so ties your design to one particular FPGA and makes it harder to port. I've used an equivalent design (in VHDL, on a Spartan6) before and had it work - synthesis should convert the tristate into the right primitives, or complain if it can't.

Is it possible that the error is in the logic that supplies the r_w signal? I strongly recommend setting up a testbed and running it through a simulator. Or you could route r_w to a spare pin and look at that. FPGA designs get nasty to debug when you can't see what's happening inside.


Top
 Profile  
Reply with quote  
PostPosted: Sun Mar 10, 2024 6:05 pm 
Offline

Joined: Tue Nov 10, 2015 5:46 am
Posts: 230
Location: Kent, UK
czuhars wrote:
In my FPGA, I’m doing a bidirectional bus this way (in Verilog):

inout wire [7:0] data;

assign data = (r_w) ? data_to_cpu : 8’bZ;
assign data_from_cpu = data;

Yes, that's the correct pattern to attach to a bidirectional bus.

Other than that, making sure your FPGA signal standard (voltage, current) is compatible with the rest of the bus.

Good luck!


Top
 Profile  
Reply with quote  
PostPosted: Sun Mar 10, 2024 11:21 pm 
Offline

Joined: Mon Sep 17, 2018 2:39 am
Posts: 138
Hi!

John West wrote:
dmsc wrote:
You don't use bidirectional signals in a FPGA, as those are not supported in the internal fabric. You use two separate busses, one for input and one for output. And then, you use bidirectional I/O pins in the FPGA, that should have control signals for enabling/disabling the output buffer.


That's what czuhars has. There are no tristate signals in the internal logic; only on the I/O signals. data_to_cpu and data_from_cpu are the separate busses you're talking about.


You are right, I missread.

About instantiating the tristate I/O, I prefer to do that because normally you can then select buffer parameters like speed and voltages.

Have Fun!


Top
 Profile  
Reply with quote  
PostPosted: Tue Mar 12, 2024 9:47 pm 
Offline

Joined: Tue Apr 12, 2016 6:30 pm
Posts: 13
Thanks a ton for the feedback. At least I have a better idea that I’m on the right path.

I created a very simple test project to allow me to check the incoming data bus value on r_w active low (cpu write) for a given address. I’m using the BB primitive for the Lattice ECP5 in synthesis and the method mentioned above for simulation.

Here’s the weirdness: When a inout pin is configured as such in my top level module:

BB i_data0 (.B(i_data[0]), .I(data_to_cpu[0]), .O(data_from_cpu[0]), .T(r_w));
data_from_cpu is supposed to be the value during a write from the cpu to be processed inside the FPGA.
data_to_cpu is for when I want the FPGA to send data to the cpu.

The data_from_cpu is accurate, but only on the r_w high (read) and for the address where this value is read from an external ROM onto the shared data bus. The code is then supposed to write that value to to a specific address which the fpga inout pins can capture. But when r_w is low, the value of data_from_cpu is 8’bZ !! Simulation shows it working as it should.

So, I thought, ok - I’ve got my from/to wires mixed up. But not so apparently.

Anyway, I know this is impossible to troubleshoot with only the information I’ve given. I can only ask, have I set up my BB tri-state primitives correctly? Also, as I understand it, the PULLMODE should be set to NONE for the tri-state. Right?

I’ve definitely got a solid, reproducible test that is failing, which is a good starting point to figure out what the hell is going on.


Top
 Profile  
Reply with quote  
PostPosted: Wed Mar 13, 2024 1:48 am 
Offline

Joined: Mon Sep 17, 2018 2:39 am
Posts: 138
Hi!

czuhars wrote:
Thanks a ton for the feedback. At least I have a better idea that I’m on the right path.

I created a very simple test project to allow me to check the incoming data bus value on r_w active low (cpu write) for a given address. I’m using the BB primitive for the Lattice ECP5 in synthesis and the method mentioned above for simulation.

Here’s the weirdness: When a inout pin is configured as such in my top level module:

BB i_data0 (.B(i_data[0]), .I(data_to_cpu[0]), .O(data_from_cpu[0]), .T(r_w));
data_from_cpu is supposed to be the value during a write from the cpu to be processed inside the FPGA.
data_to_cpu is for when I want the FPGA to send data to the cpu.

The data_from_cpu is accurate, but only on the r_w high (read) and for the address where this value is read from an external ROM onto the shared data bus. The code is then supposed to write that value to to a specific address which the fpga inout pins can capture. But when r_w is low, the value of data_from_cpu is 8’bZ !! Simulation shows it working as it should.

So, I thought, ok - I’ve got my from/to wires mixed up. But not so apparently.


Some questions:
- Is the r_w signal coming from outside the FPGA?
- If it is so, is it properly synchronized to your clock?
- Does your FPGA logic use some master clock with the CPU or has an independent clock?

As you are probably using an embedded block ram for your ROM, you need a synchronous interface to it.

Have Fun!


Top
 Profile  
Reply with quote  
PostPosted: Wed Mar 13, 2024 11:57 am 
Offline

Joined: Tue Apr 12, 2016 6:30 pm
Posts: 13
My FPGA is generating the phi2 to the 65c02, so it is synchronized. However, I know I still need to sync the signals coming from the 65c02 into the FPGA. The original system schematic relied on the pho2 from the original NMOS 6502B to set various signals. But since I’m using the WDC version, I am generating my own internal pho2. But the test system I am working with doesn’t use this setup.
I am starting to think that:
1) my FPGA “read the incoming address and read the incoming data” logic isn’t accounting properly for the address/data set up times.
2) the r_w signal coming from the 65c02 that I’m using to switch the BB primitives between reading from or writing to the bidirectional io might be reversed. I.E., when r_w is active low (cpu is writing data to the bus) then the BB .O() net is active, rather than the .I()

Regardless, since I’m using the Yosys/nextpnr toolchain, I might switch those primitives to the TRELLIS_IO even though the toolchain is supposed to translate the BB primitive to the TRELLIS_IO primitives.
I’ll also run it through the Lattice Diamond software to see if that makes a difference. I know the software, esp. the open source version, is supposed to do that with generic Verilog. But I’m trying to eliminate as many points of potential failure I can.


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 8 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 15 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: