From a746bd9e5f5f0afb2862136886967431d68fbcf0 Mon Sep 17 00:00:00 2001 From: Ash Wolf Date: Sun, 22 Dec 2019 13:45:46 +0000 Subject: [PATCH] lots of arm710a fixes --- WindCore/arm710a.cpp | 196 ++++++++++++++++++++++++++++-------------- WindCore/arm710a.h | 46 ++++++---- WindCore/emu.cpp | 43 +++++++-- WindQt/mainwindow.cpp | 35 ++++++-- WindQt/mainwindow.ui | 135 +++++++++++++++-------------- 5 files changed, 298 insertions(+), 157 deletions(-) diff --git a/WindCore/arm710a.cpp b/WindCore/arm710a.cpp index 41434f3..1dff383 100644 --- a/WindCore/arm710a.cpp +++ b/WindCore/arm710a.cpp @@ -104,6 +104,7 @@ uint32_t ARM710a::tick() { if (insnFault != NoFault) { // Raise a prefetch error // These do not set FSR or FAR + log("prefetch error!"); raiseException(Abort32, GPRs[15] - 8, 0xC); } else { clocks += executeInstruction(insn); @@ -131,6 +132,7 @@ static inline bool extract1(uint32_t value, uint32_t bit) { uint32_t ARM710a::executeInstruction(uint32_t i) { uint32_t cycles = 1; +// log("executing insn %08x @ %08x", i, GPRs[15] - 0xC); // a big old dispatch thing here // but first, conditions! @@ -191,59 +193,64 @@ uint32_t ARM710a::execDataProcessing(bool I, uint32_t Opcode, bool S, uint32_t R op2 -= 4; } - switch (extract(Operand2, 6, 5)) { - case 0: // Logical Left (LSL) - if (shiftBy == 0) { - shifterCarryOutput = flagC(); - // no change to op2! - } else if (shiftBy <= 31) { - shifterCarryOutput = extract1(op2, 31 - shiftBy); - op2 <<= shiftBy; - } else if (shiftBy == 32) { - shifterCarryOutput = extract1(op2, 0); - op2 = 0; - } else /*if (shiftBy >= 33)*/ { - shifterCarryOutput = false; - op2 = 0; - } - break; - case 1: // Logical Right (LSR) - if (shiftBy == 0 || shiftBy == 32) { - shifterCarryOutput = extract1(op2, 31); - op2 = 0; - } else if (shiftBy <= 31) { - shifterCarryOutput = extract1(op2, shiftBy - 1); - op2 >>= shiftBy; - } else /*if (shiftBy >= 33)*/ { - shifterCarryOutput = false; - op2 = 0; - } - break; - case 2: // Arithmetic Right (ASR) - if (shiftBy == 0 || shiftBy >= 32) { - shifterCarryOutput = extract1(op2, 31); - op2 = (int32_t)op2 >> 31; - } else /*if (shiftBy <= 31)*/ { - shifterCarryOutput = extract1(op2, shiftBy - 1); - op2 = (int32_t)op2 >> shiftBy; - } - break; - case 3: // Rotate Right (ROR) - if (shiftBy == 0) { // treated as RRX - shifterCarryOutput = op2 & 1; - op2 >>= 1; - op2 |= flagC() ? 0x80000000 : 0; - } else { - shiftBy %= 32; - if (shiftBy == 0) { // like 32 - shifterCarryOutput = extract1(op2, 31); - // no change to op2 - } else { - shifterCarryOutput = extract1(op2, shiftBy - 1); - op2 = ROR(op2, shiftBy); + if (extract(Operand2, 4, 4) && (shiftBy == 0)) { + // register shift by 0 never does anything + shifterCarryOutput = flagC(); + } else { + switch (extract(Operand2, 6, 5)) { + case 0: // Logical Left (LSL) + if (shiftBy == 0) { + shifterCarryOutput = flagC(); + // no change to op2! + } else if (shiftBy <= 31) { + shifterCarryOutput = extract1(op2, 31 - shiftBy); + op2 <<= shiftBy; + } else if (shiftBy == 32) { + shifterCarryOutput = extract1(op2, 0); + op2 = 0; + } else /*if (shiftBy >= 33)*/ { + shifterCarryOutput = false; + op2 = 0; } + break; + case 1: // Logical Right (LSR) + if (shiftBy == 0 || shiftBy == 32) { + shifterCarryOutput = extract1(op2, 31); + op2 = 0; + } else if (shiftBy <= 31) { + shifterCarryOutput = extract1(op2, shiftBy - 1); + op2 >>= shiftBy; + } else /*if (shiftBy >= 33)*/ { + shifterCarryOutput = false; + op2 = 0; + } + break; + case 2: // Arithmetic Right (ASR) + if (shiftBy == 0 || shiftBy >= 32) { + shifterCarryOutput = extract1(op2, 31); + op2 = (int32_t)op2 >> 31; + } else /*if (shiftBy <= 31)*/ { + shifterCarryOutput = extract1(op2, shiftBy - 1); + op2 = (int32_t)op2 >> shiftBy; + } + break; + case 3: // Rotate Right (ROR) + if (shiftBy == 0) { // treated as RRX + shifterCarryOutput = op2 & 1; + op2 >>= 1; + op2 |= flagC() ? 0x80000000 : 0; + } else { + shiftBy %= 32; + if (shiftBy == 0) { // like 32 + shifterCarryOutput = extract1(op2, 31); + // no change to op2 + } else { + shifterCarryOutput = extract1(op2, shiftBy - 1); + op2 = ROR(op2, shiftBy); + } + } + break; } - break; } } else { // IMMEDIATE @@ -252,7 +259,6 @@ uint32_t ARM710a::execDataProcessing(bool I, uint32_t Opcode, bool S, uint32_t R uint32_t Rotate = extract(Operand2, 11, 8); uint32_t Imm = extract(Operand2, 7, 0); - Imm = (uint32_t)(int8_t)Imm; op2 = ROR(Imm, Rotate * 2); shifterCarryOutput = flagC(); // correct? unsure... } @@ -269,7 +275,7 @@ uint32_t ARM710a::execDataProcessing(bool I, uint32_t Opcode, bool S, uint32_t R flags |= (CPSR & CPSR_V); #define ADD_OP(a, b, c) \ - result = a + b + (uint32_t)(c); \ + result = (uint64_t)(a) + (uint64_t)(b) + (uint64_t)(c); \ flags |= (result & 0xFFFFFFFF) ? 0 : CPSR_Z; \ flags |= (result & 0x80000000) ? CPSR_N : 0; \ flags |= (result & 0x100000000) ? CPSR_C : 0; \ @@ -301,9 +307,11 @@ uint32_t ARM710a::execDataProcessing(bool I, uint32_t Opcode, bool S, uint32_t R // Output-less opcodes: special behaviour if (S) { CPSR = (CPSR & ~CPSR_FlagMask) | flags; +// log("CPSR setflags=%08x results in CPSR=%08x", flags, CPSR); } else if (Opcode == 8) { // MRS, CPSR -> Reg GPRs[Rd] = CPSR; + log("r%d <- CPSR(%08x)", Rd, GPRs[Rd]); } else if (Opcode == 9) { // MSR, Reg -> CPSR bool canChangeMode = extract1(Rn, 0); @@ -311,27 +319,33 @@ uint32_t ARM710a::execDataProcessing(bool I, uint32_t Opcode, bool S, uint32_t R auto newCPSR = GPRs[extract(Operand2, 3, 0)]; switchMode(modeFromCPSR(newCPSR)); CPSR = newCPSR; + log("CPSR change privileged: %08x", CPSR); } else { // for the flag-only version, immediates are allowed // so we just re-use what was calculated earlier... auto newFlag = I ? op2 : GPRs[extract(Operand2, 3, 0)]; CPSR &= ~CPSR_FlagMask; CPSR |= (newFlag & CPSR_FlagMask); + log("CPSR change unprivileged: new=%08x result=%08x", newFlag, CPSR); } } else if (Opcode == 0xA) { // MRS, SPSR -> Reg - if (isPrivileged()) + if (isPrivileged()) { GPRs[Rd] = SPSRs[currentBank()]; + log("r%d <- SPSR(%08x)", Rd, GPRs[Rd]); + } } else /*if (Opcode == 0xB)*/ { bool canChangeMode = extract1(Rn, 0); if (isPrivileged()) { if (canChangeMode) { SPSRs[currentBank()] = GPRs[extract(Operand2, 3, 0)]; + log("SPSR change privileged: %08x", SPSRs[currentBank()]); } else { // same hat auto newFlag = I ? op2 : GPRs[extract(Operand2, 3, 0)]; SPSRs[currentBank()] &= ~CPSR_FlagMask; SPSRs[currentBank()] |= (newFlag & CPSR_FlagMask); + log("SPSR change unprivileged: new=%08x result=%08x", newFlag, SPSRs[currentBank()]); } } } @@ -348,9 +362,11 @@ uint32_t ARM710a::execDataProcessing(bool I, uint32_t Opcode, bool S, uint32_t R auto saved = SPSRs[currentBank()]; switchMode(modeFromCPSR(saved)); CPSR = saved; + log("dataproc restore CPSR: %08x", CPSR); } } else if (S) { CPSR = (CPSR & ~CPSR_FlagMask) | flags; +// log("dataproc flag change: flags=%08x CPSR=%08x", flags, CPSR); } } @@ -400,7 +416,7 @@ uint32_t ARM710a::execSingleDataTransfer(uint32_t IPUBWL, uint32_t Rn, uint32_t auto valueSize = extract1(IPUBWL, 2) ? V8 : V32; bool up = extract1(IPUBWL, 3); bool preIndex = extract1(IPUBWL, 4); - bool immediate = extract1(IPUBWL, 5); + bool immediate = !extract1(IPUBWL, 5); // calculate the offset uint32_t calcOffset; @@ -438,10 +454,8 @@ uint32_t ARM710a::execSingleDataTransfer(uint32_t IPUBWL, uint32_t Rn, uint32_t } } else { // IMMEDIATE - uint32_t Rotate = extract(offset, 11, 8); - uint32_t Imm = extract(offset, 7, 0); - Imm = (uint32_t)(int8_t)Imm; - calcOffset = ROR(Imm, Rotate * 2); + // No rotation or anything here + calcOffset = offset; } uint32_t base = GPRs[Rn]; @@ -458,8 +472,10 @@ uint32_t ARM710a::execSingleDataTransfer(uint32_t IPUBWL, uint32_t Rn, uint32_t if (changeModes) switchMode(User32); auto readResult = readVirtual(transferAddr, valueSize); if (changeModes) switchMode(saveMode); - if (readResult.first.has_value()) + if (readResult.first.has_value()) { GPRs[Rd] = readResult.first.value(); + if (Rd == 15) prefetchCount = 0; + } fault = readResult.second; } else { uint32_t value = GPRs[Rd]; @@ -538,6 +554,9 @@ uint32_t ARM710a::execBlockDataTransfer(uint32_t PUSWL, uint32_t Rn, uint32_t re } } + if (registerList & 0x8000) + prefetchCount = 0; + // datasheet specifies that base register must be // restored if an error occurs during LDM if (load && fault != NoFault) @@ -741,7 +760,7 @@ pair ARM710a::readVirtual(uint32_t virtAddr, ValueS if (auto v = readPhysical(virtAddr, valueSize); v.has_value()) return make_pair(v.value(), NoFault); else - return make_pair(MaybeU32(), NonMMUError); + return make_pair(MaybeU32(), encodeFault(NonMMUError, 0, virtAddr)); } auto translated = translateAddressUsingTlb(virtAddr); @@ -775,7 +794,7 @@ ARM710a::MMUFault ARM710a::writeVirtual(uint32_t value, uint32_t virtAddr, Value if (!isMMUEnabled()) { // direct virtual -> physical mapping, sans MMU if (!writePhysical(value, virtAddr, valueSize)) - return NonMMUError; + return encodeFault(NonMMUError, 0, virtAddr); } else { auto translated = translateAddressUsingTlb(virtAddr); if (holds_alternative(translated)) @@ -965,12 +984,61 @@ ARM710a::MMUFault ARM710a::checkAccessPermissions(ARM710a::TlbEntry *entry, uint void ARM710a::reportFault(MMUFault fault) { if (fault != NoFault) { if ((fault & 0xF) != NonMMUError) { - cp15_faultStatus = fault & 0xFFFF; - cp15_faultAddress = fault >> 32; + cp15_faultStatus = fault & (MMUFaultTypeMask | MMUFaultDomainMask); + cp15_faultAddress = fault >> MMUFaultAddressShift; } + static const char *faultTypes[] = { + "NoFault", + "AlignmentFault", + "???", + "NonMMUError", + "SectionLinefetchError", + "SectionTranslationFault", + "PageLinefetchError", + "PageTranslationFault", + "SectionOtherBusError", + "SectionDomainFault", + "PageOtherBusError", + "PageDomainFault", + "Lv1TranslationError", + "SectionPermissionFault", + "Lv2TranslationError", + "PagePermissionFault" + }; + log("⚠️ Fault type=%s domain=%d address=%08x pc=%08x lr=%08x", + faultTypes[fault & MMUFaultTypeMask], + (fault & MMUFaultDomainMask) >> MMUFaultDomainShift, + fault >> MMUFaultAddressShift, + GPRs[15], GPRs[14]); + // this signals a branch to DataAbort after the // instruction is done executing faultTriggeredThisCycle = true; } } + + +void ARM710a::log(const char *format, ...) { + if (logger) { + char buffer[1024]; + + va_list vaList; + va_start(vaList, format); + vsnprintf(buffer, sizeof(buffer), format, vaList); + va_end(vaList); + + logger(buffer); + } +} + + +void ARM710a::test() { + uint64_t result; + uint32_t flags = 0; + uint32_t v = 0x10000000; + + SUB_OP(v, v, 1); + + log("RESULT:%llx FLAGS:%08x", result, flags); +} diff --git a/WindCore/arm710a.h b/WindCore/arm710a.h index f4116d6..30fc2a5 100644 --- a/WindCore/arm710a.h +++ b/WindCore/arm710a.h @@ -18,6 +18,8 @@ typedef optional MaybeU32; class ARM710a { public: + void test(); + enum ValueSize { V8 = 0, V32 = 1 }; enum MMUFault : uint64_t { @@ -42,8 +44,11 @@ public: // so we are reusing it for nefarious purposes NonMMUError = 3, + MMUFaultTypeMask = 0xF, MMUFaultDomainMask = 0xF0, - MMUFaultAddressMask = 0xFFFFFFFF00000000 + MMUFaultDomainShift = 4, + MMUFaultAddressMask = 0xFFFFFFFF00000000, + MMUFaultAddressShift = 32 }; @@ -83,6 +88,7 @@ public: void requestIRQ(); // pull nIRQ low void reset(); // pull nRESET low + bool instructionReady() const { return (prefetchCount == 2); } uint32_t tick(); // run the chip for at least 1 clock cycle MaybeU32 readVirtualDebug(uint32_t virtAddr, ValueSize valueSize); @@ -94,8 +100,14 @@ public: virtual bool writePhysical(uint32_t value, uint32_t physAddr, ARM710a::ValueSize valueSize) = 0; uint32_t getGPR(int index) const { return GPRs[index]; } + uint32_t getCPSR() const { return CPSR; } + void setLogger(std::function newLogger) { logger = newLogger; } +protected: + void log(const char *format, ...); private: + std::function logger; + enum { Nop = 0xE1A00000 }; enum Mode : uint8_t { @@ -158,22 +170,22 @@ private: bool flagN() const { return CPSR & CPSR_N; } bool checkCondition(int cond) const { switch (cond) { - case 0: return flagZ(); - case 1: return !flagZ(); - case 2: return flagC(); - case 3: return !flagC(); - case 4: return flagN(); - case 5: return !flagN(); - case 6: return flagV(); - case 7: return !flagV(); - case 8: return flagC() && !flagZ(); - case 9: return !flagC() || flagZ(); - case 0xA: return flagN() == flagV(); - case 0xB: return flagN() != flagV(); - case 0xC: return !flagZ() && (flagN() == flagV()); - case 0xD: return flagZ() || (flagN() != flagV()); - case 0xE: return true; - /*case 0xF:*/ + /*EQ*/ case 0: return flagZ(); + /*NE*/ case 1: return !flagZ(); + /*CS*/ case 2: return flagC(); + /*CC*/ case 3: return !flagC(); + /*MI*/ case 4: return flagN(); + /*PL*/ case 5: return !flagN(); + /*VS*/ case 6: return flagV(); + /*VC*/ case 7: return !flagV(); + /*HI*/ case 8: return flagC() && !flagZ(); + /*LS*/ case 9: return !flagC() || flagZ(); + /*GE*/ case 0xA: return flagN() == flagV(); + /*LT*/ case 0xB: return flagN() != flagV(); + /*GT*/ case 0xC: return !flagZ() && (flagN() == flagV()); + /*LE*/ case 0xD: return flagZ() || (flagN() != flagV()); + /*AL*/ case 0xE: return true; + /*NV*/ /*case 0xF:*/ default: return false; } } diff --git a/WindCore/emu.cpp b/WindCore/emu.cpp index 4234af9..d878c9e 100644 --- a/WindCore/emu.cpp +++ b/WindCore/emu.cpp @@ -224,6 +224,8 @@ MaybeU32 Emu::readPhysical(uint32_t physAddr, ValueSize valueSize) { else if (region == 0xD1) return MemoryBlockD1[physAddr & MemoryBlockMask]; #endif + else if (region >= 0xC0) + return 0xFF; // just throw accesses to unmapped RAM away } else { uint32_t result; if (region == 0) @@ -244,6 +246,8 @@ MaybeU32 Emu::readPhysical(uint32_t physAddr, ValueSize valueSize) { else if (region == 0xD1) LOAD_32LE(result, physAddr & MemoryBlockMask, MemoryBlockD1); #endif + else if (region >= 0xC0) + return 0xFFFFFFFF; // just throw accesses to unmapped RAM away else return {}; return result; @@ -267,6 +271,8 @@ bool Emu::writePhysical(uint32_t value, uint32_t physAddr, ValueSize valueSize) else if (region == 0xD1) MemoryBlockD1[physAddr & MemoryBlockMask] = (uint8_t)value; #endif + else if (region >= 0xC0) + return true; // just throw accesses to unmapped RAM away else if (region == 0x20 && physAddr <= 0x20000FFF) etna.writeReg8(physAddr & 0xFFF, value); else if (region == 0x80 && physAddr <= 0x80000FFF) @@ -287,6 +293,8 @@ bool Emu::writePhysical(uint32_t value, uint32_t physAddr, ValueSize valueSize) else if (region == 0xD1) STORE_32LE(value, physAddr & MemoryBlockMask, MemoryBlockD1); #endif + else if (region >= 0xC0) + return true; // just throw accesses to unmapped RAM away else if (region == 0x20 && physAddr <= 0x20000FFF) etna.writeReg32(physAddr & 0xFFF, value); else if (region == 0x80 && physAddr <= 0x80000FFF) @@ -311,6 +319,7 @@ void Emu::configure() { nextTickAt = TICK_INTERVAL; rtc = getRTC(); + setProcessorID(0x41807100); reset(); } @@ -352,11 +361,15 @@ void Emu::executeUntil(int64_t cycles) { // keep the clock moving passedCycles++; } else { + if (auto v = virtToPhys(getGPR(15) - 0xC); v.has_value() && instructionReady()) + debugPC(v.value()); passedCycles += tick(); uint32_t new_pc = getGPR(15) - 0xC; - if (_breakpoints.find(new_pc) != _breakpoints.end()) + if (_breakpoints.find(new_pc) != _breakpoints.end()) { + log("⚠️ Breakpoint triggered at %08x!\n", new_pc); return; + } } } } @@ -426,14 +439,34 @@ void Emu::debugPC(uint32_t pc) { const char *wut = identifyObjectCon(container); if (wut) { fetchName(obj, objName); - printf("OBJS: added %s at %08x <%s>", wut, obj, objName); if (strcmp(wut, "process") == 0) { - fetchProcessFilename(obj, objName); - printf(" <%s>", objName); + char procName[1000]; + fetchProcessFilename(obj, procName); + log("OBJS: added %s at %08x <%s> <%s>", wut, obj, objName, procName); + } else { + log("OBJS: added %s at %08x <%s>", wut, obj, objName); } - printf("\n"); } } + + if (pc == 0x6D8) { + uint32_t virtAddr = getGPR(0); + uint32_t physAddr = getGPR(1); + uint32_t btIndex = getGPR(2); + uint32_t regionSize = getGPR(3); + log("KERNEL MMU SECTION: v:%08x p:%08x size:%08x idx:%02x", + virtAddr, physAddr, regionSize, btIndex); + } + if (pc == 0x710) { + uint32_t virtAddr = getGPR(0); + uint32_t physAddr = getGPR(1); + uint32_t btIndex = getGPR(2); + uint32_t regionSize = getGPR(3); + uint32_t pageTableA = getGPR(4); + uint32_t pageTableB = getGPR(5); + log("KERNEL MMU PAGES: v:%08x p:%08x size:%08x idx:%02x tableA:%08x tableB:%08x", + virtAddr, physAddr, regionSize, btIndex, pageTableA, pageTableB); + } } diff --git a/WindQt/mainwindow.cpp b/WindQt/mainwindow.cpp index 36a385e..31ad800 100644 --- a/WindQt/mainwindow.cpp +++ b/WindQt/mainwindow.cpp @@ -10,9 +10,14 @@ MainWindow::MainWindow(QWidget *parent) : ui(new Ui::MainWindow) { ui->setupUi(this); + ui->logView->setMaximumBlockCount(1000); emu = new Emu; emu->loadROM("/Users/ash/src/psion/Sys$rom.bin"); + emu->setLogger([&](const char *str) { + ui->logView->appendPlainText(str); + }); + emu->test(); timer = new QTimer(this); timer->setInterval(1000/64); @@ -32,8 +37,25 @@ void MainWindow::updateScreen() updateMemory(); + char flagDisplay[] = { + (emu->getCPSR() & 0x80000000) ? 'N' : '-', + (emu->getCPSR() & 0x40000000) ? 'Z' : '-', + (emu->getCPSR() & 0x20000000) ? 'C' : '-', + (emu->getCPSR() & 0x10000000) ? 'V' : '-', + 0 + }; + const char *modeName = "???"; + switch (emu->getCPSR() & 0x1F) { + case 0x10: modeName = "User"; break; + case 0x11: modeName = "FIQ"; break; + case 0x12: modeName = "IRQ"; break; + case 0x13: modeName = "Supervisor"; break; + case 0x17: modeName = "Abort"; break; + case 0x1B: modeName = "Undefined"; break; + } + ui->regsLabel->setText( - QString("R0: %1 / R1: %2 / R2: %3 / R3: %4 / R4: %5 / R5: %6 / R6: %7 / R7: %8\nR8: %9 / R9: %10 / R10:%11 / R11:%12 / R12:%13 / SP: %14 / LR: %15 / PC: %16") + QString("R0: %1 / R1: %2 / R2: %3 / R3: %4 / R4: %5 / R5: %6 / R6: %7 / R7: %8\nR8: %9 / R9: %10 / R10:%11 / R11:%12 / R12:%13 / SP: %14 / LR: %15 / PC: %16\n%17 / Mode: %18") .arg(emu->getGPR(0), 8, 16) .arg(emu->getGPR(1), 8, 16) .arg(emu->getGPR(2), 8, 16) @@ -50,11 +72,13 @@ void MainWindow::updateScreen() .arg(emu->getGPR(13), 8, 16) .arg(emu->getGPR(14), 8, 16) .arg(emu->getGPR(15), 8, 16) + .arg(flagDisplay) + .arg(modeName) ); // show a crude disassembly const int context = 8 * 4; - uint32_t pc = emu->getGPR(15) - 4; + uint32_t pc = emu->getGPR(15) - 8; uint32_t minCode = pc - context; if (minCode >= (UINT32_MAX - context)) minCode = 0; @@ -64,7 +88,7 @@ void MainWindow::updateScreen() QStringList codeLines; for (uint32_t addr = minCode; addr >= minCode && addr <= maxCode; addr += 4) { - const char *prefix = (addr == pc) ? "==>" : " "; + const char *prefix = (addr == pc) ? (emu->instructionReady() ? "==>" : "...") : " "; struct ARMInstructionInfo info; char buffer[512]; @@ -228,8 +252,9 @@ void MainWindow::on_stopButton_clicked() void MainWindow::on_stepTickButton_clicked() { - emu->executeUntil(emu->currentCycles() + (CLOCK_SPEED * 2)); - updateScreen(); +// emu->executeUntil(emu->currentCycles() + (CLOCK_SPEED * 2)); + emu->executeUntil(emu->currentCycles() + 25000); + updateScreen(); } void MainWindow::on_stepInsnButton_clicked() diff --git a/WindQt/mainwindow.ui b/WindQt/mainwindow.ui index 7ddbdd5..c2250b6 100644 --- a/WindQt/mainwindow.ui +++ b/WindQt/mainwindow.ui @@ -22,72 +22,6 @@ - - - - - Courier New - - - - - - - - - - - Start - - - - - - - Step (Tick) - - - - - - - Qt::ClickFocus - - - - - - - - - - Step (Insn) - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - false - - - Stop - - - @@ -315,6 +249,75 @@ + + + + + Courier New + + + + + + + + + + + Start + + + + + + + Step (Tick) + + + + + + + Qt::ClickFocus + + + + + + + + + + Step (Insn) + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + false + + + Stop + + + + + +