Skip to content

Commit

Permalink
First commit
Browse files Browse the repository at this point in the history
  • Loading branch information
wd5gnr committed Aug 26, 2018
0 parents commit e3fae2e
Show file tree
Hide file tree
Showing 43 changed files with 3,564 additions and 0 deletions.
56 changes: 56 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
This is a fork of OpenVerifla that tries to do a few things:

1) Document some of the settings a bit better
2) Fix a bug where samples that changed on one clock were not handled properly
3) Add synchronous memory that is easier for some tools to infer
4) Some minor cleanups and plans for enhancments
5) C tool to read output and generate VCD directly (see C directory for build instructions)
6) Adds clock enable/qualifer
7) Adds armed and trigger outputs

The PDF attached has some good information on it. However, a few things to note:

1) Do not set Run to 1 in your code unless your trigger is infrequent. If data constantly
spews out of the FPGA, the JAVA code can not sync to it.

2) There are some strange unsquashed bugs. For example, on the Lattice iCe40
with Icestorm tools (at least) setting memory to 256 bytes and the trigger position to
128 causes a hang. Trigger positions at 127 and 129 are fine.

Possible Enhancements
1) Uart clock vs Sample clock (Uart clock >> Sample clock)
2) Clock Enable for sample clock (done)
3) Change post trigger samples to do post trigger memory words (or document to set huge #)
4) Java: Pick up Verilog file from template

=== Quick Start
1. Link or copy the verifla directory (the one under verilog) to your project directory
2. Copy config_verifla.v.template to your working directory and rename it to config_verifla.v
3. Make sure your Verilog tool will look in the verifla directory as a library
4. Make sure the search path for includes will look in your project directory first
5. Edit config_verifla.v in your project directory to se clock speed, baud rate, memory size, etc.
6. Write your verilog in the project directory.
7. Create a top_of_verifla module. Here are the signals:
* clk - Clock
* cqual - Qualifier for data capture clock (UART and other things use clk alone). If you don't want a qualifer, just set to 1'b1. IMPORTANT: You do need to set this to something.
* rst_l - Active low reset.
* sys_run - High to arm logic analyzer. If you only want to arm from the PC, set to 1'b0.
* data_in - Your inputs. Group together like {led3, led2, led1, led0, count[3:0]}.
* uart_XMIT_dataH - Your RS232 transmit line
* uart_REC_dataH - Your RS232 receive line
* armed - digital output showing LA is armed
* triggered - digital output showing LA is triggered
8. Once running you can use the original Java program to create a .v file you will need to simulate or the C program (la2vcd) to create a .vcd you can read using a waveform viewer (like GTKWave)

=== Notes about using GTKWave
The C program creates a simple dump that has the entire capture data and also each byte captured. You can supress the bytes (-W) or the aggregate (-B) if you like. However, you really want to have the signals broken back out like they are in your code.

Suppose you have 16-bits of data like this:
counter8[7:0], led0, state[6:0]

It is easy to add the capdata[15:0] data to GTKWave. Then expand it into bits. Select the
counter8 bits and press Combine Down on the Edit menu (or Combine Up if you are reversed endian).
This will prompt you for a name so enter "counter8" and press OK. Now you'll have a counter 8 signal. Repeat for state. For the led0 signal, you can create an alias.

Of course, this is painful to set up every time so use Write Save File on the File menu. This will save the layout for next time you load a VCD with the same format.

306 changes: 306 additions & 0 deletions c/la2vcd.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,306 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libserialport.h> // From SIGROK -- need newer version than Ubuntu provides :(
// Look at https://sigrok.org/wiki/Libserialport
#include <ctype.h>
#include <unistd.h>
#include <time.h>
#include <stdint.h>

#define USERCMD_RESET 0
#define USERCMD_RUN 1

// Need to make command line options
#define BAUD 9600
#define CAPTURE 2
#define REPEAT 1
#define SIZE 256
#define COUNT (SIZE*(REPEAT+CAPTURE))

void help()
{
fprintf(stderr,"Usage: la2vcd [-B] [-W] [-F frequency] [-T timescale] -b baud, -t trigger_pos -c cap_width, -r repeat_width, -n samples -o vcd_file port_name\n");
fprintf(stderr,"You need all the lower case options, although baud will default to 9600\n");
fprintf(stderr,"-B output only bytes of capture\n-W output only words (default is both bytes and words)\n");
fprintf(stderr,"-F sets frequency in MHz (e.g., -F 250).\n"
"Or you can set the timescale (e.g, -T 1ns) with -T. Note the timescale should be twice the clock frequency. Default to 1nS and you do your own math.\n");
fprintf(stderr,"Al Williams [email protected]\n");
exit(1);
}

