void LCDScreen::seeSamplingEdge(ticks_t time) { ++edgeCounter; // TODO According to the AT043TN24 datasheet data should be sampled on the // falling edge. However the sc_lcd code drives on the falling edge so for // the moment sample on the rising to match that. if (DETracker.getSignal().getValue(time)) { // Thb const unsigned minHorizontalClks = 40; // Th * tvb const unsigned minVerticalClks = 5 * 520; ticks_t lowEdges = edgeCounter - (lastDEHighEdge + 1); if (lowEdges >= minVerticalClks) { // VSync x = y = 0; screen.flip(); } else if (lowEdges >= minHorizontalClks) { // HSync x = 0; ++y; } if (x < screen.getWidth() && y < screen.getHeigth()) { screen.writePixel(x++, y, DataTracker.getSignal().getValue(time)); } lastDEHighEdge = edgeCounter; } }
SDRAM::Command SDRAM::getCommand(ticks_t time) const { uint32_t cmd = 0; if (WE.getSignal().getValue(time)) cmd |= 0x1; if (CAS.getSignal().getValue(time)) cmd |= 0x2; if (RAS.getSignal().getValue(time)) cmd |= 0x4; switch (cmd) { default: assert(0 && "Unexpected cmd"); case 0: return Command::LOAD_MODE_REGISTER; case 1: return Command::AUTO_REFRESH; case 2: return Command::PRECHARGE; case 3: return Command::ACTIVE; case 4: return Command::WRITE; case 5: return Command::READ; case 6: return Command::BURST_TERMINATE; case 7: return Command::NOP; } }
bool SDRAM::getUDQMValue(ticks_t time) const { if (useUDQM) return UDQM.getSignal().getValue(time); // Otherwise use NOR of CAS and RAS signal to match the SDRAM slice. return CAS.getSignal().getValue(time) == 0 && RAS.getSignal().getValue(time) == 0; }
void SDRAM::seeCLKChange(const Signal &value, ticks_t time) { if (value.getValue(time)) { // Rising edge. Command newCommand = getCommand(time); switch (newCommand) { case Command::ACTIVE: currentRow = A.getSignal().getValue(time) & ((1 << config.rowBits) - 1); break; case Command::AUTO_REFRESH: case Command::NOP: case Command::PRECHARGE: break; case Command::LOAD_MODE_REGISTER: modeReg.set(A.getSignal().getValue(time)); break; case Command::READ: currentColumn = A.getSignal().getValue(time) & ((1 << config.columnBits) - 1); currentBank = BA.getSignal().getValue(time) & ((1 << config.bankBits) - 1); counter = 0; break; case Command::WRITE: currentColumn = A.getSignal().getValue(time) & ((1 << config.columnBits) - 1); currentBank = BA.getSignal().getValue(time) & ((1 << config.bankBits) - 1); counter = 0; break; case Command::BURST_TERMINATE: break; } if (newCommand != Command::NOP) { currentCommand = newCommand; } switch (currentCommand) { default: break; case Command::READ: { uint16_t mask = getReadWriteMask(time); unsigned burstLength = modeReg.getReadBurstLength(); uint16_t data = mem[getMemoryIndex(burstLength)] & mask; uint8_t readEdge = edgeNumber + modeReg.getCASLatency(); pendingReads.push(std::make_pair(data, readEdge)); ++counter; if (burstLength != 0 && counter == burstLength) currentCommand = Command::NOP; } break; case Command::WRITE: { unsigned burstLength = modeReg.getReadBurstLength(); if (WE.getSignal().getValue(time)) { uint16_t mask = getReadWriteMask(time); uint32_t index = getMemoryIndex(burstLength); uint16_t old = mem[index]; uint16_t data = DQ.getSignal().getValue(time); mem[index] ^= (old ^ data) & mask; } ++counter; if (burstLength != 0 && counter == burstLength) currentCommand = Command::NOP; } break; } ++edgeNumber; } else { // Falling edge. if (!pendingReads.empty() && pendingReads.front().second == edgeNumber) { DQPort->seePinsChange(Signal(pendingReads.front().first), time); pendingReads.pop(); } } }