From 6f9406bbe3a91ec2b291a4b087390b38807f2997 Mon Sep 17 00:00:00 2001 From: Sidney Cadot Date: Tue, 17 Dec 2024 23:24:35 +0100 Subject: [PATCH 01/38] This adds timer functionality to sim65. It provides access to a handful of 64-bit counters that count different things: - clock cycles - instructions - number of IRQ processed - number of NMIs processed - nanoseconds since 1-1-1970. This in not ready yet to be pushed as a merge request into the upstream CC65 repository. What's lacking: - documentation - tests And to be discussed: - do we agree on this implementation direction and interface in principe? - can I include inttypes.h for printing a 64-bit unsigned value? - will clock_gettime() work on a Windows build? --- cfg/sim6502.cfg | 2 +- cfg/sim65c02.cfg | 2 +- src/sim65/6502.c | 13 +++- src/sim65/error.c | 8 +- src/sim65/main.c | 6 +- src/sim65/memory.c | 20 ++++- src/sim65/peripherals.c | 159 ++++++++++++++++++++++++++++++++++++++++ src/sim65/peripherals.h | 98 +++++++++++++++++++++++++ 8 files changed, 293 insertions(+), 15 deletions(-) create mode 100644 src/sim65/peripherals.c create mode 100644 src/sim65/peripherals.h diff --git a/cfg/sim6502.cfg b/cfg/sim6502.cfg index 39c33581c..d393a4aee 100644 --- a/cfg/sim6502.cfg +++ b/cfg/sim6502.cfg @@ -5,7 +5,7 @@ SYMBOLS { MEMORY { ZP: file = "", start = $0000, size = $0100; HEADER: file = %O, start = $0000, size = $000C; - MAIN: file = %O, define = yes, start = $0200, size = $FDF0 - __STACKSIZE__; + MAIN: file = %O, define = yes, start = $0200, size = $FDC0 - __STACKSIZE__; } SEGMENTS { ZEROPAGE: load = ZP, type = zp; diff --git a/cfg/sim65c02.cfg b/cfg/sim65c02.cfg index 39c33581c..d393a4aee 100644 --- a/cfg/sim65c02.cfg +++ b/cfg/sim65c02.cfg @@ -5,7 +5,7 @@ SYMBOLS { MEMORY { ZP: file = "", start = $0000, size = $0100; HEADER: file = %O, start = $0000, size = $000C; - MAIN: file = %O, define = yes, start = $0200, size = $FDF0 - __STACKSIZE__; + MAIN: file = %O, define = yes, start = $0200, size = $FDC0 - __STACKSIZE__; } SEGMENTS { ZEROPAGE: load = ZP, type = zp; diff --git a/src/sim65/6502.c b/src/sim65/6502.c index 48a1d560d..f48ba8fee 100644 --- a/src/sim65/6502.c +++ b/src/sim65/6502.c @@ -42,6 +42,7 @@ */ #include "memory.h" +#include "peripherals.h" #include "error.h" #include "6502.h" #include "paravirt.h" @@ -391,7 +392,7 @@ CPUType CPU; typedef void (*OPFunc) (void); /* The CPU registers */ -static CPURegs Regs; +CPURegs Regs; /* Cycles for the current insn */ static unsigned Cycles; @@ -4107,6 +4108,8 @@ unsigned ExecuteInsn (void) if (HaveNMIRequest) { HaveNMIRequest = 0; + PRegs.counter_nmi_events += 1; + PUSH (PCH); PUSH (PCL); PUSH (Regs.SR & ~BF); @@ -4121,6 +4124,8 @@ unsigned ExecuteInsn (void) } else if (HaveIRQRequest && GET_IF () == 0) { HaveIRQRequest = 0; + PRegs.counter_irq_events += 1; + PUSH (PCH); PUSH (PCL); PUSH (Regs.SR & ~BF); @@ -4139,8 +4144,14 @@ unsigned ExecuteInsn (void) /* Execute it */ Handlers[CPU][OPC] (); + + /* Increment the instruction counter by one.NMIs and IRQs are counted separately. */ + PRegs.counter_instructions += 1; } + /* Increment the 64-bit clock cycle counter with the cycle count for the instruction that we just executed */ + PRegs.counter_clock_cycles += Cycles; + /* Return the number of clock cycles needed by this insn */ return Cycles; } diff --git a/src/sim65/error.c b/src/sim65/error.c index fc24ca006..3618d660f 100644 --- a/src/sim65/error.c +++ b/src/sim65/error.c @@ -36,9 +36,10 @@ #include #include #include +#include #include "error.h" - +#include "peripherals.h" /*****************************************************************************/ @@ -50,9 +51,6 @@ /* flag to print cycles at program termination */ int PrintCycles = 0; -/* cycles are counted by main.c */ -extern unsigned long long TotalCycles; - /*****************************************************************************/ @@ -120,7 +118,7 @@ void SimExit (int Code) /* Exit the simulation with an exit code */ { if (PrintCycles) { - fprintf (stdout, "%llu cycles\n", TotalCycles); + fprintf (stdout, PRIu64 " cycles\n", PRegs.counter_clock_cycles); } exit (Code); } diff --git a/src/sim65/main.c b/src/sim65/main.c index 76c912c6b..8b41fcc0f 100644 --- a/src/sim65/main.c +++ b/src/sim65/main.c @@ -47,6 +47,7 @@ #include "6502.h" #include "error.h" #include "memory.h" +#include "peripherals.h" #include "paravirt.h" @@ -60,9 +61,6 @@ /* Name of program file */ const char* ProgramFile; -/* count of total cycles executed */ -unsigned long long TotalCycles = 0; - /* exit simulator after MaxCycles Cccles */ unsigned long long MaxCycles = 0; @@ -309,6 +307,7 @@ int main (int argc, char* argv[]) } MemInit (); + PeripheralsInit (); SPAddr = ReadProgramFile (); ParaVirtInit (I, SPAddr); @@ -318,7 +317,6 @@ int main (int argc, char* argv[]) RemainCycles = MaxCycles; while (1) { Cycles = ExecuteInsn (); - TotalCycles += Cycles; if (MaxCycles) { if (Cycles > RemainCycles) { ErrorCode (SIM65_ERROR_TIMEOUT, "Maximum number of cycles reached."); diff --git a/src/sim65/memory.c b/src/sim65/memory.c index b93693b91..c4b6bb220 100644 --- a/src/sim65/memory.c +++ b/src/sim65/memory.c @@ -36,7 +36,7 @@ #include #include "memory.h" - +#include "peripherals.h" /*****************************************************************************/ @@ -59,7 +59,14 @@ uint8_t Mem[0x10000]; void MemWriteByte (uint16_t Addr, uint8_t Val) /* Write a byte to a memory location */ { - Mem[Addr] = Val; + if ((PERIPHERALS_APERTURE_BASE_ADDRESS <= Addr) && (Addr <= PERIPHERALS_APERTURE_LAST_ADDRESS)) + { + /* Defer the the memory-mapped peripherals handler for this write. */ + PeripheralWriteByte (Addr - PERIPHERALS_APERTURE_BASE_ADDRESS, Val); + } else { + /* Write to the Mem array. */ + Mem[Addr] = Val; + } } @@ -76,7 +83,14 @@ void MemWriteWord (uint16_t Addr, uint16_t Val) uint8_t MemReadByte (uint16_t Addr) /* Read a byte from a memory location */ { - return Mem[Addr]; + if ((PERIPHERALS_APERTURE_BASE_ADDRESS <= Addr) && (Addr <= PERIPHERALS_APERTURE_LAST_ADDRESS)) + { + /* Defer the the memory-mapped peripherals handler for this read. */ + return PeripheralReadByte (Addr - PERIPHERALS_APERTURE_BASE_ADDRESS); + } else { + /* Read from the Mem array. */ + return Mem[Addr]; + } } diff --git a/src/sim65/peripherals.c b/src/sim65/peripherals.c new file mode 100644 index 000000000..edf401b02 --- /dev/null +++ b/src/sim65/peripherals.c @@ -0,0 +1,159 @@ +/*****************************************************************************/ +/* */ +/* peripherals.c */ +/* */ +/* Memory-mapped peripheral subsystem for the 6502 simulator */ +/* */ +/* */ +/* */ +/* (C) 2024-2025, Sidney Cadot */ +/* */ +/* */ +/* This software is provided 'as-is', without any expressed or implied */ +/* warranty. In no event will the authors be held liable for any damages */ +/* arising from the use of this software. */ +/* */ +/* Permission is granted to anyone to use this software for any purpose, */ +/* including commercial applications, and to alter it and redistribute it */ +/* freely, subject to the following restrictions: */ +/* */ +/* 1. The origin of this software must not be misrepresented; you must not */ +/* claim that you wrote the original software. If you use this software */ +/* in a product, an acknowledgment in the product documentation would be */ +/* appreciated but is not required. */ +/* 2. Altered source versions must be plainly marked as such, and must not */ +/* be misrepresented as being the original software. */ +/* 3. This notice may not be removed or altered from any source */ +/* distribution. */ +/* */ +/*****************************************************************************/ + + + +#include +#include "peripherals.h" + + +/*****************************************************************************/ +/* Data */ +/*****************************************************************************/ + + + +/* The peripheral registers. */ +PeripheralRegs PRegs; + + + +/*****************************************************************************/ +/* Code */ +/*****************************************************************************/ + + + +static uint64_t get_uint64_wallclock_time(void) +{ + struct timespec ts; + int result = clock_gettime(CLOCK_REALTIME, &ts); + if (result != 0) + { + // On failure, time will be set to the max value. + return 0xffffffffffffffff; + } + + /* Return time since the 1-1-1970 epoch, in nanoseconds. + * Note that this time may be off by an integer number of seconds, as POSIX + * maintaines that all days are 86,400 seconds long, which is not true due to + * leap seconds. + */ + return ts.tv_sec * 1000000000 + ts.tv_nsec; +} + + + +void PeripheralWriteByte (uint8_t Addr, uint8_t Val) +/* Write a byte to a memory location in the peripheral address aperture. */ +{ + switch (Addr) { + case PERIPHERALS_ADDRESS_OFFSET_LATCH: { + /* A write to the "latch" register performs a simultaneous latch of all registers */ + + /* Latch the current wallclock time first. */ + PRegs.latched_wallclock_time = get_uint64_wallclock_time(); + + /* Now latch all the cycles maintained by the processor. */ + PRegs.latched_counter_clock_cycles = PRegs.latched_counter_clock_cycles; + PRegs.latched_counter_instructions = PRegs.latched_counter_instructions; + PRegs.latched_counter_irq_events = PRegs.latched_counter_irq_events; + PRegs.latched_counter_nmi_events = PRegs.latched_counter_nmi_events; + break; + } + case PERIPHERALS_ADDRESS_OFFSET_SELECT: { + /* Set the value of the visibility-selection register. */ + PRegs.visible_latch_register = Val; + break; + } + default: { + /* Any other write is ignored */ + } + } +} + + + +uint8_t PeripheralReadByte (uint8_t Addr) +/* Read a byte from a memory location in the peripheral address aperture. */ +{ + switch (Addr) { + case PERIPHERALS_ADDRESS_OFFSET_SELECT: { + return PRegs.visible_latch_register; + } + case PERIPHERALS_ADDRESS_OFFSET_REG64 + 0: + case PERIPHERALS_ADDRESS_OFFSET_REG64 + 1: + case PERIPHERALS_ADDRESS_OFFSET_REG64 + 2: + case PERIPHERALS_ADDRESS_OFFSET_REG64 + 3: + case PERIPHERALS_ADDRESS_OFFSET_REG64 + 4: + case PERIPHERALS_ADDRESS_OFFSET_REG64 + 5: + case PERIPHERALS_ADDRESS_OFFSET_REG64 + 6: + case PERIPHERALS_ADDRESS_OFFSET_REG64 + 7: { + /* Read from any of the eight counter bytes. + * The first byte is the 64 bit value's LSB, the seventh byte is its MSB. + */ + unsigned byte_select = Addr - PERIPHERALS_ADDRESS_OFFSET_REG64; /* 0 .. 7 */ + uint64_t value; + switch (PRegs.visible_latch_register) { + case PERIPHERALS_REG64_SELECT_CLOCKCYCLE_COUNTER: value = PRegs.latched_counter_clock_cycles; break; + case PERIPHERALS_REG64_SELECT_INSTRUCTION_COUNTER: value = PRegs.latched_counter_instructions; break; + case PERIPHERALS_REG64_SELECT_IRQ_COUNTER: value = PRegs.latched_counter_irq_events; break; + case PERIPHERALS_REG64_SELECT_NMI_COUNTER: value = PRegs.latched_counter_nmi_events; break; + case PERIPHERALS_REG64_SELECT_WALLCLOCK_TIME: value = PRegs.latched_wallclock_time; break; + default: value = 0; /* Reading from a non-supported register will yield 0. */ + } + /* Return the desired byte of the latched counter. 0==LSB, 7==MSB. */ + return value >> (byte_select * 8); + } + default: { + /* Any other read yields a zero value. */ + return 0; + } + } +} + + + +void PeripheralsInit (void) +/* Initialize the peripheral registers */ +{ + PRegs.counter_clock_cycles = 0; + PRegs.counter_instructions = 0; + PRegs.counter_irq_events = 0; + PRegs.counter_nmi_events = 0; + + PRegs.latched_counter_clock_cycles = 0; + PRegs.latched_counter_instructions = 0; + PRegs.latched_counter_irq_events = 0; + PRegs.latched_counter_nmi_events = 0; + PRegs.latched_wallclock_time = 0; + + PRegs.visible_latch_register = 0; +} diff --git a/src/sim65/peripherals.h b/src/sim65/peripherals.h new file mode 100644 index 000000000..76da6e2f8 --- /dev/null +++ b/src/sim65/peripherals.h @@ -0,0 +1,98 @@ +/*****************************************************************************/ +/* */ +/* peripherals.h */ +/* */ +/* Memory-mapped peripheral subsystem for the 6502 simulator */ +/* */ +/* */ +/* */ +/* (C) 2024-2025, Sidney Cadot */ +/* */ +/* */ +/* This software is provided 'as-is', without any expressed or implied */ +/* warranty. In no event will the authors be held liable for any damages */ +/* arising from the use of this software. */ +/* */ +/* Permission is granted to anyone to use this software for any purpose, */ +/* including commercial applications, and to alter it and redistribute it */ +/* freely, subject to the following restrictions: */ +/* */ +/* 1. The origin of this software must not be misrepresented; you must not */ +/* claim that you wrote the original software. If you use this software */ +/* in a product, an acknowledgment in the product documentation would be */ +/* appreciated but is not required. */ +/* 2. Altered source versions must be plainly marked as such, and must not */ +/* be misrepresented as being the original software. */ +/* 3. This notice may not be removed or altered from any source */ +/* distribution. */ +/* */ +/*****************************************************************************/ + + + +#ifndef PERIPHERALS_H +#define PERIPHERALS_H + +#include + +#define PERIPHERALS_APERTURE_BASE_ADDRESS 0xffc0 +#define PERIPHERALS_APERTURE_LAST_ADDRESS 0xffc9 + +#define PERIPHERALS_ADDRESS_OFFSET_LATCH 0x00 +#define PERIPHERALS_ADDRESS_OFFSET_SELECT 0x01 +#define PERIPHERALS_ADDRESS_OFFSET_REG64 0x02 + +#define PERIPHERALS_LATCH (PERIPHERALS_APERTURE_BASE_ADDRESS + PERIPHERALS_ADDRESS_OFFSET_LATCH) +#define PERIPHERALS_SELECT (PERIPHERALS_APERTURE_BASE_ADDRESS + PERIPHERALS_ADDRESS_OFFSET_SELECT) +#define PERIPHERALS_REG64 (PERIPHERALS_APERTURE_BASE_ADDRESS + PERIPHERALS_ADDRESS_OFFSET_REG64) + +#define PERIPHERALS_REG64_SELECT_CLOCKCYCLE_COUNTER 0x00 +#define PERIPHERALS_REG64_SELECT_INSTRUCTION_COUNTER 0x01 +#define PERIPHERALS_REG64_SELECT_IRQ_COUNTER 0x02 +#define PERIPHERALS_REG64_SELECT_NMI_COUNTER 0x03 +#define PERIPHERALS_REG64_SELECT_WALLCLOCK_TIME 0x80 + +typedef struct { + /* the invisible counters that are continuously updated */ + uint64_t counter_clock_cycles; + uint64_t counter_instructions; + uint64_t counter_irq_events; + uint64_t counter_nmi_events; + /* latched counters upon a write to the 'latch' address. + * One of these will be visible (read only) through an each-byte aperture. */ + uint64_t latched_counter_clock_cycles; + uint64_t latched_counter_instructions; + uint64_t latched_counter_irq_events; + uint64_t latched_counter_nmi_events; + uint64_t latched_wallclock_time; + /* Select which of the five latched registers will be visible. + * This is a Read/Write byte-wide register. + * If a non-existent register is selected, the 8-byte aperture will read as zero. + */ + uint8_t visible_latch_register; +} PeripheralRegs; + +extern PeripheralRegs PRegs; + +/*****************************************************************************/ +/* Code */ +/*****************************************************************************/ + + + +void PeripheralWriteByte (uint8_t Addr, uint8_t Val); +/* Write a byte to a memory location in the peripheral address aperture. */ + + +uint8_t PeripheralReadByte (uint8_t Addr); +/* Read a byte from a memory location in the peripheral address aperture. */ + + +void PeripheralsInit (void); +/* Initialize the peripheral registers */ + + + +/* End of peripherals.h */ + +#endif From a3cc9b47571c885f590ec73692f8027870a79222 Mon Sep 17 00:00:00 2001 From: Sidney Cadot Date: Wed, 18 Dec 2024 08:55:30 +0100 Subject: [PATCH 02/38] Fixed mistake in the latching code. --- src/sim65/peripherals.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sim65/peripherals.c b/src/sim65/peripherals.c index edf401b02..6ff420a24 100644 --- a/src/sim65/peripherals.c +++ b/src/sim65/peripherals.c @@ -82,10 +82,10 @@ void PeripheralWriteByte (uint8_t Addr, uint8_t Val) PRegs.latched_wallclock_time = get_uint64_wallclock_time(); /* Now latch all the cycles maintained by the processor. */ - PRegs.latched_counter_clock_cycles = PRegs.latched_counter_clock_cycles; - PRegs.latched_counter_instructions = PRegs.latched_counter_instructions; - PRegs.latched_counter_irq_events = PRegs.latched_counter_irq_events; - PRegs.latched_counter_nmi_events = PRegs.latched_counter_nmi_events; + PRegs.latched_counter_clock_cycles = PRegs.counter_clock_cycles; + PRegs.latched_counter_instructions = PRegs.counter_instructions; + PRegs.latched_counter_irq_events = PRegs.counter_irq_events; + PRegs.latched_counter_nmi_events = PRegs.counter_nmi_events; break; } case PERIPHERALS_ADDRESS_OFFSET_SELECT: { From 8a7cd9c632c6090f52aee7925b7611093a73aa73 Mon Sep 17 00:00:00 2001 From: sidney Date: Thu, 19 Dec 2024 03:04:55 +0100 Subject: [PATCH 03/38] Fixed format string. --- src/sim65/error.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sim65/error.c b/src/sim65/error.c index 3618d660f..58c188676 100644 --- a/src/sim65/error.c +++ b/src/sim65/error.c @@ -118,7 +118,7 @@ void SimExit (int Code) /* Exit the simulation with an exit code */ { if (PrintCycles) { - fprintf (stdout, PRIu64 " cycles\n", PRegs.counter_clock_cycles); + fprintf (stdout, "%" PRIu64 " cycles\n", PRegs.counter_clock_cycles); } exit (Code); } From 5239d3a11b11619d6fb65f2691cea7ac92c136f7 Mon Sep 17 00:00:00 2001 From: sidney Date: Thu, 19 Dec 2024 03:48:15 +0100 Subject: [PATCH 04/38] Polishing the peripherals (and counter) interface. --- src/sim65/6502.c | 8 +-- src/sim65/error.c | 2 +- src/sim65/memory.c | 4 +- src/sim65/peripherals.c | 123 +++++++++++++++++++--------------------- src/sim65/peripherals.h | 82 +++++++++++++++++---------- 5 files changed, 117 insertions(+), 102 deletions(-) diff --git a/src/sim65/6502.c b/src/sim65/6502.c index f48ba8fee..7e993a59c 100644 --- a/src/sim65/6502.c +++ b/src/sim65/6502.c @@ -4108,7 +4108,7 @@ unsigned ExecuteInsn (void) if (HaveNMIRequest) { HaveNMIRequest = 0; - PRegs.counter_nmi_events += 1; + Peripherals.Counter.nmi_events += 1; PUSH (PCH); PUSH (PCL); @@ -4124,7 +4124,7 @@ unsigned ExecuteInsn (void) } else if (HaveIRQRequest && GET_IF () == 0) { HaveIRQRequest = 0; - PRegs.counter_irq_events += 1; + Peripherals.Counter.irq_events += 1; PUSH (PCH); PUSH (PCL); @@ -4146,11 +4146,11 @@ unsigned ExecuteInsn (void) Handlers[CPU][OPC] (); /* Increment the instruction counter by one.NMIs and IRQs are counted separately. */ - PRegs.counter_instructions += 1; + Peripherals.Counter.cpu_instructions += 1; } /* Increment the 64-bit clock cycle counter with the cycle count for the instruction that we just executed */ - PRegs.counter_clock_cycles += Cycles; + Peripherals.Counter.clock_cycles += Cycles; /* Return the number of clock cycles needed by this insn */ return Cycles; diff --git a/src/sim65/error.c b/src/sim65/error.c index 58c188676..45fb243d8 100644 --- a/src/sim65/error.c +++ b/src/sim65/error.c @@ -118,7 +118,7 @@ void SimExit (int Code) /* Exit the simulation with an exit code */ { if (PrintCycles) { - fprintf (stdout, "%" PRIu64 " cycles\n", PRegs.counter_clock_cycles); + fprintf (stdout, "%" PRIu64 " cycles\n", Peripherals.Counter.clock_cycles); } exit (Code); } diff --git a/src/sim65/memory.c b/src/sim65/memory.c index c4b6bb220..c80bf0f93 100644 --- a/src/sim65/memory.c +++ b/src/sim65/memory.c @@ -62,7 +62,7 @@ void MemWriteByte (uint16_t Addr, uint8_t Val) if ((PERIPHERALS_APERTURE_BASE_ADDRESS <= Addr) && (Addr <= PERIPHERALS_APERTURE_LAST_ADDRESS)) { /* Defer the the memory-mapped peripherals handler for this write. */ - PeripheralWriteByte (Addr - PERIPHERALS_APERTURE_BASE_ADDRESS, Val); + PeripheralsWriteByte (Addr - PERIPHERALS_APERTURE_BASE_ADDRESS, Val); } else { /* Write to the Mem array. */ Mem[Addr] = Val; @@ -86,7 +86,7 @@ uint8_t MemReadByte (uint16_t Addr) if ((PERIPHERALS_APERTURE_BASE_ADDRESS <= Addr) && (Addr <= PERIPHERALS_APERTURE_LAST_ADDRESS)) { /* Defer the the memory-mapped peripherals handler for this read. */ - return PeripheralReadByte (Addr - PERIPHERALS_APERTURE_BASE_ADDRESS); + return PeripheralsReadByte (Addr - PERIPHERALS_APERTURE_BASE_ADDRESS); } else { /* Read from the Mem array. */ return Mem[Addr]; diff --git a/src/sim65/peripherals.c b/src/sim65/peripherals.c index 6ff420a24..cc2eb6528 100644 --- a/src/sim65/peripherals.c +++ b/src/sim65/peripherals.c @@ -40,8 +40,8 @@ -/* The peripheral registers. */ -PeripheralRegs PRegs; +/* The system-wide state of the peripherals */ +Sim65Peripherals Peripherals; @@ -51,46 +51,37 @@ PeripheralRegs PRegs; -static uint64_t get_uint64_wallclock_time(void) -{ - struct timespec ts; - int result = clock_gettime(CLOCK_REALTIME, &ts); - if (result != 0) - { - // On failure, time will be set to the max value. - return 0xffffffffffffffff; - } - - /* Return time since the 1-1-1970 epoch, in nanoseconds. - * Note that this time may be off by an integer number of seconds, as POSIX - * maintaines that all days are 86,400 seconds long, which is not true due to - * leap seconds. - */ - return ts.tv_sec * 1000000000 + ts.tv_nsec; -} - - - -void PeripheralWriteByte (uint8_t Addr, uint8_t Val) -/* Write a byte to a memory location in the peripheral address aperture. */ +void PeripheralsWriteByte (uint8_t Addr, uint8_t Val) +/* Write a byte to a memory location in the peripherals address aperture. */ { switch (Addr) { - case PERIPHERALS_ADDRESS_OFFSET_LATCH: { - /* A write to the "latch" register performs a simultaneous latch of all registers */ + case PERIPHERALS_COUNTER_ADDRESS_OFFSET_LATCH: { + /* A write to the "latch" register performs a simultaneous latch of all registers. */ /* Latch the current wallclock time first. */ - PRegs.latched_wallclock_time = get_uint64_wallclock_time(); + struct timespec ts; + int result = clock_gettime(CLOCK_REALTIME, &ts); + if (result != 0) { + /* Unable to read time. Report max uint64 value for both fields. */ + Peripherals.Counter.latched_wallclock_time = 0xffffffffffffffff; + Peripherals.Counter.latched_wallclock_time_split = 0xffffffffffffffff; + } else { + /* Number of nanoseconds since 1-1-1970. */ + Peripherals.Counter.latched_wallclock_time = 1000000000u * ts.tv_sec + ts.tv_nsec; + /* High word is number of seconds, low word is number of nanoseconds. */ + Peripherals.Counter.latched_wallclock_time_split = (ts.tv_sec << 32) | ts.tv_nsec; + } - /* Now latch all the cycles maintained by the processor. */ - PRegs.latched_counter_clock_cycles = PRegs.counter_clock_cycles; - PRegs.latched_counter_instructions = PRegs.counter_instructions; - PRegs.latched_counter_irq_events = PRegs.counter_irq_events; - PRegs.latched_counter_nmi_events = PRegs.counter_nmi_events; + /* Latch the counters that reflect the state of the processor. */ + Peripherals.Counter.latched_clock_cycles = Peripherals.Counter.clock_cycles; + Peripherals.Counter.latched_cpu_instructions = Peripherals.Counter.cpu_instructions; + Peripherals.Counter.latched_irq_events = Peripherals.Counter.irq_events; + Peripherals.Counter.latched_nmi_events = Peripherals.Counter.nmi_events; break; } - case PERIPHERALS_ADDRESS_OFFSET_SELECT: { + case PERIPHERALS_COUNTER_ADDRESS_OFFSET_SELECT: { /* Set the value of the visibility-selection register. */ - PRegs.visible_latch_register = Val; + Peripherals.Counter.visible_latch_register = Val; break; } default: { @@ -101,33 +92,34 @@ void PeripheralWriteByte (uint8_t Addr, uint8_t Val) -uint8_t PeripheralReadByte (uint8_t Addr) -/* Read a byte from a memory location in the peripheral address aperture. */ +uint8_t PeripheralsReadByte (uint8_t Addr) +/* Read a byte from a memory location in the peripherals address aperture. */ { switch (Addr) { - case PERIPHERALS_ADDRESS_OFFSET_SELECT: { - return PRegs.visible_latch_register; + case PERIPHERALS_COUNTER_ADDRESS_OFFSET_SELECT: { + return Peripherals.Counter.visible_latch_register; } - case PERIPHERALS_ADDRESS_OFFSET_REG64 + 0: - case PERIPHERALS_ADDRESS_OFFSET_REG64 + 1: - case PERIPHERALS_ADDRESS_OFFSET_REG64 + 2: - case PERIPHERALS_ADDRESS_OFFSET_REG64 + 3: - case PERIPHERALS_ADDRESS_OFFSET_REG64 + 4: - case PERIPHERALS_ADDRESS_OFFSET_REG64 + 5: - case PERIPHERALS_ADDRESS_OFFSET_REG64 + 6: - case PERIPHERALS_ADDRESS_OFFSET_REG64 + 7: { + case PERIPHERALS_COUNTER_ADDRESS_OFFSET_VALUE + 0: + case PERIPHERALS_COUNTER_ADDRESS_OFFSET_VALUE + 1: + case PERIPHERALS_COUNTER_ADDRESS_OFFSET_VALUE + 2: + case PERIPHERALS_COUNTER_ADDRESS_OFFSET_VALUE + 3: + case PERIPHERALS_COUNTER_ADDRESS_OFFSET_VALUE + 4: + case PERIPHERALS_COUNTER_ADDRESS_OFFSET_VALUE + 5: + case PERIPHERALS_COUNTER_ADDRESS_OFFSET_VALUE + 6: + case PERIPHERALS_COUNTER_ADDRESS_OFFSET_VALUE + 7: { /* Read from any of the eight counter bytes. * The first byte is the 64 bit value's LSB, the seventh byte is its MSB. */ - unsigned byte_select = Addr - PERIPHERALS_ADDRESS_OFFSET_REG64; /* 0 .. 7 */ + unsigned byte_select = Addr - PERIPHERALS_COUNTER_ADDRESS_OFFSET_VALUE; /* 0 .. 7 */ uint64_t value; - switch (PRegs.visible_latch_register) { - case PERIPHERALS_REG64_SELECT_CLOCKCYCLE_COUNTER: value = PRegs.latched_counter_clock_cycles; break; - case PERIPHERALS_REG64_SELECT_INSTRUCTION_COUNTER: value = PRegs.latched_counter_instructions; break; - case PERIPHERALS_REG64_SELECT_IRQ_COUNTER: value = PRegs.latched_counter_irq_events; break; - case PERIPHERALS_REG64_SELECT_NMI_COUNTER: value = PRegs.latched_counter_nmi_events; break; - case PERIPHERALS_REG64_SELECT_WALLCLOCK_TIME: value = PRegs.latched_wallclock_time; break; - default: value = 0; /* Reading from a non-supported register will yield 0. */ + switch (Peripherals.Counter.visible_latch_register) { + case PERIPHERALS_COUNTER_SELECT_CLOCKCYCLE_COUNTER: value = Peripherals.Counter.latched_clock_cycles; break; + case PERIPHERALS_COUNTER_SELECT_INSTRUCTION_COUNTER: value = Peripherals.Counter.latched_cpu_instructions; break; + case PERIPHERALS_COUNTER_SELECT_IRQ_COUNTER: value = Peripherals.Counter.latched_irq_events; break; + case PERIPHERALS_COUNTER_SELECT_NMI_COUNTER: value = Peripherals.Counter.latched_nmi_events; break; + case PERIPHERALS_COUNTER_SELECT_WALLCLOCK_TIME: value = Peripherals.Counter.latched_wallclock_time; break; + case PERIPHERALS_COUNTER_SELECT_WALLCLOCK_TIME_SPLIT: value = Peripherals.Counter.latched_wallclock_time_split; break; + default: value = 0; /* Reading from a non-existent register will yield 0. */ } /* Return the desired byte of the latched counter. 0==LSB, 7==MSB. */ return value >> (byte_select * 8); @@ -144,16 +136,19 @@ uint8_t PeripheralReadByte (uint8_t Addr) void PeripheralsInit (void) /* Initialize the peripheral registers */ { - PRegs.counter_clock_cycles = 0; - PRegs.counter_instructions = 0; - PRegs.counter_irq_events = 0; - PRegs.counter_nmi_events = 0; + /* Initialize the COUNTER peripheral */ - PRegs.latched_counter_clock_cycles = 0; - PRegs.latched_counter_instructions = 0; - PRegs.latched_counter_irq_events = 0; - PRegs.latched_counter_nmi_events = 0; - PRegs.latched_wallclock_time = 0; + Peripherals.Counter.clock_cycles = 0; + Peripherals.Counter.cpu_instructions = 0; + Peripherals.Counter.irq_events = 0; + Peripherals.Counter.nmi_events = 0; - PRegs.visible_latch_register = 0; + Peripherals.Counter.latched_clock_cycles = 0; + Peripherals.Counter.latched_cpu_instructions = 0; + Peripherals.Counter.latched_irq_events = 0; + Peripherals.Counter.latched_nmi_events = 0; + Peripherals.Counter.latched_wallclock_time = 0; + Peripherals.Counter.latched_wallclock_time_split = 0; + + Peripherals.Counter.visible_latch_register = 0; } diff --git a/src/sim65/peripherals.h b/src/sim65/peripherals.h index 76da6e2f8..988fd2460 100644 --- a/src/sim65/peripherals.h +++ b/src/sim65/peripherals.h @@ -35,44 +35,64 @@ #include -#define PERIPHERALS_APERTURE_BASE_ADDRESS 0xffc0 -#define PERIPHERALS_APERTURE_LAST_ADDRESS 0xffc9 +/* The memory range where the memory-mapped peripherals can be accessed. */ -#define PERIPHERALS_ADDRESS_OFFSET_LATCH 0x00 -#define PERIPHERALS_ADDRESS_OFFSET_SELECT 0x01 -#define PERIPHERALS_ADDRESS_OFFSET_REG64 0x02 +#define PERIPHERALS_APERTURE_BASE_ADDRESS 0xffc0 +#define PERIPHERALS_APERTURE_LAST_ADDRESS 0xffc9 -#define PERIPHERALS_LATCH (PERIPHERALS_APERTURE_BASE_ADDRESS + PERIPHERALS_ADDRESS_OFFSET_LATCH) -#define PERIPHERALS_SELECT (PERIPHERALS_APERTURE_BASE_ADDRESS + PERIPHERALS_ADDRESS_OFFSET_SELECT) -#define PERIPHERALS_REG64 (PERIPHERALS_APERTURE_BASE_ADDRESS + PERIPHERALS_ADDRESS_OFFSET_REG64) +/* Declarations for the COUNTER peripheral (currently the only peripheral). */ -#define PERIPHERALS_REG64_SELECT_CLOCKCYCLE_COUNTER 0x00 -#define PERIPHERALS_REG64_SELECT_INSTRUCTION_COUNTER 0x01 -#define PERIPHERALS_REG64_SELECT_IRQ_COUNTER 0x02 -#define PERIPHERALS_REG64_SELECT_NMI_COUNTER 0x03 -#define PERIPHERALS_REG64_SELECT_WALLCLOCK_TIME 0x80 +#define PERIPHERALS_COUNTER_ADDRESS_OFFSET_LATCH 0x00 +#define PERIPHERALS_COUNTER_ADDRESS_OFFSET_SELECT 0x01 +#define PERIPHERALS_COUNTER_ADDRESS_OFFSET_VALUE 0x02 + +#define PERIPHERALS_COUNTER_LATCH (PERIPHERALS_APERTURE_BASE_ADDRESS + PERIPHERALS_ADDRESS_OFFSET_COUNTER_LATCH) +#define PERIPHERALS_COUNTER_SELECT (PERIPHERALS_APERTURE_BASE_ADDRESS + PERIPHERALS_ADDRESS_OFFSET_COUNTER_SELECT) +#define PERIPHERALS_COUNTER_VALUE (PERIPHERALS_APERTURE_BASE_ADDRESS + PERIPHERALS_ADDRESS_OFFSET_COUNTER) + +#define PERIPHERALS_COUNTER_SELECT_CLOCKCYCLE_COUNTER 0x00 +#define PERIPHERALS_COUNTER_SELECT_INSTRUCTION_COUNTER 0x01 +#define PERIPHERALS_COUNTER_SELECT_IRQ_COUNTER 0x02 +#define PERIPHERALS_COUNTER_SELECT_NMI_COUNTER 0x03 +#define PERIPHERALS_COUNTER_SELECT_WALLCLOCK_TIME 0x80 +#define PERIPHERALS_COUNTER_SELECT_WALLCLOCK_TIME_SPLIT 0x81 typedef struct { - /* the invisible counters that are continuously updated */ - uint64_t counter_clock_cycles; - uint64_t counter_instructions; - uint64_t counter_irq_events; - uint64_t counter_nmi_events; - /* latched counters upon a write to the 'latch' address. - * One of these will be visible (read only) through an each-byte aperture. */ - uint64_t latched_counter_clock_cycles; - uint64_t latched_counter_instructions; - uint64_t latched_counter_irq_events; - uint64_t latched_counter_nmi_events; + /* The invisible counters that keep processor state. */ + uint64_t clock_cycles; + uint64_t cpu_instructions; + uint64_t irq_events; + uint64_t nmi_events; + /* Latched counters upon a write to the PERIPHERALS_COUNTER_LATCH address. + * One of these will be visible (read only) through an eight-byte aperture. + * The purpose of these latched registers is to read 64-bit values one byte + * at a time, without having to worry that their content will change along + * the way. + */ + uint64_t latched_clock_cycles; + uint64_t latched_cpu_instructions; + uint64_t latched_irq_events; + uint64_t latched_nmi_events; uint64_t latched_wallclock_time; - /* Select which of the five latched registers will be visible. - * This is a Read/Write byte-wide register. - * If a non-existent register is selected, the 8-byte aperture will read as zero. + uint64_t latched_wallclock_time_split; + /* Select which of the six latched registers will be visible. + * This is a single byte, read/write register, accessible via address PERIPHERALS_COUNTER_SELECT. + * If a non-existent latch register is selected, the PERIPHERALS_REGS64 value will be zero. */ uint8_t visible_latch_register; -} PeripheralRegs; +} CounterPeripheral; -extern PeripheralRegs PRegs; + + +/* Declare the 'Sim65Peripherals' type and its single instance 'Peripherals'. */ + +typedef struct { + /* State of the peripherals simulated by sim65. + * Currently, there is only one: the COUNTER peripheral. */ + CounterPeripheral Counter; +} Sim65Peripherals; + +extern Sim65Peripherals Peripherals; /*****************************************************************************/ /* Code */ @@ -80,11 +100,11 @@ extern PeripheralRegs PRegs; -void PeripheralWriteByte (uint8_t Addr, uint8_t Val); +void PeripheralsWriteByte (uint8_t Addr, uint8_t Val); /* Write a byte to a memory location in the peripheral address aperture. */ -uint8_t PeripheralReadByte (uint8_t Addr); +uint8_t PeripheralsReadByte (uint8_t Addr); /* Read a byte from a memory location in the peripheral address aperture. */ From 3cd7548b59bef554c1ae7c412c3849019691099b Mon Sep 17 00:00:00 2001 From: sidney Date: Thu, 19 Dec 2024 03:50:44 +0100 Subject: [PATCH 05/38] Cosmetic fixes. --- src/sim65/peripherals.c | 16 ++++++++-------- src/sim65/peripherals.h | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/sim65/peripherals.c b/src/sim65/peripherals.c index cc2eb6528..74fc49d89 100644 --- a/src/sim65/peripherals.c +++ b/src/sim65/peripherals.c @@ -59,16 +59,16 @@ void PeripheralsWriteByte (uint8_t Addr, uint8_t Val) /* A write to the "latch" register performs a simultaneous latch of all registers. */ /* Latch the current wallclock time first. */ - struct timespec ts; + struct timespec ts; int result = clock_gettime(CLOCK_REALTIME, &ts); - if (result != 0) { - /* Unable to read time. Report max uint64 value for both fields. */ - Peripherals.Counter.latched_wallclock_time = 0xffffffffffffffff; + if (result != 0) { + /* Unable to read time. Report max uint64 value for both fields. */ + Peripherals.Counter.latched_wallclock_time = 0xffffffffffffffff; Peripherals.Counter.latched_wallclock_time_split = 0xffffffffffffffff; - } else { - /* Number of nanoseconds since 1-1-1970. */ + } else { + /* Number of nanoseconds since 1-1-1970. */ Peripherals.Counter.latched_wallclock_time = 1000000000u * ts.tv_sec + ts.tv_nsec; - /* High word is number of seconds, low word is number of nanoseconds. */ + /* High word is number of seconds, low word is number of nanoseconds. */ Peripherals.Counter.latched_wallclock_time_split = (ts.tv_sec << 32) | ts.tv_nsec; } @@ -134,7 +134,7 @@ uint8_t PeripheralsReadByte (uint8_t Addr) void PeripheralsInit (void) -/* Initialize the peripheral registers */ +/* Initialize the peripherals. */ { /* Initialize the COUNTER peripheral */ diff --git a/src/sim65/peripherals.h b/src/sim65/peripherals.h index 988fd2460..517931d85 100644 --- a/src/sim65/peripherals.h +++ b/src/sim65/peripherals.h @@ -109,7 +109,7 @@ uint8_t PeripheralsReadByte (uint8_t Addr); void PeripheralsInit (void); -/* Initialize the peripheral registers */ +/* Initialize the peripherals. */ From 743a3dc73518cf862c38df4a88c1e78fe2966358 Mon Sep 17 00:00:00 2001 From: sidney Date: Thu, 19 Dec 2024 07:44:01 +0100 Subject: [PATCH 06/38] Changed nameing convention of fields (now CamelCase), and improved comments. --- src/sim65/6502.c | 10 ++--- src/sim65/error.c | 2 +- src/sim65/peripherals.c | 87 +++++++++++++++++++++++------------------ src/sim65/peripherals.h | 34 ++++++++-------- 4 files changed, 74 insertions(+), 59 deletions(-) diff --git a/src/sim65/6502.c b/src/sim65/6502.c index 7e993a59c..84360bad4 100644 --- a/src/sim65/6502.c +++ b/src/sim65/6502.c @@ -4108,7 +4108,7 @@ unsigned ExecuteInsn (void) if (HaveNMIRequest) { HaveNMIRequest = 0; - Peripherals.Counter.nmi_events += 1; + Peripherals.Counter.NmiEvents += 1; PUSH (PCH); PUSH (PCL); @@ -4124,7 +4124,7 @@ unsigned ExecuteInsn (void) } else if (HaveIRQRequest && GET_IF () == 0) { HaveIRQRequest = 0; - Peripherals.Counter.irq_events += 1; + Peripherals.Counter.IrqEvents += 1; PUSH (PCH); PUSH (PCL); @@ -4146,11 +4146,11 @@ unsigned ExecuteInsn (void) Handlers[CPU][OPC] (); /* Increment the instruction counter by one.NMIs and IRQs are counted separately. */ - Peripherals.Counter.cpu_instructions += 1; + Peripherals.Counter.CpuInstructions += 1; } - /* Increment the 64-bit clock cycle counter with the cycle count for the instruction that we just executed */ - Peripherals.Counter.clock_cycles += Cycles; + /* Increment the 64-bit clock cycle counter with the cycle count for the instruction that we just executed. */ + Peripherals.Counter.ClockCycles += Cycles; /* Return the number of clock cycles needed by this insn */ return Cycles; diff --git a/src/sim65/error.c b/src/sim65/error.c index 45fb243d8..af8e88413 100644 --- a/src/sim65/error.c +++ b/src/sim65/error.c @@ -118,7 +118,7 @@ void SimExit (int Code) /* Exit the simulation with an exit code */ { if (PrintCycles) { - fprintf (stdout, "%" PRIu64 " cycles\n", Peripherals.Counter.clock_cycles); + fprintf (stdout, "%" PRIu64 " cycles\n", Peripherals.Counter.ClockCycles); } exit (Code); } diff --git a/src/sim65/peripherals.c b/src/sim65/peripherals.c index 74fc49d89..fbd4159e3 100644 --- a/src/sim65/peripherals.c +++ b/src/sim65/peripherals.c @@ -55,6 +55,9 @@ void PeripheralsWriteByte (uint8_t Addr, uint8_t Val) /* Write a byte to a memory location in the peripherals address aperture. */ { switch (Addr) { + + /* Handle writes to the Counter peripheral. */ + case PERIPHERALS_COUNTER_ADDRESS_OFFSET_LATCH: { /* A write to the "latch" register performs a simultaneous latch of all registers. */ @@ -63,29 +66,33 @@ void PeripheralsWriteByte (uint8_t Addr, uint8_t Val) int result = clock_gettime(CLOCK_REALTIME, &ts); if (result != 0) { /* Unable to read time. Report max uint64 value for both fields. */ - Peripherals.Counter.latched_wallclock_time = 0xffffffffffffffff; - Peripherals.Counter.latched_wallclock_time_split = 0xffffffffffffffff; + Peripherals.Counter.LatchedWallclockTime = 0xffffffffffffffff; + Peripherals.Counter.LatchedWallclockTimeSplit = 0xffffffffffffffff; } else { - /* Number of nanoseconds since 1-1-1970. */ - Peripherals.Counter.latched_wallclock_time = 1000000000u * ts.tv_sec + ts.tv_nsec; - /* High word is number of seconds, low word is number of nanoseconds. */ - Peripherals.Counter.latched_wallclock_time_split = (ts.tv_sec << 32) | ts.tv_nsec; + /* Wallclock time: number of nanoseconds since 1-1-1970. */ + Peripherals.Counter.LatchedWallclockTime = 1000000000u * ts.tv_sec + ts.tv_nsec; + /* Wallclock time, split: high word is number of seconds since 1-1-1970, + * low word is number of nanoseconds since the start of that second. */ + Peripherals.Counter.LatchedWallclockTimeSplit = (ts.tv_sec << 32) | ts.tv_nsec; } /* Latch the counters that reflect the state of the processor. */ - Peripherals.Counter.latched_clock_cycles = Peripherals.Counter.clock_cycles; - Peripherals.Counter.latched_cpu_instructions = Peripherals.Counter.cpu_instructions; - Peripherals.Counter.latched_irq_events = Peripherals.Counter.irq_events; - Peripherals.Counter.latched_nmi_events = Peripherals.Counter.nmi_events; + Peripherals.Counter.LatchedClockCycles = Peripherals.Counter.ClockCycles; + Peripherals.Counter.LatchedCpuInstructions = Peripherals.Counter.CpuInstructions; + Peripherals.Counter.LatchedIrqEvents = Peripherals.Counter.IrqEvents; + Peripherals.Counter.LatchedNmiEvents = Peripherals.Counter.NmiEvents; break; } case PERIPHERALS_COUNTER_ADDRESS_OFFSET_SELECT: { /* Set the value of the visibility-selection register. */ - Peripherals.Counter.visible_latch_register = Val; + Peripherals.Counter.LatchedValueSelected = Val; break; } + + /* Handle writes to unused and read-only peripheral addresses. */ + default: { - /* Any other write is ignored */ + /* No action. */ } } } @@ -96,8 +103,11 @@ uint8_t PeripheralsReadByte (uint8_t Addr) /* Read a byte from a memory location in the peripherals address aperture. */ { switch (Addr) { + + /* Handle reads from the Counter peripheral. */ + case PERIPHERALS_COUNTER_ADDRESS_OFFSET_SELECT: { - return Peripherals.Counter.visible_latch_register; + return Peripherals.Counter.LatchedValueSelected; } case PERIPHERALS_COUNTER_ADDRESS_OFFSET_VALUE + 0: case PERIPHERALS_COUNTER_ADDRESS_OFFSET_VALUE + 1: @@ -110,22 +120,25 @@ uint8_t PeripheralsReadByte (uint8_t Addr) /* Read from any of the eight counter bytes. * The first byte is the 64 bit value's LSB, the seventh byte is its MSB. */ - unsigned byte_select = Addr - PERIPHERALS_COUNTER_ADDRESS_OFFSET_VALUE; /* 0 .. 7 */ - uint64_t value; - switch (Peripherals.Counter.visible_latch_register) { - case PERIPHERALS_COUNTER_SELECT_CLOCKCYCLE_COUNTER: value = Peripherals.Counter.latched_clock_cycles; break; - case PERIPHERALS_COUNTER_SELECT_INSTRUCTION_COUNTER: value = Peripherals.Counter.latched_cpu_instructions; break; - case PERIPHERALS_COUNTER_SELECT_IRQ_COUNTER: value = Peripherals.Counter.latched_irq_events; break; - case PERIPHERALS_COUNTER_SELECT_NMI_COUNTER: value = Peripherals.Counter.latched_nmi_events; break; - case PERIPHERALS_COUNTER_SELECT_WALLCLOCK_TIME: value = Peripherals.Counter.latched_wallclock_time; break; - case PERIPHERALS_COUNTER_SELECT_WALLCLOCK_TIME_SPLIT: value = Peripherals.Counter.latched_wallclock_time_split; break; - default: value = 0; /* Reading from a non-existent register will yield 0. */ + unsigned ByteIndex = Addr - PERIPHERALS_COUNTER_ADDRESS_OFFSET_VALUE; /* 0 .. 7 */ + uint64_t Value; + switch (Peripherals.Counter.LatchedValueSelected) { + case PERIPHERALS_COUNTER_SELECT_CLOCKCYCLE_COUNTER: Value = Peripherals.Counter.LatchedClockCycles; break; + case PERIPHERALS_COUNTER_SELECT_INSTRUCTION_COUNTER: Value = Peripherals.Counter.LatchedCpuInstructions; break; + case PERIPHERALS_COUNTER_SELECT_IRQ_COUNTER: Value = Peripherals.Counter.LatchedIrqEvents; break; + case PERIPHERALS_COUNTER_SELECT_NMI_COUNTER: Value = Peripherals.Counter.LatchedNmiEvents; break; + case PERIPHERALS_COUNTER_SELECT_WALLCLOCK_TIME: Value = Peripherals.Counter.LatchedWallclockTime; break; + case PERIPHERALS_COUNTER_SELECT_WALLCLOCK_TIME_SPLIT: Value = Peripherals.Counter.LatchedWallclockTimeSplit; break; + default: Value = 0; /* Reading from a non-existent latch register will yield 0. */ } /* Return the desired byte of the latched counter. 0==LSB, 7==MSB. */ - return value >> (byte_select * 8); + return Value >> (ByteIndex * 8); } + + /* Handle reads from unused peripheral and write-only addresses. */ + default: { - /* Any other read yields a zero value. */ + /* Return zero value. */ return 0; } } @@ -136,19 +149,19 @@ uint8_t PeripheralsReadByte (uint8_t Addr) void PeripheralsInit (void) /* Initialize the peripherals. */ { - /* Initialize the COUNTER peripheral */ + /* Initialize the Counter peripheral */ - Peripherals.Counter.clock_cycles = 0; - Peripherals.Counter.cpu_instructions = 0; - Peripherals.Counter.irq_events = 0; - Peripherals.Counter.nmi_events = 0; + Peripherals.Counter.ClockCycles = 0; + Peripherals.Counter.CpuInstructions = 0; + Peripherals.Counter.IrqEvents = 0; + Peripherals.Counter.NmiEvents = 0; - Peripherals.Counter.latched_clock_cycles = 0; - Peripherals.Counter.latched_cpu_instructions = 0; - Peripherals.Counter.latched_irq_events = 0; - Peripherals.Counter.latched_nmi_events = 0; - Peripherals.Counter.latched_wallclock_time = 0; - Peripherals.Counter.latched_wallclock_time_split = 0; + Peripherals.Counter.LatchedClockCycles = 0; + Peripherals.Counter.LatchedCpuInstructions = 0; + Peripherals.Counter.LatchedIrqEvents = 0; + Peripherals.Counter.LatchedNmiEvents = 0; + Peripherals.Counter.LatchedWallclockTime = 0; + Peripherals.Counter.LatchedWallclockTimeSplit = 0; - Peripherals.Counter.visible_latch_register = 0; + Peripherals.Counter.LatchedValueSelected = 0; } diff --git a/src/sim65/peripherals.h b/src/sim65/peripherals.h index 517931d85..16ea83782 100644 --- a/src/sim65/peripherals.h +++ b/src/sim65/peripherals.h @@ -59,27 +59,29 @@ typedef struct { /* The invisible counters that keep processor state. */ - uint64_t clock_cycles; - uint64_t cpu_instructions; - uint64_t irq_events; - uint64_t nmi_events; - /* Latched counters upon a write to the PERIPHERALS_COUNTER_LATCH address. + uint64_t ClockCycles; + uint64_t CpuInstructions; + uint64_t IrqEvents; + uint64_t NmiEvents; + /* The 'latched_...' fields below hold values that are sampled upon a write + * to the PERIPHERALS_COUNTER_LATCH address. * One of these will be visible (read only) through an eight-byte aperture. * The purpose of these latched registers is to read 64-bit values one byte * at a time, without having to worry that their content will change along * the way. */ - uint64_t latched_clock_cycles; - uint64_t latched_cpu_instructions; - uint64_t latched_irq_events; - uint64_t latched_nmi_events; - uint64_t latched_wallclock_time; - uint64_t latched_wallclock_time_split; + uint64_t LatchedClockCycles; + uint64_t LatchedCpuInstructions; + uint64_t LatchedIrqEvents; + uint64_t LatchedNmiEvents; + uint64_t LatchedWallclockTime; + uint64_t LatchedWallclockTimeSplit; /* Select which of the six latched registers will be visible. - * This is a single byte, read/write register, accessible via address PERIPHERALS_COUNTER_SELECT. - * If a non-existent latch register is selected, the PERIPHERALS_REGS64 value will be zero. + * This is a single byte, read/write register, accessible via address + * PERIPHERALS_COUNTER_SELECT. If a non-existent latch register is selected, + * the PERIPHERALS_COUNTER_VALUE will be zero. */ - uint8_t visible_latch_register; + uint8_t LatchedValueSelected; } CounterPeripheral; @@ -87,8 +89,8 @@ typedef struct { /* Declare the 'Sim65Peripherals' type and its single instance 'Peripherals'. */ typedef struct { - /* State of the peripherals simulated by sim65. - * Currently, there is only one: the COUNTER peripheral. */ + /* State of the peripherals available in sim65. + * Currently, there is only one peripheral: the Counter. */ CounterPeripheral Counter; } Sim65Peripherals; From eb8ea0f2c41841a5fe44ea1a40027f90d2dda85e Mon Sep 17 00:00:00 2001 From: Sidney Cadot Date: Thu, 19 Dec 2024 20:57:34 +0100 Subject: [PATCH 07/38] Replaced incidental tab by spaces. --- src/sim65/peripherals.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/sim65/peripherals.c b/src/sim65/peripherals.c index fbd4159e3..33e206ff3 100644 --- a/src/sim65/peripherals.c +++ b/src/sim65/peripherals.c @@ -29,7 +29,6 @@ /*****************************************************************************/ - #include #include "peripherals.h" @@ -72,7 +71,7 @@ void PeripheralsWriteByte (uint8_t Addr, uint8_t Val) /* Wallclock time: number of nanoseconds since 1-1-1970. */ Peripherals.Counter.LatchedWallclockTime = 1000000000u * ts.tv_sec + ts.tv_nsec; /* Wallclock time, split: high word is number of seconds since 1-1-1970, - * low word is number of nanoseconds since the start of that second. */ + * low word is number of nanoseconds since the start of that second. */ Peripherals.Counter.LatchedWallclockTimeSplit = (ts.tv_sec << 32) | ts.tv_nsec; } @@ -105,7 +104,7 @@ uint8_t PeripheralsReadByte (uint8_t Addr) switch (Addr) { /* Handle reads from the Counter peripheral. */ - + case PERIPHERALS_COUNTER_ADDRESS_OFFSET_SELECT: { return Peripherals.Counter.LatchedValueSelected; } From e149d1dcf69278a47b9afdbc027cc5a3e2e819a9 Mon Sep 17 00:00:00 2001 From: Sidney Cadot Date: Tue, 24 Dec 2024 11:14:30 +0100 Subject: [PATCH 08/38] Disable the use of clock_gettime(), to see if this fixes the CC65 CI builds. --- src/sim65/peripherals.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/sim65/peripherals.c b/src/sim65/peripherals.c index 33e206ff3..516a827b0 100644 --- a/src/sim65/peripherals.c +++ b/src/sim65/peripherals.c @@ -61,6 +61,7 @@ void PeripheralsWriteByte (uint8_t Addr, uint8_t Val) /* A write to the "latch" register performs a simultaneous latch of all registers. */ /* Latch the current wallclock time first. */ +#if 0 struct timespec ts; int result = clock_gettime(CLOCK_REALTIME, &ts); if (result != 0) { @@ -74,6 +75,11 @@ void PeripheralsWriteByte (uint8_t Addr, uint8_t Val) * low word is number of nanoseconds since the start of that second. */ Peripherals.Counter.LatchedWallclockTimeSplit = (ts.tv_sec << 32) | ts.tv_nsec; } +#else + /* Temporarily skip call to clock_gettime() to check that we can build for Windows */ + Peripherals.Counter.LatchedWallclockTime = 0xffffffffffffffff; + Peripherals.Counter.LatchedWallclockTimeSplit = 0xffffffffffffffff; +#endif /* Latch the counters that reflect the state of the processor. */ Peripherals.Counter.LatchedClockCycles = Peripherals.Counter.ClockCycles; From d512954fe9ef8299d8982cf8f1dbb37d3f81787d Mon Sep 17 00:00:00 2001 From: Sidney Cadot Date: Tue, 24 Dec 2024 11:23:05 +0100 Subject: [PATCH 09/38] Added peripherals.c and peripherals.h to sim65.vcxproj --- src/sim65.vcxproj | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sim65.vcxproj b/src/sim65.vcxproj index 7bc489398..b5b642d02 100644 --- a/src/sim65.vcxproj +++ b/src/sim65.vcxproj @@ -86,6 +86,7 @@ + @@ -93,8 +94,9 @@ + - \ No newline at end of file + From 073606b858f9858571f5d02028538c24484733c7 Mon Sep 17 00:00:00 2001 From: Sidney Cadot Date: Tue, 24 Dec 2024 11:30:34 +0100 Subject: [PATCH 10/38] Trying re-ordering of dependencies to get the Windows version to compile. --- src/sim65.vcxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sim65.vcxproj b/src/sim65.vcxproj index b5b642d02..46260e052 100644 --- a/src/sim65.vcxproj +++ b/src/sim65.vcxproj @@ -82,19 +82,19 @@ + - + - From ca76db1ee4402c3c54ae41146aef0aee4c070f36 Mon Sep 17 00:00:00 2001 From: Sidney Cadot Date: Tue, 24 Dec 2024 11:59:52 +0100 Subject: [PATCH 11/38] peripherals.c now at the back of the dependency list. --- src/sim65.vcxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sim65.vcxproj b/src/sim65.vcxproj index 46260e052..b5b642d02 100644 --- a/src/sim65.vcxproj +++ b/src/sim65.vcxproj @@ -82,19 +82,19 @@ - + - + From 1096023e00b427bbee2cdf5d29990f636c3dc9c3 Mon Sep 17 00:00:00 2001 From: Sidney Cadot Date: Thu, 26 Dec 2024 22:48:42 +0100 Subject: [PATCH 12/38] Update src/sim65.vcxproj Co-authored-by: Matteo Pompili <6500688+matpompili@users.noreply.github.com> --- src/sim65.vcxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sim65.vcxproj b/src/sim65.vcxproj index b5b642d02..07a9f7fb5 100644 --- a/src/sim65.vcxproj +++ b/src/sim65.vcxproj @@ -94,7 +94,7 @@ - + From 9978600d28cc9e408ce0bf939cd8b45c5e1fcf6b Mon Sep 17 00:00:00 2001 From: sidney Date: Thu, 26 Dec 2024 22:55:32 +0100 Subject: [PATCH 13/38] Fixed erroneous ClInclude to ClCompile (thanks Matteo Pompili!) --- src/sim65.vcxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sim65.vcxproj b/src/sim65.vcxproj index b5b642d02..07a9f7fb5 100644 --- a/src/sim65.vcxproj +++ b/src/sim65.vcxproj @@ -94,7 +94,7 @@ - + From 61bedbdd55bcd8ede1b1488cba5cd4bd76e3d77b Mon Sep 17 00:00:00 2001 From: sidney Date: Thu, 26 Dec 2024 22:55:52 +0100 Subject: [PATCH 14/38] Added explicit cast to uint8_t, to make the Cisual Studio compiler happy. --- src/sim65/peripherals.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sim65/peripherals.c b/src/sim65/peripherals.c index 516a827b0..d48cf7137 100644 --- a/src/sim65/peripherals.c +++ b/src/sim65/peripherals.c @@ -137,7 +137,7 @@ uint8_t PeripheralsReadByte (uint8_t Addr) default: Value = 0; /* Reading from a non-existent latch register will yield 0. */ } /* Return the desired byte of the latched counter. 0==LSB, 7==MSB. */ - return Value >> (ByteIndex * 8); + return (uint8_t)(Value >> (ByteIndex * 8)); } /* Handle reads from unused peripheral and write-only addresses. */ From a90640230855b6f33057ae4a3ef7c3537cf9e597 Mon Sep 17 00:00:00 2001 From: sidney Date: Thu, 26 Dec 2024 23:15:41 +0100 Subject: [PATCH 15/38] Re-enabling the clock_gettime() code path. --- src/sim65/peripherals.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sim65/peripherals.c b/src/sim65/peripherals.c index d48cf7137..90156aa17 100644 --- a/src/sim65/peripherals.c +++ b/src/sim65/peripherals.c @@ -61,7 +61,8 @@ void PeripheralsWriteByte (uint8_t Addr, uint8_t Val) /* A write to the "latch" register performs a simultaneous latch of all registers. */ /* Latch the current wallclock time first. */ -#if 0 +#if 1 + /* Enabling clock_gettime dependent codepath (expected to fail at least on Windows build.) */ struct timespec ts; int result = clock_gettime(CLOCK_REALTIME, &ts); if (result != 0) { From 8c40568566a8a27987c6208f34c2bc6644d84793 Mon Sep 17 00:00:00 2001 From: sidney Date: Thu, 26 Dec 2024 23:32:00 +0100 Subject: [PATCH 16/38] Made wallclock time fail on Windows (due to lack of clock_gettime), succeed everywhere else. --- src/sim65/peripherals.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/sim65/peripherals.c b/src/sim65/peripherals.c index 90156aa17..ac11d7b73 100644 --- a/src/sim65/peripherals.c +++ b/src/sim65/peripherals.c @@ -58,28 +58,30 @@ void PeripheralsWriteByte (uint8_t Addr, uint8_t Val) /* Handle writes to the Counter peripheral. */ case PERIPHERALS_COUNTER_ADDRESS_OFFSET_LATCH: { + /* A write to the "latch" register performs a simultaneous latch of all registers. */ - /* Latch the current wallclock time first. */ -#if 1 - /* Enabling clock_gettime dependent codepath (expected to fail at least on Windows build.) */ + /* Latch the current wallclock time first (if possible). */ + +#if defined(_WIN32) + /* clock_gettime() is not available on Windows. Report max uint64 value for both fields. */ + Peripherals.Counter.LatchedWallclockTime = 0xffffffffffffffff; + Peripherals.Counter.LatchedWallclockTimeSplit = 0xffffffffffffffff; +#else + /* Other targets are presumed to have it. */ struct timespec ts; int result = clock_gettime(CLOCK_REALTIME, &ts); if (result != 0) { - /* Unable to read time. Report max uint64 value for both fields. */ + /* Unable to get time. Report max uint64 value for both fields. */ Peripherals.Counter.LatchedWallclockTime = 0xffffffffffffffff; Peripherals.Counter.LatchedWallclockTimeSplit = 0xffffffffffffffff; } else { /* Wallclock time: number of nanoseconds since 1-1-1970. */ - Peripherals.Counter.LatchedWallclockTime = 1000000000u * ts.tv_sec + ts.tv_nsec; + Peripherals.Counter.LatchedWallclockTime = 1000000000 * (uint64_t)ts.tv_sec + ts.tv_nsec; /* Wallclock time, split: high word is number of seconds since 1-1-1970, * low word is number of nanoseconds since the start of that second. */ - Peripherals.Counter.LatchedWallclockTimeSplit = (ts.tv_sec << 32) | ts.tv_nsec; + Peripherals.Counter.LatchedWallclockTimeSplit = ((uint64_t)ts.tv_sec << 32) | ts.tv_nsec; } -#else - /* Temporarily skip call to clock_gettime() to check that we can build for Windows */ - Peripherals.Counter.LatchedWallclockTime = 0xffffffffffffffff; - Peripherals.Counter.LatchedWallclockTimeSplit = 0xffffffffffffffff; #endif /* Latch the counters that reflect the state of the processor. */ From 1f9e731fc9b16869ff466c77dba7dd7e344b802a Mon Sep 17 00:00:00 2001 From: sidney Date: Thu, 26 Dec 2024 23:48:34 +0100 Subject: [PATCH 17/38] Try if gettimeofday() will work in Windows. --- src/sim65/peripherals.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/sim65/peripherals.c b/src/sim65/peripherals.c index ac11d7b73..143f72e76 100644 --- a/src/sim65/peripherals.c +++ b/src/sim65/peripherals.c @@ -29,6 +29,7 @@ /*****************************************************************************/ +#include #include #include "peripherals.h" @@ -65,8 +66,19 @@ void PeripheralsWriteByte (uint8_t Addr, uint8_t Val) #if defined(_WIN32) /* clock_gettime() is not available on Windows. Report max uint64 value for both fields. */ - Peripherals.Counter.LatchedWallclockTime = 0xffffffffffffffff; - Peripherals.Counter.LatchedWallclockTimeSplit = 0xffffffffffffffff; + struct timeval tv; + int result = gettimeofday(&tv, NULL); + if (result != 0) { + /* Unable to get time. Report max uint64 value for both fields. */ + Peripherals.Counter.LatchedWallclockTime = 0xffffffffffffffff; + Peripherals.Counter.LatchedWallclockTimeSplit = 0xffffffffffffffff; + } else { + /* Wallclock time: number of nanoseconds since 1-1-1970. */ + Peripherals.Counter.LatchedWallclockTime = 1000000000 * (uint64_t)ts.tv_sec + 1000 * ts.tv_usec; + /* Wallclock time, split: high word is number of seconds since 1-1-1970, + * low word is number of nanoseconds since the start of that second. */ + Peripherals.Counter.LatchedWallclockTimeSplit = ((uint64_t)ts.tv_sec << 32) | (1000 * ts.tv_usec); + } #else /* Other targets are presumed to have it. */ struct timespec ts; From ae3106af4aa84994f1021d841b4a52d35734edff Mon Sep 17 00:00:00 2001 From: sidney Date: Fri, 27 Dec 2024 00:04:06 +0100 Subject: [PATCH 18/38] Windows version now uses timespec_get() as a substitute for clock_gettime(). --- src/sim65/peripherals.c | 39 +++++++++++++-------------------------- 1 file changed, 13 insertions(+), 26 deletions(-) diff --git a/src/sim65/peripherals.c b/src/sim65/peripherals.c index 143f72e76..0ad11a5bf 100644 --- a/src/sim65/peripherals.c +++ b/src/sim65/peripherals.c @@ -28,8 +28,7 @@ /* */ /*****************************************************************************/ - -#include +#include #include #include "peripherals.h" @@ -64,37 +63,25 @@ void PeripheralsWriteByte (uint8_t Addr, uint8_t Val) /* Latch the current wallclock time first (if possible). */ -#if defined(_WIN32) - /* clock_gettime() is not available on Windows. Report max uint64 value for both fields. */ - struct timeval tv; - int result = gettimeofday(&tv, NULL); - if (result != 0) { - /* Unable to get time. Report max uint64 value for both fields. */ - Peripherals.Counter.LatchedWallclockTime = 0xffffffffffffffff; - Peripherals.Counter.LatchedWallclockTimeSplit = 0xffffffffffffffff; - } else { - /* Wallclock time: number of nanoseconds since 1-1-1970. */ - Peripherals.Counter.LatchedWallclockTime = 1000000000 * (uint64_t)ts.tv_sec + 1000 * ts.tv_usec; - /* Wallclock time, split: high word is number of seconds since 1-1-1970, - * low word is number of nanoseconds since the start of that second. */ - Peripherals.Counter.LatchedWallclockTimeSplit = ((uint64_t)ts.tv_sec << 32) | (1000 * ts.tv_usec); - } -#else - /* Other targets are presumed to have it. */ struct timespec ts; - int result = clock_gettime(CLOCK_REALTIME, &ts); - if (result != 0) { - /* Unable to get time. Report max uint64 value for both fields. */ - Peripherals.Counter.LatchedWallclockTime = 0xffffffffffffffff; - Peripherals.Counter.LatchedWallclockTimeSplit = 0xffffffffffffffff; - } else { + +#if defined(_WIN32) + /* clock_gettime() is not available on Windows. Use timespec_get() instead. */ + bool time_valid = timespec_get(&ts, TIME_UTC) == TIME_UTC; +#else + bool time_valid = clock_gettime(CLOCK_REALTIME, &ts) == 0; +#endif + if (time_valid) { /* Wallclock time: number of nanoseconds since 1-1-1970. */ Peripherals.Counter.LatchedWallclockTime = 1000000000 * (uint64_t)ts.tv_sec + ts.tv_nsec; /* Wallclock time, split: high word is number of seconds since 1-1-1970, * low word is number of nanoseconds since the start of that second. */ Peripherals.Counter.LatchedWallclockTimeSplit = ((uint64_t)ts.tv_sec << 32) | ts.tv_nsec; + } else { + /* Unable to get time. Report max uint64 value for both fields. */ + Peripherals.Counter.LatchedWallclockTime = 0xffffffffffffffff; + Peripherals.Counter.LatchedWallclockTimeSplit = 0xffffffffffffffff; } -#endif /* Latch the counters that reflect the state of the processor. */ Peripherals.Counter.LatchedClockCycles = Peripherals.Counter.ClockCycles; From db0b8c2d2c9fcd1544b93822a676da9a0e252b8a Mon Sep 17 00:00:00 2001 From: sidney Date: Fri, 27 Dec 2024 00:21:50 +0100 Subject: [PATCH 19/38] Check if we have it working now on the MinGW32 and 64 compilers. --- src/sim65/peripherals.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sim65/peripherals.c b/src/sim65/peripherals.c index 0ad11a5bf..81d397c2f 100644 --- a/src/sim65/peripherals.c +++ b/src/sim65/peripherals.c @@ -65,10 +65,11 @@ void PeripheralsWriteByte (uint8_t Addr, uint8_t Val) struct timespec ts; -#if defined(_WIN32) - /* clock_gettime() is not available on Windows. Use timespec_get() instead. */ +#if defined(_MSC_VER) + /* clock_gettime() is not available in the Visual Studio compiler. Use timespec_get() instead. */ bool time_valid = timespec_get(&ts, TIME_UTC) == TIME_UTC; #else + /* clock_gettime() is available on Linux, MacOS, MinGW32, and MinGW64. bool time_valid = clock_gettime(CLOCK_REALTIME, &ts) == 0; #endif if (time_valid) { From f3e8f36f00b1f3363386b5033b28d3eba5c69a91 Mon Sep 17 00:00:00 2001 From: sidney Date: Fri, 27 Dec 2024 00:28:19 +0100 Subject: [PATCH 20/38] Corrected typo. --- src/sim65/peripherals.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sim65/peripherals.c b/src/sim65/peripherals.c index 81d397c2f..22c0b8232 100644 --- a/src/sim65/peripherals.c +++ b/src/sim65/peripherals.c @@ -69,7 +69,7 @@ void PeripheralsWriteByte (uint8_t Addr, uint8_t Val) /* clock_gettime() is not available in the Visual Studio compiler. Use timespec_get() instead. */ bool time_valid = timespec_get(&ts, TIME_UTC) == TIME_UTC; #else - /* clock_gettime() is available on Linux, MacOS, MinGW32, and MinGW64. + /* clock_gettime() is available on Linux, MacOS, MinGW32, and MinGW64. */ bool time_valid = clock_gettime(CLOCK_REALTIME, &ts) == 0; #endif if (time_valid) { From 328006e5000a3835e7bc35e1d988d81fff89a9c7 Mon Sep 17 00:00:00 2001 From: sidney Date: Fri, 27 Dec 2024 00:42:29 +0100 Subject: [PATCH 21/38] Split out cases for MINGW32 and MINGW64 --- src/sim65/peripherals.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/sim65/peripherals.c b/src/sim65/peripherals.c index 22c0b8232..1606c19b9 100644 --- a/src/sim65/peripherals.c +++ b/src/sim65/peripherals.c @@ -65,7 +65,11 @@ void PeripheralsWriteByte (uint8_t Addr, uint8_t Val) struct timespec ts; -#if defined(_MSC_VER) +#if defined(__MINGW64__) + bool time_valid = false; +#elif defined(__MINGW32__) + bool time_valid = false; +#elif defined(_MSC_VER) /* clock_gettime() is not available in the Visual Studio compiler. Use timespec_get() instead. */ bool time_valid = timespec_get(&ts, TIME_UTC) == TIME_UTC; #else From 65d20eaab426f5120c59f1f0c109daaeca250920 Mon Sep 17 00:00:00 2001 From: sidney Date: Fri, 27 Dec 2024 00:55:13 +0100 Subject: [PATCH 22/38] Enable timespec_get in MINGW64 code path to see if that works. --- src/sim65/peripherals.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/sim65/peripherals.c b/src/sim65/peripherals.c index 1606c19b9..c7b465872 100644 --- a/src/sim65/peripherals.c +++ b/src/sim65/peripherals.c @@ -61,19 +61,25 @@ void PeripheralsWriteByte (uint8_t Addr, uint8_t Val) /* A write to the "latch" register performs a simultaneous latch of all registers. */ - /* Latch the current wallclock time first (if possible). */ + /* Latch the current wallclock time before doing anything else. */ - struct timespec ts; + struct timespec ts; /* Available on all compilers we use. */ #if defined(__MINGW64__) + /* We check for MINGW64 before MINGW32, since MINGW64 also defines __MINGW32__. */ + /* does timespec_get work? */ + bool time_valid = timespec_get(&ts, TIME_UTC) == TIME_UTC; + /* does clock_gettime work? */ bool time_valid = false; #elif defined(__MINGW32__) + /* does timespec_get work? */ + /* does clock_gettime work? */ bool time_valid = false; #elif defined(_MSC_VER) - /* clock_gettime() is not available in the Visual Studio compiler. Use timespec_get() instead. */ + /* clock_gettime() is not available when using the Microsoft compiler. Use timespec_get() instead. */ bool time_valid = timespec_get(&ts, TIME_UTC) == TIME_UTC; #else - /* clock_gettime() is available on Linux, MacOS, MinGW32, and MinGW64. */ + /* clock_gettime() is available on Linux and MacOS. */ bool time_valid = clock_gettime(CLOCK_REALTIME, &ts) == 0; #endif if (time_valid) { From 74f12b449888de87396e2f456ce68cca7edca296 Mon Sep 17 00:00:00 2001 From: sidney Date: Fri, 27 Dec 2024 01:12:04 +0100 Subject: [PATCH 23/38] Enable timespec_get in MINGW64 code path to see if that works (2). --- src/sim65/peripherals.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sim65/peripherals.c b/src/sim65/peripherals.c index c7b465872..7d0df91bc 100644 --- a/src/sim65/peripherals.c +++ b/src/sim65/peripherals.c @@ -67,10 +67,10 @@ void PeripheralsWriteByte (uint8_t Addr, uint8_t Val) #if defined(__MINGW64__) /* We check for MINGW64 before MINGW32, since MINGW64 also defines __MINGW32__. */ - /* does timespec_get work? */ + /* Using timespec_get() in the MinGW64 compiler makes the Linux workflow build fail. */ bool time_valid = timespec_get(&ts, TIME_UTC) == TIME_UTC; /* does clock_gettime work? */ - bool time_valid = false; + //bool time_valid = false; #elif defined(__MINGW32__) /* does timespec_get work? */ /* does clock_gettime work? */ From 2743644b02fb106beeafcb3bc8cb4ccda1cf75b8 Mon Sep 17 00:00:00 2001 From: sidney Date: Fri, 27 Dec 2024 01:24:44 +0100 Subject: [PATCH 24/38] Enable timespec_get in MINGW64 code path to see if that works (3). --- src/sim65/peripherals.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sim65/peripherals.c b/src/sim65/peripherals.c index 7d0df91bc..c5c42b87e 100644 --- a/src/sim65/peripherals.c +++ b/src/sim65/peripherals.c @@ -68,13 +68,14 @@ void PeripheralsWriteByte (uint8_t Addr, uint8_t Val) #if defined(__MINGW64__) /* We check for MINGW64 before MINGW32, since MINGW64 also defines __MINGW32__. */ /* Using timespec_get() in the MinGW64 compiler makes the Linux workflow build fail. */ - bool time_valid = timespec_get(&ts, TIME_UTC) == TIME_UTC; + //bool time_valid = timespec_get(&ts, TIME_UTC) == TIME_UTC; /* does clock_gettime work? */ - //bool time_valid = false; + bool time_valid = false; #elif defined(__MINGW32__) /* does timespec_get work? */ /* does clock_gettime work? */ - bool time_valid = false; + //bool time_valid = false; + bool time_valid = timespec_get(&ts, TIME_UTC) == TIME_UTC; #elif defined(_MSC_VER) /* clock_gettime() is not available when using the Microsoft compiler. Use timespec_get() instead. */ bool time_valid = timespec_get(&ts, TIME_UTC) == TIME_UTC; From a94b389965d0c0392aa0f22a6717b6fad2f2e6e3 Mon Sep 17 00:00:00 2001 From: sidney Date: Fri, 27 Dec 2024 01:39:18 +0100 Subject: [PATCH 25/38] Enable timespec_get in MINGW64 code path to see if that works (4). --- src/sim65/peripherals.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/sim65/peripherals.c b/src/sim65/peripherals.c index c5c42b87e..1c62b2bfb 100644 --- a/src/sim65/peripherals.c +++ b/src/sim65/peripherals.c @@ -70,12 +70,13 @@ void PeripheralsWriteByte (uint8_t Addr, uint8_t Val) /* Using timespec_get() in the MinGW64 compiler makes the Linux workflow build fail. */ //bool time_valid = timespec_get(&ts, TIME_UTC) == TIME_UTC; /* does clock_gettime work? */ - bool time_valid = false; -#elif defined(__MINGW32__) - /* does timespec_get work? */ - /* does clock_gettime work? */ + bool time_valid = clock_gettime(CLOCK_REALTIME, &ts) == 0; //bool time_valid = false; - bool time_valid = timespec_get(&ts, TIME_UTC) == TIME_UTC; +#elif defined(__MINGW32__) + /* does timespec_get work? -- yes! */ + /* does clock_gettime work? */ + bool time_valid = false; + //bool time_valid = timespec_get(&ts, TIME_UTC) == TIME_UTC; #elif defined(_MSC_VER) /* clock_gettime() is not available when using the Microsoft compiler. Use timespec_get() instead. */ bool time_valid = timespec_get(&ts, TIME_UTC) == TIME_UTC; From 083c968885cad634df04a7f4b739241cc6078995 Mon Sep 17 00:00:00 2001 From: sidney Date: Fri, 27 Dec 2024 01:53:16 +0100 Subject: [PATCH 26/38] Enable timespec_get in MINGW64 code path to see if that works (5). --- src/sim65/peripherals.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/sim65/peripherals.c b/src/sim65/peripherals.c index 1c62b2bfb..ea402ccb6 100644 --- a/src/sim65/peripherals.c +++ b/src/sim65/peripherals.c @@ -68,14 +68,13 @@ void PeripheralsWriteByte (uint8_t Addr, uint8_t Val) #if defined(__MINGW64__) /* We check for MINGW64 before MINGW32, since MINGW64 also defines __MINGW32__. */ /* Using timespec_get() in the MinGW64 compiler makes the Linux workflow build fail. */ - //bool time_valid = timespec_get(&ts, TIME_UTC) == TIME_UTC; - /* does clock_gettime work? */ - bool time_valid = clock_gettime(CLOCK_REALTIME, &ts) == 0; - //bool time_valid = false; + /* Using clock_gettime() in the MinGW64 compiler makes the Linux workflow build fail. */ + bool time_valid = false; #elif defined(__MINGW32__) /* does timespec_get work? -- yes! */ /* does clock_gettime work? */ - bool time_valid = false; + //bool time_valid = false; + bool time_valid = clock_gettime(CLOCK_REALTIME, &ts) == 0; //bool time_valid = timespec_get(&ts, TIME_UTC) == TIME_UTC; #elif defined(_MSC_VER) /* clock_gettime() is not available when using the Microsoft compiler. Use timespec_get() instead. */ From 6ccde66c863c0cad8593c0344567c95e55285219 Mon Sep 17 00:00:00 2001 From: sidney Date: Fri, 27 Dec 2024 02:06:15 +0100 Subject: [PATCH 27/38] Enable timespec_get in MINGW64 code path to see if that works (6). --- src/sim65/peripherals.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sim65/peripherals.c b/src/sim65/peripherals.c index ea402ccb6..20393cc1d 100644 --- a/src/sim65/peripherals.c +++ b/src/sim65/peripherals.c @@ -72,9 +72,10 @@ void PeripheralsWriteByte (uint8_t Addr, uint8_t Val) bool time_valid = false; #elif defined(__MINGW32__) /* does timespec_get work? -- yes! */ - /* does clock_gettime work? */ + /* does clock_gettime work? -- yes! */ //bool time_valid = false; - bool time_valid = clock_gettime(CLOCK_REALTIME, &ts) == 0; + //bool time_valid = clock_gettime(CLOCK_REALTIME, &ts) == 0; + #error "MinGW32 compiler was used; we're not handling it." //bool time_valid = timespec_get(&ts, TIME_UTC) == TIME_UTC; #elif defined(_MSC_VER) /* clock_gettime() is not available when using the Microsoft compiler. Use timespec_get() instead. */ From c735a83a98bd8577539e8ec4c57be174f953ec00 Mon Sep 17 00:00:00 2001 From: sidney Date: Fri, 27 Dec 2024 02:19:36 +0100 Subject: [PATCH 28/38] Enable timespec_get in MINGW64 code path to see if that works (7). --- src/sim65/peripherals.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/sim65/peripherals.c b/src/sim65/peripherals.c index 20393cc1d..012af3d30 100644 --- a/src/sim65/peripherals.c +++ b/src/sim65/peripherals.c @@ -32,6 +32,10 @@ #include #include "peripherals.h" +#if defined(__MINGW64__) +/* For gettimeofday() */ +#include +#endif /*****************************************************************************/ /* Data */ @@ -66,17 +70,18 @@ void PeripheralsWriteByte (uint8_t Addr, uint8_t Val) struct timespec ts; /* Available on all compilers we use. */ #if defined(__MINGW64__) - /* We check for MINGW64 before MINGW32, since MINGW64 also defines __MINGW32__. */ + /* Note: we check for MINGW64 before MINGW32, since MINGW64 also defines __MINGW32__. */ /* Using timespec_get() in the MinGW64 compiler makes the Linux workflow build fail. */ /* Using clock_gettime() in the MinGW64 compiler makes the Linux workflow build fail. */ - bool time_valid = false; + struct timeval tv; + bool time_valid = (gettimeofday(&tv, NULL) == 0); + if (time_valid) + { + ts.tv_sec = tv.tv_sec; + ts.tv_nsec = tv.tv_usec * 1000; + } #elif defined(__MINGW32__) - /* does timespec_get work? -- yes! */ - /* does clock_gettime work? -- yes! */ - //bool time_valid = false; - //bool time_valid = clock_gettime(CLOCK_REALTIME, &ts) == 0; - #error "MinGW32 compiler was used; we're not handling it." - //bool time_valid = timespec_get(&ts, TIME_UTC) == TIME_UTC; + #error "MinGW32 compiler detected, but we're not handling it." #elif defined(_MSC_VER) /* clock_gettime() is not available when using the Microsoft compiler. Use timespec_get() instead. */ bool time_valid = timespec_get(&ts, TIME_UTC) == TIME_UTC; From 58b8c147386093026bd7130401937d17150437e1 Mon Sep 17 00:00:00 2001 From: sidney Date: Fri, 27 Dec 2024 08:57:58 +0100 Subject: [PATCH 29/38] Split off the compiler-depended wallclock time function in a separate function. --- src/sim65/peripherals.c | 61 +++++++++++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 21 deletions(-) diff --git a/src/sim65/peripherals.c b/src/sim65/peripherals.c index 012af3d30..e155ba04c 100644 --- a/src/sim65/peripherals.c +++ b/src/sim65/peripherals.c @@ -52,6 +52,44 @@ Sim65Peripherals Peripherals; /* Code */ /*****************************************************************************/ +static bool GetWallclockTime (struct timespec * ts) +{ + /* Note: the 'struct timespec' type is supported on all compilers we want to support. */ + +#if defined(__MINGW64__) + /* This check comes before the check on symbol __MINGW32__, as MinGW64 defines both. + * + * When using the MinGW64 compiler, neither timespec_get() nor clock_gettime() + * are available; this makes the Linux workflow build fail. + * The gettimeofday() function works, so use that. + */ + struct timeval tv; + bool time_valid = (gettimeofday(&tv, NULL) == 0); + if (time_valid) + { + ts->tv_sec = tv.tv_sec; + ts->tv_nsec = tv.tv_usec * 1000; + } +#elif defined(__MINGW32__) + /* The MinGW32 compiler is not used in the build process. + * Support can be added when the need arises. + */ +#error "The MinGW32 compiler is not supported." +#elif defined(_MSC_VER) + /* Using the Microsoft C++ compiler. + * clock_gettime() is not available; use timespec_get() instead. + */ + bool time_valid = timespec_get(ts, TIME_UTC) == TIME_UTC; +#else + /* Other platforms (Linux, MacOS, ...): assume that clock_gettime() + * is available. + */ + bool time_valid = clock_gettime(CLOCK_REALTIME, ts) == 0; +#endif + + return time_valid; +} + void PeripheralsWriteByte (uint8_t Addr, uint8_t Val) @@ -67,28 +105,9 @@ void PeripheralsWriteByte (uint8_t Addr, uint8_t Val) /* Latch the current wallclock time before doing anything else. */ - struct timespec ts; /* Available on all compilers we use. */ + struct timespec ts; /* The type is available on all compilers we use. */ + bool time_valid = GetWallclockTime (&ts); -#if defined(__MINGW64__) - /* Note: we check for MINGW64 before MINGW32, since MINGW64 also defines __MINGW32__. */ - /* Using timespec_get() in the MinGW64 compiler makes the Linux workflow build fail. */ - /* Using clock_gettime() in the MinGW64 compiler makes the Linux workflow build fail. */ - struct timeval tv; - bool time_valid = (gettimeofday(&tv, NULL) == 0); - if (time_valid) - { - ts.tv_sec = tv.tv_sec; - ts.tv_nsec = tv.tv_usec * 1000; - } -#elif defined(__MINGW32__) - #error "MinGW32 compiler detected, but we're not handling it." -#elif defined(_MSC_VER) - /* clock_gettime() is not available when using the Microsoft compiler. Use timespec_get() instead. */ - bool time_valid = timespec_get(&ts, TIME_UTC) == TIME_UTC; -#else - /* clock_gettime() is available on Linux and MacOS. */ - bool time_valid = clock_gettime(CLOCK_REALTIME, &ts) == 0; -#endif if (time_valid) { /* Wallclock time: number of nanoseconds since 1-1-1970. */ Peripherals.Counter.LatchedWallclockTime = 1000000000 * (uint64_t)ts.tv_sec + ts.tv_nsec; From e785b88d425cd4ad741d9b7f018a4a9615625ef8 Mon Sep 17 00:00:00 2001 From: sidney Date: Fri, 27 Dec 2024 09:21:04 +0100 Subject: [PATCH 30/38] Cleaning up the GetWallclockTime function. --- src/sim65/peripherals.c | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/src/sim65/peripherals.c b/src/sim65/peripherals.c index e155ba04c..bd00c5b3a 100644 --- a/src/sim65/peripherals.c +++ b/src/sim65/peripherals.c @@ -53,38 +53,34 @@ Sim65Peripherals Peripherals; /*****************************************************************************/ static bool GetWallclockTime (struct timespec * ts) +/* Get the wallclock time with nanosecond resolution. */ { - /* Note: the 'struct timespec' type is supported on all compilers we want to support. */ + /* Note: the 'struct timespec' type is available on all compilers we want to support. */ + + bool time_valid; #if defined(__MINGW64__) - /* This check comes before the check on symbol __MINGW32__, as MinGW64 defines both. - * - * When using the MinGW64 compiler, neither timespec_get() nor clock_gettime() - * are available; this makes the Linux workflow build fail. - * The gettimeofday() function works, so use that. + /* When using the MinGW64 compiler, neither timespec_get() nor clock_gettime() + * are available; using either of them makes the Linux workflow build fail. + * The gettimeofday() function does work, so use that; its microsecond resulution + * is plenty for most applications. */ struct timeval tv; - bool time_valid = (gettimeofday(&tv, NULL) == 0); + time_valid = (gettimeofday(&tv, NULL) == 0); if (time_valid) { ts->tv_sec = tv.tv_sec; ts->tv_nsec = tv.tv_usec * 1000; } -#elif defined(__MINGW32__) - /* The MinGW32 compiler is not used in the build process. - * Support can be added when the need arises. - */ -#error "The MinGW32 compiler is not supported." #elif defined(_MSC_VER) /* Using the Microsoft C++ compiler. * clock_gettime() is not available; use timespec_get() instead. */ - bool time_valid = timespec_get(ts, TIME_UTC) == TIME_UTC; + time_valid = timespec_get(ts, TIME_UTC) == TIME_UTC; #else - /* Other platforms (Linux, MacOS, ...): assume that clock_gettime() - * is available. + /* On all other compilers, assume that the clock_gettime() function is available. */ - bool time_valid = clock_gettime(CLOCK_REALTIME, ts) == 0; + time_valid = clock_gettime(CLOCK_REALTIME, ts) == 0; #endif return time_valid; From 29063021a815a05dca3a0cff9ea057504aae217b Mon Sep 17 00:00:00 2001 From: sidney Date: Sat, 28 Dec 2024 06:49:23 +0100 Subject: [PATCH 31/38] Cosmetic improvements. --- src/sim65/peripherals.c | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/sim65/peripherals.c b/src/sim65/peripherals.c index bd00c5b3a..713b8173c 100644 --- a/src/sim65/peripherals.c +++ b/src/sim65/peripherals.c @@ -2,7 +2,7 @@ /* */ /* peripherals.c */ /* */ -/* Memory-mapped peripheral subsystem for the 6502 simulator */ +/* Memory-mapped peripheral subsystem for the 6502 simulator */ /* */ /* */ /* */ @@ -30,13 +30,15 @@ #include #include -#include "peripherals.h" - #if defined(__MINGW64__) /* For gettimeofday() */ #include #endif + +#include "peripherals.h" + + /*****************************************************************************/ /* Data */ /*****************************************************************************/ @@ -62,13 +64,12 @@ static bool GetWallclockTime (struct timespec * ts) #if defined(__MINGW64__) /* When using the MinGW64 compiler, neither timespec_get() nor clock_gettime() * are available; using either of them makes the Linux workflow build fail. - * The gettimeofday() function does work, so use that; its microsecond resulution - * is plenty for most applications. + * The gettimeofday() function does work, so use that; its microsecond resolution + * is fine for most applications. */ struct timeval tv; time_valid = (gettimeofday(&tv, NULL) == 0); - if (time_valid) - { + if (time_valid) { ts->tv_sec = tv.tv_sec; ts->tv_nsec = tv.tv_usec * 1000; } @@ -78,7 +79,8 @@ static bool GetWallclockTime (struct timespec * ts) */ time_valid = timespec_get(ts, TIME_UTC) == TIME_UTC; #else - /* On all other compilers, assume that the clock_gettime() function is available. + /* On all other compilers, assume that clock_gettime() is available. + * This is true on Linux and MacOS, at least. */ time_valid = clock_gettime(CLOCK_REALTIME, ts) == 0; #endif @@ -101,7 +103,7 @@ void PeripheralsWriteByte (uint8_t Addr, uint8_t Val) /* Latch the current wallclock time before doing anything else. */ - struct timespec ts; /* The type is available on all compilers we use. */ + struct timespec ts; bool time_valid = GetWallclockTime (&ts); if (time_valid) { @@ -109,11 +111,11 @@ void PeripheralsWriteByte (uint8_t Addr, uint8_t Val) Peripherals.Counter.LatchedWallclockTime = 1000000000 * (uint64_t)ts.tv_sec + ts.tv_nsec; /* Wallclock time, split: high word is number of seconds since 1-1-1970, * low word is number of nanoseconds since the start of that second. */ - Peripherals.Counter.LatchedWallclockTimeSplit = ((uint64_t)ts.tv_sec << 32) | ts.tv_nsec; + Peripherals.Counter.LatchedWallclockTimeSplit = (uint64_t)ts.tv_sec << 32 | ts.tv_nsec; } else { /* Unable to get time. Report max uint64 value for both fields. */ - Peripherals.Counter.LatchedWallclockTime = 0xffffffffffffffff; - Peripherals.Counter.LatchedWallclockTimeSplit = 0xffffffffffffffff; + Peripherals.Counter.LatchedWallclockTime = -1; + Peripherals.Counter.LatchedWallclockTimeSplit = -1; } /* Latch the counters that reflect the state of the processor. */ @@ -160,8 +162,9 @@ uint8_t PeripheralsReadByte (uint8_t Addr) /* Read from any of the eight counter bytes. * The first byte is the 64 bit value's LSB, the seventh byte is its MSB. */ - unsigned ByteIndex = Addr - PERIPHERALS_COUNTER_ADDRESS_OFFSET_VALUE; /* 0 .. 7 */ + unsigned SelectedByteIndex = Addr - PERIPHERALS_COUNTER_ADDRESS_OFFSET_VALUE; /* 0 .. 7 */ uint64_t Value; + uint8_t SelectedByteValue; switch (Peripherals.Counter.LatchedValueSelected) { case PERIPHERALS_COUNTER_SELECT_CLOCKCYCLE_COUNTER: Value = Peripherals.Counter.LatchedClockCycles; break; case PERIPHERALS_COUNTER_SELECT_INSTRUCTION_COUNTER: Value = Peripherals.Counter.LatchedCpuInstructions; break; @@ -172,7 +175,8 @@ uint8_t PeripheralsReadByte (uint8_t Addr) default: Value = 0; /* Reading from a non-existent latch register will yield 0. */ } /* Return the desired byte of the latched counter. 0==LSB, 7==MSB. */ - return (uint8_t)(Value >> (ByteIndex * 8)); + SelectedByteValue = Value >> (SelectedByteIndex * 8); + return SelectedByteValue; } /* Handle reads from unused peripheral and write-only addresses. */ From 7576f59e6aa67e5993c737da966267b27493e45e Mon Sep 17 00:00:00 2001 From: sidney Date: Sat, 28 Dec 2024 06:57:37 +0100 Subject: [PATCH 32/38] Visual Studio compiler demands an explicit cast from uint64_t to uint8_t. --- src/sim65/peripherals.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/sim65/peripherals.c b/src/sim65/peripherals.c index 713b8173c..4fa512ed8 100644 --- a/src/sim65/peripherals.c +++ b/src/sim65/peripherals.c @@ -164,7 +164,6 @@ uint8_t PeripheralsReadByte (uint8_t Addr) */ unsigned SelectedByteIndex = Addr - PERIPHERALS_COUNTER_ADDRESS_OFFSET_VALUE; /* 0 .. 7 */ uint64_t Value; - uint8_t SelectedByteValue; switch (Peripherals.Counter.LatchedValueSelected) { case PERIPHERALS_COUNTER_SELECT_CLOCKCYCLE_COUNTER: Value = Peripherals.Counter.LatchedClockCycles; break; case PERIPHERALS_COUNTER_SELECT_INSTRUCTION_COUNTER: Value = Peripherals.Counter.LatchedCpuInstructions; break; @@ -174,9 +173,8 @@ uint8_t PeripheralsReadByte (uint8_t Addr) case PERIPHERALS_COUNTER_SELECT_WALLCLOCK_TIME_SPLIT: Value = Peripherals.Counter.LatchedWallclockTimeSplit; break; default: Value = 0; /* Reading from a non-existent latch register will yield 0. */ } - /* Return the desired byte of the latched counter. 0==LSB, 7==MSB. */ - SelectedByteValue = Value >> (SelectedByteIndex * 8); - return SelectedByteValue; + /* Return the desired byte of the latched counter; 0==LSB, 7==MSB. */ + return (uint8_t)(Value >> (SelectedByteIndex * 8)); } /* Handle reads from unused peripheral and write-only addresses. */ From e37a2b1559570d567e35ae55928280b09b3655d1 Mon Sep 17 00:00:00 2001 From: sidney Date: Tue, 31 Dec 2024 13:35:16 +0100 Subject: [PATCH 33/38] Updated documentation with counter documentation. --- doc/sim65.sgml | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/doc/sim65.sgml b/doc/sim65.sgml index 962f07254..9c54c71f3 100644 --- a/doc/sim65.sgml +++ b/doc/sim65.sgml @@ -151,6 +151,71 @@ int main() // sim65 example.prg +Counter peripheral

+ +The sim65 simulator supports a memory-mapped counter peripheral that manages +a number of 64-bit counters that are continuously updated as the simulator is +running. For each counter, it also provides a 64 bit "latching" register. + +The functionality of the counter peripheral is accessible through 3 registers: + +* PERIPHERALS_COUNTER_LATCH ($FFC0, write-only) +* PERIPHERALS_COUNTER_SELECT ($FFC1, read/write) +* PERIPHERALS_COUNTER_VALUE ($FFC2..$FFC9, read-only) + +These three registers are used as follows. + +When a program explicitly requests a "counter latch" operation by writing any value +to the PERIPHERALS_COUNTER_LATCH address ($FFC0), all live registers are copied to +the latch registers. They will keep the latched value until another latch operation +updates them. + +The PERIPHERALS_COUNTER_SELECT address ($FFC1) register holds an 8-bit value that +specifies which 64-bit value is currently readable through the PERIPHERALS_COUNTER_VALUE +address range. Possible values are: + +$00: latched clock cycle counter selected. +$01: latched CPU instruction counter selected. +$02: latched IRQ interrupt counter selected. +$03: latched NMI interrupt counter selected. + +In addition to these counters, two other latch registers are available that are also +updated when the PERIPHERALS_COUNTER_LATCH address is written: + +$80: latched wallclock time (nanoseconds) selected. +$81: latched wallclock time (split s/ns) selected. + +When PERIPHERALS_COUNTER_LATCH equals $80, the PERIPHERALS_COUNTER_VALUE will be a +64-bit value corresponding to the number of nanoseconds elapsed since Midnight, Jan 1st, +1970 UTC. + +When PERIPHERALS_COUNTER_LATCH equals $81, the high 32 bits of PERIPHERALS_COUNTER_VALUE +will be a 32-bit value corresponding to the number of seconds elapsed since Midnight, +Jan 1st, 1970 UTC. The low 32 bits of PERIPHERALS_COUNTER_VALUE will hold the +nanoseconds since the start of that seconds. + +The two different wallclock-time latch registers are provided for different applications. +For some applications, the single 64-bit value will be more convenient, while for other +applications, the split 32/32 bits representations with separate seconds and nanoseconds +is more convenient. + +Note that the definition above given as "time since Midnight, Jan 1st, 1970 UTC" is an +approximation, as the implementation depends on the POSIX definition of time which does +not account for leap seconds. + +If the PERIPHERALS_COUNTER_SELECT register holds a value other than one of the six values +described above, all PERIPHERALS_COUNTER_VALUE bytes will read as zero. + +On reset, PERIPHERALS_COUNTER_SELECT is initialized to zero. + +The PERIPHERALS_COUNTER_VALUE addresses ($FFC2..$FFC9) are used to read to currently +selected latch register value. Address $FFF2 holds the least significant byte (LSB), +while address $FFC9 holds the most significant byte (MSB). + +On reset, all latch registers are reset to zero. this means that reading any of the +PERIPHERALS_COUNTER_VALUE bytes before a write to PERIPHERALS_COUNTER_LATCH will +yield zero. + Creating a Test in Assembly

