当前位置: 首页 > news >正文

13 双口 RAM IP 核

双口 RAM IP 核简介

双口 RAM IP 核有两个端口,它又分为伪双端口 RAM 和真双端口 RAM,伪双端口 RAM 一个端口只能读,另一个端口只能
写,真双端口 RAM 两个端口都可以进行读写操作。同时对存储器进行读写操作时就会用到双端口 RAM,例如有一个 FIFO 存储器,需要同时对其进行数据的写入和读出,这时候就需要一个写端口和一个读端口。

伪双端口 RAM

BMG IP 核配置成简单双端口 RAM 的框图如下图所示:
在这里插入图片描述
它有两组独立的端口 A 和 B,其中 A 端口只能提供了 DINA 数据总线,只能进行写操作,B 端口只提供了 DOUTB 数据总线,只能进行读操作,此外它相当于单口 RAM 还多出了以下信号线(在常规使用中一般不会关注这些信号线):

  1. IINJECTSBITERR:Inject Single-Bit Error 的简写,即注入单 bit 错误,仅适用于 Xilinx Zynq-7000 和 7系列芯片的 ECC 配置。
  2. IINJECTDBITERR:Inject Double-Bit Error 的简写,即注入双 bit 错误,同样仅适用于 Xilinx Zynq-7000和 7 系列芯片的 ECC 配置。
  3. SBITERR:Single-Bit Error 的简写,即单 bit 错误,标记内存中存在的单 bit 错误,该错误已在输出总线上自动更正。
  4. DBITERR:Double-Bit Error 的简写,即双 bit 错误,标记内存中存在双 bit 错误,需要注意的是内置的ECC 解码模块不能自动纠正双 bit 错误。
  5. RDADDRECC:Read Address for ECC Error output 的简写,即读地址 ECC 错误输出,同样仅适用于Xilinx Zynq-7000 和 7 系列芯片的 ECC 配置。

真双口 RAM

BMG IP 核配置成真双端口RAM 的框图如下图所示:
在这里插入图片描述
它有两组独立的端口 A 和 B,且每组端口都可进行读写操作。

不同 RAM 端口对比

在这里插入图片描述
通过对比可以发现无论是哪种双端口 RAM,其地址线、时钟线、使能线都有两组,所以双端口 RAM 可以实现在不同时钟域下的读/写,且可以同时对不同的地址进行读/写,这便大大提高了我们数据处理的灵活性。

读写冲突和写写冲突

写-写冲突:当两个端口都试图向同一个地址写数据(即两个端口写使能同时有效且写地址相同)时则会产生写-写冲突,发生写-写冲突后对应内存地址的数据为未知。
读-写冲突:一个端口进行读取数据操作,另一个端口进行写入数据操作,当同时操作到同一地址时就会发生读-写冲突,此时如果:

  • 写端口为 READ_FIRST 模式,则读端口读出的数据为写入操作前存储在RAM中的数据。
  • 写端口为 WRITE_FIRST 或 NO_CHANGE 模式,则读端口读出的数据为无效。

双口 RAM 配置核生成

打开 BMG IP 核的“Customize IP”窗口

  1. Vivado 工程左侧“Flow Navigator”栏中的“IP Catalog”
    在这里插入图片描述
  2. 在“IP Catalog”窗口的搜索栏中输入“Block Memory”关键字后,出现唯一匹配的“Block Memory Generator”
    在这里插入图片描述
  3. 双击“Block Memory Generator”后弹出 IP 核的配置界面
    在这里插入图片描述

BMG IP 核有关伪双口 RAM 的配置

Block Memory Generator IP核的 IP Catalog 窗口如下,主要包括一个IP名称输入框核4个选项卡,页面依次进行介绍。
在这里插入图片描述

  1. 在“Component Name”一栏可以设置该 IP 元件的名称
    在这里插入图片描述
  2. “Basic”选项卡
    在这里插入图片描述
    (1)“lnterface Type(接口模式)”:有两种接口模式可选,分别为 Native(常规)接口和 AXI4 接口。AXI4 模式一般是在处理器中的数据需要和 BRAM 交互时才会使用,当不需要与处理器数据进行交互时一般采用 Native 模式。
    (2) “Generate address interface with 32 bits”选项为是否生成位宽为 32 的地址接口,勾选后内存的数据位宽也必须设置成 32 的整数倍,一般不做勾选。
    (3) “Memory Type(存储类型)”:有五种类型可选,分别为“Single Port RAM(单端口RAM)”、“Simple Dual Port RAM(伪双端口 RAM)”、“True Dual Port RAM(真双端口 RAM)”、“Single Port ROM(单端口 ROM)”和“Dual Port ROM(双端口 ROM)”,这里以单端口 RAM 为例。
    (4) “Common Clock”选项:是否启用同步时钟,Port A 和 Port B 在同一个时钟域时可以勾选也可以不勾选在不同时钟域时不能勾选,否则跨时钟域会出问题。
    (5) “ECC Options(ECC 选项)”:ECC纠错码选项只有在伪双端口 RAM 类型下才可以进行配置。
    (6) “Write Enable(写使能)”:可以选择是否使用字节写使能功能,启用后可设置字节大小为 8 位或 9 位,需要注意的是启用后内存的数据位宽必须设置为所选字节大小的整数倍。
    (7) “Algorithm Options(算法选项)”:算法选项主要用于决定 BRAM 的拼接的方式,一般在BRAM 深度、宽度较大的时候起作用,有三种算法可选,分别为“Minimum Area(最小面积算法)”、“Low Power(低功耗算法)”和“Fixed Primitives(固定单元算法)”
  3. “Port A Options选项卡,Port A实现数据写入操作。
    在这里插入图片描述
    (1)“Memory Size(内存大小)”:用于指定端口宽度和深度、运行模式和使能端口类型。
  • Port A Width;数据位宽,单位 bit,本次实验我们设置成 8,可设置的位宽范围为 1~4608。
  • Port A Depth;深度,即 RAM 所能访问的地址范围。这里有一点需要注意,那就是写深度和写位宽的乘积不要超过器件本身的 ram 资源的大小。
  • Operating Mode;RAM 运作模式,有三种模式可选,分别是Write First(写优先模式)、 Read First(读优先模式)、No Change(不变模式),单口 RAM 一般选 No Change(不变模式)。
  • Enable Port Type;使能端口类型。有两种可选,分别为 Use ENA pin(添加使能端口 A 的信号)和 Always Enabled(取消使能信号,端口 A 一直处于使能状态)。
    (2)“Port A Optional Output Register”:用于为 RAM 的输出端添加寄存器,Port A 不支持。
    (3)“Port A Output Reset Options”:用于配置端口的复位信号。,Port A 不支持
    (4)“READ Address Change A”:用于更改端口的读地址,这个功能只在 UltraScale 设备上使用。
  1. “Port B Options”选项卡,Port B 只支持读操作。
    在这里插入图片描述
    (1)“Memory Size(内存大小)”:用于指定端口宽度和深度、运行模式和使能端口类型。
  • Port B Width;数据位宽,其位宽设置必须与 Port A 数据位宽存在倍数关系,通常情况下保持一致。
  • Port B Depth;深度,当 Port B 数据位宽、Port A 数据位宽和深度的值确定后,Port B 深度的值就会自动确定。
  • Operating Mode;RAM 运作模式,Port B 不可配置。
  • Enable Port Type;使能端口类型。有两种可选,分别为 Use ENA pin(添加使能端口 A 的信号)和 Always Enabled(取消使能信号,端口 B 一直处于使能状态)。
    (2)“Port B Optional Output Register”:用于为 RAM 的输出端添加寄存器。其作用是提高 BRAM 的运行频率和改善时序,当然为此付出的代价就是每勾选一个寄存器,输出就会延迟一拍。
  • Primitives Output Register 使用 BRAM 内部的寄存器打拍输出。
  • Core Output Register 使用 SLICE 的寄存器打拍输出。
  • SoftECC Input Register 当使用软 ECC 的时候,用 SLICE 的寄存器打拍。
  • REGCEA,当使用 Primitives Output Register 或者 Core Output Register 时,可以用 REGCEA 来使能相应的输出。
    (3)“Port B Output Reset Options”:用于配置端口的复位信号。可以添加一个复位信号(RSTA Pin)、配置复位时 RAM 输出总线上的数据值(Output Reset Value)、配置是否复位内置锁存器(Reset Memory Latch)、配置复位信号与时钟使能之间的优先级(Reset Priority)。
    (4)“READ Address Change B”:用于更改端口的读地址,这个功能只在 UltraScale 设备上使用。
  1. “Other Options”选项卡
    在这里插入图片描述
    (1)“Pipeline Stages within Mux”:输出端 Mux 选择器的流水线级数。在大位宽、大深度的 BRAM 拼接场景中会用 MUX 来选择输出地址所对应的数据,勾选该选项后可以使输出数据具有更好的时序。
    (2)“Memory Initialization(初始化文件)”:选择是否使用本地初始化文件(.coe 文件)来对存储空间进行初始化。
    (3)“Structural/UniSim Simulation Model Options”:用于选择结构仿真模型发生碰撞时生成的警告消息和输出的类型。
    (4)“Behavioral Simulation Model Options”:用于关闭仿真时的冲突告警和超出范围告警。
  2. “Summary”选项卡
    在这里插入图片描述
    该界面显示了配置的存储器的类型,消耗的 BRAM 资源等信息,检查没问题可以直接点击“OK”按钮生成 RAM IP 核。
    在这里插入图片描述
    在弹出的“Generate Output Products”窗口直接点击“Generate”即可。
    在这里插入图片描述

模块设计

本次实验的用 Xilinx BMG IP 核配置成一个伪装双口 RAM 并对其进行读写操作,系统框图如下:
在这里插入图片描述

编写代码

大多数情况下伪双口 RAM 都已经满足使用需求,入跨时钟域传输数据、存储数据、FIFO等,所以这里以伪双口 RAM 为例。

生成伪双口 RAM IP 核

伪双口 RAM IP 核的配置如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

伪双口 RAM IP读写代码编写

在伪双口 RAM IP读写代码先例化一个伪双口 RAM IP核,在复位完成后开始通过 Port A 周期写入数据,当第一次写入到一半时启动 Port B 进行周期读数据,波形图如下:
在这里插入图片描述

module ram_ip_rw(input sys_clk,input sys_rst_n
);//端口 A 时钟
wire clka;
//端口 A 使能,高电平使能
reg ena;
//端口 A 写使能,高电平写入
reg wea;
//端口 A 地址
reg [5:0]addra;
//写入端口 A 的数据
wire [7:0]dina;//端口 B 时钟
wire clkb;
//端口 B 使能,高电平使能
reg enb;
//端口 B 地址
reg [5:0]addrb;
//端口 B 读出的数据
wire [7:0]doutb;//端口 A 时钟
assign clka = sys_clk;//端口 A 使能
always @(posedge sys_clk) beginif(!sys_rst_n)ena <= 0;elseena <= 1;
end//端口 A 写使能
always @(posedge sys_clk) beginif(!sys_rst_n)wea <= 0;elsewea <= 1;
end//端口 A 地址,0~63
always @(posedge sys_clk) beginif(!sys_rst_n)addra <= 0;else if((addra < 63) && (wea == 1))addra <= addra + 1;elseaddra <= 0;
end//端口 A 写入数据,从地址0~63依次写入如0~63
assign dina = (wea == 1) ? addra : 0;//端口 B 时钟
assign clkb = sys_clk;//端口 B 使能
always @(posedge sys_clk) beginif(!sys_rst_n)enb <= 0;else if(addra == 31)enb <= 1;
end//端口 B 地址,0~63
always @(posedge sys_clk) beginif(!sys_rst_n)addrb <= 0;else if((addrb < 63) && (enb == 1))addrb <= addrb + 1;elseaddrb <= 0;
end//例化伪双口RAM IP核
blk_mem_gen_0 u_blk_mem_gen_0_inst0(.clka(clka),.ena(ena),.wea(wea),.addra(addra),.dina(dina),.clkb(clkb),.enb(enb),.addrb(addrb),.doutb(doutb)
);endmodule

仿真激励代码编写

仿真激励代码非常简单,只需要例化 单口 RAM IP读写模块 ,然后产生一个周期时钟即可,完整的代码如下:

module tb_ram_ip_rw(
);reg sys_clk;				//系统时钟
reg sys_rst_n;				//系统复位,低电平有效//信号初始化
initial beginsys_clk = 1'b0;sys_rst_n = 1'b0;#200sys_rst_n = 1'b1;
end//产生时钟
always #20 sys_clk = ~sys_clk;//例化需要仿真的IP核
ram_ip_rw tb_u_ram_ip_rw_inst0(.sys_clk(sys_clk),				//系统时钟.sys_rst_n(sys_rst_n)			//系统复位,低电平有效
);endmodule

相关文章:

13 双口 RAM IP 核

双口 RAM IP 核简介 双口 RAM IP 核有两个端口&#xff0c;它又分为伪双端口 RAM 和真双端口 RAM&#xff0c;伪双端口 RAM 一个端口只能读&#xff0c;另一个端口只能 写&#xff0c;真双端口 RAM 两个端口都可以进行读写操作。同时对存储器进行读写操作时就会用到双端口 RAM…...

【高级数据结构】Trie树

原理 介绍 高效地存储和查询字符串的数据结构。所以其重点在于&#xff1a;存储、查询两个操作。 存储操作 示例和图片来自&#xff1a;https://blog.csdn.net/qq_42024195/article/details/88364485 假设有这么几个字符串&#xff1a;b&#xff0c;abc&#xff0c;abd&…...

国际化 Vue-i18n的安装与使用 (Vue2.0 / Vue3.0)

国际化 Vue-i18n的安装与使用 &#xff08;Vue2.0 / Vue3.0&#xff09; 一、Vue-i18n是什么&#xff1f; Vue-I18n是 Vue.js 的国际化插件。它可以轻松地将一些本地化功能集成到你的 Vue.js 应用程序中。简单来说就是可以帮助用户进行语言的切换” 二、使用步骤 1.引入库 代码…...

Linux 学习笔记(8)

