AXI4總線協議 ------ AXI_LITE協議

一、AXI 相關知識介紹

https://download.csdn.net/download/mvpkuku/90841873?AXI_LITE

?選出部分重點,詳細文檔見上面鏈接。

1.AXI4 協議類型

2.握手機制?

?二、AXI_LITE 協議的實現?

?1. AXI_LITE 通道及各通道端口功能介紹

2.實現思路及框架?

2.1 總體框架?

2.2 寫通道?

1.復位信號進行跨時鐘域同步(用戶時鐘/AXI4時鐘)

2.僅當user_wr_ready為高時,用戶的寫通道是有效的

3.例化兩個fifo分別存儲用戶端傳來的地址以及數據用戶時鐘寫入,并通過AXI時鐘讀出

4.控制AXI_LITE(狀態機)接口信號是在AXI時鐘下進行 (控制cmd_rden/data_rden并輸出對應的相關接口數據)

`timescale 1ns / 1ps
//
// Description: AXI_lite寫通道
//
module axlite_wr_channel#(parameter USER_WR_DATA_WIDTH    = 32 ,//用戶寫數據位寬和AXI4—Lite數據位寬保持一致parameter AXI_DATA_WIDTH 		= 32, //AXI4_LITE總線規定,數據位寬只支持32Bit或者64bitparameter AXI_ADDR_WIDTH        = 32	
)(input   wire							        clk,     //用戶寫時鐘		input   wire									axi_clk, //從機讀時鐘   input   wire									reset,//與 用戶端 交互信號input   wire								    user_wr_en,input   wire  [USER_WR_DATA_WIDTH-1:0]	        user_wr_data,input   wire  [AXI_ADDR_WIDTH-1 :0]		        user_wr_addr,output  wire                                    user_wr_ready,	//與 axi_lite從機 交互信號output  reg   [AXI_ADDR_WIDTH -1:0]  	        m_axi_awaddr, //write addr channeloutput  wire  [2:0] 				 	        m_axi_awprot, output  reg   		 				 	        m_axi_awvalid, input   wire    		 			 	        m_axi_awready,output  reg   [AXI_DATA_WIDTH-1:0]	 	        m_axi_wdata,   //write data channeloutput  wire  [AXI_DATA_WIDTH/8-1:0] 	        m_axi_wstrb,output  reg      					 	        m_axi_wvalid,input   wire    					 	        m_axi_wready,input   wire  [1:0]	         	                m_axi_bresp,  //wirte response channelinput   wire	   			         	        m_axi_bvalid,output  wire    			         	        m_axi_bready
);(* dont_touch = "true"*) reg reset_sync_d0;  //user clk
(* dont_touch = "true"*) reg reset_sync_d1;
(* dont_touch = "true"*) reg reset_sync;
(* dont_touch = "true"*) reg a_reset_sync_d0; //axi clk
(* dont_touch = "true"*) reg a_reset_sync_d1;
(* dont_touch = "true"*) reg a_reset_sync;reg	 [31:0]  cmd_din;
reg          cmd_wren;
wire [31:0]  cmd_dout;
reg 		 cmd_rden;
wire		 cmd_wrfull ;
wire		 cmd_rdempty;
wire [4:0]   cmd_wrcount;
wire [4:0]   cmd_rdcount;reg	 [31:0]  data_din;
reg          data_wren;
wire [31:0]  data_dout;
reg 		 data_rden;
wire		 data_wrfull;
wire		 data_rdempty;
wire [4:0]   data_wrcount;
wire [4:0]   data_rdcount;reg [2 : 0]	 cur_status;
reg [2 : 0]	 nxt_status;localparam WR_IDLE     = 3'b000;
localparam WR_PRE      = 3'b001;
localparam WR_DATA_EN  = 3'b010;
localparam WR_END      = 3'b100;
/*--------------------------------------------------*\assign
\*--------------------------------------------------*/
assign m_axi_bready  = 1'b1;
assign m_axi_awprot  = 0;
assign m_axi_wstrb   = {AXI_DATA_WIDTH/8{1'b1}};assign user_wr_ready = reset_sync ? 1'b0 : cmd_wrcount <= 'd12 ; //留一點余量 //當user_wr_ready為低的時候,用戶發送寫是無效的
/*--------------------------------------------------*\CDC process
\*--------------------------------------------------*/
always @(posedge clk) beginreset_sync_d0   <= reset;reset_sync_d1   <= reset_sync_d0;reset_sync      <= reset_sync_d1;
endalways @(posedge axi_clk) begina_reset_sync_d0 <= reset;a_reset_sync_d1 <= a_reset_sync_d0;a_reset_sync    <= a_reset_sync_d1;
end/*--------------------------------------------------*\wirte addr to cmd fifo、write data to data fifo 
\*--------------------------------------------------*/
always @(posedge clk) beginif (user_wr_ready) begincmd_wren  <= user_wr_en;cmd_din   <= user_wr_addr;data_wren <= user_wr_en;data_din  <= user_wr_data; 		endelse begincmd_wren  <= 0;cmd_din   <= 0;data_wren <= 0;data_din  <= 0; 		end
end/*--------------------------------------------------*\WR state machine  (三段式)
\*--------------------------------------------------*/
always@(posedge axi_clk)beginif(a_reset_sync)cur_status <= WR_IDLE;elsecur_status <= nxt_status;       
endalways@(*)beginif(a_reset_sync)beginnxt_status <= WR_IDLE;endelse begincase(cur_status)WR_IDLE : beginif(!cmd_rdempty)nxt_status <= WR_PRE;elsenxt_status <= cur_status;endWR_PRE : beginnxt_status <= WR_DATA_EN;endWR_DATA_EN : beginif (m_axi_bvalid && m_axi_bready)nxt_status <= WR_END;else nxt_status <= cur_status;end			WR_END : beginnxt_status <= WR_IDLE;enddefault : nxt_status <= WR_IDLE;endcaseend  
end
/*-----------------------------------------------------------*\read addr from cmd_fifo 、 read data from data_fifo  
\*-----------------------------------------------------------*/
always @(*) beginif (a_reset_sync) begincmd_rden   <= 0;data_rden  <= 0;endelse begincmd_rden   <= cur_status == WR_PRE;data_rden  <= cur_status == WR_PRE;end
endalways @(posedge axi_clk) beginif (cmd_rden) m_axi_awaddr <= cmd_dout;else m_axi_awaddr <= m_axi_awaddr;
endalways @(posedge axi_clk) beginif (a_reset_sync) m_axi_awvalid <= 0;else if (cur_status == WR_PRE)m_axi_awvalid <= 1'b1;else if (m_axi_awvalid && m_axi_awready)m_axi_awvalid <= 0;
endalways @(posedge axi_clk) beginif (data_rden) m_axi_wdata <= data_dout;else m_axi_wdata <= m_axi_wdata;
endalways @(posedge axi_clk) beginif (a_reset_sync) m_axi_wvalid <= 0;else if (cur_status == WR_PRE)m_axi_wvalid <= 1'b1;else if (m_axi_wvalid && m_axi_wready)m_axi_wvalid <= 0;
end//寫地址fifo
fifo_w32xd16 wr_cmd_fifo (.rst          ( reset_sync  ), // input wire rst.wr_clk       ( clk         ), // input wire wr_clk         用戶寫時鐘.din          ( cmd_din     ), // input wire [31 : 0] din.wr_en        ( cmd_wren    ), // input wire wr_en.rd_clk       ( axi_clk     ), // input wire rd_clk         從機讀時鐘 .rd_en        ( cmd_rden    ), // input wire rd_en.dout         ( cmd_dout    ), // output wire [31 : 0] dout.full         ( cmd_wrfull  ), // output wire full.empty        ( cmd_rdempty ), // output wire empty.rd_data_count( cmd_wrcount ), // output wire [4 : 0] rd_data_count.wr_data_count( cmd_rdcount )  // output wire [4 : 0] wr_data_count
);//寫數據fifo
fifo_w32xd16 wr_data_fifo (.rst          ( reset_sync   ), // input wire rst.wr_clk       ( clk          ), // input wire wr_clk        用戶寫時鐘.din          ( data_din     ), // input wire [31 : 0] din.wr_en        ( data_wren    ), // input wire wr_en.rd_clk       ( axi_clk      ), // input wire rd_clk        從機讀時鐘 .rd_en        ( data_rden    ), // input wire rd_en.dout         ( data_dout    ), // output wire [31 : 0] dout.full         ( data_wrfull  ), // output wire full.empty        ( data_rdempty ), // output wire empty.rd_data_count( data_rdcount ), // output wire [4 : 0] rd_data_count.wr_data_count( data_wrcount )  // output wire [4 : 0] wr_data_count
);
endmodule

2.3 讀通道?

讀通道的實現分兩步,用戶端發出讀請求并給讀的地址,然后從機根據地址發出數據,用戶讀出。

因此讀地址fifo的邏輯部分與寫通道一致,只有狀態機跳轉的RD_DATA_EN的條件根據模塊端口有所改變,但是讀數據fifo,是在AXI_CLK的時鐘域下,端口輸入有效及端口輸入數據,根據非空開始用戶讀,然后賦給模塊用戶端口

`timescale 1ns / 1ps
//
// Description: AXI_LITE讀通道
//
module axilite_rd_channel#(parameter USER_RD_DATA_WIDTH    = 32 , //用戶讀數據位寬和AXI4—Lite數據位寬保持一致parameter AXI_DATA_WIDTH 		= 32, parameter AXI_ADDR_WIDTH        = 32		
)(input   wire								    clk,  	  input   wire								    axi_clk,    input   wire								    reset,//用戶端讀請求,讀地址信號input   wire								    user_rd_en,input   wire  [AXI_ADDR_WIDTH-1 :0]		        user_rd_addr,output  wire                                    user_rd_ready,output  reg   [USER_RD_DATA_WIDTH-1:0]	        user_rd_data,output  reg                                     user_rd_valid,//與AXI_LITE從機 交互信號output  reg   		 							m_axi_arvalid, // axi read address channelinput   wire   		 							m_axi_arready, output  reg   [AXI_ADDR_WIDTH-1:0] 				m_axi_araddr,output  wire  [2:0] 							m_axi_arprot, input   wire  [AXI_DATA_WIDTH-1:0]	    		m_axi_rdata,   // axi read data channelinput   wire  [1:0] 				    		m_axi_resp,input   wire     					    		m_axi_rvalid,output  wire   						   	 		m_axi_rready
);(* dont_touch = "true"*) reg reset_sync_d0;  //user clk
(* dont_touch = "true"*) reg reset_sync_d1;
(* dont_touch = "true"*) reg reset_sync;
(* dont_touch = "true"*) reg a_reset_sync_d0; //axi clk
(* dont_touch = "true"*) reg a_reset_sync_d1;
(* dont_touch = "true"*) reg a_reset_sync;reg	 [31:0]  cmd_din;
reg          cmd_wren;
wire [31:0]  cmd_dout;
reg 		 cmd_rden;
wire		 cmd_wrfull;
wire		 cmd_rdempty;
wire [4:0]   cmd_wrcount;
wire [4:0]   cmd_rdcount;reg	 [31:0]  data_din;
reg          data_wren;
wire [31:0]  data_dout;
wire 		 data_rden;
wire		 data_wrfull;
wire		 data_rdempty;
wire [4:0]   data_wrcount;
wire [4:0]   data_rdcount;reg [2 : 0]	 cur_status;
reg [2 : 0]	 nxt_status;localparam RD_IDLE     = 3'b000;
localparam RD_PRE      = 3'b001;
localparam RD_DATA_EN  = 3'b010;
localparam RD_END      = 3'b100;
/*--------------------------------------------------*\assign
\*--------------------------------------------------*/
assign user_rd_ready = reset_sync ? 1'b0 : cmd_wrcount <= 'd12 ; 
assign m_axi_rready  = 1'b1;
assign m_axi_arprot  = 0;
/*--------------------------------------------------*\CDC process
\*--------------------------------------------------*/
always @(posedge clk) beginreset_sync_d0   <= reset;reset_sync_d1   <= reset_sync_d0;reset_sync      <= reset_sync_d1;
endalways @(posedge axi_clk) begina_reset_sync_d0 <= reset;a_reset_sync_d1 <= a_reset_sync_d0;a_reset_sync    <= a_reset_sync_d1;
end/*--------------------------------------------------*\wirte addr to cmd fifo
\*--------------------------------------------------*/
always @(posedge clk) beginif (user_rd_ready) begincmd_wren  <= user_rd_en;cmd_din   <= user_rd_addr;	endelse begincmd_wren  <= 0;cmd_din   <= 0;			end
end/*--------------------------------------------------*\RD state machine  
\*--------------------------------------------------*/
always @(posedge axi_clk) beginif (a_reset_sync) begincur_status <= RD_IDLE;endelse begincur_status <= nxt_status;end
endalways @(*) beginif (a_reset_sync) beginnxt_status <= RD_IDLE;		endelse begincase(cur_status)RD_IDLE : beginif (~cmd_rdempty)nxt_status <= RD_PRE;else nxt_status <= cur_status;endRD_PRE : beginnxt_status <= RD_DATA_EN;endRD_DATA_EN : beginif (m_axi_rvalid && m_axi_rready)nxt_status <= RD_END;else nxt_status <= cur_status;endRD_END : beginnxt_status <= RD_IDLE;enddefault : nxt_status <= RD_IDLE;endcase	end
end/*-----------------------------------------------------------*\read addr from cmd_fifo 
\*-----------------------------------------------------------*/
always @(*) beginif (a_reset_sync) cmd_rden  <= 0;else cmd_rden  <= cur_status == RD_PRE;
endalways @(posedge axi_clk) beginif (cmd_rden) m_axi_araddr <= cmd_dout;else m_axi_araddr <= m_axi_araddr;
endalways @(posedge axi_clk) beginif (a_reset_sync) m_axi_arvalid <= 0;else if (cur_status == RD_PRE)m_axi_arvalid <= 1'b1;else if (m_axi_arvalid && m_axi_arready)m_axi_arvalid <= 0;
end/*-----------------------------------------------------------*\read user data from data fifo
\*-----------------------------------------------------------*/
always @(posedge axi_clk) begindata_din  <= m_axi_rdata;data_wren <= m_axi_rvalid;
end assign data_rden = reset_sync ? 1'b0 : ~data_rdempty;always @(posedge clk) beginuser_rd_valid  <= data_rden;user_rd_data   <= data_dout;
end//讀地址fifo
fifo_w32xd16 rd_cmd_fifo (.rst          ( reset_sync  ), // input wire rst.wr_clk       ( clk         ), // input wire wr_clk         用戶寫時鐘.din          ( cmd_din     ), // input wire [31 : 0] din.wr_en        ( cmd_wren    ), // input wire wr_en.rd_clk       ( axi_clk     ), // input wire rd_clk         從機讀時鐘 .rd_en        ( cmd_rden    ), // input wire rd_en.dout         ( cmd_dout    ), // output wire [31 : 0] dout.full         ( cmd_wrfull  ), // output wire full.empty        ( cmd_rdempty ), // output wire empty.rd_data_count( cmd_wrcount ), // output wire [4 : 0] rd_data_count.wr_data_count( cmd_rdcount )  // output wire [4 : 0] wr_data_count
);//讀數據fifo
fifo_w32xd16 rd_data_fifo (.rst          ( a_reset_sync ), // input wire rst.wr_clk       ( axi_clk      ), // input wire wr_clk        從機寫時鐘.din          ( data_din     ), // input wire [31 : 0] din.wr_en        ( data_wren    ), // input wire wr_en.rd_clk       ( clk          ), // input wire rd_clk            用戶讀時鐘 .rd_en        ( data_rden    ), // input wire rd_en.dout         ( data_dout    ), // output wire [31 : 0] dout.full         ( data_wrfull  ), // output wire full.empty        ( data_rdempty ), // output wire empty.rd_data_count( data_rdcount ), // output wire [4 : 0] rd_data_count.wr_data_count( data_wrcount )  // output wire [4 : 0] wr_data_count
);
endmodule

