A DSP-based decompressor unit for high-fidelity MPEG-Audio over TCP/IP networks

Copyright 1997 by Björn Wesén at Axis Communications AB, Sweden

[ Home | Contents | Component and tool archive ]


Previous chapter: Appendix A, next chapter: Appendix C

Appendix B - The logic code for the MACH chip

The statemachines and gluelogic needed in the Whitney hardware are all contained in a MACH-210 device from AMD. The synthesis language used is AMD's MACHXL. The sourcefile for the device in Whitney follows below:


#TITLE 'Whitney Parloading Controller and D/A clocking';
#ENGINEER 'Bjorn Wesen';
#REVISION '0.1';

input MYRESET; "from the reset generator - same as the DSP gets, active low
input CLK0, CLK1; "CLK0 is a 15 MHz clock, CLK1 is a 384*fs clock from the DA
input STRB, INIT, AUTOFD, SELIN;
output ACK clocked_by CLK1 reset_by /MYRESET default_to last_value; 
output PE, DIR, ERR, SEL, INT3;
output BUSY clocked_by CLK1 reset_by /MYRESET default_to last_value; 
input PD[8];
input XF0, XF1, TCLK0, TCLK1;

output CLKR clocked_by CLK1 reset_by /MYRESET default_to last_value; 
output FSR clocked_by CLK1 reset_by /MYRESET default_to last_value; 

output TEST1, TEST2;

" the 8-bit internal shift register
output DR clocked_by CLK1 reset_by /MYRESET default_to last_value; "this is the MSB
node SDAT[7] clocked_by CLK1 reset_by /MYRESET default_to last_value; "these are bits 6-0

node bytecount[2] clocked_by CLK1 reset_by /MYRESET default_to last_value; "counting the 4 bytes per 32-bit wor
d

node strblatch clocked_by CLK1 reset_by /MYRESET;

"Receive data (DR) is latched into the receive shift register of the DSP on the falling
"edge of the serial-port clock (CLKR).

"Data from the parallel port PD[0..7] is serialized using the shift register SDAT[0..7].
"Whenever a byte is loaded (by /STRB) into the SDAT register, eight CLKR clocks are 
"generated and SDAT[7] is equal to DR, the serial data into the DSP. Before the start of
"each fourth 8-bit transfer, a frame synch (FSR) is generated during one CLKR period, to
"tell the DSP's serial port that a transfer is beginning. When the eight bits have been
"transferred, an ACK signal back to the host is generated, we wait for /STRB to go inactive,
"and then we're back to standby.

"Serial-port timings are given on page 13-55 of the TMS320C3x User's Guide
"FSR is detected at the falling edge of CLKR, and should therefore preferably be setup
"at the rising edge of CLKR and kept during the whole period. 
"Received serial data (DR) is latched at the falling edge of CLKR.

"D/A Interfacing:
"When the DSP is transmitting, using internal FSX, FSX and DX are valid on the 
"falling edge of CLKX. FSX is setup one CLKX period before the first bit is sent.
"Since the D/A shifts on the RISING edge of BCKIN (CLKX), we configure the DSP's transmitter
"to invert polarity sense on CLKX. So, FSX and DX is valid on the rising edge of CLKX.
"
"The DSP is configured for fixed continous mode with frame sync. Our task is to take the
"384*fs sampleclock from the D/A, divide it down to a 32*fs clock, feed that into the
"DSP's CLKX and the D/A's BCKIN, and generate the LRCIN signal to the D/A so it knows 
"when to latch data. FSX is configured to be internally generated in the DSP. 
"
"The LRCIN signal can easily be constructed from the FSX signal coming from the DSP. When
"we detect the FSX, we know that the DSP will send 32 bits directly after. We set LRCIN
"high, count 16 bits, set LRCIN low, then wait for the next FSX (that will come after 16
"more clocks, preferably :).

output DALR clocked_by CLK1 reset_by /MYRESET default_to last_value;
input FSX;
output CLKX clocked_by CLK1 reset_by /MYRESET default_to last_value;

node dabitcount[5] clocked_by CLK1 reset_by /MYRESET default_to last_value;

"Make a division by 12 to turn the 384fs into 32fs
node fsdiv[3] clocked_by CLK1 reset_by /MYRESET;
if (fsdiv = 5) then
	CLKX = /CLKX;
	fsdiv = 0;
else
	fsdiv = fsdiv .+. 1;
end if;

"we count bits on the rising edge of CLKX
if ((fsdiv = 0) and CLKX) then
	if (FSX) then
	"if FSX, we reset the bit counter
		dabitcount = 0;
	else
	"count transmitted bits
		dabitcount = dabitcount .+. 1;
	end if;
end if;

"we change DALR/LRCIN state on the falling edges of CLKX
if ((fsdiv = 0) and /CLKX) then
	if (dabitcount = 0) then
		DALR = 1;
	elsif (dabitcount = 16) then
		DALR = 0;
	end if;
end if;


"The STROBE from PC's looks awful. It rises monotonically but very slow, like passed
"through a big low-pass filter. Therefore, it isn't good to use it directly in the
"state machine transition conditions, since it might be misinterpreted as a 1 or 0 
"in different state equations. A latch (strblatch) is used to keep an internal,
"hopefully safe, copy of STRB.

strblatch = STRB;

"The PARLOADER state machine controls the serialization of parallel input.

state_machine PARLOADER
	clocked_by CLK1
	reset_by /MYRESET
	default_to last_value;

	state bootup:
	"this state wouldn't be necessary if reset_by worked for bytecount. it doesnt,
	"bytecount boots up in 01 instead of 00, so we have to manually reset it here
	"(since the reset of the state machine works)
		bytecount = 0;
		BUSY = 1;
		goto standby;

	state standby:
		ACK = 0;
		if (/strblatch) then
			BUSY = 0; " set BUSY active, wont go inactive until next standby
			DR = PD[7]; " latch in MSB
			SDAT[0..6] = PD[0..6]; " latch in bits 6 to 0
			CLKR = 1;
			" check if this is the first byte in a 32-bit word, then we do frame synching
			if (bytecount = 0) then
				FSR = 1; "signal to the DSP that a new 32-bit transfer will start soon
				goto fsr1;
			else
				goto dat11; "directly start clocking out the byte
			end if;
		else
			if (XF1 and (bytecount = 0)) then
				BUSY = 0; "while XF1 is high, we don't want new transfers so keep the host BUSY
			else
				BUSY = 1;
			end if; 
		end if;

	state fsr1:
		CLKR = 0;
		goto fsr2;

	state fsr2:
		"prepare first bit for DR, its already there
		CLKR = 1;
		FSR = 0; "dont need the FSR bit anymore
		goto dat11;

	state dat11:
		CLKR = 0;
		goto dat12;

	state dat12:
		"prepare next bit by shifting
		DR = SDAT[6];
		SDAT[6] = SDAT[5];
		SDAT[5] = SDAT[4];
		SDAT[4] = SDAT[3];
		SDAT[3] = SDAT[2];
		SDAT[2] = SDAT[1];
		SDAT[1] = SDAT[0];
		CLKR = 1;
		goto dat21;

	state dat21:
		CLKR = 0;
		goto dat22;

	state dat22:
		"prepare next bit by shifting
		DR = SDAT[6];
		SDAT[6] = SDAT[5];
		SDAT[5] = SDAT[4];
		SDAT[4] = SDAT[3];
		SDAT[3] = SDAT[2];
		SDAT[2] = SDAT[1];
		SDAT[1] = SDAT[0];
		CLKR = 1;
		goto dat31;

	state dat31:
		CLKR = 0;
		goto dat32;

	state dat32:
		"prepare next bit by shifting
		DR = SDAT[6];
		SDAT[6] = SDAT[5];
		SDAT[5] = SDAT[4];
		SDAT[4] = SDAT[3];
		SDAT[3] = SDAT[2];
		SDAT[2] = SDAT[1];
		SDAT[1] = SDAT[0];
		CLKR = 1;
		goto dat41;

	state dat41:
		CLKR = 0;
		goto dat42;

	state dat42:
		"prepare next bit by shifting
		DR = SDAT[6];
		SDAT[6] = SDAT[5];
		SDAT[5] = SDAT[4];
		SDAT[4] = SDAT[3];
		SDAT[3] = SDAT[2];
		SDAT[2] = SDAT[1];
		SDAT[1] = SDAT[0];
		CLKR = 1;
		goto dat51;

	state dat51:
		CLKR = 0;
		goto dat52;

	state dat52:
		"prepare next bit by shifting
		DR = SDAT[6];
		SDAT[6] = SDAT[5];
		SDAT[5] = SDAT[4];
		SDAT[4] = SDAT[3];
		SDAT[3] = SDAT[2];
		SDAT[2] = SDAT[1];
		SDAT[1] = SDAT[0];
		CLKR = 1;
		ACK = 1;
		goto dat61;

	state dat61:
		CLKR = 0;
		goto dat62;

	state dat62:
		"prepare next bit by shifting
		DR = SDAT[6];
		SDAT[6] = SDAT[5];
		SDAT[5] = SDAT[4];
		SDAT[4] = SDAT[3];
		SDAT[3] = SDAT[2];
		SDAT[2] = SDAT[1];
		SDAT[1] = SDAT[0];
		CLKR = 1;
		goto dat71;

	state dat71:
		CLKR = 0;
		goto dat72;

	state dat72:
		"prepare next bit by shifting
		DR = SDAT[6];
		SDAT[6] = SDAT[5];
		SDAT[5] = SDAT[4];
		SDAT[4] = SDAT[3];
		SDAT[3] = SDAT[2];
		SDAT[2] = SDAT[1];
		SDAT[1] = SDAT[0];
		CLKR = 1;
		goto dat81;

	state dat81:
		CLKR = 0;
		"increase the bytecount
		bytecount = bytecount .+. 1;
		goto doack;

	state doack:
		"give an ACK back to the host, then wait for it to release /STRB
		if (strblatch) then
			goto standby;
		end if;

end PARLOADER;


" outputs we dont use but which need values
" In Centronics, the host requires SELECT active, and BUSY and PE
" inactive, before sending anything. 
" Normally, BUSY shall go active after the strobe and until the
" end of the ACK.

PE = 1; "active low
DIR = 0; "0 for data input, 1 for output FROM dsp
ERR = 0; "active high
SEL = 0; "active low
INT3 = 0; "0 to activate serial bootloader mode in DSP

TEST1 = bytecount[0];
TEST2 = bytecount[1];
Previous chapter: Appendix A, next chapter: Appendix C

This document may be freely distributed for educational purposes. See the copyright notice for additional information.