为什么魂斗罗只有128KB却能实现那么长的剧情有答案了
PPU
- 首发公号:Rand_cs
本文继续讲述 NES 的基本原理,承接上文的 CPU,本文来讲述 PPU,较为复杂,慢慢来看。例子基本都是使用的魂斗罗,看完本文相信对那问题“为什么魂斗罗只有128KB却可以实现那么长的剧情”有一定答案。废话不多说,直接来看,先是 PPU 的地址空间部分。
地址空间
PPU 有自己的总线,再来看看这张图:
可以看出通过 PPU 总线能够访问到的地址空间主要由三部分组成:PatternTable, NameTable, Pallete,其中 PatterTable 是映射到卡带里的 CHR
这里说明一下,关于上图前两篇文章有错,PatterTable 是在 NameTable 前面的,这里更正一下,公众号似乎不支持修改图片,我在前文标注一下吧。
有着大致概念之后,来看具体的空间布局,关于这,任天堂给出的图还是很清晰的:
看了前文,应该会对这些名词比较熟悉,前文也简要介绍了这些 Tables,下面就来详细的看看:
PatterTable
PatternTable,映射到卡带的 CHR,CHR 可能是 ROM,也可能是个 RAM。
PatternTable,中文名叫图案表,故名思意,里面存放的是游戏使用到的图案,一个图案称为一个 tile。NES 游戏不论背景还是角色等精灵都是由一个个的 tile 组成。一个 tile
8
×
8
8 \times8
8×8 像素,NES 游戏屏幕大小为
256
×
240
256 \times 240
256×240 像素,所以由
32
×
30
32 \times 30
32×30 个 tile 组成(这里相当于算的是背景由这么多个 tile 组成,精灵的话要另算)。
由上图可以看出,有两个图案表,一个图案表 4KB,图案表总共占 8KB。但其实一个 NES 游戏的图案表可能不止两个,总大小可能会超过 8KB,但 PPU 对于 PatternTable 这部分能寻址到的就只有 8KB,所以在某一时段,PPU 最多也就支持 2 个 PatternTable,那我想用其他的 PatternTable 怎么办?这就是前文简要提到过的 Mapper 来干这事了,游戏代码逻辑控制 Mapper 映射当前的地址空间映射到 CHR 里的哪一个 PatterTable
这里我们不讨论那么多,就当 2 个 PatternTable 来讲解说明。PatternTable 里面存放的到底是什么?存放的就是一个个图案 tile,看个例子,emmm 前面举了太多的超级马里奥的例子,这里来看个魂斗罗的例子:
这里不要关注颜色,颜色是我专门这么设置的,感官上要容易辨认一些。这些图案看着还挺清楚像那么一回事是吧(这是
8
×
16
8 \times 16
8×16 模式下的样子,这模式后面讲述精灵的时候详述,主要是这种模式下 PatternTable 好辨认些)。
网传魂斗罗这游戏有 128KB,我这上面 .nes 格式的文件有 129KB,也都差不多,相对于一般的 NES 有些来说算是大游戏了,它的 PatterTable 就有多个,这里我只是截取的游戏开始那一段使用的图案表。
由上可以看出一个 PatternTable 是一个个图案也就是 tile 组成,一共由 256 个 tile 组成,这里我们可以简单计算一下:
一个 PatternTable 4KB,那么一个 tile 就是
4
K
B
/
256
=
16
B
4KB / 256 = 16B
4KB/256=16B
一个 tile
8
×
8
=
64
像
素
8 \times 8 = 64 像素
8×8=64像素,一个像素使用
16
B
/
64
=
2
b
i
t
16B / 64 = 2bit
16B/64=2bit
这 2bit 信息是什么?这 2bit 就是颜色信息的一部分,它们来构成了图案。在
8
×
8
8 \times 8
8×8 的像素中,通过“点亮”某些像素,“熄灭”某些像素,就可以形成图案,而这里所谓的“点亮”和“熄灭”就是通过赋予该像素 (00, 01, 10, 11) 来实现的,举个例子,GAME OVER 的 O 这个 tile:
这个图也是根据 FCEUX 这个模拟器截出来的,是没有上色的灰阶图像,可以看出,“O” 这个 tile 在 PatterTable 中的索引为 $03,地址为:$0030。
换个更本质一点的数字版本:
这就是 tile 的本质,”64 个 2bit“ 信息,仔细看的话,这 2bit 其实是当前这个 tile 使用的 Pallete 中 4 中颜色的索引(对照上图和上上图来看,后面 Pallete 部分还会详述)。
之所以将 ”64 个 2bit“ 打上引号,是因为实际存储时,将这 2bit 的高位和低位分开存储,先存储 64 个像素的低位,再存储 64 个像素的高位。
PatternTable 就先说到这,下面来看 NameTable。
NameTable
NameTable 是背景使用的,背景占据整个屏幕,也就是说背景由
256
×
240
256 \times 240
256×240 个像素
32
×
30
32 \times 30
32×30 个 tile 组成,这
32
×
30
32 \times 30
32×30 个 tile 得有一定的次序排列,才能组成正确的背景画面,而 NameTable 就是记录这个次序的。比如说第一个 tile 槽使用哪个 tile,第二个 tile 槽使用哪个 tile,NameTable 就记录这个信息,记录
32
×
30
32 \times 30
32×30 个 tile 槽的索引。
这里又来简单的计算一下:一个 PatternTable 里面有 256 个 tile,索引 256 个 tile 需要
8
b
i
t
=
1
B
8bit = 1B
8bit=1B,一屏有
32
×
30
=
960
32 \times 30 = 960
32×30=960 个 tile,所以 一个 NameTable 就需要 960B,这与 PPU 的地址空间布局图是一致的。
由那张 PPU 的地址空间布局图可以看出,PPU 支持 4 个 NameTable 的,但是实际物理上只支持 2 个 NameTable。这部分空间是位于 PPU 内部的,是 PPU 的内存,对比现在的显卡,这部分空间就是现存 VRAM,一共 2KB,它的大小只够支持 2 个物理 NameTable。但是有的卡带和其 Mapper 支持超过 2 个 NameTable,道理同上 PatternTable,多出来的这部分空间位于 卡带,由 Mapper 控制映射。这里我们不讨论那么复杂的情况,这里就讨论 PPU 原生支持的 2 个物理 NameTable / 4 个逻辑 NameTable。
这 4 个 NameTable 的逻辑布局如下图所示:
第一个 NameTable 位于左上角,第二个 NameTable 位于右上角,第三个 NameTable 位于左下角,第四个 NameTable 位于右下角。
每个 NameTable 就能存放一屏的 tile 索引,但实际上游戏预先存放了 2 屏的数据,另外两个 NameTable 就是镜像,镜像分为多种方式。
Horizontal
Horizontal Mirroring,水平镜像,示意图如下:
这种镜像是 1、2 NameTable 一样,3、4 NameTable 一样,左右一样,所以叫做水平镜像。使用这种镜像的一般是上下移动的游戏,常见就是 雷电、兵锋这类游戏,比如说 兵锋 刚开始时的 4 个 NameTable 如下所示:
Vertical
Vertical Mirroring,垂直镜像,图示如下:
道理同上,我就不具体解释了,一般左右移动的游戏使用这种镜像,比如我们熟悉的超级马里奥:
Single-Screen
Single 镜像,4 个 NameTable 是一样的东西,我没有仔细的去找使用这类镜像的游戏,而且 FCUEX 这个模拟器似乎不支持 Single 镜像。按我想的,使用这类镜像的游戏应该像是 大金刚 这类只有固定一屏的游戏,我看了下 大金刚 的 NameTable,的确只有 1 个 NameTable 有效,但却是水平镜像,另外的 NameTable 填充的无效数据并没有使用,如下所示:
Four-Screen
四屏镜像(感觉都不叫镜像了),示意图如下
从名字从示意图来看就知道,这 4 个 NameTable 都不相同,前面曾说,物理上 PPU 的 VRAM 只支持 2 个 NameTable,也就是说最多只有 2 个 NameTable 不同,那这里有 4 个 NameTable 都不同,那么需要额外的空间,这部分空间位于 卡带,同样的如前所述,只有部分游戏和卡带以及相应的 Mapper 才支持 Four-Screen 镜像。
使用这类镜像的游戏我没玩过,也就不拿具体的例子来说明了,资料显示有 公路之星2,圣铠传说 等游戏(emmm,听都没怎么听过)
那魂斗罗呢?魂斗罗是主要是横板游戏,使用的是垂直镜像,就算像是第三关上下移动,但也还是垂直镜像,只是同 大金刚 一样,只有一个 NameTable 有效:
这是魂斗罗第三关使用的 NameTable,垂直镜像,所以上下是相同的,但是右侧的两个 NameTable 并未使用,所以实际上只有 1 个 NameTable 有效。
NameTable 就先说到这,记住它是一屏背景 960 个 tile 的索引就行了,下面来看 AttributeTable。
AttributeTable
PPU 地址空间能够寻址到的内存有 2KB,支持 2 个 NameTable,花去
960
×
2
B
960 \times 2B
960×2B,还剩下
2
K
B
−
960
×
2
=
64
×
2
B
2KB - 960 \times 2 = 64 \times 2B
2KB−960×2=64×2B,简单来说 一个 960B 的 NameTable 搭配一个 64B 的 AtrributeTable。如果说 NameTable 是记录 960 个 tile 的位置关系,那么相应的 AtrributeTable 就记录这 960 个 tile 的一部分颜色信息,注意是一部分颜色信息(还有一部分是前面的 PatterTable)。
64B 要记录
256
×
240
256 \times 240
256×240 个像素
32
×
30
32 \times 30
32×30 个 tile 的颜色信息,虽然只有部分颜色信息,但听起来仍是有些不可思议,来看 NES 是如何做的:
每
4
×
4
4 \times 4
4×4 的 tile 使用 1B,将这
1
B
=
8
b
i
t
1B = 8bit
1B=8bit 再分成 4 份,每
2
×
2
2\times2
2×2 tile 分得 2bit。
所以 2bit 就控制着
2
×
2
=
4
2 \times 2 = 4
2×2=4 个 tile,
16
×
16
16 \times 16
16×16 大小的像素区域,挺抠门的是吧,节约到极致,至于这 2bit 信息表示什么以及 PatternTable 那 2bit 表示什么后面 Pallete 再说。这里记住 64B 的 AtrributeTable 管理着整个 NameTable 的一部分颜色信息,其 2bit 就控制着
2
×
2
=
4
2 \times 2 = 4
2×2=4 个 tile 的颜色信息。
NameTable 和 AtrributeTable 这两者是一一对应的,一个 NameTable 加上 一个 AtrributeTable 占据 1KB 的内存,PPU 的 VRAM 有 2KB,所以物理上支持 2 个这样的组合。
PPU 关于这部分的地址空间是从 $2000-$3FFF,总共 8KB,4 个逻辑上的 NameTable 和 AtrributeTable 加起来也才 4KB,后面的 4KB 是前面的镜像。
关于 NameTable 和 AttributeTable 就先说这么多,下面来看 Pallete 部分。
Pallete
Pallete 调色板,不同的 PPU 芯片使用的调色板可能不同,大体上说都是这个样子:
理论上可以总共可以使用 64 种颜色,但是从上图可以看出明显有些颜色是一样的,所以少于 64 种。这里再次说明,不同的 PPU 支持不同,这里说的一般情况。
怎么表示这些颜色呢?这就分颜色系统了,我们最熟悉的就是 RGB 颜色系统,R G B 分别表示红绿蓝三个颜色通道,每个分量的取值为 [0, 255],比如说 00 号颜色的 RGB 表示为 (84, 84, 84)。
由 PPU 地址空间布局图可知,Pallete 区域为 $3F00-$3F20,其后的空间是这部分区域的镜像。
存放在这部分空间的并不是颜色本身,比如说用 RGB 来表示颜色,这部分区域并不是存放 (R, G, B) 三元组,而是存放的是颜色索引 $00,$01 等等。
关于颜色部分抠门的地方来了,上面那个调色板可以看作是总的调色板,但实际使用的是 8 个子调色板,每个子调色板包括总调色板中的 4 中颜色。便于叙述后面我就称这子调色板为 Pallete。
1 个 Pallete 包括 4 种颜色,其实是包括 4 种颜色索引,“64” 种颜色只需要 5bit 来索引,但这里索引用
8
b
i
t
=
1
B
8bit = 1B
8bit=1B 来表示,还是很大方的没有像其他地方那么“抠门”。
8 个 Pallete,需要
8
×
4
=
32
B
8 \times 4 = 32B
8×4=32B,刚好与 $3F00-$3F20 对应。
抠门的地方又来了:这 8 个 Pallete 前四个是给背景使用的,对应 $3F00-$3F10,后四个给精灵使用,对应 $3F10-$3F20。
抠门的地方又又来了,每个 Pallete 的第 0 个(我习惯上将索引从0开始的起始元素叫做第 0 个)颜色是相同的,对于背景来说,这个颜色是通用的背景色,对于精灵来说,这个颜色就是透明色不渲染。
所以对于背景来说,可以使用
4
×
3
+
1
=
13
4 \times 3 + 1 = 13
4×3+1=13 种颜色,对于精灵来说
4
×
3
=
12
4 \times 3 = 12
4×3=12 种颜色。
比如魂斗罗刚开始时使用的 8 个调色板:
这里多说一句,$3F00——背景第 0 个 Pallete 的 00 号颜色存放通用背景色,$3F04/$3F08/$3F0C 分别为背景第 1/2/3 个 Pallete 的 00 号颜色,它们可以存放不同的颜色,但是 PPU 渲染的时候通常不会使用它们,而是直接使用 $3F00 中的通用背景色。$3F10/$3F14/$3F18/$3F1C 分别是精灵第 0/1/2/3 个 Pallete 的 00 号颜色,它们是 $3F00/$3F04/$3F08/$3F0C 的镜像。所以说其实一般情况下,这 8 个 Pallete 的 00 号颜色其实是一个色。
讲到这里,就可以来解决上述遗留的问题,对于某个 tile 来说,PatternTable 中记录的 2bit 和 AttributeTable 中记录的 2bit 分别表示什么。
AttributeTable 中记录的 2bit 表示某个 tile 使用哪个 Pallete,因为背景使用的 Pallete 只有 4 个,2bit 索引就足矣,PatternTable 中记录的 2bit 表示 tile 中的某像素使用这个 Pallete 中的哪个颜色,因为 Pallete 中有 “4” 种颜色,2bit 索引足矣。
这里还可以得到这样一个事实:AttributeTable 中 2bit 控制
2
×
2
2 \times 2
2×2 个 tile 使用的 Pallete,所以一个 tile,或者说相邻的 4 个 tile 最多就只能使用 4 种颜色。
这是魂斗罗开始场景的截图,每个蓝色方格代表
2
×
2
2 \times 2
2×2 个 tile,大致还是可以看出,每个蓝色方格里最多就使用了 4 种颜色。
OAM
前面讲述的 PatternTable, NameTable, AttributeTable, Pallete 都是 PPU 地址空间中可寻到的。PPU 还有一部分较大的内部的内存,并没有包含在 PPU 地址总线可寻到的地址空间里面。
这部分内存叫做 OAM,Object Attribute Memory,用作精灵的属性信息。这里的 Attribute 并非上述讲的 Attribute,这里的 Attribute 含义更加广泛。
OAM 总共 256B,支持 64 个精灵条目,也就是说每个精灵条目有 4B 的信息。这 4 字节,每个字节都有不同的含义:
Byte 0
第 0 个字节记录该精灵的 Y 坐标,以像素为单位,坐标示意图如下
Byte 1
tile 索引,表示该精灵使用的是哪个 tile
关于精灵使用的 tile 有两种模式,一种是
8
×
8
8 \times 8
8×8 模式,一种是
8
×
16
8 \times 16
8×16 模式,这由寄存器($2000) 控制。
顾名思义,
8
×
8
8 \times 8
8×8 模式的精灵宽 8 高 8,1 个 tile 组成,而
8
×
16
8 \times 16
8×16 模式的精灵宽 8 高 16 实际上由 2 个 tile 组成。
对于
8
×
8
8 \times 8
8×8 的精灵来说,Byte1 存储的 tile 索引就是该 tile 的索引。对于
8
×
16
8 \times 16
8×16 的精灵来说,Byte1 存储的 tile 索引为该精灵上侧的 tile 索引,而下侧的 tile 索引为
B
y
t
e
1
+
1
Byte1 + 1
Byte1+1。
来看个例子,来源于魂斗罗偶数关卡角色的一部分:
Byte 2
精灵的属性:
- bit0-1:该精灵使用的 Pallete
- bit2-4:未使用
- bit5:精灵与背景的优先级,0 表示该精灵在背景前面,1 表示该精灵在背景后面。
- bit6:水平翻转
- bit7:垂直翻转
使用哪个 Pallete 道理同背景,这里的 2bit 是在精灵的 4 个 Pallete 中索引。
精灵优先级在后面渲染的时候再说明,这里也可简单说一下:当精灵与背景重叠时,那么应该是渲染精灵的像素还是背景的像素呢?当两者的颜色都不是(透明色/通用背景色,也就是说颜色索引不是00) 时,如果精灵有背景前的优先级,那么渲染精灵的像素,如果精灵使背景后的优先级,那么渲染背景的像素。
翻转也是前面所说的抠门之一,有些 tile 只要翻转一下就可以当作另一个 tile 使用。在魂斗罗第二关有种跳来跳去的敌人:
可以看出它的下半身是对称的,这两个精灵信息如下:
可以看出 PatternTable 中 实际上并没有 “左腿” tile,只有 “右腿” 的,将 “右腿” 翻转一下作为 “左腿” 使用,所以这两个精灵其实都是索引为 $C2 和 $C3 的 tile 组成的。
至于垂直翻转也是同样的道理,具体的例子一时没找出来,就不举例说明了。
Byte 3
该精灵的 X 坐标,以像素为单位,道理同 Byte 0 不再多说。
由前文可知,视频都是一帧一帧的画面组成,帧与帧之间的空隙叫做 V_Blank,这段时间一开始 PPU 就触发 NMI 中断,然后 CPU 执行 NMI 中断服务程序。通常就是这个时间段将更新好的精灵信息搬运到 PPU 的 OAM 当中。CPU 的 RAM $200-$2FF 这 256 字节通常存放的是精灵信息,CPU 运行游戏代码对这 256 字节的精灵信息更新,然后在 V_Blank 期间将其搬运到 PPU 的 OAM 中。所以说每一帧画面最多支持 64 个精灵。
另外这里讲述的 OAM 全名叫做 Primary OAM Memory,还有 Secondary OAM Memory,实际上就是 Primary OAM Memory 的一个缓存,其大小支持 8 个精灵信息。前面我们说过,一帧画面有 240 条可见的 Scanline,这 Secondary OAM Memory 就是用来存放当前 Scanline 将要渲染的精灵信息。所以说一条 Scanline 上最多只有 8 个精灵。
本文就先说到这吧,也算是对魂斗罗有了个简单分析,这篇只是讲述了 PPU 关于内存的一部分,对于它的寄存器,如何滚屏,渲染等等还未讲述,涉及到 PPU 一些硬件,留待后面讲述。
了解到这其实可以进行简单地 NES 程序开发了,只不过关于 PPU 的内存如何访问,CPU 和 PPU 如何交互信息,比如如何搬运 OAM 数据等等都未讲述,emmm 我后面闲得话再讲述吧。
好了本文就到这里,有什么还请批评指正,也欢迎大家来同我讨论交流。
最后没事睡不着吐点槽,南北方差异真的大啊(主要是没暖气一时不习惯),我好像每次过年回家都会整感冒,特别这次从高风险地区回来,提前走的,刚走 2 天就爆发疫情,幸好提前走的,不然就回不了家就地过年了。然后进行居家隔离,话说刚好 14 天开始出现“症状”,感冒了,虽然核算检测不是那玩意儿,但太 TMD 巧了,刚好这时间点,而且还经都好不了,这就有点搞心态啊。
所以大家还是要多保重身体,身体至上,像我就是反面教材,现下凌晨 3 点,这么晚了就应该睡觉了,而我还在劈里啪啦的打字写文章,所以…所以…不来个赞和在看?
- 首发公号:Rand_cs
为什么魂斗罗只有128KB却能实现那么长的剧情有答案了的更多相关文章
- 技术之余。。。电吉他自弹 魂斗罗 solo
测试一下 ---恢复内容开始--- ---恢复内容结束---
- ios 游戏《魂斗罗》 AL文件素材破解
1.破解原理非常简单就是找png的8字节的前缀(baidu png 文件编码格式). 2.破解就图就可以看见了 3.这样一个个个的改是不是非常麻烦,所有我专门写了个py脚本在干这事!一步搞定! 源码如 ...
- cocos2dx中的格子地图TileMap
格子地图的优点: a.节省内存,我们知道对于一款游戏来说,如果以图片来作为地图的话,对于神庙逃亡,魂斗罗这样的场景很多,地图很长的游戏显然不现实,因为图片很占内存,但是这些游戏的地图有一个特点就是:重 ...
- 设计模式(一):“穿越火线”中的“策略模式”(Strategy Pattern)
在前段时间呢陆陆续续的更新了一系列关于重构的文章.在重构我们既有的代码时,往往会用到设计模式.在之前重构系列的博客中,我们在重构时用到了“工厂模式”.“策略模式”.“状态模式”等.当然在重构时,有的地 ...
- GJM : 常用网站收集 【不断更新中... ... ... 】
感谢您的阅读.喜欢的.有用的就请大哥大嫂们高抬贵手"推荐一下"吧!你的精神支持是博主强大的写作动力以及转载收藏动力.欢迎转载! 版权声明:本文原创发表于 [请点击连接前往] ,未经 ...
- 【Cocos2d-x 3.x】内存管理机制与源码分析
侯捷先生说过这么一句话 : 源码之前,了无秘密. 要了解Cocos2d-x的内存管理机制,就得阅读源码. 接触Cocos2d-x时, Cocos2d-x的最新版本已经到了3.2的时代,在学习Coco ...
- 《迷宫》特点分析之NABCD
项目名称:迷宫 特点之一:死亡模式 特点描述:在路径上设置一个个点,每个点作为一个障碍或加成点,设置各种类型陷阱来减少角色血量,还有加血和各种加成设置. N:普通迷宫形式单一,游戏过程较平淡,缺乏一定 ...
- mvc与三层结构
http://www.cnblogs.com/zhhh/archive/2011/06/10/2077519.html 又看到有人在问三层架构和MVC的关系,感觉这种问题有点教条化了.因为它们都在逻辑 ...
- reverse-daily(1)-audio_visual_receiver_code
本人第一篇随笔,就以一篇CTF逆向分析的文章开始吧! 链接:http://pan.baidu.com/s/1eS6xFIa 密码:u14d 因为re的分析比较琐碎,所以主要就挑一些重点东西来说. 据说 ...
- 工具武装的前端开发工程师 Mac 软件清单
Awesome Mac 这个仓库主要是收集非常好用的Mac应用程序.软件以及工具,主要面向开发者和设计师.有这个想法是因为我最近发了一篇较为火爆的涨粉儿微信公众号文章<工具武装的前端开发工程 ...
随机推荐
- 《Effective C#》系列之(三)——充分利用C#语言的新功能
在<Effective C#>这本书中,利用C#语言的新功能是其中一章的内容.以下是该章节的一些核心建议,以及使用C#代码示例说明: 利用自动属性:在C# 3.0中引入了自动属性,可以大大 ...
- 《C# in depth》第6章C#6.0中的更改(十四)——表达式体
表达式体成员是一种在C# 6及以上版本中引入的语法.它允许开发人员使用Lambda表达式来简化方法或属性的定义. 在使用表达式体成员时,可以将方法或属性的实现写在一个Lambda表达式中,然后直接返回 ...
- 【云原生】拿下 Gartner 容器产品第一,阿里云打赢云原生关键一战!
近日,Gartner 发布 2020 年公共云容器报告,据报告显示,阿里云和 AWS 拥有最丰富的产品布局,覆盖 9 项产品能力,并列排名第一. 据 Gartner 分析师评论,阿里云拥有丰富的容器产 ...
- MaxCompute跨境访问加速解决方案
简介: MaxCompute联合全球加速服务,为有跨境访问需求的MaxCompute客户提供一套高效稳定的跨境访问加速方案. MaxCompute联合全球加速服务,为有跨境访问需求的MaxComput ...
- 重磅发布|新一代云原生数据仓库AnalyticDB「SQL智能诊断」功能详解
简介: AnalyticDB For MySQL为用户提供了高效.实时.功能丰富并且智能化的「SQL智能诊断」和「SQL智能调优」功能,提供用户SQL性能调优的思路.方向和具体的方法,降低用户使用成 ...
- [ML] 详解 ChatGLM-webui 的启动使用与 ChatGLM-6B 常见问题
1. ChatGLM-webui 总共支持以下几个命令选项: 2. 以 windows 为例,在 PowerShell 里运行命令: # 安装依赖 pip install torch==1.13. ...
- STM32的半主机与MicroLIB机制
一.半主机模式 半主机机制的作用 半主机是作用于ARM目标的一种机制,可以将来自STM32单片机应用程序的输入与输出请求传送至运行仿真器的PC主机上.使用此机制可以启用C库中的函数,如printf() ...
- SpringMVC学习二(日期参数/数据保存/重定向)
接受的参数为日期类型 controller进行数据保存 Controller如何进行重定向跳转 1.对于前端页面传来日期类型的数据时如何进行处理,有两种方法 1.1在对应的Controller中插入代 ...
- 通过AMDP调用HANA的PAL函数
SAP预测分析库(SAP Predictive Analysis Library,PAL)是SAP HANA中的一项功能,它允许我们在SAP HANA SQLScript过程中执行分析算法. 基于AB ...
- .Net 8.0 下的新RPC,IceRPC之使用Dev Containers进行 .NET QUIC 精简开发
作者引言 很高兴啊,我们来到了IceRPC之使用Dev Containers进行 .NET QUIC 精简开发,主要是一篇指引,如何使用开发容器做为开发环境,进行开发IceRPC,可适用于任务应用的开 ...