From 655c495bb354b74d33f52275755dccc90ec44722 Mon Sep 17 00:00:00 2001 From: Andrew Makousky Date: Thu, 17 Sep 2020 04:13:03 -0500 Subject: [PATCH] RTC: Implement missing links for physical test mode. Also minor refactoring. --- firmware/rtc/test/test-rtc.c | 284 +++++++++++++++++++++++------------ 1 file changed, 189 insertions(+), 95 deletions(-) diff --git a/firmware/rtc/test/test-rtc.c b/firmware/rtc/test/test-rtc.c index 3de869d..cb3a44d 100644 --- a/firmware/rtc/test/test-rtc.c +++ b/firmware/rtc/test/test-rtc.c @@ -448,6 +448,8 @@ void lingpirq_cleanup(void) #include #include "arduino_sdef.h" +#include "rpi-gpio.h" +#include "lin-gpirq.h" #include "simavr-support.h" */ @@ -475,7 +477,26 @@ uint8_t const *VIA = vBase; bool g_waitTimeUp = true; uint8_t g_timePoll = 0; -#define viaBitRead(ptr, bit) (bitRead(*(ptr), (bit))) +enum PhyPins { PHY_SEC1, PHY_CE, PHY_CLK, PHY_DATA }; + +// Physical hardware test mode (via Raspberry Pi). +bool8_t g_phyMode = false; + +// Emulated RTC VIA connections to GPIO pin mappings. +uint8_t g_phyToGpio[4] = { 0, 0, 0, 0 }; + +uint8_t viaBitRead(uint8_t *ptr, uint8_t bit) +{ + if (g_phyMode) { + switch (bit) { + case rtcData: + return rpi_gpio_get_pin(g_phyToGpio[PHY_DATA]); + default: + return 0; // unrecognized signals read as zero + } + } // else + return bitRead(*(ptr), (bit)); +} void viaBitWrite(uint8_t *ptr, uint8_t bit, uint8_t bitvalue) { @@ -488,27 +509,42 @@ void viaBitWrite(uint8_t *ptr, uint8_t bit, uint8_t bitvalue) // Send the signal to the actual hardware. switch (bit) { case rtcEnb: - avr_raise_irq(bench_irqs + IRQ_CE, bitvalue & 1); + if (g_phyMode) + rpi_gpio_set_pin(g_phyToGpio[PHY_CE], bitvalue & 1); + else + avr_raise_irq(bench_irqs + IRQ_CE, bitvalue & 1); break; case rtcClk: - avr_raise_irq(bench_irqs + IRQ_CLK, bitvalue & 1); + if (g_phyMode) + rpi_gpio_set_pin(g_phyToGpio[PHY_CLK], bitvalue & 1); + else + avr_raise_irq(bench_irqs + IRQ_CLK, bitvalue & 1); break; case rtcData: - avr_raise_irq(bench_irqs + IRQ_DATA_IN, bitvalue & 1); + if (g_phyMode) + rpi_gpio_set_pin(g_phyToGpio[PHY_DATA], bitvalue & 1); + else + avr_raise_irq(bench_irqs + IRQ_DATA_IN, bitvalue & 1); break; default: break; // unrecognized signals do nothing } } else if (ptr == vBase + vDirB) { - // TODO FIXME: - - // The main special handling we do here is to set to the - // corresponding buffer bit to the input value as soon as we - // change to an input type. With the `simavr` setup, we simply - // set to default logic value 1 and we will get an IRQ if we - // should do otherwise. - if (bitvalue == DIR_IN) - bitWrite(vBase[vBufB], bit, 1); + if (g_phyMode) { + // We only support changing the direction of the data pin. + if (bit == rtcData) { + uint8_t fn = (bitvalue == DIR_IN) ? GPFN_INPUT : GPFN_OUTPUT; + rpi_gpio_set_fn(g_phyToGpio[PHY_DATA], fn); + } + } else { + // The main special handling we do here is to set to the + // corresponding buffer bit to the input value as soon as we + // change to an input type. With the `simavr` setup, we simply + // set to default logic value 1 and we will get an IRQ if we + // should do otherwise. + if (bitvalue == DIR_IN) + bitWrite(vBase[vBufB], bit, 1); + } } else return; // Update our register value. @@ -527,41 +563,41 @@ void viaBitWrite(uint8_t *ptr, uint8_t bit, uint8_t bitvalue) silicon RTC. */ void waitQuarterCycle(void) { -#ifdef RPI_DRIVER - struct timespec tv = { 0, 500000 }; - struct timespec tvNext; - do { - if (clock_nanosleep(CLOCK_MONOTONIC, 0, &tv, &tvNext) == 0) - break; - tv.tv_nsec = tvNext.tv_nsec; - } while (tv.tv_nsec > 0); -#else - // Unfortunately, if the AVR runs at 32.768 kHz, I've found from - // simulation that serial communications are only reliable at an - // abysmal 50 Hz serial clock speed. Therefore, running at a higher - // core speed and using a phase-locked loop on the crystal clock - // frequency a must. - struct timespec tv, tvTarget; - // N.B. Over here we are using cycle timers mainly to prevent - // simulation waits stretching unbearably long. - g_timePoll = 16; - avr_cycle_timer_register(avr, g_timePoll, notify_timeup, NULL); - clock_gettime(CLOCK_MONOTONIC, &tv); - tvTarget.tv_nsec = tv.tv_nsec + 500000; - tvTarget.tv_sec = tv.tv_sec; - if (tvTarget.tv_nsec >= 1000000000) { - tvTarget.tv_nsec -= 1000000000; - tvTarget.tv_sec++; - } - while (tv.tv_sec < tvTarget.tv_sec || - (tv.tv_sec == tvTarget.tv_sec && - tv.tv_nsec < tvTarget.tv_nsec)) { - if (!simAvrStep()) - break; + if (g_phyMode) { + struct timespec tv = { 0, 500000 }; + struct timespec tvNext; + do { + if (clock_nanosleep(CLOCK_MONOTONIC, 0, &tv, &tvNext) == 0) + break; + tv.tv_nsec = tvNext.tv_nsec; + } while (tv.tv_nsec > 0); + } else { + // Unfortunately, if the AVR runs at 32.768 kHz, I've found from + // simulation that serial communications are only reliable at an + // abysmal 50 Hz serial clock speed. Therefore, running at a + // higher core speed and using a phase-locked loop on the crystal + // clock frequency a must. + struct timespec tv, tvTarget; + // N.B. Over here we are using cycle timers mainly to prevent + // simulation waits stretching unbearably long. + g_timePoll = 16; + avr_cycle_timer_register(avr, g_timePoll, notify_timeup, NULL); clock_gettime(CLOCK_MONOTONIC, &tv); + tvTarget.tv_nsec = tv.tv_nsec + 500000; + tvTarget.tv_sec = tv.tv_sec; + if (tvTarget.tv_nsec >= 1000000000) { + tvTarget.tv_nsec -= 1000000000; + tvTarget.tv_sec++; + } + while (tv.tv_sec < tvTarget.tv_sec || + (tv.tv_sec == tvTarget.tv_sec && + tv.tv_nsec < tvTarget.tv_nsec)) { + if (!simAvrStep()) + break; + clock_gettime(CLOCK_MONOTONIC, &tv); + } + g_timePoll = 0; } - g_timePoll = 0; -#endif } void waitHalfCycle(void) @@ -578,26 +614,55 @@ void waitCycle(void) void waitOneSec(void) { -#ifdef RPI_DRIVER - sleep(1); -#else - struct timespec tv, tvTarget; - // N.B. Over here we are using cycle timers mainly to prevent - // simulation waits stretching unbearably long. - g_timePoll = 16; - avr_cycle_timer_register(avr, g_timePoll, notify_timeup, NULL); - clock_gettime(CLOCK_MONOTONIC, &tv); - tvTarget.tv_nsec = tv.tv_nsec; - tvTarget.tv_sec = tv.tv_sec + 1; - while (tv.tv_sec < tvTarget.tv_sec || - (tv.tv_sec == tvTarget.tv_sec && - tv.tv_nsec < tvTarget.tv_nsec)) { - if (!simAvrStep()) - break; + if (g_phyMode) { + sleep(1); + } else { + struct timespec tv, tvTarget; + // N.B. Over here we are using cycle timers mainly to prevent + // simulation waits stretching unbearably long. + g_timePoll = 16; + avr_cycle_timer_register(avr, g_timePoll, notify_timeup, NULL); clock_gettime(CLOCK_MONOTONIC, &tv); + tvTarget.tv_nsec = tv.tv_nsec; + tvTarget.tv_sec = tv.tv_sec + 1; + while (tv.tv_sec < tvTarget.tv_sec || + (tv.tv_sec == tvTarget.tv_sec && + tv.tv_nsec < tvTarget.tv_nsec)) { + if (!simAvrStep()) + break; + clock_gettime(CLOCK_MONOTONIC, &tv); + } + g_timePoll = 0; + } +} + +void viaInit(void) +{ + if (g_phyMode) { + // Setup GPIO pins. + rpi_gpio_set_fn(g_phyToGpio[PHY_SEC1], GPFN_INPUT); + rpi_gpio_set_pull(g_phyToGpio[PHY_SEC1], GPUL_UP); + rpi_gpio_set_fn(g_phyToGpio[PHY_CE], GPFN_OUTPUT); + rpi_gpio_set_fn(g_phyToGpio[PHY_CLK], GPFN_OUTPUT); + rpi_gpio_set_fn(g_phyToGpio[PHY_DATA], GPFN_OUTPUT); + // Setup GPIO IRQ for 1-second pin. + lingpirq_setup(g_phyToGpio[PHY_SEC1]); + } +} + +void viaDestroy(void) +{ + if (g_phyMode) { + // Cleanup GPIO pins, change to all pull-up inputs. + rpi_gpio_set_fn(g_phyToGpio[PHY_CE], GPFN_INPUT); + rpi_gpio_set_pull(g_phyToGpio[PHY_CE], GPUL_UP); + rpi_gpio_set_fn(g_phyToGpio[PHY_CLK], GPFN_INPUT); + rpi_gpio_set_pull(g_phyToGpio[PHY_CLK], GPUL_UP); + rpi_gpio_set_fn(g_phyToGpio[PHY_DATA], GPFN_INPUT); + rpi_gpio_set_pull(g_phyToGpio[PHY_DATA], GPUL_UP); + // Cleanup GPIO IRQ for 1-second pin. + lingpirq_cleanup(); } - g_timePoll = 0; -#endif } /********************************************************************/ @@ -1221,7 +1286,6 @@ bool8_t fileDumpAllXMem(const char *filename) /* #include #include -#include #include #include @@ -1672,12 +1736,11 @@ uint8_t execMultiCmdLine(char *lineBuf) } // Return false on exit with error, true on graceful exit. -bool8_t cmdLoop(void) +bool8_t cmdLoop(bool8_t notScripted) { uint8_t retVal = true; char lineBuf[512]; char *parsePtr; - bool8_t notScripted = isatty(STDIN_FILENO); // Print the prompt character. if (notScripted) putchar('*'); @@ -2030,7 +2093,6 @@ void writehex(char *rch) #include #include #include -#include #include "sim_avr.h" #include "avr_ioport.h" @@ -2090,16 +2152,6 @@ void pin_change_notify(avr_irq_t *irq, uint32_t value, void *param) } } -static void -sig_int(int sign) -{ - printf("signal caught, simavr terminating\n"); - if (avr) - avr_terminate(avr); - pramDestroy(); - exit(0); -} - int setupSimAvr(char *progName, const char *fname, bool8_t interactMode) { elf_firmware_t f; @@ -2237,9 +2289,6 @@ int setupSimAvr(char *progName, const char *fname, bool8_t interactMode) fputs( "\nSimulation launching:\n", stdout); - signal(SIGINT, sig_int); - signal(SIGTERM, sig_int); - return 0; } @@ -2853,15 +2902,36 @@ uint8_t getSuiteMode(void) /* #include +#include #include #include +#include #include "arduino_sdef.h" +#include "via-emu.h" #include "simavr-support.h" #include "cmdline.h" #include "auto-test-suite.h" */ +void mainCleanup(void) +{ + viaDestroy(); + if (!g_phyMode) { + if (avr) + { avr_terminate(avr); avr = NULL; } + } + pramDestroy(); +} + +static void +sig_int(int sign) +{ + printf("signal caught, terminating\n"); + mainCleanup(); + exit(0); +} + int main(int argc, char *argv[]) { char *firmwareName = ""; @@ -2873,40 +2943,64 @@ int main(int argc, char *argv[]) for (i = 1; i < argc; i++) { if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) { - printf("Usage: %s [-i] FIRMWARE_FILE\n" - "\n" - " -i Run interactive mode\n" - "\n", argv[0]); + printf( +"Usage: %s [-i] [-r a,b,c,d] FIRMWARE_FILE\n" +"\n" +" -i Run interactive mode\n" +" -r Physical hardware test mode (via Raspberry Pi).\n" +" Configure SEC1,CE*,CLK,DATA to the given BCM GPIO pin numbers.\n" +"\n", argv[0]); return 0; } else if (strcmp(argv[i], "-i") == 0) interactMode = true; - else + else if (strcmp(argv[i], "-r") == 0) { + i++; + if (i >= argc) { + fprintf(stderr, "%s: Missing command line argument.\n", argv[0]); + return 1; + } + g_phyMode = true; + sscanf(argv[i], "%d,%d,%d,%d", + g_phyToGpio + PHY_SEC1, g_phyToGpio + PHY_CE, + g_phyToGpio + PHY_CLK, g_phyToGpio + PHY_DATA); + if (g_phyToGpio[PHY_SEC1] == 0 || + g_phyToGpio[PHY_CE] == 0 || + g_phyToGpio[PHY_CLK] == 0 || + g_phyToGpio[PHY_DATA] == 0) { + fprintf(stderr, "%s: Invalid pin configuration.\n", argv[0]); + return 1; + } + } else firmwareName = argv[i]; } } + + signal(SIGINT, sig_int); + signal(SIGTERM, sig_int); + pramInit(); - retVal = setupSimAvr(argv[0], firmwareName, interactMode); + viaInit(); + if (!g_phyMode) + retVal = setupSimAvr(argv[0], firmwareName, interactMode); if (retVal != 0) return retVal; if (interactMode) { + bool8_t notScripted = isatty(STDIN_FILENO); fputs("Launching interactive console.\n", stdout); - if (isatty(STDIN_FILENO)) + if (notScripted) fputs("Type help for summary of commands.\n", stdout); - if (!cmdLoop()) { - avr_terminate(avr); - pramDestroy(); + if (!cmdLoop(notScripted)) { + mainCleanup(); return 1; } - avr_terminate(avr); - pramDestroy(); + mainCleanup(); return 0; } // Run automated test suite. fputs("Running automated test suite.\n", stdout); retVal = !autoTestSuite(false, true, true); - avr_terminate(avr); - pramDestroy(); + mainCleanup(); return retVal; }