Commit 72351237 authored by Iulian Gheorghiu's avatar Iulian Gheorghiu

Add TWI IP, now is working.

Does not support multiple master TWI devices on the same IP and does not support synchronization.
parent f614b9e5
......@@ -24,7 +24,7 @@
module twi_s #(
parameter DINAMIC_BAUDRATE = "TRUE",
parameter BAUDRATE_DIVIDER = 19200,
parameter BAUDRATE_DIVIDER = 255,
parameter ADDRESS = 0,
parameter BUS_ADDR_DATA_LEN = 16
)(
......@@ -35,26 +35,81 @@ module twi_s #(
input rd,
input [7:0]bus_in,
output reg[7:0]bus_out,
output int,
inout int_rst
output int_tx_cmpl,
output int_rx_cmpl,
input int_tx_rst,
input int_rx_rst,
inout scl,
inout sda
);
reg [7:0]CTRLA;
reg [7:0]CTRLB;
reg [7:0]CTRLC;
reg [7:0]STATUS;
reg [7:0]BAUD;
reg [7:0]DATA;
wire cs_int = addr >= ADDRESS && addr < (ADDRESS + 16);
wire rd_int = cs_int && rd;
wire wr_int = cs_int && wr;
reg [7:0]baud_cnt;
reg [1:0]cmd;
reg tx_mode;
reg start_sent;
reg rcv_ack;
reg send_ack;
reg send_ack_st2;
reg [1:0]stage;
reg [2:0]bit_count;
reg scl_int;
reg sda_int;
reg send_ack_int;
always @ (posedge clk or posedge rst)
localparam [2:0]CMD_NOP = {1'b1, 2'b00};
localparam [2:0]CMD_RESTART = {1'b0, 2'b01};
localparam [2:0]CMD_RECEIVE = {1'b0, 2'b10};
localparam [2:0]CMD_STOP = {1'b0, 2'b11};
always @ (*)
begin
bus_out <= 'hz;
if(rd_int)
begin
case(addr[3:0])
`TWI_MASTER_CTRLA: bus_out <= CTRLA;
`TWI_MASTER_CTRLB: bus_out <= CTRLB;
`TWI_MASTER_CTRLC: bus_out <= CTRLC;
`TWI_MASTER_STATUS: bus_out <= STATUS;
`TWI_MASTER_BAUD: bus_out <= BAUD;
`TWI_MASTER_DATA: bus_out <= DATA;
endcase
end
end
always @ (posedge clk or posedge rst)
begin
if(rst)
begin
baud_cnt = 'h00;
CTRLA <= 'h0;
CTRLB <= 'h0;
CTRLC <= 'h0;
STATUS <= 'h0;
BAUD <= 'h0;
DATA <= 'h0;
baud_cnt <= 'h00;
cmd <= 'h00;
tx_mode <= 1'b0;
start_sent <= 1'b0;
scl_int <= 1'b1;
sda_int <= 1'b1;
rcv_ack <= 1'b0;
send_ack <= 1'b0;
send_ack_st2 <= 1'b0;
stage <= 'h00;
send_ack_int <= 1'b1;
end
else
begin
......@@ -63,12 +118,216 @@ begin
baud_cnt <= 'h00;
if(CTRLA[`TWI_MASTER_ENABLE_bp])
begin
case({tx_mode, cmd})
CMD_NOP:
begin
if(~start_sent)
begin/* Send the start sequence */
stage <= stage + 1;
case(stage)
'h0:
begin
scl_int <= 1'b1;
sda_int <= 1'b0;
end
'h1:
begin
scl_int <= 1'b0;
bit_count <= 'hF;
start_sent <= 1'b1;
stage <= 'h0;
end
endcase
end
else
begin/* Send bits */
stage <= stage + 1;
case(stage)
'h0:
begin
case(rcv_ack)
1'b0:
begin
sda_int <= DATA[bit_count];
end
1'b1:
sda_int <= 1'b1;
endcase
end
'h1:
begin
scl_int <= 1'b1;
end
'h2:
begin
if(rcv_ack)
STATUS[`TWI_MASTER_RXACK_bp] <= sda;
end
'h3:
begin
stage <= 'h0;
scl_int <= 1'b0;
case(rcv_ack)
1'b0:
begin
if(~|bit_count)
rcv_ack <= 1'b1;
bit_count <= bit_count - 1;
end
1'b1:
begin
tx_mode <= 1'b0;
STATUS[`TWI_MASTER_WIF_bp] <= 1'b1;
rcv_ack <= 1'b0;
end
endcase
end
endcase
end
end
CMD_RESTART:
begin/* Send restart */
stage <= stage + 1;
case(stage)
'h0:
begin
sda_int <= 1'b1;
end
'h1:
begin
scl_int <= 1'b1;
end
'h2:
begin
sda_int <= 1'b0;
end
'h3:
begin
scl_int <= 1'b0;
bit_count <= 'hF;
start_sent <= 1'b1;
stage <= 'h0;
cmd <= 'h0;
CTRLC[`TWI_MASTER_CMD_gp + 1:`TWI_MASTER_CMD_gp] <= 'h0;
end
endcase
end
CMD_RECEIVE:
begin/* Receive bits */
stage <= stage + 1;
case(stage)
'h0:
begin
if(send_ack && ~send_ack_st2)
sda_int <= send_ack_int;
else if(send_ack_st2)
begin
STATUS[`TWI_MASTER_RIF_bp] <= 1'b1;
cmd <= 'h0;
CTRLC[`TWI_MASTER_CMD_gp + 1:`TWI_MASTER_CMD_gp] <= 'h0;
sda_int <= 1'b1;
end
end
'h1:
begin
scl_int <= 1'b1;
end
'h2:
begin
if(~send_ack)
DATA[bit_count] <= sda;
end
'h3:
begin
scl_int <= 1'b0;
stage <= 'h0;
case(send_ack)
1'b0:
begin
if(~|bit_count)
send_ack <= 1'b1;
bit_count <= bit_count - 1;
end
1'b1: send_ack_st2 <= 1'b1;
endcase
end
endcase
end
CMD_STOP:
begin/* Send stop */
stage <= stage + 1;
case(stage)
'h0: sda_int <= 1'b0;
'h1: scl_int <= 1'b1;
'h2:
begin
sda_int <= 1'b1;
start_sent <= 1'b0;
stage <= 'h0;
cmd <= 'h0;
CTRLC[`TWI_MASTER_CMD_gp + 1:`TWI_MASTER_CMD_gp] <= 'h0;
end
endcase
end
endcase
end
end
else
begin
baud_cnt <= baud_cnt + 1;
end
if(CTRLA[`TWI_MASTER_ENABLE_bp])
begin
if(CTRLC[`TWI_MASTER_CMD_gp + 1:`TWI_MASTER_CMD_gp] && ~|cmd && ~tx_mode)
begin
cmd <= CTRLC[`TWI_MASTER_CMD_gp + 1:`TWI_MASTER_CMD_gp];
stage <= 'h0;
send_ack <= 1'b0;
send_ack_st2 <= 1'b0;
send_ack_int <= CTRLC[`TWI_SLAVE_ACKACT_bp];
end
end
if(wr_int)
begin
case(addr[3:0])
`TWI_MASTER_CTRLA: CTRLA <= bus_in;
`TWI_MASTER_CTRLB: CTRLB <= bus_in;
`TWI_MASTER_CTRLC: CTRLC <= bus_in;
`TWI_MASTER_STATUS: STATUS <= STATUS ^ bus_in;
`TWI_MASTER_BAUD: BAUD <= bus_in;
//`TWI_MASTER_ADDR: ADDR <= bus_in;
`TWI_MASTER_DATA:
begin
if(~|CTRLC[`TWI_MASTER_CMD_gp + 1:`TWI_MASTER_CMD_gp])
begin
DATA <= bus_in;
tx_mode <= 1'b1;
STATUS[`TWI_MASTER_WIF_bp] <= 1'b0;
end
end
endcase
end
if(rd_int)
begin
case(addr[3:0])
`TWI_MASTER_DATA:
begin
STATUS[`TWI_MASTER_RIF_bp] <= 1'b0;
end
endcase
end
end
end
PULLUP PULLUP_scl_inst (
.O(scl) // 1-bit output: Pullup output (connect directly to top-level port)
);
PULLUP PULLUP_sda_inst (
.O(sda) // 1-bit output: Pullup output (connect directly to top-level port)
);
assign scl = scl_int ? 1'bz : scl_int;
assign sda = sda_int ? 1'bz : sda_int;
endmodule
/*
* This is the simulation file for TWI IP.
*
* Copyright (C) 2018 Iulian Gheorghiu
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
`timescale 1ns / 1ps
`include "io_s_h.v"
module sim_i2c(
output reg rst,
output reg clk,
output reg [15:0]addr,
output reg wr,
output reg rd,
output [7:0]bus_in,
output reg [7:0]bus_out,
output int_tx_cmpl,
output int_rx_cmpl,
output int_tx_rst,
output int_rx_rst,
inout scl,
inout sda
);
always #(1) clk <= ~clk; // clocking device
initial
begin
rst = 0;
clk = 1;
wr = 0;
rd = 0;
#2;
rst = 1;
#2;
rst = 0;
#4;
addr = `TWI_MASTER_BAUD;
bus_out = 'h1;
wr = 1;
#2;
addr = `TWI_MASTER_CTRLA;
bus_out = `TWI_MASTER_ENABLE_bm;
#2;
addr = `TWI_MASTER_DATA;
bus_out = 8'h55;
#2;
wr = 0;
bus_out = 'hz;
rd = 1;
addr = `TWI_MASTER_STATUS;
#2;
while(~bus_in[`TWI_MASTER_WIF_bp]) #2;
rd = 0;
#2;
wr = 1;
addr = `TWI_MASTER_DATA;
bus_out = 8'hAA;
#2;
wr = 0;
bus_out = 'hz;
rd = 1;
addr = `TWI_MASTER_STATUS;
#2;
while(~bus_in[`TWI_MASTER_WIF_bp]) #2;
rd = 0;
#2;
addr = `TWI_MASTER_CTRLC;
bus_out = `TWI_MASTER_CMD_REPSTART_gc;
#2;
wr = 1;
addr = `TWI_MASTER_CTRLC;
bus_out = `TWI_MASTER_CMD_RECVTRANS_gc;
#2;
wr = 0;
bus_out = 'hz;
rd = 1;
addr = `TWI_MASTER_STATUS;
#2;
while(~bus_in[`TWI_MASTER_RIF_bp]) #2;
addr = `TWI_MASTER_DATA;
#2;
rd = 0;
#2;
wr = 1;
addr = `TWI_MASTER_CTRLC;
bus_out = `TWI_MASTER_ACKACT_bm | `TWI_MASTER_CMD_RECVTRANS_gc;
#2;
wr = 0;
bus_out = 'hz;
rd = 1;
addr = `TWI_MASTER_STATUS;
#2;
while(~bus_in[`TWI_MASTER_RIF_bp]) #2;
addr = `TWI_MASTER_DATA;
#2;
rd = 0;
#2;
wr = 1;
addr = `TWI_MASTER_CTRLC;
bus_out = `TWI_MASTER_CMD_STOP_gc;
#2;
wr = 0;
bus_out = 'hz;
#10;
$finish;
end
twi_s #(
.DINAMIC_BAUDRATE("TRUE"),
.BAUDRATE_DIVIDER(19200),
.ADDRESS(0),
.BUS_ADDR_DATA_LEN(16)
)twi_inst(
.rst(rst),
.clk(clk),
.addr(addr),
.wr(wr),
.rd(rd),
.bus_in(bus_out),
.bus_out(bus_in),
.int_tx_cmpl(int_tx_cmpl),
.int_rx_cmpl(int_rx_cmpl),
.int_tx_rst(int_tx_rst),
.int_rx_rst(int_rx_rst),
.scl(scl),
.sda(sda)
);
endmodule
......@@ -37,10 +37,10 @@
`define DDR3_ADDR_BUS_LEN 15
module sim_uc(
`DDR3_TOP
//`DDR3_TOP
);
`DDR3_IO
//`DDR3_IO
reg rst = 0;
......@@ -115,6 +115,27 @@ wire int_uart_a_tx_buff_empty;
wire int_spi_a;
wire [10:0]int_rst;
initial begin
rst = 0;
#1;
rst = 1;
#1;
rst = 0;
//port_out = 8'haa;
#110000;
int1 = 1;
//int2 = 1;
//int3 = 1;
#20;
int1 = 0;
int2 = 0;
int3 = 0;
#1200000;
$finish;
end
rtc_s # (
.ADDRESS('h40),
.BUS_ADDR_DATA_LEN(`BUS_ADDR_DATA_LEN_SIM),
......@@ -254,6 +275,30 @@ spi_s #(
.ss()/* SPI 'ss' signal (if send buffer is maintained full the ss signal will not go high between between transmit chars)(output) */
);
wire ja_scl;
wire ja_sda;
twi_s #(
.DINAMIC_BAUDRATE("TRUE"),
.BAUDRATE_DIVIDER(255),
.ADDRESS('h800),
.BUS_ADDR_DATA_LEN(`BUS_ADDR_DATA_LEN_SIM)
)twi_inst(
.rst(sys_rst),
.clk(core_clk),
.addr(data_addr),
.wr(data_we),
.rd(data_re),
.bus_in(data_out),
.bus_out(data_in),
.int_tx_cmpl(),
.int_rx_cmpl(),
.int_tx_rst(),
.int_rx_rst(),
.scl(ja_scl),
.sda(ja_sda)
);
wire lcd_h_int;
wire lcd_v_int;
wire lcd_de;
......@@ -347,26 +392,6 @@ hdmi_out # (
`endif
initial begin
rst = 0;
#1;
rst = 1;
#1;
rst = 0;
//port_out = 8'haa;
#110000;
int1 = 1;
//int2 = 1;
//int3 = 1;
#20;
int1 = 0;
int2 = 0;
int3 = 0;
#1200000;
$finish;
end
rom #(
.ADDR_ROM_BUS_WIDTH(`BUS_ADDR_PGM_LEN_SIM),
.ROM_PATH("core1ROM.mem"),
......@@ -425,6 +450,7 @@ mega_core #(
.wdt_rst_out()
);
endmodule
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment