public void notifyRead(int address) { if (cpu.isFlashBusy) { triggerAccessViolation("Flash read not allowed while BUSY flag set"); return; } if (DEBUG) { if (wait == false && currentWriteMode == WriteMode.WRITE_BLOCK) { log("Reading flash prohibited. Would read 0x3fff!!!"); log("CPU PC=$" + Utils.hex(cpu.getPC(), 4) + " read address $" + Utils.hex(address, 4)); } } }
private void triggerAccessViolation(String reason) { logw( WarningType.EXECUTION, "Access violation: " + reason + ". PC=$" + Utils.hex(cpu.getPC(), 4)); statusreg |= ACCVIFG; if (cpu.getSFR().isIEBitsSet(SFR.IE1, ACCVIE)) { cpu.flagInterrupt(NMI_VECTOR, this, true); } }
public void write(int address, int value, boolean word, long cycles) { if (address == offset) { if ((value >> 8) == 0x5a) { wdtctl = value & 0xff; if (DEBUG) log("Wrote to WDTCTL: " + Utils.hex8(wdtctl) + " from $" + Utils.hex(cpu.getPC(), 4)); // Is it on? wdtOn = (value & 0x80) == 0; // boolean lastACLK = sourceACLK; sourceACLK = (value & WDTSSEL) != 0; // scheduleTimer should use the current delay, so update delay each time // issue: if WDTCNTCL is not active the timer should be recalculated but an new timer is // scheduled // if ((value & WDTCNTCL) != 0) { // Clear timer => reset the delay delay = DELAY[value & WDTISx]; // } timerMode = (value & WDTMSEL) != 0; // Start it if it should be started! if (wdtOn) { if (DEBUG) log("Setting WDTCNT to count: " + delay); scheduleTimer(); } else { // Stop it and remember current "delay" left! wdtTrigger.remove(); } } else { // Trigger reset!! logw( WarningType.EXECUTION, "illegal write to WDTCTL (" + value + ") from $" + Utils.hex(cpu.getPC(), 4) + " - reset!!!!"); cpu.flagInterrupt(resetVector, this, true); } } }
public void flashWrite(int address, int data, AccessMode dataMode) { int wait_time = -1; if (locked) { if (DEBUG) { log("Write to flash blocked because of LOCK flag."); } return; } if (cpu.isFlashBusy || wait == false) { if (!((mode & BLKWRT) != 0 && wait)) { triggerAccessViolation("Flash write prohbited while BUSY=1 or WAIT=0"); return; } } switch (currentWriteMode) { case ERASE_SEGMENT: int a_area_start[] = new int[1]; int a_area_end[] = new int[1]; getSegmentRange(address, a_area_start, a_area_end); int area_start = a_area_start[0]; int area_end = a_area_end[0]; if (DEBUG) { log( "Segment erase @" + Utils.hex(address, 4) + ": erasing area " + Utils.hex(area_start, 4) + "-" + Utils.hex(area_end, 4)); } for (int i = area_start; i < area_end; i++) { memory[i] = 0xff; } waitFlashProcess(SEGMENT_ERASE_TIME); break; case ERASE_MAIN: if (!main_range.isInRange(address)) { return; } for (int i = main_range.start; i < main_range.end; i++) { memory[i] = 0xff; } waitFlashProcess(MASS_ERASE_TIME); break; case ERASE_ALL: for (int i = main_range.start; i < main_range.end; i++) { memory[i] = 0xff; } for (int i = info_range.start; i < main_range.end; i++) { memory[i] = 0xff; } waitFlashProcess(MASS_ERASE_TIME); break; case WRITE_SINGLE: case WRITE_BLOCK: if (currentWriteMode == WriteMode.WRITE_BLOCK) { wait = false; // TODO: Register target block and verify all writes stay in the same // block. What does the real hardware on random writes?!? if (blockwriteCount == 0) { wait_time = BLOCKWRITE_FIRST_TIME; if (DEBUG) { log("Flash write in block mode started @" + Utils.hex(address, 4)); } if (addressInFlash(cpu.getPC())) { logw( WarningType.EXECUTION, "Oops. Block write access only allowed when executing from RAM."); } } else { wait_time = BLOCKWRITE_TIME; } } else { wait_time = WRITE_TIME; } /* Flash memory allows clearing bits only */ memory[address] &= data & 0xff; if (dataMode != AccessMode.BYTE) { memory[address + 1] &= (data >> 8) & 0xff; if (dataMode == AccessMode.WORD20) { /* TODO should the write really write the full word? CHECK THIS */ memory[address + 2] &= (data >> 16) & 0xff; memory[address + 3] &= (data >> 24) & 0xff; } } if (DEBUG) { log( "Writing $" + Utils.hex20(data) + " to $" + Utils.hex(address, 4) + " (" + dataMode.bytes + " bytes)"); } waitFlashProcess(wait_time); break; } }