Though a C test may also link with assembly code, From f95a60d5ad7249e0f40e41356595b6839a56d418 Mon Sep 17 00:00:00 2001 From: sidney Date: Tue, 31 Dec 2024 13:48:45 +0100 Subject: [PATCH 34/38] Updating sim65 docs. --- doc/sim65.sgml | 71 ++++++++++++++++++++++++++------------------------ 1 file changed, 37 insertions(+), 34 deletions(-) diff --git a/doc/sim65.sgml b/doc/sim65.sgml index 9c54c71f3..7d54b87b9 100644 --- a/doc/sim65.sgml +++ b/doc/sim65.sgml @@ -151,70 +151,73 @@ int main() // sim65 example.prg -Counter peripheral

+Counter peripheral -The sim65 simulator supports a memory-mapped counter peripheral that manages +

The sim65 simulator supports a memory-mapped counter peripheral that manages a number of 64-bit counters that are continuously updated as the simulator is running. For each counter, it also provides a 64 bit "latching" register. -The functionality of the counter peripheral is accessible through 3 registers: +

The functionality of the counter peripheral is accessible through 3 registers: -* PERIPHERALS_COUNTER_LATCH ($FFC0, write-only) -* PERIPHERALS_COUNTER_SELECT ($FFC1, read/write) -* PERIPHERALS_COUNTER_VALUE ($FFC2..$FFC9, read-only) + +PERIPHERALS_COUNTER_LATCH ($FFC0, write-only) +PERIPHERALS_COUNTER_SELECT ($FFC1, read/write) +PERIPHERALS_COUNTER_VALUE ($FFC2..$FFC9, read-only) + -These three registers are used as follows. +

These three registers are used as follows. -When a program explicitly requests a "counter latch" operation by writing any value -to the PERIPHERALS_COUNTER_LATCH address ($FFC0), all live registers are copied to +

When a program explicitly requests a "counter latch" operation by writing any value +to the PERIPHERALS_COUNTER_LATCH address ($FFC0), all live registers are copied to the latch registers. They will keep the latched value until another latch operation updates them. -The PERIPHERALS_COUNTER_SELECT address ($FFC1) register holds an 8-bit value that -specifies which 64-bit value is currently readable through the PERIPHERALS_COUNTER_VALUE -address range. Possible values are: +

The PERIPHERALS_COUNTER_SELECT address ($FFC1) register holds an 8-bit value that +specifies which 64-bit value is currently readable through the PERIPHERALS_COUNTER_VALUE +address range. Six values are currently defined: -$00: latched clock cycle counter selected. -$01: latched CPU instruction counter selected. -$02: latched IRQ interrupt counter selected. -$03: latched NMI interrupt counter selected. + +$00: latched clock cycle counter selected. +$01: latched CPU instruction counter selected. +$02: latched IRQ interrupt counter selected. +$03: latched NMI interrupt counter selected. +$80: latched wallclock time (nanoseconds) selected. +$81: latched wallclock time (split s/ns) selected. + -In addition to these counters, two other latch registers are available that are also -updated when the PERIPHERALS_COUNTER_LATCH address is written: +

