上午去报道,结果得知下午比赛。还好提前一天把《黑神话:悟空》下好了。10点10分开始解压,到编译完着色器正常进入游戏已经是10点45了。就看了个过场动画,然后收拾行李准备去比赛。

然而回来也没能爽玩。一是手柄没带,键鼠操作依托;二是显卡还是带不动,虽然之前性能测试可以确保全高无光追60帧,但是实际进了游戏才发现是真的卡。只能拉低DLSS的渲染分辨率,但是画面及其模糊,看着跟老花眼一样,遂罢。等后面换了好一点的电脑再来罢。

前言

信诺达杯杯赛的总决赛是现场测试芯片。现场开题,现场测试。可以说,这是对临场发挥能力、自学能力和团队协作能力的一次完整的考验。

虽然是现场开题,但是在赛前可以通过阅读各类未见过的芯片技术手册来锻炼自己的分析能力。

赛题

本次决赛考察的是XD8255芯片。XD8255-2_XINLUDA(信路达)-XD8255-2中文资料

8255芯片是Intel公司生产的可编程并行I/O接口芯片,有3个8位并行I/O口。具有3个通道3种工作方式的可编程并行接口芯片(40引脚)。 其各口功能可由软件选择,使用灵活,通用性强。8255可作为单片机与多种外设连接时的中间接口电路。

这是一颗组合逻辑芯片,引脚非常多。比赛时看到信路达22页的全英文手册头都大了而且还有很多抽象的应用示例图

时间安排

我对自己是很不满意的,因为我感觉我并没能发挥出全力。

小队一共花了30分钟的时间读技术手册。之后花了10分钟的时间来排查板子和芯片的通道是否连接上。因为我们没有见过原理版,我们只能现场对着引脚一个一个进行测量。

在确认芯片通道设置正确后,我们花了整整30分钟的时间来尝试对芯片的总线进行读写。但是这本应该是在前面就已经完成的。随后,我花了30分钟使用Python自动生成了测试代码并进行测试。做完这一切后,只剩下20分钟了。

队友还在写静态参数测试的代码和图形文件,最后还要拼合在一起。而且,在将图形文件拼合后,发生了编译不过的情况。查看报错发现是IO设置错误,以及标号重复。

最终,我们也只测试出来一部分静态参数和mode0的功能测试。

驱动板分析

官方并未给出信诺达的数字通用驱动板的原理图。当时板子拿到手后,分析+调试还用了20min。

驱动板原理图 驱动板PCB图

测量数字芯片仅需要用到两侧的数字引脚。板子上有16组12位的拨码开关。左边四列右边四列,上下两行,覆盖了24个引脚。

三列中,有两列分别用于设置DPS和GND,只要将芯片对应电源引脚的拨码开关拨下,即可和ST3020的DPS或GND通道进行连接。

此外,在最上面还有一个二位拨码开关,用于将一个电容和DPS进行连接,可能是用于测量一些直流参数或者滤波吧。

后面有时间可能会试着去画一下驱动板吧。先鸽了

芯片分析

两个小时的时间还是非常紧张的。不过,现在想想,要是再给一个小时,应该就没问题了。因为,最难的部分——芯片读写的逻辑已经弄清楚了。

引脚定义

阅读技术手册可知:芯片的引脚分为四类:

  1. 供电引脚VDDGND
  2. 数据IO引脚PA/PB/PC,均为八位。其中PC较特殊,为4+4的形式。
  3. 总线IO引脚D,为八位。同时,它还可作为控制信号输入。
  4. 控制引脚A1/10nCS/nRD/nWRReset

当时非常傻逼,没有看清楚Reset引脚是低有效还是高有效,因此浪费了10分钟进行调试。

Reset是高有效!

静态参数

要测的基础静态参数当然有Pc、Icc、II、Io等。

功能分析

这颗芯片没有时钟,所有的输出输入完全依赖控制引脚和IO接口。因此,图形文件相对来说比较简单。

阅读技术手册可知,芯片的工作模式有三种:

  1. Basic Input/Output 基础输入输出
  2. Strobed Input/Output 闪烁输入输出(实际上是带有握手协议的输入输出)
  3. Bidirectional Bus 双向总线

依旧是从易到难,先看最简单的mode0。

mode0 基础输入输出

顾名思义:简单的输入输出,无需任何准备即可。

芯片内部的总线有寄存器,用于保存数据。当时就是卡在这一步,在Data端输入后直接去读写PA总线,结果自然是什么也没有。

正确的顺序应当是:先从A/B两组输入中选择一组进行数据输入,将数据写入Databus,随后再从Databus中读取到A/B端口。

本来应该是测试4x4=16种的,即ABCD四个端口之间的写入读出。鉴于时间有限,比赛中只写了A写A读、B写B读、C写C读的图形文件,而且最后一种还未能正常通过测试。

之后想想,可能是因为D作为控制位时未能正确设置C的4+4两组数据的传输方式。

