AXI4-Lite总线读写BRAM

news2024/11/18 9:43:39

博主参考和学习的博客

  1. AXI协议基础知识 。这篇博客比较详细地介绍了AXI总线,并且罗列了所有的通道和端口,写代码的时候可以方便地进行查表。
  2. AXI总线,AXI_BRAM读写仿真测试 。 这篇文章为代码的书写提供大致的思路,比如状态机和时序的控制问题,可以参考。

valid-ready双向握手机制

  1. 双向握手机制的实质是:
    数据接收方R告诉数据发送方T“我准备好接收数据了”,并拉高ready;同样的,数据发送方T告诉数据接收方R“我准备好发送数据了”,并拉高valid。

数据发送方给出valid,数据接收方给出ready

  1. 重点:只有在valid和ready同时拉高时,表面成功握手,数据才得以传输。
    【例】比如下图,当前clk上升沿检测到awvalid和awready都拉高,aw握手成功,此时32位的awaddr地址得以写入bram。
    在这里插入图片描述
    【例】比如下图,当前clk上升沿检测到wvalid和wready都拉高,w握手成功,此时32位的wdata数据得以写入bram。
    在这里插入图片描述

  2. 读写BRAM需要用到四个的AXI通道。每一个通道下都有很多端口,包括常规的数据线和valid-ready线
    ① 写地址通道AW(address write)

//写地址通道AW
reg [31:0]  awaddr;    //in(视角:bram)
reg         awvalid;   //in
wire        awready;   //out

② 写数据通道W(write)

//写数据通道W
reg [31:0]  wdata;     //in
reg         wvalid;    //in
wire        wready;    //out
reg [3:0]   wstrb;     //in

③ 写响应通道B

//写响应通道B
reg         bready;    //in:表示主机准备好接收bram的数据
wire        bvalid;    //out:表示bram可以给master发送数据
wire [1:0]  bresp;     //out

④ 读地址通道AR(address read)

//读地址通道AR
reg [31:0]  araddr;    //in
reg         arvalid;   //in
wire        arready;   //out

⑤ 读数据通道R(read)

//读数据通道R
wire [31:0] rdata;     //out
wire        rvalid;    //out
reg         rready;    //in
wire [1:0]  rresp;     //out

博主画了一张图方便理解和查询:
在这里插入图片描述

这是BRAM的IP核设置界面,可以清晰地看到各个通道。
在这里插入图片描述


突发读和突发写时序


有关AXI进行BRAM读写的细节问题

【主从valid-ready互不干扰】
正常工作情况下valid不等待ready,ready也不等待valid。因为主机和从机的逻辑判断是独立的,都是根据自己的情况拉高valid或者ready,换句话说就是:“主机想发数据就把自己的valid拉高,从机能接收数据就把自己的ready拉高”。正好握上了数据就开始传。

【有一边出现繁忙,才会出现等待握手的情况】
如果现在主机可以发送数据,拉高了valid,但是从机处于繁忙状态不能接收数据,没有拉高ready。这个时候主机valid信号就要等待从机退出繁忙并将ready拉高。


代码详解

我们书写代码,是站在“主机master”的视角,去操控bram的。

我们的程序中关于valid-ready双向握手协议的部分,只需要操纵主机的三个valid信号(awvalid,wvalid,arvalid)和一个ready信号(rready),从机bram的ready不需要我们操心。如果主从握手成功,数据便会成功传输,即对于数据传输的过程只要握手成功便会进行,也不需要我们操心。

  1. 状态机——状态空间:
    由于AXI读写时序较为复杂,为了更加好地操控时序和debug,博主使用状态机进行书写。
