[Contents] [Prev: 7 TERM] [Next: 9 Using the LE Board]

8 Logic Engine Programmer's Interface

8.1 Introduction

The Logic Engine Programmer's Interface (LEPI) is a library of Microsoft C routines that allow the user to monitor and control the LE board from the PC host. At the lowest level, the LEPI allows the user to read from the lights and write to the switches, buttons and pipeline of the LE board. It can also control the clock on the LE board. At a higher level, the LEPI provides a powerful way to name and invoke values onto groups of signals. Some of the many uses of the LEPI include, test vector generation, providing control signals to systems in lieu of microcode, the migration of software simulations to hardware implementations and high level diagnostics.

8.2 How the LEPI Works

The LE board contains 128 lights, 16 toggle switches, 12 buttons and 40 bits of pipeline. The PC host has the ability to read from the lights and write to the switches, buttons and pipeline. With this ability any signal that is wired to a light can be monitored by the PC host and any input signal that is wired to a switch, a button or the pipeline can be controlled by the PC host. The LE board also contains a clock which can be stopped, started and pulsed under the control of the PC host.

From the perspective of the host, the switches and buttons behave identically and will both be refered to as switches in this document. Associated with each switch is a register which can be written by the PC host. The output of each switch is connected to the output of its corresponding register. Normally, the output of the register is disabled and the output of the switch is enabled. The PC host can take control of the switches by disabling the output of the switches and enabling the output of the registers. In addition to the 28 registers associated with the switches, there are 4 hidden registers which are accessible from the PC host which do not have an associated switch or button.

The pipeline is part of the microcontroller which is on the LE board and is used to control input signals to a design. The PC host can however, write directly to the pipeline to provide these signals.

The PC host has the ability to stop a running clock, pulse a stopped clock, or start a stopped clock by writing to the clocks control register. When the clock is stopped the clock controls on the LE board are disabled. When the clock is running, its frequency is controlled from the LE board.

With these resources, the LE board has 128 parallel output signals which can be monitored and 72 parallel input signals which can be controlled. Section 8.6 describes how to access the switches, buttons and pipeline on the LE board.

8.3 Low Level Interface Routines

The low level interface includes routines to read the lights, write the switches and pipeline and stop, start or pulse the clock. Table I. is a list of all the low level routines available, including the signature and a description of each. In order to use these routines, the file /<le>/include/lelib.h has to be included into the source file and the file /<le>/bin/lelib.lib has to be linked to the object files. See Section 8.7 for instructions on linking this library.


#include "/le/include/lelib.h"
Required for function declarations.


int initboard(void);

Configures the LE board so that the PC host can control the operation of the clock, switches, buttons and pipeline. It also determines on which port the board is attached and does a minimal test to determine if the board is functioning. If the board is present and functioning initboard returns 0 otherwise it returns a positive integer. If no board is found, it could mean that the board is not powered on, the interface cable is not connected properly or the LE board is not functioning properly. This function should be called before any of the LEPI functions are used.


void restoreboard(void);

Restores the LE board to a state in which the clock, switches and buttons are all enabled. This function should be called before exiting the user program.


void readlights(lights);
unsigned char *lights;

Reads the current value of all the lights. The values are stored in the user supplied array lights. Each entry in the array holds eight bits representing the value of the lights. The first entry (lights[0]) contains lights 0-7, the second, lights 8-15 and so on up to the sixteenth entry which contains lights 120-127. In each entry the lowest numbered light is the least significant bit.


int readlight(n);
int n;

Reads the nth 8-bit group of lights. Readlight(n) returns the value of the lights n*8 through n*8+7. The lowest numbered light is the least significant bit of the value returned. The value of n can range from 0 to 15. If n is outside this range, -1 is returned indicating an error.


void readswitches(switches);

Reads the current value of all the switches and buttons. The values are stored in the user supplied array switches. Each entry in the array holds eight bits representing the value of the switches. The first entry (switches[0]) contains switches 0-7, the second, switches 8-15 and so on up to the forth entry which contains switched 24-31. In each entry the lowest numbered switch is the least significant bit.