Values $00 to $03 provide access to the latched (frozen) value of their respective live +counters at the time of the last write to PERIPHERALS_COUNTER_LATCH . -$80: latched wallclock time (nanoseconds) selected. -$81: latched wallclock time (split s/ns) selected. - -When PERIPHERALS_COUNTER_LATCH equals $80, the PERIPHERALS_COUNTER_VALUE will be a -64-bit value corresponding to the number of nanoseconds elapsed since Midnight, Jan 1st, +

When PERIPHERALS_COUNTER_LATCH equals $80, the PERIPHERALS_COUNTER_VALUE +will be a 64-bit value corresponding to the number of nanoseconds elapsed since Midnight, Jan 1st, 1970 UTC. -When PERIPHERALS_COUNTER_LATCH equals $81, the high 32 bits of PERIPHERALS_COUNTER_VALUE +

When PERIPHERALS_COUNTER_LATCH equals $81, the high 32 bits of PERIPHERALS_COUNTER_VALUE will be a 32-bit value corresponding to the number of seconds elapsed since Midnight, -Jan 1st, 1970 UTC. The low 32 bits of PERIPHERALS_COUNTER_VALUE will hold the +Jan 1st, 1970 UTC. The low 32 bits of PERIPHERALS_COUNTER_VALUE will hold the nanoseconds since the start of that seconds. -The two different wallclock-time latch registers are provided for different applications. +