char *binary(uint64_t v, unsigned int bits)
{
static char buffer[65];
char *p=buffer+sizeof(buffer)-1;
memset(buffer,'0',sizeof(buffer));
*p--='\0';
while (v)
{
*p--=(v&1)?'1':'0';
v=v>>1;
}
return buffer+sizeof(buffer)-1-bits; // note this is static with all that implies
}



uint64_t getbin(unsigned width, unsigned char *buf, unsigned base)
{
uint64_t v=0;
int j;
for (j=0;j<width;j++) v=v*0x100+buf[base+j];
return v;
}

void getbline(unsigned w1, unsigned w2, char *buf, unsigned base, uint64_t *v1, uint64_t *v2 )
{

*v1=getbin(w1,buf,base+w2);
*v2=getbin(w2,buf,base);
}

int bflag=3; // bytes=1, words=2


void writeline(FILE *f,uint64_t *t,uint64_t rpt, uint64_t data, int trigger, int capwidth)
{
unsigned int i;
unsigned int j;
for (j=0;j<rpt;j++)
{
fprintf(f,"#%lu\n1!\n",*t); // always do clock
if (j==0) // only have to do the first data point for the change block
{
if (bflag&2) fprintf(f,"b%s # \n", binary(data,capwidth*8));
if (bflag&1) for (i=0;i<capwidth;i++) fprintf(f,"b%s %c \n",binary(data>>(8*i)&0xFF,8),'&'+i);
if (trigger)
fprintf(f,"1^\n");
}
fprintf(f,"#%lu\n0!\n",*t+1); // always trim up the clock

*t+=2;
}
}


void sizerr(const char *msg)
{
fprintf(stderr,"Error: %s exceeds 64 bits\n",msg);
exit(9);
}





