Generic Memory-Mapped VHDL Module

Hello all,

I've futzed around with this enough--time to ask the experts!

I am working on a design for a Spartan 3 FPGA but that isn't that important. This is the same discussion (I think) for every FPGA family that doesn't have built-in tri-state buffers.

What I am trying to do is to hookup multiple peripheral modules that have all functionality and address decoding contained in separate trees in the hierarchy. The ides is that I can add a uart, digital io, ... peripherals at the top level and none of the logic for the other modules needs to change. All the modules can just hook up to the data bus and the peripheral I/O as need be. All modules would be memory mapped and would connect to the system data bus for uc control.

How I intended to implement this is with a tri-state like bus knowing that the synthesizer would replace the tri-state bus with a mux. That is actually what I want but I'm not sure how to get it.

Below is one such peripheral VHDL module. This is a really simple module but just picture many of these all instantiated on the same bus. Other modules would be things like a UART,...

The problem I am having right now is that XST thinks that there are multiple sources for some of the data bits. There are but I want them all muxed together.

I'd be ecstatic if someone could point me in the right direction.

TIA,

James.

-------------------

entity dig_io is generic ( ADDR_WIDTH : integer := 4; ADDR : std_logic_vector(ADDR_WIDTH-1 downto 0) := "0000"; DATA_WIDTH : integer := 16; IO_WIDTH : integer := 4 ); port ( -- System Control Rst_i : in std_logic;

-- Data Bus nMs_i : in std_logic; nRd_i : in std_logic; nWr_i : in std_logic; Addr_i : in std_logic_vector(ADDR_WIDTH-1 downto 0); Data_io : inout std_logic_vector(DATA_WIDTH-1 downto 0);

-- Peripheral Interface Dig_i : in std_logic_vector(IO_WIDTH-1 downto 0); Dig_o : out std_logic_vector(IO_WIDTH-1 downto 0)

); end dig_io;

architecture Behavioral of dig_io is

signal LOW : std_logic; signal HIGH : std_logic; signal HIZ : std_logic;

signal data_in : std_logic_vector(DATA_WIDTH-1 downto 0); signal data_out : std_logic_vector(DATA_WIDTH-1 downto 0); signal data_oe : std_logic;

signal dig_in_reg : std_logic_vector(IO_WIDTH-1 downto 0); signal dig_out_reg : std_logic_vector(IO_WIDTH-1 downto 0);

begin

---------------------------------------------------------------------------- -- Write from processor to this peripheral

----------------------------------------------------------------------------

data_in LOW);

-- -- Address decoding of write -- process( Rst_i, nWr_i, LOW, HIGH ) begin if( Rst_i = HIGH ) then dig_out_reg LOW); elsif( rising_edge(nWr_i) ) then if( (Addr_i = ADDR) and (nMs_i = LOW) ) then dig_out_reg

Reply to
James Morrison
Loading thread data ...

The discussion's over. There haven't been any real internal tri-buffs for many years. It's actually a good thing.

This is a very good idea. When the IO registers are all in one module, changes are painful.

Consider modeling what's really there -- gates and clock-enabled flops. Separate writedata from readdata signals. Write regs are clock enabled for the correct address in write mode. Read regs drive readdata for the correct address in write mode. Nothing to it.

Here's a cpu_reg example procedure. It is intended to be called from a synchronous process.

-- Mike Treseler

--------------------------------------------------- procedure cpu_regs is -- CPU registers -- this procedure does some post processing on the rx and tx -- state variables and must *follow* those procedures. begin W : if write_stb = '1' then case address is when '0' =>

TXQ : Tx_v := writeData; -- grab a byte kick : TxState_v := START; -- kick off tx when others => -- nop for cpu write to unused address end case; end if W;

-- +----------------------------------------+

-- | Table 1 UART Memory Map |

-- +------+-----+-----+----------+----------+

-- |Name |Add |R/W |Data |Comment |

-- +------+-----+-----+----------+----------+

-- |TXQ |0 |W |7_downto_0| Transmit |

-- | | | | | Data |

-- +------+-----+-----+----------+----------+

-- |RXQ |0 |R |7_downto 0| Receive |

-- | | | | | Data |

-- +------+-----+-----+----------+----------+

-- |StatQ |1 |R |2->TxReady| Status |

-- | | | |1->RxError| Data |

-- | | | |0->RxReady| |

-- +------+-----+-----+----------+----------+ R : if read_stb = '1' then case address is -- when '0' => -- Collect a byte from the input shifter RXQ : read_data_v := Rx_v; RxState_v := IDLE; -- restart the read cycle when '1' =>

StatQ: if RxState_v = FULL then -- Update rx status: RxReady : read_data_v(0) := '1'; -- data ready elsif RxState_v = ERR then RxError : read_data_v(1) := '1'; -- bad stop RxState_v := IDLE; -- restart end if; if TxState_v = IDLE then TX_Ready : read_data_v(2) := '1'; -- Update tx end if; when others =>

end case; end if R; end procedure cpu_regs;

-- For details see

formatting link

Reply to
Mike Treseler

How is this for an idea : (Some examples from

formatting link

This is in the Bally code top level. It intantiates a cpu and number of peripherals. I bring out of each peripheral an "output enable" signal and the data bus, then build a mux to to the biz at the top level. Big multiplexers are expensive (you are building a priority mux so be careful - if you preserve the hierarchy in the synthesis tool it won't spot they are exclusive) but for an 8 bit data bus you can get away with it. If nobody is enabled I return a "floated high" bus, but you can do a bus hold by registering the muxer result, and returning that as the default. The vic-20 does that I think.

Cheers, MikeJ

peripheral instantiation :

u_data : BALLY_DATA port map ( I_MXA => cpu_addr, I_MXD => cpu_data_out, O_MXD => mx_data, O_MXD_OE_L => mx_data_oe_l,

-- cpu control signals I_M1_L => cpu_m1_l, I_RD_L => cpu_rd_l, etc I mux :

cpu_src_data_mux : process(rom_dout, sys_cs_l, I_CAS_DATA, cas_cs_l, I_EXP_OE_L, I_EXP_DATA, exp_buzoff_l, mx_addr_oe_l, mx_addr, mx_data_oe_l, mx_data, mx_io_oe_l, mx_io) begin -- nasty mux if (I_EXP_OE_L = '0') or (exp_buzoff_l = '0') then cpu_data_in

Reply to
MikeJ

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.