• FPGA实现AXI4总线的读写_如何写axi4逻辑


    FPGA实现AXI4总线的读写_如何写axi4逻辑

    一、AXI4 接口描述

    通道

    信号

    信号描述

    全局信号

    aclk

    主机

    全局时钟

    aresetn

    主机

    全局复位,低有效

    写通道地址与控制信号通道

    M_AXI_WR_awid[3:0]

    主机

    写地址ID,用来标志一组写信号

    M_AXI_WR_awaddr[31:0]

    主机

    写地址,给出一次写突发传输的写地址

    M_AXI_WR_awlen[7:0]

    主机

    突发长度,给出突发传输的次数

    M_AXI_WR_awsize[2:0]

    主机

    突发大小,给出每次突发传输的字节数

    M_AXI_WR_awburst[1:0]

    主机

    突发类型

    M_AXI_WR_awlock

    主机

    总线锁信号,可提供操作的原子性

    M_AXI_WR_awcache[3:0]

    主机

    内存类型,表明一次传输是怎样通过系统的

    M_AXI_WR_awprot[2:0]

    主机

    保护类型,表明一次传输的特权级及安全等级

    M_AXI_WR_awqos[3:0]

    主机

    质量服务QoS

    M_AXI_WR_awvalid

    主机

    有效信号,表明此通道的地址控制信号有效

    M_AXI_WR_awready

    从机

    表明“从”可以接收地址和对应的控制信号

    写通道数据通道

    M_AXI_WR_wdata[63:0]

    主机

    写数据

    M_AXI_WR_wstrb[7:0]

    主机

    写数据有效的字节线,用来表明哪8bits数据是有效的

    M_AXI_WR_wlast

    主机

    表明此次传输是最后一个突发传输

    M_AXI_WR_wvalid

    主机

    写有效,表明此次写有效

    M_AXI_WR_wready

    从机

    表明从机可以接收写数据

    写通道响应通道

    M_AXI_WR_bid[3:0]

    从机

    写响应ID TAG

    M_AXI_WR_bresp[1:0]

    从机

    写响应,表明写传输的状态

    M_AXI_WR_bvalid

    从机

    写响应有效

    M_AXI_WR_bready

    主机

    表明主机能够接收写响应

    读通道地址与控制信号通道

    M_AXI_RD_arid[3:0]

    主机

    读地址ID,用来标志一组写信号

    M_AXI_RD_araddr[31:0]

    主机

    读地址,给出一次写突发传输的读地址

    M_AXI_RD_arlen[7:0]

    主机

    突发长度,给出突发传输的次数

    M_AXI_RD_arsize[2:0]

    主机

    突发大小,给出每次突发传输的字节数

    M_AXI_RD_arburst[1:0]

    主机

    突发类型

    M_AXI_RD_arlock[1:0]

    主机

    总线锁信号,可提供操作的原子性

    M_AXI_RD_arcache[3:0]

    主机

    内存类型,表明一次传输是怎样通过系统的

    M_AXI_RD_arprot[2:0]

    主机

    保护类型,表明一次传输的特权级及安全等级

    M_AXI_RD_arqos[3:0]

    主机

    质量服务QOS

    M_AXI_RD_arvalid

    主机

    有效信号,表明此通道的地址控制信号有效

    M_AXI_RD_arready

    从机

    表明“从”可以接收地址和对应的控制信号

    读通道数据通道

    M_AXI_RD_rid[3:0]

    从机

    读IDtag

    M_AXI_RD_rdata[63:0]

    从机

    读数据

    M_AXI_RD_rresp[1:0]

    从机

    读响应,表明读传输的状态

    M_AXI_RD_rlast

    从机

    表明读突发的最后一次传输

    M_AXI_RD_rvalid

    从机

    表明此通道信号有效

    M_AXI_RD_rready

    主机

    表明主机能够接收读数据和响应信息

    二、地址通道的控制信号与地址描述

    1、地址ID

    AWID[3:0]与ARID[3:0]:对于只有一个主机从机设备,该值可设置为任意

    2、地址结构

    AWADDR[31:0]与ARADDR[31:0]:AXI协议是基于burst(突发)的,主机只给出突发传输的第一个字节的地址,从机必须计算突发传输后续的地址。突发传输不能跨4KB边界(防止突发跨越两个从机的边界,也限制了从机所需支持的地址自增数

    3、突发长度

    AWLEN[7:0]与ARLEN[7:0]:ARLEN[7:0]决定读传输的突发长度,AWLEN[7:0]决定写传输的突发长度。AXI4扩展突发长度支持INCR突发类型为1256次传输,对于其他的传输类型依然保持116次突发传输(Burst_Length=AxLEN[7:0]+1)

    4、突发大小

    ARSIZE[2:0],读突发传输;AWSIZE[2:0],写突发传输。

    AxSIZE[2:0]

    传输字节大小

    3'b000

    1

    3'b001

    2

    3'b010

    4

    3'b011

    8

    3'b100

    16

    3'b101

    32

    3'b110

    64

    3'b111

    128

    5、突发类型

    AWBURST[1:0]与ARBURST[1:0]:

    AxBURST[1:0]

    突发类型

    2'b00

    FIXED

    2'b01

    INCR

    2'b10

    WRAP

    2'b11

    Reserved

    FIXED:突发传输过程中地址固定,用于FIFO访问

    INCR:增量突发,传输过程中,地址递增。增加量取决AxSIZE的值

    WRAP:回环突发,和增量突发类似,但会在特定高地址的边界处回到低地址处。回环突发的长度只能是2,4,8,16次传输,传输首地址和每次传输的大小对齐。最低的地址整个传输的数据大小对齐。回环边界等于(AxSIZE*AxLEN)

    三、数据通道信号描述

    1、WDATA与RDATA:写与读数据线信号

    WSTRB:有效字节,WSTRB[n:0]对应于对应的写字节,WSTRB[n]对应WDATA[8n+7:8n],也就是对于的数据宽度的字节数是否有效。WVALID为低时,WSTRB可以为任意值,WVALID为高时,WSTRB为高的字节线必须指示有效的数据。对于一般应用,将WSTRB全部置1即可,保证全部数据有效。读通道无该信号。

    2、WLAST与RLAST

    写与读最后一个字节,拉高表示传输最后一个字节,也意味着传输结束

    3、burst[1:0]

    描述读写相应结构

    burst[1:0]

    00

    常规访问成功

    01

    独占访问成功

    10

    从机错误

    11

    解码错误

    四、突发写时序:

    AXI4突发写可以分为7个状态,写空闲,写通道写地址等待,写通道写地址,写数据等待,写数据循环,接受写应答,写结束这7种状态。之所以划分为7个状态是为了后续写程序的状态机做准备。

    7种状态

    1、写空闲:等待触发突发信号

    2、写通道写地址等待:准备好写地址AWADDR,然后拉高AWVALID。

    3、写通道写地址:从机接受到AWVALID,发出AWREADY。

    4、写数据等待:准备好数据WDATA,拉高WVALID。

    5、写数据循环:从机接受WVALID,确认数据WDATA有效并且接受,发出WREADY,AXI是突发传输:循环该操作到接受到WLAST最后一个数据标志位。

    6、接受写应答:接受到从机发出的BVALID,主机发出BREADY。

    7、写结束:拉低未拉低的信号,进入写空闲

    五、突发读时序

    AXI4突发读可以分为6个状态,读空闲,读通道写地址等待,读通道写地址,读数据等待,读数据循环,读结束这6种状态。之所以划分为6个状态是为了后续写程序的状态机做准备。

    6种状态

    1、读空闲:等待触发突发信号。

    2、读通道写地址等待:准备好写地址ARADDR,然后拉高ARVALID。

    3、读通道写地址:从机接受到ARVALID,发出ARREADY。

    4、读数据等待:从机准备好数据WDATA,从机拉高RVALID。

    5、读数据循环:主机接受RVALID,确认数据RDATA有效并且接受,发出RREADY给从机,AXI是突发传输:循环该操作到接受到RLAST最后一个数据标志位

    6、读结束:拉低未拉低的信号,进入读空闲

    注:

    1、读数据必须总是跟在与其数据相关联的地址之后。

    2、写响应必须总是跟在与其相关联的写事务的最后出现。

    六、写时序状态机

    七、写时序代码

    module axi4_write(
        input               clk             ,
        input               resetn          ,
        input               enable_write    ,  //写使能
        input  [31:0]       w_addr          ,  //地址
        input  [63:0]       w_data          ,  //数据
        output reg          write_done      ,  //写完成
        output reg          write_data      ,  //表示数据写入,突发模式下可用于切换数据的指示信号
        //axi4写通道地址通道
        output  [3:0]       m_axi_awid      , //写地址ID,用来标志一组写信号
        output reg[31:0]    m_axi_awaddr    ,//写地址,给出一次写突发传输的写地址 
        output [7:0]        m_axi_awlen     , //突发长度,给出突发传输的次数 
        output [2:0]        m_axi_awsize    , //突发大小,给出每次突发传输的字节数 
        output [1:0]        m_axi_awburst   , //突发类型 
        output              m_axi_awlock    , //总线锁信号,可提供操作的原子性 
        output [3:0]        m_axi_awcache   , //内存类型,表明一次传输是怎样通过系统的
        output [2:0]        m_axi_awprot    , //保护类型,表明一次传输的特权级及安全等级 
        output [3:0]        m_axi_awqos     , //质量服务QoS
        output reg          m_axi_awvalid   , //有效信号,表明此通道的地址控制信号有效 
        input               m_axi_awready   , //表明“从”可以接收地址和对应的控制信号
        //axi4写通道数据通道
        output reg[63:0]    m_axi_wdata     , //写数据 
        output [7:0]        m_axi_wstrb     , //写数据有效的字节线 
        output reg          m_axi_wlast     , //表明此次传输是最后一个突发传输
        output reg          m_axi_wvalid    , //写有效,表明此次写有效
        input               m_axi_wready    , //表明从机可以接收写数据 
        //axi4写通道应答通道 
        input [3:0]         m_axi_bid       , //写响应ID TAG
        input [1:0]         m_axi_bresp     , //写响应,表明写传输的状态
        input               m_axi_bvalid    , //写响应有效
        output reg          m_axi_bready      //表明主机能够接收写响应
        );
    
    //*******************参数*****************************
        localparam  W_IDLEW     = 3'b001    ; //空闲等待
        localparam  W_DRIVEW    = 3'b011    ; //准备、取地址
        localparam  W_HANDS     = 3'b010    ; //握手
        localparam  W_WSTBR     = 3'b110    ; //突发
        localparam  W_WAIT      = 3'b111    ; //等待结束的信息
        localparam  W_END       = 3'b101    ; //写数据阶段
    
        parameter   LEN_NUM     = 1         ;
        parameter   AWID        = 0         ;
    //*********内部信号******************************
        reg  [2:0]  state ,   next_state   ;
        reg         wready_over            ;
        reg  [7:0]  len                    ;
    
        assign  m_axi_awid    = AWID[3:0] ;    // [3:0]  //写地址ID,用来标志一组写信号  
        assign  m_axi_awlen   = LEN_NUM-1 ;    // [7:0]  //突发长度,给出突发传输的次数  
        assign  m_axi_awsize  = 3'b011    ;    // [2:0]  //突发大小,给出每次突发传输的字节数  
        assign  m_axi_awburst = 2'b10     ;    // [1:0]  //突发类型  
        assign  m_axi_awlock  = 1'b0      ;    //        //总线锁信号,可提供操作的原子性  
        assign  m_axi_awcache = 4'b0010   ;    // [3:0]  //内存类型,表明一次传输是怎样通过系统的 
        assign  m_axi_awprot  = 3'b000    ;    // [2:0]  //保护类型,表明一次传输的特权级及安全等级 
        assign  m_axi_awqos   = 4'b0000   ;    // [3:0]  //质量服务QoS 
        assign  m_axi_wstrb   = 8'hff     ;
    
    //状态机
        always @(*) begin
            state   =   next_state    ;
        end    
    
    
        always @(posedge clk or negedge resetn) begin
            if(!resetn) begin
                wready_over<=0;
            end
            else if(state==W_IDLEW || state==W_END )
                wready_over<=0;
            else if(m_axi_wready)
                wready_over<=1;
        end
       
        always @(posedge clk or negedge resetn) begin
            if(!resetn) begin
                next_state  <=  W_IDLEW   ;
                len <=0 ;
            end
            else case(state)
                    W_IDLEW :   if(enable_write) next_state <= W_DRIVEW  ;  else next_state<=W_IDLEW    ;
                    W_DRIVEW:   if(m_axi_awready) begin
                                    next_state <= W_HANDS ; 
                                    len<=LEN_NUM-1          ; 
                                end 
                                else next_state<=W_DRIVEW   ;
                    W_HANDS :   if(wready_over && len==0)
                                    next_state <= W_WAIT ;  
                                else   if(wready_over ) next_state <= W_WSTBR   ;
                                else next_state<=W_HANDS  ;
                    W_WSTBR :   if(len==1)       next_state <= W_WAIT ;  
                                else begin 
                                    next_state <= W_WSTBR ;
                                    len <=len-1           ;
                                end
                    W_WAIT  :   next_state<=W_END ;  
                    W_END   :   if(m_axi_bvalid)next_state <= W_IDLEW  ;  else next_state<=W_END    ;
                    default :   next_state<=W_IDLEW ;
            endcase   
        end
      // 组合逻辑输出
        always @(* ) begin
            case(state)
                W_IDLEW :   begin
                                m_axi_wlast    =   0        ;
                                m_axi_awaddr   =   0        ;
                                m_axi_awvalid  =   0        ;
                                m_axi_wdata    =   0        ;
                                m_axi_wvalid   =   0        ;
                                m_axi_bready   =   0        ;
                                write_done     =   0        ;
                                write_data     =   0        ;
                        end
                W_DRIVEW:   begin
                                m_axi_wlast    =   0       ;
                                m_axi_awaddr   =   w_addr  ;
                                m_axi_awvalid  =   1       ;
                                m_axi_wdata    =   0       ;
                                m_axi_wvalid   =   0       ;
                                m_axi_bready   =   0       ;
                                write_done     =   0       ;
                                write_data     =   0       ;
                        end
                W_HANDS :   begin
                                m_axi_wlast    =   0       ;
                                m_axi_awaddr   =   0       ;
                                m_axi_awvalid  =   0       ;
                                m_axi_wdata    =   0       ;
                                m_axi_wvalid   =   0       ;
                                m_axi_bready   =   0       ;
                                write_done     =   0       ;
                                write_data     =   0       ;
                        end
                W_WSTBR :   begin
                                m_axi_wlast    =   0       ;
                                m_axi_awaddr   =   0       ;
                                m_axi_awvalid  =   0       ;
                                m_axi_wdata    =   w_data  ;
                                m_axi_wvalid   =   1       ;
                                m_axi_bready   =   0       ;
                                write_done     =   0       ;
                                write_data     =   1       ;
                        end
                W_WAIT  :   begin
                                m_axi_wlast    =   1       ;
                                m_axi_awaddr   =   0       ;
                                m_axi_awvalid  =   0       ;
                                m_axi_wdata    =   w_data  ;
                                m_axi_wvalid   =   1       ;
                                m_axi_bready   =   0       ;
                                write_done     =   1       ;
                                write_data     =   1       ;
                        end
               
                W_END   :   begin
                                m_axi_wlast    =   0       ;
                                m_axi_awaddr   =   0       ;
                                m_axi_awvalid  =   0       ;
                                m_axi_wdata    =   0       ;
                                m_axi_wvalid   =   0       ;
                                m_axi_bready   =   1       ;
                                write_done     =   0       ;
                                write_data     =   0       ;
                        end
                default :   begin
                                m_axi_wlast    =   0   ;
                                m_axi_awaddr   =   0   ;
                                m_axi_awvalid  =   0   ;
                                m_axi_wdata    =   0   ;
                                m_axi_wvalid   =   0   ;
                                m_axi_bready   =   0   ;
                                write_done     =   0   ;
                                write_data     =   0   ;
                        end
            endcase
        end
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177

    八、读时序状态机

    九、读时序代码

    module axi4_read(
        input               resetn          ,//axi复位 
        input               clk             ,  //axi时钟 
        input               enable_read     ,
        output              read_data       ,
        output              read_done       ,
        input       [31:0]  r_addr          ,
        output  reg [63:0]  r_data          ,
        //axi读通道写地址 
         output     [3:0]   m_axi_arid      , //读地址ID,用来标志一组写信号
         output reg [31:0]  m_axi_araddr    , //读地址,给出一次写突发传输的读地址
         output     [7:0]   m_axi_arlen     , //突发长度,给出突发传输的次数
         output     [2:0]   m_axi_arsize    , //突发大小,给出每次突发传输的字节数
         output     [1:0]   m_axi_arburst   , //突发类型
         output     [1:0]   m_axi_arlock    , //总线锁信号,可提供操作的原子性
         output     [3:0]   m_axi_arcache   , //内存类型,表明一次传输是怎样通过系统的 
         output     [2:0]   m_axi_arprot    , //保护类型,表明一次传输的特权级及安全等级
         output     [3:0]   m_axi_arqos     , //质量服务QOS 
         output reg         m_axi_arvalid   , //有效信号,表明此通道的地址控制信号有效 
         input              m_axi_arready   , //表明“从”可以接收地址和对应的控制信号
         //axi读通道读数据 
         input      [3:0]   m_axi_rid       , //读ID tag 
         input      [63:0]  m_axi_rdata     , //读数据 
         input      [1:0]   m_axi_rresp     , //读响应,表明读传输的状态
         input              m_axi_rlast     , //表明读突发的最后一次传输
         input              m_axi_rvalid    , //表明此通道信号有效 
         output reg         m_axi_rready      //表明主机能够接收读数据和响应信息
        
        );
    //
        localparam [2:0] R_IDLER      =  3'b001   ;
        localparam [2:0] R_WAIT       =  3'b011   ;
        localparam [2:0] R_BURST      =  3'b010   ;
        localparam [2:0] R_END        =  3'b110   ;
    
        parameter  ARID   = 0    ;
        parameter  RD_LEN = 1    ;
    //
        reg [2:0] state , next_state    ;
        reg          rvalid_over    ;
    //    
        assign m_axi_arid      = ARID[3:0]      ;//地址id 
        assign m_axi_arlen     = RD_LEN-32'd1   ;//突发长度
        assign m_axi_arsize    = 3'b011         ;//表示AXI总线每个数据宽度是8字节,64位 
        assign m_axi_arburst   = 2'b01          ;//地址递增方式传输
        assign m_axi_arlock    = 1'b0           ;
        assign m_axi_arcache   = 4'b0010        ; 
        assign m_axi_arprot    = 3'b000         ;
        assign m_axi_arqos     = 4'b0000        ;
    
        assign read_data       =  m_axi_rvalid  ;
        assign read_done       = m_axi_rlast    ;
    //axi读状态机
        always @(*) begin
            state   =   next_state  ;
        end
        //
        always @(posedge clk  or negedge resetn) begin
            if(!resetn) begin
                rvalid_over <=0  ;
            end 
            else if(state==R_IDLER) begin
                rvalid_over <=0  ;
            end
            else if(m_axi_rvalid)begin
                rvalid_over <= 1 ;
            end
        end
    
        always @(posedge clk or negedge resetn) begin
            if(!resetn)
                next_state <= R_IDLER;
            else    case(state)
                        R_IDLER  :  if(enable_read) next_state <= R_WAIT ;else next_state<=R_IDLER   ; 
                        R_WAIT   :  if(m_axi_arready) next_state<=R_BURST  ;else next_state<=R_WAIT  ;  
                        R_BURST  :  if(m_axi_rlast)  next_state<=R_END    ;else next_state  <=  R_BURST ;
                        R_END    :  if(rvalid_over) next_state<=R_IDLER;else next_state<=R_END ;  
                        default  :  next_state<=R_IDLER ;
            endcase
        end
        //
        always @(*) begin
            case(state)
                R_IDLER  :  begin
                                m_axi_araddr  = 0       ;  
                                m_axi_arvalid = 0       ;  
                                m_axi_rready  = 0       ;  
                                r_data        = 0       ;  
                            end 
                R_WAIT   :  begin
                                m_axi_araddr  = r_addr      ;  
                                m_axi_arvalid = 1           ;  
                                m_axi_rready  = 0           ;  
                                r_data        = 0           ;    
                            end             
                R_BURST  :  begin
                                m_axi_araddr  = 0           ;  
                                m_axi_arvalid = 0           ;  
                                m_axi_rready  = 1           ;  
                                r_data        = m_axi_rdata ;      
                            end   
                R_END    :  begin
                                m_axi_araddr  = 0           ;  
                                m_axi_arvalid = 0           ;  
                                m_axi_rready  = 1           ;  
                                r_data        = 0           ;     
                            end 
                default  :  begin
                                m_axi_araddr  = 0           ;  
                                m_axi_arvalid = 0           ;  
                                m_axi_rready  = 0           ;  
                                r_data        = 0           ;     
                            end 
            endcase
        end
    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
  • 相关阅读:
    1978-2021年全国各省有效灌溉面积数据
    山东省专精特新|山东省“专精特新”条件|专业申报认定补贴
    30万以上的qps高并发服务如何优化
    Mac修改Mysql8.0密码
    Linux进阶-用户管理与文件权限
    微服务治理之道:构建可伸缩和高可用的系统
    33K Star?这才是程序员需要的神器。。。
    酷开科技生态内容价值+酷开系统的开放性和可塑性,实现品效合一
    vite基础概述+搭建vue项目基础框架+Vant组件库
    高校房产管理现状及数图互通解决方案?
  • 原文地址:https://blog.csdn.net/m0_59161987/article/details/138187371