reg [3:0]   STATE;
parameter   wr_addr             = 4'b0000;
parameter   wr_addr_shakehand   = 4'b0001;
parameter   wr_data             = 4'b0010;
parameter   wr_data_shakehand   = 4'b0011;
parameter   write               = 4'b0100;          
parameter   rd_addr             = 4'b0101;
parameter   rd_addr_shakehand   = 4'b0110;
parameter   rd_data             = 4'b0111;
parameter   rd_data_shakehand   = 4'b1000;
parameter   read                = 4'b1001;
parameter   init                = 4'b1010;
parameter   buffer              = 4'b1011;
parameter   stop                = 4'b1111;
  1. 状态机——状态跳转:
always@(posedge clk or negedge rst_n)
begin
    if(!rst_n)    STATE <= init;
    else    begin
        case(STATE)
            init:   begin
                if(init_cnt == 5)   STATE <= wr_addr;
                    else            STATE <= init;                    
            end
            wr_addr:            STATE <= wr_addr_shakehand;
            wr_addr_shakehand:  begin
                if(awvalid == 1'b1 && awready == 1'b1)  STATE <= wr_data;
                    else                                STATE <= wr_addr_shakehand;     
            end
            wr_data:            STATE <= wr_data_shakehand;
            wr_data_shakehand:  begin
                if(wvalid == 1'b1 && wready == 1'b1)    STATE <= write;
                    else                                STATE <= wr_data_shakehand;
            end
            write:              STATE <= buffer;
            buffer:             STATE <= rd_addr;
            rd_addr:            STATE <= rd_addr_shakehand;
            rd_addr_shakehand:  begin
                if(arvalid == 1'b1 && arready == 1'b1)  STATE <= rd_data;
                    else                                STATE <= rd_addr_shakehand;
            end
            rd_data:            STATE <= rd_data_shakehand;
            rd_data_shakehand:  begin
                if(rready == 1'b1 && rvalid == 1'b1)    STATE <= read;
                    else                                STATE <= rd_data_shakehand;
            end
            read:               STATE <= stop;
            stop:               STATE <= stop;
            default:           STATE <= init;
        endcase
    end    
end
  1. 写地址通道AW:

① 给出要写入的地址ADDRESS,并将awvalid拉高,等待bram拉高awready进行握手。
(准确来说不是等待,因为bram只要满足条件就会拉高awready,主从逻辑独立。此处为方便表达。)
② awvalid-awready握手后,数据awaddr传输完成,此时主机要主动拉低awvalid。

//写地址通道AW
parameter   ADDRESS = 114;
always@(posedge clk or negedge rst_n)
begin
    if(!rst_n) begin
        awaddr  <= 32'b0;
        awvalid <= 1'b0;
    end     
    else if(STATE == wr_addr)    begin
        awaddr <= ADDRESS;
        awvalid <= 1'b1;
    end
    else    begin
        awaddr <= awaddr;
        awvalid <= awvalid;
    end
end
always@(posedge clk or negedge rst_n)
begin
    if(STATE == wr_addr_shakehand)  begin
        if(awvalid == 1'b1 && awready == 1'b1)  begin
            awvalid <= 1'b0;     //成功握手,valid拉低
            awaddr <= 32'b0;
        end
    end
end
  1. 写数据通道W:

① 给出要写入的数据WR_DATA,同时拉高wvalid,等待bram拉高wready进行握手
② wvalid-wready握手后,数据wdata传输完成,此时主机要主动拉低wvalid。
③ 对于wstrb,在数据传输时赋为 4’b1111,表示wdata32位数据均有效。
(wstrb:写数据有效的字节线,用来表明哪8bits数据是有效的。)

//写数据通道W
parameter   WR_DATA = 514;
always@(posedge clk or negedge rst_n)
begin
    if(!rst_n) begin
        wdata <= 32'b0;
        wvalid <= 1'b0;
        wstrb <= 4'b0;
    end
    else if(STATE == wr_data)   begin
        wdata <= WR_DATA;
        wvalid <= 1'b1;
        wstrb <= 4'b1111;
    end    
    else    begin
        wdata <= wdata;
        wvalid <= wvalid;
        wstrb <= wstrb;
    end
