DS3134 Step By Step Configuration Unchannelized Port—Configuration Mode

要約

Application Note 369 provides an example of how to construct, send, receive, and check a packet in loopback mode on a DS3134 unchannelized port. A coding example is discussed for easy adaptation to end user applications.

Overview
This application note describes an example of how to configure a single port for unchannelized operation on the DS3134 in configuration mode. Additionally, this example describes how to construct, send, receive, and check a packet in loopback mode on that port. This application note is presented as a coding example for easy adaptation to end user applications.

There is an errata that would be helpful to reference: Internal Chip Timing in the Unchannelized Mode. Currently, (die rev B2) the chip does not correctly handle unchannelized mode. The errata sheet describes the work around and this application note will also configure the part according to the errata sheet. The workaround is to configure the chip to think that it is operating in the channelized mode (this note will use 8MHz).

The Local Bus can operate in two modes in DS3134:

  1. PCI Bridge Mode
  2. Configuration Mode
In the Configuration Mode, the Local Bus is used only to control and monitor the DS3134 while the HDLC packet data will be transferred via PCI Bus. Data cannot be passed from the Local Bus to the PCI bus in this mode. (Refer to the DS3134 data sheet section 10).

This example has the following configuration:

  • Port 1 of the DS3134 is operated as an unchannelized port. That is, the port gets receive/transmit clocks, but no sync pulse. All other ports are not used.
  • Port 1 DS0's 0-127 of the DS3134 is assigned to HDLC channel 3. HDLC channel 3 of the DS3134 is assigned 10 RX FIFO blocks, 10 TX FIFO blocks, an RX FIFO high water mark of 8, and a TX low water mark of 4.
  • Ten 16-byte packets are constructed in host memory using 10 TX buffers, 10 TX descriptors and one TX pending queue entry. The TX pending queue entry points to a descriptor and that packet descriptor is chained to a total of 10 descriptors via the Next Descriptor Pointer field and the EOF and CV being set (see page 130 of the datasheet).
  • Since the DS3134 is in loopback mode, when the packet is transmitted it will also be received by the DS3134. The received packet is written to host memory using ten RX buffers, ten RX descriptors and ten RX done queue entries.
  • The host memory is configured as follows:
    1. Receive Side:
      1. RX free queue base address (RFQBA1/0) = 0x10000000
      2. RX done queue base address (RDQBA1/0) = 0x10000B00
      3. RX descriptor base address (RDBA1/0) = 0x10001080
      4. RX buffer base address = 0x10002680
    2. Transmit Side:
      1. TX pending queue base address (TPQBA1/0) = 0x10059084
      2. TX done queue base address (TDQBA1/0) = 0x10059604
      3. TX descriptor base address (TDBA1/0) = 0x10059B84
      4. TX buffer base address = 0x1005B184

Definition of the Coding Example Function Calls
In order to improve readability, the code in this example uses several function calls. The definitions of these functions are as follows:

write_reg(address, data)
Write the specified data to the specified DS3134 register address

Inputs:

  • address = the register address where data is to be written
  • data = the data to be written to the specified register

Outputs: None

read_reg(address, data)
Read the contents of the DS3134 register at the specified address

Input: address = the register address which is to be read
Output: data = the value read from the register

write_reg_IS(address, data)
Write the specified data to the specified DS3134 indirect select register and then wait for that register's busy bit to clear before returning

Inputs:

  • address = the indirect select register where data is to be written
  • data = the data to be written to the specified register

Outputs: None

Function Code:

write_reg(address, data);
bit_check = 0x8000;
while (bit_check & 0x8000)
	read_reg(address, bit_check);

wr_dword(address, data)
Write the specified 32-bit data value to the specified 32-bit host memory address

Inputs:

  • address = the host memory address where data is to be written
  • data = the data to be written to the specified memory address

Outputs: None

rd_dword(address, data)
Read a 32-bit data value from the specified 32-bit host memory address

Input: address = the host memory address which is to be read
Output: data = the 32-bit data value read from host memory

frame_wait(count)
Provides a delay equal to count number of frame periods where a frame period is 125 microseconds

Input: count = number of frame periods to wait
Outputs: None


Unchannelized Configuration Mode Coding Example
This application note-coding example consists of the following steps:

  1. Reset the DS3134
  2. Configure the DS3134
  3. Enable the HDLC channel
  4. Put the HDLC channel in loopback mode
  5. Queue, send, receive, and check a data packet
Each of these steps is detailed in the following sections by a brief description and coding example. Register names are used instead of addresses to improve readability. The corresponding address/offset of the DS3134 internal device configuration registers are listed in accompanying tables. Additionally, the abbreviations TX and RX are used to represent transmit side and receive side respectively. Refer to the DS3134 data sheet for more detailed information.


Reset The DS3134
Resetting the DS3134 consists of two steps. First the internal RAM's of the DS3134 must be zeroed and then the DS3134 internal registers must be reset.

Zero The DS3134 Internal RAM's
The DS3134 internal configuration RAM's are not cleared by resetting the chip and therefore must be manually zeroed. This task is accomplished performing a series of writes to each internal ram in the DS3134 using the appropriate data and indirect select registers of the DS3134. This section details the procedure for accomplishing this task.

Offset/ Address Acronym Register Name Data Sheet Section
03xx CP[n]RDIS Channelized Port n Register Data Indirect Select 5.3
03xx CP[n]RD Channelized Port n Register Data 5.3

// Zero RX configuration and TX configuration RAM's for all ports
for(port=0; port<16; port=port+1)
{
	write_reg(CP0RD + 8*port, 0x0000);
	for(ds0=0; ds0<128; ds0=ds0+1)
	{
		// Set bits 9-8 = 01 to select RX Configuration RAM
		// Set bits 9-8 = 10 to select TX Configuration RAM
		write_reg_IS(CP0RDIS + 8*port, (0x0100 + ds0));
		write_reg_IS(CP0RDIS + 8*port, (0x0200 + ds0));
	}
}
Offset/ Address Acronym Register Name Data Sheet Section
0400 RHCDIS Receive HDLC Channel Definition Indirect Select 6.2
0404 RHCD Receive HDLC Channel Definition 6.2

