There are two C libraries that help create and debug C code for the mMIPS NOC: stdcomm and mtools. Together they will be referred to as noctools. The stdcomm library implements a message passing communication protocol and mtools supports simple debugging using a printf() variant. The libraries can be compiled for both the mMIPS (using lcc) and the PC/i386 platform (using gcc). In the latter case printf() sends its output to stdout and the message passing functions read from input.bin and output to output_to_0xXXYY.bin. The libraries are located in the folder ./c_prog/noctools of the package.
The files stdcomm.h and stdcomm.c discussed here contain the interface and implementation of a simple message passing library for the networked mMIPS. The network interface hardware supports memory mapped, packet based communication. Message passing was chosen because it integrates very well with this type of hardware communication, resulting the smallest possible development and performance overhead costs. Message passing is discussed in paragraphs 1.1. and 1.2. Paragraph 1.3 explains how to log all communication using the function mprintf() of the library mtools. Paragraph 1.4 explains and motivates the support of the library for the PC/i386. Paragraphs 1.5 and 1.6 give a full list of all the functions, variables and preprocessor symbols that make up the interface of the library.
int sc_send(const int address, const void *data, const int size_in_bytes);
Use sc_send() to send data and not sc_send_word() because the former encapsulates the internals of the communication with the network interface and the latter does not. The first argument address is the relative address of the target processor. Bits [15:8] are the X distance, bits [7:0] the Y distance (see the mMIPS network interface for more information). The network is a torus network with E-cube routing. A packet first travels over the X dimension and then over the Y dimension. The X or Y distance is decreased with one for each node visited. The target processor has been reached when both X and Y distance are zero. Packets wrap at the edges of the torus, so a node in a X by Y torus could theoretically sent itself a message by sending to address (X,Y), (X,0), (0,Y) or (0,0).
The parameter data of sc_send() is a void pointer to the data that needs to be sent. The size of this structure is set with the size_in_bytes parameter. Packets can be any integer size range from 1 to 232-1 inclusive.
The global variable try_count_sc_send determines the number of tries before sc_send() gives up and returns. sc_send() uses sc_send_word() to send each 4 byte fraction of data. The retry counter is reset whenever such a fraction has been sent successfully. If you set try_count_sc_send to zero then sc_send() is a blocking send that retries indefinitely.
The return value of sc_send() contains the number of bytes that was actually sent.
The function sc_receive() is used for receiving data. The parameters address, data, and size_in_bytes are the same as for sc_send(). The global variable try_count_sc_receive determines the behavior of sc_receive() completely similar to the way try_count_sc_send determines the behavior of sc_send().
If the DEBUGMODE preprocessor symbol has been defined then a text string is printed using mprintf() each time to sc_receive_word() or sc_receive_word() has been called. mprintf() is defined in the mMIPS library mtools.h.
The preprocessor symbol CC_I386 determines the target platform: PC/i386 or mMIPS. The PC/i386 platform is useful in the development phase of a program, because:
See the application design flow for a more complete comparison between the mMIPS platform (FPGA implementation and hardware simulator) and the PC/i386 option (referred to as "IDE" there).
mMIPS (CC_I386 is NOT defined)
If the preprocessor symbol CC_I386 has not been defined, then the communications
library operates in native mMIPS mode and an attempt is made to actually send
or receive data using the network interface of the mMIPS.
PC/i386 (CC_I386 is defined)
If the preprocessor symbol CC_I386
has been defined then data is read from the file
input.bin and output to the file
output_to_0xXXYY.bin, where XXYY is the
hexadecimal representation of the 16 least significant bits of the destination
address passed to
sc_send(). The program is stopped with an error message if the in- or
output file could not be opened. Reading beyond the end of
input.bin does not stop the program. If the
preprocessor symbol DEBUGMODE
is defined any transmission or reception (failure) is print to
stdout using
mprintf().
This section presents the interface of the send and receive primitives. Check stdcomm.h for the full interface details.
Function | int sc_send(const int address, const void *data, const int size_in_bytes); |
Description | Tries to send a block of size_in_bytes bytes. Uses sc_send_word() to send each 4 byte word in data. The maximum retry_count for each call to sc_send_word() is given by try_count_sc_send. |
Return value | The number of bytes that was successfully sent. |
Function | int sc_send_word(const int *ctrlword, const int *data, int try_count); |
Description | Tries to send the 32 bit word data. Checks if the network interface is ready to accept the packet and if so sends it. Retries a maximum of try_count-1 times before it returns. Use sc_send() instead of sc_send_word() to avoid setting and checking the control word ctrlword yourself. |
Return value | One of the predefined error values or SC_COMMERR_SUCCESS if the operation completed successfully. |
Function | int sc_receive(void *data, const int size_in_bytes); |
Description | Tries to receive a block of size_in_bytes bytes. Uses sc_receive_word() to receive each 4-byte fragment of data. The maximum retry_count for each call to sc_receive_word() is given by try_count_sc_receive. |
Return value | Returns the number of bytes that were successfully sent or minus size_in_bytes if the rcv_eop bit was not set after the last call to sc_receive_word(). |
Function | int sc_receive_word(int *ctrlword, int *data, int try_count); |
Description | Tries to receive a 32 bit word data. Checks if the receiver is ready and then reads the 32 bit word in data if that is the case. Retries a maximum of try_count-1 times before it returns. Use sc_receive() instead of sc_receive_word() to avoid setting and checking the control word ctrlword yourself. |
Return value | One of the predefined error values or SC_COMMERR_SUCCESS if the operation completed successfully. |
This section presents an overview of the variables and preprocessor symbols in stdcomm.h. Check stdcomm.h for the full interface details.
#define DEBUGMODE | - | Prints any send or receive using mprintf() if defined. Effective on both mMIPS and PC platforms. |
#define DEBUG2FILE | - | Any data sent is appended to the file output.bin and any data that should have been received is expected in input.bin. Effective only on the PC/i386 platform. |
int try_count_sc_send int try_count_sc_receive |
- | Determines how many attempts will be made to resend / receive a 4-byte block. -1 results in infinite retries. |
int sc_my_address | - | The address of this node. Reserved. |
#define SC_ | - | The preprocessor symbols SC_ that are used as error codes and bit masks. |
The mMIPS library enables simple debugging and implements functions that are specific to the mMIPS. The mtools library consists of the files mtools.h, mtools.c and require sprintf.h, sprintf.c and stdarg_mm.h. The sprintf files and stdarg_mm.h is are required for the function mprintf(). They contain svprintf(), which is equivalent to the standard function vprintf() with the difference that the former outputs to a memory location and the latter to stdout. The target platform of the library is PC/i386 if the preprocessor symbol CC_I386 is defined and mMIPS otherwise.
The library consists of the following functions.
Function | int mprintf (char *format, ...); |
Description | * On the mMIPS (preprocessor symbol
CC_I386 is not defined): Operates similar to printf(), but outputs the resulting string to a rotating memory store in the address range from MPRINTF_START_ADDR up to and including MPRINTF_MAX_ADDR. When MPRINTF_MAX_ADDR is reached then the wrap around counter is increased. If it is less than or equal to MPRINTF_WRAP_COUNT, then mprintf() continues at MPRINTF_START_ADDR, overwriting existing data. Otherwise mprintf() does nothing. Any single output may not be more than MPRINTF_BUFFER_SIZE characters long (including the trailing zero). Memory corruption may result if it does exceed that size. All preprocessor symbols (in capitals) are defined in mprintf.h. * On the PC/i386 (CC_I386 is defined): Uses a printf() variant (vfprintf()) to output to stdout. |
Return value | Always returns 0. |
Function | void print4bytes(const void *data); |
Description | Saves the first 4 bytes of the data pointed to by data in both hexadecimal and ASCII format using mprintf(). The output has the form "0x******** (....)", where the stars are replaced by hexadecimal digits and the periods by ASCII characters. The bytes are output in the exact order as they are present in memory, so no little / big endian byte reordering takes place. |
Function | void dump4bytes(char *buffer, const void *data); |
Description | Saves the first 4 bytes of the data pointed to by data in both hexadecimal and ASCII format to buffer. See also print4bytes(). |
Function | void mt_halt(void); |
Description | * On the mMIPS (CC_I386 is not defined): Starts an infinite loop. * On the PC/i386 (CC_I386 is defined): Calls exit(0). |
Function | void mt_delay(int loop_count); |
Description | Delays the processor by doing loop_count iterations of an empty for. |
When the mtools library is used on the mMIPS platform, then four preprocessor symbols need to be set for mprintf() to work correctly:
#define | Result (effective only on the mMIPS platform; no effect on the PC/i386 platform) |
MPRINTF_START_ADDR | This is the address where mprintf() starts writing. |
MPRINTF_MAX_ADDR | This is the last byte address location where mprintf() is allowed to write. |
MPRINTF_WRAP_COUNT | If mprintf() has reached MPRINTF_MAX_ADDR and the wrap count MPRINTF_WRAP_COUNT has not been reached, then writing continues at MPRINTF_START_ADDR. |
MPRINTF_BUFFER_SIZE | mprintf() temporarily stores the formatted output to a buffer of MPRINTF_BUFFER_SIZE bytes in size (200 bytes by default). If the formatted output is greater than this value, then data corruption may result. The user is responsible for ensuring the buffer is large enough. |
As with the communications library, the target platform can be PC/i386 or mMIPS.
Before you can use the libraries, they need to be compiled for your system. This paragraph explains how to do that. When this procedure is complete, simply adding a #include "stdcomm.h" and #include "mtools.h" statement to your source code is sufficient to make the libraries available. There are two ways to compile the libraries:
The second option is the safest and this procedure is described in the paragraph "Set up centralized library". The compilation scripts dolcc and dogcc in the example applications gossip and the multi-processor JPEG decoder assume a centralized library at location pointed to by the environment variable NOCTOOLS (e.g. ~/mmips_noc/c_prog/noctools).
Command | Result |
make debug | The preprocessor symbols DEBUGMODE and
DEBUG2FILE. They have the
following impact:
|
make release | Defines only DEBUG2FILE and not DEBUGMODE. This increases the speed of the library. |
Platform | Command |
Linux (i386 using gcc) | gcc -g -ansi -pedantic $(I386) -Wall -O -o gossip -I$(NOCTOOLS)/src -L$(NOCTOOLS)/i386 -lmtools -lstdcomm -lsprintf -lm gossip |
NOC (mMIPS using lcc) | lcc -N -AA -o gossip -I$NOCTOOLS/src -L$NOCTOOLS/mmips -lmtools -lstdcomm -lsprintf gossip.c |
Note: these commands were copied from the scripts dolcc and dogcc and are executed by bash (even if that is not the current shell).
The difference between the libraries in i386 and mMIPS is that the former is compiled using gcc with the preprocessor symbol CC_I386 defined and the latter with lcc without CC_I386. See the Makefile for more information.