end
always@(posedge clk or negedge rst_n)
begin
   if(STATE == wr_data_shakehand)   begin
        if(wvalid == 1'b1 && wready == 1'b1)    begin
            wvalid <= 1'b0;
            wstrb  <= 4'b0000;
            wdata  <= 0;
        end
        else    begin
            wvalid <= wvalid;
            wstrb <= wstrb;
        end
   end
end
  1. 写响应通道B:

在AXI-Lite中,我们只需要管bready这一个端口就行。我们只需要一直拉高bready就行。
(bready:主机接受响应就绪信号 。该信号表示主机是否能够接受响应信息。1 = 主机就绪,0 = 主机未就绪。)
对于bvalid和bresp不需要我们操心,因为那是bram给到主机的,不由我们控制。

//写响应通道B
always@(posedge clk or negedge rst_n)
begin
    if(!rst_n) begin
        bready <= 1'b1;
    end
    else if(STATE == write || STATE == read)  begin
        bready <= 1'b1;
    end
end
  1. 读地址通道AR:

① 给出要读取的地址ADDRESS,并将arvalid拉高,等待bram拉高arready进行握手。
② arvalid-arready握手后,数据araddr传输完成,此时主机要主动拉低arvalid。

//读地址通道AR
always@(posedge clk or negedge rst_n)
begin
    if(!rst_n) begin
        araddr <= 32'b0;
        arvalid <= 1'b0;
    end
    else if (STATE == rd_addr)  begin
        araddr <= ADDRESS;
        arvalid <= 1'b1;
    end
    else    begin
        araddr <= araddr;
        arvalid <= arvalid;
    end
end
always@(posedge clk or negedge rst_n)
begin
    if(STATE == rd_addr_shakehand)  begin
        if(arvalid == 1'b1 && arready == 1'b1)  begin
            arvalid <= 1'b0;
        end
        else    arvalid <= arvalid;
    end
end
  1. 读数据通道R:

① 将rready拉高,等待bram拉高rvalid进行握手。
② rready-rvalid握手后,数据rdata传输完成,此时主机要主动拉低rready。
(注意:此时的数据流向是bram→主机,因此主机端为ready信号,bram端为valid信号。)

//读数据通道R
always@(posedge clk or negedge rst_n)
begin
    if(!rst_n) begin
        rready <= 1'b0;
    end
    else if(STATE == rd_data)    begin
        rready <= 1'b1;
    end
end
always@(posedge clk or negedge rst_n)
begin
    if(STATE == rd_data_shakehand)  begin
        if(rready == 1'b1 && rvalid == 1'b1)    begin
            rready <= 1'b0;
        end
        else    rready <= rready;
    end
end
  1. 实例化block memory generator IP核模块:
blk_mem_gen_0   mybram(
    .s_aclk(clk),
    .s_aresetn(rst_n),
    
    .s_axi_awaddr(awaddr),
    .s_axi_awvalid(awvalid),
    .s_axi_awready(awready),
    .s_axi_wdata(wdata),
    .s_axi_wvalid(wvalid),
    .s_axi_wready(wready),
    .s_axi_wstrb(wstrb),
    
    .s_axi_bready(bready),
    .s_axi_bvalid(bvalid),
    .s_axi_bresp(bresp),
    
    .s_axi_araddr(araddr),
    .s_axi_arvalid(arvalid),
    .s_axi_arready(arready),
    .s_axi_rready(rready),
    .s_axi_rvalid(rvalid),
    .s_axi_rdata(rdata)
     
);

完整代码(包含Testbench)

module axi4_light_bram(
input   wire    clk,
input   wire    rst_n
    );