// Zero the RX HDLC channel definition RAM
write_reg(RHCD, 0x0000);
for(channel=0; channel<256; channel=channel+1)
	write_reg_IS(RHCDIS, channel);
Offset/ Address Acronym Register Name Data Sheet Section
0480 THCDIS Transmit HDLC Channel Definition Indirect Select 6.2
0484 THCD Transmit HDLC Channel Definition 6.2

// Zero the TX HDLC channel definition RAM
write_reg(THCD, 0x0000);
for(channel=0; channel<256; channel=channel+1)
	write_reg_IS(THCDIS, channel);
Offset/ Address Acronym Register Name Data Sheet Section
0900 RFSBPIS Receive FIFO Staring Block Pointer Indirect Select 7.2
0904 RFSBP Receive FIFO Starting Block Pointer 7.2

// Zero the RX FIFO Starting Block Pointer RAM
write_reg(RFSBP, 0x0000);
for(channel=0; channel<256; channel=channel+1)
	write_reg_IS(RFSBPIS, channel);
Offset/ Address Acronym Register Name Data Sheet Section
0910 RFBPIS Receive FIFO Block Pointer Indirect Select 7.2
0914 RFBP Receive FIFO Block Pointer 7.2

// Zero the RX FIFO Block Pointer RAM
write_reg(RFBP, 0x0000);
for(channel=0; channel<256; channel=channel+1)
	write_reg_IS(RFBPIS, channel);
Offset/ Address Acronym Register Name Data Sheet Section
0920 RFHWMIS Receive FIFO High Water Mark Indirect Select 7.2
0924 RFHWM Receive FIFO High Water Mark 7.2

// Zero the RX FIFO High Water Mark RAM
write_reg(RFHWM, 0x0000);
for(channel=0; channel<256; channel=channel+1)
	write_reg_IS(RFHWMIS, channel);
Offset/ Address Acronym Register Name Data Sheet Section
0980 TFSBPIS Transmit FIFO Starting Block Pointer Indirect Select 7.2
0984 TFSBP Transmit FIFO Starting Block Pointer 7.2

// Zero the TX FIFO Starting Block Pointer registers
write_reg(TFSBP, 0x0000);
for(channel=0; channel<256; channel=channel+1)
	write_reg_IS(TFSBPIS, channel);
Offset/ Address Acronym Register Name Data Sheet Section
0990 TFBPIS Transmit FIFO Block Pointer Indirect Select 7.2
0994 TFBP Transmit FIFO Block Pointer 7.2

// Zero the TX FIFO Block Pointer RAM
write_reg(TFBP, 0x0000);
for(channel=0; channel<256; channel=channel+1)
	write_reg_IS(TFBPIS, channel);
Offset/ Address Acronym Register Name Data Sheet Section
09A0 TFLWMIS Transmit FIFO Low Water Mark Indirect Select 7.2
09A4 TFLWM Transmit FIFO Low Water Mark 7.2

// Zero the TX FIFO Low Water Mark RAM
write_reg(TFLWM, 0x0000);
for(channel=0; channel<256; channel=channel+1)
	write_reg_IS(TFLWMIS, channel);
Offset/ Address Acronym Register Name Data Sheet Section
0770 RDMACIS Receive DMA Configuration Indirect Select 8.1.5
0774 RDMAC Receive DMA Configuration 8.1.5

// Zero the RX DMA configuration RAM
write_reg(RDMAC, 0x0000);
for(channel=0; channel<256; channel=channel+1)
	write_reg_IS(RDMACIS, 0x0400 + channel);
Offset/ Address Acronym Register Name Data Sheet Section
0870 TDMACIS Transmit DMA Configuration Indirect Select 8.2.5
0874 TDMAC Transmit DMA Configuration 8.2.5

// Zero the TX DMA configuration RAM
write_reg(TDMAC, 0x0000);
for(channel=0; channel<256; channel=channel+1)
	write_reg_IS(TDMACIS, 0x0400 + channel);
Reset The DS3134 Internal Registers
A software reset can be performed on all registers in the DS3134 using the Master Reset Register (MRID). All internal registers will be set to a default value of 0 when bit 0 of the MRID register is set to 1.The Host must set this bit back to 0 before the device can be programmed for normal operation.

Offset/ Address Acronym Register Name Data Sheet Section
0000 MRID Master Reset & ID Register 4.1

// Reset DS3134 using MRID registers master reset bit.
write_reg(MRID, 0x0001);
write_reg(MRID, 0x0000);

Configure the DS3134
Configuration of the DS3134 consists of the following steps:

  1. Configure the PCI registers
  2. Configure the Layer 1 registers
  3. Configure the HDLC registers
  4. Configure the FIFO registers
  5. Configure the DMA registers
Configuration of each of these register sets is detailed in the following sections. Several variables are used to improve readability and provide a more algorithmic code structure. The following code provides the initialization of these variables:

// This example uses port 1 channel 3
port = 1;
channel = 3;

// RX free queue base address
rfq_base_addr = 0x10000000;

// RX free queue end address
// - RX free queue size = 16
rfq_end_idx = 0x000F;

// RX done queue base address
rdq_base_addr = 0x10000B00;

// RX done queue end address
// - RX done queue size = 16
rdq_end_idx = 0x000F;

// RX descriptor base address
// - RX descriptor table size = 256
rdscr_base_addr = 0x10001080;

// RX data buffer base address
rx_buf_base_addr = 0x10002680;

// TX pending queue base address
tpq_base_addr = 0x10059084;