3.仿真?

通過調用AXI_LITE接口的BRAM IP核,實/復位結束等一會兒進入寫數據狀態,讀寫數據(寫10個數據,讀10個數據),數據一致累加,地址也不斷累加,地址最大為1024。

?仿真結果如下,可以看出讀寫地址和數據完全一樣,說明AXI_LITE接口代碼實現無誤。

?

需要工程請私信

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/80173.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/80173.shtml
英文地址,請注明出處:http://en.pswp.cn/web/80173.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

idea運行

各種小kips Linuxidea上傳 Linux 部署流程 1、先在idea打好jar包&#xff0c;clean之后install 2、在Linux目錄下&#xff0c;找到對應項目目錄&#xff0c;把原來的jar包放在bak文件夾里面 3、殺死上一次jar包的pid ps -ef|grep cliaidata.jar kill pid 4、再進行上傳新的jar…

FPGA: XILINX Kintex 7系列器件的架構

本文將詳細介紹Kintex-7系列FPGA器件的架構。以下內容將涵蓋Kintex-7的核心架構特性、主要組成部分以及關鍵技術&#xff0c;盡量全面且結構化&#xff0c;同時用簡潔的語言確保清晰易懂。 Kintex-7系列FPGA架構概述 Kintex-7是Xilinx 7系列FPGA中的中高端產品線&#xff0c;基…