The two different wallclock-time latch registers are provided for different applications. For some applications, the single 64-bit value will be more convenient, while for other applications, the split 32/32 bits representations with separate seconds and nanoseconds is more convenient. -Note that the definition above given as "time since Midnight, Jan 1st, 1970 UTC" is an +

Note that the definition above given as time since Midnight, Jan 1st, 1970 UTC is an approximation, as the implementation depends on the POSIX definition of time which does not account for leap seconds. -If the PERIPHERALS_COUNTER_SELECT register holds a value other than one of the six values -described above, all PERIPHERALS_COUNTER_VALUE bytes will read as zero. +

If the PERIPHERALS_COUNTER_SELECT register holds a value other than one of the six +values described above, all PERIPHERALS_COUNTER_VALUE bytes will read as zero. -On reset, PERIPHERALS_COUNTER_SELECT is initialized to zero. +

On reset, PERIPHERALS_COUNTER_SELECT is initialized to zero. -The PERIPHERALS_COUNTER_VALUE addresses ($FFC2..$FFC9) are used to read to currently +

The PERIPHERALS_COUNTER_VALUE addresses ($FFC2..$FFC9) are used to read to currently selected latch register value. Address $FFF2 holds the least significant byte (LSB), while address $FFC9 holds the most significant byte (MSB). -On reset, all latch registers are reset to zero. this means that reading any of the -PERIPHERALS_COUNTER_VALUE bytes before a write to PERIPHERALS_COUNTER_LATCH will -yield zero. +

