RTC: Implement missing links for physical test mode.

Also minor refactoring.
This commit is contained in:
Andrew Makousky 2020-09-17 04:13:03 -05:00
parent 745d73b98a
commit 655c495bb3
1 changed files with 189 additions and 95 deletions

View File

@ -448,6 +448,8 @@ void lingpirq_cleanup(void)
#include <time.h>
#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 <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
@ -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 <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <signal.h>
#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 <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#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;
}