mirror of
https://github.com/antonblanchard/microwatt.git
synced 2026-04-10 22:31:45 +00:00
Merge pull request #179 from antonblanchard/yosys-verilator
Add yosys/verilator support
This commit is contained in:
@@ -60,6 +60,15 @@ all: microwatt.bit
|
||||
microwatt.json: $(VHDL_FILES)
|
||||
$(YOSYS) -m $(GHDLSYNTH) -p "ghdl --std=08 $(GHDL_IMAGE_GENERICS) $(GHDL_TARGET_GENERICS) $(VHDL_FILES) -e toplevel; synth_ecp5 -json $@"
|
||||
|
||||
microwatt.v: $(VHDL_FILES)
|
||||
$(YOSYS) -m $(GHDLSYNTH) -p "ghdl --std=08 $(GHDL_IMAGE_GENERICS) $(GHDL_TARGET_GENERICS) $(VHDL_FILES) -e toplevel; write_verilog $@"
|
||||
|
||||
microwatt-verilator: microwatt.v verilator/microwatt-verilator.cpp verilator/uart-verilator.c
|
||||
#verilator -O3 -Wall --assert --cc microwatt.v --exe verilator/microwatt-verilator.cpp verilator/uart-verilator.c -o $@ -Wno-CASEOVERLAP -Wno-UNOPTFLAT #--trace
|
||||
verilator -O3 --assert --cc microwatt.v --exe verilator/microwatt-verilator.cpp verilator/uart-verilator.c -o $@ -Wno-CASEOVERLAP -Wno-UNOPTFLAT #--trace
|
||||
make -C obj_dir -f Vmicrowatt.mk
|
||||
@cp -f obj_dir/microwatt-verilator microwatt-verilator
|
||||
|
||||
microwatt_out.config: microwatt.json $(LPF)
|
||||
$(NEXTPNR) --json $< --lpf $(LPF) --textcfg $@ $(NEXTPNR_FLAGS) --package $(PACKAGE)
|
||||
|
||||
@@ -72,7 +81,8 @@ prog: microwatt.svf
|
||||
$(OPENOCD) -f $(OPENOCD_JTAG_CONFIG) -f $(OPENOCD_DEVICE_CONFIG) -c "transport select jtag; init; svf $<; exit"
|
||||
|
||||
clean:
|
||||
@rm -f work-obj08.cf *.bit *.json *.svf *.config
|
||||
@rm -f work-obj08.cf *.bit *.json *.svf *.config microwatt.v microwatt-verilator
|
||||
@rm -rf obj_dir/
|
||||
|
||||
.PHONY: clean prog
|
||||
.PRECIOUS: microwatt.json microwatt_out.config microwatt.bit
|
||||
|
||||
83
verilator/microwatt-verilator.cpp
Normal file
83
verilator/microwatt-verilator.cpp
Normal file
@@ -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;
|
||||
}
|
||||
254
verilator/uart-verilator.c
Normal file
254
verilator/uart-verilator.c
Normal file
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user