ZYNQ之路--制作AXI4 接口IP的思路
这篇ZYNQ之路给大家带来使用AXI总线读写DDR的介绍,此篇博客的意义在于:
- AXI总线基础学习
- PL-PS交互学习
- 创建带有AXI总线接口的IP核
- 理解AXI总线IP的移植
PL与PS交互方式
上面的图片展示了PS与PL通过接口进行交互的方式,当然除此之外PS和PL还可以通过中断等方式进行一个交互。
AXI总线
概述
AXI的全称叫做“ Advanced eXtensible Interface”即高级可扩展接口,该协议是ARM公司提出的AMBA(Advanced Microcontroller Bus Architecture)3.0协议中最重要的部分,是一种面向高性能、高带宽、低延迟的片内总线。
很容易理解这个总线的重要作用:Soc上各个子模块之间要进行通信,既然是通信那么总得有一个规范和标准,AMBA就是为了这样一个目的而提出的(不要问为啥是由ARM公司提出的,问就是因为ZYNQ使用的是ARM的内核)
最新的AMBA(AXI4)标准
AMBA属于不断在发展的一个架构,从前常用的诸如APB,AHB之类的总线标准,但是近些年来都统一称为AXI标准了,目前最新的AMBA标准应该是AXI4,具体包含的总线/接口请看下面的图片:
总结,AXI协议支持以下三种接口:
- AXI-Full:即高性能存储映射接口。
- AXI-Lite:简化版的 AXI4 接口,用于较少数据量的存储映射通信,例如对模块进行配置。
- AXI-Stream:用于高速数据流传输,非存储映射接口,例如视频音频流传输(不能直接与PS端通信)。
存储映射(Meamory Map):如果一个协议是存储映射的,那么主机 所发出的会话(无论读或写)就会标明一个地址。这个地址对应于系统存储空间中的一个地址,表明是针对 该存储空间的读写操作。
协议细节
首先我们来看一下AXI4总线的组成:
AXI4总线共有五个通道:
- 读地址
- 读数据
- 写地址
- 写数据
- 写应答
每个通道的基本拓扑如下:
包含了:时钟信号(上升沿有效)、数据信号,握手信号(VALID和READY)
AXI协议的特色或者说核心就在于:握手信号。
- VALID信号由数据发送方发出,指示数据有效,因此一旦VALID为高电平,那么数据线上的数据就不能再改变。
- READY信号由数据接收方发出,指示可以进行数据接收,因此READY信号只能在VALID有效之后拉高;当VALID和READY信号都有效时数据传输完成。
之后我们再来看看五条通道的功能分配:
五条通道互相独立,并且各自都遵循握手信号协议
有关突发传输
所谓的突发传输就是只要给定一个起始地址,一次性写入多组数据。在ZYNQ的AXI协议当中,AXI-Full协议支持最高256组数据的突发传输,而AXI-Lite一次只能传输一组数据,AXI-Stream则可以无限制地进行突发传输。
关于突发传输的控制问题,例如突发写时主要使用WLAST信号线进行指示突发传输是否完成,最后一组数据写入完成后WLAST信号拉高(最下面三组是应答信号,由从机发出)。
创建AXI接口的IP核
Vivado可以使用向导创建带有AXI接口的IP模块,点击Tool里的Create and Package New IP即可打开向导。
向导上说:这个导航将被用来完成下面的任务:
- 打包一个新的IP(该导航将会指引你使用源文件或者你当前工程的文件等创建一个新的Vivado IP)
- 创建一个新的AXI4外设(该导航将会指引你创建一个新的带有AXI4接口的外设,包括HDL,驱动,软件应用等等设计)
我们选择创建一个AXI4的外设:
下面是简单地配置AXI接口的相关信息: 我们主要目的是制作一个AXI接口的IP,因此我们选择编辑这个IP:
下面是我们的重头戏来了:
各位看官请移步Sources栏目,我们可以看到工程里自动多了一个顶层模块和一个实例模块,这是什么意思呢?
这是Xilinx官方给的一个AXI接口的示例,我们设计AXI接口的IP核,如果是主接口,那么我们要有一套操控AXI接口,符合AXI时序的硬件;如果是从接口,那么我们要有能响应AXI接口请求的的一套硬件。
从理论上来说,这些东西都是要咱们自己写的。我们原本应该仔细研读AXI接口中各个信号的时序关系,然后使用状态机让我们的功能IP能够与AXI的从机通信,或者响应主机请求。但是Xilinx官方在创建AXI接口IP的时候提供给了我们一个例子,让我们可以在这个例子的基础上进行改造。这就是向导的力量!
顶层代码(从机)
`timescale 1 ns / 1 psmodule myip11_v1_0 #(// Users to add parameters here// User parameters ends// Do not modify the parameters beyond this line// Parameters of Axi Slave Bus Interface S00_AXIparameter integer C_S00_AXI_DATA_WIDTH = 32,parameter integer C_S00_AXI_ADDR_WIDTH = 4)(// Users to add ports here// User ports ends// Do not modify the ports beyond this line// Ports of Axi Slave Bus Interface S00_AXIinput wire s00_axi_aclk,input wire s00_axi_aresetn,input wire [C_S00_AXI_ADDR_WIDTH-1 : 0] s00_axi_awaddr,input wire [2 : 0] s00_axi_awprot,input wire s00_axi_awvalid,output wire s00_axi_awready,input wire [C_S00_AXI_DATA_WIDTH-1 : 0] s00_axi_wdata,input wire [(C_S00_AXI_DATA_WIDTH/8)-1 : 0] s00_axi_wstrb,input wire s00_axi_wvalid,output wire s00_axi_wready,output wire [1 : 0] s00_axi_bresp,output wire s00_axi_bvalid,input wire s00_axi_bready,input wire [C_S00_AXI_ADDR_WIDTH-1 : 0] s00_axi_araddr,input wire [2 : 0] s00_axi_arprot,input wire s00_axi_arvalid,output wire s00_axi_arready,output wire [C_S00_AXI_DATA_WIDTH-1 : 0] s00_axi_rdata,output wire [1 : 0] s00_axi_rresp,output wire s00_axi_rvalid,input wire s00_axi_rready);
// Instantiation of Axi Bus Interface S00_AXImyip11_v1_0_S00_AXI # ( .C_S_AXI_DATA_WIDTH(C_S00_AXI_DATA_WIDTH),.C_S_AXI_ADDR_WIDTH(C_S00_AXI_ADDR_WIDTH)) myip11_v1_0_S00_AXI_inst (.S_AXI_ACLK(s00_axi_aclk),.S_AXI_ARESETN(s00_axi_aresetn),.S_AXI_AWADDR(s00_axi_awaddr),.S_AXI_AWPROT(s00_axi_awprot),.S_AXI_AWVALID(s00_axi_awvalid),.S_AXI_AWREADY(s00_axi_awready),.S_AXI_WDATA(s00_axi_wdata),.S_AXI_WSTRB(s00_axi_wstrb),.S_AXI_WVALID(s00_axi_wvalid),.S_AXI_WREADY(s00_axi_wready),.S_AXI_BRESP(s00_axi_bresp),.S_AXI_BVALID(s00_axi_bvalid),.S_AXI_BREADY(s00_axi_bready),.S_AXI_ARADDR(s00_axi_araddr),.S_AXI_ARPROT(s00_axi_arprot),.S_AXI_ARVALID(s00_axi_arvalid),.S_AXI_ARREADY(s00_axi_arready),.S_AXI_RDATA(s00_axi_rdata),.S_AXI_RRESP(s00_axi_rresp),.S_AXI_RVALID(s00_axi_rvalid),.S_AXI_RREADY(s00_axi_rready));// Add user logic here// User logic endsendmodule
实例代码
`timescale 1 ns / 1 psmodule myip11_v1_0_S00_AXI #(// Users to add parameters here// User parameters ends// Do not modify the parameters beyond this line// Width of S_AXI data busparameter integer C_S_AXI_DATA_WIDTH = 32,// Width of S_AXI address busparameter integer C_S_AXI_ADDR_WIDTH = 4)(// Users to add ports here// User ports ends// Do not modify the ports beyond this line// Global Clock Signalinput wire S_AXI_ACLK,// Global Reset Signal. This Signal is Active LOWinput wire S_AXI_ARESETN,// Write address (issued by master, acceped by Slave)input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_AWADDR,// Write channel Protection type. This signal indicates the// privilege and security level of the transaction, and whether// the transaction is a data access or an instruction access.input wire [2 : 0] S_AXI_AWPROT,// Write address valid. This signal indicates that the master signaling// valid write address and control information.input wire S_AXI_AWVALID,// Write address ready. This signal indicates that the slave is ready// to accept an address and associated control signals.output wire S_AXI_AWREADY,// Write data (issued by master, acceped by Slave) input wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_WDATA,// Write strobes. This signal indicates which byte lanes hold// valid data. There is one write strobe bit for each eight// bits of the write data bus. input wire [(C_S_AXI_DATA_WIDTH/8)-1 : 0] S_AXI_WSTRB,// Write valid. This signal indicates that valid write// data and strobes are available.input wire S_AXI_WVALID,// Write ready. This signal indicates that the slave// can accept the write data.output wire S_AXI_WREADY,// Write response. This signal indicates the status// of the write transaction.output wire [1 : 0] S_AXI_BRESP,// Write response valid. This signal indicates that the channel// is signaling a valid write response.output wire S_AXI_BVALID,// Response ready. This signal indicates that the master// can accept a write response.input wire S_AXI_BREADY,// Read address (issued by master, acceped by Slave)input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_ARADDR,// Protection type. This signal indicates the privilege// and security level of the transaction, and whether the// transaction is a data access or an instruction access.input wire [2 : 0] S_AXI_ARPROT,// Read address valid. This signal indicates that the channel// is signaling valid read address and control information.input wire S_AXI_ARVALID,// Read address ready. This signal indicates that the slave is// ready to accept an address and associated control signals.output wire S_AXI_ARREADY,// Read data (issued by slave)output wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_RDATA,// Read response. This signal indicates the status of the// read transfer.output wire [1 : 0] S_AXI_RRESP,// Read valid. This signal indicates that the channel is// signaling the required read data.output wire S_AXI_RVALID,// Read ready. This signal indicates that the master can// accept the read data and response information.input wire S_AXI_RREADY);// AXI4LITE signalsreg [C_S_AXI_ADDR_WIDTH-1 : 0] axi_awaddr;reg axi_awready;reg axi_wready;reg [1 : 0] axi_bresp;reg axi_bvalid;reg [C_S_AXI_ADDR_WIDTH-1 : 0] axi_araddr;reg axi_arready;reg [C_S_AXI_DATA_WIDTH-1 : 0] axi_rdata;reg [1 : 0] axi_rresp;reg axi_rvalid;// Example-specific design signals// local parameter for addressing 32 bit / 64 bit C_S_AXI_DATA_WIDTH// ADDR_LSB is used for addressing 32/64 bit registers/memories// ADDR_LSB = 2 for 32 bits (n downto 2)// ADDR_LSB = 3 for 64 bits (n downto 3)localparam integer ADDR_LSB = (C_S_AXI_DATA_WIDTH/32) + 1;localparam integer OPT_MEM_ADDR_BITS = 1;//----------------------------------------------//-- Signals for user logic register space example//------------------------------------------------//-- Number of Slave Registers 4reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg0;reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg1;reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg2;reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg3;wire slv_reg_rden;wire slv_reg_wren;reg [C_S_AXI_DATA_WIDTH-1:0] reg_data_out;integer byte_index;reg aw_en;// I/O Connections assignmentsassign S_AXI_AWREADY = axi_awready;assign S_AXI_WREADY = axi_wready;assign S_AXI_BRESP = axi_bresp;assign S_AXI_BVALID = axi_bvalid;assign S_AXI_ARREADY = axi_arready;assign S_AXI_RDATA = axi_rdata;assign S_AXI_RRESP = axi_rresp;assign S_AXI_RVALID = axi_rvalid;// Implement axi_awready generation// axi_awready is asserted for one S_AXI_ACLK clock cycle when both// S_AXI_AWVALID and S_AXI_WVALID are asserted. axi_awready is// de-asserted when reset is low.always @( posedge S_AXI_ACLK )beginif ( S_AXI_ARESETN == 1'b0 )beginaxi_awready <= 1'b0;aw_en <= 1'b1;end elsebegin if (~axi_awready && S_AXI_AWVALID && S_AXI_WVALID && aw_en)begin// slave is ready to accept write address when // there is a valid write address and write data// on the write address and data bus. This design // expects no outstanding transactions. axi_awready <= 1'b1;aw_en <= 1'b0;endelse if (S_AXI_BREADY && axi_bvalid)beginaw_en <= 1'b1;axi_awready <= 1'b0;endelse beginaxi_awready <= 1'b0;endend end // Implement axi_awaddr latching// This process is used to latch the address when both // S_AXI_AWVALID and S_AXI_WVALID are valid. always @( posedge S_AXI_ACLK )beginif ( S_AXI_ARESETN == 1'b0 )beginaxi_awaddr <= 0;end elsebegin if (~axi_awready && S_AXI_AWVALID && S_AXI_WVALID && aw_en)begin// Write Address latching axi_awaddr <= S_AXI_AWADDR;endend end // Implement axi_wready generation// axi_wready is asserted for one S_AXI_ACLK clock cycle when both// S_AXI_AWVALID and S_AXI_WVALID are asserted. axi_wready is // de-asserted when reset is low. always @( posedge S_AXI_ACLK )beginif ( S_AXI_ARESETN == 1'b0 )beginaxi_wready <= 1'b0;end elsebegin if (~axi_wready && S_AXI_WVALID && S_AXI_AWVALID && aw_en )begin// slave is ready to accept write data when // there is a valid write address and write data// on the write address and data bus. This design // expects no outstanding transactions. axi_wready <= 1'b1;endelsebeginaxi_wready <= 1'b0;endend end // Implement memory mapped register select and write logic generation// The write data is accepted and written to memory mapped registers when// axi_awready, S_AXI_WVALID, axi_wready and S_AXI_WVALID are asserted. Write strobes are used to// select byte enables of slave registers while writing.// These registers are cleared when reset (active low) is applied.// Slave register write enable is asserted when valid address and data are available// and the slave is ready to accept the write address and write data.assign slv_reg_wren = axi_wready && S_AXI_WVALID && axi_awready && S_AXI_AWVALID;always @( posedge S_AXI_ACLK )beginif ( S_AXI_ARESETN == 1'b0 )beginslv_reg0 <= 0;slv_reg1 <= 0;slv_reg2 <= 0;slv_reg3 <= 0;end else beginif (slv_reg_wren)begincase ( axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] )2'h0:for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )if ( S_AXI_WSTRB[byte_index] == 1 ) begin// Respective byte enables are asserted as per write strobes // Slave register 0slv_reg0[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];end 2'h1:for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )if ( S_AXI_WSTRB[byte_index] == 1 ) begin// Respective byte enables are asserted as per write strobes // Slave register 1slv_reg1[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];end 2'h2:for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )if ( S_AXI_WSTRB[byte_index] == 1 ) begin// Respective byte enables are asserted as per write strobes // Slave register 2slv_reg2[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];end 2'h3:for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )if ( S_AXI_WSTRB[byte_index] == 1 ) begin// Respective byte enables are asserted as per write strobes // Slave register 3slv_reg3[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];end default : beginslv_reg0 <= slv_reg0;slv_reg1 <= slv_reg1;slv_reg2 <= slv_reg2;slv_reg3 <= slv_reg3;endendcaseendendend // Implement write response logic generation// The write response and response valid signals are asserted by the slave // when axi_wready, S_AXI_WVALID, axi_wready and S_AXI_WVALID are asserted. // This marks the acceptance of address and indicates the status of // write transaction.always @( posedge S_AXI_ACLK )beginif ( S_AXI_ARESETN == 1'b0 )beginaxi_bvalid <= 0;axi_bresp <= 2'b0;end elsebegin if (axi_awready && S_AXI_AWVALID && ~axi_bvalid && axi_wready && S_AXI_WVALID)begin// indicates a valid write response is availableaxi_bvalid <= 1'b1;axi_bresp <= 2'b0; // 'OKAY' response end // work error responses in futureelsebeginif (S_AXI_BREADY && axi_bvalid) //check if bready is asserted while bvalid is high) //(there is a possibility that bready is always asserted high) beginaxi_bvalid <= 1'b0; end endendend // Implement axi_arready generation// axi_arready is asserted for one S_AXI_ACLK clock cycle when// S_AXI_ARVALID is asserted. axi_awready is // de-asserted when reset (active low) is asserted. // The read address is also latched when S_AXI_ARVALID is // asserted. axi_araddr is reset to zero on reset assertion.always @( posedge S_AXI_ACLK )beginif ( S_AXI_ARESETN == 1'b0 )beginaxi_arready <= 1'b0;axi_araddr <= 32'b0;end elsebegin if (~axi_arready && S_AXI_ARVALID)begin// indicates that the slave has acceped the valid read addressaxi_arready <= 1'b1;// Read address latchingaxi_araddr <= S_AXI_ARADDR;endelsebeginaxi_arready <= 1'b0;endend end // Implement axi_arvalid generation// axi_rvalid is asserted for one S_AXI_ACLK clock cycle when both // S_AXI_ARVALID and axi_arready are asserted. The slave registers // data are available on the axi_rdata bus at this instance. The // assertion of axi_rvalid marks the validity of read data on the // bus and axi_rresp indicates the status of read transaction.axi_rvalid // is deasserted on reset (active low). axi_rresp and axi_rdata are // cleared to zero on reset (active low). always @( posedge S_AXI_ACLK )beginif ( S_AXI_ARESETN == 1'b0 )beginaxi_rvalid <= 0;axi_rresp <= 0;end elsebegin if (axi_arready && S_AXI_ARVALID && ~axi_rvalid)begin// Valid read data is available at the read data busaxi_rvalid <= 1'b1;axi_rresp <= 2'b0; // 'OKAY' responseend else if (axi_rvalid && S_AXI_RREADY)begin// Read data is accepted by the masteraxi_rvalid <= 1'b0;end endend // Implement memory mapped register select and read logic generation// Slave register read enable is asserted when valid address is available// and the slave is ready to accept the read address.assign slv_reg_rden = axi_arready & S_AXI_ARVALID & ~axi_rvalid;always @(*)begin// Address decoding for reading registerscase ( axi_araddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] )2'h0 : reg_data_out <= slv_reg0;2'h1 : reg_data_out <= slv_reg1;2'h2 : reg_data_out <= slv_reg2;2'h3 : reg_data_out <= slv_reg3;default : reg_data_out <= 0;endcaseend// Output register or memory read dataalways @( posedge S_AXI_ACLK )beginif ( S_AXI_ARESETN == 1'b0 )beginaxi_rdata <= 0;end elsebegin // When there is a valid read address (S_AXI_ARVALID) with // acceptance of read address by the slave (axi_arready), // output the read dada if (slv_reg_rden)beginaxi_rdata <= reg_data_out; // register read dataend endend // Add user logic here// User logic endsendmodule
从机的代码改造相对主机更加简单,但是想要真正学会AXI协议的IP制作,研读示例代码是必须要去做的事情。
从机代码改造的逻辑在于寄存器:
如图,主机会往这些寄存器里写入数据,那么这些寄存器就可以直接和我们功能模块的端口进行对接,以实现参数传递的功能。
主机写数据--->接口实例--->寄存器-->自定义功能模块 (数据流向)
下一节,我想做一期 AXI-Master示例的代码解读。
ZYNQ之路--制作AXI4 接口IP的思路相关推荐
- 带你快速入门AXI4总线--AXI4-Full篇(3)----XILINX AXI4-Full接口IP源码仿真分析(Master接口)
写在前面 接slave接口篇,本文继续打包一个AXI4-Full-Master接口的IP,学习下源码,再仿真看看波形. 带你快速入门AXI4总线--AXI4-Full篇(2)----XILINX AX ...
- ZYNQ进阶之路13--自定义AXI-FULL IP实现PS和PL双向高速通讯
ZYNQ进阶之路13--自定义AXI-FULL IP实现PS和PL双向高速通讯 导语 实现步骤 结语 导语 不好意思,这篇博文又来晚了,是繁忙阻碍了博主博客的更新,其实博主想要有好多关于技术的话要说, ...
- 基于ZYNQ的AXI4接口通讯
目录 一.简介 1.1 AXI的三种形式 1.2 存储映射 1.3 AXI小结 二.AXI的突发传输 2.1 存储模式 2.2 突发长度 2.3 突发传输宽度 三.AXI的工作方式 3.1 AXI的通 ...
- ZYNQ中DMA与AXI4总线-DMA简介
ZYNQ中DMA与AXI4总线 为什么在ZYNQ中DMA和AXI联系这么密切?通过上面的介绍我们知道ZYNQ中基本是以AXI总线完成相关功能的: 图4‑34 连接 PS 和 PL 的 AXI 互联和接 ...
- ZYNQ中AXI-Lite,AXI4 和 AXI-Stream 三种总线特点
AXI 全称 Advanced eXtensible Interface,是 Xilinx 从 6 系列的 FPGA 开始引入的一个接口协 议,主要描述了主设备和从设备之间的数据传输方式.在 ZYNQ ...
- ZYNQ开发系列——使用AXI4LITE接口进行PS和PL交互
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 ZYNQ开发系列--使用AXI4LITE接口进行PS和PL交互 前言 PS端AXI接口 AXI4LITE slave模块的设计 后记 ...
- php 设计api,PHP制作API接口
需要单一入口文件,可以使用autoload来加载 //获取get参数 $m = !empty($_GET['m'])?$_GET['m']:'Index'; $a = !empty($_GET['a' ...
- 使用python提取华为交换机的接口IP信息保存到excel中(ensp模拟器)
实验环境: 如图所示,SW1-SW5上分别已经配置了SSH,使用外部PC可以SSH到其中. 在本次实验中,主要使用了如下三个模块: openpyxl,对excel文件进行操作,具体可以参考:https ...
- DDR3 AXI4接口读写回环测试
上篇blog中记录了DDR3提供的ui接口读写回环测试,非常方便的完成了整颗DDR颗粒的读写,官方提供的ui接口,让用户可以像操作普通RAM那样去便捷.高效的完成DDR读写开发. DDR3官方还提供了 ...
最新文章
- bottleneck resnet网络_关于ResNet及其变体的总结(上)
- android 禁用剪切板_Android EditText禁止复制粘贴
- 鲜为人知的C++ IO fstream流
- 用C/C++扩展你的PHP
- OpenGL中的二维编程——从简单的矩形开始
- CompletableFuture详解~supplyAsync
- 队列模拟约瑟夫问题(洛谷P1996题题解,Java语言描述)
- 《Spring攻略(第2版)》——1.5 指定Bean引用
- java乱码问题详解-值得收藏
- lisp把选集转成表_LISP(表处理语言)
- [论文阅读] Multiple Instance Active Learning for Object Detection
- 做游戏,学编程(C语言) 7 学习EasyX图形交互功能----flappy bird源代码
- 三个快速便捷的命令行小贴士
- markdown数学公式
- apl脚本入门-控制语句
- 万年历用c语言写,用C语言如何编写“万年历”
- java 性能框架_Java Fork Join 框架(四)性能
- mpvue学习笔记-之微信数据请求封装
- java httpsession_JavaWeb:HttpSession
- 从历史故事看企业用人-之二--三国之东吴