我已经完成了在我的Z80核心上实现ADD A,r组操作码.我对我认为已经钉入的进位和溢出标志有点混淆,但我想把它放到社区检查我是对的.
基本上,从我所看到的,Z80中的ALU并不关心有符号/无符号运算,只是添加了位.这意味着如果将两个8位值相加并由于它们的相加而产生9位值,则将设置进位标志.这包括添加两个负二的补数,例如-20(11101100)和-40(11011000),因为虽然结果是-60(11000100),但结果实际上是9位值1 1100 0100.这肯定意味着如果添加两个负二的补码值,即使没有溢出条件,也会始终设置进位标志 - 我是对的吗?
其次,我决定检测此指令中的溢出,我会将两个操作数的第7位异或,如果结果是10000000,那么肯定没有溢出 - 如果结果是00000000那么可能会有溢出这些符号是相同的,因此我将XOR的第7位与任一操作数的第7位相加,如果结果为10000000,则发生溢出,并设置P/V溢出标志.我也在这儿吗?
对于这样一个令人费解的问题我很抱歉,我很确定我是对的但是在我继续根据这个逻辑进行无数更多指令之前我需要知道.非常感谢.
对这个看似微不足道的问题道歉,但我似乎无法在任何地方找到答案 - 我只是想在我的Z80仿真器中实现DAA指令,我在Zilog手册中注意到它是为了调整的目的用于二进制编码的十进制算术的累加器.它表示该指令旨在在加法或减法指令之后运行.
我的问题是:
我有一个奇怪的问题 - 我希望有人可以向我解释发生了什么,以及可能的解决方法.我在Java中实现了一个Z80核心,并试图通过在一个单独的线程中使用java.util.Timer对象来减慢它的速度.
基本设置是我有一个线程运行一个执行循环,每秒50次.在此执行循环中,执行许多循环,然后调用wait().外部Timer线程将每隔20ms调用Z80对象上的notifyAll(),模拟PAL Sega主系统时钟频率为3.54 MHz(ish).
我上面描述的方法在Windows 7(试过两台机器)上工作得很好,但我也试过两台Windows XP机器,而且在这两台机器上,Timer对象似乎睡过了大约50%左右.这意味着在Windows XP计算机上,一秒钟的仿真时间实际上大约需要1.5秒左右.
我尝试使用Thread.sleep()而不是Timer对象,但这具有完全相同的效果.我意识到大多数操作系统的时间粒度不会超过1毫秒,但我可以忍受999毫秒或1001毫秒而不是1000毫秒.我不能忍受的是1562ms - 我只是不明白为什么我的方法在较新版本的Windows上运行正常,但不是旧版本 - 我调查了中断期等等,但似乎没有已经开发出一种解决方法.
有谁能告诉我这个问题的原因和建议的解决方法?非常感谢.
更新:这是我为了显示相同问题而构建的较小应用的完整代码:
import java.util.Timer;
import java.util.TimerTask;
public class WorkThread extends Thread
{
private Timer timerThread;
private WakeUpTask timerTask;
public WorkThread()
{
timerThread = new Timer();
timerTask = new WakeUpTask(this);
}
public void run()
{
timerThread.schedule(timerTask, 0, 20);
while (true)
{
long startTime = System.nanoTime();
for (int i = 0; i < 50; i++)
{
int a = 1 + 1;
goToSleep();
}
long timeTaken = …Run Code Online (Sandbox Code Playgroud) 我再次提出另一个无关紧要的Z80问题:-)我的仿真器内核当前的结构方式,每次从内存中取出操作码字节时,我都会递增内存刷新寄存器的低7位 - 这意味着对于多字节指令,例如作为开始DD或FD的那些,我将寄存器递增两次 - 或者在诸如RLC(IX + d)之类的指令的实例中递增三次(因为它布局为opcode1-opcode2-d-opcode3).
它是否正确?我不确定 - Z80手册有点不清楚,因为它说CPDR(一个双字节指令)将它增加两倍,但是"存储器刷新寄存器"部分仅表示它在每次取指令后递增.我注意到J80(我检查过的模拟器,因为我不确定)只在指令的第一个操作码字节后递增.
哪个是对的?我想这在任何情况下都不是非常重要,但是很高兴知道:-)非常感谢.
此致,菲尔波特
我用Java编写了一个Sega Master System仿真器(尽管这个问题不是特定于Java的)并且已经完成了除SN76489声音芯片之外的所有事情.这个芯片如何发出声音很容易 - 我遇到的问题是将其转换为可通过PC /笔记本电脑/ JVM运行的任何形式播放的形式.
我已经确定了以下步骤;
由于SN76489以大约221khz的采样率运行 - 这意味着它输出的波频率高达110khz(尽管在实践中我怀疑任何事情都不会如此高).因此,我需要在对其进行下采样之前实现低通滤波器.
然后我想将它下采样到44.1khz,所以我可以通过音频线输出它(在我的例子中是Java源数据线).
为此,我需要将低通滤波器设置为22.05khz,但问题是我不知道(从数学上讲)低通滤波器实际上是如何工作的.我需要这个才能写一个.
目前,我的声音芯片创建了0.2秒的缓冲区,如上所述,以221khz存储样本.我可以按照我的理解进行下采样 - 但如果我在没有首先应用低通滤波器的情况下进行下采样,我理解我可能会在结果声音流中出现混叠毛刺.
任何人都可以推荐最简单的数学思想算法 - 我意识到由于涉及的变量,低通永远不会"精确",但我只需要一个声音解释,对我的大脑来说已经足够了(实际上并没有现在处理波浪处理)了解.
如果它有帮助,具体是:SN76489同时输出三个方波和一个噪声槽.将它们相加在一起,然后输出到混频器/放大器 - 链路中的这个阶段是我想要在下采样然后放大波形之前运行低通滤波器的地方.人们可以给予我的任何帮助非常感谢.我意识到需要背景阅读,但我想知道"我需要阅读什么".非常感谢.
更新:我最终想出了一个更简单的方法 - 尽管还不是很好.SN76489通过从寄存器值生成每个音调通道来工作 - 输出极性1,值递减,依此类推 - 直到值为0,然后重置该值并将极性切换为-1,依此类推.然后将该值乘以体积以获得该样本的最终幅度,并与其他通道求和.
我现在只是阻止一个寄存器值,它会产生一个高于我所要求的奈奎斯特限制的方波.这给我留下了更好的信号,但它仍然有一些嗡嗡声/砰砰声 - 不知道为什么最大可能的频率应该是18,473Hz.这种爆裂/嗡嗡声是否是因为当芯片将频道从一个频率切换到另一个频率时,它不允许当前的波形完全完成?例如,芯片输出1111,然后是00 - 而不是全四个零并切换到新的频率 - 这可能会导致混叠吗?
我打算在接下来的几个月里创建一个Sega Master System模拟器,作为Java中的一个爱好项目(我知道它不是最好的语言,但我发现它很舒服,并且作为一个频繁的用户Windows和Linux我认为跨平台应用程序会很棒).我的问题是关于循环计数;
我查看了另一个Z80模拟器的源代码,以及其他模拟器,特别是执行循环引起了我的兴趣 - 当它被调用时,一个int作为参数传递(假设以1000为例).现在我得到每个操作码执行不同的循环次数,并且当执行这些循环时,循环次数从总体数字减少.一旦剩余的周期数<= 0,执行循环就完成了.
我的问题是,这些仿真器中的许多都没有考虑到这样一个事实,即要执行的最后一条指令可以将周期数推到负值 - 这意味着在执行循环之间,最终可能会说1002个周期执行而不是1000.这是重要的吗?一些仿真器通过补偿下一个执行循环来解决这个问题,有些则不能 - 哪种方法最好?请允许我说明一下我的问题,因为我并不擅长将自己放在一边:
public void execute(int numOfCycles)
{ //this is an execution loop method, called with 1000.
while (numOfCycles > 0)
{
instruction = readInstruction();
switch (instruction)
{
case 0x40: dowhatever, then decrement numOfCycles by 5;
break;
//lets say for arguments sake this case is executed when numOfCycles is 3.
}
}
Run Code Online (Sandbox Code Playgroud)
在此特定循环示例结束后,numOfCycles将为-2.这只会是一个小小的不准确,但在人们的经历中总体上是否重要?我很欣赏任何人对这一点的见解.我计划在每帧之后中断CPU,因为这似乎合适,所以1000个周期很低我知道,这只是一个例子.
非常感谢,菲尔
我从Z80的Zilog数据表中注意到,通过I/O(IN和OUT)指令组,各种寄存器的内容通常放在地址总线的前8位(取决于指令),低8位选择多达256个理论连接设备中的一个.
我的问题是用这8位高位做这个是什么意思?我知道有些机器在某种程度上使用它来降低解码复杂度,但它们是否真的用于任何事情?我想完全按照Z80的建议实现指令,但我没有看到实现这种行为的重点,因为它是非标准的.这种行为被描述为未记录,因此在"世嘉主系统"上,我会侥幸逃脱吗?非常感谢.
此致,菲尔波特
我(出于好奇)一直想知道在x86_64 Linux上定义了ioctl系统调用的用户空间包装器.我的第一个想法是glibc - 在我的Fedora 24盒子上检查已安装版本上的暴露符号之后,我可以看到(除非我做错了)libc将ioctl符号暴露为'W'意味着它是一个弱符号默认实现.misc/ioctl.c中的glibc源代码树中的默认实现似乎是一个存根,只是将errno设置为ENOSYS并返回-1.
从来没有,ioctl工作(显然或我的系统不会很有用).我知道它可能是汇编代码在某个文件中的某个地方以某种方式组装和链接,从而覆盖glibc暴露的弱符号.我也知道应用程序完全可以使用系统调用直接调用ioctl,可以通过glibc syscall包装器直接调用也可以直接使用程序集调用.
也就是说,鉴于库源代码我碰巧观察(libdrm)包含标准的ioctl头文件/usr/include/sys/ioctl.h,并且似乎没有包含我自己可以看到的包装器实现,我想知道我应该在哪里看.
这是我更深入地了解GNU/Linux系统最低级别的一部分.感谢您的任何指示,并且如果之前已经提出过这样的道歉,但如果有的话,我看不到任何答案.
更新:我忽略了上面提到但我还检查了内核映射的虚拟vdso库 - 我只能在其中找到以下内容:
0000000000000a00 W clock_gettime
0000000000000db0 W getcpu
0000000000000c40 W gettimeofday
0000000000000000 A LINUX_2.6
0000000000000d90 W time
0000000000000a00 T __vdso_clock_gettime
0000000000000db0 T __vdso_getcpu
0000000000000c40 T __vdso_gettimeofday
0000000000000d90 T __vdso_time
Run Code Online (Sandbox Code Playgroud)
更新:看起来我错误的glibc默认定义是存根.正如nos在评论中指出的那样,反汇编表明它正在执行真正的系统调用.我已经发布了一个答案来反映这一点.
抱歉让我成为我的第二个Z80 DAA问题 - 我现在已经实现了这个指令,但有一点我不确定 - 这个指令设置的是H标志吗?Z80手册中说"看到指令",但它只在DAA之前提到标志,而不是在执行之后.
我设置标志如下:
如果结果为负,则设置S(0x80&结果等于0x80)如果结果为零,则设置Z(不确定因此问题)P/V设置为结果的奇偶校验(如果是偶数则为1,如果为奇数则为0)N如果原始累加器值的高半字节被修改,则设置为C
除此之外,指令似乎按照我的预期执行:-)我希望有人可以为我清除这一点,非常感谢.
只是有点混乱我希望有人可以清理 - 这个问题问:"我们的getch和ungetch没有正确处理推回的EOF.如果EOF被推回,决定他们的属性应该是什么,然后实现你的设计".
使用代码,EOF被推回,用getch()重新获取,这会导致如下的循环:
while ((c = getch()) != EOF)
putchar(c);
Run Code Online (Sandbox Code Playgroud)
从缓冲区遇到它时终止.我没有看到这种行为是如何不正确的.当然,理论上(大多数情况下)EOF只会遇到一次,如果它被推回然后以这种方式从缓冲区中读取,它真的不重要吗?我希望有人可以为我清理这个问题的目的 - 我得到的大多数解决方案都涉及编程ungetch()忽略EOF,我只是没有看到这一点.
我确信有一个,因为Dennis Ritchie和Brian Kernighan比我年轻的人要亮得多 - 只是希望有人可以指出它.谢谢 :-)
问候,菲尔
我目前正在通过"有效的现代C++"来更新我的语言知识,并刚刚完成了第27项,该项处理重载函数,这些函数采用转发(或书中称为通用的)引用.使用以下代码我写道:
#include <iostream>
template <typename T>
void func(T&& param) {
std::cout << "forwarding reference version\n";
}
void func(int param) {
std::cout << "int version\n";
}
int main() {
func(29);
}
Run Code Online (Sandbox Code Playgroud)
请有人解释为什么调用int版本,即使29是rvalue,因此模板应该实例化为"void func(int && param)"并且调用应该是转发版本?显然它就是它,所以我的理解显然缺乏,但澄清这一点会有所帮助.我理解标准说在相同功能签名的情况下,应该首选非模板化函数,但(至少在我看来)这不适用于此?非常感谢.
问候,菲尔