unsigned char *switches;
int readswitch(n);
int n;

Reads the nth 8-bit group of switches. Readswitch(n) returns the value of the switches n*8 through n*8+7. The lowest numbered switch is the least significant bit of the value returned. The value of n can range from 0 to 3. If n is outside this range, -1 is returned indicating an error.


void writeswitches(switches);
unsigned char *switches;

Writes the values in array switches to all the switches and buttons. Each entry in the array holds eight bits representing the value of the switches. The first entry (switches[0]) contains switches 0-7, the second, switches 8-15 and so on up to the forth entry which contains switches 24-31. In each entry the lowest numbered switch is the least significant bit.


int writeswitch(n,val);
int n;
unsigned char val;

Writes the value val to the nth 8-bit group of switches. Writeswitch(n,val) writes the value val to the switches n*8 through n*8+7. The least significant bit of val is written to the lowest numbered switch. The value of n can range from 0 to 3. If n is outside this range, -1 is returned indicating an error.


void writepipeline(pipe);
unsigned char *pipe;

Writes the values in array pipe to the pipeline. Each entry in the array holds eight bits. The first entry (pipe[0]) contains bits 0-7 of the pipeline, the second, bits 8-15 and so on up to the fifth entry which contains bits 32-39. In each entry the lowest numbered pipeline bit is the least significant bit of the value.


int writepipe(n,val);
int n;
unsigned char val;

Writes the value val to the nth 8-bit group of pipeline bits. Writepipe(n,val) writes the value val to the pipeline bits n*8 through n*8+7. The least significant bit of val is written to the lowest numbered pipeline bit. The value of n can range from 0 to 4. If n is outside this range, -1 is returned indicating an error.


void pulseclock(ticks);
int ticks;

Issues ticks number of clock pulses on the user clock. The clock is left in the stopped state after this function is called, so a value of 0 for ticks will simply stop the clock.


void startclock(void);

Puts the clock in the running state. If the clock was already in the running state, nothing happens.


Example use of low level LEPI routines

Fig. 23. is a small example of a C program that uses some of the low level routines. The routine tests one NAND gate (74ls00). It assumes that the inputs (pins 1 and 2) have been wired to switches 0 and 1 and the output (pin 3) has been wired to light 0. This example uses the routines: initboard, restoreboard, writeswitch, and readlight.


#include <stdio.h>
#include "\le\include\lelib.h"

void
main()
{
 while(initboard()!=0){
  /*  initialize the board  */
  fprintf(stderr,"LE Board not present or not functioning\n");
  fprintf(stderr,"<Hit Enter key to continue>");
  getchar();
 }

 dotest();      /*  perform the test   */
 restoreboard()    /*restore the board  */
}

void
dotest()
{
 static int expected[4] = {1,1,1,0}; /* Truth Table for 74ls00 */
 int result;      /* result of running test  */
 int error;      /* number of errors so far */
 unsigned char i;     /* input value and loop index*/

 error = 0;

 for(i=0;i<4;i++){
  writeswitch(0,i);  
/* Present inputs to gate */
  result = readlight(0);  /* Read output of gate  */

  if(result != expected[i]){
   fprintf(stderr,"Error: Inputs: %d Result: %d Expected: %d\n",i,result,!(i==3));

   error++;
  }
 }

 fprintf(stderr,"The test completed with %d error(s)\n",error);
}

Figure 23. Example of a code which uses the low level routines.

8.4 High Level LEPI Routines

The high level interface includes routines to define field declarations and invocations, invoke values onto the defined fields and read values from the defined fields. Table II. is a list of all the high level routines available, including the signature and a description of each. The field declarations and invocations are defined in a separate file. The syntax for this file is nearly identical to the declaration section of the LE Micro Assembly Language described in Chapter 5 of this manual with a few additions This file must be read by the user program before any of the high level routines can be used.


