【AMD Xilinx】ZUBoard(5):移植KSZ9131千兆phy驱动

news2024/11/27 6:18:55

【AMD Xilinx】ZUBoard(5):移植KSZ9131千兆phy驱动

  • 一、需求
  • 二、软件搭建
    • 1. 在bsp中添加lwip库
    • 2. 创建lwip的例子
  • 三、 Phy驱动调试
    • 1. 问题查找
    • 2. 修改驱动
      • 1) 查找芯片手册
      • 2)增加宏PHY_MICROCHIP_IDENTIFIER
      • 3)修改函数detect_phy
      • 3)修改函数get_IEEE_phy_speed
      • 4)增加get_Microchip_phy_speed的具体实现
    • 3. 重新测试
  • 四、网口灯工作状况说明
    • 1.正常网口灯说明
    • 2. 排查过程记录

一、需求

在hackster.io上看到有人问板上的phy在裸机模式下怎么驱动。

https://www.hackster.io/whitney-knitter/getting-started-with-avnet-s-zuboard-1cg-f1d793

在这里插入图片描述

嗨,我刚买了这块板来尝试一些在同一设备上混合软件和hdl的项目。我试图在A53-0上建立并运行一些UDP通信(在独立/裸机应用程序中),并尝试了UDP模板应用程序。不幸的是,Avnet在板上安装了一个不支持的以太网PHY芯片(Microchip
KSZ9131RNXC ),模板无法初始化它。 你知道有没有这种芯片的初始化代码的独立版本的例子吗? 提前感谢。

这个phy在linux下识别是没问题的,而官方demo都是在linux下跑的,因此不需要考虑这个问题。

但是裸机模式下默认的驱动确实不支持,所以需要我们手动修改。

二、软件搭建

1. 在bsp中添加lwip库

首先在bsp包中添加lwip库,否则在软件模板中没法生成带lwip的例程。

选中platform.spr,选A53对应的Board Support Package,点Modify BSP Settings
在这里插入图片描述

选中lwip211,点ok重新编译bsp
在这里插入图片描述

注意在standalone界面,可以修改stdin和stdout的串口。一般现成的开发板串口都是固定uart0或者uart1,其实是可以自定义修改的。

在这里插入图片描述

2. 创建lwip的例子

bsp编译完成后,创建新程序,选lwIP Echo Server模板

在这里插入图片描述
创建完成后,打开main.c,根据你自己的网络环境,修改ip地址、掩码、网关,然后运行
在这里插入图片描述

运行起来一直卡在这里
在这里插入图片描述

三、 Phy驱动调试

1. 问题查找

单步跟踪发现进入到init_emacps后,问题出在函数XEmacPs_SetOperatingSpeed

源代码路径psu_cortexa53_0/standalone_psu_cortexa53_0/bsp/psu_cortexa53_0/libsrc/lwip211_v1_7/src/contrib/ports/xilinx/netif/xemacpsif_hw.c

在这里插入图片描述
因为speed只能为10,100,1000,而实际值识别到的speed为0,所以导致错误。




再回头看刚才的打印信息

在这里插入图片描述
原因很明显了,驱动默认只支持Marvell、TI、Realtek这三个品牌的phy,其他品牌的phy需要我们自己根据手册来写驱动

2. 修改驱动

在这里插入图片描述

可以看到

		XEmacPs_PhyRead(xemacpsp, phy_addr, PHY_IDENTIFIER_1_REG,
						&phy_reg);
		if ((phy_reg != PHY_MARVELL_IDENTIFIER) &&
			(phy_reg != PHY_TI_IDENTIFIER) &&
			(phy_reg != PHY_REALTEK_IDENTIFIER)) {
			xil_printf("WARNING: Not a Marvell or TI or Realtek Ethernet PHY. Please verify the initialization sequence\r\n");
		}

关键是XEmacPs_PhyRead读PHY_IDENTIFIER_1_REG寄存器的值,根据这个值判断厂家型号

#define PHY_IDENTIFIER_1_REG					2

#define PHY_MARVELL_IDENTIFIER				0x0141
#define PHY_TI_IDENTIFIER					0x2000
#define PHY_REALTEK_IDENTIFIER				0x001c

