blob: 07cf361300e815bc124e63817e322524fdfdd14b [file] [log] [blame]
module UARTDevice #(
parameter ID = 4'h0
)(
input wire clk,
input wire rst,
// Peripheral bus
input wire peripheralEnable,
input wire peripheralBus_we,
input wire peripheralBus_oe,
output wire peripheralBus_busy,
input wire[15:0] peripheralBus_address,
input wire[3:0] peripheralBus_byteSelect,
output wire[31:0] peripheralBus_dataRead,
input wire[31:0] peripheralBus_dataWrite,
output wire requestOutput,
// PWM output
output wire uart_en,
input wire uart_rx,
output wire uart_tx,
output wire uart_irq
);
localparam RX_BUFFER_SIZE = 32;
localparam TX_BUFFER_SIZE = 32;
// Buffer values used for interrupts and status register
wire txDataLost;
wire txBufferFull;
wire txDataAvailable;
wire rxDataLost;
wire rxBufferFull;
wire rxDataAvailable;
reg txDataLostBuffered;
reg txBufferFullBuffered;
reg txDataAvailableBuffered;
reg rxDataLostBuffered;
reg rxBufferFullBuffered;
reg rxDataAvailableBuffered;
always @(posedge clk) begin
if (rst) begin
txDataLostBuffered <= 1'b0;
txBufferFullBuffered <= 1'b0;
txDataAvailableBuffered <= 1'b0;
rxDataLostBuffered <= 1'b0;
rxBufferFullBuffered <= 1'b0;
rxDataAvailableBuffered <= 1'b0;
end else begin
txDataLostBuffered <= txDataLost;
txBufferFullBuffered <= txBufferFull;
txDataAvailableBuffered <= txDataAvailable;
rxDataLostBuffered <= rxDataLost;
rxBufferFullBuffered <= rxBufferFull;
rxDataAvailableBuffered <= rxDataAvailable;
end
end
// Device select
wire[11:0] localAddress;
wire deviceEnable;
DeviceSelect #(.ID(ID)) select(
.peripheralEnable(peripheralEnable),
.peripheralBus_address(peripheralBus_address),
.localAddress(localAddress),
.deviceEnable(deviceEnable));
// Register
// Configuration register Default 0x01047
// b00-b15: cyclesPerBit Default 0x1047 ((CLK_FREQ + BAUD) / BAUD) - 1 => Default uses CLK_FREQ=40MHz BAUD=9600(Actually 9599.2)
// b16: waitForTxSpace Default 0x0
// b17: enable Default 0x0
// b18: dataLostInterruptEnable Default 0x0
// b19: rxDataAvaliableInterruptEnable Default 0x0
// b20: txDataSentInterruptEnable Default 0x0
wire[31:0] configurationRegisterOutputData;
wire configurationRegisterOutputRequest;
wire[20:0] configuration;
ConfigurationRegister #(.WIDTH(21), .ADDRESS(12'h000), .DEFAULT(21'h001047)) configurationRegister(
.clk(clk),
.rst(rst),
.enable(deviceEnable),
.peripheralBus_we(peripheralBus_we),
.peripheralBus_oe(peripheralBus_oe),
.peripheralBus_address(localAddress),
.peripheralBus_byteSelect(peripheralBus_byteSelect),
.peripheralBus_dataWrite(peripheralBus_dataWrite),
.peripheralBus_dataRead(configurationRegisterOutputData),
.requestOutput(configurationRegisterOutputRequest),
.currentValue(configuration));
wire[15:0] cyclesPerBit = configuration[15:0];
wire waitForTxSpace = configuration[16];
assign uart_en = configuration[17];
wire dataLostInterruptEnable = configuration[18];
wire rxDataAvaliableInterruptEnable = configuration[19];
wire txDataSentInterruptEnable = configuration[20];
// Clear register
wire[3:0] clearWriteData;
wire clearWriteEnable;
wire clearRegisterBusyBusy_nc;
wire[31:0] clearRegisterDataOut;
wire clearRegisterRequestOutput_nc;
wire clearRegisterReadDataEnable_nc;
DataRegister #(.WIDTH(4), .ADDRESS(12'h004)) clearRegister(
.clk(clk),
.rst(rst),
.enable(deviceEnable),
.peripheralBus_we(peripheralBus_we),
.peripheralBus_oe(peripheralBus_oe),
.peripheralBus_busy(clearRegisterBusyBusy_nc),
.peripheralBus_address(localAddress),
.peripheralBus_byteSelect(peripheralBus_byteSelect),
.peripheralBus_dataWrite(peripheralBus_dataWrite),
.peripheralBus_dataRead(clearRegisterDataOut),
.requestOutput(clearRegisterRequestOutput_nc),
.writeData(clearWriteData),
.writeData_en(clearWriteEnable),
.writeData_busy(1'b0),
.readData(4'b0),
.readData_en(clearRegisterReadDataEnable_nc),
.readData_busy(1'b0));
// Status register
// b00: rxDataAvailable
// b01: rxBufferFull
// b02: rxDataLost
// b03: txDataAvailable
// b04: txBufferFull
// b05: txDataLost
wire[31:0] statusRegisterOutputData;
wire statusRegisterOutputRequest;
wire statusRegisterBusBusy_nc;
wire[5:0] statusRegisterWriteData_nc;
wire statusRegisterWriteDataEnable_nc;
wire statusRegisterReadDataEnable_nc;
DataRegister #(.WIDTH(6), .ADDRESS(12'h008)) statusRegister(
.clk(clk),
.rst(rst),
.enable(deviceEnable),
.peripheralBus_we(peripheralBus_we),
.peripheralBus_oe(peripheralBus_oe),
.peripheralBus_busy(statusRegisterBusBusy_nc),
.peripheralBus_address(localAddress),
.peripheralBus_byteSelect(peripheralBus_byteSelect),
.peripheralBus_dataWrite(peripheralBus_dataWrite),
.peripheralBus_dataRead(statusRegisterOutputData),
.requestOutput(statusRegisterOutputRequest),
.writeData(statusRegisterWriteData_nc),
.writeData_en(statusRegisterWriteDataEnable_nc),
.writeData_busy(1'b0),
.readData({
txDataLostBuffered,
txBufferFullBuffered,
txDataAvailableBuffered,
rxDataLostBuffered,
rxBufferFullBuffered,
rxDataAvailableBuffered }),
.readData_en(statusRegisterReadDataEnable_nc),
.readData_busy(1'b0));
// Rx register
wire[31:0] rxRegisterOutputData;
wire rxRegisterOutputRequest;
wire[7:0] rxReadData;
wire rxReadDataEnable;
wire rxRegisterBusyBusy_nc;
wire[8:0] rxRegisterWriteData_nc;
wire rxRegisterWriteDataEnable_nc;
DataRegister #(.WIDTH(9), .ADDRESS(12'h010)) rxRegister(
.clk(clk),
.rst(rst),
.enable(deviceEnable),
.peripheralBus_we(peripheralBus_we),
.peripheralBus_oe(peripheralBus_oe),
.peripheralBus_busy(rxRegisterBusyBusy_nc),
.peripheralBus_address(localAddress),
.peripheralBus_byteSelect(peripheralBus_byteSelect),
.peripheralBus_dataWrite(peripheralBus_dataWrite),
.peripheralBus_dataRead(rxRegisterOutputData),
.requestOutput(rxRegisterOutputRequest),
.writeData(rxRegisterWriteData_nc),
.writeData_en(rxRegisterWriteDataEnable_nc),
.writeData_busy(1'b0),
.readData(rxDataAvailable ? { 1'b1, rxReadData } : 9'h0),
.readData_en(rxReadDataEnable),
.readData_busy(1'b0));
// Tx register
wire[31:0] txRegisterOutputData;
wire txRegisterOutputRequest;
wire[7:0] txWriteData;
wire txWriteDataEnable;
wire txBusy;
wire txRegisterReadDataEnable_nc;
DataRegister #(.WIDTH(8), .ADDRESS(12'h014)) txRegister(
.clk(clk),
.rst(rst),
.enable(deviceEnable),
.peripheralBus_we(peripheralBus_we),
.peripheralBus_oe(peripheralBus_oe),
.peripheralBus_busy(txBusy),
.peripheralBus_address(localAddress),
.peripheralBus_byteSelect(peripheralBus_byteSelect),
.peripheralBus_dataWrite(peripheralBus_dataWrite),
.peripheralBus_dataRead(txRegisterOutputData),
.requestOutput(txRegisterOutputRequest),
.writeData(txWriteData),
.writeData_en(txWriteDataEnable),
.writeData_busy(waitForTxSpace && txBufferFull && uart_en),
.readData(8'b0),
.readData_en(txRegisterReadDataEnable_nc),
.readData_busy(1'b0));
wire [7:0] rxByteIn;
wire rxOutAvailable;
UART_rx #(.CLOCK_SCALE_BITS(16)) uartRx(
.clk(clk),
.rst(rst || (clearWriteData[0] && clearWriteEnable && peripheralBus_byteSelect[0])),
.cyclesPerBit(cyclesPerBit),
.rx(uart_en ? uart_rx : 1'b1),
.dataOut(rxByteIn),
.dataAvailable(rxOutAvailable));
wire txSendBusy;
wire[7:0] txByteOut;
UART_tx #(.CLOCK_SCALE_BITS(16)) uartTx(
.clk(clk),
.rst(rst || (clearWriteData[1] && clearWriteEnable && peripheralBus_byteSelect[0])),
.cyclesPerBit(cyclesPerBit),
.tx(uart_tx),
.blockTransmition(!uart_en),
.busy(txSendBusy),
.dataIn(txByteOut),
.dataAvailable(txDataAvailable));
FIFO #(.WORD_SIZE(8), .BUFFER_SIZE(RX_BUFFER_SIZE)) rxBuffer(
.clk(clk),
.rst(rst || (clearWriteData[2] && clearWriteEnable && peripheralBus_byteSelect[0])),
.dataIn(rxByteIn),
.we(rxOutAvailable && uart_en),
.dataOut(rxReadData),
.oe(rxReadDataEnable),
.isData(rxDataAvailable),
.bufferFull(rxBufferFull),
.dataLost(rxDataLost));
FIFO #(.WORD_SIZE(8), .BUFFER_SIZE(TX_BUFFER_SIZE)) txBuffer(
.clk(clk),
.rst(rst || (clearWriteData[3] && clearWriteEnable && peripheralBus_byteSelect[0])),
.dataIn(txWriteData),
.we(txWriteDataEnable && peripheralBus_byteSelect[0] && (!waitForTxSpace || !txBufferFull)),
.dataOut(txByteOut),
.oe(txDataAvailable && uart_en && !txSendBusy),
.isData(txDataAvailable),
.bufferFull(txBufferFull),
.dataLost(txDataLost));
assign requestOutput = configurationRegisterOutputRequest || statusRegisterOutputRequest || rxRegisterOutputRequest || txRegisterOutputRequest;
assign peripheralBus_dataRead = configurationRegisterOutputRequest ? configurationRegisterOutputData :
statusRegisterOutputRequest ? statusRegisterOutputData :
rxRegisterOutputRequest ? rxRegisterOutputData :
txRegisterOutputRequest ? txRegisterOutputData :
~32'b0;
assign peripheralBus_busy = txBusy;
reg sendingData = 1'b0;
always @(posedge clk) begin
if (rst) sendingData <= 1'b0;
else sendingData <= txDataAvailableBuffered;
end
assign uart_irq = (dataLostInterruptEnable && (rxDataLostBuffered || txDataLostBuffered))
|| (rxDataAvaliableInterruptEnable && rxDataAvailableBuffered)
|| (txDataSentInterruptEnable && sendingData && !txDataAvailableBuffered);
endmodule