On reset, all latch registers are reset to zero. this means that reading any of the +PERIPHERALS_COUNTER_VALUE bytes before a write to PERIPHERALS_COUNTER_LATCH +will yield zero. Creating a Test in Assembly

From d8df73c36d6dfab9033cb24c4e206cb468d1fafd Mon Sep 17 00:00:00 2001 From: sidney Date: Tue, 31 Dec 2024 17:54:58 +0100 Subject: [PATCH 35/38] Improved counter peripheral documentation, and moved its documentation to the end of the page just before the copyright notice. --- doc/sim65.sgml | 134 ++++++++++++++++++++++++------------------------- 1 file changed, 66 insertions(+), 68 deletions(-) diff --git a/doc/sim65.sgml b/doc/sim65.sgml index 7d54b87b9..f8e5caf19 100644 --- a/doc/sim65.sgml +++ b/doc/sim65.sgml @@ -151,74 +151,6 @@ int main() // sim65 example.prg -Counter peripheral - -

The sim65 simulator supports a memory-mapped counter peripheral that manages -a number of 64-bit counters that are continuously updated as the simulator is -running. For each counter, it also provides a 64 bit "latching" register. - -

The functionality of the counter peripheral is accessible through 3 registers: - - -PERIPHERALS_COUNTER_LATCH ($FFC0, write-only) -PERIPHERALS_COUNTER_SELECT ($FFC1, read/write) -PERIPHERALS_COUNTER_VALUE ($FFC2..$FFC9, read-only) - - -

