⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cs8900a.asm

📁 在51单片机上用汇编实现的TCP/TP协议网络通信
💻 ASM
📖 第 1 页 / 共 2 页
字号:
;++++++++++++++++++++++++++++++++++++++++++++++
;
; 功能介绍
;
; 1. 采用I/O访问的方式读取数据
;    Port1=>SD
;    Port3 P3.0-P3.3=>SA
;    P3.4=>AEN P3.5=>IOW P3.6=>IOR P3.7=>INTR
; 2. 可以接收和发送帧
;
; 3. 实现了ARP报文传输
; 4. ARP应答
; 5. 实现了ICMP协议
; 6. 可以被其他网络中的主机Ping到
; 7. 实现了UDP协议
;
; 定义数据总线、地址总线以及控制线
CDB 	EQU 	P1
CAB 	EQU 	P3
; 控制线为P3.4-P3.7
AEN 	EQU 	P3.4
IOR  	EQU 	P3.5
IOW 	EQU 	P3.6
INTR 	EQU 	P3.7
;
; 定义本机的IP和MAC地址
; IP 202.113.24.47
IP1	EQU	202
IP2	EQU	113
IP3	EQU	24
IP4	EQU	47
; MAC 01-23-45-67-89-0A
MAC0	EQU	01H
MAC1	EQU	23H
MAC2	EQU	45H
MAC3	EQU	67H
MAC4	EQU	89H
MAC5	EQU	0AH
;
; 访问CS8900A内部寄存器需要使用下面8个I/O口
PortRxTxData	EQU 	0F0H
PortRxTxData	EQU 	0F2H		; 未用到
PortTxCmd	EQU 	0F4H
PortTxLength	EQU 	0F6H
PortISQ 	EQU 	0F8H
PortPtr		EQU 	0FAH
PortData	EQU	0FCH
PortData1	EQU	0FEH	; 未用到
;
; 各个寄存器的地址
ppEISA		EQU	0000H
ppProdID	EQU	0002H
ppIOBase	EQU	0020H
ppIntNum	EQU	0022H
ppRxCfg		EQU	0102H
ppRxCtl		EQU	0104H
ppTxCfg		EQU	0106H
ppBufCfg	EQU	010AH
ppLineCtl	EQU	0112H
ppSelfCtl	EQU	0114H
ppBusCtl	EQU	0116H
ppTestCtl	EQU	0118H
ppISQ		EQU	0120H
ppRxEvt		EQU	0124H
ppTxEvt		EQU	0128H
ppBufEvt	EQU	012CH
ppRxMiss	EQU	0130H
ppTxCol		EQU	0132H
ppLineSt	EQU	0134H
ppSelfSt	EQU	0136H
ppBusSt		EQU	0138H
ppTxCmd		EQU	0144H
ppTxLength	EQU	0146H
ppIndAddr	EQU	0158H
ppIndAdds	EQU	015AH
ppIndAddt	EQU	015CH
ppRxStat	EQU	0400H
ppRxStH		EQU	04H
ppRxStL		EQU	00H
ppRxLength	EQU	0402H
ppRxFrame	EQU	0404H
ppTxFrame	EQU	0A00H
;
; 定义各寄存器的值
Slfctlrst	EQU	00C0H
LineCtl		EQU	4015H
TestCtl		EQU	8017H
BusCtl		EQU	8017H
Rxcfg		EQU	7103H
Txcfg		EQU	8FC0H
Rxctl		EQU	0D85H
Rxoka		EQU	0100H
Rxinda		EQU	0400H
Rxbsta		EQU	0800H
SKIP		EQU	0140H
Txcmd		EQU	0C0H
;
; 设置51中的一些参数
; 设置堆栈
Sp_base		EQU	70H
; 保存读取数据的高位
TempH		EQU	07H
; 保存读取数据的低位
TempL		EQU	06H
; 计算校验和时使用的变量
cnt_low		EQU	05H
cnt_mid		EQU	04H
cnt_hi		EQU	03H
;
; 设置以太网帧的有关地址及偏移量
PacketRAM	EQU		10H	; 放置帧起始位置10H
MaxPackLen	EQU		96	; 设置帧最大长度为96字节
; 设置以太网帧相关字段
; 帧长度
pktLenH		EQU		00H	; 高位
pktLenL		EQU		01H	; 低位
; 帧目的地址
pktDest0H		EQU		02H
pktDest0L		EQU		03H
pktDest1H		EQU		04H
pktDest1L		EQU		05H
pktDest2H		EQU		06H
pktDest2L		EQU		07H
; 帧的源地址
pktSrc0H		EQU		08H
pktSrc0L		EQU		09H
pktSrc1H		EQU		0AH
pktSrc1L		EQU		0BH
pktSrc2H		EQU		0CH
pktSrc2L		EQU		0DH
; 帧类型
pktTypeH		EQU		0EH
pktTypeL		EQU		0FH
;
; ARP部分
; 硬件类型字段,0001H表示10M以太网
arp_hwtype		EQU		10H
; 协议类型字段,0806H表示ARP协议
arp_ptype		EQU		12H
; 硬件地址长度,应为6
arp_hwlen		EQU		14H
; 协议地址长度,应为4
arp_prlen		EQU		15H
; 操作码字段,ARP请求为0001H,ARP应答为0002H
arp_op		EQU		16H
; 发送端硬件地址,应为6字节
arp_sha		EQU		18H
; 发送端协议地址,应为4字节
arp_spa		EQU		1EH
; 接收端硬件地址,应为6字节
arp_tha		EQU		22H
; 接收端协议地址,应为4字节
arp_tpa		EQU		28H
;
; IP部分
; 版本字段内容为4,IP首部长度应为14H
ip_VerLen		EQU		10H
; TOS服务类型字段
ip_TOS		EQU		11H
; 总长度字段
ip_Len		EQU		12H
; 标识字段
ip_ID			EQU		14H
; 段偏移量及标志位
ip_Fragoff		EQU		16H
; TTL生存时间字段
ip_ttl			EQU		18H
; 协议类型:01H为ICMP报文,11H为UDP报文
ip_proto		EQU		19H
; 校验和字段
ip_cksum		EQU		1AH
; 源IP地址,4字节
ip_src		EQU		1CH
; 目的IP地址,4字节
ip_dst		EQU		20H
; 数据段
ip_data		EQU		24H
;
; ICMP部分
; ICMP类型字段,00H为回显应答,08H为回显请求
ic_type		EQU		ip_data
; ICMP代码字段,应为0
ic_code		EQU		ic_type+1
; ICMP检验和
ic_cksum		EQU		ic_code+1
; ICMP回显标识字段
ic_id			EQU		ic_cksum+2
; ICMP回显序列号字段
ic_seq		EQU		ic_id+2
;
; UDP部分
; 源端口字段
u_src			EQU		ip_data
; 目的端口字段
u_dst			EQU		u_src+2
; UDP总长度
u_len			EQU		u_dst+2
; UDP校验和
u_cksum		EQU		u_len+2
; UDP数据
u_data		EQU		u_cksum+2
;
; IP类型转换表
IPT_ICMP	EQU	01H
IPT_TCP		EQU		06H
IPT_UDP		EQU		11H
;
;***************************************
;               程序开始
;***************************************
org	0
Ljmp	Start
Start:
; 对CS8900A复位
LCALL	ResetChip
; 对CS8900A初始化
LCALL	InitChip
LCALL VWAIT
; 开始工作
Loop:
; 设置堆栈指针
MOV	A,#SP_BASE
MOV	SP,A
; 通过直接读取RxEvt寄存器的第8位数据判断
MOV	TempL,#00H
MOV	TempH,#00H
ACALL	RegRead
DW	ppRxEvt
MOV	A,TempH
ANL	A,#01H
JZ	Loop
; 发现有数据就接收
Lcall	Receiver
; 对接收到的数据进行判断
MOV	R0,#PacketRAM+pkTypeH
; 判断是IP还是ARP
MOV	A,@R0
CJNE	A,#08H,Loop
MOV	R0,#PacketRAM+pkTypeL
MOV	A,@R0
CJNE	A,#06H,PcsRxIp
; 如果是0806H则为ARP
LCALL	DoARP
; 判断是否是IP
PcsRxIp:
如果不是0800H,忽略该帧
CJNE	A,#00H,PcsRxQuit
LCALL	DoIP
PcsRxQuit:
LJMP	Ignore_Frame
;************************************
;                 DoARP
; 当发现一个有效的ARP请求时就发送应答
;************************************
DoARP:
MOV	R0,#PacketRAM+arp_hwtype
; 得到ARP包
MOV	R1,#28
LCALL	LoadPacket
MOV	R0,#PacketRAM+arp_hwtype
MOV	A,@R0
CJNE	A,#00,DoARPbad
MOV	R0,#PacketRAM+arp_hwtype+1
MOV	A,@R0
CJNE	A,#01,DoARPbad
MOV	R0,#PacketRAM+arp_prtype
MOV	A,@R0
CJNE	A,#08,DoARPbad
MOV	R0,#PacketRAM+arp_prtype+1
MOV	A,@R0
CJNE	A,#00,DoARPbad
MOV	R0,#PacketRAM+arp_hwlen
MOV	A,@R0
CJNE	A,#06,DoARPbad
MOV	R0,#PacketRAM+arp_prlen
MOV	A,@R0
CJNE	A,#04,DoARPbad
MOV	R0,#PacketRAM+arp_op
MOV	A,@R0
CJNE	A,#00,DoARPbad
MOV	R0,#PacketRAM+arp_op+1
MOV	A,@R0
CJNE	A,#01,DoARPbad
MOV	R0,#PacketRAM+arp_tpa
MOV	A,@R0
CJNE	A,#IP1,DoARPbad
MOV	R0,#PacketRAM+arp_tpa+1
MOV	A,@R0
CJNE	A,#IP2,DoARPbad
MOV	R0,#PacketRAM+arp_tpa+2
MOV	A,@R0
CJNE	A,#IP3,DoARPbad
MOV	R0,#PacketRAM+arp_tpa+3
MOV	A,@R0
CJNE	A,#IP4,DoARPbad
SJMP	SendARP
DoARPbad:
RET
SendARP:
MOV	R0,#PacketRAM+pktLenH
; 设置帧长度
MOV	@R0,#0
INC	R0
MOV	@R0,#42
LCALL	EthResp
; 交换MAC地址
MOV	R0,#PacketRAM+arp_op+1
; ARP响应 00 02
MOV	@R0,#02H
MOV	R0,#PacketRAM+arp_sha
; 源MAC地址写入目的MAC地址
MOV	R0,#PacketRAM+arp_tha
MOV	A,@R0
MOV	@R1,A

