Line 6... |
Line 6... |
//
|
//
|
// Purpose: To create a pass-through test of the receiver and transmitter
|
// Purpose: To create a pass-through test of the receiver and transmitter
|
// which can be exercised/proven via Verilator.
|
// which can be exercised/proven via Verilator.
|
//
|
//
|
// If you run this program with no arguments, it will run an automatic
|
// If you run this program with no arguments, it will run an automatic
|
// test, returning "SUCCESS" on success, or "FAIL" on failure as a last
|
// test, returning "PASS" on success, or "FAIL" on failure as a last
|
// output line--hence it should support automated testing.
|
// output line--hence it should support automated testing.
|
//
|
//
|
// If you run with a '-i' argument, the program will run interactively.
|
// If you run with a '-i' argument, the program will run interactively.
|
// It will then be up to you to determine if it works (or not). As
|
// It will then be up to you to determine if it works (or not). As
|
// always, it may be killed with a control C.
|
// always, it may be killed with a control C.
|
Line 48... |
Line 48... |
#include <fcntl.h>
|
#include <fcntl.h>
|
#include <unistd.h>
|
#include <unistd.h>
|
#include <string.h>
|
#include <string.h>
|
#include <time.h>
|
#include <time.h>
|
#include <sys/types.h>
|
#include <sys/types.h>
|
|
#include <sys/wait.h>
|
#include <signal.h>
|
#include <signal.h>
|
#include "verilated.h"
|
#include "verilated.h"
|
#include "Vlinetest.h"
|
#include "Vlinetest.h"
|
|
#include "verilated_vcd_c.h"
|
#include "uartsim.h"
|
#include "uartsim.h"
|
|
|
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
Verilated::commandArgs(argc, argv);
|
Verilated::commandArgs(argc, argv);
|
Vlinetest tb;
|
Vlinetest tb;
|
UARTSIM *uart;
|
UARTSIM *uart;
|
bool run_interactively = false;
|
bool run_interactively = false;
|
int port = 0;
|
int port = 0;
|
unsigned setup = 25;
|
unsigned setup = 25;
|
|
char string[] = "This is a UART testing string\r\n";
|
|
|
for(int argn=1; argn<argc; argn++) {
|
for(int argn=1; argn<argc; argn++) {
|
if (argv[argn][0] == '-') for(int j=1; (j<1000)&&(argv[argn][j]); j++)
|
if (argv[argn][0] == '-') for(int j=1; (j<1000)&&(argv[argn][j]); j++)
|
switch(argv[argn][j]) {
|
switch(argv[argn][j]) {
|
case 'i':
|
case 'i':
|
Line 81... |
Line 84... |
break;
|
break;
|
}
|
}
|
}
|
}
|
|
|
tb.i_setup = setup;
|
tb.i_setup = setup;
|
tb.i_uart = 1;
|
int baudclocks = setup & 0x0ffffff;
|
|
tb.i_uart_rx = 1;
|
if (run_interactively) {
|
if (run_interactively) {
|
uart = new UARTSIM(port);
|
uart = new UARTSIM(port);
|
uart->setup(tb.i_setup);
|
uart->setup(tb.i_setup);
|
|
|
while(1) {
|
while(1) {
|
Line 93... |
Line 97... |
tb.i_clk = 1;
|
tb.i_clk = 1;
|
tb.eval();
|
tb.eval();
|
tb.i_clk = 0;
|
tb.i_clk = 0;
|
tb.eval();
|
tb.eval();
|
|
|
tb.i_uart = (*uart)(tb.o_uart);
|
tb.i_uart_rx = (*uart)(tb.o_uart_tx);
|
}
|
}
|
|
|
} else {
|
} else {
|
int childs_stdin[2], childs_stdout[2];
|
int childs_stdin[2], childs_stdout[2];
|
|
|
Line 106... |
Line 110... |
perror("O/S ERR");
|
perror("O/S ERR");
|
printf("TEST FAILURE\n");
|
printf("TEST FAILURE\n");
|
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
}
|
}
|
|
|
pid_t pid = fork();
|
pid_t childs_pid = fork();
|
|
|
if (pid < 0) {
|
if (childs_pid < 0) {
|
fprintf(stderr, "ERR setting up child process\n");
|
fprintf(stderr, "ERR setting up child process\n");
|
perror("O/S ERR");
|
perror("O/S ERR");
|
printf("TEST FAILURE\n");
|
printf("TEST FAILURE\n");
|
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
}
|
}
|
|
|
if (pid) {
|
if (childs_pid) {
|
int nr=-2, nw;
|
int nr=-2, nw;
|
|
|
// We are the parent
|
// We are the parent
|
close(childs_stdin[ 0]); // Close the read end
|
close(childs_stdin[ 0]); // Close the read end
|
close(childs_stdout[1]); // Close the write end
|
close(childs_stdout[1]); // Close the write end
|
|
|
char string[] = "This is a UART testing string\r\n";
|
|
char test[256];
|
char test[256];
|
|
|
nw = write(childs_stdin[1], string, strlen(string));
|
nw = write(childs_stdin[1], string, strlen(string));
|
if (nw == (int)strlen(string)) {
|
if (nw == (int)strlen(string)) {
|
int rpos = 0;
|
int rpos = 0;
|
Line 140... |
Line 143... |
if (rpos > 0)
|
if (rpos > 0)
|
test[rpos] = '\0';
|
test[rpos] = '\0';
|
printf("Successfully read %d characters: %s\n", nr, test);
|
printf("Successfully read %d characters: %s\n", nr, test);
|
}
|
}
|
|
|
// We are done, kill our child if not already dead
|
int status = 0, rv = -1;
|
kill(pid, SIGTERM);
|
|
|
// Give the child the oppoortunity to take another
|
|
// 60 seconds to finish closing itself
|
|
for(int waitcount=0; waitcount < 60; waitcount++) {
|
|
rv = waitpid(-1, &status, WNOHANG);
|
|
if (rv == childs_pid)
|
|
break;
|
|
else if (rv < 0)
|
|
break;
|
|
else // rv == 0
|
|
sleep(1);
|
|
}
|
|
|
|
if (rv != childs_pid) {
|
|
kill(childs_pid, SIGTERM);
|
|
printf("WARNING: Child/simulator did not terminate normally\n");
|
|
}
|
|
|
|
if (WEXITSTATUS(status) != EXIT_SUCCESS) {
|
|
printf("WARNING: Child/simulator exit status does not indicate success\n");
|
|
}
|
|
|
if ((nr == nw)&&(nw == (int)strlen(string))
|
if ((nr == nw)&&(nw == (int)strlen(string))
|
&&(strcmp(test, string) == 0))
|
&&(strcmp(test, string) == 0)) {
|
printf("SUCCESS!\n");
|
printf("PASS!\n");
|
else
|
exit(EXIT_SUCCESS);
|
|
} else {
|
printf("TEST FAILED\n");
|
printf("TEST FAILED\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
} else {
|
} else {
|
close(childs_stdin[ 1]);
|
close(childs_stdin[ 1]);
|
close(childs_stdout[0]);
|
close(childs_stdout[0]);
|
close(STDIN_FILENO);
|
close(STDIN_FILENO);
|
if (dup(childs_stdin[0]) < 0) {
|
if (dup(childs_stdin[0]) < 0) {
|
Line 171... |
Line 197... |
uart->setup(tb.i_setup);
|
uart->setup(tb.i_setup);
|
|
|
// Make sure we don't run longer than 4 seconds ...
|
// Make sure we don't run longer than 4 seconds ...
|
time_t start = time(NULL);
|
time_t start = time(NULL);
|
int iterations_before_check = 2048;
|
int iterations_before_check = 2048;
|
|
unsigned clocks = 0;
|
bool done = false;
|
bool done = false;
|
|
|
for(int i=0; i<200000; i++) {
|
#define VCDTRACE
|
|
#ifdef VCDTRACE
|
|
Verilated::traceEverOn(true);
|
|
VerilatedVcdC* tfp = new VerilatedVcdC;
|
|
tb.trace(tfp, 99);
|
|
tfp->open("linetest.vcd");
|
|
#define TRACE_POSEDGE tfp->dump(10*clocks)
|
|
#define TRACE_NEGEDGE tfp->dump(10*clocks+5)
|
|
#define TRACE_CLOSE tfp->close()
|
|
#else
|
|
#define TRACE_POSEDGE while(0)
|
|
#define TRACE_NEGEDGE while(0)
|
|
#define TRACE_CLOSE while(0)
|
|
#endif
|
|
|
|
for(int i=0; i<(baudclocks*24); i++) {
|
// Clear any initial break condition
|
// Clear any initial break condition
|
tb.i_clk = 1;
|
tb.i_clk = 1;
|
tb.eval();
|
tb.eval();
|
tb.i_clk = 0;
|
tb.i_clk = 0;
|
tb.eval();
|
tb.eval();
|
|
|
tb.i_uart = 1;
|
tb.i_uart_rx = 1;
|
}
|
}
|
|
|
while(!done) {
|
while(clocks < 2*(baudclocks*16)*strlen(string)) {
|
tb.i_clk = 1;
|
tb.i_clk = 1;
|
tb.eval();
|
tb.eval();
|
|
TRACE_POSEDGE;
|
tb.i_clk = 0;
|
tb.i_clk = 0;
|
tb.eval();
|
tb.eval();
|
|
TRACE_NEGEDGE;
|
|
clocks++;
|
|
|
tb.i_uart = (*uart)(tb.o_uart);
|
tb.i_uart_rx = (*uart)(tb.o_uart_tx);
|
|
|
if (false) {
|
if (false) {
|
static long counts = 0;
|
/*
|
static int lasti = 1, lasto = 1;
|
static long counts = 0;
|
bool writeout = false;
|
static int lasti = 1, lasto = 1;
|
|
bool writeout = false;
|
counts++;
|
|
if (lasti != tb.i_uart) {
|
counts++;
|
writeout = true;
|
if (lasti != tb.i_uart) {
|
lasti = tb.i_uart;
|
writeout = true;
|
} if (lasto != tb.o_uart) {
|
lasti = tb.i_uart;
|
writeout = true;
|
} if (lasto != tb.o_uart) {
|
lasto = tb.o_uart;
|
writeout = true;
|
}
|
lasto = tb.o_uart;
|
|
}
|
if (writeout) {
|
|
fprintf(stderr, "%08lx : [%d -> %d] %02x:%02x (%02x/%d) %d,%d->%02x [%2d/%d/%08x]\n",
|
if (writeout) {
|
counts, tb.i_uart, tb.o_uart,
|
fprintf(stderr, "%08lx : [%d -> %d] %02x:%02x (%02x/%d) %d,%d->%02x [%2d/%d/%08x]\n",
|
tb.v__DOT__head,
|
counts, tb.i_uart, tb.o_uart,
|
tb.v__DOT__tail,
|
tb.v__DOT__head,
|
tb.v__DOT__lineend,
|
tb.v__DOT__tail,
|
tb.v__DOT__run_tx,
|
tb.v__DOT__lineend,
|
tb.v__DOT__tx_stb,
|
tb.v__DOT__run_tx,
|
tb.v__DOT__transmitter__DOT__r_busy,
|
tb.v__DOT__tx_stb,
|
tb.v__DOT__tx_data & 0x0ff,
|
tb.v__DOT__transmitter__DOT__r_busy,
|
tb.v__DOT__transmitter__DOT__state,
|
tb.v__DOT__tx_data & 0x0ff,
|
tb.v__DOT__transmitter__DOT__zero_baud_counter,
|
tb.v__DOT__transmitter__DOT__state,
|
tb.v__DOT__transmitter__DOT__baud_counter);
|
tb.v__DOT__transmitter__DOT__zero_baud_counter,
|
}
|
tb.v__DOT__transmitter__DOT__baud_counter);
|
|
} */
|
}
|
}
|
|
|
if (iterations_before_check-- <= 0) {
|
if (iterations_before_check-- <= 0) {
|
iterations_before_check = 2048;
|
iterations_before_check = 2048;
|
done = ((time(NULL)-start)>60);
|
done = ((time(NULL)-start)>60);
|
if (done)
|
if (done)
|
fprintf(stderr, "CHILD-TIMEOUT\n");
|
fprintf(stderr, "CHILD-TIMEOUT\n");
|
}
|
}
|
}
|
}
|
|
|
|
TRACE_CLOSE;
|
|
|
|
exit(EXIT_SUCCESS);
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
No newline at end of file
|
No newline at end of file
|