blob: dff5ca9d2c4b08aea6535c5233de07e1e520341d [file] [log] [blame]
////////////////////////////////////////////////////////////////////////////
// SPDX-FileCopyrightText: 2022 , <Julien OURY/Dinesh Annayya>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileContributor: Created by Julien OURY <julien.oury@outlook.fr>
// and Dinesh Annayya <dinesh.annayya@gmail.com>
//
////////////////////////////////////////////////////////////////////////////
/**********************************************************************
NEC IR Register
This file is part of the riscduino cores project
https://github.com/dineshannayya/riscduino.git
To Do:
nothing
Author(s):
- Julien OURY <julien.oury@outlook.fr>
- Dinesh Annayya <dinesh.annayya@gmail.com>
Revision :
0.1 - 11 Dec 2022, Dinesh A
initial version picked from
https://github.com/JulienOury/ChristmasTreeController
0.2 - 13 Dec 2022, Dinesh A
A. Bug fix, Read access clearing the register content
B. FIFO Occpancy added
C. Support for IR Transmitter
***************************************************************************/
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Registers
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
module nec_ir_regs #(
parameter PSIZE = 32 , // Size of prescaler counter(bits)
parameter DSIZE = 32 , // Size of delay counter (bits)
parameter ASIZE = 3 // MEMORY ADDRESS POINTER SIZE
)(
input logic rst_n , // Asynchronous reset (active low)
input logic clk , // Clock (rising edge)
// Configuration
output logic cfg_ir_en , // IR Global Enable
output logic cfg_ir_tx_en , // Transmitter enable
output logic cfg_ir_rx_en , // Receiver enable
output logic cfg_repeat_en , // Repeat enable
output logic cfg_tx_polarity , // Polarity (value of idle state)
output logic cfg_rx_polarity , // Polarity (value of idle state)
output logic [PSIZE-1:0] cfg_multiplier , // frequency multiplier
output logic [PSIZE-1:0] cfg_divider , // frequency divider
output logic [DSIZE-1:0] reload_offset , // Delay counter reload offset
output logic [DSIZE-1:0] delay_mask , // Mask delay
// Wishbone bus
input logic wbs_cyc_i , // Wishbone strobe/request
input logic wbs_stb_i , // Wishbone strobe/request
input logic [4:0] wbs_adr_i , // Wishbone address
input logic wbs_we_i , // Wishbone write (1:write, 0:read)
input logic [31:0] wbs_dat_i , // Wishbone data output
input logic [ 3:0] wbs_sel_i , // Wishbone byte enable
output logic [31:0] wbs_dat_o , // Wishbone data input
output logic wbs_ack_o , // Wishbone acknowlegement
// Input frame interface
// <IR RECEIVER> => <RX FIFO> => WB
input logic rx_frame_new , // New frame received
input logic fifo_rx_full , // RX FIFO full
input logic [16:0] fifo_rx_rdata , // RX FIFO Read Data
output logic fifo_rx_read , // RX FIFO Read
input logic [ASIZE:0] fifo_rx_occ , // RX FIFO Occupancy
// <WB> => <TX FIFO> => <IR Transmitter>
input logic fifo_tx_full , // Tx FIFO full
output logic [15:0] fifo_tx_wdata , // TX FIFO Wdata
output logic fifo_tx_write , // TX FIFO Write
input logic [ASIZE:0] fifo_tx_occ , // FIFO TX Occpancy
// Interrupt
output reg irq // Interrupt
);
localparam
IR_CFG_CMD = 3'b000,
IR_CFG_MULTIPLIER = 3'b001,
IR_CFG_DIVIDER = 3'b010,
IR_CFG_RX_DATA = 3'b011,
IR_CFG_TX_DATA = 3'b100;
logic valid;
logic rstrb;
logic [2:0] addr;
logic [1:0] cfg_tolerance;
logic cfg_irq_en;
logic frame_lost;
logic ready;
assign valid = wbs_cyc_i && wbs_stb_i;
assign rstrb = ~wbs_we_i;
assign addr = wbs_adr_i[4:2];
assign wbs_ack_o = ready;
wire [7:0] rx_frame_data = fifo_rx_rdata[7:0];
wire [7:0] rx_frame_addr = fifo_rx_rdata[15:8];
wire rx_frame_repeat = fifo_rx_rdata[16];
wire fifo_rx_available = (fifo_rx_occ > 0);
always @(negedge rst_n or posedge clk) begin
if (rst_n == 1'b0) begin
ready <= 1'b0;
wbs_dat_o <= 'h0;
cfg_tolerance <= 2'b01;
cfg_multiplier <= {PSIZE{1'b0}};
cfg_divider <= {PSIZE{1'b0}};
cfg_ir_en <= 1'b0;
cfg_ir_tx_en <= 1'b0;
cfg_ir_rx_en <= 1'b0;
cfg_repeat_en <= 1'b0;
cfg_irq_en <= 1'b0;
cfg_tx_polarity <= 1'b0;
cfg_rx_polarity <= 1'b0;
frame_lost <= 1'b0;
irq <= 1'b0;
fifo_tx_write <= 1'b0;
fifo_rx_read <= 1'b0;
end else begin
if (valid && !ready) begin
//Write
case (addr)
IR_CFG_CMD : begin
wbs_dat_o[31] <= cfg_ir_en ; if (wbs_sel_i[3] && wbs_we_i) cfg_ir_en <= wbs_dat_i[31];
wbs_dat_o[30] <= cfg_ir_tx_en ; if (wbs_sel_i[3] && wbs_we_i) cfg_ir_tx_en <= wbs_dat_i[30];
wbs_dat_o[29] <= cfg_ir_rx_en ; if (wbs_sel_i[3] && wbs_we_i) cfg_ir_rx_en <= wbs_dat_i[29];
wbs_dat_o[28] <= cfg_repeat_en ; if (wbs_sel_i[3] && wbs_we_i) cfg_repeat_en <= wbs_dat_i[28];
wbs_dat_o[27] <= cfg_irq_en ; if (wbs_sel_i[3] && wbs_we_i) cfg_irq_en <= wbs_dat_i[27];
wbs_dat_o[26] <= cfg_rx_polarity ; if (wbs_sel_i[3] && wbs_we_i) cfg_rx_polarity <= wbs_dat_i[26];
wbs_dat_o[25] <= cfg_tx_polarity ; if (wbs_sel_i[3] && wbs_we_i) cfg_tx_polarity <= wbs_dat_i[25];
wbs_dat_o[24] <= cfg_tolerance[1] ; if (wbs_sel_i[3] && wbs_we_i) cfg_tolerance[1]<= wbs_dat_i[24];
wbs_dat_o[23] <= cfg_tolerance[0] ; if (wbs_sel_i[2] && wbs_we_i) cfg_tolerance[0]<= wbs_dat_i[23];
wbs_dat_o[22:8] <= 'b0;
wbs_dat_o[7:4] <= fifo_tx_occ;
wbs_dat_o[3:0] <= fifo_rx_occ;
end
IR_CFG_MULTIPLIER : begin
wbs_dat_o <= cfg_multiplier;
if(wbs_sel_i[0] && wbs_we_i) cfg_multiplier[7:0] <= wbs_dat_i[7:0];
if(wbs_sel_i[1] && wbs_we_i) cfg_multiplier[15:8] <= wbs_dat_i[15:8];
if(wbs_sel_i[2] && wbs_we_i) cfg_multiplier[23:16] <= wbs_dat_i[23:16];
if(wbs_sel_i[3] && wbs_we_i) cfg_multiplier[31:24] <= wbs_dat_i[31:24];
end
IR_CFG_DIVIDER : begin
wbs_dat_o <= cfg_divider;
if(wbs_sel_i[0] && wbs_we_i) cfg_divider[7:0] <= wbs_dat_i[7:0];
if(wbs_sel_i[1] && wbs_we_i) cfg_divider[15:8] <= wbs_dat_i[15:8];
if(wbs_sel_i[2] && wbs_we_i) cfg_divider[23:16] <= wbs_dat_i[23:16];
if(wbs_sel_i[3] && wbs_we_i) cfg_divider[31:24] <= wbs_dat_i[31:24];
end
IR_CFG_RX_DATA : begin
if (fifo_rx_available == 1'b1 && !wbs_we_i) begin
wbs_dat_o[31] <= 1'b1;
wbs_dat_o[30] <= rx_frame_repeat;
wbs_dat_o[29] <= frame_lost;
wbs_dat_o[28:16] <= 13'b0;
wbs_dat_o[15:8] <= rx_frame_addr;
wbs_dat_o[7:0] <= rx_frame_data;
fifo_rx_read <= 1'b0;
end else begin
wbs_dat_o[31:0] <= 'b0;
end
end
IR_CFG_TX_DATA : begin
if (fifo_tx_full == 1'b0 && wbs_we_i) begin
fifo_tx_wdata <= wbs_dat_i[15:0];
fifo_tx_write <= 1'b1;
end
end
default: wbs_dat_o[31:0] <= 'b0;
endcase
ready <= 1'b1;
end else begin
fifo_tx_write <= 1'b0;
fifo_rx_read <= 1'b0;
ready <= 1'b0;
end
if ((rx_frame_new == 1'b1) && (fifo_rx_full == 1'b1)) begin
frame_lost <= 1'b1;
end else if (valid && !ready && rstrb && (addr == IR_CFG_RX_DATA)) begin
frame_lost <= 1'b0;
end
if (valid && !ready && rstrb && (addr == IR_CFG_RX_DATA) && fifo_rx_available) begin
fifo_rx_read <= 1'b1;
end else begin
fifo_rx_read <= 1'b0;
end
if ((cfg_irq_en == 1'b1) && (rx_frame_new == 1'b1)) begin
irq <= 1'b1;
end else begin
irq <= 1'b0;
end
end
end
always @(*) begin
case (cfg_tolerance)
2'b00 : begin
reload_offset = {{(DSIZE-3){1'b0}}, 3'b001};
delay_mask = {{(DSIZE-3){1'b1}}, 3'b110};
end
2'b01 : begin
reload_offset = {{(DSIZE-3){1'b0}}, 3'b010};
delay_mask = {{(DSIZE-3){1'b1}}, 3'b100};
end
default : begin
reload_offset = {{(DSIZE-3){1'b0}}, 3'b100};
delay_mask = {{(DSIZE-3){1'b1}}, 3'b000};
end
endcase
end
endmodule