From: Luke Kenneth Casson Leighton Date: Tue, 17 Jul 2018 10:53:43 +0000 (+0100) Subject: add rs232 uart X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=474de2554cbefa89a5a19df1474632a738828419;p=pinmux.git add rs232 uart --- diff --git a/src/bsv/bsv_lib/RS232_modified.bsv b/src/bsv/bsv_lib/RS232_modified.bsv new file mode 100644 index 0000000..ca336d9 --- /dev/null +++ b/src/bsv/bsv_lib/RS232_modified.bsv @@ -0,0 +1,747 @@ +/* +Copyright (c) 2013, IIT Madras +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +* Neither the name of IIT Madras nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +*/ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2010 Bluespec, Inc. ALL RIGHTS RESERVED. +//////////////////////////////////////////////////////////////////////////////// +// Filename : RS232.bsv +// Description : Simple UART BFM RS232 <-> Bit#(8) +//////////////////////////////////////////////////////////////////////////////// +package RS232_modified; + +// Notes : + +//////////////////////////////////////////////////////////////////////////////// +/// Imports +//////////////////////////////////////////////////////////////////////////////// +import Clocks ::*; +import GetPut ::*; +import Connectable ::*; +import FIFOLevel ::*; +import Vector ::*; +import BUtils ::*; +import Counter ::*; + +//////////////////////////////////////////////////////////////////////////////// +/// Exports +//////////////////////////////////////////////////////////////////////////////// +export RS232 (..); +export UART (..); +export BaudGenerator (..); +export Parity (..); +export StopBits (..); +export InputFilter (..); +export Synchronizer (..); +export EdgeDetector (..); +export InputMovingFilter (..); +export mkUART; +export mkBaudGenerator; +export mkInputFilter; +export mkSynchronizer; +export mkEdgeDetector; +export mkInputMovingFilter; + +//////////////////////////////////////////////////////////////////////////////// +/// Types +//////////////////////////////////////////////////////////////////////////////// +typedef union tagged { + void Start; + void Center; + void Wait; + void Sample; + void Parity; + void StopFirst; + void StopLast; + } RecvState deriving (Bits, Eq); + +typedef union tagged { + void Idle; + void Start; + void Wait; + void Shift; + void Stop; + void Stop5; + void Stop2; + void Parity; + } XmitState deriving (Bits, Eq); + +typedef enum { + NONE, + ODD, + EVEN + } Parity deriving (Bits, Eq); + +typedef enum { + STOP_1, + STOP_1_5, + STOP_2 + } StopBits deriving (Bits, Eq); + +//////////////////////////////////////////////////////////////////////////////// +/// Interfaces +//////////////////////////////////////////////////////////////////////////////// +(* always_ready, always_enabled *) +interface RS232; + // Inputs + (* prefix = "" *) + method Action sin((* port = "SIN" *)Bit#(1) x); + // Outputs + (* prefix = "", result = "SOUT" *) + method Bit#(1) sout(); +endinterface + +interface BaudGenerator; + method Action clock_enable(); + method Action clear(); + method Bool baud_tick_16x(); + method Bool baud_tick_2x(); +endinterface + +interface InputFilter#(numeric type size, type a); + method Action clock_enable(); + method a _read(); +endinterface + +(* always_ready, always_enabled *) +interface EdgeDetector#(type a); + method Bool rising(); + method Bool falling(); +endinterface + +(* always_ready, always_enabled *) +interface Synchronizer#(type a); + method Action _write(a x); + method a _read(); +endinterface + +interface InputMovingFilter#(numeric type width, numeric type threshold, type a); + method Action sample(); + method Action clear(); + method a _read(); +endinterface + +interface UART#(numeric type depth); + (* prefix = "" *) + interface RS232 rs232; + interface Get#(Bit#(8)) tx; + interface Put#(Bit#(8)) rx; + method Bool transmission_done; + method Bool receiver_not_empty; + method Bool receiver_not_full; + method Bool transmittor_not_empty; +endinterface + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +/// +/// Implementation of Baud Generator +/// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +module mkBaudGenerator#(Bit#(16) divider)(BaudGenerator); + + //////////////////////////////////////////////////////////////////////////////// + /// Design Elements + //////////////////////////////////////////////////////////////////////////////// + Counter#(16) rBaudCounter <- mkCounter(0); + PulseWire pwBaudTick16x <- mkPulseWire; + + Counter#(3) rBaudTickCounter <- mkCounter(0); + PulseWire pwBaudTick2x <- mkPulseWire; + + Wire#(Bit#(16)) wBaudCount <- mkWire; + rule baud_count_wire; + wBaudCount <= rBaudCounter.value; + endrule + Wire#(Bit#(3)) wBaudTickCount <- mkWire; + rule baud_tick_count_wire; + wBaudTickCount <= rBaudTickCounter.value; + endrule + + //////////////////////////////////////////////////////////////////////////////// + /// Rules + //////////////////////////////////////////////////////////////////////////////// + rule count_baudtick_16x(pwBaudTick16x); + rBaudTickCounter.up; + endrule + + rule assert_2x_baud_tick(rBaudTickCounter.value() == 0 && pwBaudTick16x); + pwBaudTick2x.send; + endrule + + //////////////////////////////////////////////////////////////////////////////// + /// Interface Connections / Methods + //////////////////////////////////////////////////////////////////////////////// + method Action clock_enable(); + if (rBaudCounter.value() + 1 >= divider) begin + pwBaudTick16x.send; + rBaudCounter.clear; + end + else begin + rBaudCounter.up; + end + endmethod + + method Action clear(); + rBaudCounter.clear; + endmethod + + method Bool baud_tick_16x(); + return pwBaudTick16x; + endmethod + + method Bool baud_tick_2x(); + return pwBaudTick2x; + endmethod + +endmodule: mkBaudGenerator + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +/// +/// Implementation of Input Filter +/// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +module mkInputFilter#(a initval, a din)(InputFilter#(size, a)) + provisos( Bits#(a, sa) + , Eq#(a) + , Add#(0, sa, 1) + , Log#(size, logsize) + , Add#(logsize, 1, csize) + ); + + //////////////////////////////////////////////////////////////////////////////// + /// Design Elements + //////////////////////////////////////////////////////////////////////////////// + Counter#(csize) counter <- mkCounter(0); + Reg#(a) rOut <- mkReg(initval); + + //////////////////////////////////////////////////////////////////////////////// + /// Rules + //////////////////////////////////////////////////////////////////////////////// + + //////////////////////////////////////////////////////////////////////////////// + /// Interface Connections / Methods + //////////////////////////////////////////////////////////////////////////////// + method Action clock_enable(); + if (din == unpack(1) && counter.value() != fromInteger(valueof(size))) + counter.up; + else if (din == unpack(0) && counter.value() != 0) + counter.down; + + if (counter.value() == fromInteger(valueof(size))) + rOut <= unpack(1); + else if (counter.value() == 0) + rOut <= unpack(0); + endmethod + + method a _read; + return rOut; + endmethod + +endmodule + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +/// +/// Implementation +/// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +module mkEdgeDetector#(a initval, a din)(EdgeDetector#(a)) + provisos( Bits#(a, sa) + , Eq#(a) + , Add#(0, sa, 1) + ); + + //////////////////////////////////////////////////////////////////////////////// + /// Design Elements + //////////////////////////////////////////////////////////////////////////////// + Reg#(a) rDinD1 <- mkReg(initval); + + //////////////////////////////////////////////////////////////////////////////// + /// Rules + //////////////////////////////////////////////////////////////////////////////// + (* fire_when_enabled *) + (* no_implicit_conditions *) + rule pipeline; + rDinD1 <= din; + endrule + + //////////////////////////////////////////////////////////////////////////////// + /// Interface Connections / Methods + //////////////////////////////////////////////////////////////////////////////// + method Bool rising(); + return (din == unpack(1) && rDinD1 == unpack(0)); + endmethod + + method Bool falling(); + return (din == unpack(0) && rDinD1 == unpack(1)); + endmethod + +endmodule: mkEdgeDetector + +//////////////////////////////////////////////////////////////////////////////// +/// +//////////////////////////////////////////////////////////////////////////////// +function Bool getRising(EdgeDetector#(a) ifc); + return ifc.rising; +endfunction + +function Bool getFalling(EdgeDetector#(a) ifc); + return ifc.falling; +endfunction + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +/// +/// Implementation of Synchronizer +/// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +module mkSynchronizer#(a initval)(Synchronizer#(a)) + provisos( Bits#(a, sa) + , Add#(0, sa, 1) + ); + + //////////////////////////////////////////////////////////////////////////////// + /// Design Elements + //////////////////////////////////////////////////////////////////////////////// + Reg#(a) d1 <- mkReg(initval); + Reg#(a) d2 <- mkReg(initval); + + //////////////////////////////////////////////////////////////////////////////// + /// Interface Connections / Methods + //////////////////////////////////////////////////////////////////////////////// + method Action _write(x); + d1 <= x; + d2 <= d1; + endmethod + + method a _read(); + return d2; + endmethod + +endmodule: mkSynchronizer + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +/// +/// Implementation of Input Filter +/// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +module mkInputMovingFilter#(a din)(InputMovingFilter#(width, threshold, a)) + provisos( Bits#(a, sa) + , Eq#(a) + , Add#(0, sa, 1) + ); + + //////////////////////////////////////////////////////////////////////////////// + /// Design Elements + //////////////////////////////////////////////////////////////////////////////// + Counter#(width) counter <- mkCounter(0); + Reg#(a) rOut <- mkReg(unpack(0)); + PulseWire pwSample <- mkPulseWire; + + //////////////////////////////////////////////////////////////////////////////// + /// Rules + //////////////////////////////////////////////////////////////////////////////// + (* preempts = "threshold_compare, take_sample" *) + rule threshold_compare(counter.value() >= fromInteger(valueof(threshold))); + rOut <= unpack(1); + endrule + + rule take_sample(pwSample && din == unpack(1)); + counter.up; + endrule + + //////////////////////////////////////////////////////////////////////////////// + /// Interface Connections / Methods + //////////////////////////////////////////////////////////////////////////////// + method Action sample(); + pwSample.send; + endmethod + + method Action clear(); + counter.clear(); + rOut <= unpack(0); + endmethod + + method a _read; + return rOut; + endmethod + +endmodule + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +/// +/// Implementation of UART +/// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +module mkUART( Bit#(4) charsize + , Parity paritysel + , StopBits stopbits + , Bit#(16) divider + , UART#(d) ifc) + provisos(Add#(2, _1, d)); + + Integer fifodepth = valueof(d); + + //////////////////////////////////////////////////////////////////////////////// + /// Design Elements + //////////////////////////////////////////////////////////////////////////////// + let baudGen <- mkBaudGenerator( divider ); + + //////////////////////////////////////////////////////////////////////////////// + /// Receive UART + //////////////////////////////////////////////////////////////////////////////// + FIFOLevelIfc#(Bit#(8), d) fifoRecv <- mkGFIFOLevel(True, False, True); + + Vector#(8, Reg#(Bit#(1))) vrRecvBuffer <- replicateM(mkRegU); + + Reg#(Bit#(1)) rRecvData <- mkReg(1); + + Reg#(RecvState) rRecvState <- mkRegA(Start); + Reg#(Bit#(4)) rRecvCellCount <- mkRegA(0); + Reg#(Bit#(4)) rRecvBitCount <- mkRegA(0); + Reg#(Bit#(1)) rRecvParity <- mkRegA(0); + + PulseWire pwRecvShiftBuffer <- mkPulseWire; + PulseWire pwRecvCellCountReset <- mkPulseWire; + PulseWire pwRecvResetBitCount <- mkPulseWire; + PulseWire pwRecvEnableBitCount <- mkPulseWire; + + //////////////////////////////////////////////////////////////////////////////// + /// Transmit UART + //////////////////////////////////////////////////////////////////////////////// + FIFOLevelIfc#(Bit#(8), d) fifoXmit <- mkGFIFOLevel(False, False, True); + + Vector#(8, Reg#(Bit#(1))) vrXmitBuffer <- replicateM(mkRegU); + + Reg#(XmitState) rXmitState <- mkRegA(Idle); + Reg#(Bit#(4)) rXmitCellCount <- mkRegA(0); + Reg#(Bit#(4)) rXmitBitCount <- mkRegA(0); + Reg#(Bit#(1)) rXmitDataOut <- mkRegA(1); + Reg#(Bit#(1)) rXmitParity <- mkRegA(0); + + PulseWire pwXmitCellCountReset <- mkPulseWire; + PulseWire pwXmitResetBitCount <- mkPulseWire; + PulseWire pwXmitEnableBitCount <- mkPulseWire; + PulseWire pwXmitLoadBuffer <- mkPulseWire; + PulseWire pwXmitShiftBuffer <- mkPulseWire; + + //////////////////////////////////////////////////////////////////////////////// + /// Definitions + //////////////////////////////////////////////////////////////////////////////// + let tick = baudGen.baud_tick_16x; + + //////////////////////////////////////////////////////////////////////////////// + /// Baud Clock Enable + //////////////////////////////////////////////////////////////////////////////// + (* no_implicit_conditions, fire_when_enabled *) + rule baud_generator_clock_enable; + baudGen.clock_enable; + endrule + + //////////////////////////////////////////////////////////////////////////////// + /// Receive Rules + //////////////////////////////////////////////////////////////////////////////// + rule receive_bit_cell_time_counter(tick); + if (pwRecvCellCountReset) + rRecvCellCount <= 0; + else + rRecvCellCount <= rRecvCellCount + 1; + endrule + + rule receive_buffer_shift(pwRecvShiftBuffer); + let v = shiftInAtN(readVReg(vrRecvBuffer), rRecvData); + writeVReg(vrRecvBuffer, v); + endrule + + rule receive_bit_counter; + if (pwRecvResetBitCount) + rRecvBitCount <= 0; + else if (pwRecvEnableBitCount) + rRecvBitCount <= rRecvBitCount + 1; + endrule + + rule receive_wait_for_start_bit(rRecvState == Start && tick); + pwRecvCellCountReset.send(); + if (rRecvData == 1'b0) begin + rRecvState <= Center; + end + else begin + rRecvState <= Start; + pwRecvResetBitCount.send(); + end + endrule + + rule receive_find_center_of_bit_cell(rRecvState == Center && tick); + if (rRecvCellCount == 4'h4) begin + pwRecvCellCountReset.send(); + if (rRecvData == 1'b0) + rRecvState <= Wait; + else + rRecvState <= Start; + end + else begin + rRecvState <= Center; + end + endrule + + rule receive_wait_bit_cell_time_for_sample(rRecvState == Wait && rRecvCellCount == 4'hF && tick); + pwRecvCellCountReset.send; + + if (rRecvBitCount == charsize) begin + if (paritysel != NONE) + rRecvState <= Parity; + else if (stopbits != STOP_1) + rRecvState <= StopFirst; + else + rRecvState <= StopLast; + end + else if (rRecvBitCount == charsize + 1) begin + if (paritysel == NONE || stopbits == STOP_1) + rRecvState <= StopLast; + else + rRecvState <= StopFirst; + end + else if (rRecvBitCount == charsize + 2) begin + rRecvState <= StopLast; + end + else begin + rRecvState <= Sample; + end + endrule + + rule receive_sample_pin(rRecvState == Sample && tick); + pwRecvShiftBuffer.send; + pwRecvEnableBitCount.send; + pwRecvCellCountReset.send; + rRecvState <= Wait; + endrule + + rule receive_parity_bit(rRecvState == Parity && tick); + rRecvParity <= rRecvData; + pwRecvEnableBitCount.send; + pwRecvCellCountReset.send; + rRecvState <= Wait; + endrule + + rule receive_stop_first_bit(rRecvState == StopFirst && tick); + pwRecvEnableBitCount.send; + pwRecvCellCountReset.send; + if (rRecvData == 1) + rRecvState <= Wait; + else + rRecvState <= Start; + endrule + + rule receive_stop_last_bit(rRecvState == StopLast && tick); + Vector#(8, Bit#(1)) data = take(readVReg(vrRecvBuffer)); + Bit#(8) bitdata = pack(data) >> (8 - charsize); + + fifoRecv.enq(bitdata); + rRecvState <= Start; + pwRecvCellCountReset.send; + endrule + + //////////////////////////////////////////////////////////////////////////////// + /// Transmit Rules + //////////////////////////////////////////////////////////////////////////////// + rule transmit_bit_cell_time_counter(tick); + if (pwXmitCellCountReset) + rXmitCellCount <= 0; + else + rXmitCellCount <= rXmitCellCount + 1; + endrule + + rule transmit_bit_counter; + if (pwXmitResetBitCount) + rXmitBitCount <= 0; + else if (pwXmitEnableBitCount) + rXmitBitCount <= rXmitBitCount + 1; + endrule + + rule transmit_buffer_load(pwXmitLoadBuffer); + Bit#(8) data = pack(fifoXmit.first); + fifoXmit.deq; + + writeVReg(vrXmitBuffer, unpack(data)); + rXmitParity <= parity(data); + endrule + + rule transmit_buffer_shift(!pwXmitLoadBuffer && pwXmitShiftBuffer); + let v = shiftInAtN(readVReg(vrXmitBuffer), 1); + writeVReg(vrXmitBuffer, v); + endrule + + rule transmit_wait_for_start_command(rXmitState == Idle && tick); + rXmitDataOut <= 1'b1; + pwXmitResetBitCount.send; + if (fifoXmit.notEmpty) begin + pwXmitCellCountReset.send; + pwXmitLoadBuffer.send; + rXmitState <= Start; + end + else begin + rXmitState <= Idle; + end + endrule + + rule transmit_send_start_bit(rXmitState == Start && tick); + rXmitDataOut <= 1'b0; + if (rXmitCellCount == 4'hF) begin + rXmitState <= Wait; + pwXmitCellCountReset.send; + end + else begin + rXmitState <= Start; + end + endrule + + rule transmit_wait_1_bit_cell_time(rXmitState == Wait && tick); + rXmitDataOut <= head(readVReg(vrXmitBuffer)); + if (rXmitCellCount == 4'hF) begin + pwXmitCellCountReset.send; + if (rXmitBitCount == (charsize - 1) && (paritysel == NONE)) begin + rXmitState <= Stop; + end + else if (rXmitBitCount == (charsize - 1) && (paritysel != NONE)) begin + rXmitState <= Parity; + end + else begin + rXmitState <= Shift; + pwXmitEnableBitCount.send; + end + end + else begin + rXmitState <= Wait; + end + endrule + + rule transmit_shift_next_bit(rXmitState == Shift && tick); + rXmitDataOut <= head(readVReg(vrXmitBuffer)); + rXmitState <= Wait; + pwXmitShiftBuffer.send; + endrule + + rule transmit_send_parity_bit(rXmitState == Parity && tick); + case(paritysel) matches + ODD: rXmitDataOut <= rXmitParity; + EVEN: rXmitDataOut <= ~rXmitParity; + default: rXmitDataOut <= 1'b0; + endcase + + if (rXmitCellCount == 4'hF) begin + rXmitState <= Stop; + pwXmitCellCountReset.send; + end + else begin + rXmitState <= Parity; + end + endrule + + rule transmit_send_stop_bit(rXmitState == Stop && tick); + rXmitDataOut <= 1'b1; + if (rXmitCellCount == 4'hF && (stopbits == STOP_1)) begin + rXmitState <= Idle; + pwXmitCellCountReset.send; + end + else if (rXmitCellCount == 4'hF && (stopbits == STOP_2)) begin + rXmitState <= Stop2; + pwXmitCellCountReset.send; + end + else if (rXmitCellCount == 4'hF && (stopbits == STOP_1_5)) begin + rXmitState <= Stop5; + pwXmitCellCountReset.send; + end + else begin + rXmitState <= Stop; + end + endrule + + rule transmit_send_stop_bit1_5(rXmitState == Stop5 && tick); + rXmitDataOut <= 1'b1; + if (rXmitCellCount == 4'h7) begin + rXmitState <= Idle; + pwXmitCellCountReset.send; + end + else begin + rXmitState <= Stop5; + end + endrule + + rule transmit_send_stop_bit2(rXmitState == Stop2 && tick); + rXmitDataOut <= 1'b1; + if (rXmitCellCount == 4'hF) begin + rXmitState <= Idle; + pwXmitCellCountReset.send; + end + else begin + rXmitState <= Stop2; + end + endrule + + //////////////////////////////////////////////////////////////////////////////// + /// Interface Connections / Methods + //////////////////////////////////////////////////////////////////////////////// + interface RS232 rs232; + method sout = rXmitDataOut; + method sin = rRecvData._write; + endinterface + + interface Get tx; + method ActionValue#(Bit#(8)) get; + let data = pack(fifoRecv.first); + fifoRecv.deq; + return data; + endmethod + endinterface + + interface Put rx; + method Action put(x); + fifoXmit.enq(x); + endmethod + endinterface + + method Bool transmission_done; + if(!fifoXmit.notEmpty && rXmitState==Idle) + return True; + else + return False; + endmethod + + method Bool receiver_not_empty; + return fifoRecv.notEmpty(); + endmethod + + method Bool receiver_not_full; + return fifoRecv.notFull(); + endmethod + + method Bool transmittor_not_empty; + return fifoXmit.notEmpty(); + endmethod +endmodule + + +endpackage + diff --git a/src/bsv/bsv_lib/Uart_bs.bsv b/src/bsv/bsv_lib/Uart_bs.bsv new file mode 100644 index 0000000..0d7a27b --- /dev/null +++ b/src/bsv/bsv_lib/Uart_bs.bsv @@ -0,0 +1,156 @@ + +/* +Copyright (c) 2013, IIT Madras +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +* Neither the name of IIT Madras nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +Description: Bluespec UART with an AXI interface. +*/ +package Uart_bs; + + `define Depth 16 + + import defined_types::*; + import AXI4_Lite_Types::*; + import AXI4_Lite_Fabric::*; + import Semi_FIFOF::*; + `include "instance_defines.bsv" + import RS232_modified::*; + import GetPut::*; + import FIFO::*; + import Clocks::*; + + + interface Ifc_Uart_bs; + interface AXI4_Lite_Slave_IFC#(`PADDR,`Reg_width,`USERSPACE) slave_axi_uart; + interface RS232 coe_rs232; + endinterface + + (*synthesize*) + module mkUart_bs#(Clock core_clock, Reset core_reset)(Ifc_Uart_bs); + + Clock uart_clock<-exposeCurrentClock; + Reset uart_reset<-exposeCurrentReset; + Reg#(Bit#(16)) baud_value <-mkReg(`BAUD_RATE); + UART#(`Depth) uart <-mkUART(8,NONE,STOP_1,baud_value); // charasize,Parity,Stop Bits,BaudDIV + AXI4_Lite_Slave_Xactor_IFC #(`PADDR,`Reg_width,`USERSPACE) s_xactor <- mkAXI4_Lite_Slave_Xactor(clocked_by core_clock, reset_by core_reset); + Reg#(Bit#(4)) rg_status <-mkReg(0); //This register keeps track of whether some data + //is pending to be sent out through the UART Tx + + SyncFIFOIfc#(AXI4_Lite_Rd_Addr #(`PADDR,`USERSPACE)) ff_rd_addr <- mkSyncFIFOToCC(1,core_clock,core_reset); + SyncFIFOIfc#(AXI4_Lite_Wr_Addr #(`PADDR, `USERSPACE)) ff_wr_addr <- mkSyncFIFOToCC(1,core_clock,core_reset); + SyncFIFOIfc#(AXI4_Lite_Wr_Data #(`Reg_width)) ff_wr_data <- mkSyncFIFOToCC(1,core_clock,core_reset); + + SyncFIFOIfc#(AXI4_Lite_Rd_Data #(`Reg_width,`USERSPACE)) ff_rd_resp <- mkSyncFIFOFromCC(1,core_clock); + SyncFIFOIfc#(AXI4_Lite_Wr_Resp #(`USERSPACE)) ff_wr_resp <- mkSyncFIFOFromCC(1,core_clock); + + rule capture_read_request; + let req <- pop_o (s_xactor.o_rd_addr); + ff_rd_addr.enq(req); + endrule + + //Address 'h11304 is uart read data + rule rl_handle_axi4_uart_read(ff_rd_addr.notEmpty && ff_rd_addr.first.araddr[3:2]=='d1); + let req = ff_rd_addr.first; + ff_rd_addr.deq; + `ifdef verbose $display($time,"\tReq: RD_ADDR %h", req.araddr); `endif + Bit#(8) data<-uart.tx.get; + let lv_resp= AXI4_Lite_Rd_Data {rresp:AXI4_LITE_OKAY, rdata: zeroExtend(data), ruser: ?}; + + `ifdef verbose $display($time,"\tResp: RD_RESP %h", req.araddr); `endif + ff_rd_resp.enq(lv_resp); + endrule + + //Address 'b11308 is uart read status + rule rl_handle_axi4_uart_status(ff_rd_addr.notEmpty && ff_rd_addr.first.araddr[3:2]!='d1); + let req =ff_rd_addr.first; + ff_rd_addr.deq; + `ifdef verbose $display($time,"\tReq: RD_ADDR %h", req.araddr); `endif + let lv_resp= AXI4_Lite_Rd_Data {rresp:AXI4_LITE_OKAY, rdata: zeroExtend(rg_status), ruser: ?}; + if(req.araddr[3:2]==2) + lv_resp.rdata=zeroExtend(rg_status); + else if(req.araddr[3:2]==3) + lv_resp.rdata=zeroExtend(baud_value); + else + lv_resp.rresp=AXI4_LITE_SLVERR; + + `ifdef verbose $display($time,"\tResp: RD_RESP %h Status: %b", req.araddr, rg_status); `endif + ff_rd_resp.enq(lv_resp); + endrule + + rule send_read_respone_to_bus; + s_xactor.i_rd_data.enq(ff_rd_resp.first); + ff_rd_resp.deq; + endrule + + rule capture_write_request; + let req <- pop_o (s_xactor.o_wr_addr); + let wr_data <- pop_o(s_xactor.o_wr_data); + ff_wr_addr.enq(req); + ff_wr_data.enq(wr_data); + endrule + + //Address 'b0000 is uart write data + rule rl_handle_axi4_write_rx(ff_wr_addr.notEmpty && ff_wr_data.notEmpty && ff_wr_addr.first.awaddr[3:2]==0); + let wr_addr = ff_wr_addr.first; + ff_wr_addr.deq; + let wr_data = ff_wr_data.first; + ff_wr_data.deq; + + `ifdef verbose $display($time,"\tReq: WR_ADDR %h", wr_addr.awaddr); `endif + `ifdef verbose $display($time,"\tReq: WR_DATA %h", wr_data.wdata); `endif + + uart.rx.put(truncate(wr_data.wdata)); + let lv_resp = AXI4_Lite_Wr_Resp {bresp: AXI4_LITE_OKAY, buser: ?}; + ff_wr_resp.enq(lv_resp); + endrule + + rule rl_handle_axi4_write(ff_wr_addr.notEmpty && ff_wr_data.notEmpty && ff_wr_addr.first.awaddr[3:2]!=0); + let wr_addr = ff_wr_addr.first; + ff_wr_addr.deq; + let wr_data = ff_wr_data.first; + ff_wr_data.deq; + + `ifdef verbose $display($time,"\tReq: WR_ADDR %h", wr_addr.awaddr); `endif + `ifdef verbose $display($time,"\tReq: WR_DATA %h", wr_data.wdata); `endif + + if(wr_addr.awaddr[3:2]=='d3) begin // change the baud value + baud_value<=truncate(wr_data.wdata); + let lv_resp = AXI4_Lite_Wr_Resp {bresp: AXI4_LITE_OKAY, buser: ?}; + ff_wr_resp.enq(lv_resp); + end + else begin + let lv_resp = AXI4_Lite_Wr_Resp {bresp: AXI4_LITE_SLVERR, buser: ?}; + ff_wr_resp.enq(lv_resp); + end + endrule + + rule send_write_response; + s_xactor.i_wr_resp.enq(ff_wr_resp.first); + ff_wr_resp.deq; + endrule + + //The status register is 1 if the transmission FIFO is empty + (*no_implicit_conditions, fire_when_enabled*) + rule rl_update_status_reg; + let lv_status= {pack(uart.receiver_not_empty), pack(uart.receiver_not_full), pack(uart.transmittor_not_empty), pack(uart.transmission_done)}; + rg_status<= lv_status; + `ifdef verbose + if(lv_status==0) + $display($time,"-------UART1 TX Fifo not empty"); + `endif + endrule + + interface slave_axi_uart = s_xactor.axi_side; + interface coe_rs232= uart.rs232; + endmodule +endpackage + diff --git a/src/bsv/bsv_lib/instance_defines.bsv b/src/bsv/bsv_lib/instance_defines.bsv index e66b478..003ad2c 100644 --- a/src/bsv/bsv_lib/instance_defines.bsv +++ b/src/bsv/bsv_lib/instance_defines.bsv @@ -5,12 +5,21 @@ `define Reg_width 64 `define PRFDEPTH 6 `define VADDR 39 +`define UART1 enable `define DCACHE_BLOCK_SIZE 4 `define DCACHE_WORD_SIZE 8 `define PERFMONITORS 64 `define DCACHE_WAYS 4 `define DCACHE_TAG_BITS 20 // tag_bits = 52 + `define UART1Base 'h00011300 + `define UART1End 'h000113FF // 2 32-bit registers + +`define BAUD_RATE 130 +`ifdef simulate + `define BAUD_RATE 5 //130 // +`endif + //`define PWM_AXI4Lite enable