Files
ZPU/software/zputa/zputa.c
Philip Smart b41d5a97f0 Updates
2019-11-26 23:29:48 +00:00

1087 lines
41 KiB
C

/////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Name: zputa.c
// Created: January 2019
// Author(s): Philip Smart
// Description: ZPU test application.
// This program implements tools, test mechanisms and performance analysers such that
// a ZPU cpu and the encapsulating SoC can be tested, debugged, validated and rated in
// terms of performance.
//
// Credits:
// Copyright: (c) 2019 Philip Smart <philip.smart@net2net.org>
// (c) 2013, ChaN, framework for the SD Card testing.
//
// History: January 2019 - Initial script written for the STORM processor then changed to the ZPU.
// July 2019 - Addition of the Dhrystone and CoreMark tests.
//
// Notes: See Makefile to enable/disable conditional components
// USELOADB - The Byte write command is implemented in hw/sw so use it.
// USE_BOOT_ROM - The target is ROM so dont use initialised data.
// MINIMUM_FUNTIONALITY - Minimise functionality to limit code size.
// COREMARK_TEST - Add the CoreMark test suite.
// DHYRSTONE_TEST - Add the Dhrystone test suite.
// USE_SDCARD - Add the SDCard logic.
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// This source file is free software: you can redistribute it and#or modify
// it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This source file is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/////////////////////////////////////////////////////////////////////////////////////////////////////////
#include <zstdio.h>
//#include <stdlib.h>
//#include <string.h>
#include <zpu-types.h>
#include "zpu_soc.h"
#include "uart.h"
#include "interrupts.h"
#include "ff.h" /* Declarations of FatFs API */
#include "diskio.h"
#include <zstdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include "xprintf.h"
#ifdef COREMARK_TEST
#include "coremark.h"
#endif
#include "utils.h"
#include "zputa_app.h" /* Header for definitions specific to apps run from zputa */
#include "zputa.h"
// Version info.
#define VERSION "v1.3"
#define VERSION_DATE "18/07/2019"
#define PROGRAM_NAME "ZPUTA"
// Utility functions.
#include "tools.c"
// Method to process interrupts. This involves reading the interrupt status register and then calling
// the handlers for each triggered interrupt. A read of the interrupt controller clears the interrupt pending
// register so new interrupts will be processed after this method exits.
//
void interrupt_handler()
{
// Read the interrupt controller to find which devices caused an interrupt.
//
uint32_t intr = INTERRUPT_STATUS(INTR0);
// Prevent additional interrupts.
DisableInterrupts();
dbg_puts("ZPUTA Interrupt Handler\n");
if(INTR_IS_TIMER(intr))
{
dbg_puts("Timer interrupt\n");
}
if(INTR_IS_PS2(intr))
{
dbg_puts("PS2 interrupt\n");
}
if(INTR_IS_IOCTL_RD(intr))
{
dbg_puts("IOCTL RD interrupt\n");
}
if(INTR_IS_IOCTL_WR(intr))
{
dbg_puts("IOCTL WR interrupt\n");
}
if(INTR_IS_UART0_RX(intr))
{
dbg_puts("UART0 RX interrupt\n");
}
if(INTR_IS_UART0_TX(intr))
{
dbg_puts("UART0 TX interrupt\n");
}
if(INTR_IS_UART1_RX(intr))
{
dbg_puts("UART1 RX interrupt\n");
}
if(INTR_IS_UART1_TX(intr))
{
dbg_puts("UART1 TX interrupt\n");
}
// Enable new interrupts.
EnableInterrupts();
}
// Method to initialise the timer.
//
void initTimer()
{
dbg_puts("Setting up timer...\n");
TIMER_INDEX(TIMER1) = 0; // Set first timer
TIMER_COUNTER(TIMER1) = 100000; // Timer is prescaled to 100KHz
}
// Method to enable the timer.
//
void enableTimer()
{
dbg_puts("Enabling timer...\n");
TIMER_ENABLE(TIMER1) = 1; // Enable timer 0
}
// Method to decode a command into a key which is used to select the associated command logic.
//
int16_t decodeCommand(char **ptr)
{
uint8_t idx;
char *spaceptr = (*ptr);
// If no command entered, exit.
if(*ptr == 0x0)
return CMD_NOKEY;
// Find the end of the command and terminate it for comparison.
while(*spaceptr != ' ' && *spaceptr != 0x00) spaceptr++;
if(*spaceptr == ' ') { (*spaceptr) = 0x00; spaceptr++; }
// Loop through all the commands and try to find a match.
for (idx=0; idx < NCMDKEYS; idx++)
{
t_cmdstruct *sym = &cmdTable[idx];
if (strcmp(sym->cmd, *ptr) == 0 && sym->builtin == 1)
{
(*ptr) = spaceptr;
return sym->key;
}
}
// No command found, so raise error.
return CMD_BADKEY;
}
// Interactive command processor. Allow user to input a command and execute accordingly.
//
int cmdProcessor(void)
{
// Local variables.
char *ptr;
char *ptr2;
char *src1FileName;
char *src2FileName;
char *dstFileName;
char line[120];
uint8_t diskInitialised = 0;
uint8_t fsInitialised = 0;
long p1;
long p2;
long p3;
uint32_t up1;
uint32_t up2;
uint32_t startPos;
uint32_t memAddr;
uint32_t execAddr;
uint32_t len;
uint32_t mode;
uint32_t width;
uint32_t sizeToRead;
uint32_t retCode;
FRESULT fr;
BYTE b1;
RTC rtc;
#if defined(BUILTIN_FS_CHANGETIME) && BUILTIN_FS_CHANGETIME == 1
FILINFO Finfo;
#endif
// Initialise any globals in the structure used to pass working variables to apps.
G.Sector = 0;
// Initialise the first disk if FS enabled as external commands depend on it.
#if defined(USE_SDCARD)
fr = FR_NOT_ENABLED;
if(!disk_initialize(0, 1))
{
xsprintf(line, "0:");
fr = f_mount(&G.FatFs[0], line, 0);
}
if(fr)
{
xprintf("Failed to initialise sd card 0, please init manually.\n");
} else
{
diskInitialised = 1;
fsInitialised = 1;
}
#endif
while(1)
{
// Prompt to indicate input required.
xputs("* ");
ptr = line;
memset(line, 0x00, sizeof(line));
xgets(ptr, sizeof(line));
// main functions
switch(decodeCommand(&ptr))
{
#if defined(USE_SDCARD)
// DISK commands
#if defined(BUILTIN_DISK_DUMP) && BUILTIN_DISK_DUMP == 1
// CMD_DISK_DUMP <pd#> [<sector>] - Dump sector
case CMD_DISK_DUMP:
if (!xatoi(&ptr, &p1)) break;
if (!xatoi(&ptr, &p2)) p2 = G.Sector;
b1 = disk_read((BYTE)p1, G.Buff, p2, 1);
if (b1) { xprintf("rc=%d\n", b1); break; }
G.Sector = p2 + 1;
xprintf("Sector:%lu\n", p2);
memoryDump((uint32_t)G.Buff, 0x200, 16, 0, 32);
break;
#endif
// CMD_DISK_INIT <pd#> <card type> - Initialize disk
case CMD_DISK_INIT:
if(!xatoi(&ptr, &p1)) { xprintf("Bad disk id!\n"); break; }
if(xatoi(&ptr, &p2))
if(p2 > 1) p2 = 0;
if(!disk_initialize((BYTE)p1, (BYTE)p2))
{
xputs("Initialised.\n");
diskInitialised = 1;
} else
xputs("Failed to initialise.\n");
break;
#if defined(BUILTIN_DISK_STATUS) && BUILTIN_DISK_STATUS == 1
// CMD_DISK_STATUS <pd#> - Show disk status
case CMD_DISK_STATUS:
if (!xatoi(&ptr, &p1)) break;
if (disk_ioctl((BYTE)p1, GET_SECTOR_COUNT, &p2) == RES_OK)
{ xprintf("Drive size: %lu sectors\n", p2); }
if (disk_ioctl((BYTE)p1, GET_BLOCK_SIZE, &p2) == RES_OK)
{ xprintf("Erase block: %lu sectors\n", p2); }
if (disk_ioctl((BYTE)p1, MMC_GET_TYPE, &b1) == RES_OK)
{ xprintf("Card type: %u\n", b1); }
if (disk_ioctl((BYTE)p1, MMC_GET_CSD, G.Buff) == RES_OK)
{ xputs("CSD:\n"); memoryDump((uint32_t)G.Buff, 16, 16, 0, 32); }
if (disk_ioctl((BYTE)p1, MMC_GET_CID, G.Buff) == RES_OK)
{ xputs("CID:\n"); memoryDump((uint32_t)G.Buff, 16, 16, 0, 32); }
if (disk_ioctl((BYTE)p1, MMC_GET_OCR, G.Buff) == RES_OK)
{ xputs("OCR:\n"); memoryDump((uint32_t)G.Buff, 4, 16, 0, 32); }
if (disk_ioctl((BYTE)p1, MMC_GET_SDSTAT, G.Buff) == RES_OK) {
xputs("SD Status:\n");
memoryDump((uint32_t)G.Buff, 64, 16, 0, 32);
}
if (disk_ioctl((BYTE)p1, ATA_GET_MODEL, line) == RES_OK)
{ line[40] = '\0'; xprintf("Model: %s\n", line); }
if (disk_ioctl((BYTE)p1, ATA_GET_SN, line) == RES_OK)
{ line[20] = '\0'; xprintf("S/N: %s\n", line); }
break;
#endif
// CMD_DISK_IOCTL_SYNC <pd#> - CTRL_SYNC
case CMD_DISK_IOCTL_SYNC:
if (!xatoi(&ptr, &p1)) break;
xprintf("rc=%d\n", disk_ioctl((BYTE)p1, CTRL_SYNC, 0));
break;
// BUFFER commands
#if defined(BUILTIN_BUFFER_DUMP) && BUILTIN_BUFFER_DUMP == 1
// CMD_BUFFER_DUMP <offset> - Dump R/W buffer
case CMD_BUFFER_DUMP:
if (!xatoi(&ptr, &p1)) break;
memoryDump((uint32_t)&G.Buff[p1], 0x200, 16, p1, 32);
break;
#endif
// CMD_BUFFER_EDIT <addr> [<data>] ... - Edit R/W buffer
#if defined(BUILTIN_BUFFER_EDIT) && BUILTIN_BUFFER_EDIT == 1
case CMD_BUFFER_EDIT:
if (!xatoi(&ptr, &p1)) break;
if (xatoi(&ptr, &p2)) {
do {
G.Buff[p1++] = (BYTE)p2;
} while (xatoi(&ptr, &p2));
break;
}
for (;;) {
xprintf("%04X %02X-", (WORD)p1, G.Buff[p1]);
xgets(line, sizeof line);
ptr = line;
if (*ptr == '.') break;
if (*ptr < ' ') { p1++; continue; }
if (xatoi(&ptr, &p2)) {
G.Buff[p1++] = (BYTE)p2;
} else {
xputs("???\n");
}
}
break;
#endif
#if defined(BUILTIN_BUFFER_READ) && BUILTIN_BUFFER_READ == 1
// CMD_BUFFER_READ <pd#> <sector> [<n>] - Read disk into R/W buffer
case CMD_BUFFER_READ:
if(xatoi(&ptr, &p1))
if(xatoi(&ptr, &p2))
{
if(!xatoi(&ptr, &p3)) p3 = 1;
xprintf("rc=%u\n", disk_read((BYTE)p1, G.Buff, p2, p3));
}
break;
#endif
#if defined(BUILTIN_BUFFER_WRITE) && BUILTIN_BUFFER_WRITE == 1
// CMD_BUFFER_WRITE <pd#> <sector> [<n>] - Write R/W buffer into disk
case CMD_BUFFER_WRITE:
if(xatoi(&ptr, &p1))
if(xatoi(&ptr, &p2))
{
if (!xatoi(&ptr, &p3)) p3 = 1;
xprintf("rc=%u\n", disk_write((BYTE)p1, G.Buff, p2, p3));
}
break;
#endif
#if defined(BUILTIN_BUFFER_FILL) && BUILTIN_BUFFER_FILL == 1
// CMD_BUFFER_FILL <n> - Fill working buffer
case CMD_BUFFER_FILL:
if (!xatoi(&ptr, &p1)) break;
memset(G.Buff, (BYTE)p1, sizeof G.Buff);
break;
#endif
#if defined(BUILTIN_BUFFER_LEN) && BUILTIN_BUFFER_LEN == 1
// CMD_BUFFER_LEN <len> - Set read/write size for fr/fw command
case CMD_BUFFER_LEN:
len = getUintParam(&ptr);
fr = fileSetBlockLen(len);
if (fr) { printFSCode(fr); break; }
xprintf("R/W length = %u\n", len);
break;
#endif
// FILESYSTEM commands.
// CMD_FS_INIT <ld#> [<mount>]- Initialize logical drive
case CMD_FS_INIT:
if(xatoi(&ptr, &p1))
if((UINT)p1 > 9) break;
if(!xatoi(&ptr, &p2)) p2 = 0;
xsprintf(line, "%u:", (UINT)p1);
fr = f_mount(&G.FatFs[p1], line, (BYTE)p2);
if(fr)
printFSCode(fr);
else
{
xputs("Initialised.\n");
fsInitialised = 1;
}
break;
// CMD_FS_STATUS [<path>] - Show logical drive status
#if defined(BUILTIN_FS_STATUS) && BUILTIN_FS_STATUS == 1
case CMD_FS_STATUS:
fr = printFatFSStatus(getStrParam(&ptr));
if (fr) { printFSCode(fr); break; }
break;
#endif
// CMD_FS_DIRLIST [<path>] - Directory listing
#if defined(BUILTIN_FS_DIRLIST) && BUILTIN_FS_DIRLIST == 1
case CMD_FS_DIRLIST:
fr = printDirectoryListing(getStrParam(&ptr));
if (fr) { printFSCode(fr); break; }
break;
#endif
// CMD_FS_OPEN <mode> <name> - Open a file
#if defined(BUILTIN_FS_OPEN) && BUILTIN_FS_OPEN == 1
case CMD_FS_OPEN:
if(G.fileInUse) { xputs("File already open, please close before re-opening\n"); break; }
if (!xatoi(&ptr, &p1)) break;
while (*ptr == ' ') ptr++;
fr = f_open(&G.File[0], ptr, (BYTE)p1);
printFSCode(fr);
if( fr == FR_OK ) { G.fileInUse = 1; }
break;
#endif
// CMD_FS_CLOSE - Close a file
#if defined(BUILTIN_FS_CLOSE) && BUILTIN_FS_CLOSE == 1
case CMD_FS_CLOSE:
if(G.fileInUse == 0) { xputs("No file open, cannot close.\n"); break; }
fr=f_close(&G.File[0]);
printFSCode(fr);
if(fr == FR_OK) { G.fileInUse = 0; }
break;
#endif
// CMD_FS_SEEK - Seek file pointer
#if defined(BUILTIN_FS_READ) && BUILTIN_FS_READ == 1
case CMD_FS_SEEK:
if(G.fileInUse == 0) { xputs("No file open, cannot seek.\n"); break; }
if (!xatoi(&ptr, &p1)) break;
fr = f_lseek(&G.File[0], p1);
printFSCode(fr);
if (fr == FR_OK) {
xprintf("fptr = %lu(0x%lX)\n", (DWORD)G.File[0].fptr, (DWORD)G.File[0].fptr);
}
break;
#endif
// CMD_FS_READ <len> - read file
#if defined(BUILTIN_FS_READ) && BUILTIN_FS_READ == 1
case CMD_FS_READ:
if(G.fileInUse == 0) { xputs("No file open, cannot read.\n"); break; }
fr = fileBlockRead(&G.File[0], getUintParam(&ptr));
if(fr) { printFSCode(fr); }
break;
#endif
// CMD_FS_CAT <name> - cat/output file
#if defined(BUILTIN_FS_CAT) && BUILTIN_FS_CAT == 1
case CMD_FS_CAT:
fr = fileCat(getStrParam(&ptr));
if(fr) { printFSCode(fr); }
break;
#endif
// CMD_FS_LOAD <name> <addr> - Load a file into memory
#if defined(BUILTIN_FS_LOAD) && BUILTIN_FS_LOAD == 1
case CMD_FS_LOAD:
src1FileName = getStrParam(&ptr);
memAddr = getUintParam(&ptr);
fr = fileLoad(src1FileName, memAddr, 1);
if(fr) { printFSCode(fr); }
break;
#endif
// CMD_FS_SAVE <name> <addr> <len> - Save memory range into a file.
#if defined(BUILTIN_FS_SAVE) && BUILTIN_FS_SAVE == 1
case CMD_FS_SAVE:
dstFileName = getStrParam(&ptr);
memAddr = getUintParam(&ptr);
len = getUintParam(&ptr);
fr = fileSave(dstFileName, memAddr, len);
if(fr) { printFSCode(fr); }
break;
#endif
// CMD_FS_EXEC <name> <loadAddr> <execAddr> <mode> - Load a file into memory and exeute.
#if defined(BUILTIN_FS_EXEC) && BUILTIN_FS_EXEC == 1
case CMD_FS_EXEC:
src1FileName = getStrParam(&ptr);
memAddr = getUintParam(&ptr);
execAddr = getUintParam(&ptr);
mode = getUintParam(&ptr);
fr = fileExec(src1FileName, memAddr, execAddr, mode, 0, 0, (uint32_t)&G, (uint32_t)&cfgSoC);
if(fr) { printFSCode(fr); }
break;
#endif
// CMD_FS_DUMP <name> [<width>] - Dump a file contents as hex
#if defined(BUILTIN_FS_DUMP) && BUILTIN_FS_DUMP == 1
case CMD_FS_DUMP:
src1FileName = getStrParam(&ptr);
if((width = getUintParam(&ptr)) == 0) { width = 8; }
fr = fileDump(src1FileName, width);
if(fr) { printFSCode(fr); }
break;
#endif
// CMD_FS_INSPECT <offset> [<len>] - read and dump file from current fp
#if defined(BUILTIN_FS_INSPECT) && BUILTIN_FS_INSPECT == 1
case CMD_FS_INSPECT:
if(G.fileInUse == 0) { xputs("No file open, buffer contents invalid.\n"); break; }
startPos = getUintParam(&ptr);
len = getUintParam(&ptr);
fr = fileBlockDump(startPos, len);
if(fr) { printFSCode(fr); }
break;
#endif
// fw <len> - write buffer to file
#if defined(BUILTIN_FS_WRITE) && BUILTIN_FS_WRITE == 1
case CMD_FS_WRITE:
if(G.fileInUse == 0) { xputs("No file open, cannot write.\n"); break; }
fr = fileBlockWrite(&G.File[0], getUintParam(&ptr));
if(fr) { printFSCode(fr); }
break;
#endif
// CMD_FS_TRUNC - Truncate file
#if defined(BUILTIN_FS_TRUNC) && BUILTIN_FS_TRUNC == 1
case CMD_FS_TRUNC:
if(G.fileInUse == 0) { xputs("No file open, cannot truncate.\n"); break; }
printFSCode(f_truncate(&G.File[0]));
break;
#endif
// CMD_FS_RENAME <old_name> <new_name> - Change file/dir name
#if defined(BUILTIN_FS_RENAME) && BUILTIN_FS_RENAME == 1
case CMD_FS_RENAME:
ptr2 = strchr(ptr, ' ');
if (!ptr2) break;
*ptr2++ = 0;
while (*ptr2 == ' ') ptr2++;
printFSCode(f_rename(ptr, ptr2));
break;
#endif
// CMD_FS_DELETE <name> - Delete a file or dir
#if defined(BUILTIN_FS_DELETE) && BUILTIN_FS_DELETE == 1
case CMD_FS_DELETE:
printFSCode(f_unlink(ptr));
break;
#endif
// CMD_FS_CREATEDIR <name> - Create a directory
#if defined(BUILTIN_FS_CREATEDIR) && BUILTIN_FS_CREATEDIR == 1
case CMD_FS_CREATEDIR:
printFSCode(f_mkdir(ptr));
break;
#endif
#if defined(BUILTIN_FS_ALLOCBLOCK) && BUILTIN_FS_ALLOCBLOCK == 1
#if FF_USE_EXPAND
// CMD_FS_ALLOCBLOCK <fsz> <opt> - Allocate contiguous block
case CMD_FS_ALLOCBLOCK:
if(G.fileInUse == 0) { xputs("No file open, cannot allocate block.\n"); break; }
if (!xatoi(&ptr, &p1) || !xatoi(&ptr, &p2)) break;
fr = f_expand(&G.File[0], (DWORD)p1, (BYTE)p2);
printFSCode(fr);
break;
#endif
#endif
#if FF_USE_CHMOD
#if defined(BUILTIN_FS_CHANGEATTRIB) && BUILTIN_FS_CHANGEATTRIB == 1
// CMD_FS_CHANGEATTRIB <atrr> <mask> <name> - Change file/dir attribute
case CMD_FS_CHANGEATTRIB:
if (!xatoi(&ptr, &p1) || !xatoi(&ptr, &p2)) break;
while (*ptr == ' ') ptr++;
printFSCode(f_chmod(ptr, p1, p2));
break;
#endif
// CMD_FS_CHANGETIME <year> <month> <day> <hour> <min> <sec> <name>
#if defined(BUILTIN_FS_CHANGETIME) && BUILTIN_FS_CHANGETIME == 1
case CMD_FS_CHANGETIME:
if (!xatoi(&ptr, &p1) || !xatoi(&ptr, &p2) || !xatoi(&ptr, &p3)) break;
Finfo.fdate = ((p1 - 1980) << 9) | ((p2 & 15) << 5) | (p3 & 31);
if (!xatoi(&ptr, &p1) || !xatoi(&ptr, &p2) || !xatoi(&ptr, &p3)) break;
Finfo.ftime = ((p1 & 31) << 11) | ((p2 & 63) << 5) | ((p3 >> 1) & 31);
while (*ptr == ' ') ptr++;
printFSCode(f_utime(ptr, &Finfo));
break;
#endif
#endif
// CMD_FS_COPY <src_name> <dst_name> - Copy file
#if defined(BUILTIN_FS_COPY) && BUILTIN_FS_COPY == 1
case CMD_FS_COPY:
src1FileName=getStrParam(&ptr);
dstFileName=getStrParam(&ptr);
fr = fileCopy(src1FileName, dstFileName);
if(fr) { printFSCode(fr); }
break;
#endif
// CMD_FS_CONCAT <src_name_1> <src_name_2> <dst_file>
#if defined(BUILTIN_FS_CONCAT) && BUILTIN_FS_CONCAT == 1
case CMD_FS_CONCAT:
src1FileName=getStrParam(&ptr);
src2FileName=getStrParam(&ptr);
dstFileName=getStrParam(&ptr);
fr = fileConcatenate(src1FileName, src2FileName, dstFileName);
if(fr) { printFSCode(fr); }
break;
#endif
// CMD_FS_XTRACT <src_name> <dst_file> <start pos> <len>
#if defined(BUILTIN_FS_XTRACT) && BUILTIN_FS_XTRACT == 1
case CMD_FS_XTRACT:
src1FileName= getStrParam(&ptr);
dstFileName = getStrParam(&ptr);
startPos = getUintParam(&ptr);
len = getUintParam(&ptr);
fr = fileXtract(src1FileName, dstFileName, startPos, len);
if(fr) { printFSCode(fr); }
break;
#endif
#if FF_FS_RPATH
#if defined(BUILTIN_FS_CHANGEDIR) && BUILTIN_FS_CHANGEDIR == 1
// CMD_FS_CHANGEDIR <path> - Change current directory
case CMD_FS_CHANGEDIR:
printFSCode(f_chdir(ptr));
break;
#endif
#if FF_VOLUMES >= 2
// CMD_FS_CHANGEDRIVE <path> - Change current drive
#if defined(BUILTIN_FS_CHANGEDRIVE) && BUILTIN_FS_CHANGEDRIVE == 1
case CMD_FS_CHANGEDRIVE:
printFSCode(f_chdrive(ptr));
break;
#endif
#endif
#if FF_FS_RPATH >= 2
// CMD_FS_SHOWDIR - Show current dir path
#if defined(BUILTIN_FS_SHOWDIR) && BUILTIN_FS_SHOWDIR == 1
case CMD_FS_SHOWDIR:
fr = f_getcwd(line, sizeof line);
if (fr) {
printFSCode(fr);
} else {
xprintf("%s\n", line);
}
break;
#endif
#endif
#endif
#if FF_USE_LABEL
// CMD_FS_SETLABEL <name> - Set volume label
#if defined(BUILTIN_FS_SETLABEL) && BUILTIN_FS_SETLABEL == 1
case CMD_FS_SETLABEL:
printFSCode(f_setlabel(ptr));
break;
#endif
#endif
#if FF_USE_MKFS
// CMD_FS_CREATEFS <ld#> <type> <bytes/clust> - Create filesystem
#if defined(BUILTIN_FS_CREATEFS) && BUILTIN_FS_CREATEFS == 1
case CMD_FS_CREATEFS:
if (!xatoi(&ptr, &p1) || (UINT)p1 > 9 || !xatoi(&ptr, &p2) || !xatoi(&ptr, &p3)) break;
xprintf("The drive %u will be formatted. Are you sure? (Y/n)=", (WORD)p1);
xgets(line, sizeof line);
if (line[0] == 'Y') {
xsprintf(line, "%u:", (UINT)p1);
printFSCode(f_mkfs(line, (BYTE)p2, (DWORD)p3, G.Buff, sizeof G.Buff));
}
break;
#endif
#endif
#endif // USE_SDCARD
#if defined(BUILTIN_MISC_SETTIME) && BUILTIN_MISC_SETTIME == 1
// CMD_MISC_SETTIME [<year> <mon> <day> <hour> <min> <sec>]
case CMD_MISC_SETTIME:
if (xatoi(&ptr, &p1)) {
rtc.year = (uint16_t)p1;
xatoi(&ptr, &p1); rtc.month = (uint8_t)p1;
xatoi(&ptr, &p1); rtc.day = (uint8_t)p1;
xatoi(&ptr, &p1); rtc.hour = (uint8_t)p1;
xatoi(&ptr, &p1); rtc.min = (uint8_t)p1;
if (!xatoi(&ptr, &p1)) break;
rtc.sec = (uint8_t)p1;
rtc.msec = 0;
rtc.usec = 0;
rtcSet(&rtc);
}
rtcGet(&rtc);
xprintf("%u/%u/%u %02u:%02u:%02u.%03u%03u\n", rtc.year, rtc.month, rtc.day, rtc.hour, rtc.min, rtc.sec, rtc.msec, rtc.usec);
break;
#endif
// MEMORY commands
//
#if defined(BUILTIN_MEM_CLEAR) && BUILTIN_MEM_CLEAR == 1
// Clear memory <start addr> <end addr> [<word>]
case CMD_MEM_CLEAR:
if (!xatoi(&ptr, &p1)) break;
if (!xatoi(&ptr, &p2)) break;
if (!xatoi(&ptr, &p3))
{
p3 = 0x00000000;
}
xputs("Clearing...");
for(memAddr=p1; memAddr < p2; memAddr+=4)
{
*(uint32_t *)(memAddr) = p3;
}
xputs("\n");
break;
#endif
#if defined(BUILTIN_MEM_COPY) && BUILTIN_MEM_COPY == 1
// Copy memory <start addr> <end addr> <dst addr>
case CMD_MEM_COPY:
if (!xatoi(&ptr, &p1)) break;
if (!xatoi(&ptr, &p2)) break;
if (!xatoi(&ptr, &p3)) break;
xputs("Copying...");
for(memAddr=p1; memAddr < p2; memAddr++, p3++)
{
*(uint8_t *)(p3) = *(uint8_t *)(memAddr);
}
xputs("\n");
break;
#endif
#if defined(BUILTIN_MEM_DIFF) && BUILTIN_MEM_DIFF == 1
// Compare memory <start addr> <end addr> <compare addr>
case CMD_MEM_DIFF:
if (!xatoi(&ptr, &p1)) break;
if (!xatoi(&ptr, &p2)) break;
if (!xatoi(&ptr, &p3)) break;
xputs("Comparing...");
for(memAddr=p1; memAddr < p2; memAddr++, p3++)
{
if(*(uint8_t *)(p3) != *(uint8_t *)(memAddr))
{
xprintf("%08lx(%08x)->%08lx(%08x)\n", memAddr, *(uint8_t *)(memAddr), p3, *(uint8_t *)(p3));
}
}
xputs("\n");
break;
#endif
#if defined(BUILTIN_MEM_DUMP) && BUILTIN_MEM_DUMP == 1
// Dump memory, [<start addr>, [<end addr>], [<size>]]
case CMD_MEM_DUMP:
if (!xatoi(&ptr, &p1))
{
if(cfgSoC.implInsnBRAM) { p1 = cfgSoC.addrInsnBRAM; }
else if(cfgSoC.implBRAM) { p1 = cfgSoC.addrBRAM; }
else if(cfgSoC.implRAM || cfgSoC.implDRAM) { p1 = cfgSoC.addrRAM; }
else { p1 = cfgSoC.stackStartAddr - 512; }
}
if (!xatoi(&ptr, &p2))
{
if(cfgSoC.implInsnBRAM) { p2 = cfgSoC.sizeInsnBRAM; }
else if(cfgSoC.implBRAM) { p2 = cfgSoC.sizeBRAM; }
else if(cfgSoC.implRAM || cfgSoC.implDRAM) { p2 = cfgSoC.sizeRAM; }
else { p2 = cfgSoC.stackStartAddr + 8; }
}
if (!xatoi(&ptr, &p3) || (p3 != 8 && p3 != 16 && p3 != 32))
{
p3 = 8;
}
xputs("Dump Memory\n");
memoryDump(p1, p2, p3, p1, 32);
xputs("\nComplete.\n");
break;
#endif
#if defined(BUILTIN_MEM_EDIT_BYTES) && BUILTIN_MEM_EDIT_BYTES == 1
// Edit memory with bytes, <addr> <byte> [<byte> .... <byte>]
case CMD_MEM_EDIT_BYTES:
if (!xatoi(&ptr, &p1)) break;
if (xatoi(&ptr, &p2))
{
do {
*(uint8_t *)(p1++) = (uint8_t)p2;
} while (xatoi(&ptr, &p2));
break;
}
for (;;)
{
xprintf("%08X %02X-", (uint32_t)p1, *(uint8_t *)p1);
xgets(line, sizeof line);
ptr = line;
if (*ptr == '.') break;
if (*ptr < ' ') { p1++; continue; }
if (xatoi(&ptr, &p2))
{
*(uint8_t *)(p1++) = (uint8_t)p2;
} else {
xputs("???\n");
}
}
break;
#endif
#if defined(BUILTIN_MEM_EDIT_HWORD) && BUILTIN_MEM_EDIT_HWORD == 1
// Edit memory with half-words, <addr> <16bit h-word> [<h-word> .... <h-word>]
case CMD_MEM_EDIT_HWORD:
if (!uxatoi(&ptr, &up1)) break;
if (uxatoi(&ptr, &up2))
{
do {
*(uint16_t *)(up1) = (uint16_t)up2;
up1 += 2;
} while (uxatoi(&ptr, &up2));
break;
}
for (;;)
{
xprintf("%08X %04X-", (uint32_t)up1, *(uint16_t *)up1);
xgets(line, sizeof line);
ptr = line;
if (*ptr == '.') break;
if (*ptr < ' ') { up1 += 4; continue; }
if (uxatoi(&ptr, &up2))
{
*(uint16_t *)(up1) = (uint16_t)up2;
up1 += 2;
} else {
xputs("???\n");
}
}
break;
#endif
#if defined(BUILTIN_MEM_EDIT_WORD) && BUILTIN_MEM_EDIT_WORD == 1
// Edit memory with words, <addr> <word> [<word> .... <word>]
case CMD_MEM_EDIT_WORD:
if (!uxatoi(&ptr, &up1)) break;
if (uxatoi(&ptr, &up2))
{
do {
*(uint32_t *)(up1) = up2;
up1 += 4;
} while (uxatoi(&ptr, &up2));
break;
}
for (;;)
{
xprintf("%08X %08X-", up1, *(uint32_t *)(up1));
xgets(line, sizeof line);
ptr = line;
if (*ptr == '.') break;
if (*ptr < ' ') { up1 += 4; continue; }
if (uxatoi(&ptr, &up2))
{
xprintf("%08X %08X-", up1, up2);
*(uint32_t *)(up1) = up2;
up1 += 4;
} else {
xputs("???\n");
}
}
break;
#endif
// HARDWARE commands
//
// Disable interrupts
case CMD_HW_INTR_DISABLE:
xputs("Disabling interrupts\n");
DisableInterrupt(INTR_TIMER);
break;
// Enable interrupts
case CMD_HW_INTR_ENABLE:
xputs("Enabling interrupts\n");
//EnableInterrupt(INTR_TIMER | INTR_PS2 | INTR_IOCTL_RD | INTR_IOCTL_WR | INTR_UART0_RX | INTR_UART0_TX | INTR_UART1_RX | INTR_UART1_TX);
EnableInterrupt(INTR_TIMER | INTR_UART0_RX);
break;
#if defined(BUILTIN_HW_SHOW_REGISTER) && BUILTIN_HW_SHOW_REGISTER == 1
// Output register Information.
case CMD_HW_SHOW_REGISTER:
xputs("Register information\n");
xputs("Interrupt: ");
xprintf("%08X %08X\n", INTERRUPT_STATUS(INTR0), INTERRUPT_CTRL(INTR0));
while(getserial_nonblocking() == -1)
{
xprintf("UART 0/1: %08X %08X %08X %08X %08X %08X\r", UART_STATUS(UART0), UART_FIFO_STATUS(UART0), UART_BRGEN(UART0), UART_STATUS(UART1), UART_FIFO_STATUS(UART1), UART_BRGEN(UART1));
memAddr = INTERRUPT_STATUS(INTR0);
}
xputs("\n");
break;
#endif
#if defined(BUILTIN_HW_TEST_TIMERS) && BUILTIN_HW_TEST_TIMERS == 1
// Output RTC and test timer up/down counters.
case CMD_HW_TEST_TIMERS:
xputs("Testing RTC & Up/Down Timers\n");
TIMER_MILLISECONDS_UP = 60000;
while(getserial_nonblocking() == -1)
{
if(TIMER_MICROSECONDS_DOWN == 0)
{
TIMER_MICROSECONDS_DOWN = 10000000;
xputs("\r\nuSec down counter expired.\n");
}
if(TIMER_MILLISECONDS_DOWN == 0)
{
TIMER_MILLISECONDS_DOWN = 60000;
xputs("\r\nmSec down counter expired.\n");
}
if(TIMER_SECONDS_DOWN == 0)
{
TIMER_SECONDS_DOWN = 60;
xputs("\r\nSecond down counter expired.\n");
}
if(TIMER_MILLISECONDS_UP == 60000)
{
TIMER_MILLISECONDS_UP = 0;
xputs("\r\nmSec up counter expired.\n");
}
xprintf("%02d/%02d/%02d %02d:%02d:%02d.%03d%03d %10lu %10lu %10lu %10lu\r", RTC_YEAR, RTC_MONTH, RTC_DAY, RTC_HOUR, RTC_MINUTE, RTC_SECOND, RTC_MILLISECONDS, RTC_MICROSECONDS, TIMER_MICROSECONDS_DOWN, TIMER_MILLISECONDS_DOWN, TIMER_SECONDS_DOWN, TIMER_MILLISECONDS_UP);
}
xputs("\n");
break;
#endif
// Disable UART fifo
case CMD_HW_FIFO_DISABLE:
UART_CTRL(UART0) = UART_TX_ENABLE | UART_RX_ENABLE;
UART_CTRL(UART1) = UART_TX_ENABLE | UART_RX_ENABLE;
xputs("Disabled uart fifo\n");
break;
// Enable UART fifo
case CMD_HW_FIFO_ENABLE:
xputs("Enabling uart fifo\n");
UART_CTRL(UART0) = UART_TX_FIFO_ENABLE | UART_TX_ENABLE | UART_RX_FIFO_ENABLE | UART_RX_ENABLE;
UART_CTRL(UART1) = UART_TX_FIFO_ENABLE | UART_TX_ENABLE | UART_RX_FIFO_ENABLE | UART_RX_ENABLE;
break;
// TESTING commands
#if defined(DHRYSTONE_TEST)&& defined(BUILTIN_TST_DHRYSTONE) && BUILTIN_TST_DHRYSTONE == 1
case CMD_TEST_DHRYSTONE:
// Run a Dhrystone test to evaluate CPU speed.
xputs("Running Dhrystone test, please wait ...\n\n");
main_dhry();
break;
#endif
#if defined(COREMARK_TEST)&& defined(BUILTIN_TST_COREMARK) && BUILTIN_TST_COREMARK == 1
case CMD_TEST_COREMARK:
// Run a CoreMark test to evaluate CPU speed.
xputs("Running CoreMark test, please wait ...\n\n");
CoreMarkTest();
break;
#endif
// EXECUTION commands.
case CMD_EXECUTE:
if (!xatoi(&ptr, &p1)) break;
xprintf("Executing code @ %08x ...\n", p1);
void *jmpptr = (void *)p1;
goto *jmpptr;
break;
case CMD_CALL:
if (!xatoi(&ptr, &p1)) break;
xprintf("Calling code @ %08x ...\n", p1);
int (*func)(void) = (int (*)(void))p1;
int retCode = func();
if(retCode != 0)
{
xprintf("Call returned code (%d).\n", retCode);
}
break;
// MISC commands
case CMD_MISC_RESTART_APP:
xputs("Restarting application...\n");
_start();
break;
// Reboot the ZPU to the cold start location.
case CMD_MISC_REBOOT:
xputs("Cold rebooting...\n");
void *rbtptr = (void *)0x00000000;
goto *rbtptr;
break;
// Help screen
#if defined(BUILTIN_MISC_HELP) && BUILTIN_MISC_HELP == 1
case CMD_MISC_HELP:
displayHelp(ptr);
break;
#endif
// Test screen
case CMD_MISC_TEST:
break;
// Configuration information
case CMD_MISC_INFO:
showSoCConfig();
break;
// Unrecognised command, if SD card enabled, see if the command exists as an app. If it is an app, load and execute
// otherwise throw error..
case CMD_BADKEY:
default:
if(*ptr != 0x00)
{
#if defined(USE_SDCARD)
if(diskInitialised && fsInitialised)
{
// Append the app extension to the command and try to execute.
src1FileName=getStrParam(&ptr);
xsprintf(&line[40], "%d:\\%s\\%s.%s", APP_CMD_BIN_DRIVE, APP_CMD_BIN_DIR, src1FileName, APP_CMD_EXTENSION);
retCode = fileExec(&line[40], APP_CMD_LOAD_ADDR, APP_CMD_EXEC_ADDR, EXEC_MODE_CALL, (uint32_t) ++ptr, 0, (uint32_t)&G, (uint32_t)&cfgSoC);
}
if(!diskInitialised || !fsInitialised || retCode == 0xffffffff)
{
xprintf("Bad command.\n");
}
#else
xprintf("Unknown command!\n");
#endif
}
break;
// No input
case CMD_NOKEY:
break;
}
}
}
int main(int argc, char **argv)
{
// Initialisation.
//
G.fileInUse = 0;
// When ZPUTA is the booted app or is booted by the tiny IOCP bootstrap, initialise hardware as it hasnt yet been done.
#if defined(ZPUTA_BASEADDR) && (ZPUTA_BASEADDR == 0x0000 || ZPUTA_BASEADDR == 0x1000)
// Setup the required baud rate for the UART. Once the divider is loaded, a reset takes place within the UART.
UART_BRGEN(UART0) = BAUDRATEGEN(115200, 115200);
UART_BRGEN(UART1) = BAUDRATEGEN(115200, 115200);
// Enable the RX/TX units and enable FIFO mode.
UART_CTRL(UART0) = UART_TX_FIFO_ENABLE | UART_TX_ENABLE | UART_RX_FIFO_ENABLE | UART_RX_ENABLE;
UART_CTRL(UART1) = UART_TX_FIFO_ENABLE | UART_TX_ENABLE | UART_RX_FIFO_ENABLE | UART_RX_ENABLE;
#endif
// Setup the input/output devices for the xprintf library.
xdev_out(putchar);
xdev_in(getserial); // xdev_in(getserial_nonblocking); // xdev_in(getdbgserial);
// Setup the configuration using the SoC configuration register if implemented otherwise the compiled internals.
setupSoCConfig();
// Ensure interrupts are disabled whilst setting up.
DisableInterrupts();
//xputs("Setting up timer...\n");
//TIMER_INDEX(TIMER1) = 0; // Set first timer
//TIMER_COUNTER(TIMER1) = 100000; // Timer is prescaled to 100KHz
//enableTimer();
// Indicate life...
puts("Running...\n");
xputs("Enabling interrupts...\n");
SetIntHandler(interrupt_handler);
//EnableInterrupt(INTR_TIMER | INTR_PS2 | INTR_IOCTL_RD | INTR_IOCTL_WR | INTR_UART0_RX | INTR_UART0_TX | INTR_UART1_RX | INTR_UART1_TX);
//EnableInterrupt(INTR_UART0_RX | INTR_UART1_RX); // | INTR_TIMER);
// Intro screen
printVersion(true);
// Command processor. If it exits, then reset the CPU.
cmdProcessor();
// Reboot as it is not normal the command processor terminates.
void *rbtptr = (void *)0x00000000;
goto *rbtptr;
}