// TX pending queue end address
// - TX pending queue size = 16
tpq_end_idx = 0x000F;

// TX done queue base address
tdq_base_addr = 0x10059604;

// TX done queue end address
// - TX done queue size = 16
tdq_end_idx = 0x000F;

// TX descriptor base address
// - TX descriptor table size = 256
tdscr_base_addr = 0x10059B84;

// TX data buffer base address
tx_buf_base_addr = 0x1005B184;
Configure the PCI Registers
In configuration mode the PCI registers control how the DS3134 interfaces to the PCI bus when performing DMA operations. PCI register configuration is system dependent and therefore the coding example below may need to be modified to support a particular user application.

Offset/ Address Acronym Register Name Data Sheet Section
0x004/0A04 PCMD0 PCI Command Status 0 9.2

// PCI command/status register 0 - controls DS3134 DMA functionality
// Set Bit 2 = 1 to allow device operation as bus master on PCI bus (required for DMA)
// Set bit 6 = 1 to act on parity errors
// Set bit 8 = 1 to enable PSERR pin
write_reg(PCMD0, 0x0144);
Configure the Layer 1 Registers
Each port of the DS3134 contains a layer 1 controller that performs several functions including:

  • Assigning the HDLC channel number to the incoming and outgoing data
  • Channelized local and network loopbacks
  • Channelized selection of 64 kps, 56 kps or no data
  • Channelized transmit DS0 channel fill of all ones
  • Routing data to and from the BERT function
  • Routing data to the V.54 loop pattern detector
Layer 1 configuration is performed on a port basis via the RP[n]CR, TP[n]CR, CP[n]RD, and CP[n]RDIS registers where n is the port to be configured.

Offset/ Address Acronym Register Name Data Sheet Section
01xx RP[n]CR Receive Port n Control Register 5.2
02xx TP[n]CR Transmit Port n Control Register 5.2
03xx CP[n]RDIS Channelized Port n Register Data Indirect Select 5.3
03xx CP[n]RD Channelized Port n Register Data 5.3

// Set RX Port Control Register
// Set bits 2-0 = 000 for clock, data and sync are not inverted
// Set bits 5-4 = 00 for sync pulse 0 clocks early
// Set bits 7-6 = 11 for 8 MHz mode
// Set bit 10 = 0 to disable local loopback
write_reg(RP0CR + 4*port, 0x00C0);

// Set TX Port Control Register
// Set bit 2-0 = 000 for clock, data and sync are not inverted
// Set bit 3 = 0 to force all data at TD to be 1
// Set bits 5-4 = 00 for sync pulse 0 clocks early
// Set bits 7-6 = 11 for 8 MHz mode
write_reg(TP0CR + 4*port, 0x0C00);

// RX Port Configuration Registers
// DS0's 0-126 disabled, assigned to HDLC channel
// CP[n]RDIS bits 9-8 = 01 for Receive Configuration
write_reg(CP0RD + 8*port, 0x0000 + channel);
for(ds0=0; ds0<127; ds0=ds0+1)
	write_reg_IS(CP0RDIS + 8*port, 0x0100 + ds0);

// TX Port Configuration Registers
// DS0's 0-126 disabled, assigned to HDLC channel
// CP[n]RDIS bits 9-8 = 10 for Transmit Configuration
write_reg(CP0RD + 8*port, 0x0000 + channel);
for(ds0=0; ds0<127; ds0=ds0+1)
	write_reg_IS(CP0RDIS + 8*port, 0x0200 + ds0);

// Unchannelized workaround
// Set one DS0 to a separate HDLC channel
// After the chateau initializes, set it to the same as the other 127 (done later)
// Setting DS0 127 to HDLC channel 4
// RX Port
write_reg(CP0RD + 8*port, 0x0000 + (channel+1));
write_reg_IS(CP0RDIS + 8*port, 0x0100 + 127);

// TX port
write_reg(CP0RD + 8*port, 0x0000 + (channel+1));
write_reg_IS(CP0RDIS + 8*port, 0x0200 + 127);
Configure the HDLC Registers
The DS3134 contains a 256-channel HDLC controller, which performs the layer 2 functions. Functions performed by this controller include:

  • Zero stuffing and de-stuffing
  • Flag detection and byte alignment
  • CRC generation and checking
  • Data inversion and bit flipping
The HDLC controller is configured on a channel basis via the RHCD, RHCDIS, THCD, and THCDIS registers.

Offset/ Address Acronym Register Name Data Sheet Section
0400 RHCDIS Receive HDLC Channel Definition Indirect Select 6.2
0404 RHCD Receive HDLC Channel Definition 6.2
0480 THCDIS Transmit HDLC Channel Definition Indirect Select 6.2
0484 THCD Transmit HDLC Channel Definition 6.2

// RX HDLC configuration
// Set bits 3-2 = 10 for 32-bit CRC
write_reg(RHCD, 0x0008);
write_reg_IS(RHCDIS, channel);

// TX HDLC configuration
// Set bit 1= 0 to select an interfill byte of 7E
// Set bits 3-2 = 10 for 32-bit CRC
// Set bits 11-8 = 0000 share closing and opening flag
write_reg(THCD, 0x0008);
write_reg_IS(THCDIS, channel);
Configure the FIFO Registers
The DS3134 contains a 16K-byte transmit FIFO and a 16K-byte receive FIFO. Each FIFO is divided into 1024 blocks of 4 dwords or 16 bytes. FIFO memory is allocated on an HDLC channel basis. The amount of FIFO memory allocated to each HDLC channel is programmable and can be a minimum of 4 blocks and a maximum of 1024 blocks. FIFO memory is allocated to HDLC channels by creating a circular linked list out of a group of blocks where each block points to the next block in the chain and the last block points to the first. The FIFO block linked list is assigned to a specific HDLC channel by assigning one block in the linked list to be that channel's FIFO starting block pointer.

