【问题标题】:Need help allocating a far pointer on Borland C++ 3.0需要帮助在 Borland C++ 3.0 上分配远指针
【发布时间】:2023-03-19 23:44:01
【问题描述】:

我正在编写一个 DOS 游戏框架,以更好地学习 C 语言,并且对在旧硬件上编程(尤其是在我长大的系统上)产生普遍兴趣。

我正在尝试实现一个双缓冲系统,但我无法分配一个指向 320*200 数组的远指针。

起初我尝试使用 malloc,但发现它只能分配 64kb 以下。我读到您需要使用farmalloc(malloc返回NULL)并且它分配正确。然而,当 _fmemset 或 _fmemcpy 运行时....整个系统冻结。

backBuffer = (unsigned char far*) farmalloc(64000);

何时需要交换我使用的缓冲区

_fmemcpy(VGA, backBuffer, 64000);

程序正在使用小内存模型。

【问题讨论】:

  • 什么是VGA,它的值,backbuffer_fmemcpy()
  • VGA 是一个 unsigned char far 指针,指向地址 0xA000000L,即 VGA 内存的地址。 Backbuffer 也是一个 unsigned char far 指针,是用上面的函数分配的。
  • 我不明白 0xA000000L。它必须是:segment=0xA000 & offset=0(对应于物理地址=segment * 0x10 + offset = 0xA0000 = 640K)。它真的有segment=0xA000 & offset=0吗?或者是 segment=0xA00 & offset=0 还是别的什么?制作这样一个指针的正确方法是通过MK_FP(0xA000, 0)
  • @loncannon,也许是你的评论打错了,但你漏掉了一个零,应该是 0xA0000000L。

标签: c memory pointers dos


【解决方案1】:

很有趣的帖子,我也很喜欢旧硬件。

  • 您是否尝试过在中型或大型模型中编译以检查代码是否正确运行?

  • 您确定指向 VGA 显存的指针已正确初始化吗?

我记得在那些日子里,使用内存副本来交换屏幕缓冲区非常缓慢,更不用说您必须等待垂直回溯期才能开始复制内存。 (我有一个基本的 VGA 卡,所以也许你的硬件更好,延迟是可以接受的)。

如果您有兴趣,我强烈建议您阅读 Michael Abrash 的 Mode-X 专栏。

Mode-X 及其衍生模式是由 Michael Abrash 首次记录的替代图形模式。基本上,它们是对 256 色 13H 模式的破解,您可以通过调整 VGA 卡中的一些寄存器来激活该模式。

激活后,有两大优势:

  1. 四页显示内存
  2. 方形像素(在 320x240 的原始 ModeX 中),(绘制的圆形看起来像圆形,而不是椭圆)

实现双甚至三缓冲区是轻而易举的事,因为您可以直接写入非活动缓冲区并激活它,只需更改 vga 卡中的寄存器,根本不需要 memcopy!(您还是需要等待垂直回扫,否则会出现难看的闪烁)

缺点是这种模式更难编程,基本上,模式-X 现在单个内存地址映射到四个连续像素,因此,单个像素写入实际上会同时改变四个像素。 (这对于多边形填充程序来说是一个很好的加速!)。

如果你想改变一个像素,那么你必须设置一个“像素掩码”(也是一个 VGA 卡寄存器),指定四个像素中的哪一个会受到内存写入的影响,就在你绘制像素之前。

如果幼稚地完成,这会很慢,因为绘制的每个像素都需要设置遮罩。通常我们直观地倾向于从左到右,从上到下(因为这正是视频内存在 VGA 模式 13H 上的映射方式),但我们 Mode-X 程序员了解到“旋转范式”要快得多,即,我们从上到下、从左到右绘制东西。

为什么?因为这允许我们为绘制的每一列只修改一次像素掩码! 这是一些伪代码:

朴素、直观的编程

pixelptr = start of screen memory
foreach row
   foreach column
      adjust pixel mask
      write pixel value
      pixelptr+= 1      // advance pointer to next pixel to the left
   next
next

循环编程方式

[Edit1:添加了指针必须移动到下一列顶部的缺失步骤]

[Edit2:更正,我添加 320 以前进到下一行,实际上这应该除以 4,因为视频内存地址的连续增量将映射到右侧的下一个四个像素组上一个,四像素组]

for each column
   pixelptr = start of screen memory + current column index
   adjust pixel mask       // same mask applies to every pixel in the same column!
   for each row
      write pixel value
      pixelptr += (320 / 4)  // advance pointer to next pixel, to the bottom
   next
next

所有涉及的步骤和注册地址在我提供的 Michael Abrash 专栏的链接中都有详细说明。这是古老的东西,但我打赌你会发现它很迷人!

干杯!

【讨论】:

  • 似乎有人解决了我的问题 :(。无论如何,这似乎是我读到的“无链模式”是的?回答您的问题:尝试了中等模式,当它退出时会表现得很奇怪内联汇编块。VGA 显示内存已初始化,因为我在处理后台缓冲区之前已经绘制了程序。
  • 是的!它们指的是相同的模式。它显然是由几个开发人员同时“发现”的,因为在 VGA 技术文档中暗示了该模式的存在,但没有详细说明。我没有 BC++ 3.0,你能检查一下是否有可用的紧凑模型并尝试一下吗?它应该是 64KB 代码(就像小型模式一样)但 64+ KB 数据(也许汇编块假设一个单段,64KB 代码?) - 如果您可以获得 Watcom 的 C 编译器的副本,那么您可以编程在更简单、平坦的内存模型(无段)中,并使用保护模式寻址所有可用内存。
  • 奇怪,将其设置为紧凑内存模型会导致 fread 冻结。程序中的随机点似乎冻结取决于我选择的模型。太令人沮丧了。
  • 嗨@loncannon,很抱歉听到这个消息,我出去旅行了。从您所描述的情况来看,您可能遇到了一些内存损坏问题(可能是系统其他部分的缓冲区溢出)。像 Numega 的 BoundsChecker 这样的工具对于查找这些错误点非常有帮助。
  • 如果您在现代系统下调试,另一种可能性是时间问题。我记得一些图书馆通过测量计算机的速度来同步事物,并根据该速度调整延迟,但是今天的计算机是如此之快,以至于在许多情况下,计数器都会溢出并给出错误的计时结果。许多旧游戏因此而崩溃。只是放弃一些想法。
猜你喜欢
  • 1970-01-01
  • 2021-10-13
  • 2011-07-20
  • 2013-12-13
  • 1970-01-01
  • 2014-05-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多