data/full_repos/permissive/140998581/hdl/micro_uart2.v
data/verilator_xmls/66f155ce-7792-4420-9711-e4d9610d6bda.xml
module micro_uart2
(
   input             clk,
   input             reset_n,
   input             ref_clock,



   input             data_select,
   input             baud_select,
   input             cpu_read,
   input             cpu_write,
   input      [15:0] cpu_wdata,
   output reg [15:0] cpu_rdata,

   output            irq,


   input             ser_in,
   output reg        ser_out
);



localparam TX_IDLE = 2'h0,
           TX_TICK = 2'h1,
           TX_SS   = 2'h2,
           TX_DATA = 2'h3,

           RX_IDLE = 2'h0,
           RX_DATA = 2'h1,
           RX_LOAD = 2'h2,
           RX_STOP = 2'h3;

localparam TX_IRQ  = 0,
           RX_IRQ  = 1;


reg [ 1:0] irq_enable;
reg        ref_meta,ref_sync,ref_edge;
wire       ref_pulse;
reg [15:0] baud_rate,baud_count;
wire       samp_tick;

reg  [2:0] tx_bit_cnt, nxt_tx_bit_cnt;
reg  [2:0] tx_samp_cnt,nxt_tx_samp_cnt;
reg  [1:0] tx_state,   nxt_tx_state;
reg  [7:0] shift_out,  nxt_shift_out;

reg        ser_in_meta,ser_in_sync;
reg  [2:0] rx_bit_cnt, nxt_rx_bit_cnt;
reg  [2:0] rx_samp_cnt,nxt_rx_samp_cnt;
reg  [1:0] rx_state,   nxt_rx_state;
reg  [7:0] shift_in,   nxt_shift_in;
reg  [7:0] rec_reg;
reg        rx_transfer;
reg        rec_has_data;
reg        overflow;





   always @( * )
   begin







      nxt_tx_state    = tx_state;
      nxt_tx_bit_cnt  = tx_bit_cnt;
      nxt_tx_samp_cnt = tx_samp_cnt;
      nxt_shift_out   = shift_out;

      case (tx_state)
      TX_IDLE :
         begin


           ser_out = 1'b1;
           if (cpu_write & data_select)
           begin
              nxt_shift_out  = cpu_wdata[7:0];


              nxt_tx_state   = TX_TICK;
           end
         end
      TX_TICK :
         begin

            nxt_tx_samp_cnt = 3'h0;
            nxt_tx_bit_cnt  = 3'h0;
            ser_out =  1'b1;
            if (samp_tick)
               nxt_tx_state = TX_SS;
         end
      TX_SS :



         begin
            ser_out = (tx_bit_cnt==3'h7) ? 1'b1 : 1'b0;
            if (samp_tick)
            begin
               nxt_tx_samp_cnt = tx_samp_cnt + 3'h1;
               if (tx_samp_cnt==3'h7)
               begin
                  if (tx_bit_cnt==3'h7)
                     nxt_tx_state = TX_IDLE;
                  else
                     nxt_tx_state = TX_DATA;
               end
            end
         end
      TX_DATA :
         begin
            ser_out = shift_out[0];
            if (samp_tick)
            begin
               nxt_tx_samp_cnt = tx_samp_cnt + 3'h1;
               if (tx_samp_cnt==3'h7)
               begin
                  nxt_shift_out= {1'b1,shift_out[7:1]};
                  if (tx_bit_cnt==3'h7)
                     nxt_tx_state = TX_SS;
                  else
                     nxt_tx_bit_cnt = tx_bit_cnt + 3'h1;
               end
            end
         end
      endcase







      nxt_rx_state    = rx_state;
      nxt_rx_bit_cnt  = rx_bit_cnt;
      nxt_rx_samp_cnt = rx_samp_cnt;
      nxt_shift_in    = shift_in;
      rx_transfer     = 1'b0;

      case (rx_state)
      RX_IDLE :
         begin
            nxt_rx_bit_cnt  = 3'h0;
            if (samp_tick)
            begin


               if (ser_in_sync==1'b0)
               begin
                  nxt_rx_samp_cnt = rx_samp_cnt + 3'h1;



                  if (rx_samp_cnt==3'h4)
                     nxt_rx_state = RX_DATA;
               end
               else
                  nxt_rx_samp_cnt = 3'h0;

             end
         end
      RX_DATA :
         if (samp_tick)
         begin

            nxt_rx_samp_cnt = rx_samp_cnt + 3'h1;
            if (rx_samp_cnt==3'h3)
            begin

               nxt_shift_in= {ser_in_sync,shift_in[7:1]};
               nxt_rx_bit_cnt = rx_bit_cnt + 3'h1;
               if (rx_bit_cnt==3'h7)
                  nxt_rx_state = RX_LOAD;
            end
         end

      RX_LOAD :

         if (samp_tick)
         begin
            rx_transfer = (rx_samp_cnt==3'h4);
            nxt_rx_samp_cnt = rx_samp_cnt + 3'h1;
            if (rx_samp_cnt==3'h7)
               nxt_rx_state = RX_STOP;
         end

      RX_STOP :
         if (samp_tick)
         begin


            if (ser_in_sync==1'b1)
            begin
               nxt_rx_samp_cnt = rx_samp_cnt + 3'h1;






               if (rx_samp_cnt==3'h4)
                  nxt_rx_state = RX_IDLE;
            end
            else
               nxt_rx_samp_cnt = 3'h0;

         end
      endcase
   end


   assign ref_pulse = ~ref_edge & ref_sync;
   


   

   assign samp_tick = ref_pulse & (baud_count==16'h0000);





   always @(posedge clk or negedge reset_n)
   begin
      if (!reset_n)
      begin
         ser_in_meta  <= 1'b0;
         ser_in_sync  <= 1'b0;
         ref_meta     <= 1'b0;
         ref_sync     <= 1'b0;
         ref_edge     <= 1'b0;
         rec_has_data <= 1'b0;
         overflow     <= 1'b0;
         baud_count   <= 16'h0;

         tx_state    <= TX_IDLE;
         rx_state    <= RX_IDLE;
         rx_samp_cnt <= 3'h0;
         tx_samp_cnt <= 3'h0;
         irq_enable  <= 2'b00;



         shift_out   <= 8'h00;
         shift_in    <= 8'h00;
         rx_bit_cnt  <= 3'h0;
         tx_bit_cnt  <= 3'h0;
         rec_reg     <= 8'h00;
         baud_rate   <= 16'h0;

      end
      else
      begin



         ser_in_meta <= ser_in;
         ser_in_sync <= ser_in_meta;
         


         ref_meta     <= ref_clock;
         ref_sync     <= ref_meta;
         

         ref_edge     <= ref_sync;
         

         if (ref_pulse)
         begin
            if (samp_tick)
               baud_count <= baud_rate;
            else
               baud_count <= baud_count-1'b1;
         end



         tx_bit_cnt  <= nxt_tx_bit_cnt;
         tx_samp_cnt <= nxt_tx_samp_cnt;
         tx_state    <= nxt_tx_state;
         shift_out   <= nxt_shift_out;
         rx_bit_cnt  <= nxt_rx_bit_cnt;
         rx_samp_cnt <= nxt_rx_samp_cnt;
         rx_state    <= nxt_rx_state;
         shift_in    <= nxt_shift_in;



         if (cpu_write)
         begin
            if (~data_select)
            begin
               if (baud_select)
                  baud_rate <= cpu_wdata[15:0];
               else
                  irq_enable <= cpu_wdata[1:0];
            end
         end




         if (rx_transfer)
         begin

            rec_reg      <= shift_in;
            rec_has_data <= 1'b1;


            if (cpu_read & data_select)
               overflow <= 1'b0;
            else

               if (rec_has_data)
                  overflow <= 1'b1;
         end
         else
         begin
            if (cpu_read & data_select)
            begin
               overflow     <= 1'b0;
               rec_has_data <= 1'b0;
            end
         end

      end

   end


wire tx_ready = (tx_state==TX_IDLE);




wire tx_irq = (irq_enable[TX_IRQ] & tx_ready);
wire rx_irq = (irq_enable[RX_IRQ] & rec_has_data);

   assign irq = tx_irq | rx_irq ;







   always @( * )
   begin
      if (cpu_read)
      begin
         if (data_select)
            cpu_rdata = {8'h00,rec_reg};
         else
         if (baud_select)
            cpu_rdata = baud_rate;
         else

            cpu_rdata = {11'h0,tx_irq,rx_irq,tx_ready,overflow,rec_has_data};
      end
      else
         cpu_rdata = 16'h0;
   end


endmodule
module micro_uart2
(
   input             clk,
   input             reset_n,
   input             ref_clock,



   input             data_select,
   input             baud_select,
   input             cpu_read,
   input             cpu_write,
   input      [15:0] cpu_wdata,
   output reg [15:0] cpu_rdata,

   output            irq,


   input             ser_in,
   output reg        ser_out
);




localparam TX_IDLE = 2'h0,
           TX_TICK = 2'h1,
           TX_SS   = 2'h2,
           TX_DATA = 2'h3,

           RX_IDLE = 2'h0,
           RX_DATA = 2'h1,
           RX_LOAD = 2'h2,
           RX_STOP = 2'h3;

localparam TX_IRQ  = 0,
           RX_IRQ  = 1;


reg [ 1:0] irq_enable;
reg        ref_meta,ref_sync,ref_edge;
wire       ref_pulse;
reg [15:0] baud_rate,baud_count;
wire       samp_tick;

reg  [2:0] tx_bit_cnt, nxt_tx_bit_cnt;
reg  [2:0] tx_samp_cnt,nxt_tx_samp_cnt;
reg  [1:0] tx_state,   nxt_tx_state;
reg  [7:0] shift_out,  nxt_shift_out;

reg        ser_in_meta,ser_in_sync;
reg  [2:0] rx_bit_cnt, nxt_rx_bit_cnt;
reg  [2:0] rx_samp_cnt,nxt_rx_samp_cnt;
reg  [1:0] rx_state,   nxt_rx_state;
reg  [7:0] shift_in,   nxt_shift_in;
reg  [7:0] rec_reg;
reg        rx_transfer;
reg        rec_has_data;
reg        overflow;





   always @( * )
   begin







      nxt_tx_state    = tx_state;
      nxt_tx_bit_cnt  = tx_bit_cnt;
      nxt_tx_samp_cnt = tx_samp_cnt;
      nxt_shift_out   = shift_out;

      case (tx_state)
      TX_IDLE :
         begin


           ser_out = 1'b1;
           if (cpu_write & data_select)
           begin
              nxt_shift_out  = cpu_wdata[7:0];


              nxt_tx_state   = TX_TICK;
           end
         end
      TX_TICK :
         begin

            nxt_tx_samp_cnt = 3'h0;
            nxt_tx_bit_cnt  = 3'h0;
            ser_out =  1'b1;
            if (samp_tick)
               nxt_tx_state = TX_SS;
         end
      TX_SS :



         begin
            ser_out = (tx_bit_cnt==3'h7) ? 1'b1 : 1'b0;
            if (samp_tick)
            begin
               nxt_tx_samp_cnt = tx_samp_cnt + 3'h1;
               if (tx_samp_cnt==3'h7)
               begin
                  if (tx_bit_cnt==3'h7)
                     nxt_tx_state = TX_IDLE;
                  else
                     nxt_tx_state = TX_DATA;
               end
            end
         end
      TX_DATA :
         begin
            ser_out = shift_out[0];
            if (samp_tick)
            begin
               nxt_tx_samp_cnt = tx_samp_cnt + 3'h1;
               if (tx_samp_cnt==3'h7)
               begin
                  nxt_shift_out= {1'b1,shift_out[7:1]};
                  if (tx_bit_cnt==3'h7)
                     nxt_tx_state = TX_SS;
                  else
                     nxt_tx_bit_cnt = tx_bit_cnt + 3'h1;
               end
            end
         end
      endcase







      nxt_rx_state    = rx_state;
      nxt_rx_bit_cnt  = rx_bit_cnt;
      nxt_rx_samp_cnt = rx_samp_cnt;
      nxt_shift_in    = shift_in;
      rx_transfer     = 1'b0;

      case (rx_state)
      RX_IDLE :
         begin
            nxt_rx_bit_cnt  = 3'h0;
            if (samp_tick)
            begin


               if (ser_in_sync==1'b0)
               begin
                  nxt_rx_samp_cnt = rx_samp_cnt + 3'h1;



                  if (rx_samp_cnt==3'h4)
                     nxt_rx_state = RX_DATA;
               end
               else
                  nxt_rx_samp_cnt = 3'h0;

             end
         end
      RX_DATA :
         if (samp_tick)
         begin

            nxt_rx_samp_cnt = rx_samp_cnt + 3'h1;
            if (rx_samp_cnt==3'h3)
            begin

               nxt_shift_in= {ser_in_sync,shift_in[7:1]};
               nxt_rx_bit_cnt = rx_bit_cnt + 3'h1;
               if (rx_bit_cnt==3'h7)
                  nxt_rx_state = RX_LOAD;
            end
         end

      RX_LOAD :

         if (samp_tick)
         begin
            rx_transfer = (rx_samp_cnt==3'h4);
            nxt_rx_samp_cnt = rx_samp_cnt + 3'h1;
            if (rx_samp_cnt==3'h7)
               nxt_rx_state = RX_STOP;
         end

      RX_STOP :
         if (samp_tick)
         begin


            if (ser_in_sync==1'b1)
            begin
               nxt_rx_samp_cnt = rx_samp_cnt + 3'h1;






               if (rx_samp_cnt==3'h4)
                  nxt_rx_state = RX_IDLE;
            end
            else
               nxt_rx_samp_cnt = 3'h0;

         end
      endcase
   end


   assign ref_pulse = ~ref_edge & ref_sync;
   


   

   assign samp_tick = ref_pulse & (baud_count==16'h0000);





   always @(posedge clk or negedge reset_n)
   begin
      if (!reset_n)
      begin
         ser_in_meta  <= 1'b0;
         ser_in_sync  <= 1'b0;
         ref_meta     <= 1'b0;
         ref_sync     <= 1'b0;
         ref_edge     <= 1'b0;
         rec_has_data <= 1'b0;
         overflow     <= 1'b0;
         baud_count   <= 16'h0;

         tx_state    <= TX_IDLE;
         rx_state    <= RX_IDLE;
         rx_samp_cnt <= 3'h0;
         tx_samp_cnt <= 3'h0;
         irq_enable  <= 2'b00;



         shift_out   <= 8'h00;
         shift_in    <= 8'h00;
         rx_bit_cnt  <= 3'h0;
         tx_bit_cnt  <= 3'h0;
         rec_reg     <= 8'h00;
         baud_rate   <= 16'h0;

      end
      else
      begin



         ser_in_meta <= ser_in;
         ser_in_sync <= ser_in_meta;
         


         ref_meta     <= ref_clock;
         ref_sync     <= ref_meta;
         

         ref_edge     <= ref_sync;
         

         if (ref_pulse)
         begin
            if (samp_tick)
               baud_count <= baud_rate;
            else
               baud_count <= baud_count-1'b1;
         end



         tx_bit_cnt  <= nxt_tx_bit_cnt;
         tx_samp_cnt <= nxt_tx_samp_cnt;
         tx_state    <= nxt_tx_state;
         shift_out   <= nxt_shift_out;
         rx_bit_cnt  <= nxt_rx_bit_cnt;
         rx_samp_cnt <= nxt_rx_samp_cnt;
         rx_state    <= nxt_rx_state;
         shift_in    <= nxt_shift_in;



         if (cpu_write)
         begin
            if (~data_select)
            begin
               if (baud_select)
                  baud_rate <= cpu_wdata[15:0];
               else
                  irq_enable <= cpu_wdata[1:0];
            end
         end




         if (rx_transfer)
         begin

            rec_reg      <= shift_in;
            rec_has_data <= 1'b1;


            if (cpu_read & data_select)
               overflow <= 1'b0;
            else

               if (rec_has_data)
                  overflow <= 1'b1;
         end
         else
         begin
            if (cpu_read & data_select)
            begin
               overflow     <= 1'b0;
               rec_has_data <= 1'b0;
            end
         end

      end

   end


wire tx_ready = (tx_state==TX_IDLE);




wire tx_irq = (irq_enable[TX_IRQ] & tx_ready);
wire rx_irq = (irq_enable[RX_IRQ] & rec_has_data);

   assign irq = tx_irq | rx_irq ;







   always @( * )
   begin
      if (cpu_read)
      begin
         if (data_select)
            cpu_rdata = {8'h00,rec_reg};
         else
         if (baud_select)
            cpu_rdata = baud_rate;
         else

            cpu_rdata = {11'h0,tx_irq,rx_irq,tx_ready,overflow,rec_has_data};
      end
      else
         cpu_rdata = 16'h0;
   end


endmodule