简述
因为项目只用到了IO cycle,故只对IO Write/Read进行设计
时序
Typical Timing for LFRAME
Extended Timing for LFRAME
Abort Mechanism
正常情况下,START只存在1个clock,EXTEND情况是2个clock(代码里已考虑到)。
按照LDC规范的表述,Abort是在Sync状态发生的,也就是在Data状态之前,此次传输无效,如果发生在Data则按正常传输进行
peripheral代码
点击查看代码
`resetall
`timescale 1ns / 1ns
`default_nettype none
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2025/07/21 08:56:23
// Design Name:
// Module Name: lpc
// Project Name:
// Target Devices:
// Tool Versions:
// Description: limited for I/O read/write
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////`include "apb_lpc_defines.vh"
module lpc_peripheral(// LPCinput wire lclk ,input wire lreset_n ,input wire lframe ,output reg lad_oe ,input wire [3:0] lad_in , output reg [3:0] lad_out ,// User interfaceoutput reg m_apb_lpc_penable , output reg m_apb_lpc_psel ,output reg m_apb_lpc_write , output reg [15:0] m_apb_lpc_paddr ,output wire [ 7:0] m_apb_lpc_wdata ,input wire [ 7:0] m_apb_lpc_rdata ,input wire m_apb_lpc_pready
);/*--------------------------------------------------------------------------------------------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------------------------------------------------------------------------------------------*/reg [13:0] state_reg = `LPC_ST_START, state_next;reg [ 1:0] count_reg = 2'b0, count_next;reg [15:0] lpc_addr = 16'h0, lpc_addr_next;reg [ 7:0] lpc_wdata = 8'h0, lpc_wdata_next;reg [ 7:0] lpc_rdata;reg rw_indicator,rw_indicator_next; // 1 for write, 0 for read
/*--------------------------------------------------------------------------------------------------------------------------------------------------------------*/ always @(*) beginstate_next = state_reg;lpc_addr_next = lpc_addr;lpc_wdata_next = lpc_wdata;rw_indicator_next = rw_indicator;count_next = 2'b0;lad_oe = 4'b0; lad_out = `LPC_STOP;case (state_reg)`LPC_ST_START : beginrw_indicator_next = 1'b0;lpc_wdata_next = 8'h0;lpc_addr_next = 16'h0;if (~lframe) beginstate_next = (lad_in == `LPC_START)? `LPC_ST_CYCTYP:`LPC_ST_START;end else beginstate_next = `LPC_ST_START;endend `LPC_ST_CYCTYP : beginif (~lframe) beginstate_next = `LPC_ST_CYCTYP;end else beginstate_next = `LPC_ST_ADDR;if (lad_in[1]) beginrw_indicator_next = 1'b1;end else beginrw_indicator_next = 1'b0;endend end`LPC_ST_ADDR : begincount_next = count_reg + 1;case (count_reg)0: lpc_addr_next[15:12] = lad_in;1: lpc_addr_next[11: 8] = lad_in;2: lpc_addr_next[ 7: 4] = lad_in;3: lpc_addr_next[ 3: 0] = lad_in;endcaseif (count_reg == 2'h3)state_next = `LPC_ST_H_TAR1;else beginstate_next = `LPC_ST_ADDR;endend`LPC_ST_H_TAR1 : beginstate_next = `LPC_ST_H_TAR2;end`LPC_ST_H_TAR2 : begin // host float LADstate_next = `LPC_ST_SYNC1; end`LPC_ST_SYNC1 : beginlad_oe = 1'b1;lad_out = `LPC_SYNC_SWAIT; if (~lframe) state_next = `LPC_ST_START; else state_next = `LPC_ST_SYNC2; end `LPC_ST_SYNC2 : begin if (~lframe) begin state_next = `LPC_ST_START; end else begin lad_oe = 1'b1;lad_out = `LPC_SYNC_READY; if (rw_indicator) state_next = `LPC_ST_H_DATA;elsestate_next = `LPC_ST_P_DATA;endend `LPC_ST_H_DATA : begincount_next = count_reg + 1;if (count_reg == 0) beginlpc_wdata_next[3:0] = lad_in;end else beginlpc_wdata_next[7:4] = lad_in;state_next = `LPC_ST_P_TAR1;endend`LPC_ST_P_DATA : begincount_next = count_reg + 1;lad_oe = 1'b1;if (count_reg == 0) beginlad_out = lpc_rdata[3:0];end else beginlad_out = lpc_rdata[7:4];state_next = `LPC_ST_P_TAR1;endend `LPC_ST_P_TAR1 : beginlad_oe = 1'b1;lad_out = `LPC_STOP;state_next = `LPC_ST_P_TAR2;end`LPC_ST_P_TAR2 : beginlad_oe = 1'b0; // peripherals float LADstate_next = `LPC_ST_START;end default: state_next = `LPC_ST_START; endcase
end always @(posedge lclk or negedge lreset_n) beginif (~lreset_n) beginstate_reg <= `LPC_ST_START;count_reg <= 2'h0;lpc_addr <= 16'h0; rw_indicator <= 1'b0;lpc_wdata <= 8'h0;end else beginstate_reg <= state_next;count_reg <= count_next;lpc_addr <= lpc_addr_next;lpc_wdata <= lpc_wdata_next;rw_indicator <= rw_indicator_next;end
endwire host_write = m_apb_lpc_penable & m_apb_lpc_psel & m_apb_lpc_write & m_apb_lpc_pready;
wire host_read = m_apb_lpc_penable & m_apb_lpc_psel & (~m_apb_lpc_write) & m_apb_lpc_pready;assign m_apb_lpc_wdata = lpc_wdata;always @(posedge lclk) beginif (~lreset_n) beginm_apb_lpc_penable <= 1'b0;m_apb_lpc_psel <= 1'b0;m_apb_lpc_paddr <= 16'h0;m_apb_lpc_write <= 1'b0;lpc_rdata <= 8'h0; end else beginif (rw_indicator) beginif (state_reg == `LPC_ST_H_DATA) beginm_apb_lpc_psel <= 1'b1;m_apb_lpc_penable <= 1'b0; m_apb_lpc_write <= 1'b1; end else if (state_reg == `LPC_ST_P_TAR1) beginm_apb_lpc_psel <= 1'b1;m_apb_lpc_penable <= 1'b1; m_apb_lpc_write <= 1'b1; end else beginm_apb_lpc_penable <= 1'b0;m_apb_lpc_psel <= 1'b0; m_apb_lpc_write <= 1'b0; end end else beginif (state_reg == `LPC_ST_H_TAR2) beginm_apb_lpc_psel <= 1'b1;m_apb_lpc_penable <= 1'b0; m_apb_lpc_write <= 1'b0; end else if (state_reg == `LPC_ST_SYNC1) beginm_apb_lpc_psel <= 1'b1;m_apb_lpc_penable <= 1'b1; m_apb_lpc_write <= 1'b0; end else beginm_apb_lpc_penable <= 1'b0;m_apb_lpc_psel <= 1'b0; m_apb_lpc_write <= 1'b0; end endm_apb_lpc_paddr <= lpc_addr;if (host_read) beginlpc_rdata <= m_apb_lpc_rdata;endend
endendmodule
`resetall
搭建Host进行仿真
host task代码搭建
点击查看代码
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2025/07/24 16:16:14
// Design Name:
// Module Name: lpc_host
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////module lpc_host(input wire lclk , output reg lframe ,output reg lad_oe ,output reg [3:0] lad_o ,input wire [3:0] lad_i
);/*----------------------------------------------------------------------------------------------------------------------------------------------------------------*/`define LPC_START 4'h0`define LPC_STOP 4'hf`define LPC_SWAIT 4'h5`define LPC_READY 4'h0`define IO_WRITE 4'h2`define IO_READ 4'h0integer index = 0;/*----------------------------------------------------------------------------------------------------------------------------------------------------------------*/task Start;begin@(posedge lclk);lframe = 1'b1;lad_oe = 1'b1;lad_o = `LPC_STOP;@(posedge lclk);lframe = 1'b0; lad_oe = 1'b1;lad_o = `LPC_START; end
endtasktask Start_extend;begin@(posedge lclk);lframe = 1'b1;lad_oe = 1'b1;lad_o = `LPC_STOP;@(posedge lclk);lframe = 1'b0; lad_oe = 1'b1;lad_o = `LPC_START;@(posedge lclk);end
endtasktask Cyctype;input [3:0] dir_type;begin@(posedge lclk);lframe = 1'b1;lad_oe = 1'b1; lad_o = dir_type;end
endtasktask Addr;input [15:0] host_addr;beginwhile(index < 4) begin@(posedge lclk);lad_oe = 1'b1;lad_o = host_addr[(15-index*4)-:4];index = index + 1;endend
endtasktask Tar_h;begin@(posedge lclk);lad_oe = 1'b1;lad_o = 4'b1111;// turn-around@(posedge lclk);lad_oe = 1'b0;lad_o = 4'b1111;end
endtasktask Sync;beginrepeat(2) begin@(posedge lclk);end end
endtasktask Sync_abort;beginrepeat(2) begin@(posedge lclk);endlframe = 1'b0; end
endtasktask Host_write;input [7:0] host_dout;begin@(posedge lclk);lad_oe = 1'b1;lad_o = host_dout[3:0];@(posedge lclk);lad_oe = 1'b1;lad_o = host_dout[7:4]; end
endtasktask Host_read;output [7:0] host_din;begin@(posedge lclk);lad_oe = 1'b0;host_din[3:0] = lad_i;@(posedge lclk);host_din[7:4] = lad_i; end
endtasktask Tar_peripheral;begin@(posedge lclk);lad_oe = 1'b1;lad_o = `LPC_STOP;@(posedge lclk);lad_oe = 1'b0;lad_o = `LPC_STOP;index = 0; end
endtask/*----------------------------------------------------------------------------------------------------------------------------------------------------------------*/
task lpc_host_write(input [15:0] host_addr ,input [ 7:0] host_wdata
);beginStart();Cyctype(`IO_WRITE);Addr(host_addr);Tar_h();Sync();Host_write(host_wdata);Tar_peripheral();end
endtasktask lpc_host_read(input [15:0] host_addr ,output [ 7:0] host_rdata
);beginStart();Cyctype(`IO_READ);Addr(host_addr);Tar_h();Sync();Host_read(host_rdata);Tar_peripheral();end
endtasktask host_ex_write(input [15:0] host_addr ,input [ 7:0] host_wdata
);beginStart_extend();Cyctype(`IO_WRITE);Addr(host_addr);Tar_h();Sync();Host_write(host_wdata);Tar_peripheral();end
endtasktask host_ex_read(input [15:0] host_addr ,output [ 7:0] host_rdata
);beginStart_extend();Cyctype(`IO_READ);Addr(host_addr);Tar_h();Sync();Host_read(host_rdata);Tar_peripheral();end
endtasktask host_write_abort(input [15:0] host_addr ,input [ 7:0] host_wdata
);beginStart();Cyctype(`IO_WRITE);Addr(host_addr);Tar_h();Sync_abort();end
endtasktask host_read_abort(input [15:0] host_addr ,output [ 7:0] host_rdata
);beginStart();Cyctype(`IO_READ);Addr(host_addr);Tar_h();Sync_abort();end
endtaskinitial beginlframe = 1'b1;lad_oe = 1'b1;lad_o = 4'hf;
end endmodule
仿真顶层
点击查看代码
`timescale 1ns / 1ns
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2025/07/24 08:31:32
// Design Name:
// Module Name: tb_lpc
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////module tb_lpc();reg LCLK,LRESET_N;
wire LFRAME; wire [3:0] LAD;wire lad_oe;
wire [3:0] lad_o,lad_i;reg serirq_oe,serirq_o;
wire serirq_i;wire [31:0] IRQ = 32'h1234;
reg [ 7:0] host_di ;always #15 LCLK = ~LCLK;initial beginLCLK = 1'b0;LRESET_N = 1'b0;host_di = 8'h0; #200LRESET_N = 1'b1;
#200host.lpc_host_write(16'h0,8'h0);host.lpc_host_write(16'h1,8'h1);host.lpc_host_write(16'h2,8'h2);host.lpc_host_write(16'h3,8'h3);host.lpc_host_write(16'h4,8'h4);host.lpc_host_write(16'h5,8'h5);host.lpc_host_write(16'h6,8'h6);host.lpc_host_write(16'h7,8'h7);
#200 host.host_ex_read(16'h0,host_di); host.host_ex_read(16'h1,host_di); host.host_ex_read(16'h2,host_di); host.host_ex_read(16'h3,host_di); host.host_ex_read(16'h4,host_di); host.host_ex_read(16'h5,host_di); host.host_ex_read(16'h6,host_di); host.host_ex_read(16'h7,host_di);
#200 host.host_ex_write(16'h0,8'h7);host.host_ex_write(16'h1,8'h6);host.host_ex_write(16'h2,8'h5);host.host_ex_write(16'h3,8'h4);host.host_ex_write(16'h4,8'h3);host.host_ex_write(16'h5,8'h2);host.host_ex_write(16'h6,8'h1);host.host_ex_write(16'h7,8'h0);
#200 host.lpc_host_read(16'h0,host_di);host.lpc_host_read(16'h1,host_di);host.lpc_host_read(16'h2,host_di);host.lpc_host_read(16'h3,host_di);host.lpc_host_read(16'h4,host_di);host.lpc_host_read(16'h5,host_di);host.lpc_host_read(16'h6,host_di);host.lpc_host_read(16'h7,host_di);
#200 host.host_write_abort(16'h3,8'h3);
#200host.host_read_abort(16'h4,host_di);
#2000$stop;
end
/*------------------------------------------------------------------------------------------------------------------------------------------*/
genvar i;
generatefor (i = 0; i < 4; i=i+1) beginpullup(LAD[i]); end
endgeneratepullup(SERIRQ);assign lad_i = LAD;
assign LAD = (lad_oe)? lad_o : 4'bzzzz;super_io_top super_io(.LCLK (LCLK ),.LRESET_N (LRESET_N),.LFRAME (LFRAME ),.LAD (LAD ),.SERIRQ (SERIRQ ),.IRQ (IRQ )
);lpc_host host(.lclk (LCLK ), .lframe (LFRAME ),.lad_oe (lad_oe ),.lad_o (lad_o ),.lad_i (lad_i )
);endmodule
仿真结果
IO write部分波形
IO read部分波形
不知道为啥,读回来的结果高低位是反的,但代码没看出毛病