.en
.ps 11
.vs 13
.hy 0
.nr sf .25i
.ps +2
.vs +2
.ce 1000
.ft B
An Example Application for the TMU Package
.sp
.ps -2
.vs -2
.ft I
Dave Galloway
.sp
Edward S. Rogers Sr. Department of Electrical and Computer Engineering
University of Toronto
.sp
April 2013
.ce 0
.ft R
.ds TL ''- % -''
.su
Introduction
.pp
This document describes a simple application circuit
for the TMU package on the DE-4 demonstration board, and
explains how to create, compile and run it.
.pp
The circuit implements a 32-bit counter.
A program running on a workstation will read the output of the counter over
the network.
.su
Getting the Source for the Circuit
.pp
The source for this example circuit is on the EECG machines in the
directory ~tm4/tmu/examples/de4/counter.
.pp
Sign on to one of the EECG Debian Linux workstations (ex: islanders.eecg).
Make a new directory, and copy some of the files from
the example directory:
.sp
.ft CW
.in +1i
.nf
mkdir counter
cd counter
mydir=`pwd`
pushd ~tm4/tmu/examples/de4/counter
cp makefile top.qpf top.sdc top.qsf $mydir
cp counter.v top.v top.ports suncounter.c $mydir
cp EXT_PLL_CTRL.v $mydir
popd
.fi
.in -1i
.ft R
.pp
Add the following directory to your path, so that the Transmogrifier
commands are available to you:
.sp
.ft CW
.in +1i
.nf
PATH="/jayar/i/tm4/bin:$PATH"
.fi
.in -1i
.ft R
.sp
You should probably add that line to your .profile file so that the change will
be permanent.
.pp
The files that you copied include:
.l1
.le
\f(CWcounter.v\fP	the circuit that will run on the board,
described in Verilog
.le
\f(CWtop.v\fP		a top level wrapper that connects counter.v to the
.le
\f(CWEXT_PLL_CTRL.v\fP	a Verilog file that describes some pll information
needed by the DE-4
.le
\f(CWtop.sdc\fP	a file containing timing constraints for Altera's Quartus software
.le
\f(CWtop.qsf\fP	a file containing compiler settings for Altera's Quartus software
.le
\f(CWtop.qpf\fP	another file that Altera's Quartus software wants to have
.le
\f(CWtop.ports\fP	a description of the inputs and outputs of the circuit
.le
\f(CWmakefile\fP	used to compile the circuit and the program
.le
\f(CWsuncounter.c\fP	a C program that runs on a UNIX workstation and talks
to the circuit
.e1
.su "Compiling the Example"
.pp
To compile the circuit into a form that can be used to program the board,
type:
.sp
.ft CW
.in +1i
.nf
make bits
.fi
.in -1i
.ft R
.sp
The circuit source will be compiled by the \f(CWquartus_sh\fP
and \f(CWqcmd\fP commands that are supplied with
Altera's Quartus software.
The results, along with a number of intermediate files, will be placed into
your current directory.
The whole process will take about 5 minutes.
.pp
To compile the program that runs on a Linux workstation and talks to the
circuit, type:
.sp
.ft CW
.in +1i
.nf
make linux_counter
.fi
.in -1i
.ft R
.su "Downloading the Example to the Board"
.pp
First, you must decide which demonstration board you want to use.
By default, the commands will use the DE-4 board attached to
skynet.eecg.
If you want to use a different board, you must set the
TM_SERVER environment variable to the name of the workstation that is
attached to the board you want, something like this:
.sp
.ft CW
.in +1i
.nf
export TM_SERVER=some_other_machine.eecg
.fi
.in -1i
.ft R
.pp
At this point, you may want to run the status monitor display on your
workstation.
Make sure your DISPLAY environment variable is set correctly and run:
.sp
.ft CW
.in +1i
.nf
tmstatus -t &
.fi
.in -1i
.ft R
.sp
This will produce a new window on your screen which displays the name of
the person currently using the board, if any.
.pp
Now use the \f(CWtmget\fR command to reserve the board for 10 minutes:
.sp
.ft CW
.in +1i
.nf
tmget
.fi
.in -1i
.ft R
.sp
If someone else is using the machine, you will get a message telling you
how long you will have to wait:
.sp
.ft CW
.in +1i
.nf
sorry, drg has it (priority 100) for 597 more seconds
.fi
.in -1i
.ft R
.pp
To download your circuit into the board, run:
.sp
.ft CW
.in +1i
.nf
quartus
.fi
.in -1i
.ft R
.sp
open the \f(CWtop.qpf\fP project and use the Quartus programmer tool
to communicate with the USBblaster cable attached to the board.
.su
Interacting with the Circuit
.pp
To communicate with the circuit, run the linux_counter program that
you compiled earlier:
.sp
.ft CW
.in +1i
.nf
% linux_counter
0 1 2 3 4 5 6 7 8 9 
.fi
.in -1i
.ft R
.sp
Every time you run it, you will get another 10 numbers from the counter.
.su
Releasing the Board
.pp
You should now release the board so that someone else can use it:
.sp
.ft CW
.in +1i
.nf
tmrelease
.fi
.in -1i
.ft R
.su "How the Sample Design Works"
.pp
The circuit is written in Verilog.
The complete counter.v file contains this:
.sp
.ft CW
.nf
module counter (
   input   clk,
   input   reset,
   output reg [31:0] result,
   output reg count_ready,
   input want_count);

   reg [31:0] count;

   always @(posedge clk or posedge reset) begin
      if(reset) begin
         count <= 0;
         count_ready <= 0;
         result <= 0;
      end
      else begin
         if(count_ready && want_count) begin
            count_ready <= 0;
            count <= count + 1;
         end
         else begin
            result <= count;
            count_ready <= 1;
         end
      end
   end

endmodule
.fi
.ft R
.sp
The circuit has one 32-bit output port called \f(CWresult\fR, and two 
1-bit handshaking variables called \f(CWwant_count\fR
and \f(CWcount_ready\fP.
The circuit sits in an infinite loop, waiting for someone to ask for a count.
It performs a handshake with the outside world using the \f(CWwant_count\fR
and \f(CWcount_ready\fP variables, increments the counter, and
waits for the next request.
.pp
The circuit uses the TMU ports package to communicate with the outside world.
The connections to the outside world are handled by the component
named \f(CWusb_portmux\fP.
This component is automatically supplied by the TMU ports package.
Read \fIThe TMU Ports Package\fP for a description of how this works.
The \f(CWtop.ports\fP file contains:
.sp
.ft CW
.nf
# Name	direction	bits	Handshake_from_circuit	Handshake_from_workstation
result	o	32	count_ready	want_count
.fi
.ft R
.sp
It describes the single 32-bit output called \f(CWresult\fP
along with the two handshaking variables.
.pp
The \f(CWtop.v\fP that connects the counter module to the automatically
generated \f(CWusb_portmux\fP component contains:
.sp
.ft CW
.nf
module top(

... Many auto-generated lines omitted ...

// The code above this line was auto-generated by the Terasic DE4 System Builder.

// Connect the user's counter.v circuit to the usb_portmux wrapper that was
// generated by the tmu command.

wire [31:0] result;
wire count_ready;
wire want_count;

usb_portmux usb_portmux_inst(
	.reset_n(rstn),
	.clk(OSC_50_BANK2),
	.OSC1_50(OSC_50_BANK2),

	.result(result),
	.count_ready(count_ready),
	.want_count(want_count),

	.OTG_D(OTG_D),
	.OTG_A(OTG_A),
	.OTG_CS_n(OTG_CS_n),
	.OTG_WE_n(OTG_WE_n),
	.OTG_OE_n(OTG_OE_n),
	.OTG_HC_IRQ(OTG_HC_IRQ),
	.OTG_DC_IRQ(OTG_DC_IRQ),
	.OTG_RESET_n(OTG_RESET_n),
	.OTG_HC_DREQ(OTG_HC_DREQ),
	.OTG_HC_DACK(OTG_HC_DACK),
	.OTG_DC_DREQ(OTG_DC_DREQ),
	.OTG_DC_DACK(OTG_DC_DACK)
);

counter counter_inst(
	.reset(~rstn),
	.clk(OSC_50_BANK2),

	.result(result),
	.count_ready(count_ready),
	.want_count(want_count)
);

endmodule
.fi
.ft R
.sp
It connects to a DE-4 clock signal called \f(CWOSC_50_BANK2\fP, and to a number
of DE-4 signals with names that start with \f(CWOTG_\fP that connect
to the USB interface chip on the DE-4 board.
It connects those signals to the \f(CWusb_portmux\fP component, and also
connects the user's signals between the counter and \f(CWusb_portmux\fP.
.pp
The suncounter.c program that runs on the workstation looks like this:
.sp
.ft CW
.nf
/* A program to test a simple counter circuit, using the ports package */

#include <stdio.h>
#include <stdlib.h>

main(argc, argv)
	int argc;
	char *argv[];
	{
	int portresult;
	int *result;
	int i, count, j;

	tm_init("");

	if((portresult = tm_open("result", "r")) < 0) {
		printf("Can't open port result\\n");
		exit(1);
		}

	count = 10;
	if(argc>1)
		count = atoi(argv[1]);

	result = (int *) malloc(count * sizeof(int));
	if(result == NULL) {
		printf("Can't allocate memory\\n");
		exit(1);
		}

	if(tm_read(portresult, result, count * sizeof(int))
			!= (count * sizeof(int))) {
		fprintf(stderr, "suncounter: error in reading\\n");
		exit(1);
		}

	for(i=0; i<count; i++) {
		printf("%d ", result[i]);
		if((i % 10) == 9) {
			printf("\\n");
			}
		}
	printf("\\n\\n");

	exit(0);
	}
.fi
.ft R
.sp
It initializes the ports package by calling \f(CWtm_init()\fP, opens the
\f(CWresult\fP port with \f(CWtm_open()\fP, reads 10 values of the counter
with a single call to \f(CWtm_read()\fP and then prints them out.
