搜索
bottom↓
回复: 0

【正点原子FPGA连载】 第十三章IP核之FIFO实验--摘自【正点原子】领航者 ZYNQ 之FPGA开发指南

[复制链接]

出0入234汤圆

发表于 2020-9-19 10:24:12 | 显示全部楼层 |阅读模式
1)实验平台:正点原子领航者ZYNQ开发板
2)购买链接:https://item.taobao.com/item.htm?id=606160108761
3)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boards/fpga/zdyz_linhanz.html
4) 正点原子官方B站:https://space.bilibili.com/394620890
5)对正点原子FPGA感兴趣的同学可以加群讨论:876744900 点击加入:
QQ群头像.png                                                                   
6)关注正点原子公众号,获取最新资料

100846rel79a9p4uelap24.jpg

100846f1ce1fg14zbg0va4.png

第十三章IP核之FIFO实验



FIFO的英文全称是First In First Out,即先进先出。FPGA使用的FIFO一般指的是对数据的存储具有先进先出特性的一个缓存器,常被用于数据的缓存,或者高速异步数据的交互也即所谓的跨时钟域信号传递。它与FPGA内部的RAM和ROM的区别是没有外部读写地址线,采取顺序写入数据,顺序读出数据的方式,使用起来简单方便,由此带来的缺点就是不能像RAM和ROM那样可以由地址线决定读取或写入某个指定的地址。本章我们将对Vivado软件生成的FIFO IP核进行读写测试,来向大家介绍Xilinx FIFO IP核的使用方法。
本章包括以下几个部分:
1313.1FIFO IP核简介
13.2实验任务
13.3硬件设计
13.4程序设计
13.5下载验证


13.1FIFO IP核简介
根据FIFO工作的时钟域,可以将FIFO分为同步FIFO和异步FIFO。同步FIFO是指读时钟和写时钟为同一个时钟,在时钟沿来临时同时发生读写操作。异步FIFO是指读写时钟不一致,读写时钟是互相独立的。Xilinx的FIFO IP核可以被配置为同步FIFO或异步FIFO,其信号框图如下图所示。从图中可以了解到,当被配置为同步FIFO时,只使用wr_clk,所有的输入输出信号都同步于wr_clk信号。而当被配置为异步FIFO时,写端口和读端口分别有独立的时钟,所有与写相关的信号都是同步于写时钟wr_clk,所有与读相关的信号都是同步于读时钟rd_clk。
阿莫论坛发帖领航者专用2615.png

图 13.1.1 Xilinx的FIFO IP核的信号框图

对于FIFO需要了解一些常见参数:
FIFO的宽度:FIFO一次读写操作的数据位N;
FIFO的深度:FIFO可以存储多少个宽度为N位的数据。
空标志:empty。FIFO已空时由FIFO的状态电路送出的一个信号,以阻止FIFO的读操作继续从FIFO中读出数据而造成无效数据的读出。
满标志:full。FIFO已满或将要写满时由FIFO的状态电路送出的一个信号,以阻止FIFO的写操作继续向FIFO中写数据而造成溢出。
读时钟:读FIFO时所遵循的时钟,在每个时钟的上升沿触发。
写时钟:写FIFO时所遵循的时钟,在每个时钟的上升沿触发。
对于FIFO的基本知识先了解这些就足够了,可能有人会好奇为什么会有同步FIFO和异步FIFO,它们各自的用途是什么。之所以有同步FIFO和异步FIFO是因为各自的作用不同。同步FIFO常用于同步时钟的数据缓存,异步FIFO常用于跨时钟域的数据信号的传递,例如时钟域A下的数据data1传递给异步时钟域B,当data1为连续变化信号时,如果直接传递给时钟域B则可能会导致收非所送的情况,即在采集过程中会出现包括亚稳态问题在内的一系列问题,使用异步FIFO能够将不同时钟域中的数据同步到所需的时钟域中。
13.2实验任务
本节实验任务是使用Vivado生成FIFO IP核,并实现以下功能:当FIFO为空时就开始向FIFO中写入数据,直到FIFO被写满为止;当FIFO为满时则开始从FIFO中读出数据,直到FIFO被读空为止,以此向大家详细介绍一下FIFO IP核的使用方法。
13.3硬件设计
本章实验只用到了输入的时钟信号和按键复位信号,没有用到其它硬件外设。
本实验中,各端口信号的管脚分配如下表所示。
表 13.3.1 IP实验管脚分配
1331.png

