Merge pull request #1749 from TomHarte/6809Timing
Fix 6809 LEAx timing.
This commit is contained in:
5 files changed
+31
-120
No files matched your search
@@ -11,97 +11,7 @@
|
||||
using namespace Thomson;
|
||||
|
||||
CD90_640::CD90_640() : WD::WD1770(P1770) {
|
||||
// 325 is a peculiar RPM, but seems to match a spin-up test in the disk ROM that polls the WD1770's status register
|
||||
// index hole bit and counts time. Furthermore there are other machines with unusual RPMs. Could definitely
|
||||
// still just imply an issue elsewhere in the emulator though.
|
||||
emplace_drives(2, 8'000'000, 325, 2);
|
||||
|
||||
//
|
||||
// On "325 RPM":
|
||||
//
|
||||
// Faulty reasoning was:
|
||||
// ---------------------
|
||||
//
|
||||
// The DOS ROM verifies that a disk is present and spinning before proceeding.
|
||||
// Part of that test is of spin speed.
|
||||
//
|
||||
// Specifically, with X = 0xa7d0 it performs:
|
||||
//
|
||||
// ;
|
||||
// ; Wait for index hole set.
|
||||
// ;
|
||||
// a29b LDA ,X ; 4 µs
|
||||
// a29d ANDA #$02 ; 2 µs
|
||||
// a29f BEQ ZA29B ; 3 µs
|
||||
//
|
||||
// ;
|
||||
// ; i.e. start of track falls about here
|
||||
// ;
|
||||
//
|
||||
// ;
|
||||
// ; Fixed delay...
|
||||
// ;
|
||||
// a2a1 LDY #M09C4 ; 4 µs
|
||||
// a2a5 DEY ; 5 µs
|
||||
// a2a7 BNE ZA2A5 ; 3 µs = net delay of 4 + 9C4*7 = 17,504 µs
|
||||
//
|
||||
// a2a9 PSHS CC ; 6 µs
|
||||
// a2ab SEIF ; 3 µs
|
||||
//
|
||||
// ;
|
||||
// ; Count time until index hole is set again
|
||||
// ;
|
||||
// a2ad LDA ,X ; 4 µs, read WD status
|
||||
// a2af INY ; 5 µs
|
||||
// a2b1 ANDA #$02 ; 2 µs
|
||||
// a2b3 BEQ ZA2AD ; 3 µs
|
||||
//
|
||||
// a2b5 PULS CC
|
||||
//
|
||||
// ;
|
||||
// ; Check whether rotation speed was within bounds
|
||||
// ;
|
||||
// a2b7 CMPY #M311B
|
||||
// a2bb BMI ZA2C7
|
||||
// a2bd CMPY #M3357
|
||||
// a2c1 BPL ZA2C7
|
||||
//
|
||||
// [test passed code here, test failed code from a2c7]
|
||||
//
|
||||
// If I've disassembled that correctly, then the process is:
|
||||
//
|
||||
// (1) wait for index hole, with up to 9 µs of latency;
|
||||
// (2) spin in a loop for 17,504 µs;
|
||||
// (3) do minor stack/flag work for 9 µs;
|
||||
// (4) count time from here until next index hole, ending with Y = time/13;
|
||||
// (5) test that that is within the bounds 0x311b, 0x3357.
|
||||
//
|
||||
// Ignoring minor potential latencies in loop exits, that's:
|
||||
//
|
||||
// (1) wait for index hole;
|
||||
// (2) spend 17,513 µs doing something else;
|
||||
// (3) get Y = [µs from there to next index hole] / 13.
|
||||
//
|
||||
// i.e. it's a test that the rotation it samples takes n µs, where:
|
||||
//
|
||||
// 14 * 0x311b < n - 17,513 < 14 * 0x3357
|
||||
// 14 * 12,571 + 20,009 < n < 14 * 13,143 + 20,009
|
||||
// 196,003 < n < 204,011
|
||||
//
|
||||
// i.e.
|
||||
//
|
||||
// ~331 >= RPM >= ~319 RPM.
|
||||
//
|
||||
// So 325 RPM is a really weird number but I can't currently say why it should be
|
||||
// wrong rather than merely unexpected. So here it is.
|
||||
//
|
||||
// Correct reasoning is:
|
||||
// ---------------------
|
||||
//
|
||||
// The LEAYs that constitute INY and DEY above should be _five_ cycles long, not four.
|
||||
// My 6809 timing is adrift.
|
||||
// If loops were properly timed then 300 RPM looks appropriate.
|
||||
// Cf. https://forum.system-cfg.com/viewtopic.php?f=1&t=17137
|
||||
emplace_drives(2, 8'000'000, 300, 2);
|
||||
}
|
||||
|
||||
uint8_t CD90_640::control() {
|
||||
|
||||
@@ -824,7 +824,8 @@ struct M6809Traits {
|
||||
sequence(0xbf); // STY
|
||||
}
|
||||
|
||||
// Omitted entirely: LEAS, LEAU, LEAX, LEAY that come only in indexed mode. Maybe use those as the indexed test?
|
||||
// Omitted entirely: LEAS, LEAU, LEAX, LEAY that come only in indexed mode. LEAS is the subject of the indexed
|
||||
// timing tests, and I _assume_ the rest conform.
|
||||
|
||||
// MARK: - JMP
|
||||
|
||||
@@ -1087,35 +1088,35 @@ struct M6809Traits {
|
||||
test(
|
||||
{0x32, NoOffset | RegX}, // ,R
|
||||
{
|
||||
RW::Read, RW::Read, RW::NoData
|
||||
RW::Read, RW::Read, RW::NoData, RW::NoData,
|
||||
}
|
||||
);
|
||||
|
||||
test(
|
||||
{0x32, NoOffset | RegX | Indirect}, // [,R]
|
||||
{
|
||||
RW::Read, RW::Read, RW::NoData, RW::Read, RW::Read, RW::NoData
|
||||
RW::Read, RW::Read, RW::NoData, RW::Read, RW::Read, RW::NoData, RW::NoData,
|
||||
}
|
||||
);
|
||||
|
||||
test(
|
||||
{0x32, Offset5bit | RegX}, // [5n,R]
|
||||
{
|
||||
RW::Read, RW::Read, RW::NoData, RW::NoData
|
||||
RW::Read, RW::Read, RW::NoData, RW::NoData, RW::NoData,
|
||||
}
|
||||
);
|
||||
|
||||
test(
|
||||
{0x32, Offset8bit | RegX, 0x00}, // 8n,R
|
||||
{
|
||||
RW::Read, RW::Read, RW::Read, RW::NoData
|
||||
RW::Read, RW::Read, RW::Read, RW::NoData, RW::NoData,
|
||||
}
|
||||
);
|
||||
|
||||
test(
|
||||
{0x32, Offset8bit | RegX | Indirect, 0x00}, // [8n,R]
|
||||
{
|
||||
RW::Read, RW::Read, RW::Read, RW::NoData, RW::Read, RW::Read, RW::NoData,
|
||||
RW::Read, RW::Read, RW::Read, RW::NoData, RW::Read, RW::Read, RW::NoData, RW::NoData,
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1124,7 +1125,7 @@ struct M6809Traits {
|
||||
{
|
||||
RW::Read, RW::Read,
|
||||
RW::Read, RW::Read,
|
||||
RW::NoData, RW::NoData, RW::NoData,
|
||||
RW::NoData, RW::NoData, RW::NoData, RW::NoData,
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1132,7 +1133,7 @@ struct M6809Traits {
|
||||
{0x32, ARegisterOffset | RegX}, // A,R
|
||||
{
|
||||
RW::Read, RW::Read,
|
||||
RW::NoData, RW::NoData,
|
||||
RW::NoData, RW::NoData, RW::NoData,
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1141,7 +1142,7 @@ struct M6809Traits {
|
||||
{
|
||||
RW::Read, RW::Read,
|
||||
RW::NoData, RW::NoData,
|
||||
RW::Read, RW::Read, RW::NoData,
|
||||
RW::Read, RW::Read, RW::NoData, RW::NoData,
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1152,7 +1153,7 @@ struct M6809Traits {
|
||||
{0x32, DRegisterOffset | RegX}, // D,R
|
||||
{
|
||||
RW::Read, RW::Read,
|
||||
RW::NoData, RW::NoData, RW::NoData, RW::NoData, RW::NoData,
|
||||
RW::NoData, RW::NoData, RW::NoData, RW::NoData, RW::NoData, RW::NoData,
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1161,7 +1162,7 @@ struct M6809Traits {
|
||||
{
|
||||
RW::Read, RW::Read,
|
||||
RW::NoData, RW::NoData, RW::NoData, RW::NoData, RW::NoData,
|
||||
RW::Read, RW::Read, RW::NoData,
|
||||
RW::Read, RW::Read, RW::NoData, RW::NoData,
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1169,7 +1170,7 @@ struct M6809Traits {
|
||||
{0x32, PostInc1 | RegX}, // R+
|
||||
{
|
||||
RW::Read, RW::Read,
|
||||
RW::NoData, RW::NoData, RW::NoData,
|
||||
RW::NoData, RW::NoData, RW::NoData, RW::NoData,
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1177,7 +1178,7 @@ struct M6809Traits {
|
||||
{0x32, PreDec1 | RegX}, // -R
|
||||
{
|
||||
RW::Read, RW::Read,
|
||||
RW::NoData, RW::NoData, RW::NoData,
|
||||
RW::NoData, RW::NoData, RW::NoData, RW::NoData,
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1185,7 +1186,7 @@ struct M6809Traits {
|
||||
{0x32, PostInc2 | RegX}, // R++
|
||||
{
|
||||
RW::Read, RW::Read,
|
||||
RW::NoData, RW::NoData, RW::NoData, RW::NoData,
|
||||
RW::NoData, RW::NoData, RW::NoData, RW::NoData, RW::NoData,
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1194,14 +1195,14 @@ struct M6809Traits {
|
||||
{
|
||||
RW::Read, RW::Read,
|
||||
RW::NoData, RW::NoData, RW::NoData, RW::NoData,
|
||||
RW::Read, RW::Read, RW::NoData,
|
||||
RW::Read, RW::Read, RW::NoData, RW::NoData,
|
||||
}
|
||||
);
|
||||
|
||||
test(
|
||||
{0x32, PCOffset8bit | RegX, 0x00}, // 8n, PC
|
||||
{
|
||||
RW::Read, RW::Read, RW::Read, RW::NoData,
|
||||
RW::Read, RW::Read, RW::Read, RW::NoData, RW::NoData,
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1209,7 +1210,7 @@ struct M6809Traits {
|
||||
{0x32, PCOffset8bit | RegX | Indirect, 0x00, 0x00, 0x00}, // [8n, PC]
|
||||
{
|
||||
RW::Read, RW::Read, RW::Read, RW::NoData,
|
||||
RW::Read, RW::Read, RW::NoData,
|
||||
RW::Read, RW::Read, RW::NoData, RW::NoData,
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1217,7 +1218,7 @@ struct M6809Traits {
|
||||
{0x32, PCOffset16bit | RegX, 0x00, 0x00}, // 16n, PC
|
||||
{
|
||||
RW::Read, RW::Read, RW::Read, RW::Read,
|
||||
RW::NoData, RW::NoData, RW::NoData, RW::NoData,
|
||||
RW::NoData, RW::NoData, RW::NoData, RW::NoData, RW::NoData,
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1226,7 +1227,7 @@ struct M6809Traits {
|
||||
{
|
||||
RW::Read, RW::Read, RW::Read, RW::Read,
|
||||
RW::NoData, RW::NoData, RW::NoData, RW::NoData,
|
||||
RW::Read, RW::Read, RW::NoData,
|
||||
RW::Read, RW::Read, RW::NoData, RW::NoData,
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1235,7 +1236,7 @@ struct M6809Traits {
|
||||
{
|
||||
RW::Read, RW::Read,
|
||||
RW::Read, RW::Read, RW::NoData,
|
||||
RW::Read, RW::Read, RW::NoData,
|
||||
RW::Read, RW::Read, RW::NoData, RW::NoData,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -666,7 +666,7 @@ struct Processor {
|
||||
);
|
||||
address_.halves.high = registers_.reg<R8::DP>();
|
||||
|
||||
if(operation_.type == AccessType::LEA) {
|
||||
if(operation_.operation == Operation::JMP) {
|
||||
goto internal_lic_break;
|
||||
}
|
||||
internal_cycle(LIC::Inactive);
|
||||
@@ -694,7 +694,7 @@ struct Processor {
|
||||
++registers_.pc.full
|
||||
);
|
||||
|
||||
if(operation_.type == AccessType::LEA) {
|
||||
if(operation_.operation == Operation::JMP) {
|
||||
goto internal_lic_break;
|
||||
}
|
||||
internal_cycle(LIC::Inactive);
|
||||
@@ -766,7 +766,7 @@ struct Processor {
|
||||
read(BusState::Normal, LIC::Inactive, Literal(address_.full), operand_.halves.low, ++address_.full);
|
||||
|
||||
address_ = operand_;
|
||||
if(operation_.type == AccessType::LEA) {
|
||||
if(operation_.operation == Operation::JMP) {
|
||||
goto internal_lic_break;
|
||||
}
|
||||
internal_cycle(LIC::Inactive);
|
||||
|
||||
@@ -545,10 +545,10 @@ Cycles perform(
|
||||
case STY: st<R16::Y>(registers, word); return 0;
|
||||
case STS: st<R16::S>(registers, word); return 0;
|
||||
|
||||
case LEAU: lea<R16::U>(registers, word); return 0;
|
||||
case LEAX: lea<R16::X>(registers, word); return 0;
|
||||
case LEAY: lea<R16::Y>(registers, word); return 0;
|
||||
case LEAS: lea<R16::S>(registers, word); return 0;
|
||||
case LEAU: lea<R16::U>(registers, word); return 1;
|
||||
case LEAX: lea<R16::X>(registers, word); return 1;
|
||||
case LEAY: lea<R16::Y>(registers, word); return 1;
|
||||
case LEAS: lea<R16::S>(registers, word); return 1;
|
||||
|
||||
case MUL: mul(registers); return 9; // Per 6809cyc.txt; might need more research.
|
||||
|
||||
@@ -606,8 +606,7 @@ inline bool is_zero_costed(const InstructionSet::M6809::Operation operation) {
|
||||
case CLR: case LDA: case LDB: case STA: case STB:
|
||||
case LDD: case LDU: case LDX: case LDY: case LDS:
|
||||
case STD: case STU: case STX: case STY: case STS:
|
||||
case LEAU: case LEAX: case LEAY: case LEAS: case SEX:
|
||||
case TSTA: case TSTB: case JMP:
|
||||
case SEX: case TSTA: case TSTB: case JMP:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <cstdint>
|
||||
|
||||
#include "Numeric/RegisterSizes.hpp"
|
||||
|
||||
Reference in new issue
Block a user