【LLM】大模型落地應用的技術 ——— 推理訓練 MOE,AI搜索 RAG,AI Agent MCP

【LLM】大模型落地應用的技術 ——— 推理訓練MOE&#xff0c;AI搜索RAG&#xff0c;AI Agent MCP 文章目錄 1、推理訓練 MOE2、AI搜索 RAG3、AI Agent MCP 1、推理訓練 MOE MoE 是模型架構革新&#xff0c;解決了算力瓶頸。原理是多個專家模型聯合計算。 推理訓練MoE&#xff…

10 web 自動化之 yaml 數據/日志/截圖

文章目錄 一、yaml 數據獲取二、日志獲取三、截圖 一、yaml 數據獲取 需要安裝 PyYAML 庫 import yaml import os from TestPOM.common import dir_config as Dir import jsonpathclass Data:def __init__(self,keyNone,file_name"test_datas.yaml"):file_path os…

中exec()函數因$imagePath參數導致的命令注入漏洞

exec(zbarimg -q . $imagePath, $barcodeList, $returnVar); 針對PHP中exec()函數因$imagePath參數導致的命令注入漏洞&#xff0c;以下是安全解決方案和最佳實踐&#xff1a; 一、漏洞原理分析 直接拼接用戶輸入$imagePath到系統命令中&#xff0c;攻擊者可通過注入特殊字…