int initboard(void);

Besides initiating the board as described above in the low level routines, this routine initiates the pipeline, switches and buttons to their default values as defined in the declaration file. It should therefore be called after calling declare.


int declare(filename);
char *filename;

Reads the named declaration file. This will construct an internal symbol table that is used by the initboard, command, mask and readval routines. The syntax of the declaration file is described in section XX. This routine should be called before the initboard routine. The value returned is the number of errors that occurred while parsing the declaration file.


int command(comlist[,arg]...);
char *comlist;

The command routine is used to assert values onto the defined field. Comlist is a string with the same syntax as the command list portion of a microinstruction statement of the LE Micro Assembly Language as described in chapter 5 of this manual. In addition, the comlist can contain format specifications as in the printf routine (See the Microsoft C Run-time Library Reference). The command routine asserts only the signals as defined in comlist. All other signals take on their default value. A negative value will be returned if a error occurred while parsing comlist otherwise 0 will be returned.


int mask(comlist[,arg]...);
char *comlist;

The mask routine is identical to the command routine with the exception that signals which are not asserted as defined in comlist, remain at their current value.


int readval(field);
char *field;

The readval routine returns the value of the named field as defined in the declaration file. The field argument is a string containing the name of the field to be read. A negative result indicates that an error has occurred in parsing field.


Example use of high-level LEPI routines

Figure 24 is a small example of a C program that uses some of the high level routines and Figure 25 is the accompanying declaration file. The routine tests an ALU (74ls181). It assumes that the inputs and outputs have been wired as defined in the declaration file. This example uses the routines: declare, initboard, restoreboard, command and readval. The testing algorithm used is to present the device with all possible inputs, checking the outputs for each against a software model of the device. The code for the software model (LS181 in fig. 24 ) is not shown in the figure. Notice that in the code of Figure 24 , there is no reference to light or switch numbers. All signals are referenced by name.

#include <stdio.h>
#include "lelib.h"

void main()
{
 if(declare("ls181.dec")!=0){
  fprintf(stderr,"Error: Declaration File\n");
  exit(-1);
 }

 while(initboard()!=0){
  fprintf(stderr,"LE Board not present or not functioning\n");
  fprintf(stderr,"<Hit Enter key to continue> ");
  getchar();
 }

 dotest();
 restoreboard()
}

void dotest()
{
 int a,b,s,m,c0,f,expected,errors;

 errors = 0;
 for(s=0;s<16;s++){
  fprintf(stderr,"Testing function %x for all possible inputs\n",s);
  for(b=0;b<16;b++){
   for(a=0;a<16;a++){
    for(m=0;m<2;m++){
     for(c0=0;c0<2;c0++){
         command("A=%d,B=%d,S=%d,M=%d,C0=%d",a,b,s,m,c0);

      f = readval("F");
      expected = LS181f(a,b,s,m,c0);
      if(f != expected){
        fprintf(stderr,
                "Error: A=%x,B=%x,S=%x,M=%x,C0=%x­>F=%x:Expected:%x\n",
                a,b,s,m,c0,f,expected);
        errors++;
        printf("test>");
        if(getchar()=='q') exit(-1);
      }
     }
    }
   }
  }
 }
 fprintf(stderr,"The test completed with %d error(s)\n",errors);
}

Figure 24. Example of code which uses high level routines.


A  SW(0:3)
B  SW(4:7)
S  SW(8:11)
M  SW(12)
C0 SW(13), T=%L
F  LT(8:12), T=%LHHHH

Figure 25. Example of a declaration file.

8.5 Declaration File Syntax

The declaration file is used to give logically names to a group of signals and to describe the use of these signals. The syntax is similar to the declaration portion of the Micro Assembly Language described in Chapter 5 of this manual with a few addtions to support the switches, buttons, and lights. The description of the syntax given here is only a subset of the complete syntax. For a complete description of the sytax, see Chapter 5.

