Add softuart to soc_cxxrtl test.
This commit is contained in:
parent
464bd40440
commit
2e649e2c86
|
@ -1,12 +1,23 @@
|
|||
|
||||
|
||||
#include "tb_cxxrtl_io.h"
|
||||
__attribute__((optimize("O0"))) int main() {
|
||||
#include "uart.h"
|
||||
|
||||
#define CLK_FREQ_MHZ 12
|
||||
|
||||
// __attribute__((optimize("O0")))
|
||||
int main() {
|
||||
// Float stuff should all be compile-time. 115200 baud.
|
||||
uart_init();
|
||||
uart_clkdiv_baud(CLK_FREQ_MHZ, 9600);
|
||||
uart_puts("Hello, UART!\n");
|
||||
// Need to wait for completion, else we will terminate the simulation
|
||||
// while characters still in FIFO.
|
||||
uart_wait_done();
|
||||
|
||||
// tb_puts("Hello world from Hazard3 + CXXRTL!\n");
|
||||
uint32_t addr = 0x40008000;
|
||||
uint32_t *point = (uint32_t *)addr;
|
||||
*point = 'C';
|
||||
*point = 'O';
|
||||
*point = 'L';
|
||||
*point = 'I';
|
||||
*point = 'N';
|
||||
return 123;
|
||||
}
|
||||
|
|
|
@ -11,6 +11,9 @@ TBEXEC := $(patsubst %.f,%,$(DOTF))
|
|||
FILE_LIST := $(shell HDL=$(HDL) $(SCRIPTS)/listfiles $(DOTF))
|
||||
BUILD_DIR := build-$(patsubst %.f,%,$(DOTF))
|
||||
|
||||
SRC = tb.cpp softuart.c
|
||||
INC = -I ${BUILD_DIR} -I ./
|
||||
|
||||
# Note: clang++-18 has a >20x compile time regression, even at low
|
||||
# optimisation levels. I have tried clang++-16 and clang++-17, both fine.
|
||||
CLANGXX := clang++-16
|
||||
|
@ -40,7 +43,7 @@ gdb:
|
|||
/opt/riscv/bin/riscv32-unknown-elf-gdb -x gdb_init
|
||||
|
||||
$(TBEXEC): $(BUILD_DIR)/dut.cpp tb.cpp
|
||||
$(CLANGXX) -O3 -std=c++14 $(addprefix -D,$(CDEFINES) $(CDEFINES_$(DOTF))) -I $(shell yosys-config --datdir)/include/backends/cxxrtl/runtime -I $(BUILD_DIR) tb.cpp -o $(TBEXEC)
|
||||
$(CLANGXX) -O3 -std=c++14 $(addprefix -D,$(CDEFINES) $(CDEFINES_$(DOTF))) -I $(shell yosys-config --datdir)/include/backends/cxxrtl/runtime $(INC) ${SRC} -o $(TBEXEC)
|
||||
|
||||
lint:
|
||||
verilator --lint-only --top-module $(TOP) -I$(HDL) $(FILE_LIST)
|
||||
|
|
|
@ -15,100 +15,72 @@
|
|||
#define SoftUart_IDEF_LEN_C2 (SoftUart_IDEF_LEN_C1 + SoftUart_STOP_Bit)
|
||||
|
||||
// All Soft Uart Config and State
|
||||
SoftUart_S SUart[Number_Of_SoftUarts];
|
||||
SoftUart_S SUart;
|
||||
|
||||
// TX RX Data Buffer
|
||||
SoftUartBuffer_S SUBuffer[Number_Of_SoftUarts];
|
||||
SoftUartBuffer_S SUBuffer;
|
||||
|
||||
// For timing division
|
||||
__IO uint8_t SU_Timer = 0;
|
||||
uint8_t SU_Timer = 0;
|
||||
|
||||
// Parity var
|
||||
static uint8_t DV, PCount;
|
||||
|
||||
// Read RX single Pin Value
|
||||
GPIO_PinState SoftUartGpioReadPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin) {
|
||||
return HAL_GPIO_ReadPin(GPIOx, GPIO_Pin);
|
||||
}
|
||||
|
||||
// Write TX single Pin Value
|
||||
void SoftUartGpioWritePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin,
|
||||
GPIO_PinState PinState) {
|
||||
HAL_GPIO_WritePin(GPIOx, GPIO_Pin, PinState);
|
||||
}
|
||||
|
||||
// Initial Soft Uart
|
||||
SoftUartState_E SoftUartInit(uint8_t SoftUartNumber, GPIO_TypeDef *TxPort,
|
||||
uint16_t TxPin, GPIO_TypeDef *RxPort,
|
||||
uint16_t RxPin) {
|
||||
if (SoftUartNumber >= Number_Of_SoftUarts) return SoftUart_Error;
|
||||
SoftUart_S *SoftUartInit() {
|
||||
SUart.TxNComplated = 0;
|
||||
|
||||
SUart[SoftUartNumber].TxNComplated = 0;
|
||||
SUart.RxBitCounter = 0;
|
||||
SUart.RxBitShift = 0;
|
||||
SUart.RxIndex = 0;
|
||||
|
||||
SUart[SoftUartNumber].RxBitCounter = 0;
|
||||
SUart[SoftUartNumber].RxBitShift = 0;
|
||||
SUart[SoftUartNumber].RxIndex = 0;
|
||||
SUart.TxEnable = 0;
|
||||
SUart.RxEnable = 0;
|
||||
|
||||
SUart[SoftUartNumber].TxEnable = 0;
|
||||
SUart[SoftUartNumber].RxEnable = 0;
|
||||
SUart.TxBitCounter = 0;
|
||||
SUart.TxBitShift = 0;
|
||||
SUart.TxIndex = 0;
|
||||
|
||||
SUart[SoftUartNumber].TxBitCounter = 0;
|
||||
SUart[SoftUartNumber].TxBitShift = 0;
|
||||
SUart[SoftUartNumber].TxIndex = 0;
|
||||
SUart.TxSize = 0;
|
||||
|
||||
SUart[SoftUartNumber].TxSize = 0;
|
||||
SUart.Buffer = &SUBuffer;
|
||||
|
||||
SUart[SoftUartNumber].Buffer = &SUBuffer[SoftUartNumber];
|
||||
SUart.RxTimingFlag = 0;
|
||||
SUart.RxBitOffset = 0;
|
||||
|
||||
SUart[SoftUartNumber].RxPort = RxPort;
|
||||
SUart[SoftUartNumber].RxPin = RxPin;
|
||||
|
||||
SUart[SoftUartNumber].TxPort = TxPort;
|
||||
SUart[SoftUartNumber].TxPin = TxPin;
|
||||
|
||||
SUart[SoftUartNumber].RxTimingFlag = 0;
|
||||
SUart[SoftUartNumber].RxBitOffset = 0;
|
||||
|
||||
return SoftUart_OK;
|
||||
return &SUart;
|
||||
}
|
||||
|
||||
// Send one bit to TX pin
|
||||
void SoftUartTransmitBit(SoftUart_S *SU, uint8_t Bit0_1) {
|
||||
SoftUartGpioWritePin(SU->TxPort, SU->TxPin, (GPIO_PinState)Bit0_1);
|
||||
SU->TxPinValue = Bit0_1;
|
||||
}
|
||||
|
||||
// Enable Soft Uart Receiving
|
||||
SoftUartState_E SoftUartEnableRx(uint8_t SoftUartNumber) {
|
||||
if (SoftUartNumber >= Number_Of_SoftUarts) return SoftUart_Error;
|
||||
SUart[SoftUartNumber].RxEnable = 1;
|
||||
SoftUartState_E SoftUartEnableRx() {
|
||||
SUart.RxEnable = 1;
|
||||
return SoftUart_OK;
|
||||
}
|
||||
|
||||
// Disable Soft Uart Receiving
|
||||
SoftUartState_E SoftUartDisableRx(uint8_t SoftUartNumber) {
|
||||
if (SoftUartNumber >= Number_Of_SoftUarts) return SoftUart_Error;
|
||||
SUart[SoftUartNumber].RxEnable = 0;
|
||||
SoftUartState_E SoftUartDisableRx() {
|
||||
SUart.RxEnable = 0;
|
||||
return SoftUart_OK;
|
||||
}
|
||||
|
||||
// Read Size of Received Data in buffer
|
||||
uint8_t SoftUartRxAlavailable(uint8_t SoftUartNumber) {
|
||||
return SUart[SoftUartNumber].RxIndex;
|
||||
}
|
||||
uint8_t SoftUartRxAlavailable() { return SUart.RxIndex; }
|
||||
|
||||
// Move Received Data to Another Buffer
|
||||
SoftUartState_E SoftUartReadRxBuffer(uint8_t SoftUartNumber, uint8_t *Buffer,
|
||||
uint8_t Len) {
|
||||
SoftUartState_E SoftUartReadRxBuffer(uint8_t *Buffer, uint8_t Len) {
|
||||
int i;
|
||||
if (SoftUartNumber >= Number_Of_SoftUarts) return SoftUart_Error;
|
||||
for (i = 0; i < Len; i++) {
|
||||
Buffer[i] = SUart[SoftUartNumber].Buffer->Rx[i];
|
||||
Buffer[i] = SUart.Buffer->Rx[i];
|
||||
}
|
||||
for (i = 0; i < SUart[SoftUartNumber].RxIndex; i++) {
|
||||
SUart[SoftUartNumber].Buffer->Rx[i] =
|
||||
SUart[SoftUartNumber].Buffer->Rx[i + Len];
|
||||
for (i = 0; i < SUart.RxIndex; i++) {
|
||||
SUart.Buffer->Rx[i] = SUart.Buffer->Rx[i + Len];
|
||||
}
|
||||
SUart[SoftUartNumber].RxIndex -= Len;
|
||||
SUart.RxIndex -= Len;
|
||||
return SoftUart_OK;
|
||||
}
|
||||
|
||||
|
@ -212,78 +184,56 @@ void SoftUartRxDataBitProcess(SoftUart_S *SU, uint8_t B0_1) {
|
|||
|
||||
// Wait Until Transmit Completed
|
||||
// You do not usually need to use this function!
|
||||
void SoftUartWaitUntilTxComplate(uint8_t SoftUartNumber) {
|
||||
while (SUart[SoftUartNumber].TxNComplated);
|
||||
}
|
||||
void SoftUartWaitUntilTxComplate() { while (SUart.TxNComplated); }
|
||||
|
||||
// Copy Data to Transmit Buffer and Start Sending
|
||||
SoftUartState_E SoftUartPuts(uint8_t SoftUartNumber, uint8_t *Data,
|
||||
uint8_t Len) {
|
||||
SoftUartState_E SoftUartPuts(uint8_t *Data, uint8_t Len) {
|
||||
int i;
|
||||
|
||||
if (SoftUartNumber >= Number_Of_SoftUarts) return SoftUart_Error;
|
||||
if (SUart[SoftUartNumber].TxNComplated) return SoftUart_Error;
|
||||
|
||||
SUart[SoftUartNumber].TxIndex = 0;
|
||||
SUart[SoftUartNumber].TxSize = Len;
|
||||
|
||||
if (SUart.TxNComplated) return SoftUart_Error;
|
||||
SUart.TxIndex = 0;
|
||||
SUart.TxSize = Len;
|
||||
for (i = 0; i < Len; i++) {
|
||||
SUart[SoftUartNumber].Buffer->Tx[i] = Data[i];
|
||||
SUart.Buffer->Tx[i] = Data[i];
|
||||
}
|
||||
|
||||
SUart[SoftUartNumber].TxNComplated = 1;
|
||||
SUart[SoftUartNumber].TxEnable = 1;
|
||||
|
||||
SUart.TxNComplated = 1;
|
||||
SUart.TxEnable = 1;
|
||||
return SoftUart_OK;
|
||||
}
|
||||
|
||||
// Capture RX and Get BitOffset
|
||||
uint8_t SoftUartScanRxPorts(void) {
|
||||
int i;
|
||||
uint8_t SoftUartScanRxPorts(SoftUart_S *SU) {
|
||||
uint8_t Buffer = 0x00, Bit;
|
||||
|
||||
for (i = 0; i < Number_Of_SoftUarts; i++) {
|
||||
// Read RX GPIO Value
|
||||
Bit = SoftUartGpioReadPin(SUart[i].RxPort, SUart[i].RxPin);
|
||||
|
||||
// Starting conditions
|
||||
if (!SUart[i].RxBitCounter && !SUart[i].RxTimingFlag && !Bit) {
|
||||
// Save RX Bit Offset
|
||||
// Calculate middle position of data puls
|
||||
SUart[i].RxBitOffset = ((SU_Timer + 2) % 5);
|
||||
|
||||
// Timing Offset is Set
|
||||
SUart[i].RxTimingFlag = 1;
|
||||
}
|
||||
|
||||
// Add all RX GPIO State to Buffer
|
||||
Buffer |= ((Bit & 0x01) << i);
|
||||
// Read RX GPIO Value
|
||||
Bit = SU->RxPinValue;
|
||||
// Starting conditions
|
||||
if (!SUart.RxBitCounter && !SUart.RxTimingFlag && !Bit) {
|
||||
// Save RX Bit Offset
|
||||
// Calculate middle position of data puls
|
||||
SUart.RxBitOffset = ((SU_Timer + 2) % 5);
|
||||
// Timing Offset is Set
|
||||
SUart.RxTimingFlag = 1;
|
||||
}
|
||||
// Add all RX GPIO State to Buffer
|
||||
Buffer |= (Bit & 0x01);
|
||||
return Buffer;
|
||||
}
|
||||
|
||||
// SoftUartHandler must call in interrupt every 0.2*(1/BR)
|
||||
// if BR=9600 then 0.2*(1/9600)=20.8333333 uS
|
||||
void SoftUartHandler(void) {
|
||||
int i;
|
||||
uint8_t SU_DBuffer;
|
||||
|
||||
// Capture RX and Get BitOffset
|
||||
SU_DBuffer = SoftUartScanRxPorts();
|
||||
|
||||
for (i = 0; i < Number_Of_SoftUarts; i++) {
|
||||
// Receive Data if we in middle data pulse position
|
||||
if (SUart[i].RxBitOffset == SU_Timer) {
|
||||
SoftUartRxDataBitProcess(&SUart[i], ((SU_DBuffer >> i) & 0x01));
|
||||
}
|
||||
SU_DBuffer = SoftUartScanRxPorts(&SUart);
|
||||
// Receive Data if we in middle data pulse position
|
||||
if (SUart.RxBitOffset == SU_Timer) {
|
||||
SoftUartRxDataBitProcess(&SUart, (SU_DBuffer & 0x01));
|
||||
}
|
||||
|
||||
// Sending always happens in the first time slot
|
||||
if (SU_Timer == 0) {
|
||||
// Transmit Data
|
||||
for (i = 0; i < Number_Of_SoftUarts; i++) {
|
||||
SoftUartTxProcess(&SUart[i]);
|
||||
}
|
||||
SoftUartTxProcess(&SUart);
|
||||
}
|
||||
|
||||
// Timing process
|
||||
|
|
|
@ -4,6 +4,11 @@
|
|||
https://github.com/liyanboy74
|
||||
*/
|
||||
|
||||
#include <cstdint>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#define Number_Of_SoftUarts 1 // Max 8
|
||||
|
||||
#define SoftUartTxBufferSize 32
|
||||
|
@ -21,7 +26,7 @@ typedef struct {
|
|||
} SoftUartBuffer_S;
|
||||
|
||||
typedef struct {
|
||||
__IO uint8_t TxNComplated;
|
||||
uint8_t TxNComplated;
|
||||
uint8_t TxEnable;
|
||||
uint8_t RxEnable;
|
||||
uint8_t TxBitShift, TxBitCounter;
|
||||
|
@ -29,25 +34,19 @@ typedef struct {
|
|||
uint8_t TxIndex, TxSize;
|
||||
uint8_t RxIndex;
|
||||
SoftUartBuffer_S *Buffer;
|
||||
GPIO_TypeDef *TxPort;
|
||||
uint16_t TxPin;
|
||||
GPIO_TypeDef *RxPort;
|
||||
uint16_t RxPin;
|
||||
uint8_t RxTimingFlag;
|
||||
uint8_t RxBitOffset;
|
||||
uint8_t RxPinValue; // set before SoftUartHandler
|
||||
uint8_t TxPinValue; // get after SoftUartHandler
|
||||
} SoftUart_S;
|
||||
|
||||
// Call Every (0.2)*(1/9600) = 20.83 uS
|
||||
void SoftUartHandler(void);
|
||||
|
||||
void SoftUartWaitUntilTxComplate(uint8_t SoftUartNumber);
|
||||
uint8_t SoftUartRxAlavailable(uint8_t SoftUartNumber);
|
||||
SoftUartState_E SoftUartPuts(uint8_t SoftUartNumber, uint8_t *Data,
|
||||
uint8_t Len);
|
||||
SoftUartState_E SoftUartEnableRx(uint8_t SoftUartNumber);
|
||||
SoftUartState_E SoftUartDisableRx(uint8_t SoftUartNumber);
|
||||
SoftUartState_E SoftUartInit(uint8_t SoftUartNumber, GPIO_TypeDef *TxPort,
|
||||
uint16_t TxPin, GPIO_TypeDef *RxPort,
|
||||
uint16_t RxPin);
|
||||
SoftUartState_E SoftUartReadRxBuffer(uint8_t SoftUartNumber, uint8_t *Buffer,
|
||||
uint8_t Len);
|
||||
void SoftUartWaitUntilTxComplate();
|
||||
uint8_t SoftUartRxAlavailable();
|
||||
SoftUartState_E SoftUartPuts(uint8_t *Data, uint8_t Len);
|
||||
SoftUartState_E SoftUartEnableRx();
|
||||
SoftUartState_E SoftUartDisableRx();
|
||||
SoftUart_S *SoftUartInit();
|
||||
SoftUartState_E SoftUartReadRxBuffer(uint8_t *Buffer, uint8_t Len);
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <cxxrtl/cxxrtl_vcd.h>
|
||||
|
||||
#include "dut.cpp"
|
||||
#include "softuart.h"
|
||||
|
||||
// There must be a better way
|
||||
#ifdef __x86_64__
|
||||
|
@ -110,6 +111,9 @@ int main(int argc, char **argv) {
|
|||
bool replay_jtag = false;
|
||||
std::string jtag_replay_path;
|
||||
|
||||
SoftUart_S *su = SoftUartInit();
|
||||
SoftUartEnableRx();
|
||||
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
std::string s(argv[i]);
|
||||
if (s.rfind("--", 0) != 0) {
|
||||
|
@ -246,6 +250,8 @@ int main(int argc, char **argv) {
|
|||
top.step();
|
||||
top.step(); // workaround for github.com/YosysHQ/yosys/issues/2780
|
||||
|
||||
int uart_sample_count = 0;
|
||||
|
||||
bool timed_out = false;
|
||||
for (int64_t cycle = 0; cycle < max_cycles || max_cycles == 0; ++cycle) {
|
||||
top.p_clk.set<bool>(false);
|
||||
|
@ -335,6 +341,31 @@ int main(int argc, char **argv) {
|
|||
}
|
||||
}
|
||||
|
||||
// 12Mhz -> 9600 = 1250
|
||||
// SoftUartHandler must call in interrupt every 0.2*(1/BR)
|
||||
if (uart_sample_count >= (1250 / 5)) {
|
||||
// if (top.p_uart__tx.get<bool>())
|
||||
// printf("1");
|
||||
// else
|
||||
// printf("0");
|
||||
su->RxPinValue = (top.p_uart__tx.get<bool>() ? 1 : 0);
|
||||
SoftUartHandler();
|
||||
// uint8_t tx = su->TxPinValue;
|
||||
|
||||
// uint8_t ch = getchar(0);
|
||||
// SoftUartPuts(0, &ch, 1);
|
||||
|
||||
if (SoftUartRxAlavailable()) {
|
||||
uint8_t ch = 0;
|
||||
auto re = SoftUartReadRxBuffer(&ch, 1);
|
||||
if (re == SoftUart_OK && ch) printf("%c", ch);
|
||||
}
|
||||
|
||||
uart_sample_count = 0;
|
||||
} else {
|
||||
uart_sample_count++;
|
||||
}
|
||||
|
||||
if (dump_waves) {
|
||||
// The extra step() is just here to get the bus responses to line up
|
||||
// nicely in the VCD (hopefully is a quick update)
|
||||
|
|
Loading…
Reference in New Issue