These three registers are used as follows. - -

When a program explicitly requests a "counter latch" operation by writing any value -to the PERIPHERALS_COUNTER_LATCH address ($FFC0), all live registers are copied to -the latch registers. They will keep the latched value until another latch operation -updates them. - -

The PERIPHERALS_COUNTER_SELECT address ($FFC1) register holds an 8-bit value that -specifies which 64-bit value is currently readable through the PERIPHERALS_COUNTER_VALUE -address range. Six values are currently defined: - - -$00: latched clock cycle counter selected. -$01: latched CPU instruction counter selected. -$02: latched IRQ interrupt counter selected. -$03: latched NMI interrupt counter selected. -$80: latched wallclock time (nanoseconds) selected. -$81: latched wallclock time (split s/ns) selected. - - -

Values $00 to $03 provide access to the latched (frozen) value of their respective live -counters at the time of the last write to PERIPHERALS_COUNTER_LATCH . - -

When PERIPHERALS_COUNTER_LATCH equals $80, the PERIPHERALS_COUNTER_VALUE -will be a 64-bit value corresponding to the number of nanoseconds elapsed since Midnight, Jan 1st, -1970 UTC. - -

When PERIPHERALS_COUNTER_LATCH equals $81, the high 32 bits of PERIPHERALS_COUNTER_VALUE -will be a 32-bit value corresponding to the number of seconds elapsed since Midnight, -Jan 1st, 1970 UTC. The low 32 bits of PERIPHERALS_COUNTER_VALUE will hold the -nanoseconds since the start of that seconds. - -

The two different wallclock-time latch registers are provided for different applications. -For some applications, the single 64-bit value will be more convenient, while for other -applications, the split 32/32 bits representations with separate seconds and nanoseconds -is more convenient. - -

Note that the definition above given as time since Midnight, Jan 1st, 1970 UTC is an -approximation, as the implementation depends on the POSIX definition of time which does -not account for leap seconds. - -

If the PERIPHERALS_COUNTER_SELECT register holds a value other than one of the six -values described above, all PERIPHERALS_COUNTER_VALUE bytes will read as zero. - -

On reset, PERIPHERALS_COUNTER_SELECT is initialized to zero. - -

The PERIPHERALS_COUNTER_VALUE addresses ($FFC2..$FFC9) are used to read to currently -selected latch register value. Address $FFF2 holds the least significant byte (LSB), -while address $FFC9 holds the most significant byte (MSB). - -

On reset, all latch registers are reset to zero. this means that reading any of the -PERIPHERALS_COUNTER_VALUE bytes before a write to PERIPHERALS_COUNTER_LATCH -will yield zero. - Creating a Test in Assembly

Though a C test may also link with assembly code, @@ -296,6 +228,72 @@ but if customization is needed +Counter peripheral + +

The sim65 simulator supports a memory-mapped counter peripheral that manages +a number of 64-bit counters that are continuously updated as the simulator is +running. For each counter, it also provides a 64 bit "latching" register. + +

The functionality of the counter peripheral is accessible through 3 registers: + + +PERIPHERALS_COUNTER_LATCH ($FFC0, write-only) +PERIPHERALS_COUNTER_SELECT ($FFC1, read/write) +PERIPHERALS_COUNTER_VALUE ($FFC2..$FFC9, read-only) + + +

These three registers are used as follows. + +

When a program explicitly requests a "counter latch" operation by writing any value +to the PERIPHERALS_COUNTER_LATCH address ($FFC0), all live registers are simultaneously +copied to the latch registers. They will keep the newly latched value until another latch +operation is requested. + +

The PERIPHERALS_COUNTER_SELECT address ($FFC1) register holds an 8-bit value that +specifies which 64-bit latch register is currently readable through the PERIPHERALS_COUNTER_VALUE +address range. Six values are currently defined: + + +$00: latched clock cycle counter selected. +$01: latched CPU instruction counter selected. +$02: latched IRQ interrupt counter selected. +$03: latched NMI interrupt counter selected. +$80: latched wallclock time (nanoseconds) selected. +$81: latched wallclock time (split s/ns) selected. + + +

Values $00 to $03 provide access to the latched (frozen) value of their respective live +counters at the time of the last write to PERIPHERALS_COUNTER_LATCH. + +

When PERIPHERALS_COUNTER_LATCH equals $80, the PERIPHERALS_COUNTER_VALUE +will be a 64-bit value corresponding to the number of nanoseconds elapsed since Midnight, Jan 1st, +1970 UTC, at the time of the last latch operation. + +

When PERIPHERALS_COUNTER_LATCH equals $81, the high 32 bits of PERIPHERALS_COUNTER_VALUE +will be a 32-bit value corresponding to the number of seconds elapsed since Midnight, +Jan 1st, 1970 UTC, at the time of the last latch operation. The low 32 bits of +PERIPHERALS_COUNTER_VALUE will hold the nanoseconds since the start of that second. + +

The two different wallclock-time latch registers will always refer to precisely the same time instant. +For some applications, the single 64-bit value measured in nanoseconds will be more convenient, while +for other applications, the split 32/32 bits representations with separate seconds and nanosecond +values will be more convenient. + +

Note that the definition above, with time elapsed measured since Midnight, Jan 1st, 1970 UTC is +an approximation, as the implementation depends on the way POSIX definition time, which does +not account for leap seconds (POSIX falsely assumes that all days are precisely 86400 seconds +long). + +

On reset, PERIPHERALS_COUNTER_SELECT is initialized to zero. If the PERIPHERALS_COUNTER_SELECT +register holds a value other than one of the six values described above, all PERIPHERALS_COUNTER_VALUE +bytes will read as zero. + +

The PERIPHERALS_COUNTER_VALUE addresses ($FFC2..$FFC9) are used to read to currently +selected 64-bit latch register value. Address $FFC2 holds the least significant byte (LSB), +while address $FFC9 holds the most significant byte (MSB). + +

On reset, all latch registers are reset to zero. Reading any of the PERIPHERALS_COUNTER_VALUE +bytes before the first write to PERIPHERALS_COUNTER_LATCH will yield zero. Copyright

From 915416dc663323dbc9cff2fab404a8395aa6448f Mon Sep 17 00:00:00 2001 From: sidney Date: Tue, 31 Dec 2024 18:11:35 +0100 Subject: [PATCH 36/38] Added example. --- doc/sim65.sgml | 42 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/doc/sim65.sgml b/doc/sim65.sgml index f8e5caf19..849d6c65c 100644 --- a/doc/sim65.sgml +++ b/doc/sim65.sgml @@ -276,13 +276,12 @@ Jan 1st, 1970 UTC, at the time of the last latch operation. The low 32 bits of

The two different wallclock-time latch registers will always refer to precisely the same time instant. For some applications, the single 64-bit value measured in nanoseconds will be more convenient, while -for other applications, the split 32/32 bits representations with separate seconds and nanosecond +for other applications, the split 32/32 bits representations with separate second and nanosecond values will be more convenient. -

Note that the definition above, with time elapsed measured since Midnight, Jan 1st, 1970 UTC is -an approximation, as the implementation depends on the way POSIX definition time, which does -not account for leap seconds (POSIX falsely assumes that all days are precisely 86400 seconds -long). +

Note that the definition above, with time elapsed measured since Midnight, Jan 1st, 1970 UTC, is +an approximation, as the implementation depends on the way POSIX definition time, and POSIX does +not account for leap seconds; it falsely assumes that all days are precisely 86400 seconds long.

On reset, PERIPHERALS_COUNTER_SELECT is initialized to zero. If the PERIPHERALS_COUNTER_SELECT register holds a value other than one of the six values described above, all PERIPHERALS_COUNTER_VALUE @@ -295,6 +294,39 @@ while address $FFC9 holds the most significant byte (MSB).

On reset, all latch registers are reset to zero. Reading any of the PERIPHERALS_COUNTER_VALUE bytes before the first write to PERIPHERALS_COUNTER_LATCH will yield zero. +Example: + + +#include +#include + +volatile uint8_t * CounterLatch = (uint8_t *)0xffc0; +volatile uint8_t * CounterSelect = (uint8_t *)0xffc1; +volatile uint32_t * CounterValue = (uint32_t *)0xffc1; + +static void print_current_counters(void) +{ + *CounterLatch = 0; /* latch values */ + + *CounterSelect = 0x00; + printf("clock cycles ............... : %08lx %08lx\n", CounterValue[1], CounterValue[0]); + *CounterSelect = 0x01; + printf("instructions ............... : %08lx %08lx\n", CounterValue[1], CounterValue[0]); + *CounterSelect = 0x80; + printf("wallclock time ............. : %08lx %08lx\n", CounterValue[1], CounterValue[0]); + *CounterSelect = 0x81; + printf("wallclock time, split ...... : %08lx %08lx\n", CounterValue[1], CounterValue[0]); + printf("\n"); +} + +int main(void) +{ + print_current_counters(); + print_current_counters(); + return 0; +} + + Copyright

sim65 (and all cc65 binutils) are (C) Copyright 1998-2000 Ullrich von From b2851be34099b9c3137e5df6fe722a84e47c63e4 Mon Sep 17 00:00:00 2001 From: sidney Date: Tue, 31 Dec 2024 18:20:11 +0100 Subject: [PATCH 37/38] Fixed several typos. --- doc/sim65.sgml | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/doc/sim65.sgml b/doc/sim65.sgml index 849d6c65c..2b99a6682 100644 --- a/doc/sim65.sgml +++ b/doc/sim65.sgml @@ -246,7 +246,7 @@ running. For each counter, it also provides a 64 bit "latching" register.

When a program explicitly requests a "counter latch" operation by writing any value to the PERIPHERALS_COUNTER_LATCH address ($FFC0), all live registers are simultaneously -copied to the latch registers. They will keep the newly latched value until another latch +copied to the latch registers. They will keep their newly latched values until another latch operation is requested.

The PERIPHERALS_COUNTER_SELECT address ($FFC1) register holds an 8-bit value that @@ -259,7 +259,7 @@ address range. Six values are currently defined: $02: latched IRQ interrupt counter selected. $03: latched NMI interrupt counter selected. $80: latched wallclock time (nanoseconds) selected. -$81: latched wallclock time (split s/ns) selected. +$81: latched wallclock time (split: seconds, nanoseconds) selected.

Values $00 to $03 provide access to the latched (frozen) value of their respective live @@ -276,12 +276,13 @@ Jan 1st, 1970 UTC, at the time of the last latch operation. The low 32 bits of

The two different wallclock-time latch registers will always refer to precisely the same time instant. For some applications, the single 64-bit value measured in nanoseconds will be more convenient, while -for other applications, the split 32/32 bits representations with separate second and nanosecond +for other applications, the split 32/32 bits representation with separate second and nanosecond values will be more convenient.

Note that the definition above, with time elapsed measured since Midnight, Jan 1st, 1970 UTC, is -an approximation, as the implementation depends on the way POSIX definition time, and POSIX does -not account for leap seconds; it falsely assumes that all days are precisely 86400 seconds long. +an approximation, as the implementation depends on the way POSIX definition time. Unfortunately, +POSIX does not account for leap seconds; it incorrectly assumes that all days are precisely 86400 seconds +long.

On reset, PERIPHERALS_COUNTER_SELECT is initialized to zero. If the PERIPHERALS_COUNTER_SELECT register holds a value other than one of the six values described above, all PERIPHERALS_COUNTER_VALUE @@ -302,7 +303,7 @@ Example: volatile uint8_t * CounterLatch = (uint8_t *)0xffc0; volatile uint8_t * CounterSelect = (uint8_t *)0xffc1; -volatile uint32_t * CounterValue = (uint32_t *)0xffc1; +volatile uint32_t * CounterValue = (uint32_t *)0xffc2; static void print_current_counters(void) { From a8581d042f31aef6fc3c38f2d4b82255dd327285 Mon Sep 17 00:00:00 2001 From: sidney Date: Tue, 31 Dec 2024 18:32:11 +0100 Subject: [PATCH 38/38] Improved description. --- doc/sim65.sgml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/doc/sim65.sgml b/doc/sim65.sgml index 2b99a6682..9f2914254 100644 --- a/doc/sim65.sgml +++ b/doc/sim65.sgml @@ -265,13 +265,13 @@ address range. Six values are currently defined:

Values $00 to $03 provide access to the latched (frozen) value of their respective live counters at the time of the last write to PERIPHERALS_COUNTER_LATCH. -

When PERIPHERALS_COUNTER_LATCH equals $80, the PERIPHERALS_COUNTER_VALUE -will be a 64-bit value corresponding to the number of nanoseconds elapsed since Midnight, Jan 1st, -1970 UTC, at the time of the last latch operation. +

When PERIPHERALS_COUNTER_SELECT equals $80, the PERIPHERALS_COUNTER_VALUE +will be a 64-bit value corresponding to the number of nanoseconds elapsed since the Unix epoch +(Midnight, Jan 1st, 1970 UTC), at the time of the last latch operation. -

When PERIPHERALS_COUNTER_LATCH equals $81, the high 32 bits of PERIPHERALS_COUNTER_VALUE -will be a 32-bit value corresponding to the number of seconds elapsed since Midnight, -Jan 1st, 1970 UTC, at the time of the last latch operation. The low 32 bits of +

When PERIPHERALS_COUNTER_SELECT equals $81, the high 32 bits of PERIPHERALS_COUNTER_VALUE +will be a 32-bit value corresponding to the number of seconds elapsed since the Unix epoch (Midnight, Jan 1st, +1970 UTC), at the time of the last latch operation. The low 32 bits of PERIPHERALS_COUNTER_VALUE will hold the nanoseconds since the start of that second.

The two different wallclock-time latch registers will always refer to precisely the same time instant. @@ -279,10 +279,10 @@ For some applications, the single 64-bit value measured in nanoseconds will be m for other applications, the split 32/32 bits representation with separate second and nanosecond values will be more convenient. -

Note that the definition above, with time elapsed measured since Midnight, Jan 1st, 1970 UTC, is -an approximation, as the implementation depends on the way POSIX definition time. Unfortunately, -POSIX does not account for leap seconds; it incorrectly assumes that all days are precisely 86400 seconds -long. +

Note that the time elapsed since the Unix epoch is an approximation, as the implementation depends on the +way POSIX defines time-since-the-epoch. Unfortunately, POSIX incorrectly assumes that all days are precisely +86400 seconds long, which is not true in case of leap seconds. The way this inconsistency is resolved is +system dependent.

On reset, PERIPHERALS_COUNTER_SELECT is initialized to zero. If the PERIPHERALS_COUNTER_SELECT register holds a value other than one of the six values described above, all PERIPHERALS_COUNTER_VALUE