this.$set的用法-響應式數據更新

目錄 一、核心作用 三、使用場景與示例 1. 給對象添加新屬性 四、與 Vue.set 的關系 五、底層原理 六、Vue 3 的替代方案 七、最佳實踐 八、常見問題 Q&#xff1a;為什么修改嵌套對象屬性不需要 $set&#xff1f; Q&#xff1a;$set 和 $forceUpdate 的區別&#xf…

【生成式AI文本生成實戰】DeepSeek系列應用深度解析

目錄 &#x1f31f; 前言&#x1f3d7;? 技術背景與價值&#x1fa79; 當前技術痛點&#x1f6e0;? 解決方案概述&#x1f465; 目標讀者說明 &#x1f9e0; 一、技術原理剖析&#x1f4ca; 核心概念圖解&#x1f4a1; 核心作用講解&#x1f527; 關鍵技術模塊說明?? 技術選…

c/c++的opencv的圖像預處理講解

OpenCV 圖像預處理核心技術詳解 (C/C) 圖像預處理是計算機視覺任務中至關重要的一步。原始圖像往往受到噪聲、光照不均、尺寸不一等多種因素的影響&#xff0c;直接用于后續分析&#xff08;如特征提取、目標檢測、機器學習模型訓練等&#xff09;可能會導致性能下降或結果不準…