reg [3:0]   STATE;
parameter   wr_addr             = 4'b0000;
parameter   wr_addr_shakehand   = 4'b0001;
parameter   wr_data             = 4'b0010;
parameter   wr_data_shakehand   = 4'b0011;
parameter   write               = 4'b0100;          
parameter   rd_addr             = 4'b0101;
parameter   rd_addr_shakehand   = 4'b0110;
parameter   rd_data             = 4'b0111;
parameter   rd_data_shakehand   = 4'b1000;
parameter   read                = 4'b1001;
parameter   init                = 4'b1010;
parameter   buffer              = 4'b1011;
parameter   stop                = 4'b1111;

//写地址通道AW
reg [31:0]  awaddr;    //in(视角:bram)
reg         awvalid;   //in
wire        awready;   //out
//写数据通道W
reg [31:0]  wdata;     //in
reg         wvalid;    //in
wire        wready;    //out
reg [3:0]   wstrb;     //in
//写响应通道B
reg         bready;    //in:表示主机准备好接收bram的数据
wire        bvalid;    //out:表示bram可以给master发送数据
wire [1:0]  bresp;     //out
//读地址通道AR
reg [31:0]  araddr;    //in
reg         arvalid;   //in
wire        arready;   //out
//读数据通道R
wire [31:0] rdata;     //out
wire        rvalid;    //out
reg         rready;    //in
wire [1:0]  rresp;     //out

//初始缓冲init
reg [3:0] init_cnt;
always@(posedge clk or negedge rst_n)
begin
    if(!rst_n) init_cnt <= 0;
    else    init_cnt <= (init_cnt == 5) ? 0 : (init_cnt + 1);
end

always@(posedge clk or negedge rst_n)
begin
    if(!rst_n)    STATE <= init;
    else    begin
        case(STATE)
            init:   begin
                if(init_cnt == 5)   STATE <= wr_addr;
                    else            STATE <= init;                    
            end
            wr_addr:            STATE <= wr_addr_shakehand;
            wr_addr_shakehand:  begin
                if(awvalid == 1'b1 && awready == 1'b1)  STATE <= wr_data;
                    else                                STATE <= wr_addr_shakehand;     
            end
            wr_data:            STATE <= wr_data_shakehand;
            wr_data_shakehand:  begin
                if(wvalid == 1'b1 && wready == 1'b1)    STATE <= write;
                    else                                STATE <= wr_data_shakehand;
            end
            write:              STATE <= buffer;
            buffer:             STATE <= rd_addr;
            rd_addr:            STATE <= rd_addr_shakehand;
            rd_addr_shakehand:  begin
                if(arvalid == 1'b1 && arready == 1'b1)  STATE <= rd_data;
                    else                                STATE <= rd_addr_shakehand;
            end
            rd_data:            STATE <= rd_data_shakehand;
            rd_data_shakehand:  begin
                if(rready == 1'b1 && rvalid == 1'b1)    STATE <= read;
                    else                                STATE <= rd_data_shakehand;
            end
            read:               STATE <= stop;
            stop:               STATE <= stop;
            default:           STATE <= init;
        endcase
    end    
end


//写地址通道AW
parameter   ADDRESS = 114;
always@(posedge clk or negedge rst_n)
begin
    if(!rst_n) begin
        awaddr  <= 32'b0;
        awvalid <= 1'b0;
    end     
    else if(STATE == wr_addr)    begin
        awaddr <= ADDRESS;
        awvalid <= 1'b1;
    end
    else    begin
        awaddr <= awaddr;
        awvalid <= awvalid;
    end
end
always@(posedge clk or negedge rst_n)
begin
    if(STATE == wr_addr_shakehand)  begin
        if(awvalid == 1'b1 && awready == 1'b1)  begin
            awvalid <= 1'b0;     //成功握手,valid拉低
            awaddr <= 32'b0;
        end
    end
end

//写数据通道W
parameter   WR_DATA = 514;
always@(posedge clk or negedge rst_n)
begin
    if(!rst_n) begin
        wdata <= 32'b0;
        wvalid <= 1'b0;
        wstrb <= 4'b0;
    end
    else if(STATE == wr_data)   begin
        wdata <= WR_DATA;
        wvalid <= 1'b1;
        wstrb <= 4'b1111;
    end    
    else    begin
        wdata <= wdata;
        wvalid <= wvalid;
        wstrb <= wstrb;
    end