int main(int argc, char *argv[])
{
struct sp_port *port;
int err;
unsigned i;
int copt;
int baud=BAUD;
unsigned int capwidth=0;
unsigned int repwidth=0;
unsigned int caplength=0;
unsigned int count;
unsigned int trigpos=0;
char *vcdfile=NULL;
char *timescale="1ns";
float freq=-1;

unsigned char *workbuf;
FILE *vfile;
time_t rawtime;
struct tm * timedata;
int debugging=0; // undocumented ;-)



if (argc<2)
{
help();
}


while ((copt=getopt(argc,argv,"DF:T:BWb:c:r:n:o:t:")) != -1)
switch (copt)
{
case 'D':
debugging=1;
break;
case 'T':
timescale=optarg;
break;
case 'F':
freq=atof(optarg);
freq=1.0/(freq*.000002); // double plus microseconds to picoseconds
break;

case 'B':
bflag=1;
break;
case 'W':
bflag=2;
break;

case 'b':
baud=atoi(optarg);
break;
case 'c':
capwidth=atoi(optarg);
if (capwidth>sizeof(uint64_t)) sizerr("Capture width");
break;
case 'r':
repwidth=atoi(optarg);
if (repwidth>sizeof(uint64_t)) sizerr("Replacement width");
break;
case 'n':
caplength=atoi(optarg);
break;
case 'o':
vcdfile=optarg;
break;
case 't':
trigpos=atoi(optarg);
break;

default:
case '?':
help();
break;
}

count=(capwidth+repwidth)*caplength;
if (count<=0)
{
fprintf(stderr,"You must specificy the number of bytes in the capture (-c),\n"
"the number of repeat count bytes in the capture (-r),\n"
"and the total number of capture samples (-n)\n");
exit(3);
}

workbuf=(char *)malloc(count);
if (!workbuf)
{
perror("Out of memory");
exit(4);
}

if (vcdfile)
vfile=fopen(vcdfile,"w");
else
vfile=stdout;
if (!vfile)
{
perror(vcdfile);
exit(6);
}


err=sp_get_port_by_name(argv[optind],&port);
if (err==SP_OK)
err=sp_open(port,SP_MODE_READ_WRITE);
if (err!=SP_OK)
{
fprintf(stderr,"Can't open port %s\n",argv[1]);
exit(2);
}
sp_set_baudrate(port,BAUD); // TODO: Command line option
// write reset
i=USERCMD_RESET;
sp_blocking_write(port,&i,1,100);
// write run
i=USERCMD_RUN;
sp_blocking_write(port,&i,1,100);
// read data (note data is backwards!)
for (i=0;i<count;i++)
{
int waiting;
int c;
do
{
waiting=sp_input_waiting(port);
} while (waiting<=0);
sp_nonblocking_read(port,(void *)&c,1);
workbuf[(count-1)-i]=c;
}
sp_close(port);

if (debugging)
{
int q;
FILE *dfile=fopen("debug.txt","w");
for (q=0;q<count;q+=3)
{
// only works for specific format -c 2 -r 1
fprintf(dfile,"%02X: %02X %02X %02X\n",q/3,workbuf[q],workbuf[q+1],workbuf[q+2]);
}
fclose(dfile);
}

fprintf(stderr,"Writing vcd file\n");
fprintf(vfile,"$version la2vcd 0.1 $end\n");

time(&rawtime);
timedata=localtime(&rawtime);
fprintf(vfile,"$date %s $end\n",asctime(timedata));
fprintf(vfile,"$timescale ");
if (freq!=-1) fprintf(vfile,"%.0fps",freq);
if (freq==-1) fprintf(vfile," %s",timescale);
fprintf(vfile," $end\n");
fprintf(vfile,"$scope module CAPTURE $end\n");
// Need to have a definition file or something for this but for now...
fprintf(vfile,"$var wire 1 ! clk $end\n");
if (bflag&2) fprintf(vfile,"$var wire %u # capdata $end\n",capwidth*8);
fprintf(vfile,"$var wire 1 ^ triggered $end\n");
if (bflag&1) for (i=0;i<capwidth;i++) fprintf(vfile,"$var wire 8 %c capbyte%u $end\n",'&'+i,i);

fprintf(vfile,"$upscope $end\n");
fprintf(vfile,"$enddefinitions $end\n");

uint64_t t=0;
unsigned linewidth=capwidth+repwidth;
uint64_t rct=0;
uint64_t data=0;
unsigned j;

fprintf(vfile,"$dumpvars\n0!\n0^\n");
if (bflag&2) fprintf(vfile,"bx #\n");
if (bflag&1) for (i=0;i<capwidth;i++) fprintf(vfile,"bx %c\n",'&'+i);
fprintf(vfile," $end\n");
uint64_t tail0,tail;
getbline(capwidth,repwidth,workbuf,(caplength-1)*linewidth,&tail,&rct); // rct not used here
tail0=tail++;
while (tail!=trigpos)
{
// output oldest part of buffer
getbline(capwidth,repwidth,workbuf,tail*linewidth,&data,&rct);
if (rct==0) break;
writeline(vfile,&t,rct,data,0,capwidth);
tail++;
}
tail=0;
while (tail<=tail0)
{
// output newer part of buffer
getbline(capwidth,repwidth,workbuf,tail*linewidth,&data,&rct);
if (rct==0) break;
writeline(vfile,&t,rct,data,0,capwidth);
tail++;
}
// now do the rest
for (i=trigpos;i<caplength-1;i++)
{
getbline(capwidth,repwidth,workbuf,i*linewidth,&data,&rct);
if (rct==0) break;
writeline(vfile,&t,rct,data,i==trigpos,capwidth);
}




if (vfile != stdout) fclose(vfile);
if (workbuf) free(workbuf);
}
29 changes: 29 additions & 0 deletions c/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
This is a simple utility to capture data from openverifla and dump it directly to a vcd.

=== Compile
Should compile with any normal C compiler where libserialport is available (get from Sigrok).
You do need a recent version of libserialport -- the one currently in Ubunut repos will not work.

gcc -o la2vcd la2vcd.c -lserialport

=== Usage
Usage: la2vcd [-B] [-W] [-F frequency] [-T timescale] -b baud, -t trigger_pos -c cap_width, -r repeat_width, -n samples -o vcd_file port_name

You need all the lower case options, although baud will default to 9600

-B output only bytes of capture

-W output only words (default is both bytes and words)

-F sets frequency in MHz (e.g., -F 250).

Or you can set the timescale (e.g, -T 1ns) with -T. Note the timescale should be twice the clock frequency. Default to 1nS and you do your own math.

Great idea to build a script with all the "standard" settings for a project:

#!/bin/bash
exec la2vcd -W -F 50 -b 57600 -t 129 -c 3 -r 1 -n 256 -o "$1"

Just as an example.

Al Williams [email protected]
Loading

0 comments on commit e3fae2e

Please sign in to comment.