INC	R0
INC	R1
MOV	A,@R0
MOV	@R1,A

INC	R0
INC	R1
MOV	A,@R0
MOV	@R1,A

INC	R0
INC	R1
MOV	A,@R0
MOV	@R1,A

INC	R0
INC	R1
MOV	A,@R0
MOV	@R1,A

INC	R0
INC	R1
MOV	A,@R0
MOV	@R1,A
; 源IP地址写入目的IP地址
INC	R0
INC	R1
MOV	A,@R0
MOV	@R1,A

INC	R0
INC	R1
MOV	A,@R0
MOV	@R1,A

INC	R0
INC	R1
MOV	A,@R0
MOV	@R1,A

INC	R0
INC	R1
MOV	A,@R0
MOV	@R1,A
; 重写发送方MAC地址
MOV	R0,#PacketRAM+arp_sha
MOV	@R0,#MAC0
INC	R0
MOV	@R0,#MAC1
INC	R0
MOV	@R0,#MAC2
INC	R0
MOV	@R0,#MAC3
INC	R0
MOV	@R0,#MAC4
INC	R0
MOV	@R0,#MAC5
INC	R0
; 重写发送方IP地址
MOV	@R0,#IP1
INC	R0
MOV	@R0,#IP2
INC	R0
MOV	@R0,#IP3
INC	R0
MOV	@R0,#IP4
LCALL	TxPacket
RET
;************************************
;                 DoIP
;************************************
DoIP:
MOV	R0,#PacketRAM+ip_verlen
; 得到IP头
MOV	R1,#20
LCALL	LoadPacket
MOV	R0,#PacketRAM+ip_proto
MOV	A,@R0
CJNE	A,#IPT_ICMP,No_ICMP
LJMP	DoICMP
No_ICMP:
CJNE	A,#IPT_UDP,No_UDP
LJMP	DoUDP
No_UDP:
; 忽略该帧
RET
;************************************
;                 DoICMP
; 当发现一个有效的ICMP请求时就发送应答
;************************************
DoICMP:
LCALL	ChkPktLen
JNC	DoICMPcnt
RET
DoICMPcnt:
MOV	R0,#PacketRAM+pktLenL
; 将数据包中ICMP部分存入PacketRAM中
MOV	A,@R0
CLR	C
SUBB	A,#34
; 14+20=34 以太网头14个字节,IP头20个字节
MOV	R1,A
MOV	R0,#PacketRAM+ic_type
; 检查ICMP Echo是否为08(Response)
MOV	A,@R0
CJNE	A,#08H,QuitICMP
; 交换以太网帧头地址
LCALL	EthResp
; 交换IP头地址
LCALL	IpResp
; 清校验和
MOV	R0,#PacketRAM+ic_cksum
MOV	@R0,#0
INC	R0
MOV	@R0,#0
; 改变ICMP类型
MOV	R0,#PacketRAM+ic_type
MOV	@R0,#0
; 改变ICMP Echo
MOV	R0,#PacketRAM+ic_code
MOV	@R0,#0
; 计算校验和
MOV	R0,#PacketRAM+ip_len+1
MOV	A,@R0
MOV	A,#20
MOV	R1,A
MOV	R0,#PacketRAM+ic_type
LCALL	CkSum
MOV	R0,#PacketRAM+ic_cksum
MOV	@R0,TempH
INC	R0
MOV	@R0,TempL
LCALL	TxPacket
QuitICMP:
RET
;************************************
; 交换源和目地的MAC地址
;************************************
EthResp:
; 把源MAC地址放入目的MAC地址
MOV	R0,#PacketRAM+pktSrc0H
MOV	R1,#PacketRAM+pktDest0H
MOV	A,@R0
MOV	@R1,A