In this example ten TX FIFO blocks and ten RX FIFO blocks are assigned to the HDLC channel. This example also uses an RX FIFO high water mark of 8 and TX FIFO low water mark of 4. The RX FIFO high water mark indicates how many blocks should be written into RX FIFO by the HDLC engines before the DMA will begin sending the data to the PCI Bus. The high water mark setting must be between one block and one less than the number of blocks in the link-list chain for the particular channel involved. The TX FIFO low water mark indicates how many blocks should be left in the TX FIFO before the DMA should begin getting more data from the PCI Bus. The amount of FIFO memory, RX FIFO high water mark, and TX FIFO low water mark required by an HDLC channel to prevent transmit underflows and receive overflows from occurring is application dependent. The TX FIFO and RX FIFO of the DS3134 are configured independently on an HDLC channel basis via the registers listed in the following tables.

Offset/ Address Acronym Register Name Data Sheet Section
0910 RFBPIS Receive FIFO Block Pointer Indirect Select 7.2
0914 RFBP Receive FIFO Block Pointer 7.2

// Build the RX FIFO block linked list
// 0->1->2->3->4 .... 9->0
for (block=0; block<9; block=block+1)
{
	// Bits 9-0 in RFBP register indicate which block is next in the
	// linked list
	write_reg(RFBP, block+1);
	write_reg_IS(RFBPIS, block);
}

// The last block points to the first block to create a circular linked list
write_reg(RFBP, 0x0000);
write_reg_IS(RFBPIS, 0x0009);

// Assign the circular linked list to a specific channel
write_reg(RFSBP, 0x0000);
write_reg_IS(RFSBPIS, channel);
Offset/ Address Acronym Register Name Data Sheet Section
0920 RFHWMIS Receive FIFO High Water Mark Indirect Select 7.2
0924 RFHWM Receive FIFO High Water Mark 7.2

// Set RX FIFO high water mark for channel to 8
write_reg(RFHWM, 0x0008);
write_reg_IS(RFHWMIS, channel);
Offset/ Address Acronym Register Name Data Sheet Section
0990 TFBPIS Transmit FIFO Block Pointer Indirect Select 7.2
0994 TFBP Transmit FIFO Block Pointer 7.2

// TX FIFO block linked list
// 0->1->2->3->4 ... 9->0
for (block=0; block<9; block=block+1)
{
	// Bits 9-0 in RFBP register indicate which block is next in the linked list
	write_reg(TFBP, block+1);
	write_reg_IS(TFBPIS, block);
}

// The last block points to the first block to create a circular linked list
write_reg(TFBP, 0x0000);
write_reg_IS(TFBPIS, 0x0009);
Offset/ Address Acronym Register Name Data Sheet Section
0980 TFSBPIS Transmit FIFO Starting Block Pointer Indirect Select 7.2
0984 TFSBP Transmit FIFO Starting Block Pointer 7.2

// Assign the circular linked list to a specific channel
write_reg(TFSBP, 0x0000);
write_reg_IS(TFSBPIS, channel);

// Set TX FIFO low water mark for channel to 4
write_reg(TFLWM, 0x0004);
write_reg_IS(TFLWMIS, channel);
Configure the DMA Registers
The DMA block handles the transfer of packet data from the FIFO block to the PCI block and vice versa. The PCI block controls data transfers between the DS3134 and the external PCI bus. The host, defined as the CPU or intelligent controller that sits on the PCI bus, instructs the DS3134 on how to handle the incoming and outgoing data.

This is accomplished using descriptors which are defined as pre-formatted messages passed from the host to the DMA block or vice versa. Via these descriptors, the host informs the DMA about the location and status of packet data to be transmitted, and where to place packet data that is received. The DMA uses these descriptors to tell the host the status of packet data that has been transmitted, and the status and location of packet data that has been received.

On the receive side the host will write to the free queue descriptors informing the DMA where it can place incoming packet data. Associated with each free queue entry is a receive data buffer location and packet descriptor. As the DS3134 uses receive free queue entries to write received packet data to host memory it creates entries in the RX done queue. These RX done queue entries inform the host about the location and status of received data. Refer to the DS3134 data sheet for more detailed information. The host must configure the RX DMA by writing to all the of the registers at the following table:

Offset/ Address Acronym Register Name Data Sheet Section
0700 RFQBA0 Receive Free Queue Base Address 0 (lower word) 8.1.3
0704 RFQBA1 Receive Free Queue Base Address 1 (upper word) 8.1.3
0708 RFQEA Receive Free Queue end Address 8.1.3
070C RFQSBSA Receive Free Small Buffer Start Address 8.1.3
0710 RFQLBWP Receive Free Queue Large Buffer Host Write Pointer 8.1.3
0714 FQSBWP Receive Free Queue Small Buffer Host Write Pointer 8.1.3
0718 RFQLBRP Receive Free Queue Large Buffer DMA Read Pointer 8.1.3
071C RFQSBRP Receive Free Queue Small Buffer DMA Read Pointer 8.1.3
0730 RDQBA0 Receive Done Queue Base Address 0 (lower word) 8.1.4
0734 RDQBA1 Receive Done Queue Base Address 1 (upper word) 8.1.4
0738 RDQEA Receive Done Queue end Address 8.1.4
073C RDQRP Receive Done Queue Host Read Pointer 8.1.4
0740 RDQWP Receive Done Queue DMA Write Pointer 8.1.4
0750 RDBA0 Receive Descriptor Base Address 0 (lower word) 8.1.2
0754 RDBA1 Receive Descriptor Base Address 1 (upper word) 8.1.2
0770 RDMACIS Receive DMA Configuration Indirect Select 8.1.5
0774 RDMAC Receive DMA Configuration 8.1.5
0790 RLBS Receive Large Buffer Size 8.1.1

