diff --git a/Makefile b/Makefile index d2029cc..1ec0ba2 100644 --- a/Makefile +++ b/Makefile @@ -43,22 +44,22 @@ check-config: # build targets clean: check-config - @make ${BUILD_CONFIG_OPTS} clean + @+make ${BUILD_CONFIG_OPTS} clean build: check-config - @make ${BUILD_CONFIG_OPTS} + @+make ${BUILD_CONFIG_OPTS} check: check-config - @make ${BUILD_CONFIG_OPTS} check + @+make ${BUILD_CONFIG_OPTS} check doc: check-config - @make ${BUILD_CONFIG_OPTS} doc + @+make ${BUILD_CONFIG_OPTS} doc doxygen: check-config - @make ${BUILD_CONFIG_OPTS} doxygen + @+make ${BUILD_CONFIG_OPTS} doxygen debian: check-config - @make ${BUILD_CONFIG_OPTS} debian + @+make ${BUILD_CONFIG_OPTS} debian # configure targets @@ -113,6 +114,6 @@ simple: # maintainance targets keytrans: check-config - @make ${BUILD_CONFIG_OPTS} keytrans + @+make ${BUILD_CONFIG_OPTS} keytrans # EOF diff --git a/app/gdbserver.cpp b/app/gdbserver.cpp index 632ede9..2941c6d 100644 --- a/app/gdbserver.cpp +++ b/app/gdbserver.cpp @@ -124,7 +124,7 @@ int GdbServerSocketUnix::ReadByte(void) { } void GdbServerSocketUnix::Write(const void* buf, size_t count) { - int res; + ssize_t res; res = write(conn, buf, count); @@ -134,8 +134,8 @@ void GdbServerSocketUnix::Write(const void* buf, size_t count) { /* FIXME: if this happens a lot, we could try to resend the unsent bytes. */ - if((unsigned int)res != count) - avr_error("write only wrote %d of %lu bytes", res, count); + if((size_t)res != count) + avr_error("write only wrote %d of %u bytes", res, count); } void GdbServerSocketUnix::SetBlockingMode(int mode) { diff --git a/app/main.cpp b/app/main.cpp index 41e50cb..7b4d1de 100644 --- a/app/main.cpp +++ b/app/main.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include @@ -221,12 +222,10 @@ int main(int argc, char *argv[]) { unsigned long long maxRunTime = 0; UserInterface *ui; - unsigned long writeToPipeOffset = 0x20; - unsigned long readFromPipeOffset = 0x21; unsigned long writeToAbort = 0; unsigned long writeToExit = 0; - std::string readFromPipeFileName = ""; - std::string writeToPipeFileName = ""; + std::list listReadFromPipeFileName; + std::list listWriteToPipeFileName; std::vector terminationArgs; @@ -279,15 +278,13 @@ int main(int argc, char *argv[]) { case 'v': global_verbose_on = 1; break; - - case 'R': //read from pipe - readFromPipeFileName = - SplitOffsetFile(optarg, "readFromPipe", 16, &readFromPipeOffset); + + case 'R': //read from pipe + listReadFromPipeFileName.push_back(optarg); break; - + case 'W': //write to pipe - writeToPipeFileName = - SplitOffsetFile(optarg, "writeToPipe", 16, &writeToPipeOffset); + listWriteToPipeFileName.push_back(optarg); break; case 'a': // write to abort @@ -475,18 +472,26 @@ int main(int argc, char *argv[]) { } //if we want to insert some special "pipe" Registers we could do this here: - if(readFromPipeFileName != "") { - avr_message("Add ReadFromPipe-Register at 0x%lx and read from file: %s", - readFromPipeOffset, readFromPipeFileName.c_str()); - dev1->ReplaceIoRegister(readFromPipeOffset, - new RWReadFromFile(dev1, "FREAD", readFromPipeFileName.c_str())); + for (std::list::iterator it = listReadFromPipeFileName.begin(); + it != listReadFromPipeFileName.end(); it++) { + unsigned long readFromPipeOffset = 0x21; + const std::string readFromPipeFileName = + SplitOffsetFile(it->c_str(), "readFromPipe", 16, &readFromPipeOffset); + avr_message("Add ReadFromPipe-Register at 0x%lx and read from file: %s", + readFromPipeOffset, readFromPipeFileName.c_str()); + dev1->ReplaceIoRegister(readFromPipeOffset, + new RWReadFromFile(dev1, std::string("FREAD") + std::to_string((long long unsigned)readFromPipeOffset), readFromPipeFileName.c_str())); } - - if(writeToPipeFileName != "") { - avr_message("Add WriteToPipe-Register at 0x%lx and write to file: %s", - writeToPipeOffset, writeToPipeFileName.c_str()); - dev1->ReplaceIoRegister(writeToPipeOffset, - new RWWriteToFile(dev1, "FWRITE", writeToPipeFileName.c_str())); + + for (std::list::iterator it = listWriteToPipeFileName.begin(); + it != listWriteToPipeFileName.end(); it++) { + unsigned long writeToPipeOffset = 0x20; + const std::string writeFromPipeFileName = + SplitOffsetFile(it->c_str(), "writeFromPipe", 16, &writeToPipeOffset); + avr_message("Add WriteToPipe-Register at 0x%lx and write from file: %s", + writeToPipeOffset, writeFromPipeFileName.c_str()); + dev1->ReplaceIoRegister(writeToPipeOffset, + new RWWriteToFile(dev1, std::string("FWRITE") + std::to_string((long long unsigned)writeToPipeOffset), writeFromPipeFileName.c_str())); } if(writeToAbort) { diff --git a/include/atxmega128aubase.h b/include/atxmega128aubase.h new file mode 100644 index 0000000..65acf79 --- /dev/null +++ b/include/atxmega128aubase.h @@ -0,0 +1,174 @@ + /* + **************************************************************************** + * + * simulavr - A simulator for the Atmel AVR family of microcontrollers. + * Copyright (C) 2021 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + **************************************************************************** + * + * $Id$ + */ + + +#ifndef ATXMEGA128AUBASE +#define ATXMEGA128AUBASE + +#include "avrdevice.h" +#include "hardware.h" +#include "rwmem.h" +#include "hwtimer/timerprescaler.h" +#include "hwtimer/timerirq.h" +#include "hwtimer/hwtimer.h" +#include "externalirq.h" +#include "hwuart.h" +#include "hwport.h" +#include "hwxport.h" +#include "hwspi.h" +#include "hwad.h" +#include "hwacomp.h" +#include "hwnvm.h" +#include "pin.h" + +#include "ioregs.h" //only for rampz here + +#include + +// Poly2: https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-8331-8-and-16-bit-AVR-Microcontroller-XMEGA-AU_Manual.pdf +// Poly5: https://ww1.microchip.com/downloads/en/devicedoc/atmel-0856-avr-instruction-set-manual.pdf +//! AVRDevice class for ATXMEGAxxxA4U +class AvrDevice_atxmega128aubase: public AvrDevice { + public: + // GPIORegister gpio[16]; // General purpose IO registers + HWPort vport0; // Virtual Port + HWPort vport1; // Virtual Port + HWPort vport2; // Virtual Port + HWPort vport3; // Virtual Port + // HWAd * adca[4]; // Analog to digital converter on port A + // HWAd * adcb[4]; // Analog to digital converter on port B + // HWAcomp * aca; // Analog comparator pair on port A + // HWAcomp * acb; // Analog comparator pair on port B + HWxPort porta; // Port A + HWxPort portb; // Port B + HWxPort portc; // Port C + HWxPort portd; // Port D + HWxPort porte; // Port E + HWxPort portf; // Port F + HWxPort portg; // Port G + HWxPort porth; // Port H + HWxPort portj; // Port J + HWxPort portk; // Port K + HWxPort portl; // Port L + HWxPort portm; // Port M + HWxPort portn; // Port N + HWxPort portp; // Port P + HWxPort portq; // Port Q + HWxPort portr; // Port R + + HWAdmuxM16 *admux; + HWARef4 * aref; + HWNvm * nvm; + + AvrDevice_atxmega128aubase(unsigned flash_bytes, unsigned ee_bytes, unsigned ext_bytes, unsigned nrww_start); + ~AvrDevice_atxmega128aubase(); + + private: + std::list ioMem; + void changeIoToRam(unsigned int s_add, unsigned int e_add); + void changeToInvalidRam(unsigned int s_add, unsigned int e_add); +}; + +/* Name Flash+Btd eep ram +ATxmega128A1-AU 128K + 8K 2K 8K +ATxmega128A1-AUR 128K + 8K 2K 8K +ATxmega128A1-CU 128K + 8K 2K 8K +ATxmega128A1CUR 128K + 8K 2K 8K +ATxmega128A1-C7U 128K + 8K 2K 8K +ATxmega128A1-C7UR 128K + 8K 2K 8K +ATxmega64A1-AU 64K + 8K 2K 4K +ATxmega64A1-CU 64K + 8K 2K 4K +ATxmega64A1-CUR 64K + 8K 2K 4K +ATxmega64A1-C7U 64K + 8K 2K 4K +ATxmega64A1-C7UR 64K + 8K 2K 4K +*/ +class AvrDevice_atxmega128a1 : public AvrDevice_atxmega128aubase { + public: AvrDevice_atxmega128a1(); +}; + +class AvrDevice_atxmega64a1 : public AvrDevice_atxmega128aubase { + public: AvrDevice_atxmega64a1(); +}; + +/* Name Flash+Btd eep ram +ATxmega128A4U-AN 128K + 8K 2K 8K +ATxmega128A4U-ANR(4) 128K + 8K 2K 8K +ATxmega128A4U-AU 128K + 8K 2K 8K +ATxmega128A4U-AUR(4) 128K + 8K 2K 8K +ATxmega128A4U-CU 128K + 8K 2K 8K +ATxmega128A4U-CUR(4) 128K + 8K 2K 8K +ATxmega128A4U-M7 128K + 8K 2K 8K +ATxmega128A4U-M7R(4) 128K + 8K 2K 8K +ATxmega128A4U-MH 128K + 8K 2K 8K +ATxmega128A4U-MHR(4) 128K + 8K 2K 8K +ATxmega64A4U-AN 64K + 4K 2K 4K +ATxmega64A4U-ANR(4) 64K + 4K 2K 4K +ATxmega64A4U-AU 64K + 4K 2K 4K +ATxmega64A4U-AUR(4) 64K + 4K 2K 4K +ATxmega64A4U-CU 64K + 4K 2K 4K +ATxmega64A4U-CUR(4) 64K + 4K 2K 4K +ATxmega64A4U-M7 64K + 4K 2K 4K +ATxmega64A4U-M7R(4) 64K + 4K 2K 4K +ATxmega64A4U-MH 64K + 4K 2K 4K +ATxmega64A4U-MHR(4) 64K + 4K 2K 4K +ATxmega32A4U-AN 32K + 4K 1K 4K +ATxmega32A4U-ANR(4) 32K + 4K 1K 4K +ATxmega32A4U-AU 32K + 4K 1K 4K +ATxmega32A4U-AUR(4) 32K + 4K 1K 4K +ATxmega32A4U-CU 32K + 4K 1K 4K +ATxmega32A4U-CUR(4) 32K + 4K 1K 4K +ATxmega32A4U-M7 32K + 4K 1K 4K +ATxmega32A4U-M7R(4) 32K + 4K 1K 4K +ATxmega32A4U-MH 32K + 4K 1K 4K +ATxmega32A4U-MHR(4) 32K + 4K 1K 4K +ATxmega16A4U-AN 16K + 4K 1K 2K +ATxmega16A4U-ANR(4) 16K + 4K 1K 2K +ATxmega16A4U-AU 16K + 4K 1K 2K +ATxmega16A4U-AUR(4) 16K + 4K 1K 2K +ATxmega16A4U-CU 16K + 4K 1K 2K +ATxmega16A4U-CUR(4) 16K + 4K 1K 2k +ATxmega16A4U-M7 16K + 4K 1K 2K +ATxmega16A4U-M7R(4) 16K + 4K 1K 2K +ATxmega16A4U-MH 16K + 4K 1K 2K +ATxmega16A4U-MHR(4) 16K + 4K 1K 2K +*/ + +class AvrDevice_atxmega128a4u : public AvrDevice_atxmega128aubase { + public: AvrDevice_atxmega128a4u(); +}; + +class AvrDevice_atxmega64a4u : public AvrDevice_atxmega128aubase { + public: AvrDevice_atxmega64a4u(); +}; + +class AvrDevice_atxmega32a4u : public AvrDevice_atxmega128aubase { + public: AvrDevice_atxmega32a4u(); +}; + +class AvrDevice_atxmega16a4u : public AvrDevice_atxmega128aubase { + public: AvrDevice_atxmega16a4u(); +}; + +#endif // ATXMEGA128AUBASE diff --git a/include/avrdevice.h b/include/avrdevice.h index 21c0111..7f5dfd5 100644 --- a/include/avrdevice.h +++ b/include/avrdevice.h @@ -102,6 +102,9 @@ class AvrDevice: public SimulationMember, public TraceValueRegister { HWEeprom *eeprom; Data *data; ///< a hack for symbol look-up HWIrqSystem *irqSystem; + AddressExtensionRegister *rampd; //!< RAMPD address extension register + AddressExtensionRegister *rampx; //!< RAMPX address extension register + AddressExtensionRegister *rampy; //!< RAMPY address extension register AddressExtensionRegister *rampz; //!< RAMPZ address extension register AddressExtensionRegister *eind; //!< EIND address extension register bool abortOnInvalidAccess; //!< Flag, that simulation abort if an invalid access occured, default is false diff --git a/include/decoder.h b/include/decoder.h index ca78a9b..cbce0d1 100644 --- a/include/decoder.h +++ b/include/decoder.h @@ -2075,8 +2075,114 @@ class avr_op_BREAK: public DecodedInstruction int Trace(); }; +class avr_op_DES: public DecodedInstruction +{ + /* + * Data Encryption Standard + * + * Opcode : 0100 0100 KKKK 1011 + * Usage : DES K + * Operation : If H = 0 then Encrypt round (R7-R0, R15-R8, K) + * If H = 1 thenDecrypt round (R7-R0, R15-R8, K) + * Flags : None + * Num Clocks : 1 + */ + protected: + unsigned char K; + + public: + avr_op_DES(word opcode, AvrDevice *c); + int operator()(); + int Trace(); +}; + + +class avr_op_XCH: public DecodedInstruction +{ + /* + * Exchange + * + * Opcode : 1001 001r rrrr 0100 + * Usage : XCH Z,Rd + * Operation : (Z) <- Rd, Rd <- (Z) + * Flags : None + * Num Clocks : 2 + */ + + protected: + unsigned char R1; + + public: + avr_op_XCH(word opcode, AvrDevice *c); + int operator()(); + int Trace(); +}; + +class avr_op_LAS: public DecodedInstruction +{ + /* + * Load and Set + * + * Opcode : 1001 001r rrrr 0101 + * Usage : LAS Z,Rd + * Operation : (Z) <- Rd v (Z), Rd <- (Z) + * Flags : None + * Num Clocks : 2 + */ + + protected: + unsigned char R1; + + public: + avr_op_LAS(word opcode, AvrDevice *c); + int operator()(); + int Trace(); +}; + +class avr_op_LAC: public DecodedInstruction +{ + /* + * Load and Clear + * + * Opcode : 1001 001r rrrr 0110 + * Usage : LAC Z,Rd + * Operation : (Z) <- ($FF -Rd) . (Z), Rd <- (Z) + * Flags : None + * Num Clocks : 2 + */ + + protected: + unsigned char R1; + + public: + avr_op_LAC(word opcode, AvrDevice *c); + int operator()(); + int Trace(); +}; + +class avr_op_LAT: public DecodedInstruction +{ + /* + * Load and Toggle + * + * Opcode : 1001 001r rrrr 0111 + * Usage : LAT Z,Rd + * Operation : (Z) <- Rd ^ (Z), Rd <- (Z) + * Flags : None + * Num Clocks : 2 + */ + + protected: + unsigned char R1; + + public: + avr_op_LAT(word opcode, AvrDevice *c); + int operator()(); + int Trace(); +}; + class avr_op_ILLEGAL: public DecodedInstruction -{ +{ //illegal instruction public: diff --git a/include/flashprog.h b/include/flashprog.h index 595358c..ee8d571 100644 --- a/include/flashprog.h +++ b/include/flashprog.h @@ -101,7 +101,7 @@ class AvrFuses { private: int fuseBitsSize; //!< count of bits in fuses - unsigned long fuseBits; //!< fuse data + unsigned long long fuseBits; //!< fuse data unsigned int nrwwAddr; //!< start address NRWW section unsigned int nrwwSize; //!< size of NRWW section in byte int bitPosBOOTSZ; //!< bit position BOOTSZ fuses (2 Bit) in fuseBits @@ -116,7 +116,7 @@ class AvrFuses { AvrFuses(void); //! Configure fuses - void SetFuseConfiguration(int size, unsigned long defvalue); + void SetFuseConfiguration(int size, unsigned long long defvalue); //! Initialize fuses from elf, checks proper size bool LoadFuses(const unsigned char *buffer, int size); //! Get fuse byte by index diff --git a/include/hwnvm.h b/include/hwnvm.h new file mode 100644 index 0000000..e3fe2d4 --- /dev/null +++ b/include/hwnvm.h @@ -0,0 +1,131 @@ +/* + **************************************************************************** + * + * simulavr - A simulator for the Atmel AVR family of microcontrollers. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + **************************************************************************** + * + * $Id$ + */ + +#ifndef HWNVM_H +#define HWNVM_H + +#include "rwmem.h" +#include "hardware.h" +#include "traceval.h" +#include "avrdevice.h" + +// This class emulate an eeprom throught an nvm module. Data can be acceded +// throught diret addressing, by mapping IO reg or throught NVM command +// Warning: interrupt not implemented +// see http://ww1.microchip.com/downloads/en/AppNotes/doc8066.pdf +class HWNvm : public Hardware, public TraceValueRegister { + public: + enum Command { + // from iox128a1.h + NVM_CMD_NO_OPERATION = 0x00, // Noop/Ordinary LPM + NVM_CMD_READ_USER_SIG_ROW = 0x01, // Read user signature row + NVM_CMD_READ_CALIB_ROW = 0x02, // Read calibration row + NVM_CMD_READ_EEPROM = 0x06, // Read EEPROM + NVM_CMD_READ_FUSES = 0x07, // Read fuse byte + NVM_CMD_WRITE_LOCK_BITS = 0x08, // Write lock bits + NVM_CMD_ERASE_USER_SIG_ROW = 0x18, // Erase user signature row + NVM_CMD_WRITE_USER_SIG_ROW = 0x1A, // Write user signature row + NVM_CMD_ERASE_APP = 0x20, // Erase Application Section + NVM_CMD_ERASE_APP_PAGE = 0x22, // Erase Application Section page + NVM_CMD_LOAD_FLASH_BUFFER = 0x23, // Load Flash page buffer + NVM_CMD_WRITE_APP_PAGE = 0x24, // Write Application Section page + NVM_CMD_ERASE_WRITE_APP_PAGE = 0x25, // Erase-and-write Application Section page + NVM_CMD_ERASE_FLASH_BUFFER = 0x26, // Erase/flush Flash page buffer + NVM_CMD_ERASE_BOOT_PAGE = 0x2A, // Erase Boot Section page + NVM_CMD_WRITE_BOOT_PAGE = 0x2C, // Write Boot Section page + NVM_CMD_ERASE_WRITE_BOOT_PAGE = 0x2D, // Erase-and-write Boot Section page + NVM_CMD_ERASE_EEPROM = 0x30, // Erase EEPROM + NVM_CMD_ERASE_EEPROM_PAGE = 0x32, // Erase EEPROM page + NVM_CMD_LOAD_EEPROM_BUFFER = 0x33, // Load EEPROM page buffer + NVM_CMD_WRITE_EEPROM_PAGE = 0x34, // Write EEPROM page + NVM_CMD_ERASE_WRITE_EEPROM_PAGE = 0x35, // Erase-and-write EEPROM page + NVM_CMD_ERASE_EEPROM_BUFFER = 0x36, // Erase/flush EEPROM page buffer + NVM_CMD_APP_CRC = 0x38, // Generate Application section CRC + NVM_CMD_BOOT_CRC = 0x39, // Generate Boot Section CRC + NVM_CMD_FLASH_RANGE_CRC = 0x3A, // Generate Flash Range CRC + }; + + HWNvm(AvrDevice *core, unsigned int memoryMapSize); + virtual ~HWNvm(); + + virtual unsigned int CpuCycle(); + void Reset(); + + void SetAddr0(unsigned char); + void SetAddr1(unsigned char); + void SetAddr2(unsigned char); + void SetData0(unsigned char); + void SetData1(unsigned char); + void SetData2(unsigned char); + void SetCmd(unsigned char); + void SetCmdEx(unsigned char); + void SetCtrlb(unsigned char); + void SetIntctrl(unsigned char); + void SetStatus(unsigned char); + void SetLockbits(unsigned char); + void SetCcp(unsigned char); + + unsigned char GetAddr0(); + unsigned char GetAddr1(); + unsigned char GetAddr2(); + unsigned char GetData0(); + unsigned char GetData1(); + unsigned char GetData2(); + unsigned char GetCmd(); + unsigned char GetStatus(); + unsigned char GetCtrlb(); + unsigned char GetIntctrl(); + unsigned char GetLockbits(); + unsigned char GetCcp(); + + IOReg + addr0_reg, // low + addr1_reg, // high + addr2_reg, // extended + data0_reg, // low + data1_reg, // high + data2_reg, // extended + cmd_reg, + ctrla_reg, // CMDEX + ctrlb_reg, + intctrl_reg, + status_reg, + lockbits_reg, + ccp_reg; + + protected: + AvrDevice *m_core; + + private: + unsigned m_address; + unsigned m_data; + unsigned char m_command; + + unsigned char m_ctrlb; + unsigned char m_intctrl; + unsigned char m_lockbits; + unsigned char m_ccp; +}; + +#endif // HWEEPROM_NVM_H diff --git a/include/hwxport.h b/include/hwxport.h new file mode 100644 index 0000000..91eaf94 --- /dev/null +++ b/include/hwxport.h @@ -0,0 +1,81 @@ +/* + **************************************************************************** + * + * simulavr - A simulator for the Atmel AVR family of microcontrollers. + * Copyright (C) 2021 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + **************************************************************************** + * + * $Id$ + */ + +#ifndef HWXPORT +#define HWXPORT + +#include "hardware.h" +#include "hwport.h" +#include "pin.h" +#include "rwmem.h" +#include "traceval.h" + +#include + +//! Defines extended Port for atxmega, e.g. a hardware device for GPIO +/*! Example for use alternateDdr and useAlternateDdr: + If the UART Tx will be enabled, the UART set alternateDdr to output, + useAlternateDdr to 1 and sets port according to Tx Pin value, thats all :-) + + useAlternatePortIfDdrSet: special case for the OCR outputs, which only be + connected to pin if ddr is set to output! */ +class HWxPort: public HWPort { + protected: + void setDirset(unsigned char value); + void setPinBitDirset(bool val, unsigned int bit); + void setDirclr(unsigned char value); + void setPinBitDirclr(bool val, unsigned int bit); + void setDirtgl(unsigned char value); + void setPinBitDirtgl(bool val, unsigned int bit); + void setOutset(unsigned char value); + void setPinBitOutset(bool val, unsigned int bit); + void setOutclr(unsigned char value); + void setPinBitOutclr(bool val, unsigned int bit); + void setOuttgl(unsigned char value); + void setPinBitOuttgl(bool val, unsigned int bit); + void setInset(unsigned char value); + void setPinBitInset(bool val, unsigned int bit); + void setInclr(unsigned char value); + void setPinBitInclr(bool val, unsigned int bit); + void setIntgl(unsigned char value); + void setPinBitIntgl(bool val, unsigned int bit); + + public: + HWxPort(AvrDevice *core, const std::string &name, int size = 8); + ~HWxPort(); + + IOReg + // dir_reg is ddr_reg + dirset_reg, + dirclr_reg, + dirtgl_reg, + // out_reg is port_reg + outset_reg, + outclr_reg, + outtgl_reg; + +}; + +#endif // HWXPORT diff --git a/include/rwmem.h b/include/rwmem.h index d1c9479..a749331 100644 --- a/include/rwmem.h +++ b/include/rwmem.h @@ -216,6 +216,45 @@ class RAM : public RWMemoryMember { TraceValueCoreRegister *corereg; }; +//! One byte, in avr eeprom/flash Ram +/*! Allows clean read and write accesses with external pointer. */ +class MemPtr: public RWMemoryMember { + + public: + MemPtr(TraceValueCoreRegister *registry, + const std::string &tracename, + unsigned char *ptrval, + const size_t number, + const size_t maxsize); + + protected: + unsigned char get() const; + void set(unsigned char); + + private: + unsigned char *pValue; + TraceValueCoreRegister *corereg; +}; + +//! Constant memory +class CstMem: public RWMemoryMember { + public: + CstMem(TraceValueCoreRegister *registry, + const std::string &tracename, + unsigned char v, + const size_t number, + const size_t maxsize); + + protected: + unsigned char get() const; + void set(unsigned char); + + private: + unsigned char value; + TraceValueCoreRegister *corereg; +}; + + //! Memory on which access should be avoided! :-) /*! All accesses to this type of memory will produce an error. */ class InvalidMem : public RWMemoryMember { @@ -297,16 +336,16 @@ class IOReg: public RWMemoryMember { IOReg(TraceValueRegister *registry, const std::string &tracename, P *_p, - getter_t _g=0, - setter_t _s=0, - getter_bit_t _gb=0, - setter_bit_t _sb=0): + getter_t _g = nullptr, + setter_t _s = nullptr, + getter_bit_t _gb = nullptr, + setter_bit_t _sb = nullptr): RWMemoryMember(registry, tracename), p(_p), - g(_g), - s(_s), - gb(_gb), - sb(_sb) + getValueFuncPtr(_g), + setValueFuncPtr(_s), + getValueFuncPtrBitwise(_gb), + setValueFuncPtrBitwise(_sb) { // 'undefined state' doesn't really make sense for IO registers if (tv) @@ -326,14 +365,14 @@ class IOReg: public RWMemoryMember { /*! bitwise access to IOReg from SBI */ - virtual void set_bit( unsigned int bitaddr ) { - if (sb) { - (p->*sb)( 1, bitaddr); + void set_bit( unsigned int bitaddr ) override { + if (setValueFuncPtrBitwise) { + (p->*setValueFuncPtrBitwise)( 1, bitaddr); } else { // default to byte access - if (g && s) { - unsigned char val = (p->*g)(); + if (getValueFuncPtr && setValueFuncPtr) { + unsigned char val = (p->*getValueFuncPtr)(); val|= 1<*s)(val); + (p->*setValueFuncPtr)(val); } else { avr_warning("Bitwise access of '%s' is not supported.", tv->name().c_str()); } @@ -342,14 +381,14 @@ class IOReg: public RWMemoryMember { /*! bitwise access to IOReg from CBI */ - virtual void clear_bit( unsigned int bitaddr ) { - if (sb) { - (p->*sb)( 0, bitaddr); + void clear_bit( unsigned int bitaddr ) override { + if (setValueFuncPtrBitwise) { + (p->*setValueFuncPtrBitwise)( 0, bitaddr); } else { // default to byte access - if (g && s) { - unsigned char val = (p->*g)(); + if (getValueFuncPtr && setValueFuncPtr) { + unsigned char val = (p->*getValueFuncPtr)(); val&= ~(1<*s)(val); + (p->*setValueFuncPtr)(val); } else { avr_warning("Bitwise access of '%s' is not supported.", tv->name().c_str()); } @@ -358,16 +397,16 @@ class IOReg: public RWMemoryMember { protected: unsigned char get() const { - if (g) - return (p->*g)(); + if (getValueFuncPtr) + return (p->*getValueFuncPtr)(); else if (tv) { avr_warning("Reading of '%s' is not supported.", tv->name().c_str()); } return 0; } void set(unsigned char val) { - if (s) - (p->*s)(val); + if (setValueFuncPtr) + (p->*setValueFuncPtr)(val); else if (tv) { avr_warning("Writing of '%s' (with %d) is not supported.", tv->name().c_str(), val); } @@ -375,10 +414,10 @@ class IOReg: public RWMemoryMember { private: P *p; - getter_t g; - setter_t s; - getter_bit_t gb; - setter_bit_t sb; + getter_t getValueFuncPtr; + setter_t setValueFuncPtr; + getter_bit_t getValueFuncPtrBitwise; + setter_bit_t setValueFuncPtrBitwise; }; class IOSpecialReg; diff --git a/include/simulationmember.h b/include/simulationmember.h index c3cb11a..0bafce6 100644 --- a/include/simulationmember.h +++ b/include/simulationmember.h @@ -36,6 +36,7 @@ class SimulationMember { virtual ~SimulationMember() { } /// Return nonzero if a breakpoint was hit. virtual int Step(bool &trueHwStep, SystemClockOffset *timeToNextStepIn_ns=0)=0; + virtual SystemClockOffset GetClockFreq() { return -1; } }; #endif diff --git a/libsim/atxmega128aubase.cpp b/libsim/atxmega128aubase.cpp new file mode 100644 index 0000000..1675adf --- /dev/null +++ b/libsim/atxmega128aubase.cpp @@ -0,0 +1,734 @@ + /* + **************************************************************************** + * + * simulavr - A simulator for the Atmel AVR family of microcontrollers. + * Copyright (C) 2021 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + **************************************************************************** + */ +#include "atxmega128aubase.h" + +#include "hardware.h" +#include "irqsystem.h" +#include "hwxport.h" +#include "hwstack.h" +#include "hwspi.h" +#include "hweeprom.h" +#include "hwwado.h" +#include "hwsreg.h" +#include "rwmem.h" + +#include "avrfactory.h" + +#include + +AVR_REGISTER(atxmega128a1, AvrDevice_atxmega128a1); +AVR_REGISTER(atxmega64a1, AvrDevice_atxmega64a1); +AVR_REGISTER(atxmega128a4u, AvrDevice_atxmega128a4u); +AVR_REGISTER(atxmega64a4u, AvrDevice_atxmega64a4u); +AVR_REGISTER(atxmega32a4u, AvrDevice_atxmega32a4u); +AVR_REGISTER(atxmega16a4u, AvrDevice_atxmega16a4u); + +#define IO_OFFSET 0x20 + +// A1U +AvrDevice_atxmega128a1::AvrDevice_atxmega128a1(): + AvrDevice_atxmega128aubase(128 * 1024, 2 * 1024, 8 * 1024, 0x10000) +{ } + +AvrDevice_atxmega64a1::AvrDevice_atxmega64a1(): + AvrDevice_atxmega128aubase(64 * 1024, 2 * 1024, 4 * 1024, 0x10000) +{ } + +// A4U +AvrDevice_atxmega128a4u::AvrDevice_atxmega128a4u(): + AvrDevice_atxmega128aubase(128 * 1024, 2 * 1024, 8 * 1024, 0x10000) +{ } + +AvrDevice_atxmega64a4u::AvrDevice_atxmega64a4u(): + AvrDevice_atxmega128aubase(64 * 1024, 2 * 1024, 4 * 1024, 0x8000) +{ } + +AvrDevice_atxmega32a4u::AvrDevice_atxmega32a4u(): + AvrDevice_atxmega128aubase(32 * 1024, 1 * 1024, 4 * 1024, 0x4000) +{ } + +AvrDevice_atxmega16a4u::AvrDevice_atxmega16a4u(): + AvrDevice_atxmega128aubase(16 * 1024, 1 * 1024, 2 * 1024, 0x2000) +{ } + +AvrDevice_atxmega128aubase::~AvrDevice_atxmega128aubase() { + + // for (unsigned int i = 0; i < sizeof(adca) / sizeof(adca[0]); i++) { + // delete adca[i]; + // } + // for (unsigned int i = 0; i < sizeof(adcb) / sizeof(adcb[0]); i++) { + // delete adcb[i]; + // } + // delete aref; + // delete admux; + delete rampz; + delete rampy; + delete rampx; + delete rampd; + delete nvm; + delete stack; + delete eeprom; + delete irqSystem; + delete spmRegister; + for (std::list::iterator it = ioMem.begin(); it != ioMem.end(); it++) { + delete *it; + } +} + +AvrDevice_atxmega128aubase::AvrDevice_atxmega128aubase(unsigned flash_bytes, + unsigned ee_bytes, + unsigned ram_bytes, + unsigned nrww_start): + // IO take address from 0x0020 to 0x0BC4+0x20 (Call with 0x20 as base). Registers take 32 bytes (0x20) + // Define Iosise to 0x1000 in order to have aligned memory with doc. + AvrDevice( + 0x1000, // IO max size (to have invalid ram in this place) + 0x1000, // internal ram (mapped on eeprom content) + ram_bytes, // extended ram + flash_bytes, + 3 // Pc size + ), + // AvrDevice (0x0BC4, 4096, ram_bytes, flash_bytes), + vport0(this, "Virt0"), + vport1(this, "Virt1"), + vport2(this, "Virt2"), + vport3(this, "Virt3"), + porta(this, "A"), + portb(this, "B"), + portc(this, "C"), + portd(this, "D"), + porte(this, "E"), + portf(this, "F"), + portg(this, "G"), + porth(this, "H"), + portj(this, "J"), + portk(this, "K"), + portl(this, "L"), + portm(this, "M"), + portn(this, "N"), + portp(this, "P"), + portq(this, "Q"), + portr(this, "R") +{ + // Fixme: To be checked + spmRegister = new FlashProgramming(this, 128, nrww_start, FlashProgramming::SPM_MEGA_MODE); + irqSystem = new HWIrqSystem(this, 2, 35); //2 bytes per vector, 35 vectors + eeprom = new HWEeprom(this, NULL, ee_bytes, 0, HWEeprom::DEVMODE_NORMAL); + stack = new HWStackSram(this, 16); + nvm = new HWNvm(this, ee_bytes); + AddToResetList(nvm); + // AddToCycleList(nvm); + + rampd = new AddressExtensionRegister(this, "RAMPD", 1); + rampx = new AddressExtensionRegister(this, "RAMPX", 1); + rampy = new AddressExtensionRegister(this, "RAMPY", 1); + rampz = new AddressExtensionRegister(this, "RAMPZ", 1); + eind = new AddressExtensionRegister(this, "EIND", 1); + + flagELPMInstructions = true; + flagEIJMPInstructions = true; + flagXMega = true; + + fuses->SetFuseConfiguration(48, 0xff00ff00ffd0UL); + // Fixme: wrong values + fuses->SetBootloaderConfig(nrww_start, 0x2000, 24, 23); + + // EEprom memory + // Will be deleted by avrDevice (parent) + for (unsigned addr = 0x0000; addr < ee_bytes; addr++) { + ReplaceMemRegister (IO_OFFSET + 0x1000 + addr, new MemPtr(&coreTraceGroup, "EEPROM_map", &eeprom->myMemory[addr], addr, ee_bytes)); + }; + for (unsigned addr = ee_bytes + 0x1000; addr < 0x2000; addr++) { + ReplaceMemRegister (IO_OFFSET + addr, new InvalidMem (this, addr)); + } + + // GPIO + changeIoToRam(0x0000, 0x000F); + /*rw[IO_OFFSET + 0x0000] = & gpio[0]; + rw[IO_OFFSET + 0x0001] = & gpio[1]; + rw[IO_OFFSET + 0x0002] = & gpio[2]; + rw[IO_OFFSET + 0x0003] = & gpio[3]; + rw[IO_OFFSET + 0x0004] = & gpio[4]; + rw[IO_OFFSET + 0x0005] = & gpio[5]; + rw[IO_OFFSET + 0x0006] = & gpio[6]; + rw[IO_OFFSET + 0x0007] = & gpio[7]; + rw[IO_OFFSET + 0x0008] = & gpio[8]; + rw[IO_OFFSET + 0x0009] = & gpio[9]; + rw[IO_OFFSET + 0x000A] = & gpio[10]; + rw[IO_OFFSET + 0x000B] = & gpio[11]; + rw[IO_OFFSET + 0x000C] = & gpio[12]; + rw[IO_OFFSET + 0x000D] = & gpio[13]; + rw[IO_OFFSET + 0x000E] = & gpio[14]; + rw[IO_OFFSET + 0x000F] = & gpio[15]; */ + + // Virtual port + rw[IO_OFFSET + 0x0010] = & vport0.ddr_reg; + rw[IO_OFFSET + 0x0011] = & vport0.port_reg; + rw[IO_OFFSET + 0x0012] = & vport0.pin_reg; + + rw[IO_OFFSET + 0x0014] = & vport1.ddr_reg; + rw[IO_OFFSET + 0x0015] = & vport1.port_reg; + rw[IO_OFFSET + 0x0016] = & vport1.pin_reg; + + rw[IO_OFFSET + 0x0018] = & vport2.ddr_reg; + rw[IO_OFFSET + 0x0019] = & vport2.port_reg; + rw[IO_OFFSET + 0x001A] = & vport2.pin_reg; + + rw[IO_OFFSET + 0x001C] = & vport3.ddr_reg; + rw[IO_OFFSET + 0x001D] = & vport3.port_reg; + rw[IO_OFFSET + 0x001E] = & vport3.ddr_reg; + + // CPU + rw[IO_OFFSET + 0x0034] = & nvm->ccp_reg; + // rw[IO_OFFSET + 0x0034] = ccp; + rw[IO_OFFSET + 0x0038] = & rampd->ext_reg; + rw[IO_OFFSET + 0x0039] = & rampx->ext_reg; + rw[IO_OFFSET + 0x003A] = & rampy->ext_reg; + rw[IO_OFFSET + 0x003B] = & rampz->ext_reg; + rw[IO_OFFSET + 0x003C] = & eind->ext_reg; + rw[IO_OFFSET + 0x003D] = & ((HWStackSram *)stack)->spl_reg; + rw[IO_OFFSET + 0x003E] = & ((HWStackSram *)stack)->sph_reg; + rw[IO_OFFSET + 0x003F] = statusRegister; + + // Clock control + changeIoToRam(0x0040, 0x0044); + + // Sleep control + changeIoToRam(0x0048, 0x0048); + + // Oscillator control + changeIoToRam(0x0050, 0x0050); + rw[IO_OFFSET + 0x0051] = new CstMem (&coreTraceGroup, "OSC.STATUS", 0x01F , 0, 1); + changeIoToRam(0x0052, 0x0056); + + // DFLL for the 32 MHz internal oscillator + changeIoToRam(0x0060, 0x0066); + + // DFLL for the 2 MHz RC oscillator + changeIoToRam(0x0068, 0x006e); + + // Power reduction + changeIoToRam(0x0070, 0x0076); + + // Reset controller + changeIoToRam(0x0078, 0x007a); + + // Watch-dog timer + rw[IO_OFFSET + 0x0080] = & wado->wdtcr_reg; // incomplete + changeIoToRam(0x0081, 0x0083); + + // MCU control + changeIoToRam(0x0090, 0x0099); + + // Programmable multilevel interrupt controller + changeIoToRam(0x00A0, 0x00A2); + + // Port configuration + changeIoToRam(0x00B0, 0x00B0); + changeIoToRam(0x00B2, 0x00B6); + + // AES module + changeIoToRam(0x00C0, 0x00C4); + + // CRC module + changeIoToRam(0x00D0, 0x00D1); + changeIoToRam(0x00D3, 0x00D7); + + // Battery backup system + changeIoToRam(0x00F0, 0x00F4); + + // DMA controller + changeIoToRam(0x0100, 0x0100); + changeIoToRam(0x0103, 0x0104); + changeIoToRam(0x0106, 0x0107); + changeIoToRam(0x0110, 0x0116); + changeIoToRam(0x0118, 0x011A); + changeIoToRam(0x011C, 0x011E); + changeIoToRam(0x0120, 0x0126); + changeIoToRam(0x0128, 0x012A); + changeIoToRam(0x012C, 0x012E); + changeIoToRam(0x0130, 0x0136); + changeIoToRam(0x0138, 0x013A); + changeIoToRam(0x013C, 0x013E); + changeIoToRam(0x0140, 0x0146); + changeIoToRam(0x0148, 0x014A); + changeIoToRam(0x011C, 0x014E); + + // Event system + changeIoToRam(0x0180, 0x0191); + + // Non volatile memory controller + rw[IO_OFFSET + 0x01C0] = & nvm->addr0_reg; // low + rw[IO_OFFSET + 0x01C1] = & nvm->addr1_reg; // high + rw[IO_OFFSET + 0x01C2] = & nvm->addr2_reg; // extended + rw[IO_OFFSET + 0x01C4] = & nvm->data0_reg; // low + rw[IO_OFFSET + 0x01C5] = & nvm->data1_reg; // high + rw[IO_OFFSET + 0x01C6] = & nvm->data2_reg; // extended + rw[IO_OFFSET + 0x01CA] = & nvm->cmd_reg; + rw[IO_OFFSET + 0x01CB] = & nvm->ctrla_reg; + rw[IO_OFFSET + 0x01CC] = & nvm->ctrlb_reg; + rw[IO_OFFSET + 0x01CD] = & nvm->intctrl_reg; + rw[IO_OFFSET + 0x01CE] = & nvm->lockbits_reg; + rw[IO_OFFSET + 0x01CF] = & nvm->status_reg; + rw[IO_OFFSET + 0x01D0] = & nvm->lockbits_reg; + + // Analog to digital converter on port A + changeIoToRam(0x0200, 0x0206); + + // Analog to digital converter on port B + changeIoToRam(0x0240, 0x0246); + + // Digital to analog converter on port A + changeIoToRam(0x0300, 0x0304); + changeIoToRam(0x0305, 0x0305); + changeIoToRam(0x0308, 0x030B); + changeIoToRam(0x0318, 0x031B); + + // Digital to analog converter on port B + changeIoToRam(0x0320, 0x0324); + changeIoToRam(0x0325, 0x0325); + changeIoToRam(0x0328, 0x032B); + changeIoToRam(0x0338, 0x033B); + + // Analog comparator pair on port A + changeIoToRam(0x0380, 0x0389); + + // Analog comparator pair on port B + changeIoToRam(0x0390, 0x0399); + + // Real time counter + changeIoToRam(0x0400, 0x0404); + changeIoToRam(0x0408, 0x040D); + + // 32-bit Real time counter + changeIoToRam(0x0420, 0x042F); + + // External bus interface + changeIoToRam(0x0440, 0x0441); + changeIoToRam(0x0444, 0x0449); + changeIoToRam(0x0450, 0x045C); + + // Two wire interface on port C + changeIoToRam(0x0480, 0x048D); + + // Two wire interface on port D + changeIoToRam(0x0490, 0x049D); + + // Two wire interface on port E + changeIoToRam(0x04A0, 0x04AD); + + // Two wire interface on port F + changeIoToRam(0x04B0, 0x04BD); + + // USB device + changeIoToRam(0x04C0, 0x04CD); + changeIoToRam(0x04FA, 0x04FB); + + // Port A + rw[IO_OFFSET + 0x0600] = & porta.ddr_reg; + rw[IO_OFFSET + 0x0601] = & porta.dirset_reg; + rw[IO_OFFSET + 0x0602] = & porta.dirclr_reg; + rw[IO_OFFSET + 0x0603] = & porta.dirtgl_reg; + rw[IO_OFFSET + 0x0604] = & porta.port_reg; + rw[IO_OFFSET + 0x0605] = & porta.outset_reg; + rw[IO_OFFSET + 0x0606] = & porta.outclr_reg; + rw[IO_OFFSET + 0x0607] = & porta.outtgl_reg; + rw[IO_OFFSET + 0x0608] = & porta.pin_reg; + changeIoToRam (0x0609, 0x060C); + changeIoToRam (0x060E, 0x060E); + changeIoToRam (0x0610, 0x0617); + + // Port B + rw[IO_OFFSET + 0x0620] = & portb.ddr_reg; + rw[IO_OFFSET + 0x0621] = & portb.dirset_reg; + rw[IO_OFFSET + 0x0622] = & portb.dirclr_reg; + rw[IO_OFFSET + 0x0623] = & portb.dirtgl_reg; + rw[IO_OFFSET + 0x0624] = & portb.port_reg; + rw[IO_OFFSET + 0x0625] = & portb.outset_reg; + rw[IO_OFFSET + 0x0626] = & portb.outclr_reg; + rw[IO_OFFSET + 0x0627] = & portb.outtgl_reg; + rw[IO_OFFSET + 0x0628] = & portb.pin_reg; + changeIoToRam (0x0629, 0x062C); + changeIoToRam (0x062E, 0x062E); + changeIoToRam (0x0630, 0x0637); + + // Port C + rw[IO_OFFSET + 0x0640] = & portc.ddr_reg; + rw[IO_OFFSET + 0x0641] = & portc.dirset_reg; + rw[IO_OFFSET + 0x0642] = & portc.dirclr_reg; + rw[IO_OFFSET + 0x0643] = & portc.dirtgl_reg; + rw[IO_OFFSET + 0x0644] = & portc.port_reg; + rw[IO_OFFSET + 0x0645] = & portc.outset_reg; + rw[IO_OFFSET + 0x0646] = & portc.outclr_reg; + rw[IO_OFFSET + 0x0647] = & portc.outtgl_reg; + rw[IO_OFFSET + 0x0648] = & portc.pin_reg; + changeIoToRam (0x0649, 0x064C); + changeIoToRam (0x064E, 0x064E); + changeIoToRam (0x0650, 0x0657); + + // Port D + rw[IO_OFFSET + 0x0660] = & portd.ddr_reg; + rw[IO_OFFSET + 0x0661] = & portd.dirset_reg; + rw[IO_OFFSET + 0x0662] = & portd.dirclr_reg; + rw[IO_OFFSET + 0x0663] = & portd.dirtgl_reg; + rw[IO_OFFSET + 0x0664] = & portd.port_reg; + rw[IO_OFFSET + 0x0665] = & portd.outset_reg; + rw[IO_OFFSET + 0x0666] = & portd.outclr_reg; + rw[IO_OFFSET + 0x0667] = & portd.outtgl_reg; + rw[IO_OFFSET + 0x0668] = & portd.pin_reg; + changeIoToRam (0x0669, 0x066C); + changeIoToRam (0x066E, 0x066E); + changeIoToRam (0x0670, 0x0677); + + // Port E + rw[IO_OFFSET + 0x0680] = & porte.ddr_reg; + rw[IO_OFFSET + 0x0681] = & porte.dirset_reg; + rw[IO_OFFSET + 0x0682] = & porte.dirclr_reg; + rw[IO_OFFSET + 0x0683] = & porte.dirtgl_reg; + rw[IO_OFFSET + 0x0684] = & porte.port_reg; + rw[IO_OFFSET + 0x0685] = & porte.outset_reg; + rw[IO_OFFSET + 0x0686] = & porte.outclr_reg; + rw[IO_OFFSET + 0x0687] = & porte.outtgl_reg; + rw[IO_OFFSET + 0x0688] = & porte.pin_reg; + changeIoToRam (0x0689, 0x068C); + changeIoToRam (0x068E, 0x068E); + changeIoToRam (0x0690, 0x0697); + + // Port F + rw[IO_OFFSET + 0x06A0] = & portf.ddr_reg; + rw[IO_OFFSET + 0x06A1] = & portf.dirset_reg; + rw[IO_OFFSET + 0x06A2] = & portf.dirclr_reg; + rw[IO_OFFSET + 0x06A3] = & portf.dirtgl_reg; + rw[IO_OFFSET + 0x06A4] = & portf.port_reg; + rw[IO_OFFSET + 0x06A5] = & portf.outset_reg; + rw[IO_OFFSET + 0x06A6] = & portf.outclr_reg; + rw[IO_OFFSET + 0x06A7] = & portf.outtgl_reg; + rw[IO_OFFSET + 0x06A8] = & portf.pin_reg; + changeIoToRam (0x06A9, 0x06AC); + changeIoToRam (0x06AE, 0x06AE); + changeIoToRam (0x06B0, 0x06B7); + + // not in doc + // Port G + rw[IO_OFFSET + 0x06C0] = & portg.ddr_reg; + rw[IO_OFFSET + 0x06C1] = & portg.dirset_reg; + rw[IO_OFFSET + 0x06C2] = & portg.dirclr_reg; + rw[IO_OFFSET + 0x06C3] = & portg.dirtgl_reg; + rw[IO_OFFSET + 0x06C4] = & portg.port_reg; + rw[IO_OFFSET + 0x06C5] = & portg.outset_reg; + rw[IO_OFFSET + 0x06C6] = & portg.outclr_reg; + rw[IO_OFFSET + 0x06C7] = & portg.outtgl_reg; + rw[IO_OFFSET + 0x06C8] = & portg.pin_reg; + changeIoToRam (0x06C9, 0x06CC); + changeIoToRam (0x06CE, 0x06CE); + changeIoToRam (0x06D0, 0x06D7); + + // Port H + rw[IO_OFFSET + 0x06E0] = & porth.ddr_reg; + rw[IO_OFFSET + 0x06E1] = & porth.dirset_reg; + rw[IO_OFFSET + 0x06E2] = & porth.dirclr_reg; + rw[IO_OFFSET + 0x06E3] = & porth.dirtgl_reg; + rw[IO_OFFSET + 0x06E4] = & porth.port_reg; + rw[IO_OFFSET + 0x06E5] = & porth.outset_reg; + rw[IO_OFFSET + 0x06E6] = & porth.outclr_reg; + rw[IO_OFFSET + 0x06E7] = & porth.outtgl_reg; + rw[IO_OFFSET + 0x06E8] = & porth.pin_reg; + changeIoToRam (0x06E9, 0x06EC); + changeIoToRam (0x06EE, 0x06EE); + changeIoToRam (0x06F0, 0x06F7); + + // Port J + rw[IO_OFFSET + 0x0700] = & portj.ddr_reg; + rw[IO_OFFSET + 0x0701] = & portj.dirset_reg; + rw[IO_OFFSET + 0x0702] = & portj.dirclr_reg; + rw[IO_OFFSET + 0x0703] = & portj.dirtgl_reg; + rw[IO_OFFSET + 0x0704] = & portj.port_reg; + rw[IO_OFFSET + 0x0705] = & portj.outset_reg; + rw[IO_OFFSET + 0x0706] = & portj.outclr_reg; + rw[IO_OFFSET + 0x0707] = & portj.outtgl_reg; + rw[IO_OFFSET + 0x0708] = & portj.pin_reg; + changeIoToRam (0x0709, 0x070D); + changeIoToRam (0x070E, 0x070F); + changeIoToRam (0x0710, 0x0717); + + // Port K + rw[IO_OFFSET + 0x0720] = & portk.ddr_reg; + rw[IO_OFFSET + 0x0721] = & portk.dirset_reg; + rw[IO_OFFSET + 0x0722] = & portk.dirclr_reg; + rw[IO_OFFSET + 0x0723] = & portk.dirtgl_reg; + rw[IO_OFFSET + 0x0724] = & portk.port_reg; + rw[IO_OFFSET + 0x0725] = & portk.outset_reg; + rw[IO_OFFSET + 0x0726] = & portk.outclr_reg; + rw[IO_OFFSET + 0x0727] = & portk.outtgl_reg; + rw[IO_OFFSET + 0x0728] = & portk.pin_reg; + changeIoToRam (0x0729, 0x072D); + changeIoToRam (0x072E, 0x072F); + changeIoToRam (0x0730, 0x0737); + + // Port L + // not in doc + rw[IO_OFFSET + 0x0740] = & portl.ddr_reg; + rw[IO_OFFSET + 0x0741] = & portl.dirset_reg; + rw[IO_OFFSET + 0x0742] = & portl.dirclr_reg; + rw[IO_OFFSET + 0x0743] = & portl.dirtgl_reg; + rw[IO_OFFSET + 0x0744] = & portl.port_reg; + rw[IO_OFFSET + 0x0745] = & portl.outset_reg; + rw[IO_OFFSET + 0x0746] = & portl.outclr_reg; + rw[IO_OFFSET + 0x0747] = & portl.outtgl_reg; + rw[IO_OFFSET + 0x0748] = & portl.pin_reg; + changeIoToRam (0x0749, 0x074D); + changeIoToRam (0x074E, 0x074F); + changeIoToRam (0x0750, 0x0757); + + // Port M + // not in doc + rw[IO_OFFSET + 0x0760] = & portm.ddr_reg; + rw[IO_OFFSET + 0x0761] = & portm.dirset_reg; + rw[IO_OFFSET + 0x0762] = & portm.dirclr_reg; + rw[IO_OFFSET + 0x0763] = & portm.dirtgl_reg; + rw[IO_OFFSET + 0x0764] = & portm.port_reg; + rw[IO_OFFSET + 0x0765] = & portm.outset_reg; + rw[IO_OFFSET + 0x0766] = & portm.outclr_reg; + rw[IO_OFFSET + 0x0767] = & portm.outtgl_reg; + rw[IO_OFFSET + 0x0768] = & portm.pin_reg; + changeIoToRam (0x0769, 0x076D); + changeIoToRam (0x076E, 0x076F); + changeIoToRam (0x0770, 0x0777); + + // Port N + // not in doc + rw[IO_OFFSET + 0x0780] = & portn.ddr_reg; + rw[IO_OFFSET + 0x0781] = & portn.dirset_reg; + rw[IO_OFFSET + 0x0782] = & portn.dirclr_reg; + rw[IO_OFFSET + 0x0783] = & portn.dirtgl_reg; + rw[IO_OFFSET + 0x0784] = & portn.port_reg; + rw[IO_OFFSET + 0x0785] = & portn.outset_reg; + rw[IO_OFFSET + 0x0786] = & portn.outclr_reg; + rw[IO_OFFSET + 0x0787] = & portn.outtgl_reg; + rw[IO_OFFSET + 0x0788] = & portn.pin_reg; + changeIoToRam (0x0789, 0x078D); + changeIoToRam (0x078E, 0x078F); + changeIoToRam (0x0790, 0x0797); + + // Port P + // not in doc + rw[IO_OFFSET + 0x07A0] = & portp.ddr_reg; + rw[IO_OFFSET + 0x07A1] = & portp.dirset_reg; + rw[IO_OFFSET + 0x07A2] = & portp.dirclr_reg; + rw[IO_OFFSET + 0x07A3] = & portp.dirtgl_reg; + rw[IO_OFFSET + 0x07A4] = & portp.port_reg; + rw[IO_OFFSET + 0x07A5] = & portp.outset_reg; + rw[IO_OFFSET + 0x07A6] = & portp.outclr_reg; + rw[IO_OFFSET + 0x07A7] = & portp.outtgl_reg; + rw[IO_OFFSET + 0x07A8] = & portp.pin_reg; + changeIoToRam (0x07A9, 0x07AD); + changeIoToRam (0x07AE, 0x07AF); + changeIoToRam (0x07B0, 0x07B7); + + // Port Q + rw[IO_OFFSET + 0x07C0] = & portq.ddr_reg; + rw[IO_OFFSET + 0x07C1] = & portq.dirset_reg; + rw[IO_OFFSET + 0x07C2] = & portq.dirclr_reg; + rw[IO_OFFSET + 0x07C3] = & portq.dirtgl_reg; + rw[IO_OFFSET + 0x07C4] = & portq.port_reg; + rw[IO_OFFSET + 0x07C5] = & portq.outset_reg; + rw[IO_OFFSET + 0x07C6] = & portq.outclr_reg; + rw[IO_OFFSET + 0x07C7] = & portq.outtgl_reg; + rw[IO_OFFSET + 0x07C8] = & portq.pin_reg; + changeIoToRam (0x07C9, 0x07CD); + changeIoToRam (0x07CE, 0x07CF); + changeIoToRam (0x07D0, 0x07D7); + + // Port R + rw[IO_OFFSET + 0x07E0] = & portr.ddr_reg; + rw[IO_OFFSET + 0x07E1] = & portr.dirset_reg; + rw[IO_OFFSET + 0x07E2] = & portr.dirclr_reg; + rw[IO_OFFSET + 0x07E3] = & portr.dirtgl_reg; + rw[IO_OFFSET + 0x07E4] = & portr.port_reg; + rw[IO_OFFSET + 0x07E5] = & portr.outset_reg; + rw[IO_OFFSET + 0x07E6] = & portr.outclr_reg; + rw[IO_OFFSET + 0x07E7] = & portr.outtgl_reg; + rw[IO_OFFSET + 0x07E8] = & portr.pin_reg; + changeIoToRam (0x07E9, 0x07ED); + changeIoToRam (0x07EE, 0x07EF); + changeIoToRam (0x07F0, 0x07F7); + + // Timer/counter 0 on port C + changeIoToRam(0x0800, 0x0804); + changeIoToRam(0x0806, 0x080C); + changeIoToRam(0x080F, 0x080F); + changeIoToRam(0x0820, 0x0821); + changeIoToRam(0x0826, 0x082F); + changeIoToRam(0x0836, 0x083F); + + // Timer/counter 1 on port C + changeIoToRam(0x0840, 0x0844); + changeIoToRam(0x0846, 0x084C); + changeIoToRam(0x084F, 0x084F); + changeIoToRam(0x0860, 0x0861); + changeIoToRam(0x0866, 0x086F); + changeIoToRam(0x0876, 0x087F); + + // Advanced waveform extension on port C + changeIoToRam(0x0880, 0x0880); + changeIoToRam(0x0882, 0x0884); + changeIoToRam(0x0886, 0x088C); + + // High resolution extension on port C + changeIoToRam(0x0890, 0x0890); + + // USART 0 on port C + changeIoToRam(0x08A0, 0x08A1); + changeIoToRam(0x08A3, 0x08A7); + + // USART 1 on port C + changeIoToRam(0x08B0, 0x08B1); + changeIoToRam(0x08B3, 0x08B7); + + // Serial peripheral interface on port C + changeIoToRam(0x08C0, 0x08C3); + + // Infrared communication module + changeIoToRam(0x08F8, 0x08FA); + + // Timer/counter 1 on port D + changeIoToRam(0x0900, 0x0904); + changeIoToRam(0x0906, 0x090C); + changeIoToRam(0x090F, 0x090F); + changeIoToRam(0x0920, 0x0921); + changeIoToRam(0x0926, 0x092F); + changeIoToRam(0x0936, 0x093F); + + // Timer/counter 1 on port D + changeIoToRam(0x0900, 0x0904); + changeIoToRam(0x0906, 0x090C); + changeIoToRam(0x090F, 0x090F); + changeIoToRam(0x0920, 0x0921); + changeIoToRam(0x0926, 0x092F); + changeIoToRam(0x0936, 0x093F); + + // Advanced waveform extension on port D + changeIoToRam(0x0980, 0x0980); + changeIoToRam(0x0982, 0x0984); + changeIoToRam(0x0986, 0x098C); + + // High resolution extension on port D + changeIoToRam(0x0990, 0x0990); + + // USART 0 on port D + changeIoToRam(0x09A0, 0x09A1); + changeIoToRam(0x09A3, 0x09A7); + + // USART 1 on port D + changeIoToRam(0x09B0, 0x09B1); + changeIoToRam(0x09B3, 0x09B7); + + // Serial peripheral interface on port D + changeIoToRam(0x09C0, 0x09C3); + + // Timer/counter 1 on port E + changeIoToRam(0x0A00, 0x0A04); + changeIoToRam(0x0A06, 0x0A0C); + changeIoToRam(0x0A0F, 0x0A0F); + changeIoToRam(0x0A20, 0x0A21); + changeIoToRam(0x0A26, 0x0A2F); + changeIoToRam(0x0A36, 0x0A3F); + + // Timer/counter 1 on port E + changeIoToRam(0x0A00, 0x0A04); + changeIoToRam(0x0A06, 0x0A0C); + changeIoToRam(0x0A0F, 0x0A0F); + changeIoToRam(0x0A20, 0x0A21); + changeIoToRam(0x0A26, 0x0A2F); + changeIoToRam(0x0A36, 0x0A3F); + + // Advanced waveform extension on port E + changeIoToRam(0x0A80, 0x0A80); + changeIoToRam(0x0A82, 0x0A84); + changeIoToRam(0x0A86, 0x0A8C); + + // High resolution extension on port E + changeIoToRam(0x0A90, 0x0A90); + + // USART 0 on port E + changeIoToRam(0x0AA0, 0x0AA1); + changeIoToRam(0x0AA3, 0x0AA7); + + // USART 1 on port E + changeIoToRam(0x0AB0, 0x0AB1); + changeIoToRam(0x0AB3, 0x0AB7); + + // Serial peripheral interface on port E + changeIoToRam(0x0AC0, 0x0AC3); + + // Timer/counter 1 on port F + changeIoToRam(0x0B00, 0x0B04); + changeIoToRam(0x0B06, 0x0B0C); + changeIoToRam(0x0B0F, 0x0B0F); + changeIoToRam(0x0B20, 0x0B21); + changeIoToRam(0x0B26, 0x0B2F); + changeIoToRam(0x0B36, 0x0B3F); + + // Timer/counter 1 on port F + changeIoToRam(0x0B00, 0x0B04); + changeIoToRam(0x0B06, 0x0B0C); + changeIoToRam(0x0B0F, 0x0B0F); + changeIoToRam(0x0B20, 0x0B21); + changeIoToRam(0x0B26, 0x0B2F); + changeIoToRam(0x0B36, 0x0B3F); + + // Advanced waveform extension on port F + changeIoToRam(0x0B80, 0x0B80); + changeIoToRam(0x0B82, 0x0B84); + changeIoToRam(0x0B86, 0x0B8C); + + // High resolution extension on port F + changeIoToRam(0x0B90, 0x0B90); + + // USART 0 on port F + changeIoToRam(0x0BA0, 0x0BA1); + changeIoToRam(0x0BA3, 0x0BA7); + + // USART 1 on port F + changeIoToRam(0x0BB0, 0x0BB1); + changeIoToRam(0x0BB3, 0x0BB7); + + // Serial peripheral interface on port F + changeIoToRam(0x0BC0, 0x0BC3); + + Reset(); +} + +// Will properly switch the Io to Ram register +void AvrDevice_atxmega128aubase::changeIoToRam(unsigned int s_add, unsigned int e_add) +{ + RAM *ptr; + unsigned nb = ioMem.size(); + for (; s_add <= e_add; s_add++) + { + ptr = new RAM(&coreTraceGroup, "IO_RAM", nb, nb + 1); + nb++; + rw[IO_OFFSET + s_add] = ptr; + ioMem.push_front (ptr); + } +} diff --git a/libsim/avrdevice.cpp b/libsim/avrdevice.cpp index c0233fa..6225aad 100644 --- a/libsim/avrdevice.cpp +++ b/libsim/avrdevice.cpp @@ -137,6 +137,9 @@ AvrDevice::AvrDevice(unsigned int _ioSpaceSize, eRamSize(ERamSize), devSignature(std::numeric_limits::max()), PC_size(pcSize), + rampd(nullptr), + rampx(nullptr), + rampy(nullptr), rampz(nullptr), eind(nullptr), abortOnInvalidAccess(false), @@ -383,7 +386,8 @@ int AvrDevice::Step(bool &untilCoreStepFinished, SystemClockOffset *nextStepIn_n } untilCoreStepFinished = !((cpuCycles > 0) || hwWait); - dumpManager->cycle(); + if(trace_on == 1) + dumpManager->cycle(); return (cpuCycles < 0) ? cpuCycles : 0; } @@ -410,9 +414,20 @@ void AvrDevice::SetDeviceNameAndSignature(const std::string &name, unsigned int } void AvrDevice::ReplaceIoRegister(unsigned int offset, RWMemoryMember *newMember) { + // Compiling the following code '(*((volatile char *)0x20)) = 0xAA;' + // with atmega128 give 'ldi r24, 0xAA; out 0x00, r24;' + // with atxmega128a1 give 'ldi r24, 0xAA; out 0x20, r24;' + // We conclude that 'out' work differently according to the chip + if (flagXMega) { + if (offset >= ioSpaceSize) // callers do use 0x00 base, not 0x20 + avr_error("Could not replace register in non existing IoRegisterSpace"); + rw[offset + registerSpaceSize] = newMember; + } + else { if (offset >= ioSpaceSize + registerSpaceSize) avr_error("Could not replace register in non existing IoRegisterSpace"); rw[offset] = newMember; + } } bool AvrDevice::ReplaceMemRegister(unsigned int offset, RWMemoryMember *newMember) { @@ -444,16 +459,31 @@ void AvrDevice::DebugOnJump() } unsigned char AvrDevice::GetRWMem(unsigned addr) { + if (flagXMega) { + if(addr + registerSpaceSize >= GetMemTotalSize()) + return 0; + return *(rw[addr + registerSpaceSize]); + } + else { if(addr >= GetMemTotalSize()) return 0; return *(rw[addr]); + } } bool AvrDevice::SetRWMem(unsigned addr, unsigned char val) { + if (flagXMega) { + if(addr + registerSpaceSize >= GetMemTotalSize()) + return false; + *(rw[addr + registerSpaceSize]) = val; + return true; + } + else { if(addr >= GetMemTotalSize()) return false; *(rw[addr]) = val; return true; + } } unsigned char AvrDevice::GetCoreReg(unsigned addr) { diff --git a/libsim/avrreadelf.cpp b/libsim/avrreadelf.cpp index 393b815..3dac513 100644 --- a/libsim/avrreadelf.cpp +++ b/libsim/avrreadelf.cpp @@ -105,7 +105,7 @@ void ELFLoad(const AvrDevice * core) { } else if(value >= 0x840000 && value < 0x840400) { /* signature space starting from 0x840000, do nothing */; } else - avr_warning("Unknown symbol address range found! (symbol='%s', address=0x%lx)", + avr_warning("Unknown symbol address range found! (symbol='%s', address=0x%llx)", name.c_str(), value); @@ -148,7 +148,7 @@ void ELFLoad(const AvrDevice * core) { } else if(vma >= 0x840000 && vma < 0x840400) { // read and check signature, if available, space from 0x840000 to 0x840400 if(filesize != 3) - avr_error("wrong device signature size in elf file, expected=3, given=%lu", + avr_error("wrong device signature size in elf file, expected=3, given=%llu", filesize); else { unsigned int sig = (((data[2] << 8) + data[1]) << 8) + data[0]; @@ -190,7 +190,7 @@ unsigned int ELFGetSignature(const char *filename) { if(vma >= 0x840000 && vma < 0x840400) { // read and check signature, if available, space from 0x840000 to 0x840400 if(filesize != 3) - avr_error("wrong device signature size in elf file, expected=3, given=%lu", + avr_error("wrong device signature size in elf file, expected=3, given=%llu", filesize); else { const unsigned char* data = (const unsigned char*)pseg->get_data(); diff --git a/libsim/avrsignature.cpp b/libsim/avrsignature.cpp index ce4c192..a32342b 100644 --- a/libsim/avrsignature.cpp +++ b/libsim/avrsignature.cpp @@ -142,6 +142,10 @@ std::map AvrSignatureToNameMap = InitMap(0x1e9108, "attiny25") << std::make_pair(0x1e910b, "attiny24") << std::make_pair(0x1e920a, "atmega48p") + << std::make_pair(0x1e9746, "atxmega128a4u") + << std::make_pair(0x1e9646, "atxmega64a4u") + << std::make_pair(0x1e9541, "atxmega32a4u") + << std::make_pair(0x1e9441, "atxmega16a4u") // MARK end ; @@ -252,6 +256,10 @@ std::map AvrNameToSignatureMap = InitMap("attiny25", 0x1e9108) << std::make_pair("attiny24", 0x1e910b) << std::make_pair("atmega48p", 0x1e920a) + << std::make_pair("atxmega128a4u", 0x1e9746) + << std::make_pair("atxmega64a4u", 0x1e9646) + << std::make_pair("atxmega32a4u", 0x1e9541) + << std::make_pair("atxmega16a4u", 0x1e9441) // MARK end ; diff --git a/libsim/decoder.cpp b/libsim/decoder.cpp index 3ea13a6..8000cf4 100644 --- a/libsim/decoder.cpp +++ b/libsim/decoder.cpp @@ -773,7 +773,9 @@ avr_op_LDD_Y::avr_op_LDD_Y(word opcode, AvrDevice *c): int avr_op_LDD_Y::operator()() { /* Y is R29:R28 */ - word Y = core->GetRegY(); + unsigned Y = core->GetRegY(); + if (core->rampy && core->flagXMega) + Y = (core->rampy->GetRegVal() << 16) | Y; core->SetCoreReg(Rd, core->GetRWMem(Y + K)); @@ -787,7 +789,9 @@ avr_op_LDD_Z::avr_op_LDD_Z(word opcode, AvrDevice *c): int avr_op_LDD_Z::operator()() { /* Z is R31:R30 */ - word Z = core->GetRegZ(); + unsigned Z = core->GetRegZ(); + if (core->rampz && core->flagXMega) + Z = (core->rampz->GetRegVal() << 16) | Z; core->SetCoreReg(Rd, core->GetRWMem(Z + K)); @@ -814,8 +818,11 @@ avr_op_LDS::avr_op_LDS(word opcode, AvrDevice *c): int avr_op_LDS::operator()() { /* Get data at k in current data segment and put into Rd */ - word offset = core->Flash->ReadMemWord((core->PC + 1) * 2); - + unsigned offset = core->Flash->ReadMemWord((core->PC + 1) * 2); + if (core->rampd && core->flagXMega) { + offset = (core->rampd->GetRegVal() << 16) | offset; + } + core->SetCoreReg(R1, core->GetRWMem(offset)); core->PC++; @@ -828,7 +835,10 @@ avr_op_LD_X::avr_op_LD_X(word opcode, AvrDevice *c): int avr_op_LD_X::operator()() { /* X is R27:R26 */ - word X = core->GetRegX(); + unsigned X = core->GetRegX(); + + if (core->rampx && core->flagXMega) + X = (core->rampx->GetRegVal() << 16) | X; core->SetCoreReg(Rd, core->GetRWMem(X)); @@ -841,16 +851,22 @@ avr_op_LD_X_decr::avr_op_LD_X_decr(word opcode, AvrDevice *c): int avr_op_LD_X_decr::operator()() { /* X is R27:R26 */ - word X = core->GetRegX(); + unsigned X = core->GetRegX(); if (Rd == 26 || Rd == 27) avr_error( "Result of operation is undefined" ); + if (core->rampx && core->flagXMega) + X = (core->rampx->GetRegVal() << 16) | X; + /* Perform pre-decrement */ X--; core->SetCoreReg(Rd, core->GetRWMem(X)); core->SetCoreReg(26, X & 0xff); core->SetCoreReg(27, (X >> 8) & 0xff); + if (core->rampx) + core->rampx->SetRegVal((X >> 16) & 0xff); + return core->flagTiny10 ? 3 : 2; } @@ -860,16 +876,22 @@ avr_op_LD_X_incr::avr_op_LD_X_incr(word opcode, AvrDevice *c): int avr_op_LD_X_incr::operator()() { /* X is R27:R26 */ - word X = core->GetRegX(); + unsigned X = core->GetRegX(); if (Rd == 26 || Rd == 27) avr_error( "Result of operation is undefined" ); + if (core->rampx && core->flagXMega ) + X = (core->rampx->GetRegVal() << 16) | X; + /* Perform post-increment */ core->SetCoreReg(Rd, core->GetRWMem(X)); X++; core->SetCoreReg(26, X & 0xff); core->SetCoreReg(27, (X >> 8) & 0xff); + if (core->rampx && core->flagXMega) + core->rampx->SetRegVal((X >> 16) & 0xff); + return core->flagXMega ? 1 : 2; } @@ -879,16 +901,22 @@ avr_op_LD_Y_decr::avr_op_LD_Y_decr(word opcode, AvrDevice *c): int avr_op_LD_Y_decr::operator()() { /* Y is R29:R28 */ - word Y = core->GetRegY(); + unsigned Y = core->GetRegY(); if (Rd == 28 || Rd == 29) avr_error( "Result of operation is undefined" ); + if (core->rampy && core->flagXMega) + Y = (core->rampy->GetRegVal() << 16) | Y; + /* Perform pre-decrement */ Y--; core->SetCoreReg(Rd, core->GetRWMem(Y)); core->SetCoreReg(28, Y & 0xff); core->SetCoreReg(29, (Y >> 8) & 0xff); + if (core->rampy && core->flagXMega) + core->rampy->SetRegVal((Y >> 16) & 0xff); + return core->flagTiny10 ? 3 : 2; } @@ -898,16 +926,22 @@ avr_op_LD_Y_incr::avr_op_LD_Y_incr(word opcode, AvrDevice *c): int avr_op_LD_Y_incr::operator()() { /* Y is R29:R28 */ - word Y = core->GetRegY(); + unsigned Y = core->GetRegY(); if (Rd == 28 || Rd == 29) avr_error( "Result of operation is undefined" ); + if (core->rampy && core->flagXMega) + Y = (core->rampy->GetRegVal() << 16) | Y; + /* Perform post-increment */ core->SetCoreReg(Rd, core->GetRWMem(Y)); Y++; core->SetCoreReg(28, Y & 0xff); core->SetCoreReg(29, (Y >> 8) & 0xff); + if (core->rampy && core->flagXMega) + core->rampy->SetRegVal((Y >> 16) & 0xff); + return core->flagXMega ? 1 : 2; } @@ -917,16 +951,22 @@ avr_op_LD_Z_incr::avr_op_LD_Z_incr(word opcode, AvrDevice *c): int avr_op_LD_Z_incr::operator()() { /* Z is R31:R30 */ - word Z = core->GetRegZ(); + unsigned Z = core->GetRegZ(); if (Rd == 30 || Rd == 31) avr_error( "Result of operation is undefined" ); + if (core->rampz && core->flagXMega) + Z = (core->rampz->GetRegVal() << 16) | Z; + /* Perform post-increment */ core->SetCoreReg(Rd, core->GetRWMem(Z)); Z++; core->SetCoreReg(30, Z & 0xff); core->SetCoreReg(31, (Z >> 8) & 0xff); + if (core->rampz && core->flagXMega) + core->rampz->SetRegVal((Z >> 16) & 0xff); + return core->flagXMega ? 1 : 2; } @@ -936,16 +976,22 @@ avr_op_LD_Z_decr::avr_op_LD_Z_decr(word opcode, AvrDevice *c): int avr_op_LD_Z_decr::operator()() { /* Z is R31:R30 */ - word Z = core->GetRegZ(); + unsigned Z = core->GetRegZ(); if (Rd == 30 || Rd == 31) avr_error( "Result of operation is undefined" ); + if (core->rampz && core->flagXMega) + Z = (core->rampz->GetRegVal() << 16) | Z; + /* Perform pre-decrement */ Z--; core->SetCoreReg(Rd, core->GetRWMem(Z)); core->SetCoreReg(30, Z & 0xff); core->SetCoreReg(31, (Z >> 8) & 0xff); + if (core->rampz && core->flagXMega) + core->rampz->SetRegVal((Z >> 16) & 0xff); + return core->flagTiny10 ? 3 : 2; } @@ -956,6 +1002,7 @@ avr_op_LPM_Z::avr_op_LPM_Z(word opcode, AvrDevice *c): int avr_op_LPM_Z::operator()() { /* Z is R31:R30 */ word Z = core->GetRegZ(); + // Do not use RAMPZ Z ^= 0x0001; core->SetCoreReg(Rd , core->Flash->ReadMem(Z)); @@ -969,7 +1016,8 @@ avr_op_LPM::avr_op_LPM(word opcode, AvrDevice *c): int avr_op_LPM::operator()() { /* Z is R31:R30 */ word Z = core->GetRegZ(); - + // Do not use RAMPZ + Z ^= 0x0001; core->SetCoreReg(0 , core->Flash->ReadMem(Z)); @@ -983,6 +1031,7 @@ avr_op_LPM_Z_incr::avr_op_LPM_Z_incr(word opcode, AvrDevice *c): int avr_op_LPM_Z_incr::operator()() { /* Z is R31:R30 */ word Z = core->GetRegZ(); + // Do not use RAMPZ core->SetCoreReg(Rd , core->Flash->ReadMem(Z ^ 0x0001)); @@ -1549,7 +1598,11 @@ avr_op_STS::avr_op_STS(word opcode, AvrDevice *c): int avr_op_STS::operator()() { /* Get data at k in current data segment and put into Rd */ - word k = core->Flash->ReadMemWord((core->PC + 1) * 2); + unsigned k = core->Flash->ReadMemWord((core->PC + 1) * 2); + + if (core->rampd && core->flagXMega) { + k = (core->rampd->GetRegVal() << 16) | k; + } core->SetRWMem(k, core->GetCoreReg(R1)); core->PC++; @@ -1563,8 +1616,11 @@ avr_op_ST_X::avr_op_ST_X(word opcode, AvrDevice *c): int avr_op_ST_X::operator()() { /* X is R27:R26 */ - word X = core->GetRegX(); + unsigned X = core->GetRegX(); + if (core->rampx && core->flagXMega) + X = (core->rampx->GetRegVal() << 16) | X; + core->SetRWMem(X, core->GetCoreReg(R1)); return (core->flagXMega || core->flagTiny10) ? 1 : 2; @@ -1576,17 +1632,23 @@ avr_op_ST_X_decr::avr_op_ST_X_decr(word opcode, AvrDevice *c): int avr_op_ST_X_decr::operator()() { /* X is R27:R26 */ - word X = core->GetRegX(); + unsigned X = core->GetRegX(); if (R1 == 26 || R1 == 27) avr_error( "Result of operation is undefined" ); + if (core->rampx && core->flagXMega) + X = (core->rampx->GetRegVal() << 16) | X; + /* Perform pre-decrement */ X--; core->SetCoreReg(26, X & 0xff); core->SetCoreReg(27, (X >> 8) & 0xff); core->SetRWMem(X, core->GetCoreReg(R1)); - return 2; + if (core->rampx && core->flagXMega) + core->rampx->SetRegVal((X >> 16) & 0xff); + + return (core->flagXMega || core->flagTiny10) ? 1 : 2; } avr_op_ST_X_incr::avr_op_ST_X_incr(word opcode, AvrDevice *c): @@ -1595,10 +1657,13 @@ avr_op_ST_X_incr::avr_op_ST_X_incr(word opcode, AvrDevice *c): int avr_op_ST_X_incr::operator()() { /* X is R27:R26 */ - word X = core->GetRegX(); + unsigned X = core->GetRegX(); if (R1 == 26 || R1 == 27) avr_error( "Result of operation is undefined" ); + if (core->rampx && core->flagXMega) + X = (core->rampx->GetRegVal() << 16) | X; + core->SetRWMem(X, core->GetCoreReg(R1)); /* Perform post-increment */ @@ -1606,6 +1671,9 @@ int avr_op_ST_X_incr::operator()() { core->SetCoreReg(26, X & 0xff); core->SetCoreReg(27, (X >> 8) & 0xff); + if (core->rampx && core->flagXMega) + core->rampx->SetRegVal((X >> 16) & 0xff); + return (core->flagXMega || core->flagTiny10) ? 1 : 2; } @@ -1615,16 +1683,22 @@ avr_op_ST_Y_decr::avr_op_ST_Y_decr(word opcode, AvrDevice *c): int avr_op_ST_Y_decr::operator()() { /* Y is R29:R28 */ - word Y = core->GetRegY(); + unsigned Y = core->GetRegY(); if (R1 == 28 || R1 == 29) avr_error( "Result of operation is undefined" ); - + + if (core->rampy && core->flagXMega) + Y = (core->rampy->GetRegVal() << 16) | Y; + /* Perform pre-decrement */ Y--; core->SetCoreReg(28, Y & 0xff); core->SetCoreReg(29, (Y >> 8) & 0xff); core->SetRWMem(Y, core->GetCoreReg(R1)); + if (core->rampy && core->flagXMega) + core->rampy->SetRegVal((Y >> 16) & 0xff); + return 2; } @@ -1634,17 +1708,22 @@ avr_op_ST_Y_incr::avr_op_ST_Y_incr(word opcode, AvrDevice *c): int avr_op_ST_Y_incr::operator()() { /* Y is R29:R28 */ - word Y = core->GetRegY(); + unsigned Y = core->GetRegY(); if (R1 == 28 || R1 == 29) avr_error( "Result of operation is undefined" ); - core->SetRWMem(Y, core->GetCoreReg(R1)); + if (core->rampy && core->flagXMega) + Y = (core->rampy->GetRegVal() << 16) | Y; /* Perform post-increment */ + core->SetRWMem(Y, core->GetCoreReg(R1)); Y++; core->SetCoreReg(28, Y & 0xff); core->SetCoreReg(29, (Y >> 8) & 0xff); + if (core->rampy && core->flagXMega) + core->rampy->SetRegVal((Y >> 16) & 0xff); + return (core->flagXMega || core->flagTiny10) ? 1 : 2; } @@ -1654,9 +1733,12 @@ avr_op_ST_Z_decr::avr_op_ST_Z_decr(word opcode, AvrDevice *c): int avr_op_ST_Z_decr::operator()() { /* Z is R31:R30 */ - word Z = core->GetRegZ(); + unsigned Z = core->GetRegZ(); if (R1 == 30 || R1 == 31) avr_error( "Result of operation is undefined" ); + + if (core->rampz && core->flagXMega) + Z = (core->rampz->GetRegVal() << 16) | Z; /* Perform pre-decrement */ Z--; @@ -1664,6 +1746,9 @@ int avr_op_ST_Z_decr::operator()() { core->SetCoreReg(31, (Z >> 8) & 0xff); core->SetRWMem(Z, core->GetCoreReg(R1)); + if (core->rampz && core->flagXMega) + core->rampz->SetRegVal((Z >> 16) & 0xff); + return 2; } @@ -1673,17 +1758,22 @@ avr_op_ST_Z_incr::avr_op_ST_Z_incr(word opcode, AvrDevice *c): int avr_op_ST_Z_incr::operator()() { /* Z is R31:R30 */ - word Z = core->GetRegZ(); + unsigned Z = core->GetRegZ(); if (R1 == 30 || R1 == 31) avr_error( "Result of operation is undefined" ); - core->SetRWMem(Z, core->GetCoreReg(R1)); + if (core->rampz && core->flagXMega) + Z = (core->rampz->GetRegVal() << 16) | Z; /* Perform post-increment */ + core->SetRWMem(Z, core->GetCoreReg(R1)); Z++; core->SetCoreReg(30, Z & 0xff); core->SetCoreReg(31, (Z >> 8) & 0xff); + if (core->rampz && core->flagXMega) + core->rampz->SetRegVal((Z >> 16) & 0xff); + return (core->flagXMega || core->flagTiny10) ? 1 : 2; } @@ -1769,6 +1859,81 @@ int avr_op_BREAK::operator()() { return BREAK_POINT+1; } +avr_op_DES::avr_op_DES(word opcode, AvrDevice *c): + DecodedInstruction(c), + K(get_rd_4(opcode)) {} + +int avr_op_DES::operator()() { + // TODO - Data encription standart + return 1; +} + +avr_op_XCH::avr_op_XCH(word opcode, AvrDevice *c): + DecodedInstruction(c), + R1(get_rd_5(opcode)) {} + +int avr_op_XCH::operator()() { + /* Z is RAMPZ:R31:R30 */ + unsigned Z = core->GetRegZ(); + if (core->rampz) + Z = (core->rampz->GetRegVal() << 16) | Z; + + unsigned char tmp = core->GetCoreReg(R1); + core->SetCoreReg(R1, core->GetRWMem(Z)); + core->SetRWMem(Z, tmp); + return 2; +} + +avr_op_LAC::avr_op_LAC(word opcode, AvrDevice *c): + DecodedInstruction(c), + R1(get_rd_5(opcode)) {} + +int avr_op_LAC::operator()() { + /* Z is RAMPZ:R31:R30 */ + unsigned Z = core->GetRegZ(); + if (core->rampz) + Z = (core->rampz->GetRegVal() << 16) | Z; + + unsigned char tmp_r = core->GetCoreReg(R1); + unsigned char tmp_m = core->GetRWMem(Z); + core->SetCoreReg(R1, tmp_m); + core->SetRWMem(Z, (~tmp_r) & tmp_m); + return 2; +} + +avr_op_LAS::avr_op_LAS(word opcode, AvrDevice *c): + DecodedInstruction(c), + R1(get_rd_5(opcode)) {} + +int avr_op_LAS::operator()() { + /* Z is RAMPZ:R31:R30 */ + unsigned Z = core->GetRegZ(); + if (core->rampz) + Z = (core->rampz->GetRegVal() << 16) | Z; + + unsigned char tmp_r = core->GetCoreReg(R1); + unsigned char tmp_m = core->GetRWMem(Z); + core->SetCoreReg(R1, tmp_m); + core->SetRWMem(Z, tmp_r | tmp_m); + return 2; +} + +avr_op_LAT::avr_op_LAT(word opcode, AvrDevice *c): + DecodedInstruction(c), + R1(get_rd_5(opcode)) {} + +int avr_op_LAT::operator()() { + /* Z is RAMPZ:R31:R30 */ + unsigned Z = core->GetRegZ(); + if (core->rampz) + Z = (core->rampz->GetRegVal() << 16) | Z; + unsigned char tmp_r = core->GetCoreReg(R1); + unsigned char tmp_m = core->GetRWMem(Z); + core->SetCoreReg(R1, tmp_m); + core->SetRWMem(Z, tmp_r ^ tmp_m); + return 2; +} + avr_op_ILLEGAL::avr_op_ILLEGAL(word opcode, AvrDevice *c): DecodedInstruction(c) {} @@ -2145,6 +2310,40 @@ DecodedInstruction* lookup_opcode( word opcode, AvrDevice *core ) else return new avr_op_ILLEGAL(opcode, core); case 0x9402: return new avr_op_SWAP(opcode, core); /* 1001 010d dddd 0010 | SWAP */ + + case 0x9204: + if (!core->flagXMega) + return new avr_op_ILLEGAL(opcode, core); + else + return new avr_op_XCH(opcode, core); /* 1001 010d dddd 0100 | XCH */ + + case 0x9205: + if (!core->flagXMega) + return new avr_op_ILLEGAL(opcode, core); + else + return new avr_op_LAS(opcode, core); /* 1001 010d dddd 0101 | LAS */ + + case 0x9206: + if (!core->flagXMega) + return new avr_op_ILLEGAL(opcode, core); + else + return new avr_op_LAC(opcode, core); /* 1001 010d dddd 0110 | LAC */ + + case 0x9207: + if (!core->flagXMega) + return new avr_op_ILLEGAL(opcode, core); + else + return new avr_op_LAT(opcode, core); /* 1001 010d dddd 0111 | LAT */ + } + + /* opcodes with single 4-bit register (Rd) operand */ + decode = opcode & ~(mask_Rd_4); + switch ( decode ) { + case 0x940B: + if (!core->flagXMega) + return new avr_op_ILLEGAL(opcode, core); + else + return new avr_op_DES(opcode, core); /* 1001 1000 dddd 1011 | DEC */ } /* opcodes with a register (Rd) and a constant data (K) as operands */ diff --git a/libsim/decoder_trace.cpp b/libsim/decoder_trace.cpp index c66d161..e76bddf 100644 --- a/libsim/decoder_trace.cpp +++ b/libsim/decoder_trace.cpp @@ -750,6 +750,36 @@ int avr_op_BREAK::Trace() { return ret; } +int avr_op_DES::Trace() { + traceOut << "DES "<< (int)K << " "; + int ret = this->operator()(); + return ret; +} + +int avr_op_XCH::Trace() { + traceOut << "XCH Z,R" << (int)R1 << " "; + int ret = this->operator()(); + return ret; +} + +int avr_op_LAS::Trace() { + traceOut << "LAS Z,R" << (int)R1 << " "; + int ret = this->operator()(); + return ret; +} + +int avr_op_LAC::Trace() { + traceOut << "LAC Z,R" << (int)R1 << " "; + int ret = this->operator()(); + return ret; +} + +int avr_op_LAT::Trace() { + traceOut << "LAT Z,R" << (int)R1 << " "; + int ret = this->operator()(); + return ret; +} + int avr_op_ILLEGAL::Trace() { traceOut << "Invalid Instruction! "; int ret = this->operator()(); diff --git a/libsim/flashprog.cpp b/libsim/flashprog.cpp index a3985f5..57ee0a7 100644 --- a/libsim/flashprog.cpp +++ b/libsim/flashprog.cpp @@ -231,7 +231,7 @@ void FlashProgramming::SetSpmcr(unsigned char v) { AvrFuses::AvrFuses(void): fuseBitsSize(2), - fuseBits(0xfffffffd), + fuseBits(0xfffffffffffffffd), nrwwAddr(0), nrwwSize(0), bitPosBOOTSZ(-1), @@ -242,7 +242,7 @@ AvrFuses::AvrFuses(void): // do nothing! } -void AvrFuses::SetFuseConfiguration(int size, unsigned long defvalue) { +void AvrFuses::SetFuseConfiguration(int size, unsigned long long defvalue) { fuseBitsSize = size; fuseBits = defvalue; } diff --git a/libsim/hwnvm.cpp b/libsim/hwnvm.cpp new file mode 100644 index 0000000..32c7997 --- /dev/null +++ b/libsim/hwnvm.cpp @@ -0,0 +1,436 @@ +/* + **************************************************************************** + * + * simulavr - A simulator for the Atmel AVR family of microcontrollers. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + **************************************************************************** + * + * $Id$ + */ + +#include "hwnvm.h" +#include "hweeprom.h" +#define NVM_MASK 0x00FFFFFF + +// #define FLASH_PAGE_SIZE 256 +// #define EEPROM_PAGE_SIZE 32 + +HWNvm::HWNvm(AvrDevice *_core, unsigned int _memoryMapSize): + Hardware(_core), + TraceValueRegister(_core, "NVM"), + addr0_reg(this, "ADDR0", this, + &HWNvm::GetAddr0, &HWNvm::SetAddr0, + nullptr, nullptr), + addr1_reg(this, "ADDR1", this, + &HWNvm::GetAddr1, &HWNvm::SetAddr1, + nullptr, nullptr), + addr2_reg(this, "ADDR2", this, + &HWNvm::GetAddr2, &HWNvm::SetAddr2, + nullptr, nullptr), + data0_reg(this, "DATA0", this, + &HWNvm::GetData0, &HWNvm::SetData0, + nullptr, nullptr), + data1_reg(this, "DATA1", this, + &HWNvm::GetData1, &HWNvm::SetData1, + nullptr, nullptr), + data2_reg(this, "DATA2", this, + &HWNvm::GetData2, &HWNvm::SetData2, + nullptr, nullptr), + cmd_reg(this, "CMD", this, + &HWNvm::GetCmd, &HWNvm::SetCmd, + nullptr, nullptr), + ctrla_reg(this, "CTRLA", this, + nullptr, &HWNvm::SetCmdEx, + nullptr, nullptr), + ctrlb_reg(this, "CTRLB", this, + &HWNvm::GetCtrlb, &HWNvm::SetCtrlb, + nullptr, nullptr), + intctrl_reg(this, "INTCTRL", this, + &HWNvm::GetIntctrl, &HWNvm::SetIntctrl, + nullptr, nullptr), + status_reg(this, "STATUS", this, + &HWNvm::GetStatus, nullptr, + nullptr, nullptr), + lockbits_reg(this, "LOCKBITS", this, + &HWNvm::GetLockbits, &HWNvm::SetLockbits, + nullptr, nullptr), + ccp_reg(this, "CCP", this, + &HWNvm::GetCcp, &HWNvm::SetCcp, + nullptr, nullptr), + m_core(_core) { + Reset(); +} + +HWNvm::~HWNvm() { +} + +unsigned int HWNvm::CpuCycle() { + return 0; +} + +void HWNvm::Reset() { + m_address = 0x000000; + m_data = 0x000000; + m_command = NVM_CMD_NO_OPERATION; + + m_ctrlb = 0x00; + m_intctrl = 0x00; + m_lockbits = 0x00; + m_ccp = 0; +} + +void HWNvm::SetAddr0(unsigned char val) { + m_address = ((m_address & 0x00FFFF00) | (val << 0)) & NVM_MASK; + if (m_core->trace_on == 1) + traceOut << "NVM_ADDR0=0x" << std::hex << val << std::dec; +} + +void HWNvm::SetAddr1(unsigned char val) { + m_address = ((m_address & 0x00FF00FF) | (val << 8)) & NVM_MASK; + if (m_core->trace_on == 1) + traceOut << "NVM_ADDR1=0x" << std::hex << val << std::dec; +} + +void HWNvm::SetAddr2(unsigned char val) { + m_address = ((m_address & 0x0000FFFF) | (val << 16)) & NVM_MASK; + if (m_core->trace_on == 1) + traceOut << "NVM_ADDR2=0x" << std::hex << val << std::dec; +} + +void HWNvm::SetData0(unsigned char val) { + m_data = ((m_data & 0x00FFFF00) | (val << 0)) & NVM_MASK; + if (m_core->trace_on == 1) + traceOut << "NVM_DATA0=0x" << std::hex << val << std::dec; + + if (m_command == NVM_CMD_LOAD_EEPROM_BUFFER || + m_command == NVM_CMD_LOAD_FLASH_BUFFER) { + // set in data 0 will trig load operation + SetCmdEx(0x01); + } +} + +void HWNvm::SetData1(unsigned char val) { + m_data = ((m_data & 0x00FF00FF) | (val << 8)) & NVM_MASK; + if (m_core->trace_on == 1) + traceOut << "NVM_DATA1=0x" << std::hex << val << std::dec; +} + +void HWNvm::SetData2(unsigned char val) { + m_data = ((m_data & 0x0000FFFF) | (val << 16)) & NVM_MASK; + if (m_core->trace_on == 1) + traceOut << "NVM_DATA2=0x" << std::hex << val << std::dec; +} + +void HWNvm::SetCmd(unsigned char val) { + m_command = val; + if (m_core->trace_on) + traceOut << "NVM_CMD=0x" << std::hex << val << std::dec; +} + +void HWNvm::SetCmdEx(unsigned char val) { + // The CMDEX is set to 1, located on bit 0. Do nothing in any other case + if (val != 1) { + avr_warning("Only set CMDEX is supported. NVM_CTRLA received 0x%02x", val); + } + if (~val & 1) return; + switch (m_command) { + case NVM_CMD_NO_OPERATION: + // Do nothing + break; + + case NVM_CMD_READ_CALIB_ROW: + m_data = 0; + avr_warning ("Command READ_CALIB_ROW (0x%02x) is not supported.", m_command); + break; + + case NVM_CMD_READ_USER_SIG_ROW: + m_data = m_core->GetDeviceSignature(); + break; + + case NVM_CMD_READ_EEPROM: + m_data = 0; + if (m_core->eeprom) { + if (m_address > 0xFFFF) { + avr_warning ("Reading eeprom at address 0x%08x is not supported.", m_address); + } + else { + m_core->eeprom->SetEearl((m_address >> 0) & 0xFF); + m_core->eeprom->SetEearh((m_address >> 8) & 0xFF); + m_core->eeprom->SetEecr(HWEeprom::CTRL_READ); + m_data = m_core->eeprom->GetEedr(); + } + } + else { + avr_warning ("Command READ_EEPROM (0x%02x) is not supported.", m_command); + } + break; + + case NVM_CMD_READ_FUSES: + m_data = 0; + if (m_core->fuses) { + m_data = m_core->fuses->GetFuseByte(3) | + m_core->fuses->GetFuseByte(2) | + m_core->fuses->GetFuseByte(1) | + m_core->fuses->GetFuseByte(0) ; + } + else { + avr_warning ("Command READ_FUSES (0x%02x) is not supported.", m_command); + } + break; + + case NVM_CMD_WRITE_LOCK_BITS: + if (m_core->lockbits) { + m_core->lockbits->SetLockBits(m_data & 0xFF); + } + else { + avr_warning ("Command WRITE_LOCK_BITS (0x%02x) is not supported.", m_command); + } + break; + + case NVM_CMD_ERASE_USER_SIG_ROW: + avr_warning ("Command ERASE_USER_SIG_ROW (0x%02x) is not supported.", m_command); + break; + + case NVM_CMD_WRITE_USER_SIG_ROW: + avr_warning ("Command WRITE_USER_SIG_ROW (0x%02x) is not supported.", m_command); + break; + + case NVM_CMD_ERASE_APP: + avr_warning ("Command ERASE_APP (0x%02x) is not supported.", m_command); + break; + + case NVM_CMD_ERASE_APP_PAGE: + avr_warning ("Command ERASE_APP_PAGE (0x%02x) is not supported.", m_command); + break; + + case NVM_CMD_LOAD_FLASH_BUFFER: + avr_warning ("Command LOAD_FLASH_BUFFER (0x%02x) is not supported.", m_command); + break; + + case NVM_CMD_WRITE_APP_PAGE: + avr_warning ("Command WRITE_APP_PAGE (0x%02x) is not supported.", m_command); + break; + + case NVM_CMD_ERASE_WRITE_APP_PAGE: + avr_warning ("Command ERASE_WRITE_APP_PAGE (0x%02x) is not supported.", m_command); + break; + + case NVM_CMD_ERASE_FLASH_BUFFER: + avr_warning ("Command ERASE_FLASH_BUFFER (0x%02x) is not supported.", m_command); + break; + + case NVM_CMD_ERASE_BOOT_PAGE: + avr_warning ("Command ERASE_BOOT_PAGE (0x%02x) is not supported.", m_command); + break; + + case NVM_CMD_WRITE_BOOT_PAGE: + avr_warning ("Command WRITE_BOOT_PAGE (0x%02x) is not supported.", m_command); + break; + + case NVM_CMD_ERASE_WRITE_BOOT_PAGE: + avr_warning ("Command ERASE_WRITE_BOOT_PAGE (0x%02x) is not supported.", m_command); + break; + + case NVM_CMD_ERASE_EEPROM: + if (m_core->eeprom) { + for (int i = m_core->eeprom->GetSize() - 1; i >=0; --i) { + m_core->eeprom->WriteAtAddress(i, 0xFF); + } + } + else { + avr_warning ("Command ERASE_EEPROM (0x%02x) is not supported.", m_command); + } + break; + + case NVM_CMD_ERASE_EEPROM_PAGE: + if (m_core->eeprom) { + if (m_address > 0xFFFF) { + avr_warning ("Erasing eeprom at address 0x%08x is not supported.", m_address); + } + else { + m_core->eeprom->SetEearl((m_address >> 0) & 0xFF); + m_core->eeprom->SetEearh((m_address >> 8) & 0xFF); + m_core->eeprom->SetEedr(0xFF); + m_core->eeprom->SetEecr(HWEeprom::CTRL_ENABLE); + m_core->eeprom->SetEecr(HWEeprom::CTRL_MODE_ERASE | HWEeprom::CTRL_WRITE); + } + } + else { + avr_warning ("Command ERASE_EEPROM_PAGE (0x%02x) is not supported.", m_command); + } + break; + + case NVM_CMD_LOAD_EEPROM_BUFFER: + if (m_core->eeprom) { + if (m_address > 0xFFFF) { + avr_warning ("Writing eeprom at address 0x%08x is not supported.", m_address); + } + else { + m_core->eeprom->SetEearl((m_address >> 0) & 0xFF); + m_core->eeprom->SetEearh((m_address >> 8) & 0xFF); + m_core->eeprom->SetEedr(m_data & 0xFF); + } + } + else { + avr_warning ("Command LOAD_EEPROM_BUFFER (0x%02x) is not supported.", m_command); + } + break; + + case NVM_CMD_WRITE_EEPROM_PAGE: + if (m_core->eeprom) { + // m_core->eeprom->WriteAtAddress ((m_core->eeprom->GetEearh() << 8) | (m_core->eeprom->GetEearl() << 0), m_core->eeprom->GetEedr()); + m_core->eeprom->SetEecr(HWEeprom::CTRL_ENABLE); + m_core->eeprom->SetEecr(HWEeprom::CTRL_MODE_WRITE | HWEeprom::CTRL_WRITE); + } + else { + avr_warning ("Command WRITE_EEPROM_PAGE (0x%02x) is not supported.", m_command); + } + break; + + case NVM_CMD_ERASE_WRITE_EEPROM_PAGE: + if (m_core->eeprom) { + // m_core->eeprom->WriteAtAddress ((m_core->eeprom->GetEearh() << 8) | (m_core->eeprom->GetEearl() << 0), m_core->eeprom->GetEedr()); + m_core->eeprom->SetEecr(HWEeprom::CTRL_ENABLE); + m_core->eeprom->SetEecr(HWEeprom::CTRL_MODE_WRITE | HWEeprom::CTRL_WRITE); + } + else { + avr_warning ("Command ERASE_WRITE_EEPROM_PAGE (0x%02x) is not supported.", m_command); + } + break; + + case NVM_CMD_ERASE_EEPROM_BUFFER: + if (m_core->eeprom) { + // m_core->eeprom->WriteAtAddress ((m_core->eeprom->GetEearh() << 8) | (m_core->eeprom->GetEearl() << 0), m_core->eeprom->GetEedr()); + m_core->eeprom->SetEecr(HWEeprom::CTRL_ENABLE); + m_core->eeprom->SetEecr(HWEeprom::CTRL_MODE_ERASE | HWEeprom::CTRL_WRITE); + } + else { + avr_warning ("Command ERASE_EEPROM_BUFFER (0x%02x) is not supported.", m_command); + } + break; + + case NVM_CMD_APP_CRC: + avr_warning ("Command APP_CRC (0x%02x) is not supported.", m_command); + break; + + case NVM_CMD_BOOT_CRC: + avr_warning ("Command BOOT_CRC (0x%02x) is not supported.", m_command); + break; + + case NVM_CMD_FLASH_RANGE_CRC: + avr_warning ("Command FLASH_RANGE_CRC (0x%02x) is not supported.", m_command); + break; + + default: + avr_warning ("Command %1$d (0x%1$02x) is not supported.", m_command); + break; + } +} + +void HWNvm::SetCtrlb(unsigned char val) { + m_ctrlb = val; +} +void HWNvm::SetIntctrl(unsigned char val) { + m_intctrl = val; +} +void HWNvm::SetLockbits(unsigned char val) { + m_lockbits = val; +} +void HWNvm::SetCcp(unsigned char val) { + m_ccp = val; +} + +unsigned char HWNvm::GetAddr0() { + return (m_address >> 0) & 0xFF; +} + +unsigned char HWNvm::GetAddr1() { + return (m_address >> 8) & 0xFF; +} + +unsigned char HWNvm::GetAddr2() { + return (m_address >> 16) & 0xFF; +} + +unsigned char HWNvm::GetData0() { + return (m_data >> 0) & 0xFF; +} + +unsigned char HWNvm::GetData1() { + return (m_data >> 8) & 0xFF; +} + +unsigned char HWNvm::GetData2() { + return (m_data >> 16) & 0xFF; +} + +unsigned char HWNvm::GetCmd() { + return m_command; +} + +unsigned char HWNvm::GetStatus() { + const unsigned char eecr = (m_core->eeprom != NULL ? m_core->eeprom->GetEecr() : 0); + const unsigned char spmcsr = (m_core->spmRegister != NULL ? m_core->spmRegister->GetSpmcr() : 0); + unsigned char status = 0; + + // FLOAD + if (spmcsr & ( + (1 << 1) | // PGERS: Page Erase + (1 << 2)) // PGWRT: Page Write + ) { + status |= 0x01; + } + + // ELOAD + if (eecr & ( + (1 << 0) | // EERE: EEPROM Read Enable + (1 << 1)) // EEWE: EEPROM Write Enable + ) { + status |= 0x02; + } + + // FBUSY + if (spmcsr & ( + (1 << 0) | // SPMEN: Store Program Memory Enable + (1 << 6)) // RWWSB: Read-While-Write Section Busy + ) { + status |= 0x40; + } + + // NVMBUSY + if (status) { + status |= 0x80; + } + + return status; +} + +unsigned char HWNvm::GetCtrlb() { + return m_ctrlb; +} + +unsigned char HWNvm::GetIntctrl() { + return m_intctrl; +} + +unsigned char HWNvm::GetLockbits() { + return m_lockbits; +} + +unsigned char HWNvm::GetCcp() { + return m_ccp; +} diff --git a/libsim/hwxport.cpp b/libsim/hwxport.cpp new file mode 100644 index 0000000..2085af2 --- /dev/null +++ b/libsim/hwxport.cpp @@ -0,0 +1,117 @@ +/* + **************************************************************************** + * + * simulavr - A simulator for the Atmel AVR family of microcontrollers. + * Copyright (C) 2021 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + **************************************************************************** + * + * $Id$ + */ + +#include + +#include "hwxport.h" +#include "avrdevice.h" +#include "avrerror.h" +#include + +HWxPort::HWxPort(AvrDevice *core, const std::string &name, int size): + HWPort(core, name, false, size), + dirset_reg(this, "DIRSET", this, + nullptr, &HWxPort::setDirset, + nullptr, &HWxPort::setPinBitDirset), + dirclr_reg(this, "DIRCLR", this, + nullptr, &HWxPort::setDirclr, + nullptr, &HWxPort::setPinBitDirclr), + dirtgl_reg(this, "DIRTGL", this, + nullptr, &HWxPort::setDirtgl, + nullptr, &HWxPort::setPinBitDirtgl), + + outset_reg(this, "OUTSET", this, + nullptr, &HWxPort::setOutset, + nullptr, &HWxPort::setPinBitOutset), + outclr_reg(this, "OUTCLR", this, + nullptr, &HWxPort::setOutclr, + nullptr, &HWxPort::setPinBitOutclr), + outtgl_reg(this, "OUTTGL", this, + nullptr, &HWxPort::setOuttgl, + nullptr, &HWxPort::setPinBitOuttgl) + +{ + // port_reg.tracename = "OUT"; + // pin_reg.tracename = "IN"; + // ddr_reg.tracename = "DIR"; +} + +HWxPort::~HWxPort() { } + +void HWxPort::setDirset(unsigned char value) +{ + SetDdr(GetDdr() | value); +} +void HWxPort::setPinBitDirset(bool val, unsigned int bit) +{ + assert((bit >= 0) && (bit < sizeof(p)/sizeof(p[0]))); + setDirset(val << bit); +} +void HWxPort::setDirclr(unsigned char value) +{ + SetDdr(GetDdr() & ~value); +} +void HWxPort::setPinBitDirclr(bool val, unsigned int bit) +{ + assert((bit >= 0) && (bit < sizeof(p)/sizeof(p[0]))); + setDirclr(val << bit); +} +void HWxPort::setDirtgl(unsigned char value) +{ + SetDdr(GetDdr() ^ value); +} +void HWxPort::setPinBitDirtgl(bool val, unsigned int bit) +{ + assert((bit >= 0) && (bit < sizeof(p)/sizeof(p[0]))); + setDirtgl((val << bit)); +} + +void HWxPort::setOutset(unsigned char value) +{ + SetPort(GetPort() | value); +} +void HWxPort::setPinBitOutset(bool val, unsigned int bit) +{ + assert((bit >= 0) && (bit < sizeof(p)/sizeof(p[0]))); + setOutset(val << bit); +} +void HWxPort::setOutclr(unsigned char value) +{ + SetPort(GetPort() & ~value); +} +void HWxPort::setPinBitOutclr(bool val, unsigned int bit) +{ + assert((bit >= 0) && (bit < sizeof(p)/sizeof(p[0]))); + setOutclr(val << bit); +} +void HWxPort::setOuttgl(unsigned char value) +{ + SetPort(GetPort() ^ value); +} +void HWxPort::setPinBitOuttgl(bool val, unsigned int bit) +{ + assert((bit >= 0) && (bit < sizeof(p)/sizeof(p[0]))); + setOuttgl(val << bit); +} diff --git a/libsim/rwmem.cpp b/libsim/rwmem.cpp index aec8b06..d6f8565 100644 --- a/libsim/rwmem.cpp +++ b/libsim/rwmem.cpp @@ -205,6 +205,42 @@ unsigned char RAM::get() const { return value; } void RAM::set(unsigned char v) { value=v; } + +MemPtr::MemPtr(TraceValueCoreRegister *_reg, const std::string &name, unsigned char *ptrvalue, const size_t number, const size_t maxsize) { + corereg = _reg; + if (ptrvalue == NULL) + avr_error("No pointer provided for MemPtr memory"); + pValue = ptrvalue; + if(name.size()) { + tv = new TraceValue(8, corereg->GetTraceValuePrefix() + name, number); + if(!corereg) { + avr_error("registry not initialized for RWMemoryMember '%s'.", name.c_str()); + } + corereg->RegisterTraceSetValue(tv, name, maxsize); + } else { + tv = NULL; + } +} +unsigned char MemPtr::get() const { return *pValue; } +void MemPtr::set(unsigned char v) { *pValue=v; } + +CstMem::CstMem(TraceValueCoreRegister *_reg, const std::string &name, unsigned char v, const size_t number, const size_t maxsize) { + corereg = _reg; + value = v; + if(name.size()) { + tv = new TraceValue(8, corereg->GetTraceValuePrefix() + name, number); + if(!corereg) { + avr_error("registry not initialized for CstMem '%s'.", name.c_str()); + } + corereg->RegisterTraceSetValue(tv, name, maxsize); + } else { + tv = NULL; + } +} +unsigned char CstMem::get() const { return value; } +void CstMem::set(unsigned char v) { avr_error("Writing into constant register %s not allowed", tv->name().c_str()); } + + InvalidMem::InvalidMem(AvrDevice* _c, int _a): RWMemoryMember(), core(_c), diff --git a/libsim/traceval.cpp b/libsim/traceval.cpp index 2826e1f..a4e028b 100644 --- a/libsim/traceval.cpp +++ b/libsim/traceval.cpp @@ -321,6 +321,9 @@ void TraceValueCoreRegister::RegisterTraceSetValue(TraceValue *t, const std::str std::pair v(s, set); _tvr_valset.insert(v); } + else if(set->size() < size) { + set->resize(size, NULL); + } // set TraceValue to set[idx] (*set)[t->index()] = t; }