//////////////////////////////////////////////////////////////////////////// | |
// 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 |