INC	R0
INC	R1
MOV	A,@R0
MOV	@R1,A

INC	R0
INC	R1
MOV	A,@R0
MOV	@R1,A

INC	R0
INC	R1
MOV	A,@R0
MOV	@R1,A

INC	R0
INC	R1
MOV	A,@R0
MOV	@R1,A

INC	R0
INC	R1
MOV	A,@R0
MOV	@R1,A
; 把本机的MAC放入源MAC地址
MOV	R0,#PacketRAM+pktSrc0H
MOV	@R0,#MAC0
INC	R0
MOV	@R0,#MAC1
INC	R0
MOV	@R0,#MAC2
INC	R0
MOV	@R0,#MAC3
INC	R0
MOV	@R0,#MAC4
INC	R0
MOV	@R0,#MAC5
INC	R0
RET
;************************************
;                 DoUDP
;************************************
DoUDP:
LCALL	ChkPktLen
JNC	UDP
RET
UDP:
; UDP头
MOV	R0,#PacketRAM+u_src
MOV	R1,#8
LCALL	LoadPacket
; 检查端口是否为100
MOV	R0,#PacketRAM+u_dst
MOV	A,@R0
ADD	A,#0
JZ	UDPhOK
UnUDP:
LJMP	Ignore_Frame
UDPhOK:
INC	R0
MOV	A,@R0
CJNE	A,#64,UnUDP
; 发送回数据
MOV	R0,#PacketRAM+u_len+1
MOV	A,@R0
CLR	C
SUBB	A,#8
MOV	R1,A
MOV	R0,#PacketRAM+u_data
LCALL	LoadPacket
;LCALL	Debug
LCALL	EthResp
LCALL	IPResp
; 先计算UDP部分的校验和
MOV	R0,#PacketRAM+u_src    ; 交换端口号
MOV	A,@R0
MOV	R0,#PacketRAM+u_dst
MOV	A,@R0
MOV	R0,#PacketRAM+u_src+1
MOV	A,@R0
MOV	R0,#PacketRAM+u_dst+1
MOV	A,@R0
MOV	R0,#PacketRAM+u_src
MOV	@R0,A
MOV	R0,#PacketRAM+u_src+1
MOV	@R0,A
; 在收到的数据后加上自己的字符串"Hello World!"
MOV	R0,#PacketRAM+u_len+1
MOV	A,@R0

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -