]> cloudbase.mooo.com Git - z180-stamp.git/blobdiff - avr/cmd_cpu.c
clean up includes
[z180-stamp.git] / avr / cmd_cpu.c
index d69221100e25ab3efe5c208e3f5f613b1df36bd0..2abf5db150d602c0d6498f0d486f40dfdb77fc2a 100644 (file)
@@ -5,22 +5,40 @@
  */
 
 #include "cmd_cpu.h"
-//#include <ctype.h>
 #include <util/atomic.h>
 
 #include "z80-if.h"
 #include "con-utils.h"
-//#include "env.h"
+#include "env.h"
 #include "eval_arg.h"
 #include "timer.h"
 #include "getopt-min.h"
-//#include "debug.h"
+#include "debug.h"
 
 /* hack to get Z180 loadfile into flash memory */
 #define const const FLASH
 #include "../z180/cpuinfo.h"
 #undef const
 
+#define DEBUG_CPU      1       /* set to 1 to debug */
+
+#define debug_cpu(fmt, args...)                                                              \
+       debug_cond(DEBUG_CPU, fmt, ##args)
+
+static
+char * ulltoa (uint64_t val, char *s)
+{
+       char *p = s;
+
+       while (val >= 10) {
+               *p++ = (val % 10) + '0';
+               val = val / 10;
+       }
+       *p++ = val + '0';
+       *p = '\0';
+
+       return strrev(s);
+}
 
 /*
  * delay for <count> ms...
@@ -32,107 +50,90 @@ static void        test_delay(uint32_t count)
        while (get_timer(ts) <= count);
 }
 
-static int32_t z80_measure_phi(uint8_t cycles, bool input_clk, uint16_t wait_ms)
+static uint32_t z80_measure_phi(uint_fast8_t cycles)
 {
        uint16_t ref_stop;
        uint16_t ref_ovfl;
+       uint8_t x_ovfl;
        uint32_t x_freq;
 
 
        PRR1 &= ~_BV(PRTIM3);
        TCCR3A = 0;
-       TCCR3B = 0b000<<CS30;   /* stop counter */
+       TCCR3B = 0b000<<CS30;                   /* stop counter */
        TCNT3 = 0;
+       x_ovfl = 0;
        TIFR3 = _BV(TOV3);
        ref_ovfl = 0;
+
        ATOMIC_BLOCK(ATOMIC_FORCEON) {
-               /* Reset pending int */
-               EIFR = _BV(INTF6);
-               /* Wait for falling edge */
-               while ((EIFR & _BV(INTF6)) == 0)
+               EIFR = _BV(INTF6);                                      /* Reset pending int */
+               while ((EIFR & _BV(INTF6)) == 0)        /* Wait for falling edge */
                        ;
-               //ref_start = TCNT4;
                OCR4B = TCNT4;
-               TCCR3B = 0b110<<CS30;   /* Count falling edges on T3 (==INT6) */
-               TIFR4 = _BV(OCF4B);             /* clear compare match flag */
-       }
-       while (ref_ovfl < 60) {
-               ATOMIC_BLOCK(ATOMIC_FORCEON) {
+               TCCR3B = 0b110<<CS30;           /* Count falling edges on T3 (==INT6) */
+               TIFR4 = _BV(OCF4B);                     /* clear compare match flag */
+
+               while (ref_ovfl < 60) {
                        if ((TIFR4 & _BV(OCF4B)) != 0) {
                                TIFR4 = _BV(OCF4B);
-                               ref_ovfl++;
+                               ++ref_ovfl;
+                       }
+                       if ((TIFR3 & _BV(TOV3)) != 0) {
+                               TIFR3 = _BV(TOV3);
+                               ++x_ovfl;
                        }
                }
-       }
 
-       ATOMIC_BLOCK(ATOMIC_FORCEON) {
                EIFR = _BV(INTF6);
                for (;;) {
-                       if (EIFR & _BV(INTF6))
+                       if (EIFR & _BV(INTF6)) {
+                               TCCR3B = 0b000<<CS30;   /* stop counter */
+                               ref_stop = TCNT4;
                                break;
-                       if (TIFR4 & _BV(OCF4B)) {
-                               if (EIFR & _BV(INTF6))
-                                       break;
+                       }
+                       if ((TIFR4 & _BV(OCF4B)) != 0) {
                                TIFR4 = _BV(OCF4B);
-                               if (EIFR & _BV(INTF6))
-                                       break;
-                               ref_ovfl++;
-                               if (EIFR & _BV(INTF6))
-                                       break;
-                               if (ref_ovfl == 0)
-                                       break;
+                               ++ref_ovfl;
                        }
                }
-               ref_stop = TCNT4;
-               TCCR3B = 0b000<<CS30;   /* stop counter */
-               if ((TIFR4 & _BV(OCF4B)) != 0) {
-                       TIFR4 = _BV(OCF4B);
-                       if (ref_ovfl)
-                               ref_ovfl++;
-               }
        }
 
-       if (ref_ovfl == 0)
-               x_freq = 0xFFFFFFFE;
-       else
-       {
-               uint32_t ref_cnt = (ref_stop - OCR4B) + ((uint32_t)ref_ovfl << 16);
-
-               x_freq = TCNT3;                                         /* x_cnt (17 bit) */
-               if ((TIFR3 & _BV(TOV3)) != 0)
-                       x_freq += 1UL << 16;
-               uint32_t x_cnt = x_freq;
-               if (input_clk)                                          /* compute input clock */
-                       x_freq *= 2;
-               x_freq *= cycles;
-
-               x_freq = ((uint64_t) x_freq * F_CPU + (ref_cnt / 2))/ ref_cnt;
-
-               printf_P(PSTR("ref_start: %6u, ref_stop: %6u, ref_ovfl: %4u, ref_cnt: %9lu\n"
-                                         "    TCNT3: %6u,    x_cnt: %6lu, cycles: %3u, xfreq: %9lu\n"),
-                                       OCR4B, ref_stop, ref_ovfl, ref_cnt,
-                                       TCNT3, x_cnt, cycles, x_freq);
-
-               /* round to 5 decimal digits */
-               uint8_t sc = 0;
-               while (x_freq >= 100000UL) {
-                       x_freq = (x_freq + 5)/10;
-                       ++sc;
-               }
-               while (sc--)
-                       x_freq *= 10;
+       if ((TIFR3 & _BV(TOV3)) != 0) {
+               TIFR3 = _BV(TOV3);
+               x_ovfl++;
        }
 
+       uint32_t ref_cnt = (ref_stop - OCR4B) + ((uint32_t)ref_ovfl << 16);
+       uint32_t x_cnt = TCNT3 + ((uint32_t) x_ovfl << 16);
+       uint64_t x_tmp = (uint64_t) 100000 * (x_cnt * cycles);
+
        /* Stop Timer */
        TCCR3B = 0;
        PRR1 |= _BV(PRTIM3);
 
-       return (int32_t) x_freq;
-}
+//     char x_tmp_str[21];
+//
+//     debug_cpu("TCNT3: %6u, ref_cnt: %9lu\n", TCNT3, ref_cnt);
+//     ulltoa(x_tmp, x_tmp_str);
+//     debug_cpu("x_tmp: %s\n", x_tmp_str);
+
+       x_tmp = (x_tmp * getenv_ulong(PSTR(ENV_FMON), 10, F_CPU) + (ref_cnt / 2)) / ref_cnt;
+
+//     ulltoa(x_tmp, x_tmp_str);
+//     debug_cpu("x_tmp: %s\n", x_tmp_str);
 
+       /* round to 5 decimal digits */
+       int_fast8_t sc = 5;
+       for ( ; sc > 0 || x_tmp >= 100000; sc--) x_tmp = (x_tmp + 5)/10;
+       x_freq = x_tmp;
+       for ( ; sc < 0; sc++) x_freq *= 10;
+
+       return x_freq;
+}
 
 static const FLASH char * const FLASH cpu_strings[] = {
-       FSTR("Unknown CPU"),
+       FSTR("Unknown"),
        FSTR("8080"),
        FSTR("8085"),
        FSTR("Z80"),
@@ -142,58 +143,161 @@ static const FLASH char * const FLASH cpu_strings[] = {
        FSTR("Z80S180"),
 };
 
-command_ret_t do_cpuchk(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc UNUSED, char * const argv[] UNUSED)
+#define O_SILENT               (1<<0)
+#define O_WENV                 (1<<1)
+#define O_LOAD_LOOP     (1<<2)
+#define O_UNLOAD_LOOP   (1<<3)
+
+static const FLASH char * const FLASH opt_strings[] = {
+       FSTR("swnu"),           /* Options for chkcpu */
+       FSTR("swnuc:"),         /* Oprions for cpufreq */
+};
+
+static const FLASH char * const FLASH env_names[] = {
+       FSTR(ENV_CPU),          /* Env var for chkcpu result */
+       FSTR(ENV_CPU_FREQ),     /* Env var for cpufreq result */
+};
+
+command_ret_t do_cpu_freq_chk(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc, char * const argv[])
 {
-       uint8_t done = 0;
-       uint8_t cputype;
+       uint_fast8_t options = O_LOAD_LOOP | O_UNLOAD_LOOP;
+       uint_fast8_t cputype = 0;
+       uint32_t cpu_freq = 0;
+       uint_fast8_t lcycles = 0;
+       uint_fast8_t freq_cmd = 0;
+//     uint16_t timeout = 1000;
+       uint8_t eimsk_save;
        ERRNUM err = ESUCCESS;
-       uint8_t ram_save[cpuinfo_length];
 
-       if (z80_bus_state() & ZST_RUNNING) {
-               err = ERUNNING;
-       } else {
-               z80_bus_request_or_exit();
-               z80_read_block(ram_save, 0, cpuinfo_length);
-               z80_load_mem(0, cpuinfo,
-                                       &cpuinfo_sections,
-                                       cpuinfo_address,
-                                       cpuinfo_length_of_sections);
+       if (argv[0][0] == 'f')
+               freq_cmd = 1;
+
+       int opt;
+       while ((opt = getopt(argc, argv, opt_strings[freq_cmd])) != -1) {
+               switch (opt) {
+               case 's':
+                       options |= O_SILENT;
+                       break;
+               case 'w':
+                       options |= O_WENV;
+                       break;
+               case 'n':
+                       options &= ~O_LOAD_LOOP;
+                       break;
+               case 'u':
+                       options &= ~O_UNLOAD_LOOP;
+                       break;
+               case 'c':
+                       lcycles = eval_arg(optarg, NULL);
+                       break;
+//             case 't':
+//                     timeout = eval_arg(optarg, NULL);
+//                     break;
+               default: /* '?' */
+                       return CMD_RET_USAGE;
+               }
+       }
+       if (argc - optind != 0)
+               return CMD_RET_USAGE;
+
+       if (z80_bus_state() & ZST_RUNNING)
+               cmd_error(CMD_RET_FAILURE, ERUNNING, NULL);
+
+       uint8_t *mem_save = NULL;
+       if (options & O_LOAD_LOOP) {
+               mem_save = (uint8_t *) malloc(cpuinfo_length);
+               if (mem_save == NULL)
+                       cmd_error(CMD_RET_FAILURE, ENOMEM, NULL);
+               z80_bus_cmd(Request);
+               z80_read_block(mem_save, 0, cpuinfo_length);
+               z80_load_mem(0, cpuinfo, &cpuinfo_sections,     cpuinfo_address,
+                                                    cpuinfo_length_of_sections);
                z80_bus_cmd(Release);
+       }
 
-               if (argv[1] && (argv[1][0] == 'n'))
-                       goto donot;
+       /* Save state and disable INT5/INT6 */
+       ATOMIC_BLOCK(ATOMIC_FORCEON) {
+               eimsk_save = EIMSK;
+               EIMSK &= ~_BV(INT6);
+               EIMSK &= ~_BV(INT5);
+       }
+       EIFR = _BV(INTF5);                              /* Reset pending int */
 
-               z80_bus_cmd(Run);
+       z80_bus_cmd(Run);
 
-               clear_ctrlc();          /* forget any previous Control C */
-               while (done != 0xFF) {
-                       _delay_ms(8);
-                       /* check for ctrl-c to abort... */
-                       if (had_ctrlc() || ctrlc()) {
-                               err = EINTR;
-                               break;
-                       }
+       clear_ctrlc();                                  /* forget any previous Control C */
+       /* Wait for falling edge */
+       do {
+               /* check for ctrl-c to abort... */
+               if (had_ctrlc() || ctrlc()) {
+                       err = EINTR;
+                       break;
+               }
+       } while ((EIFR & _BV(INTF5)) == 0);
+
+       if (freq_cmd) {
+               if (lcycles == 0) {
                        z80_bus_cmd(Request);
-                       done = z80_read(3);
-                       if (done == 0xFF)
-                               cputype = z80_read(4);
+                       if (z80_read(3) == 0xFF)
+                               lcycles = z80_read(5);
                        z80_bus_cmd(Release);
                }
-               z80_bus_cmd(Reset);
+               if (!err)
+                       cpu_freq = z80_measure_phi(lcycles);
+       }
+       z80_bus_cmd(Reset);
+
+       /* Restore INT5/INT6 */
+       ATOMIC_BLOCK(ATOMIC_FORCEON) {
+               if ((eimsk_save & _BV(INT5)) != 0)
+                       EIMSK |= _BV(INT5);
+               if ((eimsk_save & _BV(INT6)) != 0)
+                       EIMSK |= _BV(INT6);
+               /* Reset pending int */
+               EIFR = _BV(INTF5);
+               EIFR = _BV(INTF6);
+       }
+       Stat &= ~S_MSG_PENDING;
+       Stat &= ~S_CON_PENDING;
+
+       if (freq_cmd == 0) {
                z80_bus_cmd(Request);
-//             z80_write_block(ram_save, 0, cpuinfo_length);
+               if (z80_read(3) == 0xFF)
+                       cputype = z80_read(4);
                z80_bus_cmd(Release);
        }
 
-donot:
+       if ((mem_save != NULL) && options & O_UNLOAD_LOOP) {
+               z80_bus_cmd(Request);
+               z80_write_block(mem_save, 0, cpuinfo_length);
+               z80_bus_cmd(Release);
+       }
+       free(mem_save);
 
        if (err)
                cmd_error(CMD_RET_FAILURE, err, NULL);
 
-       if (done == 0xFF) {
+       char result_str[11];
+
+       if (freq_cmd) {
+               ultoa(cpu_freq, result_str, 10);
+       } else {
                if (cputype >= ARRAY_SIZE(cpu_strings))
                        cputype = 0;
-               printf_P(PSTR("Detected CPU: %S\n"), cpu_strings[cputype]);
+               strcpy_P(result_str, cpu_strings[cputype]);
+       }
+
+       if (!(options & O_SILENT))
+               printf_P(PSTR("%s\n"), result_str);
+
+       if (options & O_WENV) {
+               if (setenv(env_names[freq_cmd], result_str)) {
+                       if (!(options & O_SILENT)) {
+                               printf_P(PSTR("'setenv %S %s' failed!\n"), env_names[freq_cmd], result_str);
+                               //cmd_error(CMD_RET_FAILURE, ENOMEM, PSTR("'setenv (%S, %s)' failed"), env_names[freq_cmd], result_str);
+                       }
+                       return CMD_RET_FAILURE;
+               }
        }
 
        return CMD_RET_SUCCESS;
@@ -231,7 +335,7 @@ command_ret_t do_cpu_test(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int
 
 command_ret_t do_bus_test(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc UNUSED, char * const argv[] UNUSED)
 {
-       char ch;
+       int ch;
 
 #if 0
        int opt;
@@ -310,140 +414,33 @@ command_ret_t do_busack_test(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED,
        return CMD_RET_SUCCESS;
 }
 
-command_ret_t do_cpu_freq(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc, char * const argv[])
-{
-
-#define O_SILENT               (1<<0)
-#define O_WENV                 (1<<1)
-#define O_LOAD_LOOP     (1<<2)
-#define O_UNLOAD_LOOP   (1<<3)
-
-       uint_fast8_t options = O_LOAD_LOOP | O_UNLOAD_LOOP;
-       uint8_t lcycles = 18;
-       uint16_t timeout = 1000;
-
-       uint8_t eicrb_save;
-       uint8_t eimsk_save;
-       uint8_t mem_save[cpuinfo_length];
-
-       int opt;
-       while ((opt = getopt(argc, argv, PSTR("swnuc:t:"))) != -1) {
-               switch (opt) {
-               case 's':
-                       options |= O_SILENT;
-                       break;
-               case 'w':
-                       options |= O_WENV;
-                       break;
-               case 'n':
-                       options &= ~O_LOAD_LOOP;
-                       break;
-               case 'u':
-                       options &= ~O_UNLOAD_LOOP;
-                       break;
-               case 'c':
-                       lcycles = eval_arg(optarg, NULL);
-                       break;
-               case 't':
-                       timeout = eval_arg(optarg, NULL);
-                       break;
-               default: /* '?' */
-                       return CMD_RET_USAGE;
-               }
-       }
-       if (argc - optind != 0)
-               return CMD_RET_USAGE;
-
-       if (z80_bus_state() & ZST_RUNNING) {
-               if (!(options & O_SILENT))
-                       printf_P(PSTR("Frequency measuring failed. CPU allready running!\n"));
-               return CMD_RET_FAILURE;
-       }
-
-       ATOMIC_BLOCK(ATOMIC_FORCEON) {
-               /* Save state and disable INT6 */
-               eimsk_save = EIMSK;
-               EIMSK &= ~_BV(INT6);
-               /* Save state and set INT6 for falling edge */
-               eicrb_save = EICRB;
-               EICRB = (eicrb_save & ~(0b11 << ISC60)) | (0b10 << ISC60);
-       }
-
-       z80_bus_cmd(Request);
-       if (options & O_LOAD_LOOP) {
-               z80_read_block(mem_save, 0, cpuinfo_length);
-               z80_load_mem(0, cpuinfo,
-                                       &cpuinfo_sections,
-                                       cpuinfo_address,
-                                       cpuinfo_length_of_sections);
-       }
-       Stat &= ~S_IO_0X40;                             /* Reset pending int */
-       z80_bus_cmd(Release);
-       z80_bus_cmd(Run);
-
-       clear_ctrlc();                                  /* forget any previous Control C */
-       ERRNUM err = 0;
-
-       /* Wait for falling edge */
-       do {
-               /* check for ctrl-c to abort... */
-               if (had_ctrlc() || ctrlc()) {
-                       err = EINTR;
-                       break;
-               }
-       } while ((Stat & S_IO_0X40) == 0);
-
-       int32_t cpu_freq;
-       if (!err)
-               cpu_freq = z80_measure_phi(lcycles, false, timeout);
-
-       z80_bus_cmd(Reset);
-       if (options & O_UNLOAD_LOOP) {
-               z80_bus_cmd(Request);
-               z80_write_block(mem_save, 0, cpuinfo_length);
-               z80_bus_cmd(Release);
-       }
-       ATOMIC_BLOCK(ATOMIC_FORCEON) {
-               /* Restore INT6 */
-               eicrb_save = EICRB;
-               EICRB = (EICRB & ~(0b11 << ISC60)) | (eicrb_save & (0b11 << ISC60));
-               if ((eimsk_save & _BV(INT6)) != 0)
-                       EIMSK |= _BV(INT6);
-               /* Reset pending int */
-               EIFR = _BV(INTF6);
-       }
-
-       if (err)
-               cmd_error(CMD_RET_FAILURE, err, NULL);
-
-       if (!(options & O_SILENT)) {
-               printf_P(PSTR("%ld%S\n"), cpu_freq, cpu_freq < 0 ? PSTR("") : PSTR("Hz"));
-//             if (cpu_freq != 0)
-//             else
-//                     printf_P(PSTR("No CPU clock or input frequency to low!\n"));
-       }
-#if 0
-       if (options & O_WENV) {
-               if (setenv_ulong(PSTR(ENV_CPU_FREQ), cpu_freq)) {
-                       if (!(options & O_SILENT))
-                               printf_P(PSTR("'SETENV (%S, %lu)' failed!\n"), PSTR(ENV_CPU_FREQ), cpu_freq);
-                       return CMD_RET_FAILURE;
-               }
-       }
-#endif
-       return CMD_RET_SUCCESS;
-}
-
 
 /*
- * command table for fat subcommands
+ * command table for subcommands
  */
-
 cmd_tbl_t cmd_tbl_cpu[] = {
 CMD_TBL_ITEM(
-       chkcpu, CONFIG_SYS_MAXARGS,     CTBL_RPT,       do_cpuchk,
-       "Check CPU",
-       ""
+       freq,   CONFIG_SYS_MAXARGS,     CTBL_RPT,       do_cpu_freq_chk,
+       "Measure cpu frequency",
+//     "[-swnu] [-c loopcycles] [-t timeout]\n"
+       "[-swnu] [-c loopcycles]\n"
+       "     -s Be silent\n"
+       "     -w Write result to environment variable '"ENV_CPU_FREQ"'"
+       "     -n Don't load code snippet. \n"
+       "     -u Don't unload. Leave code snippet in ram.\n"
+       "     -c Overwrite cycles per lopp for in \"l: a,(50h)/jp l\" loop."
+//     "     -t Timeout (ms)\n"
+),
+CMD_TBL_ITEM(
+       chkcpu, CONFIG_SYS_MAXARGS,     CTBL_RPT|CTBL_SUBCMDAUTO, do_cpu_freq_chk,
+       "Check/Identify CPU",
+//     "[-swnu] [-c loopcycles] [-t timeout]\n"
+       "[-swnu] [-c loopcycles]\n"
+       "     -s Be silent\n"
+       "     -w Write result to environment variable '"ENV_CPU"'"
+       "     -n Don't load code snippet. \n"
+       "     -u Don't unload. Leave code snippet in ram."
+//     "     -t Timeout (ms)\n"
 ),
 CMD_TBL_ITEM(
        buscmd, CONFIG_SYS_MAXARGS,     CTBL_RPT,       do_bus_test,
@@ -451,22 +448,15 @@ CMD_TBL_ITEM(
        ""
 ),
 CMD_TBL_ITEM(
-       test,   CONFIG_SYS_MAXARGS,     1,      do_cpu_test,
+       test,   CONFIG_SYS_MAXARGS,     CTBL_RPT,       do_cpu_test,
        "Do bus request/release cycles",
        "[-t pulsewidth]"
 ),
 CMD_TBL_ITEM(
-       busack, 2,      1,      do_busack_test,
+       busack, 2,      CTBL_RPT,       do_busack_test,
        "Get time from /Reset high to /BUSACK low",
        ""
 ),
-CMD_TBL_ITEM(
-       freq,   CONFIG_SYS_MAXARGS,     1,      do_cpu_freq,
-       "Measure cpu frequency",
-       "[-qwn] [-c loopcycles] [-t timeout]\n"
-       "     -q Be quiet\n"
-//     "     -w  Write result to environment variable '"ENV_CPU_FREQ"'"
-),
 
 CMD_TBL_ITEM(
        help,   CONFIG_SYS_MAXARGS,     CTBL_RPT,       do_help,
@@ -478,7 +468,7 @@ CMD_TBL_ITEM(
 ),
 
 /* This does not use the CMD_TBL_ITEM macro as ? can't be used in symbol names */
-       {FSTR("?"),   CONFIG_SYS_MAXARGS, 1, do_help,
+       {FSTR("?"),   CONFIG_SYS_MAXARGS, CTBL_RPT, do_help,
         NULL,
 #ifdef  CONFIG_SYS_LONGHELP
        FSTR(""),