end
always@(posedge clk or negedge rst_n)
begin
   if(STATE == wr_data_shakehand)   begin
        if(wvalid == 1'b1 && wready == 1'b1)    begin
            wvalid <= 1'b0;
            wstrb  <= 4'b0000;
            wdata  <= 0;
        end
        else    begin
            wvalid <= wvalid;
            wstrb <= wstrb;
        end
   end
end

//写响应通道B
always@(posedge clk or negedge rst_n)
begin
    if(!rst_n) begin
        bready <= 1'b1;
    end
    else if(STATE == write || STATE == read)  begin
        bready <= 1'b1;
    end
end

//读地址通道AR
always@(posedge clk or negedge rst_n)
begin
    if(!rst_n) begin
        araddr <= 32'b0;
        arvalid <= 1'b0;
    end
    else if (STATE == rd_addr)  begin
        araddr <= ADDRESS;
        arvalid <= 1'b1;
    end
    else    begin
        araddr <= araddr;
        arvalid <= arvalid;
    end
end
always@(posedge clk or negedge rst_n)
begin
    if(STATE == rd_addr_shakehand)  begin
        if(arvalid == 1'b1 && arready == 1'b1)  begin
            arvalid <= 1'b0;
        end
        else    arvalid <= arvalid;
    end
end

//读数据通道R
always@(posedge clk or negedge rst_n)
begin
    if(!rst_n) begin
        rready <= 1'b0;
    end
    else if(STATE == rd_data)    begin
        rready <= 1'b1;
    end
end
always@(posedge clk or negedge rst_n)
begin
    if(STATE == rd_data_shakehand)  begin
        if(rready == 1'b1 && rvalid == 1'b1)    begin
            rready <= 1'b0;
        end
        else    rready <= rready;
    end
end

blk_mem_gen_0   mybram(
    .s_aclk(clk),
    .s_aresetn(rst_n),
    
    .s_axi_awaddr(awaddr),
    .s_axi_awvalid(awvalid),
    .s_axi_awready(awready),
    .s_axi_wdata(wdata),
    .s_axi_wvalid(wvalid),
    .s_axi_wready(wready),
    .s_axi_wstrb(wstrb),
    
    .s_axi_bready(bready),
    .s_axi_bvalid(bvalid),
    .s_axi_bresp(bresp),
    
    .s_axi_araddr(araddr),
    .s_axi_arvalid(arvalid),
    .s_axi_arready(arready),
    .s_axi_rready(rready),
    .s_axi_rvalid(rvalid),
    .s_axi_rdata(rdata)
     
);

endmodule

Testbench如下:

`timescale 1ns / 1ps
module axi4_light_bram_tb();

reg clk;
reg rst_n;

initial begin
    clk = 1'b0;
    rst_n = 1'b0;
    #150
    rst_n = 1'b1; 
end

always # 10  clk <= ~clk;

axi4_light_bram axi4_light_bram_uut(
    .clk(clk),
    .rst_n(rst_n)
);

endmodule

仿真结果分析

在这里插入图片描述


心得和后续工作

  1. AXI总线算是比较复杂的总线,虽然后续开发的过程中大多不需要自己去写读写时序,但是经过这么一个过程能加深我对AXI协议的理解。“握手”是协议的精髓所在,它有效地控制着整个时序,并且保证主从机互相了解对方的状态,方便数据传输的开始和终止。
  2. 本程序只是最简单的AXI-Lite,如果书写常规的AXI协议,将多出一些端口需要配置(比如id,len,size),后续博主会在这个代码的基础上写常规AXI协议。
  3. 本程序只进行了一次数据的读和写。但是使用AXI协议可以同时写很多数据,然后用last指示最后一个数据,此类云云。后续我会去写这样的代码的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/70235.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

GDB调试

文章目录1.什么是GDB2. 准备工作3.GDB命令-启动、退出、查看代码4.设置断点5.GDB命令-调试命令1.什么是GDB 2. 准备工作 通常&#xff0c;在为调试而编译时&#xff0c;我们会关掉编译器的优化选项"-o",并打开调试选选项“-g”&#xff0c;另外&#xff0c;“-wall”…

【第一章 Linux目录结构,网络连接模式,vi和vim,Linux关机重启命令,Linux用户管理】

第一章 Linux目录结构&#xff0c;网络连接模式&#xff0c;vi和vim&#xff0c;Linux关机&重启命令&#xff0c;Linux用户管理 1.Linux和Unix&#xff1a; ①Unix针对于大型&#xff0c;高性能主机或服务器&#xff1b; ②Linux适用于个人计算机。 2.网络连接的三种模式…

图解pytorch里面的torch.gather()

在 Dim1 的情况下应用 torch.gather() 上图显示了 torch gather() 函数在 dim1 的二维张量上的工作。 这里索引张量的行对应于输入张量的行&#xff08;用灰色阴影突出显示&#xff09;。现在对于索引张量中的每个索引值&#xff0c;从该行和输入张量的索引中选取相应的值。 让…

LEADTOOLS 22-23 .Net/NetCore/JS/JAVA/Win/Linux

破解版功能齐全&#xff1a;LEADTOOLS 是一系列综合工具包&#xff0c;旨在帮助程序员将光栅、文档、医学、多媒体和矢量图像集成到他们的桌面、服务器、平板电脑和移动应用程序中。LEADTOOLS 为开发人员提供最灵活、最强大的成像技术&#xff0c;为 OCR、条形码、表单识别、PD…

推荐大家一些CTF的网站和工具

一.网站 1.攻防世界 网址&#xff1a;攻防世界 这是一个有好多题目的网站 主要有Misc、Pwn、Web、Reverse、Crypto、Mobile几种题型 不会的问题还可以查题解 好用度 9星 2.BUUCTF 网址&#xff1a;BUUCTF在线评测 也有很多ctf的题目 逆向、网络等等...... 比攻防世界…

最近火爆了的对话ChatGPT

前言 相信最近小伙伴们已经被ChatGPT的惊艳效果刷屏了&#xff0c;之前笔者也介绍过一些对话方向的工作&#xff0c;感兴趣的小伙伴可以穿梭&#xff1a; 对话系统最新综述II https://zhuanlan.zhihu.com/p/446760658 在对话系统中建模意图、情感: https://zhuanlan.zhihu.com/…

Nacos是什么?

摘要&#xff1a;Nacos是 Dynamic Naming and Configuration Service的首字母简称&#xff0c;相较之下&#xff0c;它更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。本文分享自华为云社区《Nacos入门指南 - Nacos是什么》&#xff0c;作者&#xff1a;华为云P…

.gitlab-ci.yml文件常用规则说明

我自己整理了一份yml文件&#xff0c;里面包含了分支触发&#xff0c;和tag触发&#xff0c;还有缓存等&#xff1a; stages:- install- build- deploycache:key: nodeModulespaths:- node_modules- distjob_install:stage: installtags:- cvtagsonly:refs:- devscript:- npm …

基于LLVM的Fortran编译器分析

简介 本文内容基于LLVM 13.0.0。 目前基于LLVM的Fortran编译器&#xff08;或者驱动&#xff09;有3种&#xff0c;分别是flang、f18和flang-new。 flang是pgfortran的开源版本&#xff0c;基于PGI/NVIDIA的商业Fortran 编译器&#xff0c;它并不从属于LLVM项目。NVIDIA团队…

LabVIEW编程LabVIEW开发 ADAM 4015热电阻输入模块例程与相关资料

LabVIEW编程LabVIEW开发 ADAM 4015热电阻输入模块例程与相关资料 ​研华公司的ADAM 4015是6通道热电阻输入模块&#xff0c;可以采集2线或3线热电阻输入信号&#xff0c;ADAM4015T课题采集热敏电阻的输入信号。模块在工业测量和监控的有着广泛的应用&#xff0c;它既可以支持A…

Web3中文|苹果想对以太坊征税

虽然Web3是非常新的技术&#xff0c;但是似乎已经遇到了非常多“劲敌”。 这些“敌人”正在阻碍web3应用程序和区块链游戏的发展&#xff0c;因为在web3里&#xff0c;应用程序和游戏将允许用户自主相互交易数字资产所有权。 所以&#xff0c;那些大公司&#xff0c;如任天堂…

最近全网爆火的黑科技,叫做chatGPT

AI神器ChatGPT 火了。 能直接生成代码、会自动修复bug、在线问诊、模仿莎士比亚风格写作……各种话题都能hold住&#xff0c;它就是OpenAI刚刚推出的——ChatGPT。 有脑洞大开的网友甚至用它来设计游戏&#xff1a;先用ChatGPT生成游戏设定&#xff0c;再用Midjourney出图&…

vue 数据手写分页,定时展示

我们在业务之中&#xff0c;其实会常常用到一些数据的分段展示 &#xff0c; 比如数据量过大导致echarts无法展示&#xff0c;我们就可以将数据进行算法分页 &#xff0c; 然后套用定时器实时更新分段数据&#xff1b; 例子展示 &#xff1a; 将下列数组截取成每页5条数据的分…

观察者模式(python)

一、模式定义 1.观察者模式(Observer Pattern)&#xff1a;定义对象间的一种一对多依赖关系&#xff0c;使得每当一个对象状态发生改变时&#xff0c;其相关依赖对象皆得到通知并被自动更新。 2.观察者模式又叫做发布-订阅&#xff08;Publish/Subscribe&#xff09;模式、模…

SpringBoot微服务的发布与部署(3种方式)

基于 SpringBoot 的微服务开发完成之后&#xff0c;现在到了把它们发布并部署到相应的环境去运行的时候了。 SpringBoot 框架只提供了一套基于可执行 jar 包&#xff08;executable jar&#xff09;格式的标准发布形式&#xff0c;但并没有对部署做过多的界定&#xff0c;而且…

2022年Python面试题汇总【面试官爱问】

2022年Python面试题汇总【常问】1、请你讲讲python获取输入的方式&#xff0c;以及python如何打开文件2、Python数据处理的常用函数3、请你说说python传参传引用4、请你说说python和java的区别5、Python你常用的包有哪些&#xff1f;6、简单说明如何选择正确的Python版本。7、简…

Qt动态库

QT带界面的动态库 创建动态库 一、新建一个C的动态库的项目 选择C的动态库的项目&#xff0c;进行下一步 修改项目的名字和项目的保存的路径。 选着编译的方式&#xff0c;不需要改&#xff0c;进行下一步。 选着动态库&#xff0c;编译成动态库&#xff0c;进行下一步。 项目…

[附源码]JAVA毕业设计社区生活超市管理系统(系统+LW)

[附源码]JAVA毕业设计社区生活超市管理系统&#xff08;系统LW&#xff09; 项目运行 环境项配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目…

[附源码]Python计算机毕业设计SSM计算机学院课程设计管理系统(程序+LW)

[附源码]Python计算机毕业设计SSM计算机学院课程设计管理系统&#xff08;程序LW) 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。…

基于安卓的课程管理系统app设计

目 录 第1章 绪论 1 1.1 什么是电子课程管理 1 1.2 系统开发的背景 1 1.3 本文主要工作 1 1.4 系统设计目标分析 2 第2章 基本技术方案 3 2.1 Android概述 3 2.2 Android系统的四大组件 3 2.3 Android中的相关技术介绍及分析 5 2.3.1 Android系统架构研究 5 2.3.2 Android架构分…