所以要做的第一步就是查芯片手册,找到寄存器2对应的值,增加一个品牌分支

1) 查找芯片手册

查下原理图,用的phy芯片是Microchip KSZ9131RNXC
在这里插入图片描述

在这里插入图片描述

https://www.microchip.com/en-us/product/KSZ9131#document-table

2)增加宏PHY_MICROCHIP_IDENTIFIER

根据手册查找对应的寄存器描述,phy的id应该为0x0022

因此增加宏PHY_MICROCHIP_IDENTIFIER,值为0x0022

#define PHY_MICROCHIP_IDENTIFIER            0x0022

3)修改函数detect_phy

修改函数
void detect_phy(XEmacPs *xemacpsp)

void detect_phy(XEmacPs *xemacpsp)
{
	u16_t phy_reg;
	u32_t phy_addr;
	u32_t emacnum;

	if (xemacpsp->Config.BaseAddress == XPAR_XEMACPS_0_BASEADDR)
		emacnum = 0;
	else
		emacnum = 1;
	for (phy_addr = 31; phy_addr > 0; phy_addr--) {
		XEmacPs_PhyRead(xemacpsp, phy_addr, PHY_DETECT_REG,
							&phy_reg);

		if ((phy_reg != 0xFFFF) &&
			((phy_reg & PHY_DETECT_MASK) == PHY_DETECT_MASK)) {
			/* Found a valid PHY address */
			LWIP_DEBUGF(NETIF_DEBUG, ("XEmacPs detect_phy: PHY detected at address %d.\r\n",
																	phy_addr));
			xil_printf(("XEmacPs detect_phy: PHY detected at address %d.\r\n", phy_addr));
			if (emacnum == 0)
				phymapemac0[phy_addr] = TRUE;
			else
				phymapemac1[phy_addr] = TRUE;

			XEmacPs_PhyRead(xemacpsp, phy_addr, PHY_IDENTIFIER_1_REG,
							&phy_reg);
			if ((phy_reg != PHY_MARVELL_IDENTIFIER) &&
				(phy_reg != PHY_TI_IDENTIFIER) &&
				(phy_reg != PHY_REALTEK_IDENTIFIER)) {
				xil_printf("WARNING: Not a Marvell or TI or Realtek Ethernet PHY. Please verify the initialization sequence\r\n");
				if(PHY_MICROCHIP_IDENTIFIER == phy_reg){
					xil_printf("Phy: MICROCHIP --Add by Leo 2023.12\r\n");
				}
			}
		}
	}
}

3)修改函数get_IEEE_phy_speed

修改速度函数,增加对Microchip的判断分支

static u32_t get_IEEE_phy_speed(XEmacPs *xemacpsp, u32_t phy_addr)
{
	u16_t phy_identity;
	u32_t RetStatus;

	XEmacPs_PhyRead(xemacpsp, phy_addr, PHY_IDENTIFIER_1_REG,
					&phy_identity);
	if (phy_identity == PHY_TI_IDENTIFIER) {
		RetStatus = get_TI_phy_speed(xemacpsp, phy_addr);
	} else if (phy_identity == PHY_REALTEK_IDENTIFIER) {
		RetStatus = get_Realtek_phy_speed(xemacpsp, phy_addr);
	} else if (phy_identity == PHY_MICROCHIP_IDENTIFIER) { //增加了对Microchip的判断分支
		RetStatus = get_Microchip_phy_speed(xemacpsp, phy_addr); 
	} else {
		RetStatus = get_Marvell_phy_speed(xemacpsp, phy_addr);
	}

	return RetStatus;
}

4)增加get_Microchip_phy_speed的具体实现

然后再增加get_Microchip_phy_speed的具体实现,
仔细对比了寄存器的差别,主要是速度寄存器的地址和解析与ieee不一样

注意要禁用RX delay和TX delay。开始我没有设置,在100M下工作正常,在1000M下怎么都ping不通,反复查了好久还以为是网络拓扑有问题,最后才发现是这个问题。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