为了更高效地生成图形文件,我使用了Python。为什么不用C?真不熟。我可不想搞一堆复杂的字符串操作。论简易程度还得是Python这种弱类型语言。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
io_width = 8

pa = 0
pb = 2 ** io_width - 1
pc = 0
data = 0b10101001

data_num = str(bin(data)[2:]).zfill(8)
output_data = str(bin(data))[2:].zfill(8).replace("0", "L").replace("1", "H")

pb_num = str(bin(pb)[2:]).zfill(8)
pc_num = str(bin(pc)[2:]).zfill(8)

print((" {AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDD AA R C R W}"))
print(f" INC (XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XX X X X X)")
print(f" INC (XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XX 1 X X X)")
for pa in range(2 ** io_width):
pa_num = str(bin(pa)[2:]).zfill(8)
output_data = pa_num.replace("0", "L").replace("1", "H")
print(f" INC ({pa_num} XXXXXXXX XXXXXXXX XXXXXXXX 00 0 0 0 1)")
print(f" INC ({output_data} XXXXXXXX XXXXXXXX XXXXXXXX 00 0 0 1 0)")
print(" HALT (HHHHHHHH XXXXXXXX XXXXXXXX XXXXXXXX 00 0 0 1 0)")
print(" {PA Finished}\n\n")

for pb in range(2 ** io_width):
pb_num = str(bin(pb)[2:]).zfill(8)
output_data = pb_num.replace("0", "L").replace("1", "H")
print(f" INC (XXXXXXXX {pb_num} XXXXXXXX XXXXXXXX 01 0 0 0 1)")
print(f" INC (XXXXXXXX {output_data} XXXXXXXX XXXXXXXX 01 0 0 1 0)")
print(" HALT (XXXXXXXX HHHHHHHH XXXXXXXX XXXXXXXX 01 0 0 1 0)")

print(" {PB Finished}\n\n")

for pc in range(2 ** io_width):
pc_num = str(bin(pc)[2:]).zfill(8)
output_data = pc_num.replace("0", "L").replace("1", "H")
print(f" INC (XXXXXXXX XXXXXXXX {pc_num} XXXXXXXX 10 0 0 0 1)")
print(f" INC (XXXXXXXX XXXXXXXX {output_data} XXXXXXXX 10 0 0 1 0)")
print(" HALT (XXXXXXXX XXXXXXXX HHHHHHHH XXXXXXXX 10 0 0 1 0)")
print(" {PC Finished}\n\n")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// CON-TEST
SET_DPS(2, 0, V, 20, MA);
PMU_CONDITIONS(FIMV, -0.1, MA, 2, V);
if (!PMU_MEASURE("1-6,8-20,29-33,35-48", 20, "CON_", V, -0.1, -1.9))
BIN(1);

// VDD
SET_DPS(2, 5, V, 50, MA);

// VIH/VIL/VOH/VOL
SET_INPUT_LEVEL(5, 0);
SET_OUTPUT_LEVEL(3, 0.4);

// WAVE FORMAT
SET_PERIOD(500);
SET_TIMING(100, 200, 200);
FORMAT(NRZ0, "1-6,8-20,29-33,35-48");

// mode 0, abc to bus
if (!RUN_PATTERN("A2Bus", 21, 1, 0, 0))
BIN(2);
if (!RUN_PATTERN("B2Bus", 22, 1, 0, 0))
BIN(2);
if (!RUN_PATTERN("C2Bus", 23, 1, 0, 0))
BIN(2);

mode1 带有握手协议的输入输出

mode1是带有握手协议的输入输出。在这种模式下,PC的八位被用作控制信号的输入输出。在手册第13页的汇总表里有详细的说明。

不同模式下的端口定义

以下代码与方案未经过实机验证,仅供参考。

后记

2024.08.17

提前把键盘洗干净了,准备带上。更换Tab键的轴体为凯华Box白,清脆悦耳。自动补全的时候很爽。青轴虽然也碎响脆,但是手感不如Box白舒服,而且有点晃。

2024.08.21

轻松拿下保底,只能说意料之中吧。总共拿了60分居然还能拿60分。最高的那一队测出来的得分是160分,应该是几乎所有的静态参数+功能测试都测试出来了。这也没啥办法,毕竟学校没这门课程,我们又算半路出家的。能走到这里,我觉得比以往强太多了。至少,在这个杯赛,我们队是学校历史上的第一。

和拿到国一的国防科大队伍聊了一下,原来他们大一微机课学过这颗芯片。真题都做过了,你不拿奖谁拿奖?只能说运气不如人,认了。

2024.08.22

猿神,启动!

回去拿室友的3070 AD OC爽玩。直接串流到本地电脑,2K+全高+低光追稳60帧。不过GPU拉到93%,VRAM拉到88%,物尽其用了。话说Steam那个局域网文件传输确实方便,WIFI6内网互拷能跑到500M。要是有线的话应该轻松能跑满网口吧。

参考资料

《微机原理与接口技术(第3版)》,周明德、张晓霞、兰方鹏著

第八章已经讲的很详细了。