Add yosys/verilator support
Add a microwatt-verilator target that simulates the ghdl -> yosys -> verilog -> verilator path. A good test of ghdl/yosys synthesis. Because the everything is run through synthesis, the instruction image is baked into the build via the RAM_INIT_FILE generic. Signed-off-by: Anton Blanchard <anton@linux.ibm.com>pull/179/head
							parent
							
								
									6692f0db4f
								
							
						
					
					
						commit
						3e8a6a8fc2
					
				@ -0,0 +1,83 @@
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include "Vmicrowatt.h"
 | 
			
		||||
#include "verilated.h"
 | 
			
		||||
#include "verilated_vcd_c.h"
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Current simulation time
 | 
			
		||||
 * This is a 64-bit integer to reduce wrap over issues and
 | 
			
		||||
 * allow modulus.  You can also use a double, if you wish.
 | 
			
		||||
 */
 | 
			
		||||
vluint64_t main_time = 0;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Called by $time in Verilog
 | 
			
		||||
 * converts to double, to match
 | 
			
		||||
 * what SystemC does
 | 
			
		||||
 */
 | 
			
		||||
double sc_time_stamp(void)
 | 
			
		||||
{
 | 
			
		||||
	return main_time;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if VM_TRACE
 | 
			
		||||
VerilatedVcdC *tfp;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
void tick(Vmicrowatt *top)
 | 
			
		||||
{
 | 
			
		||||
	top->ext_clk = 1;
 | 
			
		||||
	top->eval();
 | 
			
		||||
#if VM_TRACE
 | 
			
		||||
	if (tfp)
 | 
			
		||||
		tfp->dump((double) main_time);
 | 
			
		||||
#endif
 | 
			
		||||
	main_time++;
 | 
			
		||||
 | 
			
		||||
	top->ext_clk = 0;
 | 
			
		||||
	top->eval();
 | 
			
		||||
#if VM_TRACE
 | 
			
		||||
	if (tfp)
 | 
			
		||||
		tfp->dump((double) main_time);
 | 
			
		||||
#endif
 | 
			
		||||
	main_time++;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void uart_tx(unsigned char tx);
 | 
			
		||||
unsigned char uart_rx(void);
 | 
			
		||||
 | 
			
		||||
int main(int argc, char **argv)
 | 
			
		||||
{
 | 
			
		||||
	Verilated::commandArgs(argc, argv);
 | 
			
		||||
 | 
			
		||||
	// init top verilog instance
 | 
			
		||||
	Vmicrowatt* top = new Vmicrowatt;
 | 
			
		||||
 | 
			
		||||
#if VM_TRACE
 | 
			
		||||
	// init trace dump
 | 
			
		||||
	Verilated::traceEverOn(true);
 | 
			
		||||
	tfp = new VerilatedVcdC;
 | 
			
		||||
	top->trace(tfp, 99);
 | 
			
		||||
	tfp->open("microwatt-verilator.vcd");
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	// Reset
 | 
			
		||||
	top->ext_rst = 0;
 | 
			
		||||
	for (unsigned long i = 0; i < 5; i++)
 | 
			
		||||
		tick(top);
 | 
			
		||||
	top->ext_rst = 1;
 | 
			
		||||
 | 
			
		||||
	while(!Verilated::gotFinish()) {
 | 
			
		||||
		tick(top);
 | 
			
		||||
 | 
			
		||||
		uart_tx(top->uart0_txd);
 | 
			
		||||
		top->uart0_rxd = uart_rx();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
#if VM_TRACE
 | 
			
		||||
	tfp->close();
 | 
			
		||||
	delete tfp;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	delete top;
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,254 @@
 | 
			
		||||
#include <signal.h>
 | 
			
		||||
#include <poll.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <termios.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
 | 
			
		||||
/* Should we exit simulation on ctrl-c or pass it through? */
 | 
			
		||||
#define EXIT_ON_CTRL_C
 | 
			
		||||
 | 
			
		||||
#define CLOCK 50000000L
 | 
			
		||||
#define BAUD 115200
 | 
			
		||||
/* Round to nearest */
 | 
			
		||||
#define BITWIDTH ((CLOCK+(BAUD/2))/BAUD)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Our UART uses 16x oversampling, so at 50 MHz and 115200 baud
 | 
			
		||||
 * each sample is: 50000000/(115200*16) = 27 clock cycles. This
 | 
			
		||||
 * means each bit is off by 0.47% so for 8 bits plus a start and
 | 
			
		||||
 * stop bit the errors add to be 4.7%.
 | 
			
		||||
 */
 | 
			
		||||
static double error = 0.05;
 | 
			
		||||
 | 
			
		||||
enum state {
 | 
			
		||||
	IDLE, START_BIT, BITS, STOP_BIT, ERROR
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static enum state tx_state = IDLE;
 | 
			
		||||
static unsigned long tx_countbits;
 | 
			
		||||
static unsigned char tx_bits;
 | 
			
		||||
static unsigned char tx_byte;
 | 
			
		||||
static unsigned char tx_prev;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Return an error if the transition is not close enough to the start or
 | 
			
		||||
 * the end of an expected bit.
 | 
			
		||||
 */
 | 
			
		||||
static bool is_error(unsigned long bits)
 | 
			
		||||
{
 | 
			
		||||
	double e = 1.0 * tx_countbits / BITWIDTH;
 | 
			
		||||
 | 
			
		||||
	if ((e <= (1.0-error)) && (e >= error))
 | 
			
		||||
		return true;
 | 
			
		||||
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void uart_tx(unsigned char tx)
 | 
			
		||||
{
 | 
			
		||||
	switch (tx_state) {
 | 
			
		||||
		case IDLE:
 | 
			
		||||
			if (tx == 0) {
 | 
			
		||||
				tx_state = START_BIT;
 | 
			
		||||
				tx_countbits = BITWIDTH;
 | 
			
		||||
				tx_bits = 0;
 | 
			
		||||
				tx_byte = 0;
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case START_BIT:
 | 
			
		||||
			tx_countbits--;
 | 
			
		||||
			if (tx == 1) {
 | 
			
		||||
				if (is_error(tx_countbits)) {
 | 
			
		||||
					printf("START_BIT error %ld %ld\n", BITWIDTH, tx_countbits);
 | 
			
		||||
					tx_countbits = BITWIDTH*2;
 | 
			
		||||
					tx_state = ERROR;
 | 
			
		||||
					break;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (tx_countbits == 0) {
 | 
			
		||||
				tx_state = BITS;
 | 
			
		||||
				tx_countbits = BITWIDTH;
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case BITS:
 | 
			
		||||
			tx_countbits--;
 | 
			
		||||
			if (tx_countbits == BITWIDTH/2) {
 | 
			
		||||
				tx_byte = tx_byte | (tx << tx_bits);
 | 
			
		||||
				tx_bits = tx_bits + 1;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (tx != tx_prev) {
 | 
			
		||||
				if (is_error(tx_countbits)) {
 | 
			
		||||
					printf("BITS error %ld %ld\n", BITWIDTH, tx_countbits);
 | 
			
		||||
					tx_countbits = BITWIDTH*2;
 | 
			
		||||
					tx_state = ERROR;
 | 
			
		||||
					break;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (tx_countbits == 0) {
 | 
			
		||||
				if (tx_bits == 8) {
 | 
			
		||||
					tx_state = STOP_BIT;
 | 
			
		||||
				}
 | 
			
		||||
				tx_countbits = BITWIDTH;
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case STOP_BIT:
 | 
			
		||||
			tx_countbits--;
 | 
			
		||||
 | 
			
		||||
			if (tx == 0) {
 | 
			
		||||
				if (is_error(tx_countbits)) {
 | 
			
		||||
					printf("STOP_BIT error %ld %ld\n", BITWIDTH, tx_countbits);
 | 
			
		||||
					tx_countbits = BITWIDTH*2;
 | 
			
		||||
					tx_state = ERROR;
 | 
			
		||||
					break;
 | 
			
		||||
				}
 | 
			
		||||
				/* Go straight to idle */
 | 
			
		||||
				write(STDOUT_FILENO, &tx_byte, 1);
 | 
			
		||||
				tx_state = IDLE;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (tx_countbits == 0) {
 | 
			
		||||
				write(STDOUT_FILENO, &tx_byte, 1);
 | 
			
		||||
				tx_state = IDLE;
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case ERROR:
 | 
			
		||||
			tx_countbits--;
 | 
			
		||||
			if (tx_countbits == 0) {
 | 
			
		||||
				tx_state = IDLE;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	tx_prev = tx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct termios oldt;
 | 
			
		||||
 | 
			
		||||
static void disable_raw_mode(void)
 | 
			
		||||
{
 | 
			
		||||
	tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void enable_raw_mode(void)
 | 
			
		||||
{
 | 
			
		||||
	static bool initialized = false;
 | 
			
		||||
 | 
			
		||||
	if (!initialized) {
 | 
			
		||||
		static struct termios newt;
 | 
			
		||||
 | 
			
		||||
		tcgetattr(STDIN_FILENO, &oldt);
 | 
			
		||||
		newt = oldt;
 | 
			
		||||
		cfmakeraw(&newt);
 | 
			
		||||
#ifdef EXIT_ON_CTRL_C
 | 
			
		||||
		newt.c_lflag |= ISIG;
 | 
			
		||||
#endif
 | 
			
		||||
		tcsetattr(STDIN_FILENO, TCSANOW, &newt);
 | 
			
		||||
		initialized = true;
 | 
			
		||||
		atexit(disable_raw_mode);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int nonblocking_read(unsigned char *c)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
	unsigned long val = 0;
 | 
			
		||||
	struct pollfd fdset[1];
 | 
			
		||||
 | 
			
		||||
	enable_raw_mode();
 | 
			
		||||
 | 
			
		||||
	memset(fdset, 0, sizeof(fdset));
 | 
			
		||||
 | 
			
		||||
	fdset[0].fd = STDIN_FILENO;
 | 
			
		||||
	fdset[0].events = POLLIN;
 | 
			
		||||
 | 
			
		||||
	ret = poll(fdset, 1, 0);
 | 
			
		||||
	if (ret == 0)
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	ret = read(STDIN_FILENO, &val, 1);
 | 
			
		||||
	if (ret != 1) {
 | 
			
		||||
		fprintf(stderr, "%s: read of stdin returns %d\n", __func__, ret);
 | 
			
		||||
		exit(1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (ret == 1) {
 | 
			
		||||
		*c = val;
 | 
			
		||||
		return true;
 | 
			
		||||
	} else {
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static enum state rx_state = IDLE;
 | 
			
		||||
static unsigned char rx_char;
 | 
			
		||||
static unsigned long rx_countbits;
 | 
			
		||||
static unsigned char rx_bit;
 | 
			
		||||
static unsigned char rx = 1;
 | 
			
		||||
 | 
			
		||||
/* Avoid calling poll() too much */
 | 
			
		||||
#define RX_INTERVAL 10000
 | 
			
		||||
static unsigned long rx_sometimes;
 | 
			
		||||
 | 
			
		||||
unsigned char uart_rx(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char c;
 | 
			
		||||
 | 
			
		||||
	switch (rx_state) {
 | 
			
		||||
		case IDLE:
 | 
			
		||||
			if (rx_sometimes++ >= RX_INTERVAL) {
 | 
			
		||||
				rx_sometimes = 0;
 | 
			
		||||
 | 
			
		||||
				if (nonblocking_read(&c)) {
 | 
			
		||||
					rx_state = START_BIT;
 | 
			
		||||
					rx_char = c;
 | 
			
		||||
					rx_countbits = BITWIDTH;
 | 
			
		||||
					rx_bit = 0;
 | 
			
		||||
					rx = 0;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case START_BIT:
 | 
			
		||||
			rx_countbits--;
 | 
			
		||||
			if (rx_countbits == 0) {
 | 
			
		||||
				rx_state = BITS;
 | 
			
		||||
				rx_countbits = BITWIDTH;
 | 
			
		||||
				rx = rx_char & 1;
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case BITS:
 | 
			
		||||
			rx_countbits--;
 | 
			
		||||
			if (rx_countbits == 0) {
 | 
			
		||||
				rx_bit = rx_bit + 1;
 | 
			
		||||
				if (rx_bit == 8) {
 | 
			
		||||
					rx = 1;
 | 
			
		||||
					rx_state = STOP_BIT;
 | 
			
		||||
				} else {
 | 
			
		||||
					rx = (rx_char >> rx_bit) & 1;
 | 
			
		||||
				}
 | 
			
		||||
				rx_countbits = BITWIDTH;
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case STOP_BIT:
 | 
			
		||||
			rx_countbits--;
 | 
			
		||||
			if (rx_countbits == 0) {
 | 
			
		||||
				rx_state = IDLE;
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return rx;
 | 
			
		||||
}
 | 
			
		||||
					Loading…
					
					
				
		Reference in New Issue