📄 cs8900a.asm
字号:
;++++++++++++++++++++++++++++++++++++++++++++++
;
; 功能介绍
;
; 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 + -