//Add by Leo Wang
#define MICROCHIP_CONTROL_REG  0x1F

#define MICROCHIP_SPEED_MASK  0x0070
#define MICROCHIP_SPEED_1000  0x0040
#define MICROCHIP_SPEED_100   0x0020
#define MICROCHIP_SPEED_10    0x0010


#define MMD_FUNCTION_DATA           0x4000

static u32_t read_mmd_register(XEmacPs *InstancePtr, u32 PhyAddress, u32 devadd,
			 u32 RegisterNum, u16 *PhyDataPtr)
{
	u32_t phyregtemp;
	u32_t RetStatus;

	XEmacPs_PhyWrite(InstancePtr, PhyAddress, PHY_REGCR, devadd);
	XEmacPs_PhyWrite(InstancePtr, PhyAddress, PHY_ADDAR, RegisterNum);
	XEmacPs_PhyWrite(InstancePtr, PhyAddress, PHY_REGCR, devadd | MMD_FUNCTION_DATA);
	RetStatus = XEmacPs_PhyRead(InstancePtr, PhyAddress, PHY_ADDAR, (u16_t *)&phyregtemp);
	if (RetStatus != XST_SUCCESS) {
		return XST_FAILURE;
	}

	*PhyDataPtr= phyregtemp;
	return XST_SUCCESS;
}

static u32_t write_mmd_register(XEmacPs *InstancePtr, u32 PhyAddress, u32 devadd,
		  u32 RegisterNum, u16 PhyData)
{
	XEmacPs_PhyWrite(InstancePtr, PhyAddress, PHY_REGCR, devadd);
	XEmacPs_PhyWrite(InstancePtr, PhyAddress, PHY_ADDAR, RegisterNum);
	XEmacPs_PhyWrite(InstancePtr, PhyAddress, PHY_REGCR, devadd | MMD_FUNCTION_DATA);
	XEmacPs_PhyWrite(InstancePtr, PhyAddress, PHY_ADDAR, PhyData);

	return XST_SUCCESS;
}

#define KSZ9131RN_MMD_COMMON_CTRL_REG	2
#define KSZ9131RN_RXC_DLL_CTRL		0x4c   //2.76
#define KSZ9131RN_TXC_DLL_CTRL		0x4d   //2.77
#define MICROCHIP_DLL_DELAY_NOT_USED	0x1000  //bit12 bypass rxdll/txdll


static u32_t get_Microchip_phy_speed(XEmacPs *xemacpsp, u32_t phy_addr)
{
	u16_t control;
	u16_t status;
	u16_t status_speed;
	u32_t timeout_counter = 0;
	u32_t temp_speed;
	u32_t RetStatus;

	xil_printf("Start PHY autonegotiation \r\n");

	XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
	XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control | IEEE_CTRL_RESET_MASK);

	sleep(1);

	RetStatus = XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
	if (RetStatus != XST_SUCCESS) {
		xil_printf("Error during reset \n\r");
		return XST_FAILURE;
	}

	//RGMII_ID SETUP

#if 0
	// --> RX
	RetStatus = read_mmd_register(xemacpsp, phy_addr, KSZ9131RN_MMD_COMMON_CTRL_REG, KSZ9131RN_RXC_DLL_CTRL, &control);
	if (RetStatus != XST_SUCCESS) {
		xil_printf("Error setting RX delay\n\r");
		return XST_FAILURE;
	}
	control &= ~MICROCHIP_DLL_DELAY_NOT_USED;
	write_mmd_register(xemacpsp, phy_addr, KSZ9131RN_MMD_COMMON_CTRL_REG, KSZ9131RN_RXC_DLL_CTRL, control);
#endif
#if 1
	//  --> TX
	RetStatus = read_mmd_register(xemacpsp, phy_addr, KSZ9131RN_MMD_COMMON_CTRL_REG, KSZ9131RN_TXC_DLL_CTRL, &control);
	if (RetStatus != XST_SUCCESS) {
		xil_printf("Error setting TX delay\n\r");
		return XST_FAILURE;
	}
	control &= ~MICROCHIP_DLL_DELAY_NOT_USED;
	write_mmd_register(xemacpsp, phy_addr, KSZ9131RN_MMD_COMMON_CTRL_REG, KSZ9131RN_TXC_DLL_CTRL, control);
#endif

	//REG4 10/100/1000M
	XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &control);
	control |= IEEE_ASYMMETRIC_PAUSE_MASK;
	control |= IEEE_PAUSE_MASK;
	control |= ADVERTISE_100;
	control |= ADVERTISE_10;
	XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, control);

	XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET,
					&control);
	control |= ADVERTISE_1000;
	XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET,
					control);

	//REG0 1.自动协商使能 2.自动协商复位
	XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
	control |= IEEE_CTRL_AUTONEGOTIATE_ENABLE;
	control |= IEEE_STAT_AUTONEGOTIATE_RESTART;
	XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control);


	//读REG1状态寄存器
	XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);

	xil_printf("Waiting for PHY to complete autonegotiation.\r\n");

	//根据bit5判断协商是否完成,没完成就一直等待,直到30秒超时
	while ( !(status & IEEE_STAT_AUTONEGOTIATE_COMPLETE) ) {
		sleep(1);
		timeout_counter++;

		if (timeout_counter == 30) {
			xil_printf("Auto negotiation error \r\n");
			return XST_FAILURE;
		}
		XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
	}
	xil_printf("autonegotiation complete \r\n");

	//主要是修改这个速度寄存器的解析
	XEmacPs_PhyRead(xemacpsp, phy_addr, MICROCHIP_CONTROL_REG,
					&status_speed);
	xil_printf("MICROCHIP_CONTROL_REG = 0x%.4x \r\n", status_speed);
	if (0 == (status_speed & 0x0001)) {
		temp_speed = status_speed & MICROCHIP_SPEED_MASK;

		if (temp_speed == MICROCHIP_SPEED_1000)
			return 1000;
		else if(temp_speed == MICROCHIP_SPEED_100)
			return 100;
		else
			return 10;
	}

	return XST_FAILURE;
}

寄存器0x1F说明如下:
在这里插入图片描述

3. 重新测试

运行结果:
正常识别到phy速度,我在电脑端用的是usb转百兆网卡,点对点方式连接的开发板,因此识别出来的速度是100M。

如果连到路由器这个值有可能是100或者1000。

现在10M网卡基本见不到了,如果显示是10大概率还是工作不正常,需要另行分析。

如果有多个网卡,windows下用-S(srcaddr的意思)来指定源网卡ip,linux下改成-I(interface)
192.168.1.100是电脑ip
192.168.1.10是开发板的ip

ping -S 192.168.1.100 192.168.1.10 -t

命令后的-t是一直ping,没有这个参数ping 4次就会停下来
在这里插入图片描述

在电脑端ping这个ip,正常ping通,说明phy确实已经正常工作。
在这里插入图片描述

四、网口灯工作状况说明

这个phy的led有点特殊,我开始以为寄存器没配置对,仔细查了手册,发现正常工作就是这样。

1.正常网口灯说明

我们正常的网口会有两个灯:
连接指示灯(绿色):连接指示灯亮就代表线路连接正常。

信号指示灯(黄色)
在连接指示灯亮的情况下,信号指示灯的含义如下:
a) 如果信号指示灯闪烁,代表信号正常,正在通信;
b) 如果信号指示灯灭,代表没有通信;
c) 如果信号指示灯长亮,代表网线短路。

而在这个板子
直接与电脑相连(100M):左边灯不亮,右边黄色闪烁。
连路由器(1000M):左边绿灯亮,隔几秒闪一下。右边灯不亮

2. 排查过程记录

先查RJ-45座的型号,ARJM11C7-502-KB-EW2,根据手册确定两个led各对应哪个io

https://abracon.com/Magnetics/ARJM11.pdf

根据手册和原理图,可以看出左边的灯对应的是Phy芯片的LED_LINK(LED2),右边的黄灯对应LED_Y(LED_ACT, LED1)

在phy手册里面有说明,在1000M情况下,LED2亮和闪烁。在100M的情况下,LED1常亮和闪烁。所以正常情况下,不会出现两个灯同时亮,只有1个灯会亮

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