对应的XDC约束语句如下所示:
  1. create_clock -period 20.000 -name clk [get_ports sys_clk]
  2. set_property -dict {PACKAGE_PIN U18 IOSTANDARD LVCMOS33} [get_ports sys_clk]
  3. set_property -dict {PACKAGE_PIN J15 IOSTANDARD LVCMOS33} [get_ports sys_rst_n]
复制代码

13.4程序设计
根据实验任务要求和模块化设计的思想,我们需要如下4个模块:fifo IP核、写fifo模块、读fifo模块以及顶层例化模块实现前三个模块的信号交互。由于FIFO多用于跨时钟域信号的处理,所以本实验我们使用异步FIFO来向大家详细介绍双时钟FIFO IP核的创建和使用。为了方便大家理解,这里我们将读/写时钟都用系统时钟来驱动。系统的功能框图如下图所示:
阿莫论坛发帖领航者专用21977.png

图 13.4.1 系统框图

首先创建一个名为ip_fifo的工程,接下来我们创建fifo IP核。在Vivado软件的左侧“Flow Navigator”栏中单击“IP Catalog”,“IP Catalog”按钮以及单击后弹出的“IP Catalog”窗口如下图所示。
阿莫论坛发帖领航者专用22159.png

图 13.4.2 “IP Catalog”按钮

阿莫论坛发帖领航者专用22203.png

图 13.4.3 “IP Catalog”窗口

在“IP Catalog”窗口中,在搜索栏中输入“fifo”关键字,这时Vivado会自动查找出与关键字匹配的IP核名称,我们双击“FIFO Generator”,如下图所示。
阿莫论坛发帖领航者专用22336.png

图 13.4.4 搜索栏中输入关键字

弹出“Customize IP”窗口,如下图所示。
阿莫论坛发帖领航者专用22401.png

图 13.4.5 “Customize IP”窗口

接下来就是配置IP核的时钟参数的过程。
最上面的“Component Name”一栏设置该IP元件的名称,这里保持默认即可。在第一个“Basic”选项卡中,“Interface Type”选项用于选择FIFO接口的类型,这里我们选择默认的“Native”,即传统意义上的FIFO接口。“Fifo Implementation”选项用于选择我们想要实现的是同步FIFO还是异步FIFO以及使用哪种资源实现FIFO,这里我们选择“Independent Clocks Block RAM”,即使用块RAM来实现的异步FIFO。如下图所示。
阿莫论坛发帖领航者专用22715.png

图 13.4.6 “Basic”选项卡

接下来是“Native Ports”选项卡,用于设置FIFO端口的参数。“Read Mode”选项用于设置读FIFO时的读模式,这里我们选择默认的“Standard FIFO”。“Data Port Parameters”一栏用于设置读写端口的数据总线的宽度以及FIFO的深度,写宽度“Write Width”我们设置为8位,写深度“Write Depth”我们设置为256,注意此时FIFO IP核所能实现的实际深度却是255;虽然读宽度“Read Width”能够设置成和写宽度不一样的位宽,且此时读深度“Read Depth”会根据上面三个参数被动地自动设置成相应的值;但是我们还是将读宽度“Read Width”设置成和写宽度“Write Width”一样的位宽,这也是在实际应用中最常用的情况。由于我们只是观察FIFO的读写,所以最下面的“Reset Pin”选项我们可以不使用,把它取消勾选。其他设置保持默认即可,如下图所示。
阿莫论坛发帖领航者专用23175.png

图 13.4.7 “Native Ports”选项卡

“Status Flags”选项卡,用于设置其他的边带信号,这里我们并不使用它们,保持默认即可,如下图所示。
阿莫论坛发帖领航者专用23277.png

图 13.4.8 “Status Flags”选项卡