使用 Docker 部署 React + Nginx 應用教程

目錄 1. 創建react項目結構2. 創建 .dockerignore3. 創建 Dockerfile4. 創建 nginx.conf5. 構建和運行6. 常用命令 1. 創建react項目結構 2. 創建 .dockerignore # 依賴目錄 node_modules npm-debug.log# 構建輸出 dist build# 開發環境文件 .git .gitignore .env .env.local …

Java 流(Stream)API

一、理論說明 1. 流的定義 Java 流&#xff08;Stream&#xff09;是 Java 8 引入的新特性&#xff0c;用于對集合&#xff08;如 List、Set&#xff09;或數組進行高效的聚合操作&#xff08;如過濾、映射、排序&#xff09;和并行處理。流不存儲數據&#xff0c;而是按需計…

網絡協議分析 實驗七 FTP、HTTP、DHCP

文章目錄 實驗7.1 FTP協議練習二 使用瀏覽器登入FTP練習三 在窗口模式下&#xff0c;上傳/下傳數據文件實驗7.2 HTTP(Hyper Text Transfer Protocol)練習二 頁面提交練習三 訪問比較復雜的主頁實驗7.3 DHCP(Dynamic Host Configuration Protocol) 實驗7.1 FTP協議 dir LIST&…

go語言學習進階