再查Phy芯片手册
在这里插入图片描述
在这里插入图片描述

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

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

相关文章

Hadoop集群环境下HDFS实践编程过滤出所有后缀名不为“.abc”的文件时运行报错:java.net.ConnectException: 拒绝连接;

一、问题描述 搭建完Hadoop集群后,在Hadoop集群环境下运行HDFS实践编程使用Eclipse开发调试HDFS Java程序(文末有源码): 假设在目录“hdfs://localhost:9000/user/hadoop”下面有几个文件,分别是file1.txt、file2.tx…

两阶段提交协议三阶段提交协议

两阶段提交协议 分布式事务是指会涉及到操作多个数据库的事务,在分布式系统中,各个节点之间在物理上相互独立,通过网络进行沟通和协调。 XA 就是 X/Open DTP 定义的交易中间件与数据库之间的接口规范(即接口函数),交易…

使用Go语言实现RESTful API

RESTful架构是一种设计风格,用于构建网络应用程序的API。它基于HTTP协议,并使用不同的HTTP方法(如GET、POST、PUT、DELETE等)来处理不同的操作。在Go语言中,我们可以使用标准库中的net/http包来实现RESTful API。 下面…

不同阶数的巴特沃斯低通滤波器的空间域表示——数字图像处理

原理 巴特沃斯低通滤波器(Butterworth Low-Pass Filter)在频率域中的定义是明确的,但它在空间域中的表示不是直观的。这是因为巴特沃斯滤波器的形式是基于频率的,并且其空间域表示涉及到一个复杂的逆傅里叶变换,该变换…

Hive10_窗口函数

窗口函数(开窗函数) 1 相关函数说明 普通的聚合函数聚合的行集是组,开窗函数聚合的行集是窗口。因此,普通的聚合函数每组(Group by)只返回一个值,而开窗函数则可为窗口中的每行都返回一个值。简单理解,就是对查询的结果多出一列…

【Android】如何设置应用程序启动Activity(应用启动时显示的界面)

前言 在Android中&#xff0c;AndroidManifest.xml文件可以通过修改来设置应用启动时显示的界面&#xff0c;即启动Activity。 操作步骤 打开AndroidManifest.xml文件。 在文件中找到想要设置为启动Activity的<activity>元素。该元素通常在<application>元素内部…

【Linux Shell】3. 传递参数

文章目录 【 1. $n 调用单个参数 】【 2. \$*、\$ 引用全部参数 】【 3. 其他符号 】 【 1. $n 调用单个参数 】 在执行 Shell 脚本时&#xff0c;可以向脚本传递参数&#xff0c; 脚本内获取参数的格式为 $n&#xff0c;n 代表一个数字&#xff0c;1 为执行脚本的第一个参数&…

[Kubernetes]4. 借助腾讯云TKE快速创建Pod、Deployment、Service部署k8s项目

前面讲解了通过命令行方式来部署k8s项目,下面来讲讲通过腾讯云TKE来快速创建Pod、Deployment、Service部署k8s项目,云平台搭建Kubernetes可参考[Kubernetes]1.Kubernetes(K8S)介绍,基于腾讯云的K8S环境搭建集群以及裸机搭建K8S集群 一.通过腾讯云TKE创建集群 1.创建集群 参考上…

vue项目中的录屏插件recordrtc且带声音

vue项目中的录屏插件recordrtc且带声音 一、效果图二、安装插件三、直接上代码 一、效果图 其中窗口录屏不带声音&#xff0c;chrome标签和整个屏幕的录屏是带声音的 二、安装插件 npm i recordrtc 三、直接上代码 <template><div class"record-page">…

修改 docker /dev/shm 的大小

修改 docker /dev/shm 的大小 1&#xff0c;获取完整id&#xff1a; docker inspect 245| grep Id rootlynxi:~# docker inspect 245| grep Id"Id": "245ab167ed9a79873b31b3a38df2053870fe72f267c3c1a660df25c63e37e88b",2&#xff0c;修改 ShmSize&…

真机调试HarmonyOS应用报错

问题表现&#xff1a; 01/04 19:00:01: Launching com.example.simplevideo $ hdc shell am force-stop com.example.simplevideo $ hdc shell bm uninstall com.example.simplevideo $ hdc file send E:\harmony\SimpleVideo\entry\build\default\outputs\default\entry-defau…

Nginx 负载均衡集群 节点健康检查

前言 正常情况下&#xff0c;nginx 做反向代理负载均衡的话&#xff0c;如果后端节点服务器宕掉的话&#xff0c;nginx 默认是不能把这台服务器踢出 upstream 负载集群的&#xff0c;所以还会有请求转发到后端的这台服务器上面&#xff0c;这样势必造成网站访问故障 注&#x…

CISSP 第9章:安全脆弱性、威胁和对策

第九章 安全脆弱性、威胁和对策 9.1 评估和缓解安全脆弱性 9.1 硬件 处理器 执行类型 多任务处理&#xff1a; 同时处理两个或更多任务 多处理&#xff1a; 利用多个处理器完成一个应用程序的处理能力 多程序设计&#xff1a;通过操作系统对单个处理器上的两个任务进行协调&…

Vue开发中使用Element UI过程中遇到的问题及解决方案Missing required prop: “value”

一、vue中使用el-table的typeindex有时不显示序号 Table 表格 用于展示多条结构类似的数据&#xff0c;可对数据进行排序、筛选、对比或其他自定义操作。 当el-table元素中注入data对象数组后&#xff0c;在el-table-column中用prop属性来对应对象中的键名即可填入数据&…

CSS免费在线字体格式转换器 CSS @font-face 生成器

今天竟意外发现的一款免费的“网页字体生成器”&#xff0c;功能强大又好用~ 工具地址&#xff1a;https://transfonter.org/ 根据你设置生成后的文件预览&#xff1a; 支持TTF、OTF、WOFF、WOFF2 或 SVG字体格式转换生成&#xff0c;每个文件最大15MB。转换完成以后还会生成一…

“华为杯”杭州电子科技大学2023新生编程大赛---树

题目链接 Problem Description 给定一棵包含 n 个节点的带边权的树&#xff0c;树是一个无环的无向联通图。定义 xordist(u,v) 为节点 u 到 v 的简单路径上所有边权值的异或和。 有 q 次询问&#xff0c;每次给出 l r x&#xff0c;求 ∑rilxordist(i,x) 的值。 Input 测试…

IO进程线程Day4

1> 创建出三个进程完成两个文件之间拷贝工作&#xff0c;子进程1拷贝前一半内容&#xff0c;子进程2拷贝后一半内容&#xff0c;父进程回收子进程的资源 #include <myhead.h> //使用三个进程完成两个文件的拷贝工作 //两个子进程分别拷贝文件的上下两部分 //父进程回…

Azure Machine Learning - 人脸识别任务概述与技术实战

Azure AI 人脸服务提供了可检测、识别和分析图像中的人脸的 AI 算法。 人脸识别软件在许多不同情形中都十分重要&#xff0c;例如识别、无接触访问控制和实现隐私的人脸模糊。你可以通过客户端库 SDK&#xff0c;或者直接调用 REST API 使用人脸服务。 目录 一、人脸识别服务场…

AspectJ入门(二)— 应用

AspectJ便于调试、测试和性能调整工作。定义的行为范围从简单的跟踪到分析&#xff0c;再到应用程序内部一致性到测试。AspectJ可以干净地模块化这类功能&#xff0c;从而可以在需要时轻松地启用和禁用这些功能。 1 基础 本节将继续介绍AspectJ到一些基础功能&#xff0c;为后…

【量化金融】《证券投资学》吴晓求(第四版)(更新中)

这里写目录标题 第一篇 基本知识第1章 证券投资工具名词解释简答题 第2章 证券市场名词解释简答题 第二篇 基本分析第三篇 技术分析第四篇 组合管理第五篇 量化分析与交易策略 第一篇 基本知识 第1章 证券投资工具 名词解释 风险&#xff08;risk&#xff09; 未来结果的不…