“Data Counts”选项卡用于设置FIFO内数据计数的输出信号,此信号表示当前在FIFO内存在多少个有效数据。为了更加方便地观察读/写过程,这里我们把读/写端口的数据计数都打开,且计数值总线的位宽设置为满位宽,即8位,如下图所示。
阿莫论坛发帖领航者专用23443.png

图 13.4.9 “Data Counts”选项卡

最后的“Summary”选项卡是对前面所有配置的一个总结,在这里我们直接点击“OK”按钮即可,如下图所示。
阿莫论坛发帖领航者专用23543.png

图 13.4.10 “Summary”选项卡

接着就弹出了“Genarate Output Products”窗口,我们直接点击“Generate”即可,如下图所示。
阿莫论坛发帖领航者专用23647.png

图 13.4.11 “Genarate Output Products”窗口

之后我们就可以在“Design Run”窗口的“Out-of-Context Module Runs”一栏中出现了该IP核对应的run“fifo_generator_0_synth_1”,其综合过程独立于顶层设计的综合,所以在我们可以看到其正在综合,如下图所示。
阿莫论坛发帖领航者专用23838.png

图 13.4.12 “fifo_generator _0_synth_1”run

在其Out-of-Context综合的过程中,我们就可以进行RTL编码了。首先打开IP核的例化模板,在“Source”窗口中的“IP Sources”选项卡中,依次用鼠标单击展开“IP”-“fifo_generator _0”-“Instantitation Template”,我们可以看到“fifo_generator_0.veo”文件,它是由IP核自动生成的只读的verilog例化模板文件,双击就可以打开它,如下图所示。
阿莫论坛发帖领航者专用24114.png

图 13.4.13 “fifo_generator_0.veo”文件

我们创建一个verilog源文件,其名称为ip_fifo.v,作为顶层模块,其代码如下:
  1. 1   module ip_fifo(
  2. 2       input    sys_clk ,  // 时钟信号
  3. 3       input    sys_rst_n  // 复位信号
  4. 4   );
  5. 5   
  6. 6   //wire define
  7. 7   wire          fifo_wr_en ;         // FIFO写使能信号
  8. 8   wire          fifo_rd_en ;         // FIFO读使能信号
  9. 9   wire   [7:0]  fifo_din ;           // 写入到FIFO的数据
  10. 10  wire   [7:0]  fifo_dout ;          // 从FIFO读出的数据
  11. 11  wire          fifo_full ;          // FIFO满信号
  12. 12  wire          fifo_empty ;         // FIFO空信号
  13. 13  wire   [7:0]  fifo_wr_data_count ; // FIFO写时钟域的数据计数
  14. 14  wire   [7:0]  fifo_rd_data_count ; // FIFO读时钟域的数据计数
  15. 15  
  16. 16  //*****************************************************
  17. 17  //**                    main code
  18. 18  //*****************************************************
  19. 19  
  20. 20  //例化FIFO IP核
  21. 21  fifo_generator_0  fifo_generator_0 (
  22. 22      .wr_clk         ( sys_clk             ),   // input wire wr_clk
  23. 23      .rd_clk         ( sys_clk             ),   // input wire rd_clk
  24. 24  
  25. 25      .wr_en          ( fifo_wr_en          ),  // input wire wr_en
  26. 26      .rd_en          ( fifo_rd_en          ),  // input wire rd_en
  27. 27  
  28. 28      .din            ( fifo_din            ),   // input wire [7 : 0] din
  29. 29      .dout           ( fifo_dout           ),  // output wire [7 : 0] dout
  30. 30  
  31. 31      .full           ( fifo_full           ),  // output wire full
  32. 32      .empty          ( fifo_empty          ),  // output wire empty
  33. 33  
  34. 34      .wr_data_count  ( fifo_wr_data_count  ),  // output wire [7 : 0] wr_data_count   
  35. 35      .rd_data_count  ( fifo_rd_data_count  )   // output wire [7 : 0] rd_data_count
  36. 36  );
  37. 37  
  38. 38  //例化写FIFO模块
  39. 39  fifo_wr  u_fifo_wr(
  40. 40      .clk           ( sys_clk    ),  // 写时钟
  41. 41      .rst_n         ( sys_rst_n  ),  // 复位信号
  42. 42  
  43. 43      .fifo_wr_en    ( fifo_wr_en ),  // fifo写请求
  44. 44      .fifo_wr_data  ( fifo_din   ),  // 写入FIFO的数据
  45. 45      .fifo_empty    ( fifo_empty ),  // fifo空信号
  46. 46      .fifo_full     ( fifo_full  )   // fifo满信号
  47. 47  );
  48. 48  
  49. 49  //例化读FIFO模块
  50. 50  fifo_rd  u_fifo_rd(
  51. 51      .clk        ( sys_clk    ),  // 读时钟
  52. 52      .rst_n      ( sys_rst_n  ),  // 复位信号
  53. 53  
  54. 54      .fifo_rd_en ( fifo_rd_en ),  // fifo读请求
  55. 55      .fifo_dout  ( fifo_dout  ),  // 从FIFO输出的数据
  56. 56      .fifo_empty ( fifo_empty ),  // fifo空信号
  57. 57      .fifo_full  ( fifo_full  )   // fifo满信号
  58. 58  );
  59. 59  
  60. 60  //例化ILA IP核
  61. 61  ila_0  ila_0 (
  62. 62      .clk    ( sys_clk            ), // input wire clk
  63. 63  
  64. 64      .probe0 ( fifo_wr_en         ), // input wire [0:0]  probe0  
  65. 65      .probe1 ( fifo_rd_en         ), // input wire [0:0]  probe1
  66. 66      .probe2 ( fifo_din           ), // input wire [7:0]  probe2
  67. 67      .probe3 ( fifo_dout          ), // input wire [7:0]  probe3
  68. 68      .probe4 ( fifo_full          ), // input wire [0:0]  probe4
  69. 69      .probe5 ( fifo_empty         ), // input wire [0:0]  probe5
  70. 70      .probe6 ( fifo_wr_data_count ), // input wire [7:0]  probe6
  71. 71      .probe7 ( fifo_rd_data_count )  // input wire [7:0]  probe7
  72. 72  );
  73. 73  
  74. 74  endmodule