八、 启动引导 1 、 Linux 的启动流程 1) BIOS 自检 2) 启动 GRUB/LILO 3) 运行 Linux kernel 并检测硬件 4) 挂载根文件系统 5) 运行 Linux 系统的第一个进程 init( 其 PID 永远为 1 &#xff0c;是所有其它进程的父进程 ) 6) init 读取系统引导配置文件…...

【python】1.python3.12.2和pycharm社区版的安装指南

欢迎来CILMY23的博客喔&#xff0c;本篇为【python】1.python3.12.2和pycharm社区版的安装指南&#xff0c;感谢观看&#xff0c;支持的可以给个一键三连&#xff0c;点赞关注收藏。 目录 一、python3.12.2的下载与安装 1.1下载 1.2安装 二、pycharm的安装 2.1下载安装 2…...

Ubuntu将c++编译成.so文件并测试

一、准备cpp和h文件 创建test.cpp 在cpp中定义相加的函数funcAdd&#xff0c;给出函数的细节代码 #include <iostream> using namespace std;int funcAdd(int x, int y) {return xy; }创建test.h 在h中声明定义的函数&#xff0c;不需要任何细节 #ifndef __TEST__ #…...

数据分析-Pandas数据的探查面积图

数据分析-Pandas数据的探查面积图 数据分析和处理中&#xff0c;难免会遇到各种数据&#xff0c;那么数据呈现怎样的规律呢&#xff1f;不管金融数据&#xff0c;风控数据&#xff0c;营销数据等等&#xff0c;莫不如此。如何通过图示展示数据的规律&#xff1f; 数据表&…...

美团分布式 ID 框架 Leaf 介绍和使用

一、Leaf 在当今日益数字化的世界里&#xff0c;软件系统的开发已经成为了几乎所有行业的核心。然而&#xff0c;随着应用程序的规模不断扩大&#xff0c;以及对性能和可扩展性的需求不断增加&#xff0c;传统的软件架构和设计模式也在不断地面临挑战。其中一个主要挑战就是如…...

Ubuntu20.04: UE4.27 中 Source Code 的编辑器下拉框没有 Rider选项

问题描述 最近想用 Rider 作为 UE4 开发的 IDE&#xff0c;但安装好 Rider 后&#xff0c;发现编辑器下拉框中没有 Rider 的选项&#xff0c;我检查了 UE4 的插件&#xff0c;发现 Rider Integration 插件已经安装且启用的。 环境&#xff1a;Ubuntu 20.04 UE4.27 Rider2023…...

【论文阅读-PRIVGUARD】Day4:3节

3 PRIVANALYZER&#xff1a;强制执行隐私政策的静态分析 本节介绍PRIVANALYZER&#xff0c;这是一个用于强制执行由PRIVGUARD追踪的隐私政策的静态分析器**。我们首先回顾LEGALEASE政策语言&#xff0c;我们使用它来正式编码政策&#xff0c;然后描述如何静态地强制执行它们**…...

新一代电话机器人开源PHP源代码

使用easyswoole 框架开发的 新一代电话机器人开源PHP源码 项目地址&#xff1a;https://gitee.com/ddrjcode/robotphp 代理商页面演示地址 http://119.23.229.15:8080 用户名&#xff1a;c0508 密码&#xff1a;123456 包含 AI外呼管理&#xff0c;话术管理&#xff0c;CR…...

dockerdocker-copose_限制容器cpu和内存

本文目录 docker的限制方式限制CPU占用限制内存占用 docker-compose docker的限制方式 限制CPU占用 Docker使用--cpus参数来限制容器的CPU资源。该参数指定了分配给容器的CPU核心数量或百分比。 例子&#xff1a;限制CPU使用个数 docker run --cpus2 <imageName>以上…...

【leetcode】圆圈中最后剩下的数字

目录 1. 问题 2. 思路 3. 代码 4. 运行 1. 问题 本题即为典型的约瑟夫问题&#xff0c;通过递推公式倒推出问题的解。原始问题是从n个人中每隔m个数踢出一个人&#xff0c;原始问题变成从n-1个人中每隔m个数踢出一个人…… 示例 1&#xff1a; 输入: n 5, m 3 输出: 3…...

利用python批量将.shp文件转换坐标生成.geojson文件,再将.geojson转换成.csv文件,最后将csv文件插入数据库表

第一步&#xff1a;.shp批量转.geojson # author: JMY # 创建时间: 2024/2/26 17:12 # 批量将.shp文件生成geojson文件并转换坐标为3857import os import geopandas as gpd# 定义输入和输出文件夹路径 input_folder shp文件 output_folder geojson文件# 定义输入和输出坐标系…...

远程服务器Ubuntu 18.04安装VNC远程桌面

一、安装vnc 1.安装图形化界面工具 # 安装过程中会弹窗让选择配置&#xff0c;选lightdm sudo apt install ubuntu-desktop sudo apt-get install gnome-panel gnome-settings-daemon metacity nautilus gnome-terminal 2.安装vnc sudo apt-get install x11vnc3.安装LightD…...

30天自制操作系统(第23天)

23.1 编写malloc 参考第22天的内容&#xff0c;在绘制窗口前先分配了150*50个字节大小的内存&#xff0c;所以导致该文件经编译后有7.6k左右&#xff0c;能否在其中使用指针呢&#xff1f;当需要开辟空间时&#xff0c;移动指针即可。在之前的章节中也有函数memman_alloc函数可…...

基于Rust语言,和WebAssembly技术,与JavaScript结合,的具体应用场景

基于Rust语言与WebAssembly&#xff08;Wasm&#xff09;技术并与JavaScript结合&#xff0c;可以应用于多个场景&#xff0c;特别是在需要高性能和/或低级系统访问的情况下。下面是一些具体的应用场景&#xff1a; 性能密集型任务: Rust加上Wasm适合执行计算密集型任务&#x…...

【MATLAB源码-第154期】基于matlab的OFDM系统多径信道下块状和梳妆两种导频插入方式误码率对比仿真。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 OFDM&#xff08;Orthogonal Frequency Division Multiplexing&#xff0c;正交频分复用&#xff09;是一种高效的无线信号传输技术&#xff0c;广泛应用于现代通信系统&#xff0c;如Wi-Fi、LTE和5G。OFDM通过将宽带信道划分…...

Linux 下 socket 编程介绍及 TCP 客户端与服务端创建示例

目录 socket 编程接口TCP 服务端TCP 客户端更多内容 本文介绍了 Linux 下的 socket 编程&#xff0c;及总结了使用 socket 接口实现 TCP 服务端和客户端的示例代码。 socket 编程接口 socket() 函数&#xff1a;用于创建一个新的 socket 描述符&#xff1a; int socket(int …...

JetBrains Gateway Github Copilot 客户端插件和主机插件

JetBrains Gateway可以通过插件支持Github Copilot&#xff08;需另行注册&#xff09;。 需要安装插件 客户端&#xff0c;而非插件 主机&#xff0c;如图所示&#xff1a; 大概是因为代码显示在客户端&#xff08;运行在本地的IDE&#xff09;&#xff1f;...

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站&#xff0c;会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后&#xff0c;网站没有变化的情况。 不熟悉siteground主机的新手&#xff0c;遇到这个问题&#xff0c;就很抓狂&#xff0c;明明是哪都没操作错误&#x…...

生成xcframework

打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式&#xff0c;可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢

随着互联网技术的飞速发展&#xff0c;消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁&#xff0c;不仅优化了客户体验&#xff0c;还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用&#xff0c;并…...

css的定位(position)详解:相对定位 绝对定位 固定定位

在 CSS 中&#xff0c;元素的定位通过 position 属性控制&#xff0c;共有 5 种定位模式&#xff1a;static&#xff08;静态定位&#xff09;、relative&#xff08;相对定位&#xff09;、absolute&#xff08;绝对定位&#xff09;、fixed&#xff08;固定定位&#xff09;和…...

RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程

本文较长&#xff0c;建议点赞收藏&#xff0c;以免遗失。更多AI大模型应用开发学习视频及资料&#xff0c;尽在聚客AI学院。 本文全面剖析RNN核心原理&#xff0c;深入讲解梯度消失/爆炸问题&#xff0c;并通过LSTM/GRU结构实现解决方案&#xff0c;提供时间序列预测和文本生成…...

Rapidio门铃消息FIFO溢出机制

关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系&#xff0c;以下是深入解析&#xff1a; 门铃FIFO溢出的本质 在RapidIO系统中&#xff0c;门铃消息FIFO是硬件控制器内部的缓冲区&#xff0c;用于临时存储接收到的门铃消息&#xff08;Doorbell Message&#xff09;。…...

RSS 2025|从说明书学习复杂机器人操作任务:NUS邵林团队提出全新机器人装配技能学习框架Manual2Skill

视觉语言模型&#xff08;Vision-Language Models, VLMs&#xff09;&#xff0c;为真实环境中的机器人操作任务提供了极具潜力的解决方案。 尽管 VLMs 取得了显著进展&#xff0c;机器人仍难以胜任复杂的长时程任务&#xff08;如家具装配&#xff09;&#xff0c;主要受限于人…...

区块链技术概述

区块链技术是一种去中心化、分布式账本技术&#xff0c;通过密码学、共识机制和智能合约等核心组件&#xff0c;实现数据不可篡改、透明可追溯的系统。 一、核心技术 1. 去中心化 特点&#xff1a;数据存储在网络中的多个节点&#xff08;计算机&#xff09;&#xff0c;而非…...

FFmpeg avformat_open_input函数分析

函数内部的总体流程如下&#xff1a; avformat_open_input 精简后的代码如下&#xff1a; int avformat_open_input(AVFormatContext **ps, const char *filename,ff_const59 AVInputFormat *fmt, AVDictionary **options) {AVFormatContext *s *ps;int i, ret 0;AVDictio…...

何谓AI编程【02】AI编程官网以优雅草星云智控为例建设实践-完善顶部-建立各项子页-调整排版-优雅草卓伊凡

何谓AI编程【02】AI编程官网以优雅草星云智控为例建设实践-完善顶部-建立各项子页-调整排版-优雅草卓伊凡 背景 我们以建设星云智控官网来做AI编程实践&#xff0c;很多人以为AI已经强大到不需要程序员了&#xff0c;其实不是&#xff0c;AI更加需要程序员&#xff0c;普通人…...