目錄 第一章 go語言中包的使用 一.main包 二.package 三.import 四.goPath環境變量 五.init包初始化 六.管理外部包 第二章 time包 第三章 File文件操作 一.FileInfo接口 二.權限 三.打開模式 四.File操作 五.讀文件 參考1&#xff1a;Golang 中的 bufio 包詳解…

Hue面試內容整理-后端框架

Cloudera 的 Hue 項目在后端采用了成熟的 Python Web 框架 Django,結合其他組件構建了一個可擴展、模塊化的系統,便于與 Hadoop 生態系統中的各個組件集成。以下是 Hue 后端架構的詳細介紹: 后端架構概覽 1. Django Web 框架 Hue 的核心是基于 Django 構建的 Web 應用,負責…

Web-CSS入門

WEB前端&#xff0c;三部分&#xff1a;HTML部分、CSS部分、Javascript部分。 1.HTML部分&#xff1a;主要負責網頁的結構層 2.CSS部分&#xff1a;主要負責網頁的樣式層 3.JS部分&#xff1a;主要負責網頁的行為層 **基本概念** 層疊樣式表&#xff0c;Cascading Style Sh…

2025年PMP 學習十六 第11章 項目風險管理 (總章)

2025年PMP 學習十六 第11章 項目風險管理 &#xff08;總章&#xff09; 第11章 項目風險管理 序號過程過程組1規劃風險管理規劃2識別風險規劃3實施定性風險分析規劃4實施定量風險分析規劃5規劃風險應對執行6實施風險應對執行7監控風險監控 目標: 提高項目中積極事件的概率和…

基于SpringBoot的小區停車位管理系統

作者&#xff1a;計算機學姐 開發技術&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源碼”。 專欄推薦&#xff1a;前后端分離項目源碼、SpringBoot項目源碼、Vue項目源碼、SSM項目源碼、微信小程序源碼 精品專欄&#xff1a;…

HTML常用標簽用法全解析:構建語義化網頁的核心指南

HTML作為網頁開發的基石&#xff0c;其標簽的合理使用直接影響頁面的可讀性、SEO效果及維護性。本文系統梳理HTML核心標簽的用法&#xff0c;結合語義化設計原則與實戰示例&#xff0c;助你構建規范、高效的網頁結構。 一、基礎結構與排版標簽 1.1 文檔結構 <!DOCTYPE htm…

國產linux系統(銀河麒麟,統信uos)使用 PageOffice自定義Word模版中的數據區域

? PageOffice 國產版 &#xff1a;支持信創系統&#xff0c;支持銀河麒麟V10和統信UOS&#xff0c;支持X86&#xff08;intel、兆芯、海光等&#xff09;、ARM&#xff08;飛騰、鯤鵬、麒麟等&#xff09;、龍芯&#xff08;Mips、LoogArch&#xff09;芯片架構。 在實際的Wor…

.NET Core liunx二進制文件安裝

最近遇見個尷尬的事情&#xff0c;都2025年了。我需要部署一個自己多年前寫的項目。由于時間緊、任務重&#xff0c;我懶得去升級到8.0了。于是計劃在Ubuntu20.04上安裝.NET Core3.1項目。可以使用包管理器卻安裝不上了。于是&#xff0c;我就嘗試二進制文件安裝。 實際上二進…

【python基礎知識】Day 27 函數專題2:裝飾器

知識點&#xff1a; 裝飾器的思想&#xff1a;進一步復用函數的裝飾器寫法注意內部函數的返回值 裝飾器教程 作業&#xff1a; 編寫一個裝飾器 logger&#xff0c;在函數執行前后打印日志信息&#xff08;如函數名、參數、返回值&#xff09; def logger(func):def wrapper(*ar…