// RX large buffer size = 256 bytes
write_reg(RLBS, 0x0100);

// RX free queue base address
write_reg(RFQBA0, rfq_base_addr & 0x0000FFFF);
write_reg(RFQBA1, (rfq_base_addr >> 16) & 0x0000FFFF);

// RX free queue large buffer read and write pointers = 0
write_reg(RFQLBRP, 0x0000);
write_reg(RFQLBWP, 0x0000);

// RX free queue small buffer start address = 16
write_reg(RFQSBSA, rfq_end_idx);

// RX free queue small buffer read and write pointers = 0
write_reg(RFQSBRP, 0x0000);
write_reg(RFQSBWP, 0x0000);

// RX free queue end address
write_reg(RFQEA, rfq_end_idx);

// RX done queue base address
write_reg(RDQBA0, rdq_base_addr & 0x0000FFFF);
write_reg(RDQBA1, (rdq_base_addr >> 16) & 0x0000FFFF);

// RX done queue read and write pointers = 0
write_reg(RDQRP, 0x0000);
write_reg(RDQWP, 0x0000);

// RX done queue end address
write_reg(RDQEA, rdq_end_idx);

// RX descriptor base address
write_reg(RDBA0, rdscr_base_addr & 0x0000FFFF);
write_reg(RDBA1, (rdscr_base_addr >> 16) & 0x0000FFFF);

// RX DMA Channel Configuration
// The data in RDMAC register is written to or read from the Receive Configuration RAM
// Set bit 0 = 0 to disable the HDLC Channel
// Set bit 201 = 00 for large buffers only
// Set bit 6-3 = 0000 for 0 byte offset from the data buffer address of the first data buffer
// Set Bit 9-7 = 000 for DMA write to the Done Queue only after packet reception is complete
// Set the HDLC Channel Number by RDMACIS register
write_reg(RDMAC, 0x0000);
write_reg_IS(RDMACIS, 0x0400 + channel);
On the transmit side the host will write to the pending queue informing the DMA which channels have packet data that is ready to be transmitted. Associated with each pending queue descriptor is a linked list of one or more transmit packet descriptors that describe the packet data. Each of these transmit packet descriptors also has a pointer to a transmit data buffer that contains the actual data payload of the HDLC packet.

As the DS3134 processes transmit pending queue descriptor entries it creates transmit done queue descriptor queue entries. The DMA will write to the done queue when it has completed transmitting either a complete packet or data buffer depending on how the DS3134 is configured. Via these done queue descriptors, the DMA informs the host about the status of the outgoing packet data. Refer to the DS3134 data sheet for more detailed information. The host must configure the TX DMA by writing to all the of the registers at the following table:

Offset/ Address Acronym Register Name Data Sheet Section
0800 TPQBA0 Transmit Pending Queue Base Address 0 (lower word) 8.2.3
0804 TPQBA1 Transmit Pending Queue Base Address 1 (upper word) 8.2.3
0808 TPQEA Transmit Pending Queue end Address 8.2.3
080C TPQWP Transmit Pending Queue Host Write Pointer 8.2.3
0810 TPQRP Transmit Pending Queue DMA Read Pointer 8.2.3
0830 TDQBA0 Transmit Done Queue Base Address 0 (lower word) 8.2.4
0834 TDQBA1 Transmit Done Queue Base Address 1 (upper word) 8.2.4
0838 TDQEA Transmit Done Queue end Address 8.2.4
083C TDQRP Transmit Done Queue Host Read Pointer 8.2.4
0840 TDQWP Transmit Done Queue DMA Write Pointer 8.2.4
0850 TDBA0 Transmit Descriptor Base Address 0 (lower word) 8.2.2
0854 TDBA1 Transmit Descriptor Base Address 1 (upper word) 8.2.2
0870 TDMACIS Transmit DMA Configuration Indirect Select 8.2.5
0874 TDMAC Transmit DMA Configuration 8.2.5

 // TX pending queue base address
write_reg(TPQBA0, tpq_base_addr & 0x0000FFFF);
write_reg(TPQBA1, (tpq_base_addr >> 16) & 0x0000FFFF);

// TX pending queue read and write pointers = 0
write_reg(TPQRP, 0x0000);
write_reg(TPQWP, 0x0000);

// TX pending queue end address
write_reg(TPQEA, tpq_end_idx);

// TX done queue base address
write_reg(TDQBA0, tdq_base_addr & 0x0000FFFF);
write_reg(TDQBA1, (tdq_base_addr >> 16) & 0x0000FFFF);

// TX done queue read and write pointers = 0
write_reg(TDQRP, 0x0000);
write_reg(TDQWP, 0x0000);

// TX done queue end address
write_reg(TDQEA, tdq_end_idx);

// TX descriptor base address
write_reg(TDBA0, tdscr_base_addr & 0x0000FFFF);
write_reg(TDBA1, (tdscr_base_addr >> 16) & 0x0000FFFF);

// TX DMA Channel Configuration
// The data in TDMAC register is written to or read from the Receive Configuration RAM
// Set bit 0 = 0 to disable HDLC Channel
// Set bit 1 = 0 for write done queue after packet transmitted
// Set the HDLC Channel Number by TDMACIS register
write_reg(TDMAC, 0x0000);
write_reg_IS(TDMACIS, 0x0200 + channel);

Enable The HDLC Channel
After the DS3134 has been initialized the next step is to enable the HDLC channel. In addition to the configuration steps already described, the following steps must be performed to enable packet transmission and reception in the DS3134:

  1. Enable the channel in the port TX and RX configuration RAM's
  2. Enable port data transmission in Layer 1
  3. Enable TX DMA and RX DMA for the DS3134
  4. Enable HDLC channel TX DMA and RX DMA