复制代码

顶层模块主要是对FIFO IP核、写FIFO模块、读FIFO模块进行例化,除此之外本实验还生成并例化了一个ILA IP核,用于对顶层模块信号的进行在线捕获观察。
写FIFO模块fifo_wr.v源文件的代码如下:
  1. 1   module fifo_wr(
  2. 2       //mudule clock
  3. 3       input                  clk ,            // 时钟信号
  4. 4       input                  rst_n ,          // 复位信号
  5. 5       //FIFO interface      
  6. 6       input                  fifo_empty ,     // FIFO空信号
  7. 7       input                  fifo_full ,      // FIFO满信号
  8. 8       output    reg          fifo_wr_en ,     // FIFO写使能
  9. 9       output    reg  [7:0]   fifo_wr_data     // 写入FIFO的数据
  10. 10  );
  11. 11  
  12. 12  //reg define
  13. 13  reg  [1:0]  state ;           //动作状态
  14. 14  reg         fifo_empty_d0  ;  //fifo_empty 延迟一拍
  15. 15  reg         fifo_empty_syn ;  //fifo_empty 延迟两拍
  16. 16  reg  [3:0]  dly_cnt ;         //延迟计数器
  17. 17  //*****************************************************
  18. 18  //**                    main code
  19. 19  //*****************************************************
  20. 20  
  21. 21  //因为 fifo_empty 信号是属于FIFO读时钟域的
  22. 22  //所以要将其同步到写时钟域中
  23. 23  always@( posedge clk ) begin
  24. 24      if( !rst_n ) begin
  25. 25          fifo_empty_d0  <= 1'b0 ;
  26. 26          fifo_empty_syn <= 1'b0 ;
  27. 27      end
  28. 28      else begin
  29. 29          fifo_empty_d0  <= fifo_empty ;
  30. 30          fifo_empty_syn <= fifo_empty_d0 ;
  31. 31      end
  32. 32  end
  33. 33  
  34. 34  //向FIFO中写入数据
  35. 35  always @(posedge clk ) begin
  36. 36      if(!rst_n) begin
  37. 37          fifo_wr_en   <= 1'b0;
  38. 38          fifo_wr_data <= 8'd0;
  39. 39          state        <= 2'd0;
  40. 40          dly_cnt      <= 4'd0;
  41. 41      end
  42. 42      else begin
  43. 43          case(state)
  44. 44              2'd0: begin
  45. 45                  if(fifo_empty_syn) begin  //如果检测到FIFO被读空
  46. 46                      state <= 2'd1;        //就进入延时状态
  47. 47                  end
  48. 48                  else
  49. 49                      state <= state;
  50. 50              end
  51. 51              2'd1: begin
  52. 52                  if(dly_cnt == 4'd10) begin  //延时10拍
  53. 53                                              //原因是FIFO IP核内部状态信号的更新存在延时
  54. 54                                              //延迟10拍以等待状态信号更新完毕                  
  55. 55                      dly_cnt    <= 4'd0;
  56. 56                      state      <= 2'd2;     //开始写操作
  57. 57                      fifo_wr_en <= 1'b1;     //打开写使能
  58. 58                  end
  59. 59                  else
  60. 60                      dly_cnt <= dly_cnt + 4'd1;
  61. 61              end            
  62. 62              2'd2: begin
  63. 63                  if(fifo_full) begin         //等待FIFO被写满
  64. 64                      fifo_wr_en   <= 1'b0;   //关闭写使能
  65. 65                      fifo_wr_data <= 8'd0;
  66. 66                      state        <= 2'd0;   //回到第一个状态
  67. 67                  end
  68. 68                  else begin                   //如果FIFO没有被写满
  69. 69                      fifo_wr_en   <= 1'b1;    //则持续打开写使能
  70. 70                      fifo_wr_data <= fifo_wr_data + 1'd1;  //且写数据值持续累加
  71. 71                  end
  72. 72              end
  73. 73              default : state <= 2'd0;
  74. 74          endcase
  75. 75      end
  76. 76  end
  77. 77  
  78. 78  endmodule
复制代码

fifo_wr模块的核心部分是一个不断进行状态循环的小状态机,如果检测到FIFO为空,则先延时10拍,这里注意,由于FIFO的边带信号的更新比实际的数据读/写操作有所延时,所以延时10拍的目的是等待FIFO的空/满状态信号、数据计数信号等边带信号的更新完毕之后再进行FIFO写操作,如果写满,则回到状态0,即等待FIFO被读空,以进行下一轮的写操作。
读FIFO模块fifo_rd.v源文件的代码如下:
  1. 1   module fifo_rd(
  2. 2       //system clock
  3. 3       input                clk ,        // 时钟信号
  4. 4       input                rst_n ,      // 复位信号
  5. 5       //FIFO interface
  6. 6       input        [7:0]   fifo_dout ,  // 从FIFO读出的数据
  7. 7       input                fifo_full ,  // FIFO满信号
  8. 8       input                fifo_empty , // FIFO空信号
  9. 9       output  reg          fifo_rd_en   // FIFO读使能
  10. 10  );
  11. 11  
  12. 12  //reg define
  13. 13  reg  [1:0]   state ;          // 动作状态
  14. 14  reg          fifo_full_d0 ;   // fifo_full 延迟一拍
  15. 15  reg          fifo_full_syn ;  // fifo_full 延迟两拍
  16. 16  reg  [3:0]   dly_cnt ;        //延迟计数器
  17. 17  
  18. 18  //*****************************************************
  19. 19  //**                    main code
  20. 20  //*****************************************************
  21. 21  
  22. 22  //因为 fifo_full 信号是属于FIFO写时钟域的
  23. 23  //所以要将其同步到读时钟域中
  24. 24  always@( posedge clk ) begin
  25. 25      if( !rst_n ) begin
  26. 26          fifo_full_d0  <= 1'b0 ;
  27. 27          fifo_full_syn <= 1'b0 ;
  28. 28      end
  29. 29      else begin
  30. 30          fifo_full_d0  <= fifo_full ;
  31. 31          fifo_full_syn <= fifo_full_d0 ;
  32. 32      end
  33. 33  end
  34. 34  
  35. 35  //读出FIFO的数据
  36. 36  always @(posedge clk ) begin
  37. 37      if(!rst_n) begin
  38. 38          fifo_rd_en <= 1'b0;
  39. 39          state      <= 2'd0;
  40. 40          dly_cnt    <= 4'd0;
  41. 41      end
  42. 42      else begin
  43. 43          case(state)
  44. 44              2'd0: begin
  45. 45                  if(fifo_full_syn)           //如果检测到FIFO被写满
  46. 46                      state <= 2'd1;          //就进入延时状态
  47. 47                  else
  48. 48                      state <= state;
  49. 49              end
  50. 50              2'd1: begin
  51. 51                  if(dly_cnt == 4'd10) begin  //延时10拍
  52. 52                                              //原因是FIFO IP核内部状态信号的更新存在延时
  53. 53                                              //延迟10拍以等待状态信号更新完毕
  54. 54                      dly_cnt <= 4'd0;
  55. 55                      state   <= 2'd2;        //开始读操作
  56. 56                  end
  57. 57                  else
  58. 58                      dly_cnt <= dly_cnt + 4'd1;
  59. 59              end
  60. 60              2'd2: begin
  61. 61                  if(fifo_empty) begin        //等待FIFO被读空
  62. 62                      fifo_rd_en <= 1'b0;     //关闭读使能
  63. 63                      state      <= 2'd0;     //回到第一个状态
  64. 64                  end
  65. 65                  else                        //如果FIFO没有被读空
  66. 66                      fifo_rd_en <= 1'b1;     //则持续打开读使能
  67. 67              end
  68. 68              default : state <= 2'd0;
  69. 69          endcase
  70. 70      end
  71. 71  end
  72. 72  
  73. 73  endmodule
复制代码

读模块的代码结构与写模块几乎一样,也是使用一个不断进行状态循环的小的状态机来控制操作过程,读者参考着代码应该很容易能够理解,这里就不再赘述。
我们对代码进行仿真,TestBench中只要送出时钟的复位信号即可。写满后转为读的仿真波形图如下图所示:
阿莫论坛发帖领航者专用212860.png

图 13.4.14 Vivado仿真波形1

由波形图可知,当写满255个数据后,fifo_full满信号就会拉高。经过延时之后,fifo_rd_en写使能信号拉高,经过一拍之后就开始将fifo中的数据送到fifo_dout端口上。
写满后转为读的仿真波形图如下图所示:
阿莫论坛发帖领航者专用213017.png

图 13.4.15 Vivado仿真波形2

由波形图可知,当读完255个数据后,fifo_empty空信号就会拉高。经过延时之后,fifo_wr_en写使能信号拉高,经过一拍之后就开始向fifo中继续写入数据。
13.5下载验证
编译工程并生成比特流.bit文件,将比特流.bit文件下载到Zynq中。
接下来在Vivado中会自动出现“hw_ila_1”Dashboard窗口,如下图所示:
阿莫论坛发帖领航者专用213231.png

图 13.5.1 “hw_ila_1”Dashboard窗口

将有关探针信号添加到波形窗口中,并将“fifo_rd_en”信号添加到触发窗口中且设置为上升沿触发,如下图所示:
阿莫论坛发帖领航者专用213339.png

图 13.5.2 将探针信号添加到波形窗口中

单击左上角的触发按钮,如下图所示:
阿莫论坛发帖领航者专用213400.png

图 13.5.3 触发按钮

最后就看到了ILA捕获得到的数据,展开波形图如下图所示:
阿莫论坛发帖领航者专用213463.png

图 13.5.4 捕获得到的波形图

从捕获得到的波形图中可以看出,其逻辑行为与仿真波形图中的一致,证明我们的代码正确地实现了预期的功能。

阿莫论坛20周年了!感谢大家的支持与爱护!!

你熬了10碗粥,别人一桶水倒进去,淘走90碗,剩下10碗给你,你看似没亏,其实你那10碗已经没有之前的裹腹了,人家的一桶水换90碗,继续卖。说白了,通货膨胀就是,你的钱是挣来的,他的钱是印来的,掺和在一起,你的钱就贬值了。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-10-2 21:16

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表