From 7c41810692ed90ece40bf4b2f125f441e2187ac5 Mon Sep 17 00:00:00 2001 From: markster Date: Mon, 22 Oct 2001 23:39:42 +0000 Subject: Version 0.1.0 from FTP git-svn-id: http://svn.digium.com/svn/zaptel/trunk@15 5390a7c7-147a-4af0-8ec9-7488f05a26cb --- tormenta2.vhd | 588 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 588 insertions(+) create mode 100755 tormenta2.vhd (limited to 'tormenta2.vhd') diff --git a/tormenta2.vhd b/tormenta2.vhd new file mode 100755 index 0000000..19b23bb --- /dev/null +++ b/tormenta2.vhd @@ -0,0 +1,588 @@ +-- Tormenta2 -- PCI Telephony Interface Card -- VHDL for Xilinx Part +-- version 1.1, 10/22/2001. +-- Copyright (c) 2001, Jim Dixon. +-- +-- Jim Dixon +-- Mark Spencer +-- +-- This program is free software, and the design, schematics, layout, +-- and artwork for the hardware on which it runs is free, and all are +-- distributed under the terms of the GNU General Public License. +-- +-- Thanks to Mark and the gang at Linux Support Services for the contribution +-- of the initial buffering code. +-- +-- + +-- The A4 die of the Dallas 21Q352 chip has a bug in it (well, it has several actually, +-- but this is the one that effects us the most) where when you have it in IBO mode +-- (where all 4 framers are combined into 1 8.192 Mhz backplane), the receive data +-- comes out of the chip late. So late, in fact, that its an entire HALF clock cycle +-- off. So what we had to do is have a separate RSYSCLK signal (which was the TSYSCLK +-- signal inverted) and a separate RSYNC signal (which corresponds to the RSYSCLK inverted +-- signal as opposed to the TSYSCLK) that was 1/2 clock cycle early, so that the data comes +-- out at the correct time. + +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use IEEE.STD_LOGIC_ARITH.ALL; +use IEEE.STD_LOGIC_UNSIGNED.ALL; + +entity tormenta2 is + Port ( +-- GCK0 signal (Local bus clock) + CLK : in std_logic; +-- GCK1 signal 8.192 Mhz clock from mk1574 and drives SYSCLK's on Dallas chip + CLK8192 : in std_logic; +-- Tx Framing Pulse to Dallas chip + TSSYNC : out std_logic; +-- Rx Framing Pulse to Dallas chip + RSYNC : out std_logic; +-- 8 Khz square wave for input to mk1574 (RCLKO divided by 193) + KHZ8000 : out std_logic; +-- RSER from Dallas chip (received serial data) + RSER : in std_logic; +-- TSER to Dallas chip (transmitted serial data) + TSER : out std_logic; +-- RCLK output to Dallas chip (TCLK) (1.544 Mhz) + RCLKO : out std_logic; +-- RCLK 1-4 are RCLK inputs from SCT's, 0 is 1.544 Mhz oscillator + RCLK : in std_logic_vector(4 downto 0); +-- LCLK is tied to GCK0, so you dont specify it here. +-- CCLK, CPROGRAM, and CDONE are tied to dedicated pins, so you dont either. +-- Local bus Data Bus + D : inout std_logic_vector(31 downto 0); +-- Local bus Address Bus + ADDR : in std_logic_vector(11 downto 2); +-- Local bus Byte Enable lines (also BE0 is A0 and BE1 is A1 for 8 bit operations) + BE : in std_logic_vector(3 downto 0); +-- Local bus "WR" signal + WR : in std_logic; +-- Local bus "RD" signal + RD : in std_logic; +-- Local bus READY signal out (also Configuration BUSY signal) + READY : out std_logic; +-- Local bus INTerrupt signal + INT : out std_logic; +-- Chip selects for Dallas chip SCT's 1 thru 4 + CS : out std_logic_vector(4 downto 1); +-- Dallas chip WRite signal + DWR : out std_logic; +-- Dallas chip ReaD signal + DRD : out std_logic; +-- Dallas chip INTerrupt signal in + DINT : in std_logic; +-- LED's output + LEDS : out std_logic_vector(7 downto 0); +-- Board ID input + BOARDID : in std_logic_vector(3 downto 0); +-- TEST pins + TEST1 : inout std_logic; + TEST2 : inout std_logic; + TEST3 : inout std_logic; + TEST4 : inout std_logic; +-- BTERM output + BTERM : out std_logic; +-- MASTER output + MASTER : out std_logic; +-- XSYNCIN input + XSYNCIN: in std_logic; +-- XSYNCOUT output + XSYNCOUT: out std_logic); +end tormenta2; + +architecture behavioral of tormenta2 is + +component RAMB4_S1_S16 + port ( + ADDRA: IN std_logic_vector(11 downto 0); + ADDRB: IN std_logic_vector(7 downto 0); + DIA: IN std_logic_vector(0 downto 0); + DIB: IN std_logic_vector(15 downto 0); + WEA: IN std_logic; + WEB: IN std_logic; + CLKA: IN std_logic; + CLKB: IN std_logic; + RSTA: IN std_logic; + RSTB: IN std_logic; + ENA: IN std_logic; + ENB: IN std_logic; + DOA: OUT std_logic_vector(0 downto 0); + DOB: OUT std_logic_vector(15 downto 0)); +END component; + +-- Counter for wait state/Dallas generator +signal waitcnt : std_logic_vector(2 downto 0); +-- Global counter +signal counter: std_logic_vector(13 downto 0); +-- Local copy of Global counter +signal lcounter: std_logic_vector(13 downto 0); +-- Position in a given buffer +signal position: std_logic_vector(11 downto 0); +-- Latched buffer position +signal lposition: std_logic_vector(11 downto 0); +-- dbuf represents the buffer that is currently being +-- operated upon by the T1 part, while not dbuf represents +-- the buffer that the bus side is operating with +signal dbuf: std_logic; +-- Lathed dbuf signal +signal ldbuf: std_logic; +-- Which ram of the buffer we are currently operating with +-- (0 = top, 1 = bottom) +signal ramno: std_logic; +-- Latched ramno signal +signal lramno: std_logic; +-- Serial output from first upper 16-bit memory +signal txqt1out: std_logic; +-- Serial output from second upper 16-bit memory +signal txqt2out: std_logic; +-- Serial output from first lower 16-bit memory +signal txqb1out: std_logic; +-- Serial output from second lower 16-bit memory +signal txqb2out: std_logic; +-- Parallel output from first 32-bits of memory +signal rxq1out: std_logic_vector(31 downto 0); +-- Parallel output from second 32-bits of memory +signal rxq2out: std_logic_vector(31 downto 0); +-- Ground bus for unnecessary inputs +signal gndbus: std_logic_vector(15 downto 0); +-- RWR: Write enable for ram +signal RWR: std_logic; +-- RRD: Read enable for ram +signal RRD: std_logic; +-- Local version of 1.544 Mhz clock to be output +signal lclk: std_logic; +-- 8khz counter +signal cnt193: std_logic_vector(7 downto 0); +-- Which of the received clocks to propagate +signal clkreg: std_logic_vector(2 downto 0); +-- Control register +signal ctlreg: std_logic_vector(7 downto 0); +-- Status register +signal statreg: std_logic_vector(2 downto 0); +-- Signal actually driving Rx buffers (after Rxserial loopback mux) +signal xrser: std_logic; +-- Signal actually driven by Tx buffers (before Txserial loopback mux) +signal xtser: std_logic; + +-- Register definitions: + +-- Write: +-- 0xC00 -- clkreg (sync source) 0=free run, 1=span 1, 2=span 2, 3=span 3, 4=span 4, 5=external. +-- 0xC01 -- ctlreg as follows: +-- bit 0 - Interrupt Enable +-- bit 1 - Drives "TEST1" signal ("Interrupt" outbit) +-- bit 2 - Dallas Interrupt Enable (Allows DINT signal to drive INT) +-- bit 3 - Enable External Synronization Drive (MASTER signal). +-- bit 5 - Remote serial loopback (When set to 1, TSER is driven from RSER) +-- bit 6 - Local serial loopback (When set to 1, Rx buffers are driven from Tx buffers) +-- bit 7 - Interrupt Acknowledge (set to 1 to acknowledge interrupt) +-- 0xC02 -- LED register as follows: +-- bit 0 - Span 1 Green +-- bit 1 - Span 1 Red +-- bit 2 - Span 2 Green +-- bit 3 - Span 2 Red +-- bit 4 - Span 3 Green +-- bit 5 - Span 3 Red +-- bit 6 - Span 4 Green +-- bit 7 - Span 4 Red +-- NOTE: turning on both red and green yields yellow. +-- 0xC03 -- TEST2, writing to bit 0 drives TEST2 pin. +-- +-- Read: +-- 0xC00 -- statreg as follows: +-- bit 0 - Interrupt Enabled +-- bit 1 - Interrupt Active +-- bit 2 - Dallas Chip Interrupt Active +-- 0xC01 -- boardid as follows: +-- bits 0-3 Board ID bits 0-3 (from rotary dip switch) + + +begin + + -- Create statreg for user to be able to read + statreg(0) <= ctlreg(0); -- Interrupt enable status + statreg(2) <= not DINT; -- Dallas chip interrupt request + -- Tie INT signal to bit in statreg + INT <= statreg(1) or ((not DINT) and ctlreg(2)); + + MASTER <= ctlreg(3); -- Control Bit to enable External Sync Driver + + TEST1 <= ctlreg(1); -- Reflect "Interrupt" Outbit + TEST3 <= statreg(1); -- Reflect Interrupt Status + TEST4 <= RSER; + + BTERM <= '1'; -- Leave this not enabled for now. + + -- Which ram we read into is from the 5th LSB of the counter + ramno <= lcounter(4); + -- Which buffer we're using is the most significant + dbuf <= lcounter(13); + -- Our position is the bottom 4 bits, inverted, and then + -- the skip one, and then the next 8 bits. + position(3 downto 0) <= not lcounter(3 downto 0); + position(11 downto 4) <= lcounter(12 downto 5); + + gndbus <= "0000000000000000"; + + txqt1: RAMB4_S1_S16 port map ( + ADDRA => position, -- Where are we in transmission + ADDRB => ADDR(9 downto 2), -- Address into our 16-bit words + DIA(0) => '0', -- We never write from the serial side + DIB => D(31 downto 16), -- Top 16-bits of data bus + WEA => '0', -- Never write from serial side + WEB => not WR, -- Write when requested + CLKA => CLK8192, -- Clock output at 8.192 Mhz + CLKB => RWR, -- Clock input when asked to by PCI bus + ENA => '1', -- Always enable output + ENB => dbuf, -- Enable when dbuf is set. + DOA(0) => txqt1out, -- Serial output to be MUXed + RSTA => '0', -- No need for silly reset + RSTB => '0' + ); + + txqt2: RAMB4_S1_S16 port map ( + ADDRA => position, -- Where are we in transmission + ADDRB => ADDR(9 downto 2), -- Address into our 16-bit words + DIA(0) => '0', -- We never write from the serial side + DIB => D(31 downto 16), -- Top 16-bits of data bus + WEA => '0', -- Never write from serial side + WEB => not WR, -- Write when requested + CLKA => CLK8192, -- Clock output at 8.192 Mhz + CLKB => RWR, -- Clock input when asked to by PCI bus + ENA => '1', -- Always enable output + ENB => not dbuf, -- Take input from user when not in use. + DOA(0) => txqt2out, -- Serial output to be MUXed + RSTA => '0', -- No need for silly reset + RSTB => '0' + ); + + txqb1: RAMB4_S1_S16 port map ( + ADDRA => position, -- Where are we in transmission + ADDRB => ADDR(9 downto 2), -- Address into our 16-bit words + DIA(0) => '0', -- We never write from the serial side + DIB => D(15 downto 0), -- Top 16-bits of data bus + WEA => '0', -- Never write from serial side + WEB => not WR, -- Write when requested + CLKA => CLK8192, -- Clock output at 8.192 Mhz + CLKB => RWR, -- Clock input when asked to by PCI bus + ENA => '1', -- Always enable output + ENB => dbuf, -- Enable input when not in use + DOA(0) => txqb1out, -- Serial output to be MUXed + RSTA => '0', -- No need for silly reset + RSTB => '0' + ); + + txqb2: RAMB4_S1_S16 port map ( + ADDRA => position, -- Where are we in transmission + ADDRB => ADDR(9 downto 2), -- Address into our 16-bit words + DIA(0) => '0', -- We never write from the serial side + DIB => D(15 downto 0), -- Top 16-bits of data bus + WEA => '0', -- Never write from serial side + WEB => not WR, -- Write when requested + CLKA => CLK8192, -- Clock output at 8.192 Mhz + CLKB => RWR, -- Clock input when asked to by PCI bus + ENA => '1', -- Always enable output + ENB => not dbuf, -- Enable when dbuf is set. + DOA(0) => txqb2out, -- Serial output to be MUXed + RSTA => '0', -- No need for silly reset + RSTB => '0' + ); + + rxqt1: RAMB4_S1_S16 port map ( + ADDRA => lposition, -- Where to put the next sample + ADDRB => ADDR(9 downto 2), -- Addressable output + DIA(0) => XRSER, -- Input from serial from T1 + DIB => gndbus, -- Never input from bus + WEA => not lramno, -- Enable writing when we're in the top + WEB => '0', + CLKA => not CLK8192, -- Clock input from T1 + CLKB => RRD, -- Clock output from bus + ENA => not ldbuf, -- Enable when we're the selected buffer + ENB => '1', -- Always enable output (it gets MUXed) + DOB => rxq1out(31 downto 16), -- Data output to MUX + RSTA => '0', + RSTB => '0' + ); + + rxqt2: RAMB4_S1_S16 port map ( + ADDRA => lposition, -- Where to put the next sample + ADDRB => ADDR(9 downto 2), -- Addressable output + DIA(0) => XRSER, -- Input from serial from T1 + DIB => gndbus, -- Never input from bus + WEA => not lramno, -- Enable writing when we're in the top + WEB => '0', + CLKA => not CLK8192, -- Clock input from T1 + CLKB => RRD, -- Clock output from bus + ENA => ldbuf, -- Enable when we're the selected buffer + ENB => '1', -- Always enable output (it gets MUXed) + DOB => rxq2out(31 downto 16), -- Data output to MUX + RSTA => '0', + RSTB => '0' + ); + + rxqb1: RAMB4_S1_S16 port map ( + ADDRA => lposition, -- Where to put the next sample + ADDRB => ADDR(9 downto 2), -- Addressable output + DIA(0) => XRSER, -- Input from serial from T1 + DIB => gndbus, -- Never input from bus + WEA => lramno, -- Enable writing when we're in the top + WEB => '0', + CLKA => not CLK8192, -- Clock input from T1 + CLKB => RRD, -- Clock output from bus + ENA => not ldbuf, -- Enable when we're the selected buffer + ENB => '1', -- Always enable output (it gets MUXed) + DOB => rxq1out(15 downto 0), -- Data output to MUX + RSTA => '0', + RSTB => '0' + ); + + rxqb2: RAMB4_S1_S16 port map ( + ADDRA => lposition, -- Where to put the next sample + ADDRB => ADDR(9 downto 2), -- Addressable output + DIA(0) => XRSER, -- Input from serial from T1 + DIB => gndbus, -- Never input from bus + WEA => lramno, -- Enable writing when we're in the top + WEB => '0', + CLKA => not CLK8192, -- Clock input from T1 + CLKB => RRD, -- Clock output from bus + ENA => ldbuf, -- Enable when we're the selected buffer + ENB => '1', -- Always enable output (it gets MUXed) + DOB => rxq2out(15 downto 0), -- Data output to MUX + RSTA => '0', + RSTB => '0' + ); + + +clkdiv193: process(lclk) -- Divider from 1.544 Mhz to 8 Khz to drive MK1574 via KHZ8000 pin +begin + if (lclk'event and lclk = '1') then + cnt193 <= cnt193 + 1; + -- Go high after 96 samples and + -- low after 193 samples + if (cnt193 = "01100000") then + KHZ8000 <= '1'; + elsif (cnt193 = "11000000") then -- *YES* C0 hex *IS* the correct value. I even checked it on a freq. counter! + KHZ8000 <= '0'; + cnt193 <= "00000000"; + end if; + end if; +end process clkdiv193; + + +-- Serial transmit data (TSER) output mux (from RAM outputs) +txmux: process (txqt1out, txqt2out, txqb1out, txqb2out,dbuf,ramno,rser) +begin + if (dbuf = '0') then + if (ramno = '0') then + XTSER <= txqt1out; + else + XTSER <= txqb1out; + end if; + else + if (ramno = '0') then + XTSER <= txqt2out; + else + XTSER <= txqb2out; + end if; + end if; + if (ctlreg(5)='1') then -- If in remote serial loopback + TSER <= RSER; + else + TSER <= XTSER; + end if; +end process txmux; + +-- Stuff to do on rising edge of TSYSCLK +process(CLK8192,lcounter(12 downto 0),ctlreg(7)) +begin + -- Make sure we're on the rising edge + if (CLK8192'event and CLK8192 = '1') then + counter <= counter + 1; + -- We latch copies of ramno, dbuf, and position on this clock so that they + -- will be stable when the RX buffer stuff needs them on the other edge of the clock + lramno <= ramno; + ldbuf <= dbuf; + lposition <= position; + if (lcounter(9 downto 0)="0000000000") then -- Generate TSSYNC signal + TSSYNC <= '1'; + else + TSSYNC <= '0'; + end if; + -- If we are on an 8 sample boundary, and interrupts are enabled, + if (((lcounter(12 downto 0)="0000000000000") and (ctlreg(0)='1'))) then + statreg(1) <= '1'; + elsif (ctlreg(7)='1' or ctlreg(0)='0') then + statreg(1) <= '0'; -- If interrupt ack-ed + end if; + end if; +end process; + +-- Stuff to do on Falling edge of TSYSCLK +process(CLK8192,counter(9 downto 0)) +begin +if (CLK8192'event and CLK8192='0') then + lcounter <= counter; -- save local copy of counter + if (counter(9 downto 0)="0000000000") then + RSYNC <= '1'; -- Generate RSYNC pulse + else + RSYNC <= '0'; + end if; +end if; +end process; + +-- Handle Data input requests +rxdata: process (ADDR(11 downto 10), rxq1out, rxq2out, RD, dbuf, statreg) +begin + -- If in 32 bit space, Send data from the block we're not using + if (RD = '0' and ADDR(11) = '0') then + RRD <= '1'; -- Assert clock to output RAM + -- Mux DATA bus to proper RAMs + if (dbuf = '1') then + D <= rxq1out; + else + D <= rxq2out; + end if; + -- If in 8 bit space, return statreg + elsif ((RD='0') and (ADDR(11 downto 10)="11")) then + if (BE(1 downto 0) = "00") then -- if C00, return status + D(2 downto 0) <= statreg; + D(31 downto 3) <= "ZZZZZZZZZZZZZZZZZZZZZZZZ00000"; + else -- if C01, return board id + D(3 downto 0) <= NOT BOARDID; + D(31 downto 4) <= "ZZZZZZZZZZZZZZZZZZZZZZZZ0000"; + end if; + RRD <= '0'; + else -- If in outer space, Data bus should be tri-state + D <= "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"; + RRD <= '0'; + end if; +end process rxdata; + +-- rx serial loopback mux +rxmux: process(rser,xtser) +begin + if (ctlreg(6)='1') then + XRSER <= XTSER; + else + XRSER <= RSER; + end if; +end process rxmux; + +-- Handle Writing of RAMs when in 32 bit space +txdecode: process (WR, CLK, BE, dbuf, D, ADDR) +begin + -- Make sure when we write to memory that we only + -- enable the clock on the actual RAM units if the + -- top bit of address is '0', and is a full 32 bit access. + if ((addr(11) = '0') and (BE="0000") and (WR='0') and (CLK='1')) then + RWR <= '1'; + else + RWR <= '0'; + end if; +end process txdecode; + +-- Select the proper output 1.544 Mhz clock +clkmux: process(clkreg, RCLK) +begin + if (clkreg = "001") then + lclk <= RCLK(1); + elsif (clkreg = "010") then + lclk <= RCLK(2); + elsif (clkreg = "011") then + lclk <= RCLK(3); + elsif (clkreg = "100") then + lclk <= RCLK(4); + elsif (clkreg = "101") then + lclk <= XSYNCIN; + else + lclk <= RCLK(0); + end if; + RCLKO <= lclk; + XSYNCOUT <= lclk; +end process clkmux; + +-- Stuff to do on positive edge of Local bus clock +process(CLK,ADDR(11 downto 10),RD,WR) +begin +if (CLK'event and CLK='1') then -- On positive transition of clock + if ((WR='0' or RD='0') and ADDR(11 downto 10)="10") then -- If in our address range + waitcnt <= waitcnt + 1; -- Bump state counter if in Dallas' address range + else + waitcnt <= "000"; -- Otherwise, leave reset + end if; + if (WR='0' and ADDR(11 downto 10)="11") then -- If to write to our configuration space + if (ADDR(7 downto 2)="000000") then + if (BE(1 downto 0)="11") then + TEST2 <= D(0); -- Write to TEST2 pin (0xC03) + elsif (BE(1 downto 0)="10") then + LEDS <= not D(7 downto 0); -- Write to the LED register (0xC02) + elsif (BE(1 downto 0)="01") then + ctlreg <= D(7 downto 0); -- Write to the ctlreg register (0xC01) + else + clkreg <= D(2 downto 0); -- Write to the clkreg register (0xC00) + end if; + end if; + end if; + if ((statreg(1)='0') and (ctlreg(7)='1')) then -- if interrupt acked and de-asserted, ack the ack + ctlreg(7) <= '0'; + end if; + if (ctlreg(0)='0') then -- if interrupts disabled, make sure ack is de-acked + ctlreg(7) <= '0'; + end if; +end if; +end process; + +-- Generate Dallas Read and Write Signals and Wait states +process(CLK,ADDR(11 downto 8),RD,WR,waitcnt) +begin +if ((WR='0' or RD='0') and ADDR(11 downto 10)="10") then -- If during valid read or write + -- Stuff for CS for Dallas Chips + if (ADDR(9 downto 8)="00") then + CS(4 downto 1) <= "1110"; -- Activate CS1 + end if; + if (ADDR(9 downto 8)="01") then + CS(4 downto 1) <= "1101"; -- Activate CS2 + end if; + if (ADDR(9 downto 8)="10") then + CS(4 downto 1) <= "1011"; -- Activate CS3 + end if; + if (ADDR(9 downto 8)="11") then + CS(4 downto 1) <= "0111"; -- Activate CS4 + end if; + if (waitcnt <= "100") then -- An intermediate cycle (before ready) + if (WR='0') then -- If a write cycle, output it + DWR <= '0'; + else + DWR <= '1'; + end if; + if (RD='0') then -- If a read cycle, output it + DRD <= '0'; + else + DRD <= '1'; + end if; + end if; + if ((waitcnt = "011") and (CLK='0')) then -- If were at 4, were ready, and this will be real one + READY <= '0'; + end if; + if (waitcnt > "100") then -- Count is greater then 4, time to reset everything + READY <= '1'; + DWR <= '1'; + DRD <= '1'; + end if; +else -- Not in read or write in the appropriate range, reset the stuff + READY <= '1'; + DWR <= '1'; + DRD <= '1'; + CS(4 downto 1) <= "1111"; -- No CS outputs +end if; +if (waitcnt="100" and CLK='1' and WR='0') then -- De-activate the DWR signal at the final half cycle + DWR <= '1'; + DWR <= '1'; +end if; +if ((WR='0' or RD='0') and ADDR(11 downto 10)/="10") then -- If during not valid read or write + READY <= '0'; -- Dont hang the bus for them +end if; +end process; + +end behavioral; -- cgit v1.2.3