blob: cc81df03108113703062a3ae56b3e99a8684393a [file] [log] [blame]
//////////////////////////////////////////////////////////////////////
//// ////
//// Single SPI Master Interface Module ////
//// ////
//// This file is part of the riscduino cores project ////
//// https://github.com/dineshannayya/riscduino.git ////
//// ////
//// Description ////
//// Subbport Single Bit SPI Master ////
//// ////
//// To Do: ////
//// nothing ////
//// ////
//// Author(s): ////
//// - Dinesh Annayya, dinesha@opencores.org ////
//// ////
//// Revision : ////
//// V.0 - 06 Oct 2021 ////
//// Initial SpI Module picked from ////
//// http://www.opencores.org/cores/turbo8051/ ////
//// ////
//// ////
//////////////////////////////////////////////////////////////////////
//// ////
//// Copyright (C) 2000 Authors and OPENCORES.ORG ////
//// ////
//// This source file may be used and distributed without ////
//// restriction provided that this copyright statement is not ////
//// removed from the file and that any derivative work contains ////
//// the original copyright notice and the associated disclaimer. ////
//// ////
//// This source file is free software; you can redistribute it ////
//// and/or modify it under the terms of the GNU Lesser General ////
//// Public License as published by the Free Software Foundation; ////
//// either version 2.1 of the License, or (at your option) any ////
//// later version. ////
//// ////
//// This source is distributed in the hope that it will be ////
//// useful, but WITHOUT ANY WARRANTY; without even the implied ////
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ////
//// PURPOSE. See the GNU Lesser General Public License for more ////
//// details. ////
//// ////
//// You should have received a copy of the GNU Lesser General ////
//// Public License along with this source; if not, download it ////
//// from http://www.opencores.org/lgpl.shtml ////
//// ////
//////////////////////////////////////////////////////////////////////
/*******************************************************************
SPI Mode:
Mode 0 (the default)− Clock is normally low (CPOL = 0), and Data sampled on rising edge and shifted out on the falling edge. (CPHA = 0). - Supported
Mode 1 − Clock is normally low (CPOL = 0), and Data sampled on the falling edge and shifted out on the rising edge. (CPHA = 1). - Not Supported
Mode 2 − Clock is normally high (CPOL = 1), and Data sampled on the rising edge and shifted out on the falling edge. (CPHA = 0). - Supported
Mode 3 − Clock is normally high (CPOL = 1), and Data sampled on the falling edge and shifted out on the rising edge (CPHA = 1). - Not Supported
********************************************************************/
module sspim_cfg (
input logic mclk ,
input logic reset_n ,
output logic [1:0] cfg_tgt_sel ,
output logic cfg_cpol , // spi clock idle phase
output logic cfg_cpha , // spi data sample and lanch phase
output logic cfg_bit_order , // SPI TX/RX Bit Order, 1 -> LSBFIRST or 0 -> MSBFIRST
output logic cfg_op_req , // SPI operation request
output logic cfg_endian , // Endian selection
output logic [1:0] cfg_op_type , // SPI operation type
output logic [1:0] cfg_transfer_size , // SPI transfer size
output logic [5:0] cfg_sck_period , // sck clock period
output logic [4:0] cfg_sck_cs_period , // cs setup/hold period
output logic [7:0] cfg_cs_byte , // cs bit information
output logic [31:0] cfg_datain , // data for transfer
input logic [31:0] cfg_dataout , // data for received
input logic hware_op_done , // operation done
//---------------------------------
// Reg Bus Interface Signal
//---------------------------------
input logic reg_cs ,
input logic reg_wr ,
input logic [7:0] reg_addr ,
input logic [31:0] reg_wdata ,
input logic [3:0] reg_be ,
// Outputs
output logic [31:0] reg_rdata ,
output logic reg_ack
);
//-----------------------------------------------------------------------
// Internal Wire Declarations
//-----------------------------------------------------------------------
logic sw_rd_en ;
logic sw_wr_en;
logic [1:0] sw_addr; // addressing 16 registers
logic [3:0] wr_be ;
logic reg_cs_l;
logic reg_cs_2l;
logic [31:0] reg_0; // Software_Reg_0
logic [31:0] reg_1; // Software-Reg_1
logic [31:0] reg_2; // Software-Reg_2
logic [31:0] reg_out;
logic [1:0] cfg_spi_mode;
//-----------------------------------------------------------------------
// Main code starts here
//-----------------------------------------------------------------------
//-----------------------------------------------------------------------
// Internal Logic Starts here
//-----------------------------------------------------------------------
assign sw_addr = reg_addr [3:2];
assign sw_rd_en = reg_cs & !reg_wr;
assign sw_wr_en = reg_cs & reg_wr;
assign wr_be = reg_be;
//-----------------------------------------------------------------------
// Read path mux
//-----------------------------------------------------------------------
always @ (posedge mclk or negedge reset_n)
begin : preg_out_Seq
if (reset_n == 1'b0)
begin
reg_rdata <= 'h0;
reg_ack <= 1'b0;
end
else if (sw_rd_en && !reg_ack)
begin
reg_rdata <= reg_out;
reg_ack <= 1'b1;
end
else if (sw_wr_en && !reg_ack)
reg_ack <= 1'b1;
else
begin
reg_ack <= 1'b0;
end
end
//-----------------------------------------------------------------------
// register read enable and write enable decoding logic
//-----------------------------------------------------------------------
wire sw_wr_en_0 = sw_wr_en & (sw_addr == 2'h0);
wire sw_rd_en_0 = sw_rd_en & (sw_addr == 2'h0);
wire sw_wr_en_1 = sw_wr_en & (sw_addr == 2'h1);
wire sw_rd_en_1 = sw_rd_en & (sw_addr == 2'h1);
wire sw_wr_en_2 = sw_wr_en & (sw_addr == 2'h2);
wire sw_rd_en_2 = sw_rd_en & (sw_addr == 2'h2);
wire sw_wr_en_3 = sw_wr_en & (sw_addr == 2'h3);
wire sw_rd_en_3 = sw_rd_en & (sw_addr == 2'h3);
always @( *)
begin : preg_sel_Com
reg_out [31:0] = 32'd0;
case (sw_addr [1:0])
2'b00 : reg_out [31:0] = reg_0 [31:0];
2'b01 : reg_out [31:0] = reg_1 [31:0];
2'b10 : reg_out [31:0] = reg_2 [31:0];
default : reg_out [31:0] = 32'h0;
endcase
end
//-----------------------------------------------------------------------
// Individual register assignments
//-----------------------------------------------------------------------
// Logic for Register 0 : SPI Control Register
//-----------------------------------------------------------------------
assign cfg_cpha = cfg_spi_mode[0];
assign cfg_cpol = cfg_spi_mode[1];
assign cfg_op_req = reg_0[31]; // cpu request
assign cfg_bit_order = reg_0[28]; // 1 -> LSBFIRST or 0 -> MSBFIRST
assign cfg_spi_mode = reg_0[27:26]; // spi mode
assign cfg_endian = reg_0[25]; // Endian, 0 - little, 1 - Big
assign cfg_tgt_sel = reg_0[24:23]; // target chip select
assign cfg_op_type = reg_0[22:21]; // SPI operation type
assign cfg_transfer_size = reg_0[20:19]; // SPI transfer size
assign cfg_sck_period = reg_0[18:13]; // sck clock period
assign cfg_sck_cs_period = reg_0[12:8]; // cs setup/hold period
assign cfg_cs_byte = reg_0[7:0]; // cs bit information
generic_register #(8,0 ) u_spi_ctrl_be0 (
.we ({8{sw_wr_en_0 &
wr_be[0] }} ),
.data_in (reg_wdata[7:0] ),
.reset_n (reset_n ),
.clk (mclk ),
//List of Outs
.data_out (reg_0[7:0] )
);
generic_register #(8,0 ) u_spi_ctrl_be1 (
.we ({8{sw_wr_en_0 &
wr_be[1] }} ),
.data_in (reg_wdata[15:8] ),
.reset_n (reset_n ),
.clk (mclk ),
//List of Outs
.data_out (reg_0[15:8] )
);
generic_register #(8,0 ) u_spi_ctrl_be2 (
.we ({8{sw_wr_en_0 &
wr_be[2] }} ),
.data_in (reg_wdata[23:16] ),
.reset_n (reset_n ),
.clk (mclk ),
//List of Outs
.data_out (reg_0[23:16] )
);
generic_register #(7,0 ) u_spi_ctrl_be3 (
.we ({7{sw_wr_en_0 &
wr_be[3] }} ),
.data_in (reg_wdata[30:24] ),
.reset_n (reset_n ),
.clk (mclk ),
//List of Outs
.data_out (reg_0[30:24] )
);
req_register #(0 ) u_spi_ctrl_req (
.cpu_we ({sw_wr_en_0 &
wr_be[3] } ),
.cpu_req (reg_wdata[31] ),
.hware_ack (hware_op_done ),
.reset_n (reset_n ),
.clk (mclk ),
//List of Outs
.data_out (reg_0[31] )
);
//-----------------------------------------------------------------------
// Logic for Register 1 : SPI Data In Register
//-----------------------------------------------------------------------
assign cfg_datain = reg_1[31:0];
generic_register #(8,0 ) u_spi_din_be0 (
.we ({8{sw_wr_en_1 &
wr_be[0] }} ),
.data_in (reg_wdata[7:0] ),
.reset_n (reset_n ),
.clk (mclk ),
//List of Outs
.data_out (reg_1[7:0] )
);
generic_register #(8,0 ) u_spi_din_be1 (
.we ({8{sw_wr_en_1 &
wr_be[1] }} ),
.data_in (reg_wdata[15:8] ),
.reset_n (reset_n ),
.clk (mclk ),
//List of Outs
.data_out (reg_1[15:8] )
);
generic_register #(8,0 ) u_spi_din_be2 (
.we ({8{sw_wr_en_1 &
wr_be[2] }} ),
.data_in (reg_wdata[23:16] ),
.reset_n (reset_n ),
.clk (mclk ),
//List of Outs
.data_out (reg_1[23:16] )
);
generic_register #(8,0 ) u_spi_din_be3 (
.we ({8{sw_wr_en_1 &
wr_be[3] }} ),
.data_in (reg_wdata[31:24] ),
.reset_n (reset_n ),
.clk (mclk ),
//List of Outs
.data_out (reg_1[31:24] )
);
//-----------------------------------------------------------------------
// Logic for Register 2 : SPI Data output Register
//-----------------------------------------------------------------------
assign reg_2 = cfg_dataout;
endmodule