Offset/ Address Acronym Register Name Data Sheet Section
0010 MC Master Configuration Register 4.2
02xx TP[n]CR Transmit Port n Control Register 5.2
03xx CP[n]RDIS Channelized Port n Register Data Indirect Select 5.3
03xx CP[n]RD Channelized Port n Register Data 5.3
0770 RDMACIS Receive DMA Configuration Indirect Select Register 8.1.5
0774 RDMAC Receive DMA Configuration Register 8.1.5
0870 TDMACIS Transmit DMA Configuration Indirect Select Register 8.2.5
0874 TDMAC Transmit DMA Configuration Indirect Select Register 8.2.5

// Enable packet reception in port layer 1 RX configuration RAM
for (ds0=0; ds0<128; ds0=ds0+1)
{
	// Read the current data value from the RX Configuration RAM
	// Set CP[n]RDIS bits 6-0 = DS0
	// Set CP[n]RDIS bit 14 = 1 to read data from the RAM
	// Set CP[n]RDIS bits 9-8 = 01 to select RX configuration RAM
	write_reg_IS(CP0RDIS + 8*port, 0x4100 + ds0);
	read_reg(CP0RD + 8*port, data);

	// Activate DS0s
	// Set CP[n]RDIS bits 6-0 = DS0
	// Set CP[n]RDIS bit 14 = 0 to write data to the RAM
	// Set CP[n]RDIS bits 9-8 = 01 to select RX configuration RAM
	// Enable DS0 by setting bit 15 = 1 in CP[0]RD register
	write_reg(CP0RD + 8*port, data | 0x8000);
	write_reg_IS(CP0RDIS + 8*port, 0x0100 + ds0);
}

// Enable packet transmission in Port Layer 1 TX configuration RAM
for (ds0=0; ds0<128; ds0=ds0+1)
{
	// Read the current data value from the TX Configuration RAM
	// Set CP[n]RDIS bits 6-0 = DS0
	// Set CP[n]RDIS bit 14 = 1 to read data from the RAM
	// Set CP[n]RDIS bits 9-8 = 10 to select TX configuration RAM
	write_reg_IS(CP0RDIS + 8*port, 0x4200 + ds0);
	read_reg(CP0RD + 8*port, data);

	// Activate DS0s
	// Set CP[n]RDIS bits 6-0 = DS0
	// Set CP[n]RDIS bit 14 = 0 to write data to the RAM
	// Set CP[n]RDIS bits 9-8 = 10 to select TX configuration RAM
	// Enable DS0 by setting bit 15 = 1 in CP[0]RD register
	write_reg(CP0RD + 8*port, data | 0x8000);
	write_reg_IS(CP0RDIS + 8*port, 0x0200 + ds0);
}

// TX port control register
// Set Bit 3 = 1 to allow data to be transmitted normally
read_reg(TP0CR + 4*port, data);
write_reg(TP0CR + 4*port, data | 0x0008);
Offset/ Address Acronym Register Name Data Sheet Section
0010 MC Master Configuration 4.2

// Enable TX and RX DMA in the DS3134 master configuration register
// Set bit 0 = 1 to enable Receive DMA
// Set bits 2-1 = 00 to burst length maximum is 32 dwords
// Set bit 3 = 1 to enable Transmit DMA
// Set bits 6 = 1 for HDLC packet data on PCI bus is big endian
// Set bits 11-7 = 00000 to select Port 0 has the dedicated resources of the BERT
write_reg(MC, 0x0049);

// Read the current channel value from the RX DMA Configuration RAM
// Set RDMACIS bits 7-0 = channel
// Set RDMACIS bits 10-8 = 100 to read lower word of dword 2
// Set RDMACIS bit 14 = 1 to read from RAM
write_reg_IS(RDMACIS, 0x4400 + channel);
read_reg(RDMAC, data);

// Enable channel RX DMA
// Update RAM with new value
// Set RDMAC bit 0 = 1 to enable the HDLC channel
// Set RDMACIS bits 7-0 = channel
// Set RDMACIS bits 10-8 = 100 to write lower word of dword 2
// Set RDMACIS bit 14 = 0 to write to RAM
write_reg(RDMAC, data | 0x0001);
write_reg_IS(RDMACIS, 0x0400 + channel);

// Read the current channel value from the TX DMA Configuration RAM
// Set TDMACIS bits 7-0 = channel
// Set TDMACIS bits 11-8 = 0010 to read lower word of dword 1
// Set TDMACIS bit 14 = 1 to read from RAM
write_reg_IS(TDMACIS, 0x4200 + channel);
read_reg(TDMAC, data);