The three basic directives used in the declaration file are COM, LT, and SW. All of which have the same syntax:

<name> <dir> <range> [,<truth values>] [,<default values>]

<name> - A string of any length containing, upper or lower case letters, numerals, "_", or ".". The first character must be a letter. This defines the name of the field.

<dir> - COM | LT | SW |

The directive defines the type of field.

<range> - (n,m) | (n)

where n and m are integers and n is less than m. The range defines the signals in the field.

<truth values> - T=<numeric value> | T=<voltage value>

The truth value defines the interpretation of the voltage of each signal in the field. If absent, each signal is assumed to be true high.

<default values> - D=<numeric value> | D=<voltage value> | D=<logic value>

The default value defines the value each signal gets when it is not asserted. Used only for COM and SW directives. If absent, the default for each signal will be a low voltage for VOLTAGE mode and a false value for LOGIC mode. See the MODE directive below.

<numeric value> - A string of digits and characters representing a number.

decimal - [0-9]*
hexadecimal - $[0-9a-fA-F]*
binary - %[01]*

<voltage value> - A string of "H" (for high voltage) and "L" (for low voltage) characters, preceded by "%".

<logic values> - A string of "T" (for true) or "F" (for false) characters, preceded by "%".

The COM and SW directives both define input fields to the board. The name defined by these directives can be used in command or mask statements. The LT directives define output fields from the board. The name defined by these directives can be used in readval statements.

8.6 Nomenclature

The naming and numbering of the switches, lights, and pipeline for the software is slightly different from that of the hardware and can be a point of confusion. The following tables describe how they relate to each other. For exact location of these points on the Logic Engine board, see the Logic Engine Board User Manual.

Switches:
Type/
Numbering:
Switch Switch Switch Switch Hidden Push
Button
Push
Button
Hidden Push
Button
Push
>Button
Software 31-28 27-24 23-20 19-16 15-14 13-12 11-8 7-6 5-4 3-0
Hardware S15-S12 S11-S8 S7-S4 S3-S0 B15-B14 B13-B12 B11-B8 B7-B6 B5-B4 B3-B0
IC/pin xx/20-17 xx/16-13 xx/20-17 xx/16-13 xx/20-19 xx/18-17 xx/16-13 xx/20-19 xx/18-17 xx/16-13

Lights:
Type/
Numbering
Light Light Light Light Light Light Light Light Light Light Light Light Light Light Light Light
Software 127-120 119-112 111-104 103-96 95-88 87-80 79-72 71-64 63-56 55-48 47-40 39-32 31-24 23-16 15-84 7-0
Hardware L127-L120 L119-L112 L111-L104 L103-L96 L95-L88 L87-L80 L79-L72 L71-L64 L63-L56 L55-L48 L47-L40 L39-L32 L31-L24 L23-L16 L15-L8 L7-L0
IC/pin xx/2-9 xx/2-9 xx/2-9 xx/2-9 xx/2-9 xx/2-9 xx/2-9 xx/2-9 xx/2-9 xx/2-9 xx/2-9 xx/2-9 xx/2-9 xx/2-9 xx/2-9 xX/2-9

Pipeline:
Type/
Numbering
Pipeline Pipeline Pipeline Pipeline Pipeline
Software 39-32 31-24 23-16 15-8 7-0
Hardware P39-P32 P31-P24 P23-P16 P15-P8 P7-P0
IC/pin xx/19-12 xx/19-12 xx/19-12 xx/19-12 xx/19-12

8.7 Linking the Library

In order use the LEPI library, the source files must be compiled using the large memory model and then linked with the library as illustrated in the example below. For more details about compiling and linking see the Microsoft C Compiler User's Guide and Reference Manual.

Compile:

  cl /c /AL file1.c
  cl /c /AL file2.c

Link:

  link file1.obj file2.obj, prog.exe, prog.map, lelib.lib;

[Contents] [Prev: 7 TERM] [Next: 9 Using the LE Board]