// Enable channel TX DMA
// Update RAM with new value
// Set TDMAC bit 0 = 1 to enable the HDLC channel
// Set TDMACIS bits 7-0 = channel
// Set TDMACIS bits 11-8 = 0010 to write lower word of dword 1
// Set TDMACIS bit 14 = 0 to write to RAM
write_reg((TDMAC, data | 0x0001);
write_reg_IS(TDMACIS, 0x0200 + channel);

Place the HDLC Channel in Loopback Mode
After the channel has been configured and enabled it takes approximately 5 frame periods, or 625 microseconds, for the internal logic of the DS3134 to complete the transition to the new configuration. Once this transition has completed the HDLC channel can then be placed in loopback mode so that all data transmitted on the channel will also be received on that channel. Placing the HDLC channel in loopback mode prior to the 5-frame wait period may result in garbage data being written into the channel's RX FIFO.

Offset/ Address Acronym Register Name Data Sheet Section
01xx RP[n]CR Receive Port n Control Register 5.2

// Wait for at least 5 frame periods for the internal DS3134 initialization to complete
frame_wait(5);
Unchannelized Workaraound—Reassign DS0 127 to correct HDLC channel

// Setting DS0 127 to HDLC channel 3
// bit 15 of CP[port]RD must be a one to activate the DS0
// RX Port
write_reg(CP0RD + 8*port, 0x8000 + channel);
write_reg_IS(CP0RDIS + 8*port, 0x0100 + 127);

// TX port
write_reg(CP0RD + 8*port, 0x8000 + channel);
write_reg_IS(CP0RDIS + 8*port, 0x0200 + 127);

// Wait for 5 frame periods to allow new initialization to complete
frame_wait(5);
// Set Bit 10 = 1 to enable loopback - routes transmit data back to the receive port
read_reg(RP0CR + 4*port, data);
write_reg(RP0CR + 4*port, data | 0x0400);

Queue, Send, Receive, And Check A Data Packet
Once the DS3134 initialization has been completed, data can be transmitted and received. Since the DS3134 is in loopback mode all data transmitted on the HDLC channel will also be received on that channel. This section will describe the process of how to build a data packet in host memory, transmit and receive the packet, and check the results. The following sections describe this process in detail.

Initialize the RX Free Queue
Before the DS3134 can transfer received packets from its internal FIFO to host memory, the host must instruct the DS3134 where to put the data. This is done via the RX free queue. Each entry in the RX free queue contains a pointer to an RX data buffer and an RX packet descriptor index. This example uses ten RX free queue entries. Each entry contains one RX free queue large buffer and one RX packet descriptor. The DS3134 RX large data buffer size has been set to 256 bytes (RLBS = 256). Additionally, the DS3134 has been configured to use a 4-byte CRC and to write the RX CRC into the RX data buffer. Therefore one RX large data buffer is capable of holding up to 252 bytes of packet data.

Offset/ Address Acronym Register Name Data Sheet Section
0710 RFQLBWP Receive Free Queue Large Buffer Host Write Pointer 8.1.3
0718 RFQLBRP Receive Free Queue Large Buffer DMA Read Pointer 8.1.3

// check for space in RX large free queue
read_reg(RFQLBWP, wr_ptr);
read_reg(RFQLBRP, rd_ptr);

if (rd_ptr > wr_ptr)
	cnt = rd_ptr - wr_ptr - 1;
else
	cnt = rfq_end_idx - wr_ptr + rd_ptr;

// If room in RX free queue then put 10 entries in the queue
// dword 0 = RX data buffer address
// (use RX data buffer starting at RX buffer area base address)
// dword 1 = corresponding RX descriptor index (use RX descriptor table index 0)
if (cnt > 9)
{
	rx_dscr_idx = 0;

	for (index=0, index<10, index++)
	{
		wr_dword(rfq_base_addr + wr_ptr*8, rx_buf_base_addr+index*256);
		wr_dword(rfq_base_addr + wr_ptr*8+4, index);

		if (wr_ptr == rfq_end_idx)
			wr_ptr = 0;
		else
			wr_ptr++;
	}

	// Advance the RX free queue large buffer write pointer by 10
	write_reg(RFQLBWP, wr_ptr);
}
Build the Packet In Host Memory
This example will send a 16-byte data packet. Before a packet can be sent it must be constructed in the host memory. Additionally, a corresponding TX packet descriptor must also be constructed in host memory. Each of these tasks is detailed in the following code.

// Create a 16-byte data packet in memory in a TX buffer whose start address is the TX buffer area base
// address
wr_dword(tx_buf_base_addr, 0x01234567);
wr_dword(tx_buf_base_addr + 4, 0x89ABCDEF);
wr_dword(tx_buf_base_addr + 8, 0x02468ACE);
wr_dword(tx_buf_base_addr + 12, 0x13579BDF);

//Second data packet goes in second data buffer (16 byte packet in 256 byte buffer).
wr_dword(tx_buf_base_addr+256, 0x08192A3B);
wr_dword(tx_buf_base_addr + 256+4, 0x4D5E6F70);
wr_dword(tx_buf_base_addr + 256+8, 0x8192A3B4);
wr_dword(tx_buf_base_addr + 256+12, 0xC5D6E7F8);
// Create 8 more packets with unique data in each.
Create Ten TX Descriptors (4 dwords each)
// TX descriptor table index 0
// dword0 = TX buffer address
// dword1 = EOF, CV, byte count (10h), next descriptor pointer
// dword2 = HDLC channel
// dword3 = PV, next pending descriptor pointer (set to 0)
tx_dscr_idx = 0;
for (index=0, index<10, index++)
{
	wr_dword(tdscr_base_addr + index*16, tx_buf_base_addr+index*256);

	if (index==9)
		wr_dword(tdscr_base_addr + index*16 + 4, 0x80100000); // end of chain, CV set to 0
	else
		wr_dword(tdscr_base_addr + index*16 + 4, 0xC0100000 + index+1);

	wr_dword(tdscr_base_addr + index*16 + 8, 0x00000000 + channel);
	wr_dword(tdscr_base_addr + index*16 + 12, 0x00000000);
}

// This creates 10 TX descriptors that are chained or linked together via the 'next descriptor pointer'.
Transmit and Receive The Packet
In order to transmit the packet, the TX descriptor must be placed in the transmit pending queue and then the transmit pending queue write pointer (TPQWP) must be incremented. When the DS3134 detects that pending queue is not empty (TPQWP not equal to TPQRP) it will begin processing queue entries and the packet will be transmitted.

Offset/ Address Acronym Register Name Data Sheet Section
0028 SDMA Status Register for DMA 4.3.2
080C TPQWP Transmit Pending Queue Host Write Pointer 8.2.3
0810 TPQRP Transmit Pending Queue DMA Read Pointer 8.2.3

// Read SDMA register to clear any previously set status bits
read_reg(SDMA, data);
Write the TX Pending Queue Entry
// check free space in TX pending queue
read_reg(TPQWP, wr_ptr);
read_reg(TPQRP, rd_ptr)

if (rd_ptr > wr_ptr)
	cnt = rd_ptr - wr_ptr - 1;
else
	cnt = rfq_end_idx - wr_ptr + rd_ptr;

// If room in the TX pending queue create an entry for the packet
if (cnt > 0)
{
	// Bits 0-15 Descriptor Pointer (0000h)
	// Bits 16-23 HDLC channel - (channel << 16)
	wr_dword(tpq_base_addr + wr_ptr*4, 0x0000000 + (channel << 16));

	// Advance the TX pending queue write pointer
	if (wr_ptr == tpq_end_idx)
		wr_ptr = 0;
	else
		wr_ptr = wr_ptr + 1;

	write_reg(TPQWP, wr_ptr);
}
Check the Results
After waiting a sufficient period of time for the packet to be transmitted and received several checks can be performed to determine if packet transmission and reception was successful. The following code details these checks.

Offset/ Address Acronym Register Name Data Sheet Section
0028 SDMA Status Register for DMA 4.3.2
0710 RFQLBWP Receive Free Queue Large Buffer Host Write Pointer 8.1.3
0718 RFQLBRP Receive Free Queue Large Buffer DMA Read Pointer 8.1.3
073C RDQRP Receive Done Queue Host Read Pointer 8.1.4
0740 RDQWP Receive Done Queue DMA Write Pointer 8.1.4
083C TDQRP Transmit Done Queue Host Read Pointer 8.2.4
0840 TDQWP Transmit Done Queue DMA Write Pointer 8.2.4

// wait 2 frame periods for packet to be transmitted/received
frame_wait(2);

// Check SDMA register
// Expected value = 0x6440, if not, it means there was error
read_reg(SDMA, data);

// Check to see how many entries are in the TX done queue (distance from TDQRP to TDQWP)
// Expected value is 0Ah - ten entries in the TX done queue corresponding to the 10 packets that were sent
read_reg(TDQRP, rd_ptr);
read_reg(TDQWP, wr_ptr);

if (wr_ptr >= rd_ptr)
	cnt = wr_ptr - rd_ptr;
else
	cnt = tdq_end_idx + 1 - rd_ptr + wr_ptr;

// Check TX done queue descriptor
// Expected value = 0x0003000
// Bits 15-0 indicates the descriptor pointer
// Bits 23-16 indicate the channel number, it should be 3 in this example
// Bits 28-26 indicate the packet status, all 0 means the packet transmission is complete and the descriptor
// pointer field corresponds to the first descriptor in the HDLC packet that has been transmitted
for (index=0; index<10; index++)
{
	rd_dword(tdq_base_addr + rd_ptr*4, tdq_entry);

	// Advance the TX done queue read pointer
	if (rd_ptr == tdq_end_idx)
		rd_ptr = 0;
	else
		rd_ptr = rd_ptr + 1;

	write_reg(TDQRP, rd_ptr);
}

// Check the RX large free queue to see how many RX buffers are in the queue (distance from RFQLBRP
// to RFQLBWP)
// Expected number is 0 since the queue had 10 buffers before the packet was received and packet
// reception required 10 buffers
read_reg(RFQLBRP, rd_ptr);
read_reg(RFQLBWP, wr_ptr);

if (wr_ptr >= rd_ptr)
	cnt = wr_ptr - rd_ptr;
else
	cnt = rfq_end_idx + 1 - rd_ptr + wr_ptr;

// Check RX done queue to see if any packets were received (distance from RDQRP to RDQWP)
// Expected value is 10 - ten entries in the RX done queue entry corresponding to the ten packets that
// should have been received
read_reg(RDQRP, rd_ptr);
read_reg(RDQWP, wr_ptr);

if (wr_ptr >= rd_ptr)
	cnt = wr_ptr - rd_ptr;
else
	cnt = rdq_end_idx + 1 - rd_ptr + wr_ptr;

// Check the RX done queue descriptor
// Expected value = 0x40030000,
// Bits 15-0 indicates the descriptor pointer
// Bits 23-16 indicate the channel number, it should be 3 in this example
// Bits 26-24 indicate the buffer count, all 0 means that a complete packet has been received
// Bit 30 EOF=1 indicates the Receiver Descriptor is the last one in the chain
for (index=0;index<10;index++) //check all 10 entries
{
	rd_dword(rdq_base_addr + 8*rd_ptr, rdq_entry);
	// Check the corresponding RX descriptor (4 dwords)
	// dword 0 expected value = 0x10002680 the RX buffer address
	// dword 1 expected value = 0x80140000
	// Bits 15-0 is the next descriptor pointer
	// Bits 28-16 is the number of bytes stored in the data buffer
	// Bits 31-29 indicates buffer status
	// dword 2 expected value = 0xxxxxxx03
	// Bits 7-0 indicates HDLC channel number (should match TDQ entry channel)
	// Bits 31-8 indicates the timestamp (varies)
	rdscr_idx = rdq_entry & 0x0000FFFF;
	rd_dword(rdscr_base_addr + 16*rdscr_idx, rdscr_dword0);
	rd_dword(rdscr_base_addr + 16*rdscr_idx + 4, rdscr_dword1);
	rd_dword(rdscr_base_addr + 16*rdscr_idx + 8, rdscr_dword2);

	// Check the data in the RX buffer
	// 16 bytes of data + 4-byte CRC
	// Expected values = 0x01234567
	// 0x89ABCDEF
	// 0x02468ACE
	// 0x13579BDF
	// 0x05127B09 (4-byte CRC)
	byte_count = (rdscr_dword1 >> 16) & 0x00001FFF;
	for (addr=rdscr_dword0, addr<rdscr_dword0+byte_count; addr=addr+4)
	rd_dword(addr, data);

	// Advance the RX done queue read pointer
	if (rd_ptr == rdq_end_idx)
		rd_ptr = 0;
	else
		rd_ptr = rd_ptr + 1;

	write_reg(RDQRP, rd_ptr);
}